From fa194a497c43061071aa6949890bb5c0da511933 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 8 Apr 2025 17:04:43 +0100
Subject: [PATCH 01/63] cleanup
---
apps/client/public/locales/zh-CN/translation.json | 3 ---
1 file changed, 3 deletions(-)
diff --git a/apps/client/public/locales/zh-CN/translation.json b/apps/client/public/locales/zh-CN/translation.json
index 0c45cd50..bbe88fce 100644
--- a/apps/client/public/locales/zh-CN/translation.json
+++ b/apps/client/public/locales/zh-CN/translation.json
@@ -75,7 +75,6 @@
"Full access": "完全访问",
"Full page width": "全页宽度",
"Full width": "全宽",
- "View headings": "查看标题",
"Show article title menu.": "显示文章标题菜单",
"General": "常规",
"Group": "群组",
@@ -172,10 +171,8 @@
"Successfully restored": "恢复成功",
"System settings": "系统设置",
"Theme": "主题",
- "On this page": "他是这个页面",
"To change your email, you have to enter your password and new email.": "要更改您的电子邮箱,您需要输入密码和新的电子邮箱地址。",
"Toggle full page width": "切换全页宽度",
- "Toggle view headings menu": "切换查看广告菜单",
"Unable to import pages. Please try again.": "无法导入页面。请重试。",
"untitled": "无标题",
"Untitled": "无标题",
From 276ececbf2ad3d4d0287013278c4039b21bbc6cf Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 8 Apr 2025 17:06:32 +0100
Subject: [PATCH 02/63] cleanup
---
apps/client/public/locales/zh-CN/translation.json | 1 -
1 file changed, 1 deletion(-)
diff --git a/apps/client/public/locales/zh-CN/translation.json b/apps/client/public/locales/zh-CN/translation.json
index bbe88fce..31788ae2 100644
--- a/apps/client/public/locales/zh-CN/translation.json
+++ b/apps/client/public/locales/zh-CN/translation.json
@@ -75,7 +75,6 @@
"Full access": "完全访问",
"Full page width": "全页宽度",
"Full width": "全宽",
- "Show article title menu.": "显示文章标题菜单",
"General": "常规",
"Group": "群组",
"Group description": "群组描述",
From ee30d9d0f2b908f09b686d7368df0b2752081231 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 8 Apr 2025 17:10:08 +0100
Subject: [PATCH 03/63] New Crowdin updates (#1003)
* New translations translation.json (French)
* New translations translation.json (Italian)
* New translations translation.json (Japanese)
* New translations translation.json (Korean)
* New translations translation.json (Russian)
* New translations translation.json (Chinese Simplified)
* New translations translation.json (English)
* New translations translation.json (Portuguese, Brazilian)
---
.../public/locales/en-US/translation.json | 13 +-------
.../public/locales/fr-FR/translation.json | 2 +-
.../public/locales/it-IT/translation.json | 10 +++---
.../public/locales/ja-JP/translation.json | 10 +++---
.../public/locales/ko-KR/translation.json | 26 +++++++--------
.../public/locales/pt-BR/translation.json | 26 +++++++--------
.../public/locales/ru-RU/translation.json | 32 +++++++++----------
.../public/locales/zh-CN/translation.json | 26 +++++++--------
8 files changed, 67 insertions(+), 78 deletions(-)
diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json
index 3cd9fae6..b69d0b28 100644
--- a/apps/client/public/locales/en-US/translation.json
+++ b/apps/client/public/locales/en-US/translation.json
@@ -351,16 +351,5 @@
"Created at: {{time}}": "Created at: {{time}}",
"Edited by {{name}} {{time}}": "Edited by {{name}} {{time}}",
"Word count: {{wordCount}}": "Word count: {{wordCount}}",
- "Character count: {{characterCount}}": "Character count: {{characterCount}}",
- "New update": "New update",
- "{{latestVersion}} is available": "{{latestVersion}} is available",
- "Delete member": "Delete member",
- "Member deleted successfully": "Member deleted successfully",
- "Are you sure you want to delete this workspace member? This action is irreversible.": "Are you sure you want to delete this workspace member? This action is irreversible."
- "Move": "Move",
- "Move page": "Move page",
- "Move page to a different space.": "Move page to a different space.",
- "Real-time editor connection lost. Retrying...": "Real-time editor connection lost. Retrying...",
- "Table of contents": "Table of contents",
- "Add headings (H1, H2, H3) to generate a table of contents.": "Add headings (H1, H2, H3) to generate a table of contents."
+ "Character count: {{characterCount}}": "Character count: {{characterCount}}"
}
diff --git a/apps/client/public/locales/fr-FR/translation.json b/apps/client/public/locales/fr-FR/translation.json
index 1d750d40..9a5bf561 100644
--- a/apps/client/public/locales/fr-FR/translation.json
+++ b/apps/client/public/locales/fr-FR/translation.json
@@ -21,7 +21,7 @@
"Can view": "Peut voir",
"Can view pages in space but not edit.": "Peut voir les pages dans l'espace mais ne peut pas les modifier.",
"Cancel": "Annuler",
- "Change email": "Changer l'email",
+ "Change email": "Changer le courriel",
"Change password": "Changer le mot de passe",
"Change photo": "Changer la photo",
"Choose a role": "Choisir un rôle",
diff --git a/apps/client/public/locales/it-IT/translation.json b/apps/client/public/locales/it-IT/translation.json
index 5712088f..04e866fb 100644
--- a/apps/client/public/locales/it-IT/translation.json
+++ b/apps/client/public/locales/it-IT/translation.json
@@ -347,9 +347,9 @@
"Members added successfully": "Membri aggiunti con successo",
"Member removed successfully": "Membro rimosso con successo",
"Member role updated successfully": "Ruolo del membro aggiornato con successo",
- "Created by: {{creatorName}} ": "Created by: {{creatorName}} ",
- "Created at: {{time}}": "Created at: {{time}}",
- "Edited by {{name}} {{time}}": "Edited by {{name}} {{time}}",
- "Word count: {{wordCount}}": "Word count: {{wordCount}}",
- "Character count: {{characterCount}}": "Character count: {{characterCount}}"
+ "Created by: {{creatorName}} ": "Creato da: {{creatorName}} ",
+ "Created at: {{time}}": "Creato il: {{time}}",
+ "Edited by {{name}} {{time}}": "Modificato da {{name}} il {{time}}",
+ "Word count: {{wordCount}}": "Conteggio parole: {{wordCount}}",
+ "Character count: {{characterCount}}": "Conteggio caratteri: {{characterCount}}"
}
diff --git a/apps/client/public/locales/ja-JP/translation.json b/apps/client/public/locales/ja-JP/translation.json
index a4194823..4d066912 100644
--- a/apps/client/public/locales/ja-JP/translation.json
+++ b/apps/client/public/locales/ja-JP/translation.json
@@ -347,9 +347,9 @@
"Members added successfully": "メンバーを追加しました",
"Member removed successfully": "メンバーが削除されました",
"Member role updated successfully": "メンバーのロールを更新しました",
- "Created by: {{creatorName}} ": "Created by: {{creatorName}} ",
- "Created at: {{time}}": "Created at: {{time}}",
- "Edited by {{name}} {{time}}": "Edited by {{name}} {{time}}",
- "Word count: {{wordCount}}": "Word count: {{wordCount}}",
- "Character count: {{characterCount}}": "Character count: {{characterCount}}"
+ "Created by: {{creatorName}} ": "作成者: {{creatorName}} ",
+ "Created at: {{time}}": "が作成しました:{{time}}",
+ "Edited by {{name}} {{time}}": "最終編集: {{name}} {{time}}",
+ "Word count: {{wordCount}}": "ワード数: {{wordCount}}",
+ "Character count: {{characterCount}}": "文字数: {{characterCount}}"
}
diff --git a/apps/client/public/locales/ko-KR/translation.json b/apps/client/public/locales/ko-KR/translation.json
index fab01a51..9ca4b572 100644
--- a/apps/client/public/locales/ko-KR/translation.json
+++ b/apps/client/public/locales/ko-KR/translation.json
@@ -148,7 +148,7 @@
"Select role to assign to all invited members": "초대된 모든 사용자에게 할당할 역할 선택",
"Select theme": "배경 선택",
"Send invitation": "초대 보내기",
- "Invitation sent": "Invitation sent",
+ "Invitation sent": "초대 발송 완료",
"Settings": "설정",
"Setup workspace": "Workspace 설정",
"Sign In": "로그인",
@@ -245,7 +245,7 @@
"Align left": "왼쪽 정렬",
"Align right": "오른쪽 정렬",
"Align center": "가운데 정렬",
- "Justify": "Justify",
+ "Justify": "정렬",
"Merge cells": "셀 병합",
"Split cell": "셀 분할",
"Delete column": "열 삭제",
@@ -341,15 +341,15 @@
"Names do not match": "이름이 일치하지 않습니다",
"Today, {{time}}": "오늘, {{time}}",
"Yesterday, {{time}}": "어제, {{time}}",
- "Space created successfully": "Space created successfully",
- "Space updated successfully": "Space updated successfully",
- "Space deleted successfully": "Space deleted successfully",
- "Members added successfully": "Members added successfully",
- "Member removed successfully": "Member removed successfully",
- "Member role updated successfully": "Member role updated successfully",
- "Created by: {{creatorName}} ": "Created by: {{creatorName}} ",
- "Created at: {{time}}": "Created at: {{time}}",
- "Edited by {{name}} {{time}}": "Edited by {{name}} {{time}}",
- "Word count: {{wordCount}}": "Word count: {{wordCount}}",
- "Character count: {{characterCount}}": "Character count: {{characterCount}}"
+ "Space created successfully": "공간 생성 완료",
+ "Space updated successfully": "공간이 성공적으로 업데이트되었습니다",
+ "Space deleted successfully": "스페이스 삭제 완료",
+ "Members added successfully": "회원 추가 완료",
+ "Member removed successfully": "멤버가 성공적으로 제거되었습니다",
+ "Member role updated successfully": "회원 역할이 성공적으로 업데이트되었습니다",
+ "Created by: {{creatorName}} ": "작성자: {{creatorName}} ",
+ "Created at: {{time}}": "생성 날짜: {{time}}",
+ "Edited by {{name}} {{time}}": "{{name}}님이 편집함 {{time}}",
+ "Word count: {{wordCount}}": "단어 수: {{wordCount}}",
+ "Character count: {{characterCount}}": "문자 수: {{characterCount}}"
}
diff --git a/apps/client/public/locales/pt-BR/translation.json b/apps/client/public/locales/pt-BR/translation.json
index 26535914..18a286a7 100644
--- a/apps/client/public/locales/pt-BR/translation.json
+++ b/apps/client/public/locales/pt-BR/translation.json
@@ -148,7 +148,7 @@
"Select role to assign to all invited members": "Selecione a função para atribuir a todos os membros convidados",
"Select theme": "Selecionar tema",
"Send invitation": "Enviar convite",
- "Invitation sent": "Invitation sent",
+ "Invitation sent": "Convite enviado",
"Settings": "Configurações",
"Setup workspace": "Configurar workspace",
"Sign In": "Entrar",
@@ -245,7 +245,7 @@
"Align left": "Alinhar à esquerda",
"Align right": "Alinhar à direita",
"Align center": "Alinhar ao centro",
- "Justify": "Justify",
+ "Justify": "Justificar",
"Merge cells": "Mesclar células",
"Split cell": "Dividir célula",
"Delete column": "Excluir coluna",
@@ -341,15 +341,15 @@
"Names do not match": "Os nomes não coincidem",
"Today, {{time}}": "Hoje, {{time}}",
"Yesterday, {{time}}": "Ontem, {{time}}",
- "Space created successfully": "Space created successfully",
- "Space updated successfully": "Space updated successfully",
- "Space deleted successfully": "Space deleted successfully",
- "Members added successfully": "Members added successfully",
- "Member removed successfully": "Member removed successfully",
- "Member role updated successfully": "Member role updated successfully",
- "Created by: {{creatorName}} ": "Created by: {{creatorName}} ",
- "Created at: {{time}}": "Created at: {{time}}",
- "Edited by {{name}} {{time}}": "Edited by {{name}} {{time}}",
- "Word count: {{wordCount}}": "Word count: {{wordCount}}",
- "Character count: {{characterCount}}": "Character count: {{characterCount}}"
+ "Space created successfully": "Espaço criado com sucesso",
+ "Space updated successfully": "Espaço atualizado com sucesso",
+ "Space deleted successfully": "Espaço excluído com sucesso",
+ "Members added successfully": "Membros adicionados com sucesso",
+ "Member removed successfully": "Membro removido com sucesso",
+ "Member role updated successfully": "Função do membro atualizada com sucesso",
+ "Created by: {{creatorName}} ": "Criado por: {{creatorName}} ",
+ "Created at: {{time}}": "Criado em: {{time}}",
+ "Edited by {{name}} {{time}}": "Editado por {{name}} {{time}}",
+ "Word count: {{wordCount}}": "Contagem de palavras: {{wordCount}}",
+ "Character count: {{characterCount}}": "Contagem de caracteres: {{characterCount}}"
}
diff --git a/apps/client/public/locales/ru-RU/translation.json b/apps/client/public/locales/ru-RU/translation.json
index 257b64db..8b692812 100644
--- a/apps/client/public/locales/ru-RU/translation.json
+++ b/apps/client/public/locales/ru-RU/translation.json
@@ -148,7 +148,7 @@
"Select role to assign to all invited members": "Выберите роль для всех приглашённых участников",
"Select theme": "Выберите тему",
"Send invitation": "Отправить приглашение",
- "Invitation sent": "Invitation sent",
+ "Invitation sent": "Приглашение отправлено",
"Settings": "Настройки",
"Setup workspace": "Настроить рабочее пространство",
"Sign In": "Вход",
@@ -245,7 +245,7 @@
"Align left": "По левому краю",
"Align right": "По правому краю",
"Align center": "По центру",
- "Justify": "Justify",
+ "Justify": "По ширине",
"Merge cells": "Объединить ячейки",
"Split cell": "Разделить ячейку",
"Delete column": "Удалить столбец",
@@ -331,25 +331,25 @@
"Insert math equation": "Вставить математическое выражение",
"Mermaid diagram": "Диаграмма Mermaid",
"Insert mermaid diagram": "Вставить диаграмму Mermaid",
- "Insert and design Drawio diagrams": "Вставьте и редактируйте диаграммы Draw.io",
+ "Insert and design Drawio diagrams": "Вставить и рисовать диаграммы Draw.io",
"Insert current date": "Вставить текущую дату",
- "Draw and sketch excalidraw diagrams": "Создайте и рисуйте диаграммы Excalidraw",
+ "Draw and sketch excalidraw diagrams": "Вставить и рисовать диаграммы Excalidraw",
"Multiple": "Несколько",
"Heading {{level}}": "Заголовок {{level}}",
"Toggle title": "Переключить заголовок",
- "Write anything. Enter \"/\" for commands": "Пишите что угодно. Введите \"/\" для выбора команд",
+ "Write anything. Enter \"/\" for commands": "Начните писать. Введите \"/\" для списка команд",
"Names do not match": "Названия не совпадают",
"Today, {{time}}": "Сегодня, {{time}}",
"Yesterday, {{time}}": "Вчера, {{time}}",
- "Space created successfully": "Space created successfully",
- "Space updated successfully": "Space updated successfully",
- "Space deleted successfully": "Space deleted successfully",
- "Members added successfully": "Members added successfully",
- "Member removed successfully": "Member removed successfully",
- "Member role updated successfully": "Member role updated successfully",
- "Created by: {{creatorName}} ": "Created by: {{creatorName}} ",
- "Created at: {{time}}": "Created at: {{time}}",
- "Edited by {{name}} {{time}}": "Edited by {{name}} {{time}}",
- "Word count: {{wordCount}}": "Word count: {{wordCount}}",
- "Character count: {{characterCount}}": "Character count: {{characterCount}}"
+ "Space created successfully": "Пространство успешно создано",
+ "Space updated successfully": "Пространство успешно обновлено",
+ "Space deleted successfully": "Пространство успешно удалено",
+ "Members added successfully": "Участники успешно добавлены",
+ "Member removed successfully": "Участник успешно удален",
+ "Member role updated successfully": "Роль участника успешно обновлена",
+ "Created by: {{creatorName}} ": "Автор: {{creatorName}} ",
+ "Created at: {{time}}": "Дата создания: {{time}}",
+ "Edited by {{name}} {{time}}": "Изменено {{name}} {{time}}",
+ "Word count: {{wordCount}}": "Количество слов: {{wordCount}}",
+ "Character count: {{characterCount}}": "Количество символов: {{characterCount}}"
}
diff --git a/apps/client/public/locales/zh-CN/translation.json b/apps/client/public/locales/zh-CN/translation.json
index 31788ae2..fb8211ea 100644
--- a/apps/client/public/locales/zh-CN/translation.json
+++ b/apps/client/public/locales/zh-CN/translation.json
@@ -148,7 +148,7 @@
"Select role to assign to all invited members": "选择要分配给所有被邀请成员的角色",
"Select theme": "选择主题",
"Send invitation": "发送邀请",
- "Invitation sent": "Invitation sent",
+ "Invitation sent": "邀请邮件已发送",
"Settings": "设置",
"Setup workspace": "设置工作空间",
"Sign In": "登录",
@@ -245,7 +245,7 @@
"Align left": "靠左对齐",
"Align right": "靠右对齐",
"Align center": "居中对齐",
- "Justify": "Justify",
+ "Justify": "两端对齐",
"Merge cells": "合并单元格",
"Split cell": "分割单元格",
"Delete column": "删除整列",
@@ -341,15 +341,15 @@
"Names do not match": "名称不匹配",
"Today, {{time}}": "今天,{{time}}",
"Yesterday, {{time}}": "昨天,{{time}}",
- "Space created successfully": "Space created successfully",
- "Space updated successfully": "Space updated successfully",
- "Space deleted successfully": "Space deleted successfully",
- "Members added successfully": "Members added successfully",
- "Member removed successfully": "Member removed successfully",
- "Member role updated successfully": "Member role updated successfully",
- "Created by: {{creatorName}} ": "Created by: {{creatorName}} ",
- "Created at: {{time}}": "Created at: {{time}}",
- "Edited by {{name}} {{time}}": "Edited by {{name}} {{time}}",
- "Word count: {{wordCount}}": "Word count: {{wordCount}}",
- "Character count: {{characterCount}}": "Character count: {{characterCount}}"
+ "Space created successfully": "空间创建成功",
+ "Space updated successfully": "空间更新成功",
+ "Space deleted successfully": "空间已成功删除",
+ "Members added successfully": "成员添加成功",
+ "Member removed successfully": "成员移除成功",
+ "Member role updated successfully": "成员角色更新成功",
+ "Created by: {{creatorName}} ": "创建者:{{creatorName}} ",
+ "Created at: {{time}}": "创建于:{{time}}",
+ "Edited by {{name}} {{time}}": "由{{name}} 编辑于 {{time}}",
+ "Word count: {{wordCount}}": "字数:{{wordCount}}",
+ "Character count: {{characterCount}}": "字符数:{{characterCount}}"
}
From cd10365f716f582ab885b1bbf167fabe268cb6f0 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 8 Apr 2025 17:10:48 +0100
Subject: [PATCH 04/63] new translations
---
apps/client/public/locales/en-US/translation.json | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json
index b69d0b28..3cd9fae6 100644
--- a/apps/client/public/locales/en-US/translation.json
+++ b/apps/client/public/locales/en-US/translation.json
@@ -351,5 +351,16 @@
"Created at: {{time}}": "Created at: {{time}}",
"Edited by {{name}} {{time}}": "Edited by {{name}} {{time}}",
"Word count: {{wordCount}}": "Word count: {{wordCount}}",
- "Character count: {{characterCount}}": "Character count: {{characterCount}}"
+ "Character count: {{characterCount}}": "Character count: {{characterCount}}",
+ "New update": "New update",
+ "{{latestVersion}} is available": "{{latestVersion}} is available",
+ "Delete member": "Delete member",
+ "Member deleted successfully": "Member deleted successfully",
+ "Are you sure you want to delete this workspace member? This action is irreversible.": "Are you sure you want to delete this workspace member? This action is irreversible."
+ "Move": "Move",
+ "Move page": "Move page",
+ "Move page to a different space.": "Move page to a different space.",
+ "Real-time editor connection lost. Retrying...": "Real-time editor connection lost. Retrying...",
+ "Table of contents": "Table of contents",
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Add headings (H1, H2, H3) to generate a table of contents."
}
From 117c7049ff57fb64bff1ef62c5871f12cab31fb8 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 8 Apr 2025 17:15:09 +0100
Subject: [PATCH 05/63] fix
---
apps/client/public/locales/en-US/translation.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json
index 3cd9fae6..bbc6a702 100644
--- a/apps/client/public/locales/en-US/translation.json
+++ b/apps/client/public/locales/en-US/translation.json
@@ -356,7 +356,7 @@
"{{latestVersion}} is available": "{{latestVersion}} is available",
"Delete member": "Delete member",
"Member deleted successfully": "Member deleted successfully",
- "Are you sure you want to delete this workspace member? This action is irreversible.": "Are you sure you want to delete this workspace member? This action is irreversible."
+ "Are you sure you want to delete this workspace member? This action is irreversible.": "Are you sure you want to delete this workspace member? This action is irreversible.",
"Move": "Move",
"Move page": "Move page",
"Move page to a different space.": "Move page to a different space.",
From a9f370660b4488d48fdeffdeadf885d21a936346 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 8 Apr 2025 17:28:33 +0100
Subject: [PATCH 06/63] New Crowdin updates (#1005)
* New translations translation.json (French)
* New translations translation.json (Spanish)
* New translations translation.json (German)
* New translations translation.json (Italian)
* New translations translation.json (Japanese)
* New translations translation.json (Korean)
* New translations translation.json (Dutch)
* New translations translation.json (Russian)
* New translations translation.json (Chinese Simplified)
* New translations translation.json (Portuguese, Brazilian)
* New translations translation.json (French)
* New translations translation.json (Spanish)
* New translations translation.json (German)
* New translations translation.json (Italian)
* New translations translation.json (Japanese)
* New translations translation.json (Korean)
* New translations translation.json (Dutch)
* New translations translation.json (Russian)
* New translations translation.json (Chinese Simplified)
* New translations translation.json (Portuguese, Brazilian)
---
apps/client/public/locales/de-DE/translation.json | 13 ++++++++++++-
apps/client/public/locales/es-ES/translation.json | 13 ++++++++++++-
apps/client/public/locales/fr-FR/translation.json | 13 ++++++++++++-
apps/client/public/locales/it-IT/translation.json | 13 ++++++++++++-
apps/client/public/locales/ja-JP/translation.json | 13 ++++++++++++-
apps/client/public/locales/ko-KR/translation.json | 13 ++++++++++++-
apps/client/public/locales/nl-NL/translation.json | 13 ++++++++++++-
apps/client/public/locales/pt-BR/translation.json | 13 ++++++++++++-
apps/client/public/locales/ru-RU/translation.json | 13 ++++++++++++-
apps/client/public/locales/zh-CN/translation.json | 13 ++++++++++++-
10 files changed, 120 insertions(+), 10 deletions(-)
diff --git a/apps/client/public/locales/de-DE/translation.json b/apps/client/public/locales/de-DE/translation.json
index 787d1ee5..294bfa79 100644
--- a/apps/client/public/locales/de-DE/translation.json
+++ b/apps/client/public/locales/de-DE/translation.json
@@ -351,5 +351,16 @@
"Created at: {{time}}": "Erstellt am: {{time}}",
"Edited by {{name}} {{time}}": "Bearbeitet von {{name}} {{time}}",
"Word count: {{wordCount}}": "Wortanzahl: {{wordCount}}",
- "Character count: {{characterCount}}": "Zeichenzahl: {{characterCount}}"
+ "Character count: {{characterCount}}": "Zeichenzahl: {{characterCount}}",
+ "New update": "Neues Update",
+ "{{latestVersion}} is available": "{{latestVersion}} ist verfügbar",
+ "Delete member": "Mitglied löschen",
+ "Member deleted successfully": "Mitglied erfolgreich gelöscht",
+ "Are you sure you want to delete this workspace member? This action is irreversible.": "Sind Sie sicher, dass Sie dieses Arbeitsbereichsmitglied löschen möchten? Diese Aktion ist unwiderruflich.",
+ "Move": "Verschieben",
+ "Move page": "Seite verschieben",
+ "Move page to a different space.": "Seite in einen anderen Bereich verschieben.",
+ "Real-time editor connection lost. Retrying...": "Echtzeit-Editor-Verbindung verloren. Wiederholen...",
+ "Table of contents": "Inhaltsverzeichnis",
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Fügen Sie Überschriften (H1, H2, H3) hinzu, um ein Inhaltsverzeichnis zu erstellen."
}
diff --git a/apps/client/public/locales/es-ES/translation.json b/apps/client/public/locales/es-ES/translation.json
index 0bc40f49..f17d13d9 100644
--- a/apps/client/public/locales/es-ES/translation.json
+++ b/apps/client/public/locales/es-ES/translation.json
@@ -351,5 +351,16 @@
"Created at: {{time}}": "Creado a: {{time}}",
"Edited by {{name}} {{time}}": "Editado por {{name}} {{time}}",
"Word count: {{wordCount}}": "Conteo de palabras: {{wordCount}}",
- "Character count: {{characterCount}}": "Recuento de caracteres: {{characterCount}}"
+ "Character count: {{characterCount}}": "Recuento de caracteres: {{characterCount}}",
+ "New update": "Nueva actualización",
+ "{{latestVersion}} is available": "{{latestVersion}} está disponible",
+ "Delete member": "Eliminar miembro",
+ "Member deleted successfully": "Miembro eliminado con éxito",
+ "Are you sure you want to delete this workspace member? This action is irreversible.": "¿Está seguro que desea eliminar este miembro del área de trabajo? Esta acción es irreversible.",
+ "Move": "Mover",
+ "Move page": "Mover página",
+ "Move page to a different space.": "Mover página a un espacio diferente.",
+ "Real-time editor connection lost. Retrying...": "Conexión del editor en tiempo real perdida. Reintentando...",
+ "Table of contents": "Índice de contenidos",
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Añadir encabezados (H1, H2, H3) para generar un índice de contenidos."
}
diff --git a/apps/client/public/locales/fr-FR/translation.json b/apps/client/public/locales/fr-FR/translation.json
index 9a5bf561..408ff420 100644
--- a/apps/client/public/locales/fr-FR/translation.json
+++ b/apps/client/public/locales/fr-FR/translation.json
@@ -351,5 +351,16 @@
"Created at: {{time}}": "Créé à : {{time}}",
"Edited by {{name}} {{time}}": "Modifié par {{name}} {{time}}",
"Word count: {{wordCount}}": "Nombre de mots : {{wordCount}}",
- "Character count: {{characterCount}}": "Nombre de caractères : {{characterCount}}"
+ "Character count: {{characterCount}}": "Nombre de caractères : {{characterCount}}",
+ "New update": "Nouvelle mise à jour",
+ "{{latestVersion}} is available": "{{latestVersion}} est disponible",
+ "Delete member": "Supprimer le membre",
+ "Member deleted successfully": "Membre supprimé avec succès",
+ "Are you sure you want to delete this workspace member? This action is irreversible.": "Êtes-vous sûr de vouloir supprimer ce membre de l'espace de travail? Cette action est irréversible.",
+ "Move": "Déplacer",
+ "Move page": "Déplacer la page",
+ "Move page to a different space.": "Déplacer la page vers un autre espace.",
+ "Real-time editor connection lost. Retrying...": "Connexion avec l'éditeur en temps réel perdue. Nouvelle tentative...",
+ "Table of contents": "",
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Ajoutez des titres (H1, H2, H3) pour générer une table des matières."
}
diff --git a/apps/client/public/locales/it-IT/translation.json b/apps/client/public/locales/it-IT/translation.json
index 04e866fb..b92377c7 100644
--- a/apps/client/public/locales/it-IT/translation.json
+++ b/apps/client/public/locales/it-IT/translation.json
@@ -351,5 +351,16 @@
"Created at: {{time}}": "Creato il: {{time}}",
"Edited by {{name}} {{time}}": "Modificato da {{name}} il {{time}}",
"Word count: {{wordCount}}": "Conteggio parole: {{wordCount}}",
- "Character count: {{characterCount}}": "Conteggio caratteri: {{characterCount}}"
+ "Character count: {{characterCount}}": "Conteggio caratteri: {{characterCount}}",
+ "New update": "Nuovo aggiornamento",
+ "{{latestVersion}} is available": "{{latestVersion}} è disponibile",
+ "Delete member": "Elimina membro",
+ "Member deleted successfully": "Membro eliminato con successo",
+ "Are you sure you want to delete this workspace member? This action is irreversible.": "Sei sicuro di voler eliminare questo membro del workspace? Questa azione è irreversibile.",
+ "Move": "Sposta",
+ "Move page": "Sposta pagina",
+ "Move page to a different space.": "Sposta la pagina in un altro spazio.",
+ "Real-time editor connection lost. Retrying...": "Connessione all'editor in tempo reale persa. Riprovo...",
+ "Table of contents": "Indice dei contenuti",
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Aggiungi intestazioni (H1, H2, H3) per generare un sommario."
}
diff --git a/apps/client/public/locales/ja-JP/translation.json b/apps/client/public/locales/ja-JP/translation.json
index 4d066912..cc6141c4 100644
--- a/apps/client/public/locales/ja-JP/translation.json
+++ b/apps/client/public/locales/ja-JP/translation.json
@@ -351,5 +351,16 @@
"Created at: {{time}}": "が作成しました:{{time}}",
"Edited by {{name}} {{time}}": "最終編集: {{name}} {{time}}",
"Word count: {{wordCount}}": "ワード数: {{wordCount}}",
- "Character count: {{characterCount}}": "文字数: {{characterCount}}"
+ "Character count: {{characterCount}}": "文字数: {{characterCount}}",
+ "New update": "新規更新",
+ "{{latestVersion}} is available": "{{latestVersion}}は利用可能です",
+ "Delete member": "メンバーを削除する",
+ "Member deleted successfully": "メンバーが削除されました",
+ "Are you sure you want to delete this workspace member? This action is irreversible.": "ワークスペースメンバーを削除してもよろしいですか?この操作は元に戻せません。",
+ "Move": "移動",
+ "Move page": "ページを移動",
+ "Move page to a different space.": "ページを別のスペースに移動します。",
+ "Real-time editor connection lost. Retrying...": "リアルタイムエディターの接続が失われました。再試行しています…",
+ "Table of contents": "目次",
+ "Add headings (H1, H2, H3) to generate a table of contents.": "見出し(H1、H2、H3)を追加して目次を生成します。"
}
diff --git a/apps/client/public/locales/ko-KR/translation.json b/apps/client/public/locales/ko-KR/translation.json
index 9ca4b572..1e87c62e 100644
--- a/apps/client/public/locales/ko-KR/translation.json
+++ b/apps/client/public/locales/ko-KR/translation.json
@@ -351,5 +351,16 @@
"Created at: {{time}}": "생성 날짜: {{time}}",
"Edited by {{name}} {{time}}": "{{name}}님이 편집함 {{time}}",
"Word count: {{wordCount}}": "단어 수: {{wordCount}}",
- "Character count: {{characterCount}}": "문자 수: {{characterCount}}"
+ "Character count: {{characterCount}}": "문자 수: {{characterCount}}",
+ "New update": "새로운 업데이트",
+ "{{latestVersion}} is available": "{{latestVersion}}이 사용 가능합니다",
+ "Delete member": "회원 삭제",
+ "Member deleted successfully": "멤버가 성공적으로 제거되었습니다",
+ "Are you sure you want to delete this workspace member? This action is irreversible.": "이 워크스페이스 멤버를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
+ "Move": "이동",
+ "Move page": "페이지 이동",
+ "Move page to a different space.": "페이지를 다른 공간으로 이동합니다.",
+ "Real-time editor connection lost. Retrying...": "실시간 편집기 연결이 끊어졌습니다. 재시도 중...",
+ "Table of contents": "목차",
+ "Add headings (H1, H2, H3) to generate a table of contents.": "목차를 생성하려면 제목 (H1, H2, H3)을 추가하세요."
}
diff --git a/apps/client/public/locales/nl-NL/translation.json b/apps/client/public/locales/nl-NL/translation.json
index 27e1ba84..dba2ee9a 100644
--- a/apps/client/public/locales/nl-NL/translation.json
+++ b/apps/client/public/locales/nl-NL/translation.json
@@ -351,5 +351,16 @@
"Created at: {{time}}": "Aangemaakt op: {{time}}",
"Edited by {{name}} {{time}}": "Bewerkt door {{name}} {{time}}",
"Word count: {{wordCount}}": "Aantal woorden: {{wordCount}}",
- "Character count: {{characterCount}}": "Aantal tekens: {{characterCount}}"
+ "Character count: {{characterCount}}": "Aantal tekens: {{characterCount}}",
+ "New update": "Nieuwe update",
+ "{{latestVersion}} is available": "{{latestVersion}} is beschikbaar",
+ "Delete member": "Verwijder lid",
+ "Member deleted successfully": "Lid succesvol verwijderd",
+ "Are you sure you want to delete this workspace member? This action is irreversible.": "Weet u zeker dat u dit lid van de werkruimte wilt verwijderen? Deze actie kan niet ongedaan gemaakt worden.",
+ "Move": "Verplaatsen",
+ "Move page": "Pagina verplaatsen",
+ "Move page to a different space.": "Verplaats pagina naar een andere ruimte.",
+ "Real-time editor connection lost. Retrying...": "Realtime editorverbinding verloren. Opnieuw proberen...",
+ "Table of contents": "Inhoudsopgave",
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Voeg koppen (H1, H2, H3) toe om een inhoudsopgave te genereren."
}
diff --git a/apps/client/public/locales/pt-BR/translation.json b/apps/client/public/locales/pt-BR/translation.json
index 18a286a7..526d298f 100644
--- a/apps/client/public/locales/pt-BR/translation.json
+++ b/apps/client/public/locales/pt-BR/translation.json
@@ -351,5 +351,16 @@
"Created at: {{time}}": "Criado em: {{time}}",
"Edited by {{name}} {{time}}": "Editado por {{name}} {{time}}",
"Word count: {{wordCount}}": "Contagem de palavras: {{wordCount}}",
- "Character count: {{characterCount}}": "Contagem de caracteres: {{characterCount}}"
+ "Character count: {{characterCount}}": "Contagem de caracteres: {{characterCount}}",
+ "New update": "Nova atualização",
+ "{{latestVersion}} is available": "{{latestVersion}} está disponível",
+ "Delete member": "Excluir membro",
+ "Member deleted successfully": "Membro removido com sucesso",
+ "Are you sure you want to delete this workspace member? This action is irreversible.": "Você tem certeza que deseja deletar este membro do workspace? Esta ação é irreversível.",
+ "Move": "Mover",
+ "Move page": "Mover página",
+ "Move page to a different space.": "Mover página para um espaço diferente.",
+ "Real-time editor connection lost. Retrying...": "Conexão do editor em tempo real perdida. Tentando novamente...",
+ "Table of contents": "Tabela de conteúdos",
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Adicionar títulos (H1, H2, H3) para gerar uma tabela de conteúdo."
}
diff --git a/apps/client/public/locales/ru-RU/translation.json b/apps/client/public/locales/ru-RU/translation.json
index 8b692812..dce96d80 100644
--- a/apps/client/public/locales/ru-RU/translation.json
+++ b/apps/client/public/locales/ru-RU/translation.json
@@ -351,5 +351,16 @@
"Created at: {{time}}": "Дата создания: {{time}}",
"Edited by {{name}} {{time}}": "Изменено {{name}} {{time}}",
"Word count: {{wordCount}}": "Количество слов: {{wordCount}}",
- "Character count: {{characterCount}}": "Количество символов: {{characterCount}}"
+ "Character count: {{characterCount}}": "Количество символов: {{characterCount}}",
+ "New update": "Новое обновление",
+ "{{latestVersion}} is available": "Доступна новая версия {{latestVersion}}",
+ "Delete member": "Удалить участника",
+ "Member deleted successfully": "Участник успешно удален",
+ "Are you sure you want to delete this workspace member? This action is irreversible.": "Вы уверены, что хотите удалить этого участника рабочей области? Это действие необратимо.",
+ "Move": "Переместить",
+ "Move page": "Переместить страницу",
+ "Move page to a different space.": "Переместите страницу в другое пространство.",
+ "Real-time editor connection lost. Retrying...": "Соединение с редактором в реальном времени потеряно. Повторная попытка...",
+ "Table of contents": "Содержание",
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Добавьте заголовки (H1, H2, H3), чтобы создать оглавление."
}
diff --git a/apps/client/public/locales/zh-CN/translation.json b/apps/client/public/locales/zh-CN/translation.json
index fb8211ea..9763c602 100644
--- a/apps/client/public/locales/zh-CN/translation.json
+++ b/apps/client/public/locales/zh-CN/translation.json
@@ -351,5 +351,16 @@
"Created at: {{time}}": "创建于:{{time}}",
"Edited by {{name}} {{time}}": "由{{name}} 编辑于 {{time}}",
"Word count: {{wordCount}}": "字数:{{wordCount}}",
- "Character count: {{characterCount}}": "字符数:{{characterCount}}"
+ "Character count: {{characterCount}}": "字符数:{{characterCount}}",
+ "New update": "新更新",
+ "{{latestVersion}} is available": "{{latestVersion}} 已经可以使用",
+ "Delete member": "删除成员",
+ "Member deleted successfully": "成员删除成功",
+ "Are you sure you want to delete this workspace member? This action is irreversible.": "您确定要删除此工作区成员吗?此操作不可逆。",
+ "Move": "移动",
+ "Move page": "移动页面",
+ "Move page to a different space.": "将页面移动到不同的空间。",
+ "Real-time editor connection lost. Retrying...": "实时编辑器连接丢失。重试中……",
+ "Table of contents": "目录",
+ "Add headings (H1, H2, H3) to generate a table of contents.": "添加标题(H1,H2,H3)以生成目录。"
}
From 7f7f2bccd032a08e796492cbf70692684502c3ae Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 9 Apr 2025 15:37:18 +0100
Subject: [PATCH 07/63] fix toggle node in non-edit mode
---
packages/editor-ext/src/lib/details/details.ts | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/packages/editor-ext/src/lib/details/details.ts b/packages/editor-ext/src/lib/details/details.ts
index 8a05f21c..1be9accf 100644
--- a/packages/editor-ext/src/lib/details/details.ts
+++ b/packages/editor-ext/src/lib/details/details.ts
@@ -111,6 +111,7 @@ export const Details = Node.create({
if (updatedNode.type !== this.type) {
return false;
}
+ if (!editor.isEditable) return true;
if (updatedNode.attrs.open) {
dom.setAttribute("open", "true");
} else {
@@ -132,9 +133,10 @@ export const Details = Node.create({
}
const slice = state.doc.slice(range.start, range.end);
-
- if(slice.content.firstChild.type.name === "detailsSummary") return false;
-
+
+ if (slice.content.firstChild.type.name === "detailsSummary")
+ return false;
+
if (
!state.schema.nodes.detailsContent.contentMatch.matchFragment(
slice.content,
From 4aa5d7e326f4c986369c5914a939694b30e23ba2 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 9 Apr 2025 15:42:29 +0100
Subject: [PATCH 08/63] hide history action menu for can-view role (#1001)
---
.../page-history/components/history-list.tsx | 46 +++++++++++++------
1 file changed, 32 insertions(+), 14 deletions(-)
diff --git a/apps/client/src/features/page-history/components/history-list.tsx b/apps/client/src/features/page-history/components/history-list.tsx
index c21fb3b7..af178eac 100644
--- a/apps/client/src/features/page-history/components/history-list.tsx
+++ b/apps/client/src/features/page-history/components/history-list.tsx
@@ -17,6 +17,13 @@ import {
import { modals } from "@mantine/modals";
import { notifications } from "@mantine/notifications";
import { useTranslation } from "react-i18next";
+import { useSpaceAbility } from "@/features/space/permissions/use-space-ability.ts";
+import { useSpaceQuery } from "@/features/space/queries/space-query.ts";
+import { useParams } from "react-router-dom";
+import {
+ SpaceCaslAction,
+ SpaceCaslSubject,
+} from "@/features/space/permissions/permissions.type.ts";
interface Props {
pageId: string;
@@ -36,6 +43,11 @@ function HistoryList({ pageId }: Props) {
const [mainEditorTitle] = useAtom(titleEditorAtom);
const [, setHistoryModalOpen] = useAtom(historyAtoms);
+ const { spaceSlug } = useParams();
+ const { data: space } = useSpaceQuery(spaceSlug);
+ const spaceRules = space?.membership?.permissions;
+ const spaceAbility = useSpaceAbility(spaceRules);
+
const confirmModal = () =>
modals.openConfirmModal({
title: t("Please confirm your action"),
@@ -103,20 +115,26 @@ function HistoryList({ pageId }: Props) {
))}
-
-
-
-
- {t("Restore")}
-
- setHistoryModalOpen(false)}
- >
- {t("Cancel")}
-
-
+ {spaceAbility.cannot(
+ SpaceCaslAction.Manage,
+ SpaceCaslSubject.Page,
+ ) ? null : (
+ <>
+
+
+
+ {t("Restore")}
+
+ setHistoryModalOpen(false)}
+ >
+ {t("Cancel")}
+
+
+ >
+ )}
);
}
From 5fd477d07457047f3d90a81b4dac2785950581ff Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 9 Apr 2025 15:46:29 +0100
Subject: [PATCH 09/63] collapse by default in node-edit mode
---
packages/editor-ext/src/lib/details/details.ts | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/packages/editor-ext/src/lib/details/details.ts b/packages/editor-ext/src/lib/details/details.ts
index 1be9accf..b28c4de7 100644
--- a/packages/editor-ext/src/lib/details/details.ts
+++ b/packages/editor-ext/src/lib/details/details.ts
@@ -78,10 +78,13 @@ export const Details = Node.create({
dom.setAttribute("data-type", this.name);
btn.setAttribute("data-type", `${this.name}Button`);
div.setAttribute("data-type", `${this.name}Container`);
- if (node.attrs.open) {
- dom.setAttribute("open", "true");
- } else {
- dom.removeAttribute("open");
+
+ if (editor.isEditable) {
+ if (node.attrs.open) {
+ dom.setAttribute("open", "true");
+ } else {
+ dom.removeAttribute("open");
+ }
}
ico.innerHTML = icon("right-line");
From 7fe3c5f17777021f043bb8b53c1b863201f5d522 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 9 Apr 2025 18:47:39 +0100
Subject: [PATCH 10/63] * time ago hook
---
apps/client/src/features/editor/page-editor.tsx | 1 +
.../page/components/header/page-header-menu.tsx | 6 ++++--
apps/client/src/hooks/use-time-ago.tsx | 16 ++++++++++++++++
3 files changed, 21 insertions(+), 2 deletions(-)
create mode 100644 apps/client/src/hooks/use-time-ago.tsx
diff --git a/apps/client/src/features/editor/page-editor.tsx b/apps/client/src/features/editor/page-editor.tsx
index 2853875e..32845c6d 100644
--- a/apps/client/src/features/editor/page-editor.tsx
+++ b/apps/client/src/features/editor/page-editor.tsx
@@ -209,6 +209,7 @@ export default function PageEditor({
queryClient.setQueryData(["pages", slugId], {
...pageData,
content: newContent,
+ updatedAt: new Date(),
});
}
}, 3000);
diff --git a/apps/client/src/features/page/components/header/page-header-menu.tsx b/apps/client/src/features/page/components/header/page-header-menu.tsx
index fefd3e28..93d10520 100644
--- a/apps/client/src/features/page/components/header/page-header-menu.tsx
+++ b/apps/client/src/features/page/components/header/page-header-menu.tsx
@@ -12,7 +12,7 @@ import {
IconTrash,
IconWifiOff,
} from "@tabler/icons-react";
-import React from "react";
+import React, { useEffect } from "react";
import useToggleAside from "@/hooks/use-toggle-aside.tsx";
import { useAtom } from "jotai";
import { historyAtoms } from "@/features/page-history/atoms/history-atoms.ts";
@@ -34,6 +34,7 @@ import {
} from "@/features/editor/atoms/editor-atoms.ts";
import { formattedDate, timeAgo } from "@/lib/time.ts";
import MovePageModal from "@/features/page/components/move-page-modal.tsx";
+import { useTimeAgo } from "@/hooks/use-time-ago.tsx";
interface PageHeaderMenuProps {
readOnly?: boolean;
@@ -102,6 +103,7 @@ function PageActionMenu({ readOnly }: PageActionMenuProps) {
{ open: openMovePageModal, close: closeMoveSpaceModal },
] = useDisclosure(false);
const [pageEditor] = useAtom(pageEditorAtom);
+ const pageUpdatedAt = useTimeAgo(page.updatedAt);
const handleCopyLink = () => {
const pageUrl =
@@ -208,7 +210,7 @@ function PageActionMenu({ readOnly }: PageActionMenuProps) {
diff --git a/apps/client/src/hooks/use-time-ago.tsx b/apps/client/src/hooks/use-time-ago.tsx
new file mode 100644
index 00000000..03fa9eda
--- /dev/null
+++ b/apps/client/src/hooks/use-time-ago.tsx
@@ -0,0 +1,16 @@
+import { timeAgo } from "@/lib/time.ts";
+import { useEffect, useState } from "react";
+
+export function useTimeAgo(date: Date | string) {
+ const [value, setValue] = useState(() => timeAgo(new Date(date)));
+
+ useEffect(() => {
+ const interval = setInterval(() => {
+ setValue(timeAgo(new Date(date)));
+ }, 5 * 1000);
+
+ return () => clearInterval(interval);
+ }, [date]);
+
+ return value;
+}
From 58d1855a360091ae175c75a97c572da934dd3f21 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 9 Apr 2025 19:03:27 +0100
Subject: [PATCH 11/63] fix hash check
---
apps/server/src/core/auth/services/auth.service.ts | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/apps/server/src/core/auth/services/auth.service.ts b/apps/server/src/core/auth/services/auth.service.ts
index 19f02230..9c761ef3 100644
--- a/apps/server/src/core/auth/services/auth.service.ts
+++ b/apps/server/src/core/auth/services/auth.service.ts
@@ -47,13 +47,18 @@ export class AuthService {
includePassword: true,
});
+ const errorMessage = 'email or password does not match';
+ if (!user || user?.deletedAt) {
+ throw new UnauthorizedException(errorMessage);
+ }
+
const isPasswordMatch = await comparePasswordHash(
loginDto.password,
- user?.password,
+ user.password,
);
- if (!user || !isPasswordMatch || user.deletedAt) {
- throw new UnauthorizedException('email or password does not match');
+ if (!isPasswordMatch) {
+ throw new UnauthorizedException(errorMessage);
}
user.lastLoginAt = new Date();
From f2241db5ee845f326b17b767c18f24422d85ecc5 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 9 Apr 2025 19:14:33 +0100
Subject: [PATCH 12/63] remove beta message
---
README.md | 3 ---
1 file changed, 3 deletions(-)
diff --git a/README.md b/README.md
index 0f1b647a..1b7b161a 100644
--- a/README.md
+++ b/README.md
@@ -9,9 +9,6 @@
-> [!NOTE]
-> Docmost is currently in **beta**. We value your feedback as we progress towards a stable release.
-
## Getting started
To get started with Docmost, please refer to our [documentation](https://docmost.com/docs).
From 29bb52db0ca874a497b31706700673006a055d99 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 9 Apr 2025 19:14:51 +0100
Subject: [PATCH 13/63] v0.10.0
---
apps/client/package.json | 2 +-
apps/server/package.json | 2 +-
package.json | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/client/package.json b/apps/client/package.json
index b64d910b..5b6ee046 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -1,7 +1,7 @@
{
"name": "client",
"private": true,
- "version": "0.9.0",
+ "version": "0.10.0",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
diff --git a/apps/server/package.json b/apps/server/package.json
index a44cf59e..83a2e85f 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -1,6 +1,6 @@
{
"name": "server",
- "version": "0.9.0",
+ "version": "0.10.0",
"description": "",
"author": "",
"private": true,
diff --git a/package.json b/package.json
index 64cf9267..290e09a3 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "docmost",
"homepage": "https://docmost.com",
- "version": "0.9.0",
+ "version": "0.10.0",
"private": true,
"scripts": {
"build": "nx run-many -t build",
From f9711918a370e2363bb9c8d273e2225bdc0d9ca8 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Fri, 11 Apr 2025 12:32:54 +0100
Subject: [PATCH 14/63] fix comment editor padding
---
.../client/src/features/comment/components/comment.module.css | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/apps/client/src/features/comment/components/comment.module.css b/apps/client/src/features/comment/components/comment.module.css
index 87dc5994..b3d0a261 100644
--- a/apps/client/src/features/comment/components/comment.module.css
+++ b/apps/client/src/features/comment/components/comment.module.css
@@ -19,8 +19,7 @@
box-shadow: 0 0 0 2px var(--mantine-color-blue-3);
}
- .ProseMirror {
- width: 100%;
+ .ProseMirror :global(.ProseMirror){
max-width: 100%;
white-space: pre-wrap;
word-break: break-word;
@@ -29,7 +28,6 @@
padding-right: 6px;
margin-top: 2px;
margin-bottom: 2px;
- font-size: 14px;
overflow: hidden auto;
}
From 27fa45a76998e32c4a90fb2cdc56d3eabda9bbb3 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Fri, 11 Apr 2025 13:18:44 +0100
Subject: [PATCH 15/63] fix local attachment paths in exports (#1013)
---
.../src/integrations/export/export.service.ts | 4 +--
apps/server/src/integrations/export/utils.ts | 27 ++++++++++++++-----
2 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/apps/server/src/integrations/export/export.service.ts b/apps/server/src/integrations/export/export.service.ts
index 9cf33234..09fdb5fd 100644
--- a/apps/server/src/integrations/export/export.service.ts
+++ b/apps/server/src/integrations/export/export.service.ts
@@ -21,7 +21,7 @@ import {
getProsemirrorContent,
PageExportTree,
replaceInternalLinks,
- updateAttachmentUrls,
+ updateAttachmentUrlsToLocalPaths,
} from './utils';
import { PageRepo } from '@docmost/db/repos/page/page.repo';
import { Node } from '@tiptap/pm/model';
@@ -193,7 +193,7 @@ export class ExportService {
if (includeAttachments) {
await this.zipAttachments(updatedJsonContent, page.spaceId, folder);
- updatedJsonContent = updateAttachmentUrls(updatedJsonContent);
+ updatedJsonContent = updateAttachmentUrlsToLocalPaths(updatedJsonContent);
}
const pageTitle = getPageTitle(page.title);
diff --git a/apps/server/src/integrations/export/utils.ts b/apps/server/src/integrations/export/utils.ts
index e296f194..f99f337a 100644
--- a/apps/server/src/integrations/export/utils.ts
+++ b/apps/server/src/integrations/export/utils.ts
@@ -62,17 +62,30 @@ export function isAttachmentNode(nodeType: string) {
return attachmentNodeTypes.includes(nodeType);
}
-export function updateAttachmentUrls(prosemirrorJson: any) {
+export function updateAttachmentUrlsToLocalPaths(prosemirrorJson: any) {
const doc = jsonToNode(prosemirrorJson);
+ if (!doc) return null;
+
+ // Helper function to replace specific URL prefixes
+ const replacePrefix = (url: string): string => {
+ const prefixes = ['/files', '/api/files'];
+ for (const prefix of prefixes) {
+ if (url.startsWith(prefix)) {
+ return url.replace(prefix, 'files');
+ }
+ }
+ return url;
+ };
doc?.descendants((node: Node) => {
if (isAttachmentNode(node.type.name)) {
- if (node.attrs.src && node.attrs.src.startsWith('/files')) {
- //@ts-expect-error
- node.attrs.src = node.attrs.src.replace('/files', 'files');
- } else if (node.attrs.url && node.attrs.url.startsWith('/files')) {
- //@ts-expect-error
- node.attrs.url = node.attrs.url.replace('/files', 'files');
+ if (node.attrs.src) {
+ // @ts-ignore
+ node.attrs.src = replacePrefix(node.attrs.src);
+ }
+ if (node.attrs.url) {
+ // @ts-ignore
+ node.attrs.url = replacePrefix(node.attrs.url);
}
}
});
From 268001ae26dc8f647fcb3f96dbc3d51ef87c569b Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Fri, 11 Apr 2025 13:23:42 +0100
Subject: [PATCH 16/63] v0.10.1
---
apps/client/package.json | 2 +-
apps/server/package.json | 2 +-
package.json | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/client/package.json b/apps/client/package.json
index 5b6ee046..c88a2860 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -1,7 +1,7 @@
{
"name": "client",
"private": true,
- "version": "0.10.0",
+ "version": "0.10.1",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
diff --git a/apps/server/package.json b/apps/server/package.json
index 83a2e85f..54cd1661 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -1,6 +1,6 @@
{
"name": "server",
- "version": "0.10.0",
+ "version": "0.10.1",
"description": "",
"author": "",
"private": true,
diff --git a/package.json b/package.json
index 290e09a3..d67cc4cd 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "docmost",
"homepage": "https://docmost.com",
- "version": "0.10.0",
+ "version": "0.10.1",
"private": true,
"scripts": {
"build": "nx run-many -t build",
From 49d0f1cc9a105e6488be20a7138dde3a69819ac0 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Fri, 11 Apr 2025 13:41:43 +0100
Subject: [PATCH 17/63] Add click handler
---
apps/client/src/components/settings/app-version.tsx | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/apps/client/src/components/settings/app-version.tsx b/apps/client/src/components/settings/app-version.tsx
index f5097d51..cb332478 100644
--- a/apps/client/src/components/settings/app-version.tsx
+++ b/apps/client/src/components/settings/app-version.tsx
@@ -35,6 +35,12 @@ export default function AppVersion() {
position="middle-end"
style={{ cursor: "pointer" }}
disabled={!hasUpdate}
+ onClick={() => {
+ window.open(
+ "https://github.com/docmost/docmost/releases",
+ "_blank",
+ );
+ }}
>
Date: Tue, 15 Apr 2025 12:46:28 +0100
Subject: [PATCH 18/63] sync ee
---
apps/server/src/ee | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/server/src/ee b/apps/server/src/ee
index a04fcc22..d3095f2d 160000
--- a/apps/server/src/ee
+++ b/apps/server/src/ee
@@ -1 +1 @@
-Subproject commit a04fcc224e36514741f064d83a3c39df31766b65
+Subproject commit d3095f2d8bd2870da7f3b534c83c84e8fb3099bc
From de57d051998d39780b0cb8e1a755d7c8b256549e Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 15 Apr 2025 12:48:40 +0100
Subject: [PATCH 19/63] 0.10.2
---
apps/client/package.json | 2 +-
apps/server/package.json | 2 +-
package.json | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/client/package.json b/apps/client/package.json
index c88a2860..5901a920 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -1,7 +1,7 @@
{
"name": "client",
"private": true,
- "version": "0.10.1",
+ "version": "0.10.2",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
diff --git a/apps/server/package.json b/apps/server/package.json
index 54cd1661..0ef03d7c 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -1,6 +1,6 @@
{
"name": "server",
- "version": "0.10.1",
+ "version": "0.10.2",
"description": "",
"author": "",
"private": true,
diff --git a/package.json b/package.json
index d67cc4cd..d84046e5 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "docmost",
"homepage": "https://docmost.com",
- "version": "0.10.1",
+ "version": "0.10.2",
"private": true,
"scripts": {
"build": "nx run-many -t build",
From 862f6d4820cfdf15f466dd0fc7671b5fa8d96bdb Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Sat, 19 Apr 2025 19:45:09 +0100
Subject: [PATCH 20/63] use non-esm nanoid version (#1040)
---
apps/server/package.json | 3 +-
.../server/src/common/helpers/nanoid.utils.ts | 5 +-
pnpm-lock.yaml | 337 +++---------------
3 files changed, 62 insertions(+), 283 deletions(-)
diff --git a/apps/server/package.json b/apps/server/package.json
index 0ef03d7c..fced5e33 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -59,14 +59,13 @@
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"cookie": "^1.0.2",
- "fix-esm": "^1.0.1",
"fs-extra": "^11.3.0",
"happy-dom": "^15.11.6",
"jsonwebtoken": "^9.0.2",
"kysely": "^0.27.5",
"kysely-migration-cli": "^0.4.2",
"mime-types": "^2.1.35",
- "nanoid": "^5.1.0",
+ "nanoid": "3.3.11",
"nestjs-kysely": "^1.1.0",
"nodemailer": "^6.10.0",
"openid-client": "^5.7.1",
diff --git a/apps/server/src/common/helpers/nanoid.utils.ts b/apps/server/src/common/helpers/nanoid.utils.ts
index 016b922f..71234659 100644
--- a/apps/server/src/common/helpers/nanoid.utils.ts
+++ b/apps/server/src/common/helpers/nanoid.utils.ts
@@ -1,9 +1,8 @@
-// eslint-disable-next-line @typescript-eslint/no-require-imports
-const { customAlphabet } = require('fix-esm').require('nanoid');
+import { customAlphabet } from 'nanoid';
const alphabet = '0123456789abcdefghijklmnopqrstuvwxyz';
export const nanoIdGen = customAlphabet(alphabet, 10);
const slugIdAlphabet =
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
-export const generateSlugId = customAlphabet(slugIdAlphabet, 10);
+export const generateSlugId = customAlphabet(slugIdAlphabet, 10);
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 70f5088b..f9cc1623 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -486,9 +486,6 @@ importers:
cookie:
specifier: ^1.0.2
version: 1.0.2
- fix-esm:
- specifier: ^1.0.1
- version: 1.0.1
fs-extra:
specifier: ^11.3.0
version: 11.3.0
@@ -508,8 +505,8 @@ importers:
specifier: ^2.1.35
version: 2.1.35
nanoid:
- specifier: ^5.1.0
- version: 5.1.0
+ specifier: 3.3.11
+ version: 3.3.11
nestjs-kysely:
specifier: ^1.1.0
version: 1.1.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)(kysely@0.27.5)(reflect-metadata@0.2.2)
@@ -633,7 +630,7 @@ importers:
version: 7.0.0
ts-jest:
specifier: ^29.2.5
- version: 29.2.5(@babel/core@7.24.3)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.3))(jest@29.7.0(@types/node@22.13.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(typescript@5.7.3)))(typescript@5.7.3)
+ version: 29.2.5(@babel/core@7.24.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.5))(jest@29.7.0(@types/node@22.13.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(typescript@5.7.3)))(typescript@5.7.3)
ts-loader:
specifier: ^9.5.2
version: 9.5.2(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.25(@swc/helpers@0.5.5)))
@@ -875,18 +872,10 @@ packages:
resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
engines: {node: '>=6.9.0'}
- '@babel/compat-data@7.23.5':
- resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==}
- engines: {node: '>=6.9.0'}
-
'@babel/compat-data@7.26.2':
resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==}
engines: {node: '>=6.9.0'}
- '@babel/core@7.24.3':
- resolution: {integrity: sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==}
- engines: {node: '>=6.9.0'}
-
'@babel/core@7.24.5':
resolution: {integrity: sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==}
engines: {node: '>=6.9.0'}
@@ -919,10 +908,6 @@ packages:
resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==}
engines: {node: '>=6.9.0'}
- '@babel/helper-compilation-targets@7.23.6':
- resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==}
- engines: {node: '>=6.9.0'}
-
'@babel/helper-compilation-targets@7.25.9':
resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==}
engines: {node: '>=6.9.0'}
@@ -952,18 +937,10 @@ packages:
resolution: {integrity: sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==}
engines: {node: '>=6.9.0'}
- '@babel/helper-function-name@7.23.0':
- resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
- engines: {node: '>=6.9.0'}
-
'@babel/helper-function-name@7.24.6':
resolution: {integrity: sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==}
engines: {node: '>=6.9.0'}
- '@babel/helper-hoist-variables@7.22.5':
- resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
- engines: {node: '>=6.9.0'}
-
'@babel/helper-hoist-variables@7.24.6':
resolution: {integrity: sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==}
engines: {node: '>=6.9.0'}
@@ -1074,10 +1051,6 @@ packages:
resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
engines: {node: '>=6.9.0'}
- '@babel/helper-validator-option@7.23.5':
- resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==}
- engines: {node: '>=6.9.0'}
-
'@babel/helper-validator-option@7.25.9':
resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==}
engines: {node: '>=6.9.0'}
@@ -1086,10 +1059,6 @@ packages:
resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==}
engines: {node: '>=6.9.0'}
- '@babel/helpers@7.24.1':
- resolution: {integrity: sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==}
- engines: {node: '>=6.9.0'}
-
'@babel/helpers@7.24.6':
resolution: {integrity: sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==}
engines: {node: '>=6.9.0'}
@@ -1102,11 +1071,6 @@ packages:
resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==}
engines: {node: '>=6.9.0'}
- '@babel/parser@7.24.1':
- resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==}
- engines: {node: '>=6.0.0'}
- hasBin: true
-
'@babel/parser@7.24.5':
resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==}
engines: {node: '>=6.0.0'}
@@ -1146,13 +1110,6 @@ packages:
peerDependencies:
'@babel/core': ^7.0.0-0
- '@babel/plugin-proposal-export-namespace-from@7.18.9':
- resolution: {integrity: sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==}
- engines: {node: '>=6.9.0'}
- deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.
- peerDependencies:
- '@babel/core': ^7.0.0-0
-
'@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2':
resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==}
engines: {node: '>=6.9.0'}
@@ -1618,14 +1575,6 @@ packages:
resolution: {integrity: sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==}
engines: {node: '>=6.9.0'}
- '@babel/template@7.22.15':
- resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==}
- engines: {node: '>=6.9.0'}
-
- '@babel/template@7.24.0':
- resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==}
- engines: {node: '>=6.9.0'}
-
'@babel/template@7.24.6':
resolution: {integrity: sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==}
engines: {node: '>=6.9.0'}
@@ -1634,10 +1583,6 @@ packages:
resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==}
engines: {node: '>=6.9.0'}
- '@babel/traverse@7.24.1':
- resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==}
- engines: {node: '>=6.9.0'}
-
'@babel/traverse@7.25.9':
resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==}
engines: {node: '>=6.9.0'}
@@ -4756,11 +4701,6 @@ packages:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
- browserslist@4.23.0:
- resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==}
- engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
- hasBin: true
-
browserslist@4.24.2:
resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
@@ -4822,9 +4762,6 @@ packages:
resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
engines: {node: '>=10'}
- caniuse-lite@1.0.30001600:
- resolution: {integrity: sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==}
-
caniuse-lite@1.0.30001684:
resolution: {integrity: sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==}
@@ -5463,9 +5400,6 @@ packages:
engines: {node: '>=0.10.0'}
hasBin: true
- electron-to-chromium@1.4.715:
- resolution: {integrity: sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg==}
-
electron-to-chromium@1.5.65:
resolution: {integrity: sha512-PWVzBjghx7/wop6n22vS2MLU8tKGd4Q91aCEGhG/TYmW6PP5OcSXcdnxTe1NNt0T66N8D6jxh4kC8UsdzOGaIw==}
@@ -5799,9 +5733,6 @@ packages:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
- fix-esm@1.0.1:
- resolution: {integrity: sha512-EZtb7wPXZS54GaGxaWxMlhd1DUDCnAg5srlYdu/1ZVeW+7wwR3Tp59nu52dXByFs3MBRq+SByx1wDOJpRvLEXw==}
-
flat-cache@4.0.1:
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
engines: {node: '>=16'}
@@ -7020,21 +6951,16 @@ packages:
resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
engines: {node: ^18.17.0 || >=20.5.0}
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
nanoid@3.3.7:
resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
- nanoid@3.3.8:
- resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==}
- engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
- hasBin: true
-
- nanoid@5.1.0:
- resolution: {integrity: sha512-zDAl/llz8Ue/EblwSYwdxGBYfj46IM1dhjVi8dyp9LQffoIGxJEAHj2oeZ4uNcgycSRcQ83CnfcZqEJzVDLcDw==}
- engines: {node: ^18 || >=20}
- hasBin: true
-
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
@@ -7104,9 +7030,6 @@ packages:
node-machine-id@1.1.12:
resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==}
- node-releases@2.0.14:
- resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
-
node-releases@2.0.18:
resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==}
@@ -8653,12 +8576,6 @@ packages:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
- update-browserslist-db@1.0.13:
- resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
- hasBin: true
- peerDependencies:
- browserslist: '>= 4.21.0'
-
update-browserslist-db@1.1.1:
resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==}
hasBin: true
@@ -9679,30 +9596,8 @@ snapshots:
js-tokens: 4.0.0
picocolors: 1.0.1
- '@babel/compat-data@7.23.5': {}
-
'@babel/compat-data@7.26.2': {}
- '@babel/core@7.24.3':
- dependencies:
- '@ampproject/remapping': 2.3.0
- '@babel/code-frame': 7.24.2
- '@babel/generator': 7.24.1
- '@babel/helper-compilation-targets': 7.23.6
- '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3)
- '@babel/helpers': 7.24.1
- '@babel/parser': 7.24.1
- '@babel/template': 7.24.0
- '@babel/traverse': 7.24.1
- '@babel/types': 7.24.0
- convert-source-map: 2.0.0
- debug: 4.3.4
- gensync: 1.0.0-beta.2
- json5: 2.2.3
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
'@babel/core@7.24.5':
dependencies:
'@ampproject/remapping': 2.3.0
@@ -9793,14 +9688,6 @@ snapshots:
dependencies:
'@babel/types': 7.26.0
- '@babel/helper-compilation-targets@7.23.6':
- dependencies:
- '@babel/compat-data': 7.23.5
- '@babel/helper-validator-option': 7.23.5
- browserslist: 4.23.0
- lru-cache: 5.1.1
- semver: 6.3.1
-
'@babel/helper-compilation-targets@7.25.9':
dependencies:
'@babel/compat-data': 7.26.2
@@ -9844,20 +9731,11 @@ snapshots:
'@babel/helper-environment-visitor@7.24.6': {}
- '@babel/helper-function-name@7.23.0':
- dependencies:
- '@babel/template': 7.22.15
- '@babel/types': 7.24.0
-
'@babel/helper-function-name@7.24.6':
dependencies:
'@babel/template': 7.24.6
'@babel/types': 7.24.6
- '@babel/helper-hoist-variables@7.22.5':
- dependencies:
- '@babel/types': 7.24.0
-
'@babel/helper-hoist-variables@7.24.6':
dependencies:
'@babel/types': 7.24.6
@@ -9881,15 +9759,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/helper-module-transforms@7.23.3(@babel/core@7.24.3)':
- dependencies:
- '@babel/core': 7.24.3
- '@babel/helper-environment-visitor': 7.22.20
- '@babel/helper-module-imports': 7.22.15
- '@babel/helper-simple-access': 7.22.5
- '@babel/helper-split-export-declaration': 7.22.6
- '@babel/helper-validator-identifier': 7.22.20
-
'@babel/helper-module-transforms@7.23.3(@babel/core@7.26.0)':
dependencies:
'@babel/core': 7.26.0
@@ -9982,8 +9851,6 @@ snapshots:
'@babel/helper-validator-identifier@7.25.9': {}
- '@babel/helper-validator-option@7.23.5': {}
-
'@babel/helper-validator-option@7.25.9': {}
'@babel/helper-wrap-function@7.22.20':
@@ -9992,14 +9859,6 @@ snapshots:
'@babel/template': 7.25.9
'@babel/types': 7.26.0
- '@babel/helpers@7.24.1':
- dependencies:
- '@babel/template': 7.24.0
- '@babel/traverse': 7.24.1
- '@babel/types': 7.24.0
- transitivePeerDependencies:
- - supports-color
-
'@babel/helpers@7.24.6':
dependencies:
'@babel/template': 7.25.9
@@ -10017,10 +9876,6 @@ snapshots:
js-tokens: 4.0.0
picocolors: 1.0.0
- '@babel/parser@7.24.1':
- dependencies:
- '@babel/types': 7.24.0
-
'@babel/parser@7.24.5':
dependencies:
'@babel/types': 7.26.0
@@ -10058,19 +9913,13 @@ snapshots:
'@babel/helper-plugin-utils': 7.25.9
'@babel/plugin-syntax-decorators': 7.23.3(@babel/core@7.26.0)
- '@babel/plugin-proposal-export-namespace-from@7.18.9(@babel/core@7.24.3)':
- dependencies:
- '@babel/core': 7.24.3
- '@babel/helper-plugin-utils': 7.24.0
- '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.3)
-
'@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.0)':
dependencies:
'@babel/core': 7.26.0
- '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.3)':
+ '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.5)':
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@babel/helper-plugin-utils': 7.25.9
optional: true
@@ -10084,9 +9933,9 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.3)':
+ '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.5)':
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@babel/helper-plugin-utils': 7.25.9
optional: true
@@ -10095,9 +9944,9 @@ snapshots:
'@babel/core': 7.24.6
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.3)':
+ '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.5)':
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@babel/helper-plugin-utils': 7.25.9
optional: true
@@ -10126,11 +9975,6 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.3)':
- dependencies:
- '@babel/core': 7.24.3
- '@babel/helper-plugin-utils': 7.24.0
-
'@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.26.0)':
dependencies:
'@babel/core': 7.26.0
@@ -10146,9 +9990,9 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.3)':
+ '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.5)':
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@babel/helper-plugin-utils': 7.25.9
optional: true
@@ -10162,9 +10006,9 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.3)':
+ '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.5)':
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@babel/helper-plugin-utils': 7.25.9
optional: true
@@ -10188,9 +10032,9 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.3)':
+ '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.5)':
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@babel/helper-plugin-utils': 7.25.9
optional: true
@@ -10204,9 +10048,9 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.3)':
+ '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.5)':
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@babel/helper-plugin-utils': 7.25.9
optional: true
@@ -10220,9 +10064,9 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.3)':
+ '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.5)':
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@babel/helper-plugin-utils': 7.25.9
optional: true
@@ -10236,9 +10080,9 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.3)':
+ '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.5)':
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@babel/helper-plugin-utils': 7.25.9
optional: true
@@ -10252,9 +10096,9 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.3)':
+ '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.5)':
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@babel/helper-plugin-utils': 7.25.9
optional: true
@@ -10268,9 +10112,9 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.3)':
+ '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.5)':
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@babel/helper-plugin-utils': 7.25.9
optional: true
@@ -10289,9 +10133,9 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.3)':
+ '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.5)':
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@babel/helper-plugin-utils': 7.25.9
optional: true
@@ -10461,13 +10305,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.24.3)':
- dependencies:
- '@babel/core': 7.24.3
- '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.3)
- '@babel/helper-plugin-utils': 7.24.0
- '@babel/helper-simple-access': 7.22.5
-
'@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.26.0)':
dependencies:
'@babel/core': 7.26.0
@@ -10770,18 +10607,6 @@ snapshots:
dependencies:
regenerator-runtime: 0.14.1
- '@babel/template@7.22.15':
- dependencies:
- '@babel/code-frame': 7.26.2
- '@babel/parser': 7.26.2
- '@babel/types': 7.24.0
-
- '@babel/template@7.24.0':
- dependencies:
- '@babel/code-frame': 7.24.2
- '@babel/parser': 7.24.1
- '@babel/types': 7.24.0
-
'@babel/template@7.24.6':
dependencies:
'@babel/code-frame': 7.26.2
@@ -10794,21 +10619,6 @@ snapshots:
'@babel/parser': 7.26.2
'@babel/types': 7.26.0
- '@babel/traverse@7.24.1':
- dependencies:
- '@babel/code-frame': 7.24.2
- '@babel/generator': 7.24.1
- '@babel/helper-environment-visitor': 7.22.20
- '@babel/helper-function-name': 7.23.0
- '@babel/helper-hoist-variables': 7.22.5
- '@babel/helper-split-export-declaration': 7.22.6
- '@babel/parser': 7.24.1
- '@babel/types': 7.24.0
- debug: 4.3.7
- globals: 11.12.0
- transitivePeerDependencies:
- - supports-color
-
'@babel/traverse@7.25.9':
dependencies:
'@babel/code-frame': 7.26.2
@@ -14003,13 +13813,13 @@ snapshots:
transitivePeerDependencies:
- debug
- babel-jest@29.7.0(@babel/core@7.24.3):
+ babel-jest@29.7.0(@babel/core@7.24.5):
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@jest/transform': 29.7.0
'@types/babel__core': 7.20.5
babel-plugin-istanbul: 6.1.1
- babel-preset-jest: 29.6.3(@babel/core@7.24.3)
+ babel-preset-jest: 29.6.3(@babel/core@7.24.5)
chalk: 4.1.2
graceful-fs: 4.2.11
slash: 3.0.0
@@ -14093,21 +13903,21 @@ snapshots:
optionalDependencies:
'@babel/traverse': 7.25.9
- babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.3):
+ babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.5):
dependencies:
- '@babel/core': 7.24.3
- '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.3)
- '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.3)
- '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.3)
- '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.3)
- '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.3)
- '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.3)
- '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.3)
- '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.3)
- '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.3)
- '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.3)
- '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3)
- '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.3)
+ '@babel/core': 7.24.5
+ '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.5)
+ '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.24.5)
+ '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.5)
+ '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.5)
+ '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.5)
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.5)
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.5)
+ '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.5)
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.5)
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.5)
+ '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.5)
+ '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.5)
optional: true
babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.6):
@@ -14126,11 +13936,11 @@ snapshots:
'@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.6)
'@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.6)
- babel-preset-jest@29.6.3(@babel/core@7.24.3):
+ babel-preset-jest@29.6.3(@babel/core@7.24.5):
dependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
babel-plugin-jest-hoist: 29.6.3
- babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.3)
+ babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.5)
optional: true
babel-preset-jest@29.6.3(@babel/core@7.24.6):
@@ -14195,13 +14005,6 @@ snapshots:
dependencies:
fill-range: 7.1.1
- browserslist@4.23.0:
- dependencies:
- caniuse-lite: 1.0.30001600
- electron-to-chromium: 1.4.715
- node-releases: 2.0.14
- update-browserslist-db: 1.0.13(browserslist@4.23.0)
-
browserslist@4.24.2:
dependencies:
caniuse-lite: 1.0.30001684
@@ -14273,8 +14076,6 @@ snapshots:
camelcase@6.3.0: {}
- caniuse-lite@1.0.30001600: {}
-
caniuse-lite@1.0.30001684: {}
chalk@2.4.2:
@@ -14921,8 +14722,6 @@ snapshots:
dependencies:
jake: 10.8.7
- electron-to-chromium@1.4.715: {}
-
electron-to-chromium@1.5.65: {}
emittery@0.13.1: {}
@@ -15476,14 +15275,6 @@ snapshots:
locate-path: 6.0.0
path-exists: 4.0.0
- fix-esm@1.0.1:
- dependencies:
- '@babel/core': 7.24.3
- '@babel/plugin-proposal-export-namespace-from': 7.18.9(@babel/core@7.24.3)
- '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.3)
- transitivePeerDependencies:
- - supports-color
-
flat-cache@4.0.1:
dependencies:
flatted: 3.2.9
@@ -16913,12 +16704,10 @@ snapshots:
mute-stream@2.0.0: {}
+ nanoid@3.3.11: {}
+
nanoid@3.3.7: {}
- nanoid@3.3.8: {}
-
- nanoid@5.1.0: {}
-
natural-compare@1.4.0: {}
needle@3.3.1:
@@ -16983,8 +16772,6 @@ snapshots:
node-machine-id@1.1.12: {}
- node-releases@2.0.14: {}
-
node-releases@2.0.18: {}
nodemailer@6.10.0: {}
@@ -17424,7 +17211,7 @@ snapshots:
postcss@8.4.31:
dependencies:
- nanoid: 3.3.8
+ nanoid: 3.3.11
picocolors: 1.1.1
source-map-js: 1.2.1
@@ -17436,7 +17223,7 @@ snapshots:
postcss@8.5.2:
dependencies:
- nanoid: 3.3.8
+ nanoid: 3.3.11
picocolors: 1.1.1
source-map-js: 1.2.1
@@ -18486,7 +18273,7 @@ snapshots:
ts-dedent@2.2.0: {}
- ts-jest@29.2.5(@babel/core@7.24.3)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.3))(jest@29.7.0(@types/node@22.13.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(typescript@5.7.3)))(typescript@5.7.3):
+ ts-jest@29.2.5(@babel/core@7.24.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.5))(jest@29.7.0(@types/node@22.13.4)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(typescript@5.7.3)))(typescript@5.7.3):
dependencies:
bs-logger: 0.2.6
ejs: 3.1.10
@@ -18500,10 +18287,10 @@ snapshots:
typescript: 5.7.3
yargs-parser: 21.1.1
optionalDependencies:
- '@babel/core': 7.24.3
+ '@babel/core': 7.24.5
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
- babel-jest: 29.7.0(@babel/core@7.24.3)
+ babel-jest: 29.7.0(@babel/core@7.24.5)
ts-loader@9.5.2(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.25(@swc/helpers@0.5.5))):
dependencies:
@@ -18687,12 +18474,6 @@ snapshots:
universalify@2.0.1: {}
- update-browserslist-db@1.0.13(browserslist@4.23.0):
- dependencies:
- browserslist: 4.23.0
- escalade: 3.1.1
- picocolors: 1.0.0
-
update-browserslist-db@1.1.1(browserslist@4.24.2):
dependencies:
browserslist: 4.24.2
From 5c957fda8dafa44b92e91b04590955eeacf6a25f Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Mon, 21 Apr 2025 19:24:25 +0100
Subject: [PATCH 21/63] fix: nested tree open state
---
.../src/features/page/tree/components/space-tree.tsx | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/apps/client/src/features/page/tree/components/space-tree.tsx b/apps/client/src/features/page/tree/components/space-tree.tsx
index c099691b..7b2f2f7d 100644
--- a/apps/client/src/features/page/tree/components/space-tree.tsx
+++ b/apps/client/src/features/page/tree/components/space-tree.tsx
@@ -7,7 +7,7 @@ import {
usePageQuery,
useUpdatePageMutation,
} from "@/features/page/queries/page-query.ts";
-import { useEffect, useRef } from "react";
+import { useEffect, useRef, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import classes from "@/features/page/tree/styles/tree.module.css";
import { ActionIcon, Menu, rem } from "@mantine/core";
@@ -84,7 +84,7 @@ export default function SpaceTree({ spaceId, readOnly }: SpaceTreeProps) {
const rootElement = useRef();
const { ref: sizeRef, width, height } = useElementSize();
const mergedRef = useMergedRef(rootElement, sizeRef);
- const isDataLoaded = useRef(false);
+ const [isDataLoaded, setIsDataLoaded] = useState(false);
const { data: currentPage } = usePageQuery({
pageId: extractPageSlugId(pageSlug),
});
@@ -108,7 +108,7 @@ export default function SpaceTree({ spaceId, readOnly }: SpaceTreeProps) {
// and append root pages instead of resetting the entire tree
// which looses async loaded children too
setData(treeData);
- isDataLoaded.current = true;
+ setIsDataLoaded(true);
setOpenTreeNodes({});
}
}
@@ -116,7 +116,7 @@ export default function SpaceTree({ spaceId, readOnly }: SpaceTreeProps) {
useEffect(() => {
const fetchData = async () => {
- if (isDataLoaded.current && currentPage) {
+ if (isDataLoaded && currentPage) {
// check if pageId node is present in the tree
const node = dfs(treeApiRef.current?.root, currentPage.id);
if (node) {
@@ -178,7 +178,7 @@ export default function SpaceTree({ spaceId, readOnly }: SpaceTreeProps) {
};
fetchData();
- }, [isDataLoaded.current, currentPage?.id]);
+ }, [isDataLoaded, currentPage?.id]);
useEffect(() => {
if (currentPage?.id) {
From 10b67929ea9ef74f0a8b4a21d149b9d4bfeb1ec0 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Mon, 21 Apr 2025 21:50:21 +0100
Subject: [PATCH 22/63] Update README.md
---
README.md | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 1b7b161a..f09680e1 100644
--- a/README.md
+++ b/README.md
@@ -4,14 +4,15 @@
Open-source collaborative wiki and documentation software.
Website |
- Documentation
+ Documentation |
+ Twitter / X
## Getting started
-To get started with Docmost, please refer to our [documentation](https://docmost.com/docs).
+To get started with Docmost, please refer to our [documentation](https://docmost.com/docs) or try our [cloud version](https://docmost.com/pricing) .
## Features
@@ -46,3 +47,16 @@ All files in the following directories are licensed under the Docmost Enterprise
### Contributing
See the [development documentation](https://docmost.com/docs/self-hosting/development)
+
+## Thanks
+Special thanks to;
+
+
+
+[Crowdin](https://crowdin.com/) for providing access to their localization platform.
+
+
+
+
+[Algolia](https://www.algolia.com/) for providing full-text search to the docs.
+
From 1a1b2c8682ccd08062d8486d3ddd0b60989a9dd5 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 22 Apr 2025 15:52:44 +0100
Subject: [PATCH 23/63] switch to vite rolldown (#1048)
* switch to vite rolldown
* update
---
apps/client/package.json | 6 +-
pnpm-lock.yaml | 929 ++++++++++++++++++---------------------
2 files changed, 435 insertions(+), 500 deletions(-)
diff --git a/apps/client/package.json b/apps/client/package.json
index 5901a920..74e3c21e 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -25,7 +25,7 @@
"@tabler/icons-react": "^3.22.0",
"@tanstack/react-query": "^5.61.4",
"@tiptap/extension-character-count": "^2.11.5",
- "axios": "^1.7.9",
+ "axios": "^1.8.4",
"clsx": "^2.1.1",
"emoji-mart": "^5.6.0",
"file-saver": "^2.0.5",
@@ -63,7 +63,7 @@
"@types/node": "22.10.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
- "@vitejs/plugin-react": "^4.3.4",
+ "@vitejs/plugin-react": "^4.4.1",
"eslint": "^9.15.0",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.1.0",
@@ -76,6 +76,6 @@
"prettier": "^3.4.1",
"typescript": "^5.7.2",
"typescript-eslint": "^8.17.0",
- "vite": "^6.1.0"
+ "vite": "npm:rolldown-vite@latest"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f9cc1623..d5eaf2ae 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -181,7 +181,7 @@ importers:
devDependencies:
'@nx/js':
specifier: 20.4.5
- version: 20.4.5(@babel/traverse@7.25.9)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)
+ version: 20.4.5(@babel/traverse@7.27.0)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)
'@types/bytes':
specifier: ^3.1.5
version: 3.1.5
@@ -246,8 +246,8 @@ importers:
specifier: ^2.11.5
version: 2.11.5(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)
axios:
- specifier: ^1.7.9
- version: 1.7.9
+ specifier: ^1.8.4
+ version: 1.8.4
clsx:
specifier: ^2.1.1
version: 2.1.1
@@ -355,8 +355,8 @@ importers:
specifier: ^18.3.1
version: 18.3.1
'@vitejs/plugin-react':
- specifier: ^4.3.4
- version: 4.3.4(vite@6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))
+ specifier: ^4.4.1
+ version: 4.4.1(rolldown-vite@6.3.3(@types/node@22.10.0)(esbuild@0.25.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.2)(yaml@2.7.0))
eslint:
specifier: ^9.15.0
version: 9.15.0(jiti@1.21.0)
@@ -394,8 +394,8 @@ importers:
specifier: ^8.17.0
version: 8.17.0(eslint@9.15.0(jiti@1.21.0))(typescript@5.7.2)
vite:
- specifier: ^6.1.0
- version: 6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)
+ specifier: npm:rolldown-vite@latest
+ version: rolldown-vite@6.3.3(@types/node@22.10.0)(esbuild@0.25.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.2)(yaml@2.7.0)
apps/server:
dependencies:
@@ -876,6 +876,10 @@ packages:
resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==}
engines: {node: '>=6.9.0'}
+ '@babel/compat-data@7.26.8':
+ resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==}
+ engines: {node: '>=6.9.0'}
+
'@babel/core@7.24.5':
resolution: {integrity: sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==}
engines: {node: '>=6.9.0'}
@@ -888,6 +892,10 @@ packages:
resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==}
engines: {node: '>=6.9.0'}
+ '@babel/core@7.26.10':
+ resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==}
+ engines: {node: '>=6.9.0'}
+
'@babel/generator@7.24.1':
resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==}
engines: {node: '>=6.9.0'}
@@ -900,6 +908,10 @@ packages:
resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==}
engines: {node: '>=6.9.0'}
+ '@babel/generator@7.27.0':
+ resolution: {integrity: sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-annotate-as-pure@7.22.5':
resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
engines: {node: '>=6.9.0'}
@@ -912,6 +924,10 @@ packages:
resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-compilation-targets@7.27.0':
+ resolution: {integrity: sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-create-class-features-plugin@7.23.7':
resolution: {integrity: sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==}
engines: {node: '>=6.9.0'}
@@ -1067,6 +1083,10 @@ packages:
resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==}
engines: {node: '>=6.9.0'}
+ '@babel/helpers@7.27.0':
+ resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==}
+ engines: {node: '>=6.9.0'}
+
'@babel/highlight@7.24.2':
resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==}
engines: {node: '>=6.9.0'}
@@ -1076,13 +1096,13 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/parser@7.24.6':
- resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==}
+ '@babel/parser@7.26.2':
+ resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==}
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/parser@7.26.2':
- resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==}
+ '@babel/parser@7.27.0':
+ resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==}
engines: {node: '>=6.0.0'}
hasBin: true
@@ -1583,10 +1603,18 @@ packages:
resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==}
engines: {node: '>=6.9.0'}
+ '@babel/template@7.27.0':
+ resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/traverse@7.25.9':
resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==}
engines: {node: '>=6.9.0'}
+ '@babel/traverse@7.27.0':
+ resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/types@7.23.6':
resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==}
engines: {node: '>=6.9.0'}
@@ -1603,6 +1631,10 @@ packages:
resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==}
engines: {node: '>=6.9.0'}
+ '@babel/types@7.27.0':
+ resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==}
+ engines: {node: '>=6.9.0'}
+
'@bcoe/v8-coverage@0.2.3':
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
@@ -1701,12 +1733,6 @@ packages:
cpu: [ppc64]
os: [aix]
- '@esbuild/aix-ppc64@0.24.2':
- resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [aix]
-
'@esbuild/aix-ppc64@0.25.0':
resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==}
engines: {node: '>=18'}
@@ -1719,12 +1745,6 @@ packages:
cpu: [arm64]
os: [android]
- '@esbuild/android-arm64@0.24.2':
- resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [android]
-
'@esbuild/android-arm64@0.25.0':
resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==}
engines: {node: '>=18'}
@@ -1737,12 +1757,6 @@ packages:
cpu: [arm]
os: [android]
- '@esbuild/android-arm@0.24.2':
- resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [android]
-
'@esbuild/android-arm@0.25.0':
resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==}
engines: {node: '>=18'}
@@ -1755,12 +1769,6 @@ packages:
cpu: [x64]
os: [android]
- '@esbuild/android-x64@0.24.2':
- resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [android]
-
'@esbuild/android-x64@0.25.0':
resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==}
engines: {node: '>=18'}
@@ -1773,12 +1781,6 @@ packages:
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-arm64@0.24.2':
- resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [darwin]
-
'@esbuild/darwin-arm64@0.25.0':
resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==}
engines: {node: '>=18'}
@@ -1791,12 +1793,6 @@ packages:
cpu: [x64]
os: [darwin]
- '@esbuild/darwin-x64@0.24.2':
- resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [darwin]
-
'@esbuild/darwin-x64@0.25.0':
resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==}
engines: {node: '>=18'}
@@ -1809,12 +1805,6 @@ packages:
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-arm64@0.24.2':
- resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [freebsd]
-
'@esbuild/freebsd-arm64@0.25.0':
resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==}
engines: {node: '>=18'}
@@ -1827,12 +1817,6 @@ packages:
cpu: [x64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.24.2':
- resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [freebsd]
-
'@esbuild/freebsd-x64@0.25.0':
resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==}
engines: {node: '>=18'}
@@ -1845,12 +1829,6 @@ packages:
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm64@0.24.2':
- resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [linux]
-
'@esbuild/linux-arm64@0.25.0':
resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==}
engines: {node: '>=18'}
@@ -1863,12 +1841,6 @@ packages:
cpu: [arm]
os: [linux]
- '@esbuild/linux-arm@0.24.2':
- resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [linux]
-
'@esbuild/linux-arm@0.25.0':
resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==}
engines: {node: '>=18'}
@@ -1881,12 +1853,6 @@ packages:
cpu: [ia32]
os: [linux]
- '@esbuild/linux-ia32@0.24.2':
- resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [linux]
-
'@esbuild/linux-ia32@0.25.0':
resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==}
engines: {node: '>=18'}
@@ -1899,12 +1865,6 @@ packages:
cpu: [loong64]
os: [linux]
- '@esbuild/linux-loong64@0.24.2':
- resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==}
- engines: {node: '>=18'}
- cpu: [loong64]
- os: [linux]
-
'@esbuild/linux-loong64@0.25.0':
resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==}
engines: {node: '>=18'}
@@ -1917,12 +1877,6 @@ packages:
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-mips64el@0.24.2':
- resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==}
- engines: {node: '>=18'}
- cpu: [mips64el]
- os: [linux]
-
'@esbuild/linux-mips64el@0.25.0':
resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==}
engines: {node: '>=18'}
@@ -1935,12 +1889,6 @@ packages:
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-ppc64@0.24.2':
- resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [linux]
-
'@esbuild/linux-ppc64@0.25.0':
resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==}
engines: {node: '>=18'}
@@ -1953,12 +1901,6 @@ packages:
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-riscv64@0.24.2':
- resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==}
- engines: {node: '>=18'}
- cpu: [riscv64]
- os: [linux]
-
'@esbuild/linux-riscv64@0.25.0':
resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==}
engines: {node: '>=18'}
@@ -1971,12 +1913,6 @@ packages:
cpu: [s390x]
os: [linux]
- '@esbuild/linux-s390x@0.24.2':
- resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==}
- engines: {node: '>=18'}
- cpu: [s390x]
- os: [linux]
-
'@esbuild/linux-s390x@0.25.0':
resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==}
engines: {node: '>=18'}
@@ -1989,24 +1925,12 @@ packages:
cpu: [x64]
os: [linux]
- '@esbuild/linux-x64@0.24.2':
- resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [linux]
-
'@esbuild/linux-x64@0.25.0':
resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
- '@esbuild/netbsd-arm64@0.24.2':
- resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [netbsd]
-
'@esbuild/netbsd-arm64@0.25.0':
resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==}
engines: {node: '>=18'}
@@ -2019,24 +1943,12 @@ packages:
cpu: [x64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.24.2':
- resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [netbsd]
-
'@esbuild/netbsd-x64@0.25.0':
resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
- '@esbuild/openbsd-arm64@0.24.2':
- resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [openbsd]
-
'@esbuild/openbsd-arm64@0.25.0':
resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==}
engines: {node: '>=18'}
@@ -2049,12 +1961,6 @@ packages:
cpu: [x64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.24.2':
- resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [openbsd]
-
'@esbuild/openbsd-x64@0.25.0':
resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==}
engines: {node: '>=18'}
@@ -2067,12 +1973,6 @@ packages:
cpu: [x64]
os: [sunos]
- '@esbuild/sunos-x64@0.24.2':
- resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [sunos]
-
'@esbuild/sunos-x64@0.25.0':
resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==}
engines: {node: '>=18'}
@@ -2085,12 +1985,6 @@ packages:
cpu: [arm64]
os: [win32]
- '@esbuild/win32-arm64@0.24.2':
- resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [win32]
-
'@esbuild/win32-arm64@0.25.0':
resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==}
engines: {node: '>=18'}
@@ -2103,12 +1997,6 @@ packages:
cpu: [ia32]
os: [win32]
- '@esbuild/win32-ia32@0.24.2':
- resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [win32]
-
'@esbuild/win32-ia32@0.25.0':
resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==}
engines: {node: '>=18'}
@@ -2121,12 +2009,6 @@ packages:
cpu: [x64]
os: [win32]
- '@esbuild/win32-x64@0.24.2':
- resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [win32]
-
'@esbuild/win32-x64@0.25.0':
resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==}
engines: {node: '>=18'}
@@ -3020,6 +2902,13 @@ packages:
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
engines: {node: '>=8.0.0'}
+ '@oxc-project/runtime@0.65.0':
+ resolution: {integrity: sha512-qn70kbkGtJ3uWz+HXha+kufRXkT+pZWckJKL8jUPzXH5UNszSSwADkNQhb7/uit3tC70wFm9qPRlLHnJcjSGuA==}
+ engines: {node: '>=6.9.0'}
+
+ '@oxc-project/types@0.65.0':
+ resolution: {integrity: sha512-7MpMzyXCcwxrTxJ4L0siy63Ds/LA8LAM4szumTFiynxTJkfrIZEV4PyR4Th0CqFZQ+oNi8WvW3Dr1MLy7o9qPQ==}
+
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@@ -3164,98 +3053,63 @@ packages:
'@remirror/core-constants@3.0.0':
resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==}
- '@rollup/rollup-android-arm-eabi@4.34.7':
- resolution: {integrity: sha512-l6CtzHYo8D2TQ3J7qJNpp3Q1Iye56ssIAtqbM2H8axxCEEwvN7o8Ze9PuIapbxFL3OHrJU2JBX6FIIVnP/rYyw==}
- cpu: [arm]
- os: [android]
-
- '@rollup/rollup-android-arm64@4.34.7':
- resolution: {integrity: sha512-KvyJpFUueUnSp53zhAa293QBYqwm94TgYTIfXyOTtidhm5V0LbLCJQRGkQClYiX3FXDQGSvPxOTD/6rPStMMDg==}
- cpu: [arm64]
- os: [android]
-
- '@rollup/rollup-darwin-arm64@4.34.7':
- resolution: {integrity: sha512-jq87CjmgL9YIKvs8ybtIC98s/M3HdbqXhllcy9EdLV0yMg1DpxES2gr65nNy7ObNo/vZ/MrOTxt0bE5LinL6mA==}
+ '@rolldown/binding-darwin-arm64@1.0.0-beta.7-commit.30e0395':
+ resolution: {integrity: sha512-2o/ZF2nt59xOksx7WKxYcnuysv9SaMfCgIAUUltbCriZwhfu02Q2I71SNp/Uh/wJ/7zKbIiEEvunTkkEjWUqow==}
cpu: [arm64]
os: [darwin]
- '@rollup/rollup-darwin-x64@4.34.7':
- resolution: {integrity: sha512-rSI/m8OxBjsdnMMg0WEetu/w+LhLAcCDEiL66lmMX4R3oaml3eXz3Dxfvrxs1FbzPbJMaItQiksyMfv1hoIxnA==}
+ '@rolldown/binding-darwin-x64@1.0.0-beta.7-commit.30e0395':
+ resolution: {integrity: sha512-SxlqmJ0dRHwPDRTUnZldVR3wtt1yZUKjMuorgoElFpLDpxGRN9C7wMUB88uw2R+LUkXHmGhgbQZc5TIWz+gi2A==}
cpu: [x64]
os: [darwin]
- '@rollup/rollup-freebsd-arm64@4.34.7':
- resolution: {integrity: sha512-oIoJRy3ZrdsXpFuWDtzsOOa/E/RbRWXVokpVrNnkS7npz8GEG++E1gYbzhYxhxHbO2om1T26BZjVmdIoyN2WtA==}
- cpu: [arm64]
- os: [freebsd]
-
- '@rollup/rollup-freebsd-x64@4.34.7':
- resolution: {integrity: sha512-X++QSLm4NZfZ3VXGVwyHdRf58IBbCu9ammgJxuWZYLX0du6kZvdNqPwrjvDfwmi6wFdvfZ/s6K7ia0E5kI7m8Q==}
+ '@rolldown/binding-freebsd-x64@1.0.0-beta.7-commit.30e0395':
+ resolution: {integrity: sha512-XiBQRJbJmihXHruDUFloWG284y8ZLgUQrlnEOw5Kdz+wxvq1Kxz5aKf62Zrw3lvY8m6F8hBeE93ne2ZDHngQOA==}
cpu: [x64]
os: [freebsd]
- '@rollup/rollup-linux-arm-gnueabihf@4.34.7':
- resolution: {integrity: sha512-Z0TzhrsNqukTz3ISzrvyshQpFnFRfLunYiXxlCRvcrb3nvC5rVKI+ZXPFG/Aa4jhQa1gHgH3A0exHaRRN4VmdQ==}
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.7-commit.30e0395':
+ resolution: {integrity: sha512-tfVAzmJ/nkMSK2o4tDf/pLSuaXieOw+XjWkVqJUHoxt5wufno9tPApOBGEbjbnENkXdR4+1dlZfE0ZmCpdUdvw==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm-musleabihf@4.34.7':
- resolution: {integrity: sha512-nkznpyXekFAbvFBKBy4nNppSgneB1wwG1yx/hujN3wRnhnkrYVugMTCBXED4+Ni6thoWfQuHNYbFjgGH0MBXtw==}
- cpu: [arm]
- os: [linux]
-
- '@rollup/rollup-linux-arm64-gnu@4.34.7':
- resolution: {integrity: sha512-KCjlUkcKs6PjOcxolqrXglBDcfCuUCTVlX5BgzgoJHw+1rWH1MCkETLkLe5iLLS9dP5gKC7mp3y6x8c1oGBUtA==}
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.7-commit.30e0395':
+ resolution: {integrity: sha512-6myOJPi7rr29FPU0BNrNufYDCHR//JsFbZEgj4ykx/22TUUZaOKJoiLNBREplO7b4YCJ9+0pTvvuGTkvmp5esg==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-arm64-musl@4.34.7':
- resolution: {integrity: sha512-uFLJFz6+utmpbR313TTx+NpPuAXbPz4BhTQzgaP0tozlLnGnQ6rCo6tLwaSa6b7l6gRErjLicXQ1iPiXzYotjw==}
+ '@rolldown/binding-linux-arm64-musl@1.0.0-beta.7-commit.30e0395':
+ resolution: {integrity: sha512-VAJlT86fnUJBOwIpZ6Y9DQQDVZ6bYVJPWhGp4EVs3aQfyub/hOvd4RXiLSjaCIL3BafNZhZ+HtqHjIngWaiLwA==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-loongarch64-gnu@4.34.7':
- resolution: {integrity: sha512-ws8pc68UcJJqCpneDFepnwlsMUFoWvPbWXT/XUrJ7rWUL9vLoIN3GAasgG+nCvq8xrE3pIrd+qLX/jotcLy0Qw==}
- cpu: [loong64]
- os: [linux]
-
- '@rollup/rollup-linux-powerpc64le-gnu@4.34.7':
- resolution: {integrity: sha512-vrDk9JDa/BFkxcS2PbWpr0C/LiiSLxFbNOBgfbW6P8TBe9PPHx9Wqbvx2xgNi1TOAyQHQJ7RZFqBiEohm79r0w==}
- cpu: [ppc64]
- os: [linux]
-
- '@rollup/rollup-linux-riscv64-gnu@4.34.7':
- resolution: {integrity: sha512-rB+ejFyjtmSo+g/a4eovDD1lHWHVqizN8P0Hm0RElkINpS0XOdpaXloqM4FBkF9ZWEzg6bezymbpLmeMldfLTw==}
- cpu: [riscv64]
- os: [linux]
-
- '@rollup/rollup-linux-s390x-gnu@4.34.7':
- resolution: {integrity: sha512-nNXNjo4As6dNqRn7OrsnHzwTgtypfRA3u3AKr0B3sOOo+HkedIbn8ZtFnB+4XyKJojIfqDKmbIzO1QydQ8c+Pw==}
- cpu: [s390x]
- os: [linux]
-
- '@rollup/rollup-linux-x64-gnu@4.34.7':
- resolution: {integrity: sha512-9kPVf9ahnpOMSGlCxXGv980wXD0zRR3wyk8+33/MXQIpQEOpaNe7dEHm5LMfyRZRNt9lMEQuH0jUKj15MkM7QA==}
+ '@rolldown/binding-linux-x64-gnu@1.0.0-beta.7-commit.30e0395':
+ resolution: {integrity: sha512-myi+HoUkWSUqMLhVGf8pD6lsfx25TBm6mQcw7qIwXKcX6a0I1SFCHFL3qlqQtXhAdwGKi18M3e5Bz67PdQV5Dg==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-linux-x64-musl@4.34.7':
- resolution: {integrity: sha512-7wJPXRWTTPtTFDFezA8sle/1sdgxDjuMoRXEKtx97ViRxGGkVQYovem+Q8Pr/2HxiHp74SSRG+o6R0Yq0shPwQ==}
+ '@rolldown/binding-linux-x64-musl@1.0.0-beta.7-commit.30e0395':
+ resolution: {integrity: sha512-CMfInIUDGY4y9JOfn30U6o7V9faT2zJs3kMshyaX3GSSmOg0QmvQlzAxWWMyIQKMXHIN0mnYQxPq9AhW2Yz1dg==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-win32-arm64-msvc@4.34.7':
- resolution: {integrity: sha512-MN7aaBC7mAjsiMEZcsJvwNsQVNZShgES/9SzWp1HC9Yjqb5OpexYnRjF7RmE4itbeesHMYYQiAtUAQaSKs2Rfw==}
+ '@rolldown/binding-wasm32-wasi@1.0.0-beta.7-commit.30e0395':
+ resolution: {integrity: sha512-EkjaSUFAAPBld7ojUmMKiSB1A7iWgLaAeSyJaO4m4oIHvzZLsTKmtFnJodT7TMl5IBtO4kpBeWc4v9J+A8MZGQ==}
+ engines: {node: '>=14.21.3'}
+ cpu: [wasm32]
+
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.7-commit.30e0395':
+ resolution: {integrity: sha512-It1vFY6GMg3Yx+rhYzuUa2nq5BY/z5hRT2NtjAOcp+DLOi5swWLoCNozA0QhGhESMnq9Nune71AKImCyIg8Peg==}
cpu: [arm64]
os: [win32]
- '@rollup/rollup-win32-ia32-msvc@4.34.7':
- resolution: {integrity: sha512-aeawEKYswsFu1LhDM9RIgToobquzdtSc4jSVqHV8uApz4FVvhFl/mKh92wc8WpFc6aYCothV/03UjY6y7yLgbg==}
+ '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.7-commit.30e0395':
+ resolution: {integrity: sha512-YSvkr4kb9RoiqObJZGEyYDB01Lf9jpqibFuFb/X9U/UAF/8lyYsjP18M/WD4inyoUBrDbh3wN0f38Una9FGKhQ==}
cpu: [ia32]
os: [win32]
- '@rollup/rollup-win32-x64-msvc@4.34.7':
- resolution: {integrity: sha512-4ZedScpxxIrVO7otcZ8kCX1mZArtH2Wfj3uFCxRJ9NO80gg1XV0U/b2f/MKaGwj2X3QopHfoWiDQ917FRpwY3w==}
+ '@rolldown/binding-win32-x64-msvc@1.0.0-beta.7-commit.30e0395':
+ resolution: {integrity: sha512-znpr7YScTNBki1u+/vk1jLl59/x+q2rrGCJYNm9o/KCOPZPIqCFy4+/y/SJo1eVa7QJdellTi5Z07Z/Bx/iViQ==}
cpu: [x64]
os: [win32]
@@ -4314,8 +4168,13 @@ packages:
'@ucast/mongo@2.4.3':
resolution: {integrity: sha512-XcI8LclrHWP83H+7H2anGCEeDq0n+12FU2mXCTz6/Tva9/9ddK/iacvvhCyW6cijAAOILmt0tWplRyRhVyZLsA==}
- '@vitejs/plugin-react@4.3.4':
- resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==}
+ '@valibot/to-json-schema@1.0.0':
+ resolution: {integrity: sha512-/9crJgPptVsGCL6X+JPDQyaJwkalSZ/52WuF8DiRUxJgcmpNdzYRfZ+gqMEP8W3CTVfuMWPqqvIgfwJ97f9Etw==}
+ peerDependencies:
+ valibot: ^1.0.0
+
+ '@vitejs/plugin-react@4.4.1':
+ resolution: {integrity: sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
vite: ^4.2.0 || ^5.0.0 || ^6.0.0
@@ -4513,6 +4372,10 @@ packages:
resolution: {integrity: sha512-zIcWDJ+Kwqxfdnogx66Gxzr0kVmCcRAdat9nlY2IHsshqTN4fBH6tMeRMPA/2w0rpBayIJvjQAaa2/4RDrNqwg==}
engines: {node: '>=14'}
+ ansis@3.17.0:
+ resolution: {integrity: sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==}
+ engines: {node: '>=14'}
+
anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
@@ -4588,11 +4451,8 @@ packages:
avvio@9.1.0:
resolution: {integrity: sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw==}
- axios@1.7.8:
- resolution: {integrity: sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==}
-
- axios@1.7.9:
- resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
+ axios@1.8.4:
+ resolution: {integrity: sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==}
babel-jest@29.7.0:
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
@@ -5492,11 +5352,6 @@ packages:
engines: {node: '>=12'}
hasBin: true
- esbuild@0.24.2:
- resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
- engines: {node: '>=18'}
- hasBin: true
-
esbuild@0.25.0:
resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==}
engines: {node: '>=18'}
@@ -6665,6 +6520,70 @@ packages:
light-my-request@6.6.0:
resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==}
+ lightningcss-darwin-arm64@1.29.3:
+ resolution: {integrity: sha512-fb7raKO3pXtlNbQbiMeEu8RbBVHnpyqAoxTyTRMEWFQWmscGC2wZxoHzZ+YKAepUuKT9uIW5vL2QbFivTgprZg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ lightningcss-darwin-x64@1.29.3:
+ resolution: {integrity: sha512-KF2XZ4ZdmDGGtEYmx5wpzn6u8vg7AdBHaEOvDKu8GOs7xDL/vcU2vMKtTeNe1d4dogkDdi3B9zC77jkatWBwEQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ lightningcss-freebsd-x64@1.29.3:
+ resolution: {integrity: sha512-VUWeVf+V1UM54jv9M4wen9vMlIAyT69Krl9XjI8SsRxz4tdNV/7QEPlW6JASev/pYdiynUCW0pwaFquDRYdxMw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ lightningcss-linux-arm-gnueabihf@1.29.3:
+ resolution: {integrity: sha512-UhgZ/XVNfXQVEJrMIWeK1Laj8KbhjbIz7F4znUk7G4zeGw7TRoJxhb66uWrEsonn1+O45w//0i0Fu0wIovYdYg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ lightningcss-linux-arm64-gnu@1.29.3:
+ resolution: {integrity: sha512-Pqau7jtgJNmQ/esugfmAT1aCFy/Gxc92FOxI+3n+LbMHBheBnk41xHDhc0HeYlx9G0xP5tK4t0Koy3QGGNqypw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-arm64-musl@1.29.3:
+ resolution: {integrity: sha512-dxakOk66pf7KLS7VRYFO7B8WOJLecE5OPL2YOk52eriFd/yeyxt2Km5H0BjLfElokIaR+qWi33gB8MQLrdAY3A==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-x64-gnu@1.29.3:
+ resolution: {integrity: sha512-ySZTNCpbfbK8rqpKJeJR2S0g/8UqqV3QnzcuWvpI60LWxnFN91nxpSSwCbzfOXkzKfar9j5eOuOplf+klKtINg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-linux-x64-musl@1.29.3:
+ resolution: {integrity: sha512-3pVZhIzW09nzi10usAXfIGTTSTYQ141dk88vGFNCgawIzayiIzZQxEcxVtIkdvlEq2YuFsL9Wcj/h61JHHzuFQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-win32-arm64-msvc@1.29.3:
+ resolution: {integrity: sha512-VRnkAvtIkeWuoBJeGOTrZxsNp4HogXtcaaLm8agmbYtLDOhQdpgxW6NjZZjDXbvGF+eOehGulXZ3C1TiwHY4QQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ lightningcss-win32-x64-msvc@1.29.3:
+ resolution: {integrity: sha512-IszwRPu2cPnDQsZpd7/EAr0x2W7jkaWqQ1SwCVIZ/tSbZVXPLt6k8s6FkcyBjViCzvB5CW0We0QbbP7zp2aBjQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ lightningcss@1.29.3:
+ resolution: {integrity: sha512-GlOJwTIP6TMIlrTFsxTerwC0W6OpQpCGuX1ECRLBUVRh6fpJH3xTqjCjRgQHTb4ZXexH9rtHou1Lf03GKzmhhQ==}
+ engines: {node: '>= 12.0.0'}
+
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
@@ -7332,9 +7251,6 @@ packages:
pgpass@1.0.5:
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
- picocolors@1.0.0:
- resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
-
picocolors@1.0.1:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
@@ -7429,8 +7345,8 @@ packages:
resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==}
engines: {node: ^10 || ^12 || >=14}
- postcss@8.5.2:
- resolution: {integrity: sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==}
+ postcss@8.5.3:
+ resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
engines: {node: ^10 || ^12 || >=14}
postgres-array@2.0.0:
@@ -7698,8 +7614,8 @@ packages:
react-promise-suspense@0.3.4:
resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==}
- react-refresh@0.14.2:
- resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
+ react-refresh@0.17.0:
+ resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
engines: {node: '>=0.10.0'}
react-remove-scroll-bar@2.3.8:
@@ -7918,10 +7834,54 @@ packages:
robust-predicates@3.0.2:
resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==}
- rollup@4.34.7:
- resolution: {integrity: sha512-8qhyN0oZ4x0H6wmBgfKxJtxM7qS98YJ0k0kNh5ECVtuchIJ7z9IVVvzpmtQyT10PXKMtBxYr1wQ5Apg8RS8kXQ==}
- engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ rolldown-vite@6.3.3:
+ resolution: {integrity: sha512-ZmIaiGPNC7bSnc8FOETiesfGtyBSYGy+m7FM6EhcjciBggv6OHd28HSS3NItosI1AXfgVHdrHpyPPy/YrfmkdA==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ esbuild: ^0.25.0
+ jiti: '>=1.21.0'
+ less: '*'
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ esbuild:
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
+ rolldown@1.0.0-beta.7-commit.30e0395:
+ resolution: {integrity: sha512-io3+hz8Eh9wdbX8SaybkPWwo17PDVezp8qEjldCAqfVZ/jXM1xF3lTnwvgMiW0rgsZuPdPSZA7hhtKJ/x6aq8g==}
+ hasBin: true
+ peerDependencies:
+ '@oxc-project/runtime': 0.65.0
+ peerDependenciesMeta:
+ '@oxc-project/runtime':
+ optional: true
rope-sequence@1.3.4:
resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
@@ -8658,6 +8618,14 @@ packages:
resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==}
engines: {node: '>=10.12.0'}
+ valibot@1.0.0:
+ resolution: {integrity: sha512-1Hc0ihzWxBar6NGeZv7fPLY0QuxFMyxwYR2sF1Blu7Wq7EnremwY2W02tit2ij2VJT8HcSkHAQqmFfl77f73Yw==}
+ peerDependencies:
+ typescript: '>=5'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
validate-npm-package-name@5.0.0:
resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -8670,46 +8638,6 @@ packages:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
- vite@6.1.0:
- resolution: {integrity: sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==}
- engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
- hasBin: true
- peerDependencies:
- '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
- jiti: '>=1.21.0'
- less: '*'
- lightningcss: ^1.21.0
- sass: '*'
- sass-embedded: '*'
- stylus: '*'
- sugarss: '*'
- terser: ^5.16.0
- tsx: ^4.8.1
- yaml: ^2.4.2
- peerDependenciesMeta:
- '@types/node':
- optional: true
- jiti:
- optional: true
- less:
- optional: true
- lightningcss:
- optional: true
- sass:
- optional: true
- sass-embedded:
- optional: true
- stylus:
- optional: true
- sugarss:
- optional: true
- terser:
- optional: true
- tsx:
- optional: true
- yaml:
- optional: true
-
void-elements@3.1.0:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
engines: {node: '>=0.10.0'}
@@ -9588,7 +9516,7 @@ snapshots:
'@babel/code-frame@7.24.2':
dependencies:
'@babel/highlight': 7.24.2
- picocolors: 1.0.0
+ picocolors: 1.1.1
'@babel/code-frame@7.26.2':
dependencies:
@@ -9598,6 +9526,8 @@ snapshots:
'@babel/compat-data@7.26.2': {}
+ '@babel/compat-data@7.26.8': {}
+
'@babel/core@7.24.5':
dependencies:
'@ampproject/remapping': 2.3.0
@@ -9658,6 +9588,26 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@babel/core@7.26.10':
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@babel/code-frame': 7.26.2
+ '@babel/generator': 7.27.0
+ '@babel/helper-compilation-targets': 7.27.0
+ '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10)
+ '@babel/helpers': 7.27.0
+ '@babel/parser': 7.27.0
+ '@babel/template': 7.27.0
+ '@babel/traverse': 7.27.0
+ '@babel/types': 7.27.0
+ convert-source-map: 2.0.0
+ debug: 4.3.7
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/generator@7.24.1':
dependencies:
'@babel/types': 7.24.0
@@ -9680,6 +9630,14 @@ snapshots:
'@jridgewell/trace-mapping': 0.3.25
jsesc: 3.0.2
+ '@babel/generator@7.27.0':
+ dependencies:
+ '@babel/parser': 7.27.0
+ '@babel/types': 7.27.0
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
+ jsesc: 3.0.2
+
'@babel/helper-annotate-as-pure@7.22.5':
dependencies:
'@babel/types': 7.26.0
@@ -9696,6 +9654,14 @@ snapshots:
lru-cache: 5.1.1
semver: 6.3.1
+ '@babel/helper-compilation-targets@7.27.0':
+ dependencies:
+ '@babel/compat-data': 7.26.8
+ '@babel/helper-validator-option': 7.25.9
+ browserslist: 4.24.2
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
'@babel/helper-create-class-features-plugin@7.23.7(@babel/core@7.26.0)':
dependencies:
'@babel/core': 7.26.0
@@ -9795,6 +9761,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)':
+ dependencies:
+ '@babel/core': 7.26.10
+ '@babel/helper-module-imports': 7.25.9
+ '@babel/helper-validator-identifier': 7.25.9
+ '@babel/traverse': 7.25.9
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/helper-optimise-call-expression@7.22.5':
dependencies:
'@babel/types': 7.26.0
@@ -9869,25 +9844,30 @@ snapshots:
'@babel/template': 7.25.9
'@babel/types': 7.26.0
+ '@babel/helpers@7.27.0':
+ dependencies:
+ '@babel/template': 7.27.0
+ '@babel/types': 7.27.0
+
'@babel/highlight@7.24.2':
dependencies:
'@babel/helper-validator-identifier': 7.22.20
chalk: 2.4.2
js-tokens: 4.0.0
- picocolors: 1.0.0
+ picocolors: 1.1.1
'@babel/parser@7.24.5':
dependencies:
'@babel/types': 7.26.0
- '@babel/parser@7.24.6':
- dependencies:
- '@babel/types': 7.24.6
-
'@babel/parser@7.26.2':
dependencies:
'@babel/types': 7.26.0
+ '@babel/parser@7.27.0':
+ dependencies:
+ '@babel/types': 7.27.0
+
'@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.26.0)':
dependencies:
'@babel/core': 7.26.0
@@ -10405,14 +10385,14 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)':
+ '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.10)':
dependencies:
- '@babel/core': 7.26.0
+ '@babel/core': 7.26.10
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0)':
+ '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.10)':
dependencies:
- '@babel/core': 7.26.0
+ '@babel/core': 7.26.10
'@babel/helper-plugin-utils': 7.25.9
'@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.26.0)':
@@ -10619,6 +10599,12 @@ snapshots:
'@babel/parser': 7.26.2
'@babel/types': 7.26.0
+ '@babel/template@7.27.0':
+ dependencies:
+ '@babel/code-frame': 7.26.2
+ '@babel/parser': 7.27.0
+ '@babel/types': 7.27.0
+
'@babel/traverse@7.25.9':
dependencies:
'@babel/code-frame': 7.26.2
@@ -10631,6 +10617,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@babel/traverse@7.27.0':
+ dependencies:
+ '@babel/code-frame': 7.26.2
+ '@babel/generator': 7.27.0
+ '@babel/parser': 7.27.0
+ '@babel/template': 7.27.0
+ '@babel/types': 7.27.0
+ debug: 4.3.7
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/types@7.23.6':
dependencies:
'@babel/helper-string-parser': 7.23.4
@@ -10654,6 +10652,11 @@ snapshots:
'@babel/helper-string-parser': 7.25.9
'@babel/helper-validator-identifier': 7.25.9
+ '@babel/types@7.27.0':
+ dependencies:
+ '@babel/helper-string-parser': 7.25.9
+ '@babel/helper-validator-identifier': 7.25.9
+
'@bcoe/v8-coverage@0.2.3': {}
'@braintree/sanitize-url@7.1.0': {}
@@ -10742,219 +10745,144 @@ snapshots:
'@esbuild/aix-ppc64@0.19.11':
optional: true
- '@esbuild/aix-ppc64@0.24.2':
- optional: true
-
'@esbuild/aix-ppc64@0.25.0':
optional: true
'@esbuild/android-arm64@0.19.11':
optional: true
- '@esbuild/android-arm64@0.24.2':
- optional: true
-
'@esbuild/android-arm64@0.25.0':
optional: true
'@esbuild/android-arm@0.19.11':
optional: true
- '@esbuild/android-arm@0.24.2':
- optional: true
-
'@esbuild/android-arm@0.25.0':
optional: true
'@esbuild/android-x64@0.19.11':
optional: true
- '@esbuild/android-x64@0.24.2':
- optional: true
-
'@esbuild/android-x64@0.25.0':
optional: true
'@esbuild/darwin-arm64@0.19.11':
optional: true
- '@esbuild/darwin-arm64@0.24.2':
- optional: true
-
'@esbuild/darwin-arm64@0.25.0':
optional: true
'@esbuild/darwin-x64@0.19.11':
optional: true
- '@esbuild/darwin-x64@0.24.2':
- optional: true
-
'@esbuild/darwin-x64@0.25.0':
optional: true
'@esbuild/freebsd-arm64@0.19.11':
optional: true
- '@esbuild/freebsd-arm64@0.24.2':
- optional: true
-
'@esbuild/freebsd-arm64@0.25.0':
optional: true
'@esbuild/freebsd-x64@0.19.11':
optional: true
- '@esbuild/freebsd-x64@0.24.2':
- optional: true
-
'@esbuild/freebsd-x64@0.25.0':
optional: true
'@esbuild/linux-arm64@0.19.11':
optional: true
- '@esbuild/linux-arm64@0.24.2':
- optional: true
-
'@esbuild/linux-arm64@0.25.0':
optional: true
'@esbuild/linux-arm@0.19.11':
optional: true
- '@esbuild/linux-arm@0.24.2':
- optional: true
-
'@esbuild/linux-arm@0.25.0':
optional: true
'@esbuild/linux-ia32@0.19.11':
optional: true
- '@esbuild/linux-ia32@0.24.2':
- optional: true
-
'@esbuild/linux-ia32@0.25.0':
optional: true
'@esbuild/linux-loong64@0.19.11':
optional: true
- '@esbuild/linux-loong64@0.24.2':
- optional: true
-
'@esbuild/linux-loong64@0.25.0':
optional: true
'@esbuild/linux-mips64el@0.19.11':
optional: true
- '@esbuild/linux-mips64el@0.24.2':
- optional: true
-
'@esbuild/linux-mips64el@0.25.0':
optional: true
'@esbuild/linux-ppc64@0.19.11':
optional: true
- '@esbuild/linux-ppc64@0.24.2':
- optional: true
-
'@esbuild/linux-ppc64@0.25.0':
optional: true
'@esbuild/linux-riscv64@0.19.11':
optional: true
- '@esbuild/linux-riscv64@0.24.2':
- optional: true
-
'@esbuild/linux-riscv64@0.25.0':
optional: true
'@esbuild/linux-s390x@0.19.11':
optional: true
- '@esbuild/linux-s390x@0.24.2':
- optional: true
-
'@esbuild/linux-s390x@0.25.0':
optional: true
'@esbuild/linux-x64@0.19.11':
optional: true
- '@esbuild/linux-x64@0.24.2':
- optional: true
-
'@esbuild/linux-x64@0.25.0':
optional: true
- '@esbuild/netbsd-arm64@0.24.2':
- optional: true
-
'@esbuild/netbsd-arm64@0.25.0':
optional: true
'@esbuild/netbsd-x64@0.19.11':
optional: true
- '@esbuild/netbsd-x64@0.24.2':
- optional: true
-
'@esbuild/netbsd-x64@0.25.0':
optional: true
- '@esbuild/openbsd-arm64@0.24.2':
- optional: true
-
'@esbuild/openbsd-arm64@0.25.0':
optional: true
'@esbuild/openbsd-x64@0.19.11':
optional: true
- '@esbuild/openbsd-x64@0.24.2':
- optional: true
-
'@esbuild/openbsd-x64@0.25.0':
optional: true
'@esbuild/sunos-x64@0.19.11':
optional: true
- '@esbuild/sunos-x64@0.24.2':
- optional: true
-
'@esbuild/sunos-x64@0.25.0':
optional: true
'@esbuild/win32-arm64@0.19.11':
optional: true
- '@esbuild/win32-arm64@0.24.2':
- optional: true
-
'@esbuild/win32-arm64@0.25.0':
optional: true
'@esbuild/win32-ia32@0.19.11':
optional: true
- '@esbuild/win32-ia32@0.24.2':
- optional: true
-
'@esbuild/win32-ia32@0.25.0':
optional: true
'@esbuild/win32-x64@0.19.11':
optional: true
- '@esbuild/win32-x64@0.24.2':
- optional: true
-
'@esbuild/win32-x64@0.25.0':
optional: true
@@ -11919,7 +11847,7 @@ snapshots:
tslib: 2.8.0
yargs-parser: 21.1.1
- '@nx/js@20.4.5(@babel/traverse@7.25.9)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)':
+ '@nx/js@20.4.5(@babel/traverse@7.27.0)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)':
dependencies:
'@babel/core': 7.26.0
'@babel/plugin-proposal-decorators': 7.23.7(@babel/core@7.26.0)
@@ -11933,7 +11861,7 @@ snapshots:
'@zkochan/js-yaml': 0.0.7
babel-plugin-const-enum: 1.2.0(@babel/core@7.26.0)
babel-plugin-macros: 3.1.0
- babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.26.0)(@babel/traverse@7.25.9)
+ babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.26.0)(@babel/traverse@7.27.0)
chalk: 4.1.2
columnify: 1.6.0
detect-port: 1.5.1
@@ -12010,6 +11938,10 @@ snapshots:
'@opentelemetry/api@1.9.0':
optional: true
+ '@oxc-project/runtime@0.65.0': {}
+
+ '@oxc-project/types@0.65.0': {}
+
'@pkgjs/parseargs@0.11.0':
optional: true
@@ -12135,61 +12067,42 @@ snapshots:
'@remirror/core-constants@3.0.0': {}
- '@rollup/rollup-android-arm-eabi@4.34.7':
+ '@rolldown/binding-darwin-arm64@1.0.0-beta.7-commit.30e0395':
optional: true
- '@rollup/rollup-android-arm64@4.34.7':
+ '@rolldown/binding-darwin-x64@1.0.0-beta.7-commit.30e0395':
optional: true
- '@rollup/rollup-darwin-arm64@4.34.7':
+ '@rolldown/binding-freebsd-x64@1.0.0-beta.7-commit.30e0395':
optional: true
- '@rollup/rollup-darwin-x64@4.34.7':
+ '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.7-commit.30e0395':
optional: true
- '@rollup/rollup-freebsd-arm64@4.34.7':
+ '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.7-commit.30e0395':
optional: true
- '@rollup/rollup-freebsd-x64@4.34.7':
+ '@rolldown/binding-linux-arm64-musl@1.0.0-beta.7-commit.30e0395':
optional: true
- '@rollup/rollup-linux-arm-gnueabihf@4.34.7':
+ '@rolldown/binding-linux-x64-gnu@1.0.0-beta.7-commit.30e0395':
optional: true
- '@rollup/rollup-linux-arm-musleabihf@4.34.7':
+ '@rolldown/binding-linux-x64-musl@1.0.0-beta.7-commit.30e0395':
optional: true
- '@rollup/rollup-linux-arm64-gnu@4.34.7':
+ '@rolldown/binding-wasm32-wasi@1.0.0-beta.7-commit.30e0395':
+ dependencies:
+ '@napi-rs/wasm-runtime': 0.2.4
optional: true
- '@rollup/rollup-linux-arm64-musl@4.34.7':
+ '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.7-commit.30e0395':
optional: true
- '@rollup/rollup-linux-loongarch64-gnu@4.34.7':
+ '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.7-commit.30e0395':
optional: true
- '@rollup/rollup-linux-powerpc64le-gnu@4.34.7':
- optional: true
-
- '@rollup/rollup-linux-riscv64-gnu@4.34.7':
- optional: true
-
- '@rollup/rollup-linux-s390x-gnu@4.34.7':
- optional: true
-
- '@rollup/rollup-linux-x64-gnu@4.34.7':
- optional: true
-
- '@rollup/rollup-linux-x64-musl@4.34.7':
- optional: true
-
- '@rollup/rollup-win32-arm64-msvc@4.34.7':
- optional: true
-
- '@rollup/rollup-win32-ia32-msvc@4.34.7':
- optional: true
-
- '@rollup/rollup-win32-x64-msvc@4.34.7':
+ '@rolldown/binding-win32-x64-msvc@1.0.0-beta.7-commit.30e0395':
optional: true
'@selderee/plugin-htmlparser2@0.11.0':
@@ -12926,20 +12839,20 @@ snapshots:
'@types/babel__core@7.20.5':
dependencies:
- '@babel/parser': 7.24.6
- '@babel/types': 7.24.6
+ '@babel/parser': 7.26.2
+ '@babel/types': 7.26.0
'@types/babel__generator': 7.6.8
'@types/babel__template': 7.4.4
'@types/babel__traverse': 7.20.5
'@types/babel__generator@7.6.8':
dependencies:
- '@babel/types': 7.24.6
+ '@babel/types': 7.26.0
'@types/babel__template@7.4.4':
dependencies:
- '@babel/parser': 7.24.6
- '@babel/types': 7.24.6
+ '@babel/parser': 7.26.2
+ '@babel/types': 7.26.0
'@types/babel__traverse@7.20.5':
dependencies:
@@ -13485,14 +13398,18 @@ snapshots:
dependencies:
'@ucast/core': 1.10.2
- '@vitejs/plugin-react@4.3.4(vite@6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))':
+ '@valibot/to-json-schema@1.0.0(valibot@1.0.0(typescript@5.7.2))':
dependencies:
- '@babel/core': 7.26.0
- '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0)
- '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0)
+ valibot: 1.0.0(typescript@5.7.2)
+
+ '@vitejs/plugin-react@4.4.1(rolldown-vite@6.3.3(@types/node@22.10.0)(esbuild@0.25.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.2)(yaml@2.7.0))':
+ dependencies:
+ '@babel/core': 7.26.10
+ '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10)
+ '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10)
'@types/babel__core': 7.20.5
- react-refresh: 0.14.2
- vite: 6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)
+ react-refresh: 0.17.0
+ vite: rolldown-vite@6.3.3(@types/node@22.10.0)(esbuild@0.25.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.2)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
@@ -13700,6 +13617,8 @@ snapshots:
ansis@3.15.0: {}
+ ansis@3.17.0: {}
+
anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
@@ -13797,15 +13716,7 @@ snapshots:
'@fastify/error': 4.0.0
fastq: 1.17.1
- axios@1.7.8:
- dependencies:
- follow-redirects: 1.15.6
- form-data: 4.0.0
- proxy-from-env: 1.1.0
- transitivePeerDependencies:
- - debug
-
- axios@1.7.9:
+ axios@1.8.4:
dependencies:
follow-redirects: 1.15.6
form-data: 4.0.0
@@ -13896,12 +13807,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
- babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.26.0)(@babel/traverse@7.25.9):
+ babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.26.0)(@babel/traverse@7.27.0):
dependencies:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
optionalDependencies:
- '@babel/traverse': 7.25.9
+ '@babel/traverse': 7.27.0
babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.5):
dependencies:
@@ -14910,34 +14821,6 @@ snapshots:
'@esbuild/win32-ia32': 0.19.11
'@esbuild/win32-x64': 0.19.11
- esbuild@0.24.2:
- optionalDependencies:
- '@esbuild/aix-ppc64': 0.24.2
- '@esbuild/android-arm': 0.24.2
- '@esbuild/android-arm64': 0.24.2
- '@esbuild/android-x64': 0.24.2
- '@esbuild/darwin-arm64': 0.24.2
- '@esbuild/darwin-x64': 0.24.2
- '@esbuild/freebsd-arm64': 0.24.2
- '@esbuild/freebsd-x64': 0.24.2
- '@esbuild/linux-arm': 0.24.2
- '@esbuild/linux-arm64': 0.24.2
- '@esbuild/linux-ia32': 0.24.2
- '@esbuild/linux-loong64': 0.24.2
- '@esbuild/linux-mips64el': 0.24.2
- '@esbuild/linux-ppc64': 0.24.2
- '@esbuild/linux-riscv64': 0.24.2
- '@esbuild/linux-s390x': 0.24.2
- '@esbuild/linux-x64': 0.24.2
- '@esbuild/netbsd-arm64': 0.24.2
- '@esbuild/netbsd-x64': 0.24.2
- '@esbuild/openbsd-arm64': 0.24.2
- '@esbuild/openbsd-x64': 0.24.2
- '@esbuild/sunos-x64': 0.24.2
- '@esbuild/win32-arm64': 0.24.2
- '@esbuild/win32-ia32': 0.24.2
- '@esbuild/win32-x64': 0.24.2
-
esbuild@0.25.0:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.0
@@ -16432,6 +16315,51 @@ snapshots:
process-warning: 4.0.0
set-cookie-parser: 2.6.0
+ lightningcss-darwin-arm64@1.29.3:
+ optional: true
+
+ lightningcss-darwin-x64@1.29.3:
+ optional: true
+
+ lightningcss-freebsd-x64@1.29.3:
+ optional: true
+
+ lightningcss-linux-arm-gnueabihf@1.29.3:
+ optional: true
+
+ lightningcss-linux-arm64-gnu@1.29.3:
+ optional: true
+
+ lightningcss-linux-arm64-musl@1.29.3:
+ optional: true
+
+ lightningcss-linux-x64-gnu@1.29.3:
+ optional: true
+
+ lightningcss-linux-x64-musl@1.29.3:
+ optional: true
+
+ lightningcss-win32-arm64-msvc@1.29.3:
+ optional: true
+
+ lightningcss-win32-x64-msvc@1.29.3:
+ optional: true
+
+ lightningcss@1.29.3:
+ dependencies:
+ detect-libc: 2.0.3
+ optionalDependencies:
+ lightningcss-darwin-arm64: 1.29.3
+ lightningcss-darwin-x64: 1.29.3
+ lightningcss-freebsd-x64: 1.29.3
+ lightningcss-linux-arm-gnueabihf: 1.29.3
+ lightningcss-linux-arm64-gnu: 1.29.3
+ lightningcss-linux-arm64-musl: 1.29.3
+ lightningcss-linux-x64-gnu: 1.29.3
+ lightningcss-linux-x64-musl: 1.29.3
+ lightningcss-win32-arm64-msvc: 1.29.3
+ lightningcss-win32-x64-msvc: 1.29.3
+
lines-and-columns@1.2.4: {}
lines-and-columns@2.0.3: {}
@@ -16814,7 +16742,7 @@ snapshots:
'@yarnpkg/lockfile': 1.1.0
'@yarnpkg/parsers': 3.0.2
'@zkochan/js-yaml': 0.0.7
- axios: 1.7.9
+ axios: 1.8.4
chalk: 4.1.2
cli-cursor: 3.1.0
cli-spinners: 2.6.1
@@ -17119,8 +17047,6 @@ snapshots:
dependencies:
split2: 4.2.0
- picocolors@1.0.0: {}
-
picocolors@1.0.1: {}
picocolors@1.1.1: {}
@@ -17221,7 +17147,7 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
- postcss@8.5.2:
+ postcss@8.5.3:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
@@ -17251,7 +17177,7 @@ snapshots:
postmark@4.0.5:
dependencies:
- axios: 1.7.8
+ axios: 1.8.4
transitivePeerDependencies:
- debug
@@ -17528,7 +17454,7 @@ snapshots:
dependencies:
fast-deep-equal: 2.0.1
- react-refresh@0.14.2: {}
+ react-refresh@0.17.0: {}
react-remove-scroll-bar@2.3.8(@types/react@18.3.12)(react@18.3.1):
dependencies:
@@ -17749,30 +17675,50 @@ snapshots:
robust-predicates@3.0.2: {}
- rollup@4.34.7:
+ rolldown-vite@6.3.3(@types/node@22.10.0)(esbuild@0.25.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.2)(yaml@2.7.0):
dependencies:
- '@types/estree': 1.0.6
+ '@oxc-project/runtime': 0.65.0
+ fdir: 6.4.3(picomatch@4.0.2)
+ lightningcss: 1.29.3
+ picomatch: 4.0.2
+ postcss: 8.5.3
+ rolldown: 1.0.0-beta.7-commit.30e0395(@oxc-project/runtime@0.65.0)(typescript@5.7.2)
+ tinyglobby: 0.2.12
optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.34.7
- '@rollup/rollup-android-arm64': 4.34.7
- '@rollup/rollup-darwin-arm64': 4.34.7
- '@rollup/rollup-darwin-x64': 4.34.7
- '@rollup/rollup-freebsd-arm64': 4.34.7
- '@rollup/rollup-freebsd-x64': 4.34.7
- '@rollup/rollup-linux-arm-gnueabihf': 4.34.7
- '@rollup/rollup-linux-arm-musleabihf': 4.34.7
- '@rollup/rollup-linux-arm64-gnu': 4.34.7
- '@rollup/rollup-linux-arm64-musl': 4.34.7
- '@rollup/rollup-linux-loongarch64-gnu': 4.34.7
- '@rollup/rollup-linux-powerpc64le-gnu': 4.34.7
- '@rollup/rollup-linux-riscv64-gnu': 4.34.7
- '@rollup/rollup-linux-s390x-gnu': 4.34.7
- '@rollup/rollup-linux-x64-gnu': 4.34.7
- '@rollup/rollup-linux-x64-musl': 4.34.7
- '@rollup/rollup-win32-arm64-msvc': 4.34.7
- '@rollup/rollup-win32-ia32-msvc': 4.34.7
- '@rollup/rollup-win32-x64-msvc': 4.34.7
+ '@types/node': 22.10.0
+ esbuild: 0.25.0
fsevents: 2.3.3
+ jiti: 1.21.0
+ less: 4.2.0
+ sugarss: 4.0.1(postcss@8.4.49)
+ terser: 5.39.0
+ tsx: 4.19.3
+ yaml: 2.7.0
+ transitivePeerDependencies:
+ - typescript
+
+ rolldown@1.0.0-beta.7-commit.30e0395(@oxc-project/runtime@0.65.0)(typescript@5.7.2):
+ dependencies:
+ '@oxc-project/types': 0.65.0
+ '@valibot/to-json-schema': 1.0.0(valibot@1.0.0(typescript@5.7.2))
+ ansis: 3.17.0
+ valibot: 1.0.0(typescript@5.7.2)
+ optionalDependencies:
+ '@oxc-project/runtime': 0.65.0
+ '@rolldown/binding-darwin-arm64': 1.0.0-beta.7-commit.30e0395
+ '@rolldown/binding-darwin-x64': 1.0.0-beta.7-commit.30e0395
+ '@rolldown/binding-freebsd-x64': 1.0.0-beta.7-commit.30e0395
+ '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.7-commit.30e0395
+ '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.7-commit.30e0395
+ '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.7-commit.30e0395
+ '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.7-commit.30e0395
+ '@rolldown/binding-linux-x64-musl': 1.0.0-beta.7-commit.30e0395
+ '@rolldown/binding-wasm32-wasi': 1.0.0-beta.7-commit.30e0395
+ '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.7-commit.30e0395
+ '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.7-commit.30e0395
+ '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.7-commit.30e0395
+ transitivePeerDependencies:
+ - typescript
rope-sequence@1.3.4: {}
@@ -18538,6 +18484,10 @@ snapshots:
'@types/istanbul-lib-coverage': 2.0.6
convert-source-map: 2.0.0
+ valibot@1.0.0(typescript@5.7.2):
+ optionalDependencies:
+ typescript: 5.7.2
+
validate-npm-package-name@5.0.0:
dependencies:
builtins: 5.0.1
@@ -18546,21 +18496,6 @@ snapshots:
vary@1.1.2: {}
- vite@6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0):
- dependencies:
- esbuild: 0.24.2
- postcss: 8.5.2
- rollup: 4.34.7
- optionalDependencies:
- '@types/node': 22.10.0
- fsevents: 2.3.3
- jiti: 1.21.0
- less: 4.2.0
- sugarss: 4.0.1(postcss@8.4.49)
- terser: 5.39.0
- tsx: 4.19.3
- yaml: 2.7.0
-
void-elements@3.1.0: {}
vscode-jsonrpc@8.2.0: {}
From 882f3093bda7d0ef3587bf7a006f0801bc1c1a03 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 22 Apr 2025 19:37:06 +0100
Subject: [PATCH 24/63] search space members by email (#1049)
---
apps/server/src/database/repos/space/space-member.repo.ts | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/apps/server/src/database/repos/space/space-member.repo.ts b/apps/server/src/database/repos/space/space-member.repo.ts
index 67275034..b9c4fbf9 100644
--- a/apps/server/src/database/repos/space/space-member.repo.ts
+++ b/apps/server/src/database/repos/space/space-member.repo.ts
@@ -119,11 +119,9 @@ export class SpaceMemberRepo {
if (pagination.query) {
query = query.where((eb) =>
- eb('users.name', 'ilike', `%${pagination.query}%`).or(
- 'groups.name',
- 'ilike',
- `%${pagination.query}%`,
- ),
+ eb('users.name', 'ilike', `%${pagination.query}%`)
+ .or('users.email', 'ilike', `%${pagination.query}%`)
+ .or('groups.name', 'ilike', `%${pagination.query}%`),
);
}
From 37a1804db9f4996951fee7c38bd3ea66e8dca3a3 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 22 Apr 2025 20:00:36 +0100
Subject: [PATCH 25/63] Revert "switch to vite rolldown (#1048)" (#1050)
This reverts commit 1a1b2c8682ccd08062d8486d3ddd0b60989a9dd5.
---
apps/client/package.json | 6 +-
pnpm-lock.yaml | 929 +++++++++++++++++++++------------------
2 files changed, 500 insertions(+), 435 deletions(-)
diff --git a/apps/client/package.json b/apps/client/package.json
index 74e3c21e..5901a920 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -25,7 +25,7 @@
"@tabler/icons-react": "^3.22.0",
"@tanstack/react-query": "^5.61.4",
"@tiptap/extension-character-count": "^2.11.5",
- "axios": "^1.8.4",
+ "axios": "^1.7.9",
"clsx": "^2.1.1",
"emoji-mart": "^5.6.0",
"file-saver": "^2.0.5",
@@ -63,7 +63,7 @@
"@types/node": "22.10.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
- "@vitejs/plugin-react": "^4.4.1",
+ "@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.15.0",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.1.0",
@@ -76,6 +76,6 @@
"prettier": "^3.4.1",
"typescript": "^5.7.2",
"typescript-eslint": "^8.17.0",
- "vite": "npm:rolldown-vite@latest"
+ "vite": "^6.1.0"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d5eaf2ae..f9cc1623 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -181,7 +181,7 @@ importers:
devDependencies:
'@nx/js':
specifier: 20.4.5
- version: 20.4.5(@babel/traverse@7.27.0)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)
+ version: 20.4.5(@babel/traverse@7.25.9)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)
'@types/bytes':
specifier: ^3.1.5
version: 3.1.5
@@ -246,8 +246,8 @@ importers:
specifier: ^2.11.5
version: 2.11.5(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)
axios:
- specifier: ^1.8.4
- version: 1.8.4
+ specifier: ^1.7.9
+ version: 1.7.9
clsx:
specifier: ^2.1.1
version: 2.1.1
@@ -355,8 +355,8 @@ importers:
specifier: ^18.3.1
version: 18.3.1
'@vitejs/plugin-react':
- specifier: ^4.4.1
- version: 4.4.1(rolldown-vite@6.3.3(@types/node@22.10.0)(esbuild@0.25.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.2)(yaml@2.7.0))
+ specifier: ^4.3.4
+ version: 4.3.4(vite@6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))
eslint:
specifier: ^9.15.0
version: 9.15.0(jiti@1.21.0)
@@ -394,8 +394,8 @@ importers:
specifier: ^8.17.0
version: 8.17.0(eslint@9.15.0(jiti@1.21.0))(typescript@5.7.2)
vite:
- specifier: npm:rolldown-vite@latest
- version: rolldown-vite@6.3.3(@types/node@22.10.0)(esbuild@0.25.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.2)(yaml@2.7.0)
+ specifier: ^6.1.0
+ version: 6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)
apps/server:
dependencies:
@@ -876,10 +876,6 @@ packages:
resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==}
engines: {node: '>=6.9.0'}
- '@babel/compat-data@7.26.8':
- resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==}
- engines: {node: '>=6.9.0'}
-
'@babel/core@7.24.5':
resolution: {integrity: sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==}
engines: {node: '>=6.9.0'}
@@ -892,10 +888,6 @@ packages:
resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==}
engines: {node: '>=6.9.0'}
- '@babel/core@7.26.10':
- resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==}
- engines: {node: '>=6.9.0'}
-
'@babel/generator@7.24.1':
resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==}
engines: {node: '>=6.9.0'}
@@ -908,10 +900,6 @@ packages:
resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==}
engines: {node: '>=6.9.0'}
- '@babel/generator@7.27.0':
- resolution: {integrity: sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==}
- engines: {node: '>=6.9.0'}
-
'@babel/helper-annotate-as-pure@7.22.5':
resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
engines: {node: '>=6.9.0'}
@@ -924,10 +912,6 @@ packages:
resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==}
engines: {node: '>=6.9.0'}
- '@babel/helper-compilation-targets@7.27.0':
- resolution: {integrity: sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==}
- engines: {node: '>=6.9.0'}
-
'@babel/helper-create-class-features-plugin@7.23.7':
resolution: {integrity: sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==}
engines: {node: '>=6.9.0'}
@@ -1083,10 +1067,6 @@ packages:
resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==}
engines: {node: '>=6.9.0'}
- '@babel/helpers@7.27.0':
- resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==}
- engines: {node: '>=6.9.0'}
-
'@babel/highlight@7.24.2':
resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==}
engines: {node: '>=6.9.0'}
@@ -1096,13 +1076,13 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/parser@7.26.2':
- resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==}
+ '@babel/parser@7.24.6':
+ resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==}
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/parser@7.27.0':
- resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==}
+ '@babel/parser@7.26.2':
+ resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==}
engines: {node: '>=6.0.0'}
hasBin: true
@@ -1603,18 +1583,10 @@ packages:
resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==}
engines: {node: '>=6.9.0'}
- '@babel/template@7.27.0':
- resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==}
- engines: {node: '>=6.9.0'}
-
'@babel/traverse@7.25.9':
resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==}
engines: {node: '>=6.9.0'}
- '@babel/traverse@7.27.0':
- resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==}
- engines: {node: '>=6.9.0'}
-
'@babel/types@7.23.6':
resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==}
engines: {node: '>=6.9.0'}
@@ -1631,10 +1603,6 @@ packages:
resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==}
engines: {node: '>=6.9.0'}
- '@babel/types@7.27.0':
- resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==}
- engines: {node: '>=6.9.0'}
-
'@bcoe/v8-coverage@0.2.3':
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
@@ -1733,6 +1701,12 @@ packages:
cpu: [ppc64]
os: [aix]
+ '@esbuild/aix-ppc64@0.24.2':
+ resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [aix]
+
'@esbuild/aix-ppc64@0.25.0':
resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==}
engines: {node: '>=18'}
@@ -1745,6 +1719,12 @@ packages:
cpu: [arm64]
os: [android]
+ '@esbuild/android-arm64@0.24.2':
+ resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [android]
+
'@esbuild/android-arm64@0.25.0':
resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==}
engines: {node: '>=18'}
@@ -1757,6 +1737,12 @@ packages:
cpu: [arm]
os: [android]
+ '@esbuild/android-arm@0.24.2':
+ resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [android]
+
'@esbuild/android-arm@0.25.0':
resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==}
engines: {node: '>=18'}
@@ -1769,6 +1755,12 @@ packages:
cpu: [x64]
os: [android]
+ '@esbuild/android-x64@0.24.2':
+ resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [android]
+
'@esbuild/android-x64@0.25.0':
resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==}
engines: {node: '>=18'}
@@ -1781,6 +1773,12 @@ packages:
cpu: [arm64]
os: [darwin]
+ '@esbuild/darwin-arm64@0.24.2':
+ resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [darwin]
+
'@esbuild/darwin-arm64@0.25.0':
resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==}
engines: {node: '>=18'}
@@ -1793,6 +1791,12 @@ packages:
cpu: [x64]
os: [darwin]
+ '@esbuild/darwin-x64@0.24.2':
+ resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [darwin]
+
'@esbuild/darwin-x64@0.25.0':
resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==}
engines: {node: '>=18'}
@@ -1805,6 +1809,12 @@ packages:
cpu: [arm64]
os: [freebsd]
+ '@esbuild/freebsd-arm64@0.24.2':
+ resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [freebsd]
+
'@esbuild/freebsd-arm64@0.25.0':
resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==}
engines: {node: '>=18'}
@@ -1817,6 +1827,12 @@ packages:
cpu: [x64]
os: [freebsd]
+ '@esbuild/freebsd-x64@0.24.2':
+ resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [freebsd]
+
'@esbuild/freebsd-x64@0.25.0':
resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==}
engines: {node: '>=18'}
@@ -1829,6 +1845,12 @@ packages:
cpu: [arm64]
os: [linux]
+ '@esbuild/linux-arm64@0.24.2':
+ resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [linux]
+
'@esbuild/linux-arm64@0.25.0':
resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==}
engines: {node: '>=18'}
@@ -1841,6 +1863,12 @@ packages:
cpu: [arm]
os: [linux]
+ '@esbuild/linux-arm@0.24.2':
+ resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==}
+ engines: {node: '>=18'}
+ cpu: [arm]
+ os: [linux]
+
'@esbuild/linux-arm@0.25.0':
resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==}
engines: {node: '>=18'}
@@ -1853,6 +1881,12 @@ packages:
cpu: [ia32]
os: [linux]
+ '@esbuild/linux-ia32@0.24.2':
+ resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [linux]
+
'@esbuild/linux-ia32@0.25.0':
resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==}
engines: {node: '>=18'}
@@ -1865,6 +1899,12 @@ packages:
cpu: [loong64]
os: [linux]
+ '@esbuild/linux-loong64@0.24.2':
+ resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==}
+ engines: {node: '>=18'}
+ cpu: [loong64]
+ os: [linux]
+
'@esbuild/linux-loong64@0.25.0':
resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==}
engines: {node: '>=18'}
@@ -1877,6 +1917,12 @@ packages:
cpu: [mips64el]
os: [linux]
+ '@esbuild/linux-mips64el@0.24.2':
+ resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==}
+ engines: {node: '>=18'}
+ cpu: [mips64el]
+ os: [linux]
+
'@esbuild/linux-mips64el@0.25.0':
resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==}
engines: {node: '>=18'}
@@ -1889,6 +1935,12 @@ packages:
cpu: [ppc64]
os: [linux]
+ '@esbuild/linux-ppc64@0.24.2':
+ resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==}
+ engines: {node: '>=18'}
+ cpu: [ppc64]
+ os: [linux]
+
'@esbuild/linux-ppc64@0.25.0':
resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==}
engines: {node: '>=18'}
@@ -1901,6 +1953,12 @@ packages:
cpu: [riscv64]
os: [linux]
+ '@esbuild/linux-riscv64@0.24.2':
+ resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==}
+ engines: {node: '>=18'}
+ cpu: [riscv64]
+ os: [linux]
+
'@esbuild/linux-riscv64@0.25.0':
resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==}
engines: {node: '>=18'}
@@ -1913,6 +1971,12 @@ packages:
cpu: [s390x]
os: [linux]
+ '@esbuild/linux-s390x@0.24.2':
+ resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==}
+ engines: {node: '>=18'}
+ cpu: [s390x]
+ os: [linux]
+
'@esbuild/linux-s390x@0.25.0':
resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==}
engines: {node: '>=18'}
@@ -1925,12 +1989,24 @@ packages:
cpu: [x64]
os: [linux]
+ '@esbuild/linux-x64@0.24.2':
+ resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [linux]
+
'@esbuild/linux-x64@0.25.0':
resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
+ '@esbuild/netbsd-arm64@0.24.2':
+ resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [netbsd]
+
'@esbuild/netbsd-arm64@0.25.0':
resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==}
engines: {node: '>=18'}
@@ -1943,12 +2019,24 @@ packages:
cpu: [x64]
os: [netbsd]
+ '@esbuild/netbsd-x64@0.24.2':
+ resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [netbsd]
+
'@esbuild/netbsd-x64@0.25.0':
resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
+ '@esbuild/openbsd-arm64@0.24.2':
+ resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [openbsd]
+
'@esbuild/openbsd-arm64@0.25.0':
resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==}
engines: {node: '>=18'}
@@ -1961,6 +2049,12 @@ packages:
cpu: [x64]
os: [openbsd]
+ '@esbuild/openbsd-x64@0.24.2':
+ resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [openbsd]
+
'@esbuild/openbsd-x64@0.25.0':
resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==}
engines: {node: '>=18'}
@@ -1973,6 +2067,12 @@ packages:
cpu: [x64]
os: [sunos]
+ '@esbuild/sunos-x64@0.24.2':
+ resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [sunos]
+
'@esbuild/sunos-x64@0.25.0':
resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==}
engines: {node: '>=18'}
@@ -1985,6 +2085,12 @@ packages:
cpu: [arm64]
os: [win32]
+ '@esbuild/win32-arm64@0.24.2':
+ resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==}
+ engines: {node: '>=18'}
+ cpu: [arm64]
+ os: [win32]
+
'@esbuild/win32-arm64@0.25.0':
resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==}
engines: {node: '>=18'}
@@ -1997,6 +2103,12 @@ packages:
cpu: [ia32]
os: [win32]
+ '@esbuild/win32-ia32@0.24.2':
+ resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==}
+ engines: {node: '>=18'}
+ cpu: [ia32]
+ os: [win32]
+
'@esbuild/win32-ia32@0.25.0':
resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==}
engines: {node: '>=18'}
@@ -2009,6 +2121,12 @@ packages:
cpu: [x64]
os: [win32]
+ '@esbuild/win32-x64@0.24.2':
+ resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==}
+ engines: {node: '>=18'}
+ cpu: [x64]
+ os: [win32]
+
'@esbuild/win32-x64@0.25.0':
resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==}
engines: {node: '>=18'}
@@ -2902,13 +3020,6 @@ packages:
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
engines: {node: '>=8.0.0'}
- '@oxc-project/runtime@0.65.0':
- resolution: {integrity: sha512-qn70kbkGtJ3uWz+HXha+kufRXkT+pZWckJKL8jUPzXH5UNszSSwADkNQhb7/uit3tC70wFm9qPRlLHnJcjSGuA==}
- engines: {node: '>=6.9.0'}
-
- '@oxc-project/types@0.65.0':
- resolution: {integrity: sha512-7MpMzyXCcwxrTxJ4L0siy63Ds/LA8LAM4szumTFiynxTJkfrIZEV4PyR4Th0CqFZQ+oNi8WvW3Dr1MLy7o9qPQ==}
-
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@@ -3053,63 +3164,98 @@ packages:
'@remirror/core-constants@3.0.0':
resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==}
- '@rolldown/binding-darwin-arm64@1.0.0-beta.7-commit.30e0395':
- resolution: {integrity: sha512-2o/ZF2nt59xOksx7WKxYcnuysv9SaMfCgIAUUltbCriZwhfu02Q2I71SNp/Uh/wJ/7zKbIiEEvunTkkEjWUqow==}
+ '@rollup/rollup-android-arm-eabi@4.34.7':
+ resolution: {integrity: sha512-l6CtzHYo8D2TQ3J7qJNpp3Q1Iye56ssIAtqbM2H8axxCEEwvN7o8Ze9PuIapbxFL3OHrJU2JBX6FIIVnP/rYyw==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.34.7':
+ resolution: {integrity: sha512-KvyJpFUueUnSp53zhAa293QBYqwm94TgYTIfXyOTtidhm5V0LbLCJQRGkQClYiX3FXDQGSvPxOTD/6rPStMMDg==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.34.7':
+ resolution: {integrity: sha512-jq87CjmgL9YIKvs8ybtIC98s/M3HdbqXhllcy9EdLV0yMg1DpxES2gr65nNy7ObNo/vZ/MrOTxt0bE5LinL6mA==}
cpu: [arm64]
os: [darwin]
- '@rolldown/binding-darwin-x64@1.0.0-beta.7-commit.30e0395':
- resolution: {integrity: sha512-SxlqmJ0dRHwPDRTUnZldVR3wtt1yZUKjMuorgoElFpLDpxGRN9C7wMUB88uw2R+LUkXHmGhgbQZc5TIWz+gi2A==}
+ '@rollup/rollup-darwin-x64@4.34.7':
+ resolution: {integrity: sha512-rSI/m8OxBjsdnMMg0WEetu/w+LhLAcCDEiL66lmMX4R3oaml3eXz3Dxfvrxs1FbzPbJMaItQiksyMfv1hoIxnA==}
cpu: [x64]
os: [darwin]
- '@rolldown/binding-freebsd-x64@1.0.0-beta.7-commit.30e0395':
- resolution: {integrity: sha512-XiBQRJbJmihXHruDUFloWG284y8ZLgUQrlnEOw5Kdz+wxvq1Kxz5aKf62Zrw3lvY8m6F8hBeE93ne2ZDHngQOA==}
+ '@rollup/rollup-freebsd-arm64@4.34.7':
+ resolution: {integrity: sha512-oIoJRy3ZrdsXpFuWDtzsOOa/E/RbRWXVokpVrNnkS7npz8GEG++E1gYbzhYxhxHbO2om1T26BZjVmdIoyN2WtA==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.34.7':
+ resolution: {integrity: sha512-X++QSLm4NZfZ3VXGVwyHdRf58IBbCu9ammgJxuWZYLX0du6kZvdNqPwrjvDfwmi6wFdvfZ/s6K7ia0E5kI7m8Q==}
cpu: [x64]
os: [freebsd]
- '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.7-commit.30e0395':
- resolution: {integrity: sha512-tfVAzmJ/nkMSK2o4tDf/pLSuaXieOw+XjWkVqJUHoxt5wufno9tPApOBGEbjbnENkXdR4+1dlZfE0ZmCpdUdvw==}
+ '@rollup/rollup-linux-arm-gnueabihf@4.34.7':
+ resolution: {integrity: sha512-Z0TzhrsNqukTz3ISzrvyshQpFnFRfLunYiXxlCRvcrb3nvC5rVKI+ZXPFG/Aa4jhQa1gHgH3A0exHaRRN4VmdQ==}
cpu: [arm]
os: [linux]
- '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.7-commit.30e0395':
- resolution: {integrity: sha512-6myOJPi7rr29FPU0BNrNufYDCHR//JsFbZEgj4ykx/22TUUZaOKJoiLNBREplO7b4YCJ9+0pTvvuGTkvmp5esg==}
+ '@rollup/rollup-linux-arm-musleabihf@4.34.7':
+ resolution: {integrity: sha512-nkznpyXekFAbvFBKBy4nNppSgneB1wwG1yx/hujN3wRnhnkrYVugMTCBXED4+Ni6thoWfQuHNYbFjgGH0MBXtw==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.34.7':
+ resolution: {integrity: sha512-KCjlUkcKs6PjOcxolqrXglBDcfCuUCTVlX5BgzgoJHw+1rWH1MCkETLkLe5iLLS9dP5gKC7mp3y6x8c1oGBUtA==}
cpu: [arm64]
os: [linux]
- '@rolldown/binding-linux-arm64-musl@1.0.0-beta.7-commit.30e0395':
- resolution: {integrity: sha512-VAJlT86fnUJBOwIpZ6Y9DQQDVZ6bYVJPWhGp4EVs3aQfyub/hOvd4RXiLSjaCIL3BafNZhZ+HtqHjIngWaiLwA==}
+ '@rollup/rollup-linux-arm64-musl@4.34.7':
+ resolution: {integrity: sha512-uFLJFz6+utmpbR313TTx+NpPuAXbPz4BhTQzgaP0tozlLnGnQ6rCo6tLwaSa6b7l6gRErjLicXQ1iPiXzYotjw==}
cpu: [arm64]
os: [linux]
- '@rolldown/binding-linux-x64-gnu@1.0.0-beta.7-commit.30e0395':
- resolution: {integrity: sha512-myi+HoUkWSUqMLhVGf8pD6lsfx25TBm6mQcw7qIwXKcX6a0I1SFCHFL3qlqQtXhAdwGKi18M3e5Bz67PdQV5Dg==}
+ '@rollup/rollup-linux-loongarch64-gnu@4.34.7':
+ resolution: {integrity: sha512-ws8pc68UcJJqCpneDFepnwlsMUFoWvPbWXT/XUrJ7rWUL9vLoIN3GAasgG+nCvq8xrE3pIrd+qLX/jotcLy0Qw==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-powerpc64le-gnu@4.34.7':
+ resolution: {integrity: sha512-vrDk9JDa/BFkxcS2PbWpr0C/LiiSLxFbNOBgfbW6P8TBe9PPHx9Wqbvx2xgNi1TOAyQHQJ7RZFqBiEohm79r0w==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.34.7':
+ resolution: {integrity: sha512-rB+ejFyjtmSo+g/a4eovDD1lHWHVqizN8P0Hm0RElkINpS0XOdpaXloqM4FBkF9ZWEzg6bezymbpLmeMldfLTw==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.34.7':
+ resolution: {integrity: sha512-nNXNjo4As6dNqRn7OrsnHzwTgtypfRA3u3AKr0B3sOOo+HkedIbn8ZtFnB+4XyKJojIfqDKmbIzO1QydQ8c+Pw==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-gnu@4.34.7':
+ resolution: {integrity: sha512-9kPVf9ahnpOMSGlCxXGv980wXD0zRR3wyk8+33/MXQIpQEOpaNe7dEHm5LMfyRZRNt9lMEQuH0jUKj15MkM7QA==}
cpu: [x64]
os: [linux]
- '@rolldown/binding-linux-x64-musl@1.0.0-beta.7-commit.30e0395':
- resolution: {integrity: sha512-CMfInIUDGY4y9JOfn30U6o7V9faT2zJs3kMshyaX3GSSmOg0QmvQlzAxWWMyIQKMXHIN0mnYQxPq9AhW2Yz1dg==}
+ '@rollup/rollup-linux-x64-musl@4.34.7':
+ resolution: {integrity: sha512-7wJPXRWTTPtTFDFezA8sle/1sdgxDjuMoRXEKtx97ViRxGGkVQYovem+Q8Pr/2HxiHp74SSRG+o6R0Yq0shPwQ==}
cpu: [x64]
os: [linux]
- '@rolldown/binding-wasm32-wasi@1.0.0-beta.7-commit.30e0395':
- resolution: {integrity: sha512-EkjaSUFAAPBld7ojUmMKiSB1A7iWgLaAeSyJaO4m4oIHvzZLsTKmtFnJodT7TMl5IBtO4kpBeWc4v9J+A8MZGQ==}
- engines: {node: '>=14.21.3'}
- cpu: [wasm32]
-
- '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.7-commit.30e0395':
- resolution: {integrity: sha512-It1vFY6GMg3Yx+rhYzuUa2nq5BY/z5hRT2NtjAOcp+DLOi5swWLoCNozA0QhGhESMnq9Nune71AKImCyIg8Peg==}
+ '@rollup/rollup-win32-arm64-msvc@4.34.7':
+ resolution: {integrity: sha512-MN7aaBC7mAjsiMEZcsJvwNsQVNZShgES/9SzWp1HC9Yjqb5OpexYnRjF7RmE4itbeesHMYYQiAtUAQaSKs2Rfw==}
cpu: [arm64]
os: [win32]
- '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.7-commit.30e0395':
- resolution: {integrity: sha512-YSvkr4kb9RoiqObJZGEyYDB01Lf9jpqibFuFb/X9U/UAF/8lyYsjP18M/WD4inyoUBrDbh3wN0f38Una9FGKhQ==}
+ '@rollup/rollup-win32-ia32-msvc@4.34.7':
+ resolution: {integrity: sha512-aeawEKYswsFu1LhDM9RIgToobquzdtSc4jSVqHV8uApz4FVvhFl/mKh92wc8WpFc6aYCothV/03UjY6y7yLgbg==}
cpu: [ia32]
os: [win32]
- '@rolldown/binding-win32-x64-msvc@1.0.0-beta.7-commit.30e0395':
- resolution: {integrity: sha512-znpr7YScTNBki1u+/vk1jLl59/x+q2rrGCJYNm9o/KCOPZPIqCFy4+/y/SJo1eVa7QJdellTi5Z07Z/Bx/iViQ==}
+ '@rollup/rollup-win32-x64-msvc@4.34.7':
+ resolution: {integrity: sha512-4ZedScpxxIrVO7otcZ8kCX1mZArtH2Wfj3uFCxRJ9NO80gg1XV0U/b2f/MKaGwj2X3QopHfoWiDQ917FRpwY3w==}
cpu: [x64]
os: [win32]
@@ -4168,13 +4314,8 @@ packages:
'@ucast/mongo@2.4.3':
resolution: {integrity: sha512-XcI8LclrHWP83H+7H2anGCEeDq0n+12FU2mXCTz6/Tva9/9ddK/iacvvhCyW6cijAAOILmt0tWplRyRhVyZLsA==}
- '@valibot/to-json-schema@1.0.0':
- resolution: {integrity: sha512-/9crJgPptVsGCL6X+JPDQyaJwkalSZ/52WuF8DiRUxJgcmpNdzYRfZ+gqMEP8W3CTVfuMWPqqvIgfwJ97f9Etw==}
- peerDependencies:
- valibot: ^1.0.0
-
- '@vitejs/plugin-react@4.4.1':
- resolution: {integrity: sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==}
+ '@vitejs/plugin-react@4.3.4':
+ resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
vite: ^4.2.0 || ^5.0.0 || ^6.0.0
@@ -4372,10 +4513,6 @@ packages:
resolution: {integrity: sha512-zIcWDJ+Kwqxfdnogx66Gxzr0kVmCcRAdat9nlY2IHsshqTN4fBH6tMeRMPA/2w0rpBayIJvjQAaa2/4RDrNqwg==}
engines: {node: '>=14'}
- ansis@3.17.0:
- resolution: {integrity: sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==}
- engines: {node: '>=14'}
-
anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
@@ -4451,8 +4588,11 @@ packages:
avvio@9.1.0:
resolution: {integrity: sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw==}
- axios@1.8.4:
- resolution: {integrity: sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==}
+ axios@1.7.8:
+ resolution: {integrity: sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==}
+
+ axios@1.7.9:
+ resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
babel-jest@29.7.0:
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
@@ -5352,6 +5492,11 @@ packages:
engines: {node: '>=12'}
hasBin: true
+ esbuild@0.24.2:
+ resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
+ engines: {node: '>=18'}
+ hasBin: true
+
esbuild@0.25.0:
resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==}
engines: {node: '>=18'}
@@ -6520,70 +6665,6 @@ packages:
light-my-request@6.6.0:
resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==}
- lightningcss-darwin-arm64@1.29.3:
- resolution: {integrity: sha512-fb7raKO3pXtlNbQbiMeEu8RbBVHnpyqAoxTyTRMEWFQWmscGC2wZxoHzZ+YKAepUuKT9uIW5vL2QbFivTgprZg==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [darwin]
-
- lightningcss-darwin-x64@1.29.3:
- resolution: {integrity: sha512-KF2XZ4ZdmDGGtEYmx5wpzn6u8vg7AdBHaEOvDKu8GOs7xDL/vcU2vMKtTeNe1d4dogkDdi3B9zC77jkatWBwEQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [darwin]
-
- lightningcss-freebsd-x64@1.29.3:
- resolution: {integrity: sha512-VUWeVf+V1UM54jv9M4wen9vMlIAyT69Krl9XjI8SsRxz4tdNV/7QEPlW6JASev/pYdiynUCW0pwaFquDRYdxMw==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [freebsd]
-
- lightningcss-linux-arm-gnueabihf@1.29.3:
- resolution: {integrity: sha512-UhgZ/XVNfXQVEJrMIWeK1Laj8KbhjbIz7F4znUk7G4zeGw7TRoJxhb66uWrEsonn1+O45w//0i0Fu0wIovYdYg==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm]
- os: [linux]
-
- lightningcss-linux-arm64-gnu@1.29.3:
- resolution: {integrity: sha512-Pqau7jtgJNmQ/esugfmAT1aCFy/Gxc92FOxI+3n+LbMHBheBnk41xHDhc0HeYlx9G0xP5tK4t0Koy3QGGNqypw==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [linux]
-
- lightningcss-linux-arm64-musl@1.29.3:
- resolution: {integrity: sha512-dxakOk66pf7KLS7VRYFO7B8WOJLecE5OPL2YOk52eriFd/yeyxt2Km5H0BjLfElokIaR+qWi33gB8MQLrdAY3A==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [linux]
-
- lightningcss-linux-x64-gnu@1.29.3:
- resolution: {integrity: sha512-ySZTNCpbfbK8rqpKJeJR2S0g/8UqqV3QnzcuWvpI60LWxnFN91nxpSSwCbzfOXkzKfar9j5eOuOplf+klKtINg==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [linux]
-
- lightningcss-linux-x64-musl@1.29.3:
- resolution: {integrity: sha512-3pVZhIzW09nzi10usAXfIGTTSTYQ141dk88vGFNCgawIzayiIzZQxEcxVtIkdvlEq2YuFsL9Wcj/h61JHHzuFQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [linux]
-
- lightningcss-win32-arm64-msvc@1.29.3:
- resolution: {integrity: sha512-VRnkAvtIkeWuoBJeGOTrZxsNp4HogXtcaaLm8agmbYtLDOhQdpgxW6NjZZjDXbvGF+eOehGulXZ3C1TiwHY4QQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [win32]
-
- lightningcss-win32-x64-msvc@1.29.3:
- resolution: {integrity: sha512-IszwRPu2cPnDQsZpd7/EAr0x2W7jkaWqQ1SwCVIZ/tSbZVXPLt6k8s6FkcyBjViCzvB5CW0We0QbbP7zp2aBjQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [win32]
-
- lightningcss@1.29.3:
- resolution: {integrity: sha512-GlOJwTIP6TMIlrTFsxTerwC0W6OpQpCGuX1ECRLBUVRh6fpJH3xTqjCjRgQHTb4ZXexH9rtHou1Lf03GKzmhhQ==}
- engines: {node: '>= 12.0.0'}
-
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
@@ -7251,6 +7332,9 @@ packages:
pgpass@1.0.5:
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
+ picocolors@1.0.0:
+ resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+
picocolors@1.0.1:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
@@ -7345,8 +7429,8 @@ packages:
resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==}
engines: {node: ^10 || ^12 || >=14}
- postcss@8.5.3:
- resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
+ postcss@8.5.2:
+ resolution: {integrity: sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==}
engines: {node: ^10 || ^12 || >=14}
postgres-array@2.0.0:
@@ -7614,8 +7698,8 @@ packages:
react-promise-suspense@0.3.4:
resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==}
- react-refresh@0.17.0:
- resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
+ react-refresh@0.14.2:
+ resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
engines: {node: '>=0.10.0'}
react-remove-scroll-bar@2.3.8:
@@ -7834,54 +7918,10 @@ packages:
robust-predicates@3.0.2:
resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==}
- rolldown-vite@6.3.3:
- resolution: {integrity: sha512-ZmIaiGPNC7bSnc8FOETiesfGtyBSYGy+m7FM6EhcjciBggv6OHd28HSS3NItosI1AXfgVHdrHpyPPy/YrfmkdA==}
- engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ rollup@4.34.7:
+ resolution: {integrity: sha512-8qhyN0oZ4x0H6wmBgfKxJtxM7qS98YJ0k0kNh5ECVtuchIJ7z9IVVvzpmtQyT10PXKMtBxYr1wQ5Apg8RS8kXQ==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
- peerDependencies:
- '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
- esbuild: ^0.25.0
- jiti: '>=1.21.0'
- less: '*'
- sass: '*'
- sass-embedded: '*'
- stylus: '*'
- sugarss: '*'
- terser: ^5.16.0
- tsx: ^4.8.1
- yaml: ^2.4.2
- peerDependenciesMeta:
- '@types/node':
- optional: true
- esbuild:
- optional: true
- jiti:
- optional: true
- less:
- optional: true
- sass:
- optional: true
- sass-embedded:
- optional: true
- stylus:
- optional: true
- sugarss:
- optional: true
- terser:
- optional: true
- tsx:
- optional: true
- yaml:
- optional: true
-
- rolldown@1.0.0-beta.7-commit.30e0395:
- resolution: {integrity: sha512-io3+hz8Eh9wdbX8SaybkPWwo17PDVezp8qEjldCAqfVZ/jXM1xF3lTnwvgMiW0rgsZuPdPSZA7hhtKJ/x6aq8g==}
- hasBin: true
- peerDependencies:
- '@oxc-project/runtime': 0.65.0
- peerDependenciesMeta:
- '@oxc-project/runtime':
- optional: true
rope-sequence@1.3.4:
resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
@@ -8618,14 +8658,6 @@ packages:
resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==}
engines: {node: '>=10.12.0'}
- valibot@1.0.0:
- resolution: {integrity: sha512-1Hc0ihzWxBar6NGeZv7fPLY0QuxFMyxwYR2sF1Blu7Wq7EnremwY2W02tit2ij2VJT8HcSkHAQqmFfl77f73Yw==}
- peerDependencies:
- typescript: '>=5'
- peerDependenciesMeta:
- typescript:
- optional: true
-
validate-npm-package-name@5.0.0:
resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -8638,6 +8670,46 @@ packages:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
+ vite@6.1.0:
+ resolution: {integrity: sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ jiti: '>=1.21.0'
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
void-elements@3.1.0:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
engines: {node: '>=0.10.0'}
@@ -9516,7 +9588,7 @@ snapshots:
'@babel/code-frame@7.24.2':
dependencies:
'@babel/highlight': 7.24.2
- picocolors: 1.1.1
+ picocolors: 1.0.0
'@babel/code-frame@7.26.2':
dependencies:
@@ -9526,8 +9598,6 @@ snapshots:
'@babel/compat-data@7.26.2': {}
- '@babel/compat-data@7.26.8': {}
-
'@babel/core@7.24.5':
dependencies:
'@ampproject/remapping': 2.3.0
@@ -9588,26 +9658,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/core@7.26.10':
- dependencies:
- '@ampproject/remapping': 2.3.0
- '@babel/code-frame': 7.26.2
- '@babel/generator': 7.27.0
- '@babel/helper-compilation-targets': 7.27.0
- '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10)
- '@babel/helpers': 7.27.0
- '@babel/parser': 7.27.0
- '@babel/template': 7.27.0
- '@babel/traverse': 7.27.0
- '@babel/types': 7.27.0
- convert-source-map: 2.0.0
- debug: 4.3.7
- gensync: 1.0.0-beta.2
- json5: 2.2.3
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
'@babel/generator@7.24.1':
dependencies:
'@babel/types': 7.24.0
@@ -9630,14 +9680,6 @@ snapshots:
'@jridgewell/trace-mapping': 0.3.25
jsesc: 3.0.2
- '@babel/generator@7.27.0':
- dependencies:
- '@babel/parser': 7.27.0
- '@babel/types': 7.27.0
- '@jridgewell/gen-mapping': 0.3.5
- '@jridgewell/trace-mapping': 0.3.25
- jsesc: 3.0.2
-
'@babel/helper-annotate-as-pure@7.22.5':
dependencies:
'@babel/types': 7.26.0
@@ -9654,14 +9696,6 @@ snapshots:
lru-cache: 5.1.1
semver: 6.3.1
- '@babel/helper-compilation-targets@7.27.0':
- dependencies:
- '@babel/compat-data': 7.26.8
- '@babel/helper-validator-option': 7.25.9
- browserslist: 4.24.2
- lru-cache: 5.1.1
- semver: 6.3.1
-
'@babel/helper-create-class-features-plugin@7.23.7(@babel/core@7.26.0)':
dependencies:
'@babel/core': 7.26.0
@@ -9761,15 +9795,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)':
- dependencies:
- '@babel/core': 7.26.10
- '@babel/helper-module-imports': 7.25.9
- '@babel/helper-validator-identifier': 7.25.9
- '@babel/traverse': 7.25.9
- transitivePeerDependencies:
- - supports-color
-
'@babel/helper-optimise-call-expression@7.22.5':
dependencies:
'@babel/types': 7.26.0
@@ -9844,30 +9869,25 @@ snapshots:
'@babel/template': 7.25.9
'@babel/types': 7.26.0
- '@babel/helpers@7.27.0':
- dependencies:
- '@babel/template': 7.27.0
- '@babel/types': 7.27.0
-
'@babel/highlight@7.24.2':
dependencies:
'@babel/helper-validator-identifier': 7.22.20
chalk: 2.4.2
js-tokens: 4.0.0
- picocolors: 1.1.1
+ picocolors: 1.0.0
'@babel/parser@7.24.5':
dependencies:
'@babel/types': 7.26.0
+ '@babel/parser@7.24.6':
+ dependencies:
+ '@babel/types': 7.24.6
+
'@babel/parser@7.26.2':
dependencies:
'@babel/types': 7.26.0
- '@babel/parser@7.27.0':
- dependencies:
- '@babel/types': 7.27.0
-
'@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.26.0)':
dependencies:
'@babel/core': 7.26.0
@@ -10385,14 +10405,14 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.10)':
+ '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)':
dependencies:
- '@babel/core': 7.26.10
+ '@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.10)':
+ '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0)':
dependencies:
- '@babel/core': 7.26.10
+ '@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
'@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.26.0)':
@@ -10599,12 +10619,6 @@ snapshots:
'@babel/parser': 7.26.2
'@babel/types': 7.26.0
- '@babel/template@7.27.0':
- dependencies:
- '@babel/code-frame': 7.26.2
- '@babel/parser': 7.27.0
- '@babel/types': 7.27.0
-
'@babel/traverse@7.25.9':
dependencies:
'@babel/code-frame': 7.26.2
@@ -10617,18 +10631,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@babel/traverse@7.27.0':
- dependencies:
- '@babel/code-frame': 7.26.2
- '@babel/generator': 7.27.0
- '@babel/parser': 7.27.0
- '@babel/template': 7.27.0
- '@babel/types': 7.27.0
- debug: 4.3.7
- globals: 11.12.0
- transitivePeerDependencies:
- - supports-color
-
'@babel/types@7.23.6':
dependencies:
'@babel/helper-string-parser': 7.23.4
@@ -10652,11 +10654,6 @@ snapshots:
'@babel/helper-string-parser': 7.25.9
'@babel/helper-validator-identifier': 7.25.9
- '@babel/types@7.27.0':
- dependencies:
- '@babel/helper-string-parser': 7.25.9
- '@babel/helper-validator-identifier': 7.25.9
-
'@bcoe/v8-coverage@0.2.3': {}
'@braintree/sanitize-url@7.1.0': {}
@@ -10745,144 +10742,219 @@ snapshots:
'@esbuild/aix-ppc64@0.19.11':
optional: true
+ '@esbuild/aix-ppc64@0.24.2':
+ optional: true
+
'@esbuild/aix-ppc64@0.25.0':
optional: true
'@esbuild/android-arm64@0.19.11':
optional: true
+ '@esbuild/android-arm64@0.24.2':
+ optional: true
+
'@esbuild/android-arm64@0.25.0':
optional: true
'@esbuild/android-arm@0.19.11':
optional: true
+ '@esbuild/android-arm@0.24.2':
+ optional: true
+
'@esbuild/android-arm@0.25.0':
optional: true
'@esbuild/android-x64@0.19.11':
optional: true
+ '@esbuild/android-x64@0.24.2':
+ optional: true
+
'@esbuild/android-x64@0.25.0':
optional: true
'@esbuild/darwin-arm64@0.19.11':
optional: true
+ '@esbuild/darwin-arm64@0.24.2':
+ optional: true
+
'@esbuild/darwin-arm64@0.25.0':
optional: true
'@esbuild/darwin-x64@0.19.11':
optional: true
+ '@esbuild/darwin-x64@0.24.2':
+ optional: true
+
'@esbuild/darwin-x64@0.25.0':
optional: true
'@esbuild/freebsd-arm64@0.19.11':
optional: true
+ '@esbuild/freebsd-arm64@0.24.2':
+ optional: true
+
'@esbuild/freebsd-arm64@0.25.0':
optional: true
'@esbuild/freebsd-x64@0.19.11':
optional: true
+ '@esbuild/freebsd-x64@0.24.2':
+ optional: true
+
'@esbuild/freebsd-x64@0.25.0':
optional: true
'@esbuild/linux-arm64@0.19.11':
optional: true
+ '@esbuild/linux-arm64@0.24.2':
+ optional: true
+
'@esbuild/linux-arm64@0.25.0':
optional: true
'@esbuild/linux-arm@0.19.11':
optional: true
+ '@esbuild/linux-arm@0.24.2':
+ optional: true
+
'@esbuild/linux-arm@0.25.0':
optional: true
'@esbuild/linux-ia32@0.19.11':
optional: true
+ '@esbuild/linux-ia32@0.24.2':
+ optional: true
+
'@esbuild/linux-ia32@0.25.0':
optional: true
'@esbuild/linux-loong64@0.19.11':
optional: true
+ '@esbuild/linux-loong64@0.24.2':
+ optional: true
+
'@esbuild/linux-loong64@0.25.0':
optional: true
'@esbuild/linux-mips64el@0.19.11':
optional: true
+ '@esbuild/linux-mips64el@0.24.2':
+ optional: true
+
'@esbuild/linux-mips64el@0.25.0':
optional: true
'@esbuild/linux-ppc64@0.19.11':
optional: true
+ '@esbuild/linux-ppc64@0.24.2':
+ optional: true
+
'@esbuild/linux-ppc64@0.25.0':
optional: true
'@esbuild/linux-riscv64@0.19.11':
optional: true
+ '@esbuild/linux-riscv64@0.24.2':
+ optional: true
+
'@esbuild/linux-riscv64@0.25.0':
optional: true
'@esbuild/linux-s390x@0.19.11':
optional: true
+ '@esbuild/linux-s390x@0.24.2':
+ optional: true
+
'@esbuild/linux-s390x@0.25.0':
optional: true
'@esbuild/linux-x64@0.19.11':
optional: true
+ '@esbuild/linux-x64@0.24.2':
+ optional: true
+
'@esbuild/linux-x64@0.25.0':
optional: true
+ '@esbuild/netbsd-arm64@0.24.2':
+ optional: true
+
'@esbuild/netbsd-arm64@0.25.0':
optional: true
'@esbuild/netbsd-x64@0.19.11':
optional: true
+ '@esbuild/netbsd-x64@0.24.2':
+ optional: true
+
'@esbuild/netbsd-x64@0.25.0':
optional: true
+ '@esbuild/openbsd-arm64@0.24.2':
+ optional: true
+
'@esbuild/openbsd-arm64@0.25.0':
optional: true
'@esbuild/openbsd-x64@0.19.11':
optional: true
+ '@esbuild/openbsd-x64@0.24.2':
+ optional: true
+
'@esbuild/openbsd-x64@0.25.0':
optional: true
'@esbuild/sunos-x64@0.19.11':
optional: true
+ '@esbuild/sunos-x64@0.24.2':
+ optional: true
+
'@esbuild/sunos-x64@0.25.0':
optional: true
'@esbuild/win32-arm64@0.19.11':
optional: true
+ '@esbuild/win32-arm64@0.24.2':
+ optional: true
+
'@esbuild/win32-arm64@0.25.0':
optional: true
'@esbuild/win32-ia32@0.19.11':
optional: true
+ '@esbuild/win32-ia32@0.24.2':
+ optional: true
+
'@esbuild/win32-ia32@0.25.0':
optional: true
'@esbuild/win32-x64@0.19.11':
optional: true
+ '@esbuild/win32-x64@0.24.2':
+ optional: true
+
'@esbuild/win32-x64@0.25.0':
optional: true
@@ -11847,7 +11919,7 @@ snapshots:
tslib: 2.8.0
yargs-parser: 21.1.1
- '@nx/js@20.4.5(@babel/traverse@7.27.0)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)':
+ '@nx/js@20.4.5(@babel/traverse@7.25.9)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)':
dependencies:
'@babel/core': 7.26.0
'@babel/plugin-proposal-decorators': 7.23.7(@babel/core@7.26.0)
@@ -11861,7 +11933,7 @@ snapshots:
'@zkochan/js-yaml': 0.0.7
babel-plugin-const-enum: 1.2.0(@babel/core@7.26.0)
babel-plugin-macros: 3.1.0
- babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.26.0)(@babel/traverse@7.27.0)
+ babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.26.0)(@babel/traverse@7.25.9)
chalk: 4.1.2
columnify: 1.6.0
detect-port: 1.5.1
@@ -11938,10 +12010,6 @@ snapshots:
'@opentelemetry/api@1.9.0':
optional: true
- '@oxc-project/runtime@0.65.0': {}
-
- '@oxc-project/types@0.65.0': {}
-
'@pkgjs/parseargs@0.11.0':
optional: true
@@ -12067,42 +12135,61 @@ snapshots:
'@remirror/core-constants@3.0.0': {}
- '@rolldown/binding-darwin-arm64@1.0.0-beta.7-commit.30e0395':
+ '@rollup/rollup-android-arm-eabi@4.34.7':
optional: true
- '@rolldown/binding-darwin-x64@1.0.0-beta.7-commit.30e0395':
+ '@rollup/rollup-android-arm64@4.34.7':
optional: true
- '@rolldown/binding-freebsd-x64@1.0.0-beta.7-commit.30e0395':
+ '@rollup/rollup-darwin-arm64@4.34.7':
optional: true
- '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.7-commit.30e0395':
+ '@rollup/rollup-darwin-x64@4.34.7':
optional: true
- '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.7-commit.30e0395':
+ '@rollup/rollup-freebsd-arm64@4.34.7':
optional: true
- '@rolldown/binding-linux-arm64-musl@1.0.0-beta.7-commit.30e0395':
+ '@rollup/rollup-freebsd-x64@4.34.7':
optional: true
- '@rolldown/binding-linux-x64-gnu@1.0.0-beta.7-commit.30e0395':
+ '@rollup/rollup-linux-arm-gnueabihf@4.34.7':
optional: true
- '@rolldown/binding-linux-x64-musl@1.0.0-beta.7-commit.30e0395':
+ '@rollup/rollup-linux-arm-musleabihf@4.34.7':
optional: true
- '@rolldown/binding-wasm32-wasi@1.0.0-beta.7-commit.30e0395':
- dependencies:
- '@napi-rs/wasm-runtime': 0.2.4
+ '@rollup/rollup-linux-arm64-gnu@4.34.7':
optional: true
- '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.7-commit.30e0395':
+ '@rollup/rollup-linux-arm64-musl@4.34.7':
optional: true
- '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.7-commit.30e0395':
+ '@rollup/rollup-linux-loongarch64-gnu@4.34.7':
optional: true
- '@rolldown/binding-win32-x64-msvc@1.0.0-beta.7-commit.30e0395':
+ '@rollup/rollup-linux-powerpc64le-gnu@4.34.7':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.34.7':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.34.7':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.34.7':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.34.7':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.34.7':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.34.7':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.34.7':
optional: true
'@selderee/plugin-htmlparser2@0.11.0':
@@ -12839,20 +12926,20 @@ snapshots:
'@types/babel__core@7.20.5':
dependencies:
- '@babel/parser': 7.26.2
- '@babel/types': 7.26.0
+ '@babel/parser': 7.24.6
+ '@babel/types': 7.24.6
'@types/babel__generator': 7.6.8
'@types/babel__template': 7.4.4
'@types/babel__traverse': 7.20.5
'@types/babel__generator@7.6.8':
dependencies:
- '@babel/types': 7.26.0
+ '@babel/types': 7.24.6
'@types/babel__template@7.4.4':
dependencies:
- '@babel/parser': 7.26.2
- '@babel/types': 7.26.0
+ '@babel/parser': 7.24.6
+ '@babel/types': 7.24.6
'@types/babel__traverse@7.20.5':
dependencies:
@@ -13398,18 +13485,14 @@ snapshots:
dependencies:
'@ucast/core': 1.10.2
- '@valibot/to-json-schema@1.0.0(valibot@1.0.0(typescript@5.7.2))':
+ '@vitejs/plugin-react@4.3.4(vite@6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))':
dependencies:
- valibot: 1.0.0(typescript@5.7.2)
-
- '@vitejs/plugin-react@4.4.1(rolldown-vite@6.3.3(@types/node@22.10.0)(esbuild@0.25.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.2)(yaml@2.7.0))':
- dependencies:
- '@babel/core': 7.26.10
- '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10)
- '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10)
+ '@babel/core': 7.26.0
+ '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0)
+ '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0)
'@types/babel__core': 7.20.5
- react-refresh: 0.17.0
- vite: rolldown-vite@6.3.3(@types/node@22.10.0)(esbuild@0.25.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.2)(yaml@2.7.0)
+ react-refresh: 0.14.2
+ vite: 6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
@@ -13617,8 +13700,6 @@ snapshots:
ansis@3.15.0: {}
- ansis@3.17.0: {}
-
anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
@@ -13716,7 +13797,15 @@ snapshots:
'@fastify/error': 4.0.0
fastq: 1.17.1
- axios@1.8.4:
+ axios@1.7.8:
+ dependencies:
+ follow-redirects: 1.15.6
+ form-data: 4.0.0
+ proxy-from-env: 1.1.0
+ transitivePeerDependencies:
+ - debug
+
+ axios@1.7.9:
dependencies:
follow-redirects: 1.15.6
form-data: 4.0.0
@@ -13807,12 +13896,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
- babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.26.0)(@babel/traverse@7.27.0):
+ babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.26.0)(@babel/traverse@7.25.9):
dependencies:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
optionalDependencies:
- '@babel/traverse': 7.27.0
+ '@babel/traverse': 7.25.9
babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.5):
dependencies:
@@ -14821,6 +14910,34 @@ snapshots:
'@esbuild/win32-ia32': 0.19.11
'@esbuild/win32-x64': 0.19.11
+ esbuild@0.24.2:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.24.2
+ '@esbuild/android-arm': 0.24.2
+ '@esbuild/android-arm64': 0.24.2
+ '@esbuild/android-x64': 0.24.2
+ '@esbuild/darwin-arm64': 0.24.2
+ '@esbuild/darwin-x64': 0.24.2
+ '@esbuild/freebsd-arm64': 0.24.2
+ '@esbuild/freebsd-x64': 0.24.2
+ '@esbuild/linux-arm': 0.24.2
+ '@esbuild/linux-arm64': 0.24.2
+ '@esbuild/linux-ia32': 0.24.2
+ '@esbuild/linux-loong64': 0.24.2
+ '@esbuild/linux-mips64el': 0.24.2
+ '@esbuild/linux-ppc64': 0.24.2
+ '@esbuild/linux-riscv64': 0.24.2
+ '@esbuild/linux-s390x': 0.24.2
+ '@esbuild/linux-x64': 0.24.2
+ '@esbuild/netbsd-arm64': 0.24.2
+ '@esbuild/netbsd-x64': 0.24.2
+ '@esbuild/openbsd-arm64': 0.24.2
+ '@esbuild/openbsd-x64': 0.24.2
+ '@esbuild/sunos-x64': 0.24.2
+ '@esbuild/win32-arm64': 0.24.2
+ '@esbuild/win32-ia32': 0.24.2
+ '@esbuild/win32-x64': 0.24.2
+
esbuild@0.25.0:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.0
@@ -16315,51 +16432,6 @@ snapshots:
process-warning: 4.0.0
set-cookie-parser: 2.6.0
- lightningcss-darwin-arm64@1.29.3:
- optional: true
-
- lightningcss-darwin-x64@1.29.3:
- optional: true
-
- lightningcss-freebsd-x64@1.29.3:
- optional: true
-
- lightningcss-linux-arm-gnueabihf@1.29.3:
- optional: true
-
- lightningcss-linux-arm64-gnu@1.29.3:
- optional: true
-
- lightningcss-linux-arm64-musl@1.29.3:
- optional: true
-
- lightningcss-linux-x64-gnu@1.29.3:
- optional: true
-
- lightningcss-linux-x64-musl@1.29.3:
- optional: true
-
- lightningcss-win32-arm64-msvc@1.29.3:
- optional: true
-
- lightningcss-win32-x64-msvc@1.29.3:
- optional: true
-
- lightningcss@1.29.3:
- dependencies:
- detect-libc: 2.0.3
- optionalDependencies:
- lightningcss-darwin-arm64: 1.29.3
- lightningcss-darwin-x64: 1.29.3
- lightningcss-freebsd-x64: 1.29.3
- lightningcss-linux-arm-gnueabihf: 1.29.3
- lightningcss-linux-arm64-gnu: 1.29.3
- lightningcss-linux-arm64-musl: 1.29.3
- lightningcss-linux-x64-gnu: 1.29.3
- lightningcss-linux-x64-musl: 1.29.3
- lightningcss-win32-arm64-msvc: 1.29.3
- lightningcss-win32-x64-msvc: 1.29.3
-
lines-and-columns@1.2.4: {}
lines-and-columns@2.0.3: {}
@@ -16742,7 +16814,7 @@ snapshots:
'@yarnpkg/lockfile': 1.1.0
'@yarnpkg/parsers': 3.0.2
'@zkochan/js-yaml': 0.0.7
- axios: 1.8.4
+ axios: 1.7.9
chalk: 4.1.2
cli-cursor: 3.1.0
cli-spinners: 2.6.1
@@ -17047,6 +17119,8 @@ snapshots:
dependencies:
split2: 4.2.0
+ picocolors@1.0.0: {}
+
picocolors@1.0.1: {}
picocolors@1.1.1: {}
@@ -17147,7 +17221,7 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
- postcss@8.5.3:
+ postcss@8.5.2:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
@@ -17177,7 +17251,7 @@ snapshots:
postmark@4.0.5:
dependencies:
- axios: 1.8.4
+ axios: 1.7.8
transitivePeerDependencies:
- debug
@@ -17454,7 +17528,7 @@ snapshots:
dependencies:
fast-deep-equal: 2.0.1
- react-refresh@0.17.0: {}
+ react-refresh@0.14.2: {}
react-remove-scroll-bar@2.3.8(@types/react@18.3.12)(react@18.3.1):
dependencies:
@@ -17675,50 +17749,30 @@ snapshots:
robust-predicates@3.0.2: {}
- rolldown-vite@6.3.3(@types/node@22.10.0)(esbuild@0.25.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.2)(yaml@2.7.0):
+ rollup@4.34.7:
dependencies:
- '@oxc-project/runtime': 0.65.0
- fdir: 6.4.3(picomatch@4.0.2)
- lightningcss: 1.29.3
- picomatch: 4.0.2
- postcss: 8.5.3
- rolldown: 1.0.0-beta.7-commit.30e0395(@oxc-project/runtime@0.65.0)(typescript@5.7.2)
- tinyglobby: 0.2.12
+ '@types/estree': 1.0.6
optionalDependencies:
- '@types/node': 22.10.0
- esbuild: 0.25.0
+ '@rollup/rollup-android-arm-eabi': 4.34.7
+ '@rollup/rollup-android-arm64': 4.34.7
+ '@rollup/rollup-darwin-arm64': 4.34.7
+ '@rollup/rollup-darwin-x64': 4.34.7
+ '@rollup/rollup-freebsd-arm64': 4.34.7
+ '@rollup/rollup-freebsd-x64': 4.34.7
+ '@rollup/rollup-linux-arm-gnueabihf': 4.34.7
+ '@rollup/rollup-linux-arm-musleabihf': 4.34.7
+ '@rollup/rollup-linux-arm64-gnu': 4.34.7
+ '@rollup/rollup-linux-arm64-musl': 4.34.7
+ '@rollup/rollup-linux-loongarch64-gnu': 4.34.7
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.34.7
+ '@rollup/rollup-linux-riscv64-gnu': 4.34.7
+ '@rollup/rollup-linux-s390x-gnu': 4.34.7
+ '@rollup/rollup-linux-x64-gnu': 4.34.7
+ '@rollup/rollup-linux-x64-musl': 4.34.7
+ '@rollup/rollup-win32-arm64-msvc': 4.34.7
+ '@rollup/rollup-win32-ia32-msvc': 4.34.7
+ '@rollup/rollup-win32-x64-msvc': 4.34.7
fsevents: 2.3.3
- jiti: 1.21.0
- less: 4.2.0
- sugarss: 4.0.1(postcss@8.4.49)
- terser: 5.39.0
- tsx: 4.19.3
- yaml: 2.7.0
- transitivePeerDependencies:
- - typescript
-
- rolldown@1.0.0-beta.7-commit.30e0395(@oxc-project/runtime@0.65.0)(typescript@5.7.2):
- dependencies:
- '@oxc-project/types': 0.65.0
- '@valibot/to-json-schema': 1.0.0(valibot@1.0.0(typescript@5.7.2))
- ansis: 3.17.0
- valibot: 1.0.0(typescript@5.7.2)
- optionalDependencies:
- '@oxc-project/runtime': 0.65.0
- '@rolldown/binding-darwin-arm64': 1.0.0-beta.7-commit.30e0395
- '@rolldown/binding-darwin-x64': 1.0.0-beta.7-commit.30e0395
- '@rolldown/binding-freebsd-x64': 1.0.0-beta.7-commit.30e0395
- '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.7-commit.30e0395
- '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.7-commit.30e0395
- '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.7-commit.30e0395
- '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.7-commit.30e0395
- '@rolldown/binding-linux-x64-musl': 1.0.0-beta.7-commit.30e0395
- '@rolldown/binding-wasm32-wasi': 1.0.0-beta.7-commit.30e0395
- '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.7-commit.30e0395
- '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.7-commit.30e0395
- '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.7-commit.30e0395
- transitivePeerDependencies:
- - typescript
rope-sequence@1.3.4: {}
@@ -18484,10 +18538,6 @@ snapshots:
'@types/istanbul-lib-coverage': 2.0.6
convert-source-map: 2.0.0
- valibot@1.0.0(typescript@5.7.2):
- optionalDependencies:
- typescript: 5.7.2
-
validate-npm-package-name@5.0.0:
dependencies:
builtins: 5.0.1
@@ -18496,6 +18546,21 @@ snapshots:
vary@1.1.2: {}
+ vite@6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0):
+ dependencies:
+ esbuild: 0.24.2
+ postcss: 8.5.2
+ rollup: 4.34.7
+ optionalDependencies:
+ '@types/node': 22.10.0
+ fsevents: 2.3.3
+ jiti: 1.21.0
+ less: 4.2.0
+ sugarss: 4.0.1(postcss@8.4.49)
+ terser: 5.39.0
+ tsx: 4.19.3
+ yaml: 2.7.0
+
void-elements@3.1.0: {}
vscode-jsonrpc@8.2.0: {}
From 3e8824435d2bd8af54b3594beeec6277cf86ff7b Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 22 Apr 2025 20:28:27 +0100
Subject: [PATCH 26/63] update vite and axios
---
apps/client/package.json | 6 +-
pnpm-lock.yaml | 659 +++++++++++++++------------------------
2 files changed, 260 insertions(+), 405 deletions(-)
diff --git a/apps/client/package.json b/apps/client/package.json
index 5901a920..ffd94cae 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -25,7 +25,7 @@
"@tabler/icons-react": "^3.22.0",
"@tanstack/react-query": "^5.61.4",
"@tiptap/extension-character-count": "^2.11.5",
- "axios": "^1.7.9",
+ "axios": "^1.8.4",
"clsx": "^2.1.1",
"emoji-mart": "^5.6.0",
"file-saver": "^2.0.5",
@@ -63,7 +63,7 @@
"@types/node": "22.10.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
- "@vitejs/plugin-react": "^4.3.4",
+ "@vitejs/plugin-react": "^4.4.1",
"eslint": "^9.15.0",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.1.0",
@@ -76,6 +76,6 @@
"prettier": "^3.4.1",
"typescript": "^5.7.2",
"typescript-eslint": "^8.17.0",
- "vite": "^6.1.0"
+ "vite": "^6.3.2"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f9cc1623..8772d574 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -181,7 +181,7 @@ importers:
devDependencies:
'@nx/js':
specifier: 20.4.5
- version: 20.4.5(@babel/traverse@7.25.9)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)
+ version: 20.4.5(@babel/traverse@7.27.0)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)
'@types/bytes':
specifier: ^3.1.5
version: 3.1.5
@@ -246,8 +246,8 @@ importers:
specifier: ^2.11.5
version: 2.11.5(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))(@tiptap/pm@2.10.3)
axios:
- specifier: ^1.7.9
- version: 1.7.9
+ specifier: ^1.8.4
+ version: 1.8.4
clsx:
specifier: ^2.1.1
version: 2.1.1
@@ -355,8 +355,8 @@ importers:
specifier: ^18.3.1
version: 18.3.1
'@vitejs/plugin-react':
- specifier: ^4.3.4
- version: 4.3.4(vite@6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))
+ specifier: ^4.4.1
+ version: 4.4.1(vite@6.3.2(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))
eslint:
specifier: ^9.15.0
version: 9.15.0(jiti@1.21.0)
@@ -394,8 +394,8 @@ importers:
specifier: ^8.17.0
version: 8.17.0(eslint@9.15.0(jiti@1.21.0))(typescript@5.7.2)
vite:
- specifier: ^6.1.0
- version: 6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)
+ specifier: ^6.3.2
+ version: 6.3.2(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)
apps/server:
dependencies:
@@ -876,6 +876,10 @@ packages:
resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==}
engines: {node: '>=6.9.0'}
+ '@babel/compat-data@7.26.8':
+ resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==}
+ engines: {node: '>=6.9.0'}
+
'@babel/core@7.24.5':
resolution: {integrity: sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==}
engines: {node: '>=6.9.0'}
@@ -888,6 +892,10 @@ packages:
resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==}
engines: {node: '>=6.9.0'}
+ '@babel/core@7.26.10':
+ resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==}
+ engines: {node: '>=6.9.0'}
+
'@babel/generator@7.24.1':
resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==}
engines: {node: '>=6.9.0'}
@@ -900,6 +908,10 @@ packages:
resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==}
engines: {node: '>=6.9.0'}
+ '@babel/generator@7.27.0':
+ resolution: {integrity: sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-annotate-as-pure@7.22.5':
resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==}
engines: {node: '>=6.9.0'}
@@ -912,6 +924,10 @@ packages:
resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-compilation-targets@7.27.0':
+ resolution: {integrity: sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-create-class-features-plugin@7.23.7':
resolution: {integrity: sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==}
engines: {node: '>=6.9.0'}
@@ -1067,6 +1083,10 @@ packages:
resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==}
engines: {node: '>=6.9.0'}
+ '@babel/helpers@7.27.0':
+ resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==}
+ engines: {node: '>=6.9.0'}
+
'@babel/highlight@7.24.2':
resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==}
engines: {node: '>=6.9.0'}
@@ -1076,13 +1096,13 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/parser@7.24.6':
- resolution: {integrity: sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==}
+ '@babel/parser@7.26.2':
+ resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==}
engines: {node: '>=6.0.0'}
hasBin: true
- '@babel/parser@7.26.2':
- resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==}
+ '@babel/parser@7.27.0':
+ resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==}
engines: {node: '>=6.0.0'}
hasBin: true
@@ -1583,10 +1603,18 @@ packages:
resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==}
engines: {node: '>=6.9.0'}
+ '@babel/template@7.27.0':
+ resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/traverse@7.25.9':
resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==}
engines: {node: '>=6.9.0'}
+ '@babel/traverse@7.27.0':
+ resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/types@7.23.6':
resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==}
engines: {node: '>=6.9.0'}
@@ -1603,6 +1631,10 @@ packages:
resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==}
engines: {node: '>=6.9.0'}
+ '@babel/types@7.27.0':
+ resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==}
+ engines: {node: '>=6.9.0'}
+
'@bcoe/v8-coverage@0.2.3':
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
@@ -1701,12 +1733,6 @@ packages:
cpu: [ppc64]
os: [aix]
- '@esbuild/aix-ppc64@0.24.2':
- resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [aix]
-
'@esbuild/aix-ppc64@0.25.0':
resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==}
engines: {node: '>=18'}
@@ -1719,12 +1745,6 @@ packages:
cpu: [arm64]
os: [android]
- '@esbuild/android-arm64@0.24.2':
- resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [android]
-
'@esbuild/android-arm64@0.25.0':
resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==}
engines: {node: '>=18'}
@@ -1737,12 +1757,6 @@ packages:
cpu: [arm]
os: [android]
- '@esbuild/android-arm@0.24.2':
- resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [android]
-
'@esbuild/android-arm@0.25.0':
resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==}
engines: {node: '>=18'}
@@ -1755,12 +1769,6 @@ packages:
cpu: [x64]
os: [android]
- '@esbuild/android-x64@0.24.2':
- resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [android]
-
'@esbuild/android-x64@0.25.0':
resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==}
engines: {node: '>=18'}
@@ -1773,12 +1781,6 @@ packages:
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-arm64@0.24.2':
- resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [darwin]
-
'@esbuild/darwin-arm64@0.25.0':
resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==}
engines: {node: '>=18'}
@@ -1791,12 +1793,6 @@ packages:
cpu: [x64]
os: [darwin]
- '@esbuild/darwin-x64@0.24.2':
- resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [darwin]
-
'@esbuild/darwin-x64@0.25.0':
resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==}
engines: {node: '>=18'}
@@ -1809,12 +1805,6 @@ packages:
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-arm64@0.24.2':
- resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [freebsd]
-
'@esbuild/freebsd-arm64@0.25.0':
resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==}
engines: {node: '>=18'}
@@ -1827,12 +1817,6 @@ packages:
cpu: [x64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.24.2':
- resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [freebsd]
-
'@esbuild/freebsd-x64@0.25.0':
resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==}
engines: {node: '>=18'}
@@ -1845,12 +1829,6 @@ packages:
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm64@0.24.2':
- resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [linux]
-
'@esbuild/linux-arm64@0.25.0':
resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==}
engines: {node: '>=18'}
@@ -1863,12 +1841,6 @@ packages:
cpu: [arm]
os: [linux]
- '@esbuild/linux-arm@0.24.2':
- resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [linux]
-
'@esbuild/linux-arm@0.25.0':
resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==}
engines: {node: '>=18'}
@@ -1881,12 +1853,6 @@ packages:
cpu: [ia32]
os: [linux]
- '@esbuild/linux-ia32@0.24.2':
- resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [linux]
-
'@esbuild/linux-ia32@0.25.0':
resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==}
engines: {node: '>=18'}
@@ -1899,12 +1865,6 @@ packages:
cpu: [loong64]
os: [linux]
- '@esbuild/linux-loong64@0.24.2':
- resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==}
- engines: {node: '>=18'}
- cpu: [loong64]
- os: [linux]
-
'@esbuild/linux-loong64@0.25.0':
resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==}
engines: {node: '>=18'}
@@ -1917,12 +1877,6 @@ packages:
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-mips64el@0.24.2':
- resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==}
- engines: {node: '>=18'}
- cpu: [mips64el]
- os: [linux]
-
'@esbuild/linux-mips64el@0.25.0':
resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==}
engines: {node: '>=18'}
@@ -1935,12 +1889,6 @@ packages:
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-ppc64@0.24.2':
- resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [linux]
-
'@esbuild/linux-ppc64@0.25.0':
resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==}
engines: {node: '>=18'}
@@ -1953,12 +1901,6 @@ packages:
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-riscv64@0.24.2':
- resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==}
- engines: {node: '>=18'}
- cpu: [riscv64]
- os: [linux]
-
'@esbuild/linux-riscv64@0.25.0':
resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==}
engines: {node: '>=18'}
@@ -1971,12 +1913,6 @@ packages:
cpu: [s390x]
os: [linux]
- '@esbuild/linux-s390x@0.24.2':
- resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==}
- engines: {node: '>=18'}
- cpu: [s390x]
- os: [linux]
-
'@esbuild/linux-s390x@0.25.0':
resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==}
engines: {node: '>=18'}
@@ -1989,24 +1925,12 @@ packages:
cpu: [x64]
os: [linux]
- '@esbuild/linux-x64@0.24.2':
- resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [linux]
-
'@esbuild/linux-x64@0.25.0':
resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
- '@esbuild/netbsd-arm64@0.24.2':
- resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [netbsd]
-
'@esbuild/netbsd-arm64@0.25.0':
resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==}
engines: {node: '>=18'}
@@ -2019,24 +1943,12 @@ packages:
cpu: [x64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.24.2':
- resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [netbsd]
-
'@esbuild/netbsd-x64@0.25.0':
resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
- '@esbuild/openbsd-arm64@0.24.2':
- resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [openbsd]
-
'@esbuild/openbsd-arm64@0.25.0':
resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==}
engines: {node: '>=18'}
@@ -2049,12 +1961,6 @@ packages:
cpu: [x64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.24.2':
- resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [openbsd]
-
'@esbuild/openbsd-x64@0.25.0':
resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==}
engines: {node: '>=18'}
@@ -2067,12 +1973,6 @@ packages:
cpu: [x64]
os: [sunos]
- '@esbuild/sunos-x64@0.24.2':
- resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [sunos]
-
'@esbuild/sunos-x64@0.25.0':
resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==}
engines: {node: '>=18'}
@@ -2085,12 +1985,6 @@ packages:
cpu: [arm64]
os: [win32]
- '@esbuild/win32-arm64@0.24.2':
- resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [win32]
-
'@esbuild/win32-arm64@0.25.0':
resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==}
engines: {node: '>=18'}
@@ -2103,12 +1997,6 @@ packages:
cpu: [ia32]
os: [win32]
- '@esbuild/win32-ia32@0.24.2':
- resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [win32]
-
'@esbuild/win32-ia32@0.25.0':
resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==}
engines: {node: '>=18'}
@@ -2121,12 +2009,6 @@ packages:
cpu: [x64]
os: [win32]
- '@esbuild/win32-x64@0.24.2':
- resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [win32]
-
'@esbuild/win32-x64@0.25.0':
resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==}
engines: {node: '>=18'}
@@ -3164,98 +3046,103 @@ packages:
'@remirror/core-constants@3.0.0':
resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==}
- '@rollup/rollup-android-arm-eabi@4.34.7':
- resolution: {integrity: sha512-l6CtzHYo8D2TQ3J7qJNpp3Q1Iye56ssIAtqbM2H8axxCEEwvN7o8Ze9PuIapbxFL3OHrJU2JBX6FIIVnP/rYyw==}
+ '@rollup/rollup-android-arm-eabi@4.40.0':
+ resolution: {integrity: sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==}
cpu: [arm]
os: [android]
- '@rollup/rollup-android-arm64@4.34.7':
- resolution: {integrity: sha512-KvyJpFUueUnSp53zhAa293QBYqwm94TgYTIfXyOTtidhm5V0LbLCJQRGkQClYiX3FXDQGSvPxOTD/6rPStMMDg==}
+ '@rollup/rollup-android-arm64@4.40.0':
+ resolution: {integrity: sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==}
cpu: [arm64]
os: [android]
- '@rollup/rollup-darwin-arm64@4.34.7':
- resolution: {integrity: sha512-jq87CjmgL9YIKvs8ybtIC98s/M3HdbqXhllcy9EdLV0yMg1DpxES2gr65nNy7ObNo/vZ/MrOTxt0bE5LinL6mA==}
+ '@rollup/rollup-darwin-arm64@4.40.0':
+ resolution: {integrity: sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==}
cpu: [arm64]
os: [darwin]
- '@rollup/rollup-darwin-x64@4.34.7':
- resolution: {integrity: sha512-rSI/m8OxBjsdnMMg0WEetu/w+LhLAcCDEiL66lmMX4R3oaml3eXz3Dxfvrxs1FbzPbJMaItQiksyMfv1hoIxnA==}
+ '@rollup/rollup-darwin-x64@4.40.0':
+ resolution: {integrity: sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==}
cpu: [x64]
os: [darwin]
- '@rollup/rollup-freebsd-arm64@4.34.7':
- resolution: {integrity: sha512-oIoJRy3ZrdsXpFuWDtzsOOa/E/RbRWXVokpVrNnkS7npz8GEG++E1gYbzhYxhxHbO2om1T26BZjVmdIoyN2WtA==}
+ '@rollup/rollup-freebsd-arm64@4.40.0':
+ resolution: {integrity: sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==}
cpu: [arm64]
os: [freebsd]
- '@rollup/rollup-freebsd-x64@4.34.7':
- resolution: {integrity: sha512-X++QSLm4NZfZ3VXGVwyHdRf58IBbCu9ammgJxuWZYLX0du6kZvdNqPwrjvDfwmi6wFdvfZ/s6K7ia0E5kI7m8Q==}
+ '@rollup/rollup-freebsd-x64@4.40.0':
+ resolution: {integrity: sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==}
cpu: [x64]
os: [freebsd]
- '@rollup/rollup-linux-arm-gnueabihf@4.34.7':
- resolution: {integrity: sha512-Z0TzhrsNqukTz3ISzrvyshQpFnFRfLunYiXxlCRvcrb3nvC5rVKI+ZXPFG/Aa4jhQa1gHgH3A0exHaRRN4VmdQ==}
+ '@rollup/rollup-linux-arm-gnueabihf@4.40.0':
+ resolution: {integrity: sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm-musleabihf@4.34.7':
- resolution: {integrity: sha512-nkznpyXekFAbvFBKBy4nNppSgneB1wwG1yx/hujN3wRnhnkrYVugMTCBXED4+Ni6thoWfQuHNYbFjgGH0MBXtw==}
+ '@rollup/rollup-linux-arm-musleabihf@4.40.0':
+ resolution: {integrity: sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm64-gnu@4.34.7':
- resolution: {integrity: sha512-KCjlUkcKs6PjOcxolqrXglBDcfCuUCTVlX5BgzgoJHw+1rWH1MCkETLkLe5iLLS9dP5gKC7mp3y6x8c1oGBUtA==}
+ '@rollup/rollup-linux-arm64-gnu@4.40.0':
+ resolution: {integrity: sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-arm64-musl@4.34.7':
- resolution: {integrity: sha512-uFLJFz6+utmpbR313TTx+NpPuAXbPz4BhTQzgaP0tozlLnGnQ6rCo6tLwaSa6b7l6gRErjLicXQ1iPiXzYotjw==}
+ '@rollup/rollup-linux-arm64-musl@4.40.0':
+ resolution: {integrity: sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-loongarch64-gnu@4.34.7':
- resolution: {integrity: sha512-ws8pc68UcJJqCpneDFepnwlsMUFoWvPbWXT/XUrJ7rWUL9vLoIN3GAasgG+nCvq8xrE3pIrd+qLX/jotcLy0Qw==}
+ '@rollup/rollup-linux-loongarch64-gnu@4.40.0':
+ resolution: {integrity: sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==}
cpu: [loong64]
os: [linux]
- '@rollup/rollup-linux-powerpc64le-gnu@4.34.7':
- resolution: {integrity: sha512-vrDk9JDa/BFkxcS2PbWpr0C/LiiSLxFbNOBgfbW6P8TBe9PPHx9Wqbvx2xgNi1TOAyQHQJ7RZFqBiEohm79r0w==}
+ '@rollup/rollup-linux-powerpc64le-gnu@4.40.0':
+ resolution: {integrity: sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==}
cpu: [ppc64]
os: [linux]
- '@rollup/rollup-linux-riscv64-gnu@4.34.7':
- resolution: {integrity: sha512-rB+ejFyjtmSo+g/a4eovDD1lHWHVqizN8P0Hm0RElkINpS0XOdpaXloqM4FBkF9ZWEzg6bezymbpLmeMldfLTw==}
+ '@rollup/rollup-linux-riscv64-gnu@4.40.0':
+ resolution: {integrity: sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==}
cpu: [riscv64]
os: [linux]
- '@rollup/rollup-linux-s390x-gnu@4.34.7':
- resolution: {integrity: sha512-nNXNjo4As6dNqRn7OrsnHzwTgtypfRA3u3AKr0B3sOOo+HkedIbn8ZtFnB+4XyKJojIfqDKmbIzO1QydQ8c+Pw==}
+ '@rollup/rollup-linux-riscv64-musl@4.40.0':
+ resolution: {integrity: sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.40.0':
+ resolution: {integrity: sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==}
cpu: [s390x]
os: [linux]
- '@rollup/rollup-linux-x64-gnu@4.34.7':
- resolution: {integrity: sha512-9kPVf9ahnpOMSGlCxXGv980wXD0zRR3wyk8+33/MXQIpQEOpaNe7dEHm5LMfyRZRNt9lMEQuH0jUKj15MkM7QA==}
+ '@rollup/rollup-linux-x64-gnu@4.40.0':
+ resolution: {integrity: sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-linux-x64-musl@4.34.7':
- resolution: {integrity: sha512-7wJPXRWTTPtTFDFezA8sle/1sdgxDjuMoRXEKtx97ViRxGGkVQYovem+Q8Pr/2HxiHp74SSRG+o6R0Yq0shPwQ==}
+ '@rollup/rollup-linux-x64-musl@4.40.0':
+ resolution: {integrity: sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-win32-arm64-msvc@4.34.7':
- resolution: {integrity: sha512-MN7aaBC7mAjsiMEZcsJvwNsQVNZShgES/9SzWp1HC9Yjqb5OpexYnRjF7RmE4itbeesHMYYQiAtUAQaSKs2Rfw==}
+ '@rollup/rollup-win32-arm64-msvc@4.40.0':
+ resolution: {integrity: sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==}
cpu: [arm64]
os: [win32]
- '@rollup/rollup-win32-ia32-msvc@4.34.7':
- resolution: {integrity: sha512-aeawEKYswsFu1LhDM9RIgToobquzdtSc4jSVqHV8uApz4FVvhFl/mKh92wc8WpFc6aYCothV/03UjY6y7yLgbg==}
+ '@rollup/rollup-win32-ia32-msvc@4.40.0':
+ resolution: {integrity: sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==}
cpu: [ia32]
os: [win32]
- '@rollup/rollup-win32-x64-msvc@4.34.7':
- resolution: {integrity: sha512-4ZedScpxxIrVO7otcZ8kCX1mZArtH2Wfj3uFCxRJ9NO80gg1XV0U/b2f/MKaGwj2X3QopHfoWiDQ917FRpwY3w==}
+ '@rollup/rollup-win32-x64-msvc@4.40.0':
+ resolution: {integrity: sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==}
cpu: [x64]
os: [win32]
@@ -4019,6 +3906,9 @@ packages:
'@types/estree@1.0.6':
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
+ '@types/estree@1.0.7':
+ resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
+
'@types/express-serve-static-core@4.17.43':
resolution: {integrity: sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==}
@@ -4314,8 +4204,8 @@ packages:
'@ucast/mongo@2.4.3':
resolution: {integrity: sha512-XcI8LclrHWP83H+7H2anGCEeDq0n+12FU2mXCTz6/Tva9/9ddK/iacvvhCyW6cijAAOILmt0tWplRyRhVyZLsA==}
- '@vitejs/plugin-react@4.3.4':
- resolution: {integrity: sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==}
+ '@vitejs/plugin-react@4.4.1':
+ resolution: {integrity: sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
vite: ^4.2.0 || ^5.0.0 || ^6.0.0
@@ -4588,11 +4478,8 @@ packages:
avvio@9.1.0:
resolution: {integrity: sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw==}
- axios@1.7.8:
- resolution: {integrity: sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==}
-
- axios@1.7.9:
- resolution: {integrity: sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==}
+ axios@1.8.4:
+ resolution: {integrity: sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==}
babel-jest@29.7.0:
resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
@@ -5492,11 +5379,6 @@ packages:
engines: {node: '>=12'}
hasBin: true
- esbuild@0.24.2:
- resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==}
- engines: {node: '>=18'}
- hasBin: true
-
esbuild@0.25.0:
resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==}
engines: {node: '>=18'}
@@ -7429,8 +7311,8 @@ packages:
resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==}
engines: {node: ^10 || ^12 || >=14}
- postcss@8.5.2:
- resolution: {integrity: sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==}
+ postcss@8.5.3:
+ resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
engines: {node: ^10 || ^12 || >=14}
postgres-array@2.0.0:
@@ -7698,8 +7580,8 @@ packages:
react-promise-suspense@0.3.4:
resolution: {integrity: sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==}
- react-refresh@0.14.2:
- resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
+ react-refresh@0.17.0:
+ resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
engines: {node: '>=0.10.0'}
react-remove-scroll-bar@2.3.8:
@@ -7918,8 +7800,8 @@ packages:
robust-predicates@3.0.2:
resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==}
- rollup@4.34.7:
- resolution: {integrity: sha512-8qhyN0oZ4x0H6wmBgfKxJtxM7qS98YJ0k0kNh5ECVtuchIJ7z9IVVvzpmtQyT10PXKMtBxYr1wQ5Apg8RS8kXQ==}
+ rollup@4.40.0:
+ resolution: {integrity: sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
@@ -8670,8 +8552,8 @@ packages:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'}
- vite@6.1.0:
- resolution: {integrity: sha512-RjjMipCKVoR4hVfPY6GQTgveinjNuyLw+qruksLDvA5ktI1150VmcMBKmQaEWJhg/j6Uaf6dNCNA0AfdzUb/hQ==}
+ vite@6.3.2:
+ resolution: {integrity: sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
peerDependencies:
@@ -9598,6 +9480,8 @@ snapshots:
'@babel/compat-data@7.26.2': {}
+ '@babel/compat-data@7.26.8': {}
+
'@babel/core@7.24.5':
dependencies:
'@ampproject/remapping': 2.3.0
@@ -9658,6 +9542,26 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@babel/core@7.26.10':
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@babel/code-frame': 7.26.2
+ '@babel/generator': 7.27.0
+ '@babel/helper-compilation-targets': 7.27.0
+ '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10)
+ '@babel/helpers': 7.27.0
+ '@babel/parser': 7.27.0
+ '@babel/template': 7.27.0
+ '@babel/traverse': 7.27.0
+ '@babel/types': 7.27.0
+ convert-source-map: 2.0.0
+ debug: 4.3.7
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/generator@7.24.1':
dependencies:
'@babel/types': 7.24.0
@@ -9680,6 +9584,14 @@ snapshots:
'@jridgewell/trace-mapping': 0.3.25
jsesc: 3.0.2
+ '@babel/generator@7.27.0':
+ dependencies:
+ '@babel/parser': 7.27.0
+ '@babel/types': 7.27.0
+ '@jridgewell/gen-mapping': 0.3.5
+ '@jridgewell/trace-mapping': 0.3.25
+ jsesc: 3.0.2
+
'@babel/helper-annotate-as-pure@7.22.5':
dependencies:
'@babel/types': 7.26.0
@@ -9696,6 +9608,14 @@ snapshots:
lru-cache: 5.1.1
semver: 6.3.1
+ '@babel/helper-compilation-targets@7.27.0':
+ dependencies:
+ '@babel/compat-data': 7.26.8
+ '@babel/helper-validator-option': 7.25.9
+ browserslist: 4.24.2
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
'@babel/helper-create-class-features-plugin@7.23.7(@babel/core@7.26.0)':
dependencies:
'@babel/core': 7.26.0
@@ -9795,6 +9715,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)':
+ dependencies:
+ '@babel/core': 7.26.10
+ '@babel/helper-module-imports': 7.25.9
+ '@babel/helper-validator-identifier': 7.25.9
+ '@babel/traverse': 7.25.9
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/helper-optimise-call-expression@7.22.5':
dependencies:
'@babel/types': 7.26.0
@@ -9869,6 +9798,11 @@ snapshots:
'@babel/template': 7.25.9
'@babel/types': 7.26.0
+ '@babel/helpers@7.27.0':
+ dependencies:
+ '@babel/template': 7.27.0
+ '@babel/types': 7.27.0
+
'@babel/highlight@7.24.2':
dependencies:
'@babel/helper-validator-identifier': 7.22.20
@@ -9880,14 +9814,14 @@ snapshots:
dependencies:
'@babel/types': 7.26.0
- '@babel/parser@7.24.6':
- dependencies:
- '@babel/types': 7.24.6
-
'@babel/parser@7.26.2':
dependencies:
'@babel/types': 7.26.0
+ '@babel/parser@7.27.0':
+ dependencies:
+ '@babel/types': 7.27.0
+
'@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.26.0)':
dependencies:
'@babel/core': 7.26.0
@@ -10405,14 +10339,14 @@ snapshots:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.0)':
+ '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.10)':
dependencies:
- '@babel/core': 7.26.0
+ '@babel/core': 7.26.10
'@babel/helper-plugin-utils': 7.25.9
- '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.0)':
+ '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.10)':
dependencies:
- '@babel/core': 7.26.0
+ '@babel/core': 7.26.10
'@babel/helper-plugin-utils': 7.25.9
'@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.26.0)':
@@ -10619,6 +10553,12 @@ snapshots:
'@babel/parser': 7.26.2
'@babel/types': 7.26.0
+ '@babel/template@7.27.0':
+ dependencies:
+ '@babel/code-frame': 7.26.2
+ '@babel/parser': 7.27.0
+ '@babel/types': 7.27.0
+
'@babel/traverse@7.25.9':
dependencies:
'@babel/code-frame': 7.26.2
@@ -10631,6 +10571,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@babel/traverse@7.27.0':
+ dependencies:
+ '@babel/code-frame': 7.26.2
+ '@babel/generator': 7.27.0
+ '@babel/parser': 7.27.0
+ '@babel/template': 7.27.0
+ '@babel/types': 7.27.0
+ debug: 4.3.7
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/types@7.23.6':
dependencies:
'@babel/helper-string-parser': 7.23.4
@@ -10654,6 +10606,11 @@ snapshots:
'@babel/helper-string-parser': 7.25.9
'@babel/helper-validator-identifier': 7.25.9
+ '@babel/types@7.27.0':
+ dependencies:
+ '@babel/helper-string-parser': 7.25.9
+ '@babel/helper-validator-identifier': 7.25.9
+
'@bcoe/v8-coverage@0.2.3': {}
'@braintree/sanitize-url@7.1.0': {}
@@ -10742,219 +10699,144 @@ snapshots:
'@esbuild/aix-ppc64@0.19.11':
optional: true
- '@esbuild/aix-ppc64@0.24.2':
- optional: true
-
'@esbuild/aix-ppc64@0.25.0':
optional: true
'@esbuild/android-arm64@0.19.11':
optional: true
- '@esbuild/android-arm64@0.24.2':
- optional: true
-
'@esbuild/android-arm64@0.25.0':
optional: true
'@esbuild/android-arm@0.19.11':
optional: true
- '@esbuild/android-arm@0.24.2':
- optional: true
-
'@esbuild/android-arm@0.25.0':
optional: true
'@esbuild/android-x64@0.19.11':
optional: true
- '@esbuild/android-x64@0.24.2':
- optional: true
-
'@esbuild/android-x64@0.25.0':
optional: true
'@esbuild/darwin-arm64@0.19.11':
optional: true
- '@esbuild/darwin-arm64@0.24.2':
- optional: true
-
'@esbuild/darwin-arm64@0.25.0':
optional: true
'@esbuild/darwin-x64@0.19.11':
optional: true
- '@esbuild/darwin-x64@0.24.2':
- optional: true
-
'@esbuild/darwin-x64@0.25.0':
optional: true
'@esbuild/freebsd-arm64@0.19.11':
optional: true
- '@esbuild/freebsd-arm64@0.24.2':
- optional: true
-
'@esbuild/freebsd-arm64@0.25.0':
optional: true
'@esbuild/freebsd-x64@0.19.11':
optional: true
- '@esbuild/freebsd-x64@0.24.2':
- optional: true
-
'@esbuild/freebsd-x64@0.25.0':
optional: true
'@esbuild/linux-arm64@0.19.11':
optional: true
- '@esbuild/linux-arm64@0.24.2':
- optional: true
-
'@esbuild/linux-arm64@0.25.0':
optional: true
'@esbuild/linux-arm@0.19.11':
optional: true
- '@esbuild/linux-arm@0.24.2':
- optional: true
-
'@esbuild/linux-arm@0.25.0':
optional: true
'@esbuild/linux-ia32@0.19.11':
optional: true
- '@esbuild/linux-ia32@0.24.2':
- optional: true
-
'@esbuild/linux-ia32@0.25.0':
optional: true
'@esbuild/linux-loong64@0.19.11':
optional: true
- '@esbuild/linux-loong64@0.24.2':
- optional: true
-
'@esbuild/linux-loong64@0.25.0':
optional: true
'@esbuild/linux-mips64el@0.19.11':
optional: true
- '@esbuild/linux-mips64el@0.24.2':
- optional: true
-
'@esbuild/linux-mips64el@0.25.0':
optional: true
'@esbuild/linux-ppc64@0.19.11':
optional: true
- '@esbuild/linux-ppc64@0.24.2':
- optional: true
-
'@esbuild/linux-ppc64@0.25.0':
optional: true
'@esbuild/linux-riscv64@0.19.11':
optional: true
- '@esbuild/linux-riscv64@0.24.2':
- optional: true
-
'@esbuild/linux-riscv64@0.25.0':
optional: true
'@esbuild/linux-s390x@0.19.11':
optional: true
- '@esbuild/linux-s390x@0.24.2':
- optional: true
-
'@esbuild/linux-s390x@0.25.0':
optional: true
'@esbuild/linux-x64@0.19.11':
optional: true
- '@esbuild/linux-x64@0.24.2':
- optional: true
-
'@esbuild/linux-x64@0.25.0':
optional: true
- '@esbuild/netbsd-arm64@0.24.2':
- optional: true
-
'@esbuild/netbsd-arm64@0.25.0':
optional: true
'@esbuild/netbsd-x64@0.19.11':
optional: true
- '@esbuild/netbsd-x64@0.24.2':
- optional: true
-
'@esbuild/netbsd-x64@0.25.0':
optional: true
- '@esbuild/openbsd-arm64@0.24.2':
- optional: true
-
'@esbuild/openbsd-arm64@0.25.0':
optional: true
'@esbuild/openbsd-x64@0.19.11':
optional: true
- '@esbuild/openbsd-x64@0.24.2':
- optional: true
-
'@esbuild/openbsd-x64@0.25.0':
optional: true
'@esbuild/sunos-x64@0.19.11':
optional: true
- '@esbuild/sunos-x64@0.24.2':
- optional: true
-
'@esbuild/sunos-x64@0.25.0':
optional: true
'@esbuild/win32-arm64@0.19.11':
optional: true
- '@esbuild/win32-arm64@0.24.2':
- optional: true
-
'@esbuild/win32-arm64@0.25.0':
optional: true
'@esbuild/win32-ia32@0.19.11':
optional: true
- '@esbuild/win32-ia32@0.24.2':
- optional: true
-
'@esbuild/win32-ia32@0.25.0':
optional: true
'@esbuild/win32-x64@0.19.11':
optional: true
- '@esbuild/win32-x64@0.24.2':
- optional: true
-
'@esbuild/win32-x64@0.25.0':
optional: true
@@ -11919,7 +11801,7 @@ snapshots:
tslib: 2.8.0
yargs-parser: 21.1.1
- '@nx/js@20.4.5(@babel/traverse@7.25.9)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)':
+ '@nx/js@20.4.5(@babel/traverse@7.27.0)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)':
dependencies:
'@babel/core': 7.26.0
'@babel/plugin-proposal-decorators': 7.23.7(@babel/core@7.26.0)
@@ -11933,7 +11815,7 @@ snapshots:
'@zkochan/js-yaml': 0.0.7
babel-plugin-const-enum: 1.2.0(@babel/core@7.26.0)
babel-plugin-macros: 3.1.0
- babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.26.0)(@babel/traverse@7.25.9)
+ babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.26.0)(@babel/traverse@7.27.0)
chalk: 4.1.2
columnify: 1.6.0
detect-port: 1.5.1
@@ -12135,61 +12017,64 @@ snapshots:
'@remirror/core-constants@3.0.0': {}
- '@rollup/rollup-android-arm-eabi@4.34.7':
+ '@rollup/rollup-android-arm-eabi@4.40.0':
optional: true
- '@rollup/rollup-android-arm64@4.34.7':
+ '@rollup/rollup-android-arm64@4.40.0':
optional: true
- '@rollup/rollup-darwin-arm64@4.34.7':
+ '@rollup/rollup-darwin-arm64@4.40.0':
optional: true
- '@rollup/rollup-darwin-x64@4.34.7':
+ '@rollup/rollup-darwin-x64@4.40.0':
optional: true
- '@rollup/rollup-freebsd-arm64@4.34.7':
+ '@rollup/rollup-freebsd-arm64@4.40.0':
optional: true
- '@rollup/rollup-freebsd-x64@4.34.7':
+ '@rollup/rollup-freebsd-x64@4.40.0':
optional: true
- '@rollup/rollup-linux-arm-gnueabihf@4.34.7':
+ '@rollup/rollup-linux-arm-gnueabihf@4.40.0':
optional: true
- '@rollup/rollup-linux-arm-musleabihf@4.34.7':
+ '@rollup/rollup-linux-arm-musleabihf@4.40.0':
optional: true
- '@rollup/rollup-linux-arm64-gnu@4.34.7':
+ '@rollup/rollup-linux-arm64-gnu@4.40.0':
optional: true
- '@rollup/rollup-linux-arm64-musl@4.34.7':
+ '@rollup/rollup-linux-arm64-musl@4.40.0':
optional: true
- '@rollup/rollup-linux-loongarch64-gnu@4.34.7':
+ '@rollup/rollup-linux-loongarch64-gnu@4.40.0':
optional: true
- '@rollup/rollup-linux-powerpc64le-gnu@4.34.7':
+ '@rollup/rollup-linux-powerpc64le-gnu@4.40.0':
optional: true
- '@rollup/rollup-linux-riscv64-gnu@4.34.7':
+ '@rollup/rollup-linux-riscv64-gnu@4.40.0':
optional: true
- '@rollup/rollup-linux-s390x-gnu@4.34.7':
+ '@rollup/rollup-linux-riscv64-musl@4.40.0':
optional: true
- '@rollup/rollup-linux-x64-gnu@4.34.7':
+ '@rollup/rollup-linux-s390x-gnu@4.40.0':
optional: true
- '@rollup/rollup-linux-x64-musl@4.34.7':
+ '@rollup/rollup-linux-x64-gnu@4.40.0':
optional: true
- '@rollup/rollup-win32-arm64-msvc@4.34.7':
+ '@rollup/rollup-linux-x64-musl@4.40.0':
optional: true
- '@rollup/rollup-win32-ia32-msvc@4.34.7':
+ '@rollup/rollup-win32-arm64-msvc@4.40.0':
optional: true
- '@rollup/rollup-win32-x64-msvc@4.34.7':
+ '@rollup/rollup-win32-ia32-msvc@4.40.0':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.40.0':
optional: true
'@selderee/plugin-htmlparser2@0.11.0':
@@ -12926,20 +12811,20 @@ snapshots:
'@types/babel__core@7.20.5':
dependencies:
- '@babel/parser': 7.24.6
- '@babel/types': 7.24.6
+ '@babel/parser': 7.26.2
+ '@babel/types': 7.26.0
'@types/babel__generator': 7.6.8
'@types/babel__template': 7.4.4
'@types/babel__traverse': 7.20.5
'@types/babel__generator@7.6.8':
dependencies:
- '@babel/types': 7.24.6
+ '@babel/types': 7.26.0
'@types/babel__template@7.4.4':
dependencies:
- '@babel/parser': 7.24.6
- '@babel/types': 7.24.6
+ '@babel/parser': 7.26.2
+ '@babel/types': 7.26.0
'@types/babel__traverse@7.20.5':
dependencies:
@@ -13105,6 +12990,8 @@ snapshots:
'@types/estree@1.0.6': {}
+ '@types/estree@1.0.7': {}
+
'@types/express-serve-static-core@4.17.43':
dependencies:
'@types/node': 22.13.4
@@ -13485,14 +13372,14 @@ snapshots:
dependencies:
'@ucast/core': 1.10.2
- '@vitejs/plugin-react@4.3.4(vite@6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))':
+ '@vitejs/plugin-react@4.4.1(vite@6.3.2(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0))':
dependencies:
- '@babel/core': 7.26.0
- '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0)
- '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0)
+ '@babel/core': 7.26.10
+ '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10)
+ '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10)
'@types/babel__core': 7.20.5
- react-refresh: 0.14.2
- vite: 6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)
+ react-refresh: 0.17.0
+ vite: 6.3.2(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
@@ -13797,15 +13684,7 @@ snapshots:
'@fastify/error': 4.0.0
fastq: 1.17.1
- axios@1.7.8:
- dependencies:
- follow-redirects: 1.15.6
- form-data: 4.0.0
- proxy-from-env: 1.1.0
- transitivePeerDependencies:
- - debug
-
- axios@1.7.9:
+ axios@1.8.4:
dependencies:
follow-redirects: 1.15.6
form-data: 4.0.0
@@ -13896,12 +13775,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
- babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.26.0)(@babel/traverse@7.25.9):
+ babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.26.0)(@babel/traverse@7.27.0):
dependencies:
'@babel/core': 7.26.0
'@babel/helper-plugin-utils': 7.25.9
optionalDependencies:
- '@babel/traverse': 7.25.9
+ '@babel/traverse': 7.27.0
babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.5):
dependencies:
@@ -14910,34 +14789,6 @@ snapshots:
'@esbuild/win32-ia32': 0.19.11
'@esbuild/win32-x64': 0.19.11
- esbuild@0.24.2:
- optionalDependencies:
- '@esbuild/aix-ppc64': 0.24.2
- '@esbuild/android-arm': 0.24.2
- '@esbuild/android-arm64': 0.24.2
- '@esbuild/android-x64': 0.24.2
- '@esbuild/darwin-arm64': 0.24.2
- '@esbuild/darwin-x64': 0.24.2
- '@esbuild/freebsd-arm64': 0.24.2
- '@esbuild/freebsd-x64': 0.24.2
- '@esbuild/linux-arm': 0.24.2
- '@esbuild/linux-arm64': 0.24.2
- '@esbuild/linux-ia32': 0.24.2
- '@esbuild/linux-loong64': 0.24.2
- '@esbuild/linux-mips64el': 0.24.2
- '@esbuild/linux-ppc64': 0.24.2
- '@esbuild/linux-riscv64': 0.24.2
- '@esbuild/linux-s390x': 0.24.2
- '@esbuild/linux-x64': 0.24.2
- '@esbuild/netbsd-arm64': 0.24.2
- '@esbuild/netbsd-x64': 0.24.2
- '@esbuild/openbsd-arm64': 0.24.2
- '@esbuild/openbsd-x64': 0.24.2
- '@esbuild/sunos-x64': 0.24.2
- '@esbuild/win32-arm64': 0.24.2
- '@esbuild/win32-ia32': 0.24.2
- '@esbuild/win32-x64': 0.24.2
-
esbuild@0.25.0:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.0
@@ -16814,7 +16665,7 @@ snapshots:
'@yarnpkg/lockfile': 1.1.0
'@yarnpkg/parsers': 3.0.2
'@zkochan/js-yaml': 0.0.7
- axios: 1.7.9
+ axios: 1.8.4
chalk: 4.1.2
cli-cursor: 3.1.0
cli-spinners: 2.6.1
@@ -17221,7 +17072,7 @@ snapshots:
picocolors: 1.1.1
source-map-js: 1.2.1
- postcss@8.5.2:
+ postcss@8.5.3:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
@@ -17251,7 +17102,7 @@ snapshots:
postmark@4.0.5:
dependencies:
- axios: 1.7.8
+ axios: 1.8.4
transitivePeerDependencies:
- debug
@@ -17528,7 +17379,7 @@ snapshots:
dependencies:
fast-deep-equal: 2.0.1
- react-refresh@0.14.2: {}
+ react-refresh@0.17.0: {}
react-remove-scroll-bar@2.3.8(@types/react@18.3.12)(react@18.3.1):
dependencies:
@@ -17749,29 +17600,30 @@ snapshots:
robust-predicates@3.0.2: {}
- rollup@4.34.7:
+ rollup@4.40.0:
dependencies:
- '@types/estree': 1.0.6
+ '@types/estree': 1.0.7
optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.34.7
- '@rollup/rollup-android-arm64': 4.34.7
- '@rollup/rollup-darwin-arm64': 4.34.7
- '@rollup/rollup-darwin-x64': 4.34.7
- '@rollup/rollup-freebsd-arm64': 4.34.7
- '@rollup/rollup-freebsd-x64': 4.34.7
- '@rollup/rollup-linux-arm-gnueabihf': 4.34.7
- '@rollup/rollup-linux-arm-musleabihf': 4.34.7
- '@rollup/rollup-linux-arm64-gnu': 4.34.7
- '@rollup/rollup-linux-arm64-musl': 4.34.7
- '@rollup/rollup-linux-loongarch64-gnu': 4.34.7
- '@rollup/rollup-linux-powerpc64le-gnu': 4.34.7
- '@rollup/rollup-linux-riscv64-gnu': 4.34.7
- '@rollup/rollup-linux-s390x-gnu': 4.34.7
- '@rollup/rollup-linux-x64-gnu': 4.34.7
- '@rollup/rollup-linux-x64-musl': 4.34.7
- '@rollup/rollup-win32-arm64-msvc': 4.34.7
- '@rollup/rollup-win32-ia32-msvc': 4.34.7
- '@rollup/rollup-win32-x64-msvc': 4.34.7
+ '@rollup/rollup-android-arm-eabi': 4.40.0
+ '@rollup/rollup-android-arm64': 4.40.0
+ '@rollup/rollup-darwin-arm64': 4.40.0
+ '@rollup/rollup-darwin-x64': 4.40.0
+ '@rollup/rollup-freebsd-arm64': 4.40.0
+ '@rollup/rollup-freebsd-x64': 4.40.0
+ '@rollup/rollup-linux-arm-gnueabihf': 4.40.0
+ '@rollup/rollup-linux-arm-musleabihf': 4.40.0
+ '@rollup/rollup-linux-arm64-gnu': 4.40.0
+ '@rollup/rollup-linux-arm64-musl': 4.40.0
+ '@rollup/rollup-linux-loongarch64-gnu': 4.40.0
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.40.0
+ '@rollup/rollup-linux-riscv64-gnu': 4.40.0
+ '@rollup/rollup-linux-riscv64-musl': 4.40.0
+ '@rollup/rollup-linux-s390x-gnu': 4.40.0
+ '@rollup/rollup-linux-x64-gnu': 4.40.0
+ '@rollup/rollup-linux-x64-musl': 4.40.0
+ '@rollup/rollup-win32-arm64-msvc': 4.40.0
+ '@rollup/rollup-win32-ia32-msvc': 4.40.0
+ '@rollup/rollup-win32-x64-msvc': 4.40.0
fsevents: 2.3.3
rope-sequence@1.3.4: {}
@@ -18546,11 +18398,14 @@ snapshots:
vary@1.1.2: {}
- vite@6.1.0(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0):
+ vite@6.3.2(@types/node@22.10.0)(jiti@1.21.0)(less@4.2.0)(sugarss@4.0.1(postcss@8.4.49))(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.0):
dependencies:
- esbuild: 0.24.2
- postcss: 8.5.2
- rollup: 4.34.7
+ esbuild: 0.25.0
+ fdir: 6.4.3(picomatch@4.0.2)
+ picomatch: 4.0.2
+ postcss: 8.5.3
+ rollup: 4.40.0
+ tinyglobby: 0.2.12
optionalDependencies:
'@types/node': 22.10.0
fsevents: 2.3.3
From 6c422011ac26c49978b5526cf8d3d644db9ca510 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 22 Apr 2025 20:37:32 +0100
Subject: [PATCH 27/63] feat: public page sharing (#1012)
* Share - WIP
* - public attachment links
- WIP
* WIP
* WIP
* Share - WIP
* WIP
* WIP
* include userRole in space object
* WIP
* Server render shared page meta tags
* disable user select
* Close Navbar on outside click on mobile
* update shared page spaceId
* WIP
* fix
* close sidebar on click
* close sidebar
* defaults
* update copy
* Store share key in lowercase
* refactor page breadcrumbs
* Change copy
* add link ref
* open link button
* add meta og:title
* add twitter tags
* WIP
* make shares/info endpoint public
* fix
* * add /p/ segment to share urls
* minore fixes
* change mobile breadcrumb icon
---
apps/client/index.html | 1 +
.../public/locales/en-US/translation.json | 23 +-
apps/client/src/App.tsx | 11 +
.../layouts/global/global-app-shell.tsx | 14 +-
.../components/settings/settings-queries.tsx | 12 +-
.../components/settings/settings-sidebar.tsx | 15 +
.../src/components/theme-toggle.module.css | 19 +
apps/client/src/components/theme-toggle.tsx | 33 +-
.../src/features/editor/atoms/editor-atoms.ts | 2 +
.../editor/components/drawio/drawio-view.tsx | 2 +-
.../components/excalidraw/excalidraw-view.tsx | 2 +-
.../components/mention/mention-view.tsx | 21 +-
.../table-of-contents.module.css | 5 +
.../table-of-contents/table-of-contents.tsx | 26 +-
.../features/editor/readonly-page-editor.tsx | 67 ++
.../breadcrumbs/breadcrumb.module.css | 1 +
.../components/breadcrumbs/breadcrumb.tsx | 88 ++-
.../components/header/page-header-menu.tsx | 3 +
apps/client/src/features/page/page.utils.ts | 19 +-
.../page/tree/components/space-tree.tsx | 31 +-
.../features/page/tree/styles/tree.module.css | 6 +-
.../src/features/page/tree/utils/utils.ts | 2 +-
.../src/features/share/atoms/sidebar-atom.ts | 9 +
.../share/components/share-action-menu.tsx | 106 +++
.../share/components/share-layout.tsx | 10 +
.../features/share/components/share-list.tsx | 97 +++
.../features/share/components/share-modal.tsx | 227 +++++++
.../features/share/components/share-shell.tsx | 196 ++++++
.../share/components/share.module.css | 20 +
.../features/share/components/shared-tree.tsx | 179 +++++
.../features/share/hooks/use-toggle-toc.ts | 8 +
.../src/features/share/queries/share-query.ts | 179 +++++
.../features/share/services/share-service.ts | 59 ++
.../src/features/share/types/share.types.ts | 73 +++
apps/client/src/features/share/utils.ts | 60 ++
.../components/sidebar/space-sidebar.tsx | 12 +-
apps/client/src/lib/api-client.ts | 1 +
.../src/pages/settings/shares/shares.tsx | 31 +
.../client/src/pages/share/share-redirect.tsx | 35 +
apps/client/src/pages/share/shared-page.tsx | 58 ++
apps/server/package.json | 12 +-
.../src/common/helpers/prosemirror/utils.ts | 39 ++
.../core/attachment/attachment.controller.ts | 611 ++++++++++--------
.../src/core/attachment/attachment.module.ts | 3 +-
apps/server/src/core/auth/dto/jwt-payload.ts | 9 +
.../src/core/auth/services/token.service.ts | 16 +
.../casl/abilities/space-ability.factory.ts | 3 +
.../casl/interfaces/space-ability.type.ts | 4 +-
apps/server/src/core/core.module.ts | 2 +
.../src/core/page/services/page.service.ts | 12 +-
apps/server/src/core/share/dto/share.dto.ts | 58 ++
.../src/core/share/share-seo.controller.ts | 109 ++++
.../server/src/core/share/share.controller.ts | 171 +++++
apps/server/src/core/share/share.module.ts | 13 +
apps/server/src/core/share/share.service.ts | 297 +++++++++
apps/server/src/core/share/share.util.ts | 22 +
apps/server/src/database/database.module.ts | 3 +
.../migrations/20250408T191830-shares.ts | 38 ++
.../src/database/repos/page/page.repo.ts | 11 +-
.../src/database/repos/share/share.repo.ts | 242 +++++++
apps/server/src/database/types/db.d.ts | 15 +
.../server/src/database/types/entity.types.ts | 6 +
.../src/integrations/export/export.service.ts | 26 +-
apps/server/src/integrations/export/utils.ts | 38 +-
apps/server/src/main.ts | 11 +-
pnpm-lock.yaml | 309 +++++----
66 files changed, 3331 insertions(+), 512 deletions(-)
create mode 100644 apps/client/src/components/theme-toggle.module.css
create mode 100644 apps/client/src/features/editor/readonly-page-editor.tsx
create mode 100644 apps/client/src/features/share/atoms/sidebar-atom.ts
create mode 100644 apps/client/src/features/share/components/share-action-menu.tsx
create mode 100644 apps/client/src/features/share/components/share-layout.tsx
create mode 100644 apps/client/src/features/share/components/share-list.tsx
create mode 100644 apps/client/src/features/share/components/share-modal.tsx
create mode 100644 apps/client/src/features/share/components/share-shell.tsx
create mode 100644 apps/client/src/features/share/components/share.module.css
create mode 100644 apps/client/src/features/share/components/shared-tree.tsx
create mode 100644 apps/client/src/features/share/hooks/use-toggle-toc.ts
create mode 100644 apps/client/src/features/share/queries/share-query.ts
create mode 100644 apps/client/src/features/share/services/share-service.ts
create mode 100644 apps/client/src/features/share/types/share.types.ts
create mode 100644 apps/client/src/features/share/utils.ts
create mode 100644 apps/client/src/pages/settings/shares/shares.tsx
create mode 100644 apps/client/src/pages/share/share-redirect.tsx
create mode 100644 apps/client/src/pages/share/shared-page.tsx
create mode 100644 apps/server/src/core/share/dto/share.dto.ts
create mode 100644 apps/server/src/core/share/share-seo.controller.ts
create mode 100644 apps/server/src/core/share/share.controller.ts
create mode 100644 apps/server/src/core/share/share.module.ts
create mode 100644 apps/server/src/core/share/share.service.ts
create mode 100644 apps/server/src/core/share/share.util.ts
create mode 100644 apps/server/src/database/migrations/20250408T191830-shares.ts
create mode 100644 apps/server/src/database/repos/share/share.repo.ts
diff --git a/apps/client/index.html b/apps/client/index.html
index 98e02c8b..c96058cb 100644
--- a/apps/client/index.html
+++ b/apps/client/index.html
@@ -6,6 +6,7 @@
Docmost
+
diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json
index bbc6a702..0746ed15 100644
--- a/apps/client/public/locales/en-US/translation.json
+++ b/apps/client/public/locales/en-US/translation.json
@@ -362,5 +362,26 @@
"Move page to a different space.": "Move page to a different space.",
"Real-time editor connection lost. Retrying...": "Real-time editor connection lost. Retrying...",
"Table of contents": "Table of contents",
- "Add headings (H1, H2, H3) to generate a table of contents.": "Add headings (H1, H2, H3) to generate a table of contents."
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Add headings (H1, H2, H3) to generate a table of contents.",
+ "Share": "Share",
+ "Public sharing": "Public sharing",
+ "Shared by": "Shared by",
+ "Shared at": "Shared at",
+ "Inherits public sharing from": "Inherits public sharing from",
+ "Share to web": "Share to web",
+ "Shared to web": "Shared to web",
+ "Anyone with the link can view this page": "Anyone with the link can view this page",
+ "Make this page publicly accessible": "Make this page publicly accessible",
+ "Include sub-pages": "Include sub-pages",
+ "Make sub-pages public too": "Make sub-pages public too",
+ "Allow search engines to index page": "Allow search engines to index page",
+ "Open page": "Open page",
+ "Page": "Page",
+ "Delete public share link": "Delete public share link",
+ "Delete share": "Delete share",
+ "Are you sure you want to delete this shared link?": "Are you sure you want to delete this shared link?",
+ "Publicly shared pages from spaces you are a member of will appear here": "Publicly shared pages from spaces you are a member of will appear here",
+ "Share deleted successfully": "Share deleted successfully",
+ "Share not found": "Share not found",
+ "Failed to share page": "Failed to share page"
}
diff --git a/apps/client/src/App.tsx b/apps/client/src/App.tsx
index c806f852..4399062f 100644
--- a/apps/client/src/App.tsx
+++ b/apps/client/src/App.tsx
@@ -26,6 +26,10 @@ import { useTranslation } from "react-i18next";
import Security from "@/ee/security/pages/security.tsx";
import License from "@/ee/licence/pages/license.tsx";
import { useRedirectToCloudSelect } from "@/ee/hooks/use-redirect-to-cloud-select.tsx";
+import SharedPage from "@/pages/share/shared-page.tsx";
+import Shares from "@/pages/settings/shares/shares.tsx";
+import ShareLayout from "@/features/share/components/share-layout.tsx";
+import ShareRedirect from '@/pages/share/share-redirect.tsx';
export default function App() {
const { t } = useTranslation();
@@ -51,6 +55,12 @@ export default function App() {
>
)}
+ }>
+ } />
+ } />
+
+
+ } />
} />
}>
@@ -78,6 +88,7 @@ export default function App() {
} />
} />
} />
+ } />
} />
{!isCloud() && } />}
{isCloud() && } />}
diff --git a/apps/client/src/components/layouts/global/global-app-shell.tsx b/apps/client/src/components/layouts/global/global-app-shell.tsx
index 4b5c0269..c8aff4cc 100644
--- a/apps/client/src/components/layouts/global/global-app-shell.tsx
+++ b/apps/client/src/components/layouts/global/global-app-shell.tsx
@@ -14,6 +14,8 @@ import { AppHeader } from "@/components/layouts/global/app-header.tsx";
import Aside from "@/components/layouts/global/aside.tsx";
import classes from "./app-shell.module.css";
import { useTrialEndAction } from "@/ee/hooks/use-trial-end-action.tsx";
+import { useClickOutside, useMergedRef } from "@mantine/hooks";
+import { useToggleSidebar } from "@/components/layouts/global/hooks/hooks/use-toggle-sidebar.ts";
export default function GlobalAppShell({
children,
@@ -22,11 +24,19 @@ export default function GlobalAppShell({
}) {
useTrialEndAction();
const [mobileOpened] = useAtom(mobileSidebarAtom);
+ const toggleMobile = useToggleSidebar(mobileSidebarAtom);
const [desktopOpened] = useAtom(desktopSidebarAtom);
const [{ isAsideOpen }] = useAtom(asideStateAtom);
const [sidebarWidth, setSidebarWidth] = useAtom(sidebarWidthAtom);
const [isResizing, setIsResizing] = useState(false);
const sidebarRef = useRef(null);
+ const navbarOutsideRef = useClickOutside(() => {
+ if (mobileOpened) {
+ toggleMobile();
+ }
+ });
+
+ const mergedRef = useMergedRef(sidebarRef, navbarOutsideRef);
const startResizing = React.useCallback((mouseDownEvent) => {
mouseDownEvent.preventDefault();
@@ -102,7 +112,7 @@ export default function GlobalAppShell({
{isSpaceRoute && }
@@ -111,7 +121,7 @@ export default function GlobalAppShell({
)}
{isSettingsRoute ? (
- {children}
+ {children}
) : (
children
)}
diff --git a/apps/client/src/components/settings/settings-queries.tsx b/apps/client/src/components/settings/settings-queries.tsx
index f4cddfaa..2f3b46bd 100644
--- a/apps/client/src/components/settings/settings-queries.tsx
+++ b/apps/client/src/components/settings/settings-queries.tsx
@@ -8,7 +8,8 @@ import { getGroups } from "@/features/group/services/group-service.ts";
import { QueryParams } from "@/lib/types.ts";
import { getWorkspaceMembers } from "@/features/workspace/services/workspace-service.ts";
import { getLicenseInfo } from "@/ee/licence/services/license-service.ts";
-import { getSsoProviders } from '@/ee/security/services/security-service.ts';
+import { getSsoProviders } from "@/ee/security/services/security-service.ts";
+import { getShares } from "@/features/share/services/share-service.ts";
export const prefetchWorkspaceMembers = () => {
const params = { limit: 100, page: 1, query: "" } as QueryParams;
@@ -56,4 +57,11 @@ export const prefetchSsoProviders = () => {
queryKey: ["sso-providers"],
queryFn: () => getSsoProviders(),
});
-};
\ No newline at end of file
+};
+
+export const prefetchShares = () => {
+ queryClient.prefetchQuery({
+ queryKey: ["share-list", { page: 1 }],
+ queryFn: () => getShares({ page: 1, limit: 100 }),
+ });
+};
diff --git a/apps/client/src/components/settings/settings-sidebar.tsx b/apps/client/src/components/settings/settings-sidebar.tsx
index 16d94c64..483c0026 100644
--- a/apps/client/src/components/settings/settings-sidebar.tsx
+++ b/apps/client/src/components/settings/settings-sidebar.tsx
@@ -11,6 +11,7 @@ import {
IconCoin,
IconLock,
IconKey,
+ IconWorld,
} from "@tabler/icons-react";
import { Link, useLocation, useNavigate } from "react-router-dom";
import classes from "./settings.module.css";
@@ -23,11 +24,14 @@ import {
prefetchBilling,
prefetchGroups,
prefetchLicense,
+ prefetchShares,
prefetchSpaces,
prefetchSsoProviders,
prefetchWorkspaceMembers,
} from "@/components/settings/settings-queries.tsx";
import AppVersion from "@/components/settings/app-version.tsx";
+import { mobileSidebarAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
+import { useToggleSidebar } from "@/components/layouts/global/hooks/hooks/use-toggle-sidebar.ts";
interface DataItem {
label: string;
@@ -82,6 +86,7 @@ const groupedData: DataGroup[] = [
},
{ label: "Groups", icon: IconUsersGroup, path: "/settings/groups" },
{ label: "Spaces", icon: IconSpaces, path: "/settings/spaces" },
+ { label: "Public sharing", icon: IconWorld, path: "/settings/sharing" },
],
},
{
@@ -103,6 +108,8 @@ export default function SettingsSidebar() {
const navigate = useNavigate();
const { isAdmin } = useUserRole();
const [workspace] = useAtom(workspaceAtom);
+ const [mobileSidebarOpened] = useAtom(mobileSidebarAtom);
+ const toggleMobileSidebar = useToggleSidebar(mobileSidebarAtom);
useEffect(() => {
setActive(location.pathname);
@@ -170,6 +177,9 @@ export default function SettingsSidebar() {
case "Security & SSO":
prefetchHandler = prefetchSsoProviders;
break;
+ case "Public sharing":
+ prefetchHandler = prefetchShares;
+ break;
default:
break;
}
@@ -181,6 +191,11 @@ export default function SettingsSidebar() {
data-active={active.startsWith(item.path) || undefined}
key={item.label}
to={item.path}
+ onClick={() => {
+ if (mobileSidebarOpened) {
+ toggleMobileSidebar();
+ }
+ }}
>
{t(item.label)}
diff --git a/apps/client/src/components/theme-toggle.module.css b/apps/client/src/components/theme-toggle.module.css
new file mode 100644
index 00000000..936c5983
--- /dev/null
+++ b/apps/client/src/components/theme-toggle.module.css
@@ -0,0 +1,19 @@
+.dark {
+ @mixin dark {
+ display: none;
+ }
+
+ @mixin light {
+ display: block;
+ }
+}
+
+.light {
+ @mixin light {
+ display: none;
+ }
+
+ @mixin dark {
+ display: block;
+ }
+}
diff --git a/apps/client/src/components/theme-toggle.tsx b/apps/client/src/components/theme-toggle.tsx
index a988db6f..bf9245a2 100644
--- a/apps/client/src/components/theme-toggle.tsx
+++ b/apps/client/src/components/theme-toggle.tsx
@@ -1,13 +1,28 @@
-import { Button, Group, useMantineColorScheme } from '@mantine/core';
+import {
+ ActionIcon,
+ Tooltip,
+ useComputedColorScheme,
+ useMantineColorScheme,
+} from "@mantine/core";
+import { IconMoon, IconSun } from "@tabler/icons-react";
+import classes from "./theme-toggle.module.css";
export function ThemeToggle() {
- const { setColorScheme } = useMantineColorScheme();
+ const { setColorScheme } = useMantineColorScheme();
+ const computedColorScheme = useComputedColorScheme();
- return (
-
- setColorScheme('light')}>Light
- setColorScheme('dark')}>Dark
- setColorScheme('auto')}>Auto
-
- );
+ return (
+
+ {
+ setColorScheme(computedColorScheme === "light" ? "dark" : "light");
+ }}
+ aria-label="Toggle color scheme"
+ >
+
+
+
+
+ );
}
diff --git a/apps/client/src/features/editor/atoms/editor-atoms.ts b/apps/client/src/features/editor/atoms/editor-atoms.ts
index 6f54c057..d4f133f7 100644
--- a/apps/client/src/features/editor/atoms/editor-atoms.ts
+++ b/apps/client/src/features/editor/atoms/editor-atoms.ts
@@ -5,4 +5,6 @@ export const pageEditorAtom = atom(null);
export const titleEditorAtom = atom(null);
+export const readOnlyEditorAtom = atom(null);
+
export const yjsConnectionStatusAtom = atom("");
diff --git a/apps/client/src/features/editor/components/drawio/drawio-view.tsx b/apps/client/src/features/editor/components/drawio/drawio-view.tsx
index 16e6dc97..468e26a0 100644
--- a/apps/client/src/features/editor/components/drawio/drawio-view.tsx
+++ b/apps/client/src/features/editor/components/drawio/drawio-view.tsx
@@ -139,7 +139,7 @@ export default function DrawioView(props: NodeViewProps) {
)}
/>
- {selected && (
+ {selected && editor.isEditable && (
- {selected && (
+ {selected && editor.isEditable && (
{entityType === "user" && (
@@ -28,7 +41,9 @@ export default function MentionView(props: NodeViewProps) {
diff --git a/apps/client/src/features/editor/components/table-of-contents/table-of-contents.module.css b/apps/client/src/features/editor/components/table-of-contents/table-of-contents.module.css
index 9554a84d..739cc0d1 100644
--- a/apps/client/src/features/editor/components/table-of-contents/table-of-contents.module.css
+++ b/apps/client/src/features/editor/components/table-of-contents/table-of-contents.module.css
@@ -52,3 +52,8 @@
) !important;
}
}
+
+
+.leftBorder {
+ border-left: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
+}
diff --git a/apps/client/src/features/editor/components/table-of-contents/table-of-contents.tsx b/apps/client/src/features/editor/components/table-of-contents/table-of-contents.tsx
index 6945a29b..b309d67d 100644
--- a/apps/client/src/features/editor/components/table-of-contents/table-of-contents.tsx
+++ b/apps/client/src/features/editor/components/table-of-contents/table-of-contents.tsx
@@ -8,6 +8,7 @@ import { useTranslation } from "react-i18next";
type TableOfContentsProps = {
editor: ReturnType;
+ isShare?: boolean;
};
export type HeadingLink = {
@@ -73,6 +74,7 @@ export const TableOfContents: FC = (props) => {
const handleUpdate = () => {
const result = recalculateLinks(props.editor?.$nodes("heading"));
+
setLinks(result.links);
setHeadingDOMNodes(result.nodes);
};
@@ -85,9 +87,12 @@ export const TableOfContents: FC = (props) => {
};
}, [props.editor]);
- useEffect(() => {
- handleUpdate();
- }, []);
+ useEffect(
+ () => {
+ handleUpdate();
+ },
+ props.isShare ? [props.editor] : [],
+ );
useEffect(() => {
try {
@@ -133,16 +138,23 @@ export const TableOfContents: FC = (props) => {
if (!links.length) {
return (
<>
-
- {t("Add headings (H1, H2, H3) to generate a table of contents.")}
-
+ {!props.isShare && (
+
+ {t("Add headings (H1, H2, H3) to generate a table of contents.")}
+
+ )}
>
);
}
return (
<>
-
+ {props.isShare && (
+
+ {t("Table of contents")}
+
+ )}
+
{links.map((item, idx) => (
component="button"
diff --git a/apps/client/src/features/editor/readonly-page-editor.tsx b/apps/client/src/features/editor/readonly-page-editor.tsx
new file mode 100644
index 00000000..bd6b9f6b
--- /dev/null
+++ b/apps/client/src/features/editor/readonly-page-editor.tsx
@@ -0,0 +1,67 @@
+import "@/features/editor/styles/index.css";
+import React, { useMemo } from "react";
+import { EditorProvider } from "@tiptap/react";
+import { mainExtensions } from "@/features/editor/extensions/extensions";
+import { Document } from "@tiptap/extension-document";
+import { Heading } from "@tiptap/extension-heading";
+import { Text } from "@tiptap/extension-text";
+import { Placeholder } from "@tiptap/extension-placeholder";
+import { useAtom } from "jotai/index";
+import {
+ pageEditorAtom,
+ readOnlyEditorAtom,
+} from "@/features/editor/atoms/editor-atoms.ts";
+import { Editor } from "@tiptap/core";
+
+interface PageEditorProps {
+ title: string;
+ content: any;
+}
+
+export default function ReadonlyPageEditor({
+ title,
+ content,
+}: PageEditorProps) {
+ const [, setReadOnlyEditor] = useAtom(readOnlyEditorAtom);
+
+ const extensions = useMemo(() => {
+ return [...mainExtensions];
+ }, []);
+
+ const titleExtensions = [
+ Document.extend({
+ content: "heading",
+ }),
+ Heading,
+ Text,
+ Placeholder.configure({
+ placeholder: "Untitled",
+ showOnlyWhenEditable: false,
+ }),
+ ];
+
+ return (
+ <>
+
+
+ {
+ if (editor) {
+ // @ts-ignore
+ setReadOnlyEditor(editor);
+ }
+ }}
+ >
+
+ >
+ );
+}
diff --git a/apps/client/src/features/page/components/breadcrumbs/breadcrumb.module.css b/apps/client/src/features/page/components/breadcrumbs/breadcrumb.module.css
index cf3637b2..cebee031 100644
--- a/apps/client/src/features/page/components/breadcrumbs/breadcrumb.module.css
+++ b/apps/client/src/features/page/components/breadcrumbs/breadcrumb.module.css
@@ -2,6 +2,7 @@
display: flex;
align-items: center;
overflow: hidden;
+ flex-wrap: nowrap;
a {
color: var(--mantine-color-default-color);
diff --git a/apps/client/src/features/page/components/breadcrumbs/breadcrumb.tsx b/apps/client/src/features/page/components/breadcrumbs/breadcrumb.tsx
index 367b2682..9d78f38c 100644
--- a/apps/client/src/features/page/components/breadcrumbs/breadcrumb.tsx
+++ b/apps/client/src/features/page/components/breadcrumbs/breadcrumb.tsx
@@ -1,6 +1,6 @@
import { useAtomValue } from "jotai";
import { treeDataAtom } from "@/features/page/tree/atoms/tree-data-atom.ts";
-import React, { useEffect, useState } from "react";
+import React, { useCallback, useEffect, useState } from "react";
import { findBreadcrumbPath } from "@/features/page/tree/utils";
import {
Button,
@@ -9,14 +9,16 @@ import {
Breadcrumbs,
ActionIcon,
Text,
+ Tooltip,
} from "@mantine/core";
-import { IconDots } from "@tabler/icons-react";
+import { IconCornerDownRightDouble, IconDots } from "@tabler/icons-react";
import { Link, useParams } from "react-router-dom";
import classes from "./breadcrumb.module.css";
import { SpaceTreeNode } from "@/features/page/tree/types.ts";
import { buildPageUrl } from "@/features/page/page.utils.ts";
import { usePageQuery } from "@/features/page/queries/page-query.ts";
import { extractPageSlugId } from "@/lib";
+import { useMediaQuery } from "@mantine/hooks";
function getTitle(name: string, icon: string) {
if (icon) {
@@ -34,6 +36,7 @@ export default function Breadcrumb() {
const { data: currentPage } = usePageQuery({
pageId: extractPageSlugId(pageSlug),
});
+ const isMobile = useMediaQuery("(max-width: 48em)");
useEffect(() => {
if (treeData?.length > 0 && currentPage) {
@@ -43,7 +46,7 @@ export default function Breadcrumb() {
}, [currentPage?.id, treeData]);
const HiddenNodesTooltipContent = () =>
- breadcrumbNodes?.slice(1, -2).map((node) => (
+ breadcrumbNodes?.slice(1, -1).map((node) => (
));
- const renderAnchor = (node: SpaceTreeNode) => (
-
- {getTitle(node.name, node.icon)}
-
+ const MobileHiddenNodesTooltipContent = () =>
+ breadcrumbNodes?.map((node) => (
+
+
+
+ {getTitle(node.name, node.icon)}
+
+
+
+ ));
+
+ const renderAnchor = useCallback(
+ (node: SpaceTreeNode) => (
+
+
+ {getTitle(node.name, node.icon)}
+
+
+ ),
+ [spaceSlug],
);
const getBreadcrumbItems = () => {
@@ -77,7 +102,7 @@ export default function Breadcrumb() {
if (breadcrumbNodes.length > 3) {
const firstNode = breadcrumbNodes[0];
- const secondLastNode = breadcrumbNodes[breadcrumbNodes.length - 2];
+ //const secondLastNode = breadcrumbNodes[breadcrumbNodes.length - 2];
const lastNode = breadcrumbNodes[breadcrumbNodes.length - 1];
return [
@@ -98,7 +123,7 @@ export default function Breadcrumb() {
,
- renderAnchor(secondLastNode),
+ //renderAnchor(secondLastNode),
renderAnchor(lastNode),
];
}
@@ -106,11 +131,40 @@ export default function Breadcrumb() {
return breadcrumbNodes.map(renderAnchor);
};
+ const getMobileBreadcrumbItems = () => {
+ if (!breadcrumbNodes) return [];
+
+ if (breadcrumbNodes.length > 0) {
+ return [
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ ];
+ }
+
+ return breadcrumbNodes.map(renderAnchor);
+ };
+
return (
{breadcrumbNodes && (
- {getBreadcrumbItems()}
+ {isMobile ? getMobileBreadcrumbItems() : getBreadcrumbItems()}
)}
diff --git a/apps/client/src/features/page/components/header/page-header-menu.tsx b/apps/client/src/features/page/components/header/page-header-menu.tsx
index 93d10520..9267ad9e 100644
--- a/apps/client/src/features/page/components/header/page-header-menu.tsx
+++ b/apps/client/src/features/page/components/header/page-header-menu.tsx
@@ -35,6 +35,7 @@ import {
import { formattedDate, timeAgo } from "@/lib/time.ts";
import MovePageModal from "@/features/page/components/move-page-modal.tsx";
import { useTimeAgo } from "@/hooks/use-time-ago.tsx";
+import ShareModal from '@/features/share/components/share-modal.tsx';
interface PageHeaderMenuProps {
readOnly?: boolean;
@@ -58,6 +59,8 @@ export default function PageHeaderMenu({ readOnly }: PageHeaderMenuProps) {
)}
+
+
{
],
});
- return `p/${titleSlug}-${pageSlugId}`;
+ return `${titleSlug}-${pageSlugId}`;
};
export const buildPageUrl = (
@@ -17,7 +17,20 @@ export const buildPageUrl = (
pageTitle?: string,
): string => {
if (spaceName === undefined) {
- return `/${buildPageSlug(pageSlugId, pageTitle)}`;
+ return `/p/${buildPageSlug(pageSlugId, pageTitle)}`;
}
- return `/s/${spaceName}/${buildPageSlug(pageSlugId, pageTitle)}`;
+ return `/s/${spaceName}/p/${buildPageSlug(pageSlugId, pageTitle)}`;
+};
+
+export const buildSharedPageUrl = (opts: {
+ shareId: string;
+ pageSlugId: string;
+ pageTitle?: string;
+}): string => {
+ const { shareId, pageSlugId, pageTitle } = opts;
+ if (!shareId) {
+ return `/share/p/${buildPageSlug(pageSlugId, pageTitle)}`;
+ }
+
+ return `/share/${shareId}/p/${buildPageSlug(pageSlugId, pageTitle)}`;
};
diff --git a/apps/client/src/features/page/tree/components/space-tree.tsx b/apps/client/src/features/page/tree/components/space-tree.tsx
index 7b2f2f7d..5a00f258 100644
--- a/apps/client/src/features/page/tree/components/space-tree.tsx
+++ b/apps/client/src/features/page/tree/components/space-tree.tsx
@@ -8,9 +8,9 @@ import {
useUpdatePageMutation,
} from "@/features/page/queries/page-query.ts";
import { useEffect, useRef, useState } from "react";
-import { useNavigate, useParams } from "react-router-dom";
+import { Link, useParams } from "react-router-dom";
import classes from "@/features/page/tree/styles/tree.module.css";
-import { ActionIcon, Menu, rem } from "@mantine/core";
+import { ActionIcon, Box, Menu, rem } from "@mantine/core";
import {
IconArrowRight,
IconChevronDown,
@@ -58,6 +58,8 @@ import { useDeletePageModal } from "@/features/page/hooks/use-delete-page-modal.
import { useTranslation } from "react-i18next";
import ExportModal from "@/components/common/export-modal";
import MovePageModal from "../../components/move-page-modal.tsx";
+import { mobileSidebarAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
+import { useToggleSidebar } from "@/components/layouts/global/hooks/hooks/use-toggle-sidebar.ts";
interface SpaceTreeProps {
spaceId: string;
@@ -230,13 +232,14 @@ export default function SpaceTree({ spaceId, readOnly }: SpaceTreeProps) {
}
function Node({ node, style, dragHandle, tree }: NodeRendererProps) {
- const navigate = useNavigate();
+ const { t } = useTranslation();
const updatePageMutation = useUpdatePageMutation();
const [treeData, setTreeData] = useAtom(treeDataAtom);
const emit = useQueryEmit();
const { spaceSlug } = useParams();
const timerRef = useRef(null);
- const { t } = useTranslation();
+ const [mobileSidebarOpened] = useAtom(mobileSidebarAtom);
+ const toggleMobileSidebar = useToggleSidebar(mobileSidebarAtom);
const prefetchPage = () => {
timerRef.current = setTimeout(() => {
@@ -287,11 +290,6 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps) {
}
}
- const handleClick = () => {
- const pageUrl = buildPageUrl(spaceSlug, node.data.slugId, node.data.name);
- navigate(pageUrl);
- };
-
const handleUpdateNodeIcon = (nodeId: string, newIcon: string) => {
const updatedTree = updateTreeNodeIcon(treeData, nodeId, newIcon);
setTreeData(updatedTree);
@@ -345,13 +343,22 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps) {
}, 650);
}
+ const pageUrl = buildPageUrl(spaceSlug, node.data.slugId, node.data.name);
+
return (
<>
- {
+ if (mobileSidebarOpened) {
+ toggleMobileSidebar();
+ }
+ }}
onMouseEnter={prefetchPage}
onMouseLeave={cancelPagePrefetch}
>
@@ -385,7 +392,7 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps
) {
/>
)}
-
+
>
);
}
diff --git a/apps/client/src/features/page/tree/styles/tree.module.css b/apps/client/src/features/page/tree/styles/tree.module.css
index 0a258fb5..716101e0 100644
--- a/apps/client/src/features/page/tree/styles/tree.module.css
+++ b/apps/client/src/features/page/tree/styles/tree.module.css
@@ -18,7 +18,7 @@
align-items: center;
height: 100%;
width: 93%; /* not to overlap with scroll bar */
-
+ text-decoration: none;
color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-0));
&:hover {
@@ -70,6 +70,10 @@
background-color: light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-5));
}
+.row:focus .node:global(.isFocused) {
+ background-color: light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-5));
+}
+
.row {
white-space: nowrap;
cursor: pointer;
diff --git a/apps/client/src/features/page/tree/utils/utils.ts b/apps/client/src/features/page/tree/utils/utils.ts
index 0dfe8ed4..7ae84e38 100644
--- a/apps/client/src/features/page/tree/utils/utils.ts
+++ b/apps/client/src/features/page/tree/utils/utils.ts
@@ -1,7 +1,7 @@
import { IPage } from "@/features/page/types/page.types.ts";
import { SpaceTreeNode } from "@/features/page/tree/types.ts";
-function sortPositionKeys(keys: any[]) {
+export function sortPositionKeys(keys: any[]) {
return keys.sort((a, b) => {
if (a.position < b.position) return -1;
if (a.position > b.position) return 1;
diff --git a/apps/client/src/features/share/atoms/sidebar-atom.ts b/apps/client/src/features/share/atoms/sidebar-atom.ts
new file mode 100644
index 00000000..0bc9d681
--- /dev/null
+++ b/apps/client/src/features/share/atoms/sidebar-atom.ts
@@ -0,0 +1,9 @@
+import { atomWithWebStorage } from "@/lib/jotai-helper.ts";
+import { atom } from 'jotai';
+
+export const tableOfContentAsideAtom = atomWithWebStorage
(
+ "showTOC",
+ true,
+);
+
+export const mobileTableOfContentAsideAtom = atom(false);
\ No newline at end of file
diff --git a/apps/client/src/features/share/components/share-action-menu.tsx b/apps/client/src/features/share/components/share-action-menu.tsx
new file mode 100644
index 00000000..398e25e9
--- /dev/null
+++ b/apps/client/src/features/share/components/share-action-menu.tsx
@@ -0,0 +1,106 @@
+import { Menu, ActionIcon, Text } from "@mantine/core";
+import React from "react";
+import {
+ IconCopy,
+ IconDots,
+ IconFileDescription,
+ IconTrash,
+} from "@tabler/icons-react";
+import { modals } from "@mantine/modals";
+import { useTranslation } from "react-i18next";
+import { ISharedItem } from "@/features/share/types/share.types.ts";
+import {
+ buildPageUrl,
+ buildSharedPageUrl,
+} from "@/features/page/page.utils.ts";
+import { useClipboard } from "@mantine/hooks";
+import { notifications } from "@mantine/notifications";
+import { useNavigate } from "react-router-dom";
+import { useDeleteShareMutation } from "@/features/share/queries/share-query.ts";
+
+interface Props {
+ share: ISharedItem;
+}
+export default function ShareActionMenu({ share }: Props) {
+ const { t } = useTranslation();
+ const navigate = useNavigate();
+ const clipboard = useClipboard();
+ const deleteShareMutation = useDeleteShareMutation();
+
+ const openPage = () => {
+ const pageLink = buildPageUrl(
+ share.space.slug,
+ share.page.slugId,
+ share.page.title,
+ );
+ navigate(pageLink);
+ };
+
+ const copyLink = () => {
+ const shareLink = buildSharedPageUrl({
+ shareId: share.key,
+ pageTitle: share.page.title,
+ pageSlugId: share.page.slugId,
+ });
+
+ clipboard.copy(shareLink);
+ notifications.show({ message: t("Link copied") });
+ };
+ const onDelete = async () => {
+ deleteShareMutation.mutateAsync(share.key);
+ };
+
+ const openDeleteModal = () =>
+ modals.openConfirmModal({
+ title: t("Delete public share link"),
+ children: (
+
+ {t("Are you sure you want to delete this shared link?")}
+
+ ),
+ centered: true,
+ labels: { confirm: t("Delete"), cancel: t("Don't") },
+ confirmProps: { color: "red" },
+ onConfirm: onDelete,
+ });
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+ }>
+ {t("Copy link")}
+
+
+ }
+ >
+ {t("Open page")}
+
+ }
+ disabled={share.space?.userRole === "reader"}
+ >
+ {t("Delete share")}
+
+
+
+ >
+ );
+}
diff --git a/apps/client/src/features/share/components/share-layout.tsx b/apps/client/src/features/share/components/share-layout.tsx
new file mode 100644
index 00000000..e3b2eb17
--- /dev/null
+++ b/apps/client/src/features/share/components/share-layout.tsx
@@ -0,0 +1,10 @@
+import { Outlet } from "react-router-dom";
+import ShareShell from "@/features/share/components/share-shell.tsx";
+
+export default function ShareLayout() {
+ return (
+
+
+
+ );
+}
diff --git a/apps/client/src/features/share/components/share-list.tsx b/apps/client/src/features/share/components/share-list.tsx
new file mode 100644
index 00000000..d5acbbd6
--- /dev/null
+++ b/apps/client/src/features/share/components/share-list.tsx
@@ -0,0 +1,97 @@
+import { Table, Group, Text, Anchor } from "@mantine/core";
+import React, { useState } from "react";
+import { Link } from "react-router-dom";
+import { useTranslation } from "react-i18next";
+import Paginate from "@/components/common/paginate.tsx";
+import { useGetSharesQuery } from "@/features/share/queries/share-query.ts";
+import { ISharedItem } from "@/features/share/types/share.types.ts";
+import { format } from "date-fns";
+import ShareActionMenu from "@/features/share/components/share-action-menu.tsx";
+import { buildSharedPageUrl } from "@/features/page/page.utils.ts";
+import { getPageIcon } from "@/lib";
+import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
+import classes from "./share.module.css";
+
+export default function ShareList() {
+ const { t } = useTranslation();
+ const [page, setPage] = useState(1);
+ const { data, isLoading } = useGetSharesQuery({ page });
+
+ return (
+ <>
+
+
+
+
+ {t("Page")}
+ {t("Shared by")}
+ {t("Shared at")}
+
+
+
+
+ {data?.items.map((share: ISharedItem, index: number) => (
+
+
+
+
+ {getPageIcon(share.page.icon)}
+
+
+ {share.page.title || t("untitled")}
+
+
+
+
+
+
+
+
+
+ {share.creator.name}
+
+
+
+
+
+ {format(new Date(share.createdAt), "MMM dd, yyyy")}
+
+
+
+
+
+
+ ))}
+
+
+
+
+ {data?.items.length > 0 && (
+
+ )}
+ >
+ );
+}
diff --git a/apps/client/src/features/share/components/share-modal.tsx b/apps/client/src/features/share/components/share-modal.tsx
new file mode 100644
index 00000000..20dcc518
--- /dev/null
+++ b/apps/client/src/features/share/components/share-modal.tsx
@@ -0,0 +1,227 @@
+import {
+ ActionIcon,
+ Anchor,
+ Button,
+ Group,
+ Indicator,
+ Popover,
+ Switch,
+ Text,
+ TextInput,
+ Tooltip,
+} from "@mantine/core";
+import { IconExternalLink, IconWorld } from "@tabler/icons-react";
+import React, { useEffect, useMemo, useState } from "react";
+import {
+ useCreateShareMutation,
+ useDeleteShareMutation,
+ useShareForPageQuery,
+ useUpdateShareMutation,
+} from "@/features/share/queries/share-query.ts";
+import { Link, useParams } from "react-router-dom";
+import { extractPageSlugId, getPageIcon } from "@/lib";
+import { useTranslation } from "react-i18next";
+import CopyTextButton from "@/components/common/copy.tsx";
+import { getAppUrl } from "@/lib/config.ts";
+import { buildPageUrl } from "@/features/page/page.utils.ts";
+import classes from "@/features/share/components/share.module.css";
+
+interface ShareModalProps {
+ readOnly: boolean;
+}
+export default function ShareModal({ readOnly }: ShareModalProps) {
+ const { t } = useTranslation();
+ const { pageSlug } = useParams();
+ const pageId = extractPageSlugId(pageSlug);
+ const { data: share } = useShareForPageQuery(pageId);
+ const { spaceSlug } = useParams();
+ const createShareMutation = useCreateShareMutation();
+ const updateShareMutation = useUpdateShareMutation();
+ const deleteShareMutation = useDeleteShareMutation();
+ // pageIsShared means that the share exists and its level equals zero.
+ const pageIsShared = share && share.level === 0;
+ // if level is greater than zero, then it is a descendant page from a shared page
+ const isDescendantShared = share && share.level > 0;
+
+ const publicLink = `${getAppUrl()}/share/${share?.key}/p/${pageSlug}`;
+
+ const [isPagePublic, setIsPagePublic] = useState(false);
+ useEffect(() => {
+ if (share) {
+ setIsPagePublic(true);
+ } else {
+ setIsPagePublic(false);
+ }
+ }, [share, pageId]);
+
+ const handleChange = async (event: React.ChangeEvent) => {
+ const value = event.currentTarget.checked;
+
+ if (value) {
+ createShareMutation.mutateAsync({
+ pageId: pageId,
+ includeSubPages: true,
+ searchIndexing: true,
+ });
+ setIsPagePublic(value);
+ } else {
+ if (share && share.id) {
+ deleteShareMutation.mutateAsync(share.id);
+ setIsPagePublic(value);
+ }
+ }
+ };
+
+ const handleSubPagesChange = async (
+ event: React.ChangeEvent,
+ ) => {
+ const value = event.currentTarget.checked;
+ updateShareMutation.mutateAsync({
+ shareId: share.id,
+ includeSubPages: value,
+ });
+ };
+
+ const handleIndexSearchChange = async (
+ event: React.ChangeEvent,
+ ) => {
+ const value = event.currentTarget.checked;
+ updateShareMutation.mutateAsync({
+ shareId: share.id,
+ searchIndexing: value,
+ });
+ };
+
+ const shareLink = useMemo(() => (
+
+ }
+ style={{ width: "100%" }}
+ />
+
+
+
+
+ ), [publicLink]);
+
+ return (
+
+
+
+
+
+ }
+ variant="default"
+ >
+ {t("Share")}
+
+
+
+ {isDescendantShared ? (
+ <>
+ {t("Inherits public sharing from")}
+
+
+ {getPageIcon(share.sharedPage.icon)}
+
+
+ {share.sharedPage.title || t("untitled")}
+
+
+
+
+
+ {shareLink}
+ >
+ ) : (
+ <>
+
+
+
+ {isPagePublic ? t("Shared to web") : t("Share to web")}
+
+
+ {isPagePublic
+ ? t("Anyone with the link can view this page")
+ : t("Make this page publicly accessible")}
+
+
+
+
+
+ {pageIsShared && (
+ <>
+ {shareLink}
+
+
+ {t("Include sub-pages")}
+
+ {t("Make sub-pages public too")}
+
+
+
+
+
+
+
+ {t("Search engine indexing")}
+
+ {t("Allow search engines to index page")}
+
+
+
+
+ >
+ )}
+ >
+ )}
+
+
+ );
+}
diff --git a/apps/client/src/features/share/components/share-shell.tsx b/apps/client/src/features/share/components/share-shell.tsx
new file mode 100644
index 00000000..82863b34
--- /dev/null
+++ b/apps/client/src/features/share/components/share-shell.tsx
@@ -0,0 +1,196 @@
+import React, { useState } from "react";
+import {
+ ActionIcon,
+ Affix,
+ AppShell,
+ Button,
+ Group,
+ ScrollArea,
+ Tooltip,
+} from "@mantine/core";
+import { useGetSharedPageTreeQuery } from "@/features/share/queries/share-query.ts";
+import { useParams } from "react-router-dom";
+import SharedTree from "@/features/share/components/shared-tree.tsx";
+import { TableOfContents } from "@/features/editor/components/table-of-contents/table-of-contents.tsx";
+import { readOnlyEditorAtom } from "@/features/editor/atoms/editor-atoms.ts";
+import { ThemeToggle } from "@/components/theme-toggle.tsx";
+import { useAtomValue } from "jotai";
+import { useAtom } from "jotai";
+import {
+ desktopSidebarAtom,
+ mobileSidebarAtom,
+} from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
+import SidebarToggle from "@/components/ui/sidebar-toggle-button.tsx";
+import { useTranslation } from "react-i18next";
+import { useToggleSidebar } from "@/components/layouts/global/hooks/hooks/use-toggle-sidebar.ts";
+import {
+ mobileTableOfContentAsideAtom,
+ tableOfContentAsideAtom,
+} from "@/features/share/atoms/sidebar-atom.ts";
+import { IconList } from "@tabler/icons-react";
+import { useToggleToc } from "@/features/share/hooks/use-toggle-toc.ts";
+import classes from "./share.module.css";
+import { useClickOutside } from "@mantine/hooks";
+
+const MemoizedSharedTree = React.memo(SharedTree);
+
+export default function ShareShell({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ const { t } = useTranslation();
+ const [mobileOpened] = useAtom(mobileSidebarAtom);
+ const [desktopOpened] = useAtom(desktopSidebarAtom);
+ const toggleMobile = useToggleSidebar(mobileSidebarAtom);
+ const toggleDesktop = useToggleSidebar(desktopSidebarAtom);
+
+ const [tocOpened] = useAtom(tableOfContentAsideAtom);
+ const [mobileTocOpened] = useAtom(mobileTableOfContentAsideAtom);
+ const toggleTocMobile = useToggleToc(mobileTableOfContentAsideAtom);
+ const toggleToc = useToggleToc(tableOfContentAsideAtom);
+
+ const { shareId } = useParams();
+ const { data } = useGetSharedPageTreeQuery(shareId);
+ const readOnlyEditor = useAtomValue(readOnlyEditorAtom);
+
+ const [navbarOutside, setNavbarOutside] = useState(null);
+ const [asideOutside, setAsideOutside] = useState(null);
+
+ useClickOutside(
+ () => {
+ if (mobileOpened) {
+ toggleMobile();
+ }
+ if (mobileTocOpened) {
+ toggleTocMobile();
+ }
+ },
+ null,
+ [navbarOutside, asideOutside],
+ );
+
+ return (
+ 1 && {
+ navbar: {
+ width: 300,
+ breakpoint: "sm",
+ collapsed: {
+ mobile: !mobileOpened,
+ desktop: !desktopOpened,
+ },
+ },
+ })}
+ aside={{
+ width: 300,
+ breakpoint: "sm",
+ collapsed: {
+ mobile: !mobileTocOpened,
+ desktop: !tocOpened,
+ },
+ }}
+ padding="md"
+ >
+
+
+
+ {data?.pageTree?.length > 1 && (
+ <>
+
+
+
+
+
+
+
+ >
+ )}
+
+
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ >
+
+
+
+
+
+
+ {data?.pageTree?.length > 1 && (
+
+
+
+ )}
+
+
+ {children}
+
+
+
+ Powered by Docmost
+
+
+
+
+
+
+
+ {readOnlyEditor && (
+
+ )}
+
+
+
+
+ );
+}
diff --git a/apps/client/src/features/share/components/share.module.css b/apps/client/src/features/share/components/share.module.css
new file mode 100644
index 00000000..617768ff
--- /dev/null
+++ b/apps/client/src/features/share/components/share.module.css
@@ -0,0 +1,20 @@
+.shareLinkText {
+ @mixin light {
+ border-bottom: 0.05em solid var(--mantine-color-dark-0);
+ }
+ @mixin dark {
+ border-bottom: 0.05em solid var(--mantine-color-dark-2);
+ }
+}
+
+.treeNode {
+ text-decoration: none;
+ user-select: none;
+}
+
+.navbar,
+.aside {
+ @media (max-width: $mantine-breakpoint-sm) {
+ width: 350px;
+ }
+}
diff --git a/apps/client/src/features/share/components/shared-tree.tsx b/apps/client/src/features/share/components/shared-tree.tsx
new file mode 100644
index 00000000..5e85ab57
--- /dev/null
+++ b/apps/client/src/features/share/components/shared-tree.tsx
@@ -0,0 +1,179 @@
+import { ISharedPageTree } from "@/features/share/types/share.types.ts";
+import { NodeApi, NodeRendererProps, Tree, TreeApi } from "react-arborist";
+import {
+ buildSharedPageTree,
+ SharedPageTreeNode,
+} from "@/features/share/utils.ts";
+import { useEffect, useMemo, useRef, useState } from "react";
+import { useElementSize, useMergedRef } from "@mantine/hooks";
+import { SpaceTreeNode } from "@/features/page/tree/types.ts";
+import { Link, useParams } from "react-router-dom";
+import { atom, useAtom } from "jotai/index";
+import { useTranslation } from "react-i18next";
+import { buildSharedPageUrl } from "@/features/page/page.utils.ts";
+import clsx from "clsx";
+import {
+ IconChevronDown,
+ IconChevronRight,
+ IconPointFilled,
+} from "@tabler/icons-react";
+import { ActionIcon, Box } from "@mantine/core";
+import { extractPageSlugId } from "@/lib";
+import { OpenMap } from "react-arborist/dist/main/state/open-slice";
+import classes from "@/features/page/tree/styles/tree.module.css";
+import styles from "./share.module.css";
+import { mobileSidebarAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
+
+interface SharedTree {
+ sharedPageTree: ISharedPageTree;
+}
+
+const openSharedTreeNodesAtom = atom({});
+
+export default function SharedTree({ sharedPageTree }: SharedTree) {
+ const [tree, setTree] = useState<
+ TreeApi | null | undefined
+ >(null);
+ const rootElement = useRef();
+ const { ref: sizeRef, width, height } = useElementSize();
+ const mergedRef = useMergedRef(rootElement, sizeRef);
+ const { pageSlug } = useParams();
+ const [openTreeNodes, setOpenTreeNodes] = useAtom(
+ openSharedTreeNodesAtom,
+ );
+
+ const currentNodeId = extractPageSlugId(pageSlug);
+
+ const treeData: SharedPageTreeNode[] = useMemo(() => {
+ if (!sharedPageTree?.pageTree) return;
+ return buildSharedPageTree(sharedPageTree.pageTree);
+ }, [sharedPageTree?.pageTree]);
+
+ useEffect(() => {
+ const parentNodeId = treeData?.[0]?.slugId;
+
+ if (parentNodeId && tree) {
+ const parentNode = tree.get(parentNodeId);
+
+ setTimeout(() => {
+ if (parentNode) {
+ tree.openSiblings(parentNode);
+ }
+ });
+
+ // open direct children of parent node
+ parentNode?.children.forEach((node) => {
+ tree.openSiblings(node);
+ });
+ }
+ }, [treeData, tree]);
+
+ useEffect(() => {
+ if (currentNodeId && tree) {
+ setTimeout(() => {
+ // focus on node and open all parents
+ tree?.select(currentNodeId, { align: "auto" });
+ }, 200);
+ } else {
+ tree?.deselectAll();
+ }
+ }, [currentNodeId, tree]);
+
+ if (!sharedPageTree || !sharedPageTree?.pageTree) {
+ return null;
+ }
+
+ return (
+
+ {rootElement.current && (
+ setTree(t)}
+ openByDefault={false}
+ disableMultiSelection={true}
+ className={classes.tree}
+ rowClassName={classes.row}
+ rowHeight={30}
+ overscanCount={10}
+ dndRootElement={rootElement.current}
+ onToggle={() => {
+ setOpenTreeNodes(tree?.openState);
+ }}
+ initialOpenState={openTreeNodes}
+ onClick={(e) => {
+ if (tree && tree.focusedNode) {
+ tree.select(tree.focusedNode);
+ }
+ }}
+ >
+ {Node}
+
+ )}
+
+ );
+}
+
+function Node({ node, style, tree }: NodeRendererProps) {
+ const { shareId } = useParams();
+ const { t } = useTranslation();
+ const [, setMobileSidebarState] = useAtom(mobileSidebarAtom);
+
+ const pageUrl = buildSharedPageUrl({
+ shareId: shareId,
+ pageSlugId: node.data.slugId,
+ pageTitle: node.data.name,
+ });
+
+ return (
+ <>
+ {
+ setMobileSidebarState(false);
+ }}
+ >
+
+ {node.data.name || t("untitled")}
+
+ >
+ );
+}
+
+interface PageArrowProps {
+ node: NodeApi;
+}
+
+function PageArrow({ node }: PageArrowProps) {
+ return (
+ {
+ e.preventDefault();
+ e.stopPropagation();
+ node.toggle();
+ }}
+ >
+ {node.isInternal ? (
+ node.children && (node.children.length > 0 || node.data.hasChildren) ? (
+ node.isOpen ? (
+
+ ) : (
+
+ )
+ ) : (
+
+ )
+ ) : null}
+
+ );
+}
diff --git a/apps/client/src/features/share/hooks/use-toggle-toc.ts b/apps/client/src/features/share/hooks/use-toggle-toc.ts
new file mode 100644
index 00000000..ec43086a
--- /dev/null
+++ b/apps/client/src/features/share/hooks/use-toggle-toc.ts
@@ -0,0 +1,8 @@
+import { useAtom } from "jotai";
+
+export function useToggleToc(tocAtom: any) {
+ const [tocState, setTocState] = useAtom(tocAtom);
+ return () => {
+ setTocState(!tocState);
+ }
+}
diff --git a/apps/client/src/features/share/queries/share-query.ts b/apps/client/src/features/share/queries/share-query.ts
new file mode 100644
index 00000000..dea047bf
--- /dev/null
+++ b/apps/client/src/features/share/queries/share-query.ts
@@ -0,0 +1,179 @@
+import {
+ keepPreviousData,
+ useMutation,
+ useQuery,
+ useQueryClient,
+ UseQueryResult,
+} from "@tanstack/react-query";
+import { notifications } from "@mantine/notifications";
+import { useTranslation } from "react-i18next";
+import {
+ ICreateShare,
+ IShare,
+ ISharedItem,
+ ISharedPage,
+ ISharedPageTree,
+ IShareForPage,
+ IShareInfoInput,
+ IUpdateShare,
+} from "@/features/share/types/share.types.ts";
+import {
+ createShare,
+ deleteShare,
+ getSharedPageTree,
+ getShareForPage,
+ getShareInfo,
+ getSharePageInfo,
+ getShares,
+ updateShare,
+} from "@/features/share/services/share-service.ts";
+import { IPage } from "@/features/page/types/page.types.ts";
+import { IPagination, QueryParams } from "@/lib/types.ts";
+import { useEffect } from "react";
+
+export function useGetSharesQuery(
+ params?: QueryParams,
+): UseQueryResult, Error> {
+ return useQuery({
+ queryKey: ["share-list"],
+ queryFn: () => getShares(params),
+ placeholderData: keepPreviousData,
+ });
+}
+
+export function useGetShareByIdQuery(
+ shareId: string,
+): UseQueryResult {
+ const query = useQuery({
+ queryKey: ["share-by-id", shareId],
+ queryFn: () => getShareInfo(shareId),
+ enabled: !!shareId,
+ });
+
+ return query;
+}
+
+export function useSharePageQuery(
+ shareInput: Partial,
+): UseQueryResult {
+ const query = useQuery({
+ queryKey: ["shares", shareInput],
+ queryFn: () => getSharePageInfo(shareInput),
+ enabled: !!shareInput.pageId,
+ });
+
+ return query;
+}
+
+export function useShareForPageQuery(
+ pageId: string,
+): UseQueryResult {
+ const query = useQuery({
+ queryKey: ["share-for-page", pageId],
+ queryFn: () => getShareForPage(pageId),
+ enabled: !!pageId,
+ staleTime: 0,
+ retry: false,
+ });
+
+ return query;
+}
+
+export function useCreateShareMutation() {
+ const { t } = useTranslation();
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: (data) => createShare(data),
+ onSuccess: (data) => {
+ queryClient.invalidateQueries({
+ predicate: (item) =>
+ ["share-for-page", "share-list"].includes(item.queryKey[0] as string),
+ });
+ },
+ onError: (error) => {
+ notifications.show({ message: t("Failed to share page"), color: "red" });
+ },
+ });
+}
+
+export function useUpdateShareMutation() {
+ const { t } = useTranslation();
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: (data) => updateShare(data),
+ onSuccess: (data) => {
+ queryClient.invalidateQueries({
+ predicate: (item) =>
+ ["share-for-page", "share-list"].includes(item.queryKey[0] as string),
+ });
+ },
+ onError: (error, params) => {
+ if (error?.["status"] === 404) {
+ queryClient.removeQueries({
+ predicate: (item) =>
+ ["share-for-page"].includes(item.queryKey[0] as string),
+ });
+
+ notifications.show({
+ message: t("Share not found"),
+ color: "red",
+ });
+ return;
+ }
+
+ notifications.show({
+ message: error?.["response"]?.data?.message || "Share not found",
+ color: "red",
+ });
+ },
+ });
+}
+
+export function useDeleteShareMutation() {
+ const { t } = useTranslation();
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: (shareId: string) => deleteShare(shareId),
+ onSuccess: (data) => {
+ queryClient.removeQueries({
+ predicate: (item) =>
+ ["share-for-page"].includes(item.queryKey[0] as string),
+ });
+
+ queryClient.invalidateQueries({
+ predicate: (item) =>
+ ["share-list"].includes(item.queryKey[0] as string),
+ });
+
+ notifications.show({ message: t("Share deleted successfully") });
+ },
+ onError: (error) => {
+ if (error?.["status"] === 404) {
+ queryClient.removeQueries({
+ predicate: (item) =>
+ ["share-for-page"].includes(item.queryKey[0] as string),
+ });
+ }
+
+ notifications.show({
+ message: error?.["response"]?.data?.message || "Failed to delete share",
+ color: "red",
+ });
+ },
+ });
+}
+
+export function useGetSharedPageTreeQuery(
+ shareId: string,
+): UseQueryResult {
+ return useQuery({
+ queryKey: ["shared-page-tree", shareId],
+ queryFn: () => getSharedPageTree(shareId),
+ enabled: !!shareId,
+ placeholderData: keepPreviousData,
+ staleTime: 60 * 60 * 1000,
+ });
+}
diff --git a/apps/client/src/features/share/services/share-service.ts b/apps/client/src/features/share/services/share-service.ts
new file mode 100644
index 00000000..2f43ba20
--- /dev/null
+++ b/apps/client/src/features/share/services/share-service.ts
@@ -0,0 +1,59 @@
+import api from "@/lib/api-client";
+import { IPage } from "@/features/page/types/page.types";
+
+import {
+ ICreateShare,
+ IShare,
+ ISharedItem,
+ ISharedPage,
+ ISharedPageTree,
+ IShareForPage,
+ IShareInfoInput,
+ IUpdateShare,
+} from "@/features/share/types/share.types.ts";
+import { IPagination, QueryParams } from "@/lib/types.ts";
+
+export async function getShares(
+ params?: QueryParams,
+): Promise> {
+ const req = await api.post("/shares", params);
+ return req.data;
+}
+
+export async function createShare(data: ICreateShare): Promise {
+ const req = await api.post("/shares/create", data);
+ return req.data;
+}
+
+export async function getShareInfo(shareId: string): Promise {
+ const req = await api.post("/shares/info", { shareId });
+ return req.data;
+}
+
+export async function updateShare(data: IUpdateShare): Promise {
+ const req = await api.post("/shares/update", data);
+ return req.data;
+}
+
+export async function getShareForPage(pageId: string): Promise {
+ const req = await api.post("/shares/for-page", { pageId });
+ return req.data;
+}
+
+export async function getSharePageInfo(
+ shareInput: Partial,
+): Promise {
+ const req = await api.post("/shares/page-info", shareInput);
+ return req.data;
+}
+
+export async function deleteShare(shareId: string): Promise {
+ await api.post("/shares/delete", { shareId });
+}
+
+export async function getSharedPageTree(
+ shareId: string,
+): Promise {
+ const req = await api.post("/shares/tree", { shareId });
+ return req.data;
+}
diff --git a/apps/client/src/features/share/types/share.types.ts b/apps/client/src/features/share/types/share.types.ts
new file mode 100644
index 00000000..c40801e8
--- /dev/null
+++ b/apps/client/src/features/share/types/share.types.ts
@@ -0,0 +1,73 @@
+import { IPage } from "@/features/page/types/page.types.ts";
+
+export interface IShare {
+ id: string;
+ key: string;
+ pageId: string;
+ includeSubPages: boolean;
+ searchIndexing: boolean;
+ creatorId: string;
+ spaceId: string;
+ workspaceId: string;
+ createdAt: string;
+ updatedAt: string;
+ deletedAt: string | null;
+ sharedPage?: ISharePage;
+}
+
+export interface ISharedItem extends IShare {
+ page: {
+ id: string;
+ title: string;
+ slugId: string;
+ icon: string | null;
+ };
+ space: {
+ id: string;
+ name: string;
+ slug: string;
+ userRole: string;
+ };
+ creator: {
+ id: string;
+ name: string;
+ avatarUrl: string | null;
+ };
+}
+
+export interface ISharedPage extends IShare {
+ page: IPage;
+ share: IShare & {
+ level: number;
+ sharedPage: { id: string; slugId: string; title: string; icon: string };
+ };
+}
+
+export interface IShareForPage extends IShare {
+ level: number;
+ sharedPage: ISharePage;
+}
+
+interface ISharePage {
+ id: string;
+ slugId: string;
+ title: string;
+ icon: string;
+}
+
+export interface ICreateShare {
+ pageId?: string;
+ includeSubPages?: boolean;
+ searchIndexing?: boolean;
+}
+
+export type IUpdateShare = ICreateShare & { shareId: string; pageId?: string };
+
+export interface IShareInfoInput {
+ pageId: string;
+}
+
+export interface ISharedPageTree {
+ share: IShare;
+ pageTree: Partial;
+}
diff --git a/apps/client/src/features/share/utils.ts b/apps/client/src/features/share/utils.ts
new file mode 100644
index 00000000..74ec349f
--- /dev/null
+++ b/apps/client/src/features/share/utils.ts
@@ -0,0 +1,60 @@
+import { IPage } from "@/features/page/types/page.types.ts";
+import { sortPositionKeys } from "@/features/page/tree/utils";
+
+export type SharedPageTreeNode = {
+ id: string;
+ slugId: string;
+ name: string;
+ icon?: string;
+ position: string;
+ spaceId: string;
+ parentPageId: string;
+ hasChildren: boolean;
+ children: SharedPageTreeNode[];
+ label: string,
+ value: string,
+};
+
+export function buildSharedPageTree(pages: Partial): SharedPageTreeNode[] {
+ const pageMap: Record = {};
+
+ // Initialize each page as a tree node and store it in a map.
+ pages.forEach((page) => {
+ pageMap[page.id] = {
+ id: page.slugId,
+ slugId: page.slugId,
+ name: page.title,
+ icon: page.icon,
+ position: page.position,
+ // Initially assume a page has no children.
+ hasChildren: false,
+ spaceId: page.spaceId,
+ parentPageId: page.parentPageId,
+ label: page.title || 'untitled',
+ value: page.id,
+ children: [],
+ };
+ });
+
+ // Build the tree structure.
+ const tree: SharedPageTreeNode[] = [];
+ pages.forEach((page) => {
+ if (page.parentPageId) {
+ // If the page has a parent, add it as a child of the parent node.
+ const parentNode = pageMap[page.parentPageId];
+ if (parentNode) {
+ parentNode.children.push(pageMap[page.id]);
+ parentNode.hasChildren = true;
+ } else {
+ // Parent not found – treat this page as a top-level node.
+ tree.push(pageMap[page.id]);
+ }
+ } else {
+ // No parentPageId indicates a top-level page.
+ tree.push(pageMap[page.id]);
+ }
+ });
+
+ // Return the sorted tree.
+ return sortPositionKeys(tree);
+}
diff --git a/apps/client/src/features/space/components/sidebar/space-sidebar.tsx b/apps/client/src/features/space/components/sidebar/space-sidebar.tsx
index 1df7a2c1..528e8051 100644
--- a/apps/client/src/features/space/components/sidebar/space-sidebar.tsx
+++ b/apps/client/src/features/space/components/sidebar/space-sidebar.tsx
@@ -38,6 +38,8 @@ import PageImportModal from "@/features/page/components/page-import-modal.tsx";
import { useTranslation } from "react-i18next";
import { SwitchSpace } from "./switch-space";
import ExportModal from "@/components/common/export-modal";
+import { mobileSidebarAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
+import { useToggleSidebar } from "@/components/layouts/global/hooks/hooks/use-toggle-sidebar.ts";
export function SpaceSidebar() {
const { t } = useTranslation();
@@ -45,6 +47,9 @@ export function SpaceSidebar() {
const location = useLocation();
const [opened, { open: openSettings, close: closeSettings }] =
useDisclosure(false);
+ const [mobileSidebarOpened] = useAtom(mobileSidebarAtom);
+ const toggleMobileSidebar = useToggleSidebar(mobileSidebarAtom);
+
const { spaceSlug } = useParams();
const { data: space, isLoading, isError } = useGetSpaceBySlugQuery(spaceSlug);
@@ -123,7 +128,12 @@ export function SpaceSidebar() {
) && (
{
+ handleCreatePage();
+ if (mobileSidebarOpened) {
+ toggleMobileSidebar();
+ }
+ }}
>
+
+
+ {t("Public sharing")} - {getAppName()}
+
+
+
+
+ }>
+ {t(
+ "Publicly shared pages from spaces you are a member of will appear here",
+ )}
+
+
+
+ >
+ );
+}
diff --git a/apps/client/src/pages/share/share-redirect.tsx b/apps/client/src/pages/share/share-redirect.tsx
new file mode 100644
index 00000000..5653e83f
--- /dev/null
+++ b/apps/client/src/pages/share/share-redirect.tsx
@@ -0,0 +1,35 @@
+import { useNavigate, useParams } from "react-router-dom";
+import { useEffect } from "react";
+import { buildSharedPageUrl } from "@/features/page/page.utils.ts";
+import { Error404 } from "@/components/ui/error-404.tsx";
+import { useGetShareByIdQuery } from "@/features/share/queries/share-query.ts";
+
+export default function ShareRedirect() {
+ const { shareId } = useParams();
+ const navigate = useNavigate();
+
+ const { data: share, isLoading, isError } = useGetShareByIdQuery(shareId);
+
+ useEffect(() => {
+ if (share) {
+ navigate(
+ buildSharedPageUrl({
+ shareId: share.key,
+ pageSlugId: share?.sharedPage.slugId,
+ pageTitle: share?.sharedPage.title,
+ }),
+ { replace: true },
+ );
+ }
+ }, [isLoading, share]);
+
+ if (isError) {
+ return ;
+ }
+
+ if (isLoading) {
+ return <>>;
+ }
+
+ return null;
+}
diff --git a/apps/client/src/pages/share/shared-page.tsx b/apps/client/src/pages/share/shared-page.tsx
new file mode 100644
index 00000000..a574a614
--- /dev/null
+++ b/apps/client/src/pages/share/shared-page.tsx
@@ -0,0 +1,58 @@
+import { useNavigate, useParams } from "react-router-dom";
+import { Helmet } from "react-helmet-async";
+import { useTranslation } from "react-i18next";
+import { useSharePageQuery } from "@/features/share/queries/share-query.ts";
+import { Container } from "@mantine/core";
+import React, { useEffect } from "react";
+import ReadonlyPageEditor from "@/features/editor/readonly-page-editor.tsx";
+import { extractPageSlugId } from "@/lib";
+import { Error404 } from "@/components/ui/error-404.tsx";
+
+export default function SingleSharedPage() {
+ const { t } = useTranslation();
+ const { pageSlug } = useParams();
+ const { shareId } = useParams();
+ const navigate = useNavigate();
+
+ const { data, isLoading, isError, error } = useSharePageQuery({
+ pageId: extractPageSlugId(pageSlug),
+ });
+
+ useEffect(() => {
+ if (shareId && data) {
+ if (data.share.key !== shareId) {
+ navigate(`/share/${data.share.key}/p/${pageSlug}`, { replace: true });
+ }
+ }
+ }, [shareId, data]);
+
+ if (isLoading) {
+ return <>>;
+ }
+
+ if (isError || !data) {
+ if ([401, 403, 404].includes(error?.["status"])) {
+ return ;
+ }
+ return {t("Error fetching page data.")}
;
+ }
+
+ return (
+
+
+ {`${data?.page?.title || t("untitled")}`}
+ {!data?.share.searchIndexing && (
+
+ )}
+
+
+
+
+
+
+ );
+}
diff --git a/apps/server/package.json b/apps/server/package.json
index fced5e33..efd8d8ca 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -37,18 +37,18 @@
"@fastify/multipart": "^9.0.3",
"@fastify/static": "^8.1.1",
"@nestjs/bullmq": "^11.0.2",
- "@nestjs/common": "^11.0.10",
- "@nestjs/config": "^4.0.0",
- "@nestjs/core": "^11.0.10",
+ "@nestjs/common": "^11.0.20",
+ "@nestjs/config": "^4.0.2",
+ "@nestjs/core": "^11.0.20",
"@nestjs/event-emitter": "^3.0.0",
"@nestjs/jwt": "^11.0.0",
"@nestjs/mapped-types": "^2.1.0",
"@nestjs/passport": "^11.0.5",
- "@nestjs/platform-fastify": "^11.0.10",
- "@nestjs/platform-socket.io": "^11.0.10",
+ "@nestjs/platform-fastify": "^11.0.20",
+ "@nestjs/platform-socket.io": "^11.0.20",
"@nestjs/schedule": "^5.0.1",
"@nestjs/terminus": "^11.0.0",
- "@nestjs/websockets": "^11.0.10",
+ "@nestjs/websockets": "^11.0.20",
"@node-saml/passport-saml": "^5.0.1",
"@react-email/components": "0.0.28",
"@react-email/render": "1.0.2",
diff --git a/apps/server/src/common/helpers/prosemirror/utils.ts b/apps/server/src/common/helpers/prosemirror/utils.ts
index 9d9b5ebe..aaadcd56 100644
--- a/apps/server/src/common/helpers/prosemirror/utils.ts
+++ b/apps/server/src/common/helpers/prosemirror/utils.ts
@@ -1,5 +1,6 @@
import { Node } from '@tiptap/pm/model';
import { jsonToNode } from '../../../collaboration/collaboration.util';
+import { validate as isValidUUID } from 'uuid';
export interface MentionNode {
id: string;
@@ -56,3 +57,41 @@ export function extractPageMentions(mentionList: MentionNode[]): MentionNode[] {
}
return pageMentionList as MentionNode[];
}
+
+
+export function getProsemirrorContent(content: any) {
+ return (
+ content ?? {
+ type: 'doc',
+ content: [{ type: 'paragraph', attrs: { textAlign: 'left' } }],
+ }
+ );
+}
+
+export function isAttachmentNode(nodeType: string) {
+ const attachmentNodeTypes = [
+ 'attachment',
+ 'image',
+ 'video',
+ 'excalidraw',
+ 'drawio',
+ ];
+ return attachmentNodeTypes.includes(nodeType);
+}
+
+export function getAttachmentIds(prosemirrorJson: any) {
+ const doc = jsonToNode(prosemirrorJson);
+ const attachmentIds = [];
+
+ doc?.descendants((node: Node) => {
+ if (isAttachmentNode(node.type.name)) {
+ if (node.attrs.attachmentId && isValidUUID(node.attrs.attachmentId)) {
+ if (!attachmentIds.includes(node.attrs.attachmentId)) {
+ attachmentIds.push(node.attrs.attachmentId);
+ }
+ }
+ }
+ });
+
+ return attachmentIds;
+}
\ No newline at end of file
diff --git a/apps/server/src/core/attachment/attachment.controller.ts b/apps/server/src/core/attachment/attachment.controller.ts
index 4804fce6..160d950b 100644
--- a/apps/server/src/core/attachment/attachment.controller.ts
+++ b/apps/server/src/core/attachment/attachment.controller.ts
@@ -1,310 +1,373 @@
import {
- BadRequestException,
- Controller,
- ForbiddenException,
- Get,
- HttpCode,
- HttpStatus,
- Logger,
- NotFoundException,
- Param,
- Post,
- Req,
- Res,
- UseGuards,
- UseInterceptors,
+ BadRequestException,
+ Controller,
+ ForbiddenException,
+ Get,
+ HttpCode,
+ HttpStatus,
+ Logger,
+ NotFoundException,
+ Param,
+ Post,
+ Query,
+ Req,
+ Res,
+ UseGuards,
+ UseInterceptors,
} from '@nestjs/common';
-import {AttachmentService} from './services/attachment.service';
-import {FastifyReply} from 'fastify';
-import {FileInterceptor} from '../../common/interceptors/file.interceptor';
+import { AttachmentService } from './services/attachment.service';
+import { FastifyReply } from 'fastify';
+import { FileInterceptor } from '../../common/interceptors/file.interceptor';
import * as bytes from 'bytes';
-import {AuthUser} from '../../common/decorators/auth-user.decorator';
-import {AuthWorkspace} from '../../common/decorators/auth-workspace.decorator';
-import {JwtAuthGuard} from '../../common/guards/jwt-auth.guard';
-import {User, Workspace} from '@docmost/db/types/entity.types';
-import {StorageService} from '../../integrations/storage/storage.service';
+import { AuthUser } from '../../common/decorators/auth-user.decorator';
+import { AuthWorkspace } from '../../common/decorators/auth-workspace.decorator';
+import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
+import { User, Workspace } from '@docmost/db/types/entity.types';
+import { StorageService } from '../../integrations/storage/storage.service';
import {
- getAttachmentFolderPath,
- validAttachmentTypes,
+ getAttachmentFolderPath,
+ validAttachmentTypes,
} from './attachment.utils';
-import {getMimeType} from '../../common/helpers';
+import { getMimeType } from '../../common/helpers';
import {
- AttachmentType,
- inlineFileExtensions,
- MAX_AVATAR_SIZE,
+ AttachmentType,
+ inlineFileExtensions,
+ MAX_AVATAR_SIZE,
} from './attachment.constants';
import {
- SpaceCaslAction,
- SpaceCaslSubject,
+ SpaceCaslAction,
+ SpaceCaslSubject,
} from '../casl/interfaces/space-ability.type';
import SpaceAbilityFactory from '../casl/abilities/space-ability.factory';
import {
- WorkspaceCaslAction,
- WorkspaceCaslSubject,
+ WorkspaceCaslAction,
+ WorkspaceCaslSubject,
} from '../casl/interfaces/workspace-ability.type';
import WorkspaceAbilityFactory from '../casl/abilities/workspace-ability.factory';
-import {PageRepo} from '@docmost/db/repos/page/page.repo';
-import {AttachmentRepo} from '@docmost/db/repos/attachment/attachment.repo';
-import {validate as isValidUUID} from 'uuid';
-import {EnvironmentService} from "../../integrations/environment/environment.service";
+import { PageRepo } from '@docmost/db/repos/page/page.repo';
+import { AttachmentRepo } from '@docmost/db/repos/attachment/attachment.repo';
+import { validate as isValidUUID } from 'uuid';
+import { EnvironmentService } from '../../integrations/environment/environment.service';
+import { TokenService } from '../auth/services/token.service';
+import { JwtAttachmentPayload, JwtType } from '../auth/dto/jwt-payload';
@Controller()
export class AttachmentController {
- private readonly logger = new Logger(AttachmentController.name);
+ private readonly logger = new Logger(AttachmentController.name);
- constructor(
- private readonly attachmentService: AttachmentService,
- private readonly storageService: StorageService,
- private readonly workspaceAbility: WorkspaceAbilityFactory,
- private readonly spaceAbility: SpaceAbilityFactory,
- private readonly pageRepo: PageRepo,
- private readonly attachmentRepo: AttachmentRepo,
- private readonly environmentService: EnvironmentService,
- ) {
- }
+ constructor(
+ private readonly attachmentService: AttachmentService,
+ private readonly storageService: StorageService,
+ private readonly workspaceAbility: WorkspaceAbilityFactory,
+ private readonly spaceAbility: SpaceAbilityFactory,
+ private readonly pageRepo: PageRepo,
+ private readonly attachmentRepo: AttachmentRepo,
+ private readonly environmentService: EnvironmentService,
+ private readonly tokenService: TokenService,
+ ) {}
- @UseGuards(JwtAuthGuard)
- @HttpCode(HttpStatus.OK)
- @Post('files/upload')
- @UseInterceptors(FileInterceptor)
- async uploadFile(
- @Req() req: any,
- @Res() res: FastifyReply,
- @AuthUser() user: User,
- @AuthWorkspace() workspace: Workspace,
- ) {
- const maxFileSize = bytes(this.environmentService.getFileUploadSizeLimit());
+ @UseGuards(JwtAuthGuard)
+ @HttpCode(HttpStatus.OK)
+ @Post('files/upload')
+ @UseInterceptors(FileInterceptor)
+ async uploadFile(
+ @Req() req: any,
+ @Res() res: FastifyReply,
+ @AuthUser() user: User,
+ @AuthWorkspace() workspace: Workspace,
+ ) {
+ const maxFileSize = bytes(this.environmentService.getFileUploadSizeLimit());
- let file = null;
- try {
- file = await req.file({
- limits: {fileSize: maxFileSize, fields: 3, files: 1},
- });
- } catch (err: any) {
- this.logger.error(err.message);
- if (err?.statusCode === 413) {
- throw new BadRequestException(
- `File too large. Exceeds the ${this.environmentService.getFileUploadSizeLimit()} limit`,
- );
- }
- }
-
- if (!file) {
- throw new BadRequestException('Failed to upload file');
- }
-
- const pageId = file.fields?.pageId?.value;
-
- if (!pageId) {
- throw new BadRequestException('PageId is required');
- }
-
- const page = await this.pageRepo.findById(pageId);
-
- if (!page) {
- throw new NotFoundException('Page not found');
- }
-
- const spaceAbility = await this.spaceAbility.createForUser(
- user,
- page.spaceId,
+ let file = null;
+ try {
+ file = await req.file({
+ limits: { fileSize: maxFileSize, fields: 3, files: 1 },
+ });
+ } catch (err: any) {
+ this.logger.error(err.message);
+ if (err?.statusCode === 413) {
+ throw new BadRequestException(
+ `File too large. Exceeds the ${this.environmentService.getFileUploadSizeLimit()} limit`,
);
- if (spaceAbility.cannot(SpaceCaslAction.Manage, SpaceCaslSubject.Page)) {
- throw new ForbiddenException();
- }
-
- const spaceId = page.spaceId;
-
- const attachmentId = file.fields?.attachmentId?.value;
- if (attachmentId && !isValidUUID(attachmentId)) {
- throw new BadRequestException('Invalid attachment id');
- }
-
- try {
- const fileResponse = await this.attachmentService.uploadFile({
- filePromise: file,
- pageId: pageId,
- spaceId: spaceId,
- userId: user.id,
- workspaceId: workspace.id,
- attachmentId: attachmentId,
- });
-
- return res.send(fileResponse);
- } catch (err: any) {
- if (err?.statusCode === 413) {
- const errMessage = `File too large. Exceeds the ${this.environmentService.getFileUploadSizeLimit()} limit`;
- this.logger.error(errMessage);
- throw new BadRequestException(errMessage);
- }
- this.logger.error(err);
- throw new BadRequestException('Error processing file upload.');
- }
+ }
}
- @UseGuards(JwtAuthGuard)
- @Get('/files/:fileId/:fileName')
- async getFile(
- @Res() res: FastifyReply,
- @AuthUser() user: User,
- @AuthWorkspace() workspace: Workspace,
- @Param('fileId') fileId: string,
- @Param('fileName') fileName?: string,
+ if (!file) {
+ throw new BadRequestException('Failed to upload file');
+ }
+
+ const pageId = file.fields?.pageId?.value;
+
+ if (!pageId) {
+ throw new BadRequestException('PageId is required');
+ }
+
+ const page = await this.pageRepo.findById(pageId);
+
+ if (!page) {
+ throw new NotFoundException('Page not found');
+ }
+
+ const spaceAbility = await this.spaceAbility.createForUser(
+ user,
+ page.spaceId,
+ );
+ if (spaceAbility.cannot(SpaceCaslAction.Manage, SpaceCaslSubject.Page)) {
+ throw new ForbiddenException();
+ }
+
+ const spaceId = page.spaceId;
+
+ const attachmentId = file.fields?.attachmentId?.value;
+ if (attachmentId && !isValidUUID(attachmentId)) {
+ throw new BadRequestException('Invalid attachment id');
+ }
+
+ try {
+ const fileResponse = await this.attachmentService.uploadFile({
+ filePromise: file,
+ pageId: pageId,
+ spaceId: spaceId,
+ userId: user.id,
+ workspaceId: workspace.id,
+ attachmentId: attachmentId,
+ });
+
+ return res.send(fileResponse);
+ } catch (err: any) {
+ if (err?.statusCode === 413) {
+ const errMessage = `File too large. Exceeds the ${this.environmentService.getFileUploadSizeLimit()} limit`;
+ this.logger.error(errMessage);
+ throw new BadRequestException(errMessage);
+ }
+ this.logger.error(err);
+ throw new BadRequestException('Error processing file upload.');
+ }
+ }
+
+ @UseGuards(JwtAuthGuard)
+ @Get('/files/:fileId/:fileName')
+ async getFile(
+ @Res() res: FastifyReply,
+ @AuthUser() user: User,
+ @AuthWorkspace() workspace: Workspace,
+ @Param('fileId') fileId: string,
+ @Param('fileName') fileName?: string,
+ ) {
+ if (!isValidUUID(fileId)) {
+ throw new NotFoundException('Invalid file id');
+ }
+
+ const attachment = await this.attachmentRepo.findById(fileId);
+ if (
+ !attachment ||
+ attachment.workspaceId !== workspace.id ||
+ !attachment.pageId ||
+ !attachment.spaceId
) {
- if (!isValidUUID(fileId)) {
- throw new NotFoundException('Invalid file id');
- }
+ throw new NotFoundException();
+ }
- const attachment = await this.attachmentRepo.findById(fileId);
- if (
- !attachment ||
- attachment.workspaceId !== workspace.id ||
- !attachment.pageId ||
- !attachment.spaceId
- ) {
- throw new NotFoundException();
- }
+ const spaceAbility = await this.spaceAbility.createForUser(
+ user,
+ attachment.spaceId,
+ );
- const spaceAbility = await this.spaceAbility.createForUser(
- user,
- attachment.spaceId,
+ if (spaceAbility.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
+ throw new ForbiddenException();
+ }
+
+ try {
+ const fileStream = await this.storageService.read(attachment.filePath);
+ res.headers({
+ 'Content-Type': attachment.mimeType,
+ 'Cache-Control': 'private, max-age=3600',
+ });
+
+ if (!inlineFileExtensions.includes(attachment.fileExt)) {
+ res.header(
+ 'Content-Disposition',
+ `attachment; filename="${encodeURIComponent(attachment.fileName)}"`,
);
+ }
- if (spaceAbility.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
- throw new ForbiddenException();
- }
+ return res.send(fileStream);
+ } catch (err) {
+ this.logger.error(err);
+ throw new NotFoundException('File not found');
+ }
+ }
- try {
- const fileStream = await this.storageService.read(attachment.filePath);
- res.headers({
- 'Content-Type': attachment.mimeType,
- 'Cache-Control': 'private, max-age=3600',
- });
-
- if (!inlineFileExtensions.includes(attachment.fileExt)) {
- res.header(
- 'Content-Disposition',
- `attachment; filename="${encodeURIComponent(attachment.fileName)}"`,
- );
- }
-
- return res.send(fileStream);
- } catch (err) {
- this.logger.error(err);
- throw new NotFoundException('File not found');
- }
+ @Get('/files/public/:fileId/:fileName')
+ async getPublicFile(
+ @Res() res: FastifyReply,
+ @AuthWorkspace() workspace: Workspace,
+ @Param('fileId') fileId: string,
+ @Param('fileName') fileName?: string,
+ @Query('jwt') jwtToken?: string,
+ ) {
+ let jwtPayload: JwtAttachmentPayload = null;
+ try {
+ jwtPayload = await this.tokenService.verifyJwt(
+ jwtToken,
+ JwtType.ATTACHMENT,
+ );
+ } catch (err) {
+ throw new BadRequestException(
+ 'Expired or invalid attachment access token',
+ );
}
- @UseGuards(JwtAuthGuard)
- @HttpCode(HttpStatus.OK)
- @Post('attachments/upload-image')
- @UseInterceptors(FileInterceptor)
- async uploadAvatarOrLogo(
- @Req() req: any,
- @Res() res: FastifyReply,
- @AuthUser() user: User,
- @AuthWorkspace() workspace: Workspace,
+ if (
+ !isValidUUID(fileId) ||
+ fileId !== jwtPayload.attachmentId ||
+ jwtPayload.workspaceId !== workspace.id
) {
- const maxFileSize = bytes(MAX_AVATAR_SIZE);
-
- let file = null;
- try {
- file = await req.file({
- limits: {fileSize: maxFileSize, fields: 3, files: 1},
- });
- } catch (err: any) {
- if (err?.statusCode === 413) {
- throw new BadRequestException(
- `File too large. Exceeds the ${MAX_AVATAR_SIZE} limit`,
- );
- }
- }
-
- if (!file) {
- throw new BadRequestException('Invalid file upload');
- }
-
- const attachmentType = file.fields?.type?.value;
- const spaceId = file.fields?.spaceId?.value;
-
- if (!attachmentType) {
- throw new BadRequestException('attachment type is required');
- }
-
- if (
- !validAttachmentTypes.includes(attachmentType) ||
- attachmentType === AttachmentType.File
- ) {
- throw new BadRequestException('Invalid image attachment type');
- }
-
- if (attachmentType === AttachmentType.WorkspaceLogo) {
- const ability = this.workspaceAbility.createForUser(user, workspace);
- if (
- ability.cannot(
- WorkspaceCaslAction.Manage,
- WorkspaceCaslSubject.Settings,
- )
- ) {
- throw new ForbiddenException();
- }
- }
-
- if (attachmentType === AttachmentType.SpaceLogo) {
- if (!spaceId) {
- throw new BadRequestException('spaceId is required');
- }
-
- const spaceAbility = await this.spaceAbility.createForUser(user, spaceId);
- if (
- spaceAbility.cannot(SpaceCaslAction.Manage, SpaceCaslSubject.Settings)
- ) {
- throw new ForbiddenException();
- }
- }
-
- try {
- const fileResponse = await this.attachmentService.uploadImage(
- file,
- attachmentType,
- user.id,
- workspace.id,
- spaceId,
- );
-
- return res.send(fileResponse);
- } catch (err: any) {
- this.logger.error(err);
- throw new BadRequestException('Error processing file upload.');
- }
+ throw new NotFoundException('File not found');
}
- @Get('attachments/img/:attachmentType/:fileName')
- async getLogoOrAvatar(
- @Res() res: FastifyReply,
- @AuthWorkspace() workspace: Workspace,
- @Param('attachmentType') attachmentType: AttachmentType,
- @Param('fileName') fileName?: string,
+ const attachment = await this.attachmentRepo.findById(fileId);
+ if (
+ !attachment ||
+ attachment.workspaceId !== workspace.id ||
+ !attachment.pageId ||
+ !attachment.spaceId ||
+ jwtPayload.pageId !== attachment.pageId
) {
- if (
- !validAttachmentTypes.includes(attachmentType) ||
- attachmentType === AttachmentType.File
- ) {
- throw new BadRequestException('Invalid image attachment type');
- }
-
- const filePath = `${getAttachmentFolderPath(attachmentType, workspace.id)}/${fileName}`;
-
- try {
- const fileStream = await this.storageService.read(filePath);
- res.headers({
- 'Content-Type': getMimeType(filePath),
- 'Cache-Control': 'private, max-age=86400',
- });
- return res.send(fileStream);
- } catch (err) {
- this.logger.error(err);
- throw new NotFoundException('File not found');
- }
+ throw new NotFoundException('File not found');
}
+
+ try {
+ const fileStream = await this.storageService.read(attachment.filePath);
+ res.headers({
+ 'Content-Type': attachment.mimeType,
+ 'Cache-Control': 'public, max-age=3600',
+ });
+
+ if (!inlineFileExtensions.includes(attachment.fileExt)) {
+ res.header(
+ 'Content-Disposition',
+ `attachment; filename="${encodeURIComponent(attachment.fileName)}"`,
+ );
+ }
+
+ return res.send(fileStream);
+ } catch (err) {
+ this.logger.error(err);
+ throw new NotFoundException('File not found');
+ }
+ }
+
+ @UseGuards(JwtAuthGuard)
+ @HttpCode(HttpStatus.OK)
+ @Post('attachments/upload-image')
+ @UseInterceptors(FileInterceptor)
+ async uploadAvatarOrLogo(
+ @Req() req: any,
+ @Res() res: FastifyReply,
+ @AuthUser() user: User,
+ @AuthWorkspace() workspace: Workspace,
+ ) {
+ const maxFileSize = bytes(MAX_AVATAR_SIZE);
+
+ let file = null;
+ try {
+ file = await req.file({
+ limits: { fileSize: maxFileSize, fields: 3, files: 1 },
+ });
+ } catch (err: any) {
+ if (err?.statusCode === 413) {
+ throw new BadRequestException(
+ `File too large. Exceeds the ${MAX_AVATAR_SIZE} limit`,
+ );
+ }
+ }
+
+ if (!file) {
+ throw new BadRequestException('Invalid file upload');
+ }
+
+ const attachmentType = file.fields?.type?.value;
+ const spaceId = file.fields?.spaceId?.value;
+
+ if (!attachmentType) {
+ throw new BadRequestException('attachment type is required');
+ }
+
+ if (
+ !validAttachmentTypes.includes(attachmentType) ||
+ attachmentType === AttachmentType.File
+ ) {
+ throw new BadRequestException('Invalid image attachment type');
+ }
+
+ if (attachmentType === AttachmentType.WorkspaceLogo) {
+ const ability = this.workspaceAbility.createForUser(user, workspace);
+ if (
+ ability.cannot(
+ WorkspaceCaslAction.Manage,
+ WorkspaceCaslSubject.Settings,
+ )
+ ) {
+ throw new ForbiddenException();
+ }
+ }
+
+ if (attachmentType === AttachmentType.SpaceLogo) {
+ if (!spaceId) {
+ throw new BadRequestException('spaceId is required');
+ }
+
+ const spaceAbility = await this.spaceAbility.createForUser(user, spaceId);
+ if (
+ spaceAbility.cannot(SpaceCaslAction.Manage, SpaceCaslSubject.Settings)
+ ) {
+ throw new ForbiddenException();
+ }
+ }
+
+ try {
+ const fileResponse = await this.attachmentService.uploadImage(
+ file,
+ attachmentType,
+ user.id,
+ workspace.id,
+ spaceId,
+ );
+
+ return res.send(fileResponse);
+ } catch (err: any) {
+ this.logger.error(err);
+ throw new BadRequestException('Error processing file upload.');
+ }
+ }
+
+ @Get('attachments/img/:attachmentType/:fileName')
+ async getLogoOrAvatar(
+ @Res() res: FastifyReply,
+ @AuthWorkspace() workspace: Workspace,
+ @Param('attachmentType') attachmentType: AttachmentType,
+ @Param('fileName') fileName?: string,
+ ) {
+ if (
+ !validAttachmentTypes.includes(attachmentType) ||
+ attachmentType === AttachmentType.File
+ ) {
+ throw new BadRequestException('Invalid image attachment type');
+ }
+
+ const filePath = `${getAttachmentFolderPath(attachmentType, workspace.id)}/${fileName}`;
+
+ try {
+ const fileStream = await this.storageService.read(filePath);
+ res.headers({
+ 'Content-Type': getMimeType(filePath),
+ 'Cache-Control': 'private, max-age=86400',
+ });
+ return res.send(fileStream);
+ } catch (err) {
+ this.logger.error(err);
+ throw new NotFoundException('File not found');
+ }
+ }
}
diff --git a/apps/server/src/core/attachment/attachment.module.ts b/apps/server/src/core/attachment/attachment.module.ts
index 7dc47ed8..f80a2eb7 100644
--- a/apps/server/src/core/attachment/attachment.module.ts
+++ b/apps/server/src/core/attachment/attachment.module.ts
@@ -5,9 +5,10 @@ import { StorageModule } from '../../integrations/storage/storage.module';
import { UserModule } from '../user/user.module';
import { WorkspaceModule } from '../workspace/workspace.module';
import { AttachmentProcessor } from './processors/attachment.processor';
+import { TokenModule } from '../auth/token.module';
@Module({
- imports: [StorageModule, UserModule, WorkspaceModule],
+ imports: [StorageModule, UserModule, WorkspaceModule, TokenModule],
controllers: [AttachmentController],
providers: [AttachmentService, AttachmentProcessor],
})
diff --git a/apps/server/src/core/auth/dto/jwt-payload.ts b/apps/server/src/core/auth/dto/jwt-payload.ts
index ad172b78..b9ce13c4 100644
--- a/apps/server/src/core/auth/dto/jwt-payload.ts
+++ b/apps/server/src/core/auth/dto/jwt-payload.ts
@@ -2,6 +2,7 @@ export enum JwtType {
ACCESS = 'access',
COLLAB = 'collab',
EXCHANGE = 'exchange',
+ ATTACHMENT = 'attachment',
}
export type JwtPayload = {
sub: string;
@@ -21,3 +22,11 @@ export type JwtExchangePayload = {
workspaceId: string;
type: 'exchange';
};
+
+export type JwtAttachmentPayload = {
+ attachmentId: string;
+ pageId: string;
+ workspaceId: string;
+ type: 'attachment';
+};
+
diff --git a/apps/server/src/core/auth/services/token.service.ts b/apps/server/src/core/auth/services/token.service.ts
index ad745290..963e8e65 100644
--- a/apps/server/src/core/auth/services/token.service.ts
+++ b/apps/server/src/core/auth/services/token.service.ts
@@ -6,6 +6,7 @@ import {
import { JwtService } from '@nestjs/jwt';
import { EnvironmentService } from '../../../integrations/environment/environment.service';
import {
+ JwtAttachmentPayload,
JwtCollabPayload,
JwtExchangePayload,
JwtPayload,
@@ -59,6 +60,21 @@ export class TokenService {
return this.jwtService.sign(payload, { expiresIn: '10s' });
}
+ async generateAttachmentToken(opts: {
+ attachmentId: string;
+ pageId: string;
+ workspaceId: string;
+ }): Promise {
+ const { attachmentId, pageId, workspaceId } = opts;
+ const payload: JwtAttachmentPayload = {
+ attachmentId: attachmentId,
+ pageId: pageId,
+ workspaceId: workspaceId,
+ type: JwtType.ATTACHMENT,
+ };
+ return this.jwtService.sign(payload, { expiresIn: '1h' });
+ }
+
async verifyJwt(token: string, tokenType: string) {
const payload = await this.jwtService.verifyAsync(token, {
secret: this.environmentService.getAppSecret(),
diff --git a/apps/server/src/core/casl/abilities/space-ability.factory.ts b/apps/server/src/core/casl/abilities/space-ability.factory.ts
index d2173383..53a57a0c 100644
--- a/apps/server/src/core/casl/abilities/space-ability.factory.ts
+++ b/apps/server/src/core/casl/abilities/space-ability.factory.ts
@@ -45,6 +45,7 @@ function buildSpaceAdminAbility() {
can(SpaceCaslAction.Manage, SpaceCaslSubject.Settings);
can(SpaceCaslAction.Manage, SpaceCaslSubject.Member);
can(SpaceCaslAction.Manage, SpaceCaslSubject.Page);
+ can(SpaceCaslAction.Manage, SpaceCaslSubject.Share);
return build();
}
@@ -55,6 +56,7 @@ function buildSpaceWriterAbility() {
can(SpaceCaslAction.Read, SpaceCaslSubject.Settings);
can(SpaceCaslAction.Read, SpaceCaslSubject.Member);
can(SpaceCaslAction.Manage, SpaceCaslSubject.Page);
+ can(SpaceCaslAction.Manage, SpaceCaslSubject.Share);
return build();
}
@@ -65,5 +67,6 @@ function buildSpaceReaderAbility() {
can(SpaceCaslAction.Read, SpaceCaslSubject.Settings);
can(SpaceCaslAction.Read, SpaceCaslSubject.Member);
can(SpaceCaslAction.Read, SpaceCaslSubject.Page);
+ can(SpaceCaslAction.Read, SpaceCaslSubject.Share);
return build();
}
diff --git a/apps/server/src/core/casl/interfaces/space-ability.type.ts b/apps/server/src/core/casl/interfaces/space-ability.type.ts
index c927229b..d7801cab 100644
--- a/apps/server/src/core/casl/interfaces/space-ability.type.ts
+++ b/apps/server/src/core/casl/interfaces/space-ability.type.ts
@@ -9,9 +9,11 @@ export enum SpaceCaslSubject {
Settings = 'settings',
Member = 'member',
Page = 'page',
+ Share = 'share',
}
export type ISpaceAbility =
| [SpaceCaslAction, SpaceCaslSubject.Settings]
| [SpaceCaslAction, SpaceCaslSubject.Member]
- | [SpaceCaslAction, SpaceCaslSubject.Page];
+ | [SpaceCaslAction, SpaceCaslSubject.Page]
+ | [SpaceCaslAction, SpaceCaslSubject.Share];
diff --git a/apps/server/src/core/core.module.ts b/apps/server/src/core/core.module.ts
index 182a1420..f7f4f785 100644
--- a/apps/server/src/core/core.module.ts
+++ b/apps/server/src/core/core.module.ts
@@ -15,6 +15,7 @@ import { SpaceModule } from './space/space.module';
import { GroupModule } from './group/group.module';
import { CaslModule } from './casl/casl.module';
import { DomainMiddleware } from '../common/middlewares/domain.middleware';
+import { ShareModule } from './share/share.module';
@Module({
imports: [
@@ -28,6 +29,7 @@ import { DomainMiddleware } from '../common/middlewares/domain.middleware';
SpaceModule,
GroupModule,
CaslModule,
+ ShareModule,
],
})
export class CoreModule implements NestModule {
diff --git a/apps/server/src/core/page/services/page.service.ts b/apps/server/src/core/page/services/page.service.ts
index 43d8f1d2..5e4553c6 100644
--- a/apps/server/src/core/page/services/page.service.ts
+++ b/apps/server/src/core/page/services/page.service.ts
@@ -212,7 +212,7 @@ export class PageService {
trx,
);
const pageIds = await this.pageRepo
- .getPageAndDescendants(rootPage.id)
+ .getPageAndDescendants(rootPage.id, { includeContent: false })
.then((pages) => pages.map((page) => page.id));
// The first id is the root page id
if (pageIds.length > 1) {
@@ -223,6 +223,16 @@ export class PageService {
trx,
);
}
+
+ // update spaceId in shares
+ if (pageIds.length > 0) {
+ await trx
+ .updateTable('shares')
+ .set({ spaceId: spaceId })
+ .where('pageId', 'in', pageIds)
+ .execute();
+ }
+
// Update attachments
await this.attachmentRepo.updateAttachmentsByPageId(
{ spaceId },
diff --git a/apps/server/src/core/share/dto/share.dto.ts b/apps/server/src/core/share/dto/share.dto.ts
new file mode 100644
index 00000000..b6e789ec
--- /dev/null
+++ b/apps/server/src/core/share/dto/share.dto.ts
@@ -0,0 +1,58 @@
+import {
+ IsBoolean,
+ IsNotEmpty,
+ IsOptional,
+ IsString,
+ IsUUID,
+} from 'class-validator';
+
+export class CreateShareDto {
+ @IsString()
+ @IsNotEmpty()
+ pageId: string;
+
+ @IsBoolean()
+ @IsOptional()
+ includeSubPages: boolean;
+
+ @IsOptional()
+ @IsBoolean()
+ searchIndexing: boolean;
+}
+
+export class UpdateShareDto extends CreateShareDto {
+ @IsString()
+ @IsNotEmpty()
+ shareId: string;
+
+ @IsString()
+ @IsOptional()
+ pageId: string;
+}
+
+export class ShareIdDto {
+ @IsString()
+ @IsNotEmpty()
+ shareId: string;
+}
+
+export class SpaceIdDto {
+ @IsUUID()
+ spaceId: string;
+}
+
+export class ShareInfoDto {
+ @IsString()
+ @IsOptional()
+ shareId?: string;
+
+ @IsString()
+ @IsOptional()
+ pageId: string;
+}
+
+export class SharePageIdDto {
+ @IsString()
+ @IsNotEmpty()
+ pageId: string;
+}
diff --git a/apps/server/src/core/share/share-seo.controller.ts b/apps/server/src/core/share/share-seo.controller.ts
new file mode 100644
index 00000000..ecacecf0
--- /dev/null
+++ b/apps/server/src/core/share/share-seo.controller.ts
@@ -0,0 +1,109 @@
+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/p/: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(/[\s\S]*?<\/title>/i, `${metaTitle} `)
+ .replace(metaTagVar, metaTags);
+
+ res.type('text/html').send(transformedHtml);
+ }
+ }
+
+ sendIndex(indexFilePath: string, res: FastifyReply) {
+ const stream = fs.createReadStream(indexFilePath);
+ res.type('text/html').send(stream);
+ }
+
+ extractPageSlugId(slug: string): string {
+ if (!slug) {
+ return undefined;
+ }
+ if (isValidUUID(slug)) {
+ return slug;
+ }
+ const parts = slug.split('-');
+ return parts.length > 1 ? parts[parts.length - 1] : slug;
+ }
+}
diff --git a/apps/server/src/core/share/share.controller.ts b/apps/server/src/core/share/share.controller.ts
new file mode 100644
index 00000000..5e8debe0
--- /dev/null
+++ b/apps/server/src/core/share/share.controller.ts
@@ -0,0 +1,171 @@
+import {
+ BadRequestException,
+ Body,
+ Controller,
+ ForbiddenException,
+ HttpCode,
+ HttpStatus,
+ NotFoundException,
+ Post,
+ UseGuards,
+} from '@nestjs/common';
+import { AuthUser } from '../../common/decorators/auth-user.decorator';
+import { User, Workspace } from '@docmost/db/types/entity.types';
+import {
+ SpaceCaslAction,
+ SpaceCaslSubject,
+} from '../casl/interfaces/space-ability.type';
+import { AuthWorkspace } from '../../common/decorators/auth-workspace.decorator';
+import SpaceAbilityFactory from '../casl/abilities/space-ability.factory';
+import { ShareService } from './share.service';
+import {
+ CreateShareDto,
+ ShareIdDto,
+ ShareInfoDto,
+ SharePageIdDto,
+ UpdateShareDto,
+} from './dto/share.dto';
+import { PageRepo } from '@docmost/db/repos/page/page.repo';
+import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
+import { Public } from '../../common/decorators/public.decorator';
+import { ShareRepo } from '@docmost/db/repos/share/share.repo';
+import { PaginationOptions } from '@docmost/db/pagination/pagination-options';
+
+@UseGuards(JwtAuthGuard)
+@Controller('shares')
+export class ShareController {
+ constructor(
+ private readonly shareService: ShareService,
+ private readonly spaceAbility: SpaceAbilityFactory,
+ private readonly shareRepo: ShareRepo,
+ private readonly pageRepo: PageRepo,
+ ) {}
+
+ @HttpCode(HttpStatus.OK)
+ @Post('/')
+ async getShares(
+ @AuthUser() user: User,
+ @Body() pagination: PaginationOptions,
+ ) {
+ return this.shareRepo.getShares(user.id, pagination);
+ }
+
+ @Public()
+ @HttpCode(HttpStatus.OK)
+ @Post('/page-info')
+ async getSharedPageInfo(
+ @Body() dto: ShareInfoDto,
+ @AuthWorkspace() workspace: Workspace,
+ ) {
+ if (!dto.pageId && !dto.shareId) {
+ throw new BadRequestException();
+ }
+
+ return this.shareService.getSharedPage(dto, workspace.id);
+ }
+
+ @Public()
+ @HttpCode(HttpStatus.OK)
+ @Post('/info')
+ async getShare(@Body() dto: ShareIdDto) {
+ const share = await this.shareRepo.findById(dto.shareId, {
+ includeSharedPage: true,
+ });
+
+ if (!share) {
+ throw new NotFoundException('Share not found');
+ }
+
+ return share;
+ }
+
+ @HttpCode(HttpStatus.OK)
+ @Post('/for-page')
+ async getShareForPage(
+ @Body() dto: SharePageIdDto,
+ @AuthUser() user: User,
+ @AuthWorkspace() workspace: Workspace,
+ ) {
+ const page = await this.pageRepo.findById(dto.pageId);
+ if (!page) {
+ throw new NotFoundException('Shared page not found');
+ }
+
+ const ability = await this.spaceAbility.createForUser(user, page.spaceId);
+ if (ability.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Share)) {
+ throw new ForbiddenException();
+ }
+
+ return this.shareService.getShareForPage(page.id, workspace.id);
+ }
+
+ @HttpCode(HttpStatus.OK)
+ @Post('create')
+ async create(
+ @Body() createShareDto: CreateShareDto,
+ @AuthUser() user: User,
+ @AuthWorkspace() workspace: Workspace,
+ ) {
+ const page = await this.pageRepo.findById(createShareDto.pageId);
+
+ if (!page || workspace.id !== page.workspaceId) {
+ throw new NotFoundException('Page not found');
+ }
+
+ const ability = await this.spaceAbility.createForUser(user, page.spaceId);
+ if (ability.cannot(SpaceCaslAction.Create, SpaceCaslSubject.Share)) {
+ throw new ForbiddenException();
+ }
+
+ return this.shareService.createShare({
+ page,
+ authUserId: user.id,
+ workspaceId: workspace.id,
+ createShareDto,
+ });
+ }
+
+ @HttpCode(HttpStatus.OK)
+ @Post('update')
+ async update(@Body() updateShareDto: UpdateShareDto, @AuthUser() user: User) {
+ const share = await this.shareRepo.findById(updateShareDto.shareId);
+
+ if (!share) {
+ throw new NotFoundException('Share not found');
+ }
+
+ const ability = await this.spaceAbility.createForUser(user, share.spaceId);
+ if (ability.cannot(SpaceCaslAction.Edit, SpaceCaslSubject.Share)) {
+ throw new ForbiddenException();
+ }
+
+ return this.shareService.updateShare(share.id, updateShareDto);
+ }
+
+ @HttpCode(HttpStatus.OK)
+ @Post('delete')
+ async delete(@Body() shareIdDto: ShareIdDto, @AuthUser() user: User) {
+ const share = await this.shareRepo.findById(shareIdDto.shareId);
+
+ if (!share) {
+ throw new NotFoundException('Share not found');
+ }
+
+ const ability = await this.spaceAbility.createForUser(user, share.spaceId);
+ if (ability.cannot(SpaceCaslAction.Manage, SpaceCaslSubject.Share)) {
+ throw new ForbiddenException();
+ }
+
+ await this.shareRepo.deleteShare(share.id);
+ }
+
+ @Public()
+ @HttpCode(HttpStatus.OK)
+ @Post('/tree')
+ async getSharePageTree(
+ @Body() dto: ShareIdDto,
+ @AuthWorkspace() workspace: Workspace,
+ ) {
+ return this.shareService.getShareTree(dto.shareId, workspace.id);
+ }
+}
diff --git a/apps/server/src/core/share/share.module.ts b/apps/server/src/core/share/share.module.ts
new file mode 100644
index 00000000..2ba9764e
--- /dev/null
+++ b/apps/server/src/core/share/share.module.ts
@@ -0,0 +1,13 @@
+import { Module } from '@nestjs/common';
+import { ShareController } from './share.controller';
+import { ShareService } from './share.service';
+import { TokenModule } from '../auth/token.module';
+import { ShareSeoController } from './share-seo.controller';
+
+@Module({
+ imports: [TokenModule],
+ controllers: [ShareController, ShareSeoController],
+ providers: [ShareService],
+ exports: [ShareService],
+})
+export class ShareModule {}
diff --git a/apps/server/src/core/share/share.service.ts b/apps/server/src/core/share/share.service.ts
new file mode 100644
index 00000000..a9140c0b
--- /dev/null
+++ b/apps/server/src/core/share/share.service.ts
@@ -0,0 +1,297 @@
+import {
+ BadRequestException,
+ Injectable,
+ Logger,
+ NotFoundException,
+} from '@nestjs/common';
+import { CreateShareDto, ShareInfoDto, UpdateShareDto } from './dto/share.dto';
+import { InjectKysely } from 'nestjs-kysely';
+import { KyselyDB } from '@docmost/db/types/kysely.types';
+import { nanoIdGen } from '../../common/helpers';
+import { PageRepo } from '@docmost/db/repos/page/page.repo';
+import { TokenService } from '../auth/services/token.service';
+import { jsonToNode } from '../../collaboration/collaboration.util';
+import {
+ getAttachmentIds,
+ getProsemirrorContent,
+ isAttachmentNode,
+} from '../../common/helpers/prosemirror/utils';
+import { Node } from '@tiptap/pm/model';
+import { ShareRepo } from '@docmost/db/repos/share/share.repo';
+import { updateAttachmentAttr } from './share.util';
+import { Page } from '@docmost/db/types/entity.types';
+import { validate as isValidUUID } from 'uuid';
+import { sql } from 'kysely';
+
+@Injectable()
+export class ShareService {
+ private readonly logger = new Logger(ShareService.name);
+
+ constructor(
+ private readonly shareRepo: ShareRepo,
+ private readonly pageRepo: PageRepo,
+ @InjectKysely() private readonly db: KyselyDB,
+ private readonly tokenService: TokenService,
+ ) {}
+
+ async getShareTree(shareId: string, workspaceId: string) {
+ const share = await this.shareRepo.findById(shareId);
+ if (!share || share.workspaceId !== workspaceId) {
+ throw new NotFoundException('Share not found');
+ }
+
+ if (share.includeSubPages) {
+ const pageList = await this.pageRepo.getPageAndDescendants(share.pageId, {
+ includeContent: false,
+ });
+
+ return { share, pageTree: pageList };
+ } else {
+ return { share, pageTree: [] };
+ }
+ }
+
+ async createShare(opts: {
+ authUserId: string;
+ workspaceId: string;
+ page: Page;
+ createShareDto: CreateShareDto;
+ }) {
+ const { authUserId, workspaceId, page, createShareDto } = opts;
+
+ try {
+ const shares = await this.shareRepo.findByPageId(page.id);
+ if (shares) {
+ return shares;
+ }
+
+ return await this.shareRepo.insertShare({
+ key: nanoIdGen().toLowerCase(),
+ pageId: page.id,
+ includeSubPages: createShareDto.includeSubPages || true,
+ searchIndexing: createShareDto.searchIndexing || true,
+ creatorId: authUserId,
+ spaceId: page.spaceId,
+ workspaceId,
+ });
+ } catch (err) {
+ this.logger.error(err);
+ throw new BadRequestException('Failed to share page');
+ }
+ }
+
+ async updateShare(shareId: string, updateShareDto: UpdateShareDto) {
+ try {
+ return this.shareRepo.updateShare(
+ {
+ includeSubPages: updateShareDto.includeSubPages,
+ searchIndexing: updateShareDto.searchIndexing,
+ },
+ shareId,
+ );
+ } catch (err) {
+ this.logger.error(err);
+ throw new BadRequestException('Failed to update share');
+ }
+ }
+
+ async getSharedPage(dto: ShareInfoDto, workspaceId: string) {
+ const share = await this.getShareForPage(dto.pageId, workspaceId);
+
+ if (!share) {
+ throw new NotFoundException('Shared page not found');
+ }
+
+ const page = await this.pageRepo.findById(dto.pageId, {
+ includeContent: true,
+ includeCreator: true,
+ });
+
+ page.content = await this.updatePublicAttachments(page);
+
+ if (!page) {
+ throw new NotFoundException('Shared page not found');
+ }
+
+ return { page, share };
+ }
+
+ async getShareForPage(pageId: string, workspaceId: string) {
+ // here we try to check if a page was shared directly or if it inherits the share from its closest shared ancestor
+ const share = await this.db
+ .withRecursive('page_hierarchy', (cte) =>
+ cte
+ .selectFrom('pages')
+ .select([
+ 'id',
+ 'slugId',
+ 'pages.title',
+ 'pages.icon',
+ 'parentPageId',
+ sql`0`.as('level'),
+ ])
+ .where(isValidUUID(pageId) ? 'id' : 'slugId', '=', pageId)
+ .unionAll((union) =>
+ union
+ .selectFrom('pages as p')
+ .select([
+ 'p.id',
+ 'p.slugId',
+ 'p.title',
+ 'p.icon',
+ 'p.parentPageId',
+ // Increase the level by 1 for each ancestor.
+ sql`ph.level + 1`.as('level'),
+ ])
+ .innerJoin('page_hierarchy as ph', 'ph.parentPageId', 'p.id'),
+ ),
+ )
+ .selectFrom('page_hierarchy')
+ .leftJoin('shares', 'shares.pageId', 'page_hierarchy.id')
+ .select([
+ 'page_hierarchy.id as sharedPageId',
+ 'page_hierarchy.slugId as sharedPageSlugId',
+ 'page_hierarchy.title as sharedPageTitle',
+ 'page_hierarchy.icon as sharedPageIcon',
+ 'page_hierarchy.level as level',
+ 'shares.id',
+ 'shares.key',
+ 'shares.pageId',
+ 'shares.includeSubPages',
+ 'shares.searchIndexing',
+ 'shares.creatorId',
+ 'shares.spaceId',
+ 'shares.workspaceId',
+ 'shares.createdAt',
+ 'shares.updatedAt',
+ ])
+ .where('shares.id', 'is not', null)
+ .orderBy('page_hierarchy.level', 'asc')
+ .executeTakeFirst();
+
+ if (!share || share.workspaceId != workspaceId) {
+ return undefined;
+ }
+
+ if (share.level === 1 && !share.includeSubPages) {
+ // we can only show a page if its shared ancestor permits it
+ return undefined;
+ }
+
+ return {
+ id: share.id,
+ key: share.key,
+ includeSubPages: share.includeSubPages,
+ searchIndexing: share.searchIndexing,
+ pageId: share.pageId,
+ creatorId: share.creatorId,
+ spaceId: share.spaceId,
+ workspaceId: share.workspaceId,
+ createdAt: share.createdAt,
+ level: share.level,
+ sharedPage: {
+ id: share.sharedPageId,
+ slugId: share.sharedPageSlugId,
+ title: share.sharedPageTitle,
+ icon: share.sharedPageIcon,
+ },
+ };
+ }
+
+ async getShareAncestorPage(
+ ancestorPageId: string,
+ childPageId: string,
+ ): Promise {
+ let ancestor = null;
+ try {
+ ancestor = await this.db
+ .withRecursive('page_ancestors', (db) =>
+ db
+ .selectFrom('pages')
+ .select([
+ 'id',
+ 'slugId',
+ 'title',
+ 'parentPageId',
+ 'spaceId',
+ (eb) =>
+ eb
+ .case()
+ .when(eb.ref('id'), '=', ancestorPageId)
+ .then(true)
+ .else(false)
+ .end()
+ .as('found'),
+ ])
+ .where(
+ isValidUUID(childPageId) ? 'id' : 'slugId',
+ '=',
+ childPageId,
+ )
+ .unionAll((exp) =>
+ exp
+ .selectFrom('pages as p')
+ .select([
+ 'p.id',
+ 'p.slugId',
+ 'p.title',
+ 'p.parentPageId',
+ 'p.spaceId',
+ (eb) =>
+ eb
+ .case()
+ .when(eb.ref('p.id'), '=', ancestorPageId)
+ .then(true)
+ .else(false)
+ .end()
+ .as('found'),
+ ])
+ .innerJoin('page_ancestors as pa', 'pa.parentPageId', 'p.id')
+ // Continue recursing only when the target ancestor hasn't been found on that branch.
+ .where('pa.found', '=', false),
+ ),
+ )
+ .selectFrom('page_ancestors')
+ .selectAll()
+ .where('found', '=', true)
+ .limit(1)
+ .executeTakeFirst();
+ } catch (err) {
+ // empty
+ }
+
+ return ancestor;
+ }
+
+ async updatePublicAttachments(page: Page): Promise {
+ const prosemirrorJson = getProsemirrorContent(page.content);
+ const attachmentIds = getAttachmentIds(prosemirrorJson);
+ const attachmentMap = new Map();
+
+ await Promise.all(
+ attachmentIds.map(async (attachmentId: string) => {
+ const token = await this.tokenService.generateAttachmentToken({
+ attachmentId,
+ pageId: page.id,
+ workspaceId: page.workspaceId,
+ });
+ attachmentMap.set(attachmentId, token);
+ }),
+ );
+
+ const doc = jsonToNode(prosemirrorJson);
+
+ doc?.descendants((node: Node) => {
+ if (!isAttachmentNode(node.type.name)) return;
+
+ const attachmentId = node.attrs.attachmentId;
+ const token = attachmentMap.get(attachmentId);
+ if (!token) return;
+
+ updateAttachmentAttr(node, 'src', token);
+ updateAttachmentAttr(node, 'url', token);
+ });
+
+ return doc.toJSON();
+ }
+}
diff --git a/apps/server/src/core/share/share.util.ts b/apps/server/src/core/share/share.util.ts
new file mode 100644
index 00000000..e21f55aa
--- /dev/null
+++ b/apps/server/src/core/share/share.util.ts
@@ -0,0 +1,22 @@
+import { Node } from '@tiptap/pm/model';
+
+export function updateAttachmentAttr(
+ node: Node,
+ attr: 'src' | 'url',
+ token: string,
+) {
+ const attrVal = node.attrs[attr];
+ if (
+ attrVal &&
+ (attrVal.startsWith('/files') || attrVal.startsWith('/api/files'))
+ ) {
+ // @ts-ignore
+ node.attrs[attr] = updateAttachmentUrl(attrVal, token);
+ }
+}
+
+function updateAttachmentUrl(src: string, jwtToken: string) {
+ const updatedSrc = src.replace('/files/', '/files/public/');
+ const separator = updatedSrc.includes('?') ? '&' : '?';
+ return `${updatedSrc}${separator}jwt=${jwtToken}`;
+}
diff --git a/apps/server/src/database/database.module.ts b/apps/server/src/database/database.module.ts
index 930bb59b..68c35dd3 100644
--- a/apps/server/src/database/database.module.ts
+++ b/apps/server/src/database/database.module.ts
@@ -24,6 +24,7 @@ import * as process from 'node:process';
import { MigrationService } from '@docmost/db/services/migration.service';
import { UserTokenRepo } from './repos/user-token/user-token.repo';
import { BacklinkRepo } from '@docmost/db/repos/backlink/backlink.repo';
+import { ShareRepo } from '@docmost/db/repos/share/share.repo';
// https://github.com/brianc/node-postgres/issues/811
types.setTypeParser(types.builtins.INT8, (val) => Number(val));
@@ -74,6 +75,7 @@ types.setTypeParser(types.builtins.INT8, (val) => Number(val));
AttachmentRepo,
UserTokenRepo,
BacklinkRepo,
+ ShareRepo
],
exports: [
WorkspaceRepo,
@@ -88,6 +90,7 @@ types.setTypeParser(types.builtins.INT8, (val) => Number(val));
AttachmentRepo,
UserTokenRepo,
BacklinkRepo,
+ ShareRepo
],
})
export class DatabaseModule
diff --git a/apps/server/src/database/migrations/20250408T191830-shares.ts b/apps/server/src/database/migrations/20250408T191830-shares.ts
new file mode 100644
index 00000000..39d91454
--- /dev/null
+++ b/apps/server/src/database/migrations/20250408T191830-shares.ts
@@ -0,0 +1,38 @@
+import { Kysely, sql } from 'kysely';
+
+export async function up(db: Kysely): Promise {
+ await db.schema
+ .createTable('shares')
+ .addColumn('id', 'uuid', (col) =>
+ col.primaryKey().defaultTo(sql`gen_uuid_v7()`),
+ )
+ .addColumn('key', 'varchar', (col) => col.notNull())
+ .addColumn('page_id', 'uuid', (col) =>
+ col.references('pages.id').onDelete('cascade'),
+ )
+ .addColumn('include_sub_pages', 'boolean', (col) => col.defaultTo(false))
+ .addColumn('search_indexing', 'boolean', (col) => col.defaultTo(false))
+ .addColumn('creator_id', 'uuid', (col) => col.references('users.id'))
+ .addColumn('space_id', 'uuid', (col) =>
+ col.references('spaces.id').onDelete('cascade').notNull(),
+ )
+ .addColumn('workspace_id', 'uuid', (col) =>
+ col.references('workspaces.id').onDelete('cascade').notNull(),
+ )
+ .addColumn('created_at', 'timestamptz', (col) =>
+ col.notNull().defaultTo(sql`now()`),
+ )
+ .addColumn('updated_at', 'timestamptz', (col) =>
+ col.notNull().defaultTo(sql`now()`),
+ )
+ .addColumn('deleted_at', 'timestamptz', (col) => col)
+ .addUniqueConstraint('shares_key_workspace_id_unique', [
+ 'key',
+ 'workspace_id',
+ ])
+ .execute();
+}
+
+export async function down(db: Kysely): Promise {
+ await db.schema.dropTable('shares').execute();
+}
diff --git a/apps/server/src/database/repos/page/page.repo.ts b/apps/server/src/database/repos/page/page.repo.ts
index 850fb2d1..8f06c4d4 100644
--- a/apps/server/src/database/repos/page/page.repo.ts
+++ b/apps/server/src/database/repos/page/page.repo.ts
@@ -211,7 +211,10 @@ export class PageRepo {
).as('contributors');
}
- async getPageAndDescendants(parentPageId: string) {
+ async getPageAndDescendants(
+ parentPageId: string,
+ opts: { includeContent: boolean },
+ ) {
return this.db
.withRecursive('page_hierarchy', (db) =>
db
@@ -221,11 +224,12 @@ export class PageRepo {
'slugId',
'title',
'icon',
- 'content',
+ 'position',
'parentPageId',
'spaceId',
'workspaceId',
])
+ .$if(opts?.includeContent, (qb) => qb.select('content'))
.where('id', '=', parentPageId)
.unionAll((exp) =>
exp
@@ -235,11 +239,12 @@ export class PageRepo {
'p.slugId',
'p.title',
'p.icon',
- 'p.content',
+ 'p.position',
'p.parentPageId',
'p.spaceId',
'p.workspaceId',
])
+ .$if(opts?.includeContent, (qb) => qb.select('content'))
.innerJoin('page_hierarchy as ph', 'p.parentPageId', 'ph.id'),
),
)
diff --git a/apps/server/src/database/repos/share/share.repo.ts b/apps/server/src/database/repos/share/share.repo.ts
new file mode 100644
index 00000000..c2943c07
--- /dev/null
+++ b/apps/server/src/database/repos/share/share.repo.ts
@@ -0,0 +1,242 @@
+import { Injectable } from '@nestjs/common';
+import { InjectKysely } from 'nestjs-kysely';
+import { KyselyDB, KyselyTransaction } from '../../types/kysely.types';
+import { dbOrTx } from '../../utils';
+import {
+ InsertableShare,
+ Share,
+ UpdatableShare,
+} from '@docmost/db/types/entity.types';
+import { PaginationOptions } from '@docmost/db/pagination/pagination-options';
+import { executeWithPagination } from '@docmost/db/pagination/pagination';
+import { validate as isValidUUID } from 'uuid';
+import { ExpressionBuilder, sql } from 'kysely';
+import { DB } from '@docmost/db/types/db';
+import { jsonObjectFrom } from 'kysely/helpers/postgres';
+import { SpaceMemberRepo } from '@docmost/db/repos/space/space-member.repo';
+
+@Injectable()
+export class ShareRepo {
+ constructor(
+ @InjectKysely() private readonly db: KyselyDB,
+ private spaceMemberRepo: SpaceMemberRepo,
+ ) {}
+
+ private baseFields: Array = [
+ 'id',
+ 'key',
+ 'pageId',
+ 'includeSubPages',
+ 'searchIndexing',
+ 'creatorId',
+ 'spaceId',
+ 'workspaceId',
+ 'createdAt',
+ 'updatedAt',
+ 'deletedAt',
+ ];
+
+ async findById(
+ shareId: string,
+ opts?: {
+ includeSharedPage?: boolean;
+ includeCreator?: boolean;
+ withLock?: boolean;
+ trx?: KyselyTransaction;
+ },
+ ): Promise {
+ const db = dbOrTx(this.db, opts?.trx);
+
+ let query = db.selectFrom('shares').select(this.baseFields);
+
+ if (opts?.includeSharedPage) {
+ query = query.select((eb) => this.withSharedPage(eb));
+ }
+
+ if (opts?.includeCreator) {
+ query = query.select((eb) => this.withCreator(eb));
+ }
+
+ if (opts?.withLock && opts?.trx) {
+ query = query.forUpdate();
+ }
+
+ if (isValidUUID(shareId)) {
+ query = query.where('id', '=', shareId);
+ } else {
+ query = query.where(sql`LOWER(key)`, '=', shareId.toLowerCase());
+ }
+
+ return query.executeTakeFirst();
+ }
+
+ async findByPageId(
+ pageId: string,
+ opts?: {
+ includeCreator?: boolean;
+ withLock?: boolean;
+ trx?: KyselyTransaction;
+ },
+ ): Promise {
+ const db = dbOrTx(this.db, opts?.trx);
+
+ let query = db
+ .selectFrom('shares')
+ .select(this.baseFields)
+ .where('pageId', '=', pageId);
+
+ if (opts?.includeCreator) {
+ query = query.select((eb) => this.withCreator(eb));
+ }
+
+ if (opts?.withLock && opts?.trx) {
+ query = query.forUpdate();
+ }
+ return query.executeTakeFirst();
+ }
+
+ async updateShare(
+ updatableShare: UpdatableShare,
+ shareId: string,
+ trx?: KyselyTransaction,
+ ) {
+ return dbOrTx(this.db, trx)
+ .updateTable('shares')
+ .set({ ...updatableShare, updatedAt: new Date() })
+ .where(
+ isValidUUID(shareId) ? 'id' : sql`LOWER(key)`,
+ '=',
+ shareId.toLowerCase(),
+ )
+ .returning(this.baseFields)
+ .executeTakeFirst();
+ }
+
+ async insertShare(
+ insertableShare: InsertableShare,
+ trx?: KyselyTransaction,
+ ): Promise {
+ const db = dbOrTx(this.db, trx);
+ return db
+ .insertInto('shares')
+ .values(insertableShare)
+ .returning(this.baseFields)
+ .executeTakeFirst();
+ }
+
+ async deleteShare(shareId: string): Promise {
+ let query = this.db.deleteFrom('shares');
+
+ if (isValidUUID(shareId)) {
+ query = query.where('id', '=', shareId);
+ } else {
+ query = query.where(sql`LOWER(key)`, '=', shareId.toLowerCase());
+ }
+
+ await query.execute();
+ }
+
+ async getShares(userId: string, pagination: PaginationOptions) {
+ const userSpaceIds = await this.spaceMemberRepo.getUserSpaceIds(userId);
+
+ const query = this.db
+ .selectFrom('shares')
+ .select(this.baseFields)
+ .select((eb) => this.withPage(eb))
+ .select((eb) => this.withSpace(eb, userId))
+ .select((eb) => this.withCreator(eb))
+ .where('spaceId', 'in', userSpaceIds)
+ .orderBy('updatedAt', 'desc');
+
+ const hasEmptyIds = userSpaceIds.length === 0;
+ const result = executeWithPagination(query, {
+ page: pagination.page,
+ perPage: pagination.limit,
+ hasEmptyIds,
+ });
+
+ return result;
+ }
+
+ withPage(eb: ExpressionBuilder) {
+ return jsonObjectFrom(
+ eb
+ .selectFrom('pages')
+ .select(['pages.id', 'pages.title', 'pages.slugId', 'pages.icon'])
+ .whereRef('pages.id', '=', 'shares.pageId'),
+ ).as('page');
+ }
+
+ withSpace(eb: ExpressionBuilder, userId?: string) {
+ return jsonObjectFrom(
+ eb
+ .selectFrom('spaces')
+ .select(['spaces.id', 'spaces.name', 'spaces.slug'])
+ .$if(Boolean(userId), (qb) =>
+ qb.select((eb) => this.withUserSpaceRole(eb, userId)),
+ )
+ .whereRef('spaces.id', '=', 'shares.spaceId'),
+ ).as('space');
+ }
+
+ withUserSpaceRole(eb: ExpressionBuilder, userId: string) {
+ return eb
+ .selectFrom(
+ eb
+ .selectFrom('spaceMembers')
+ .select(['spaceMembers.role'])
+ .whereRef('spaceMembers.spaceId', '=', 'spaces.id')
+ .where('spaceMembers.userId', '=', userId)
+ .unionAll(
+ eb
+ .selectFrom('spaceMembers')
+ .innerJoin(
+ 'groupUsers',
+ 'groupUsers.groupId',
+ 'spaceMembers.groupId',
+ )
+ .select(['spaceMembers.role'])
+ .whereRef('spaceMembers.spaceId', '=', 'spaces.id')
+ .where('groupUsers.userId', '=', userId),
+ )
+ .as('roles_union'),
+ )
+ .select('roles_union.role')
+ .orderBy(
+ sql`CASE roles_union.role
+ WHEN 'admin' THEN 3
+ WHEN 'writer' THEN 2
+ WHEN 'reader' THEN 1
+ ELSE 0
+ END`,
+
+ 'desc',
+ )
+ .limit(1)
+ .as('userRole');
+ }
+
+ withCreator(eb: ExpressionBuilder) {
+ return jsonObjectFrom(
+ eb
+ .selectFrom('users')
+ .select(['users.id', 'users.name', 'users.avatarUrl'])
+ .whereRef('users.id', '=', 'shares.creatorId'),
+ ).as('creator');
+ }
+
+ withSharedPage(eb: ExpressionBuilder) {
+ return jsonObjectFrom(
+ eb
+ .selectFrom('pages')
+ .select([
+ 'pages.id',
+ 'pages.slugId',
+ 'pages.title',
+ 'pages.icon',
+ 'pages.parentPageId',
+ ])
+ .whereRef('pages.id', '=', 'shares.pageId'),
+ ).as('sharedPage');
+ }
+}
diff --git a/apps/server/src/database/types/db.d.ts b/apps/server/src/database/types/db.d.ts
index eae94943..8c4cbd57 100644
--- a/apps/server/src/database/types/db.d.ts
+++ b/apps/server/src/database/types/db.d.ts
@@ -183,6 +183,20 @@ export interface Pages {
ydoc: Buffer | null;
}
+export interface Shares {
+ createdAt: Generated;
+ creatorId: string | null;
+ deletedAt: Timestamp | null;
+ id: Generated;
+ includeSubPages: Generated;
+ key: string;
+ pageId: string | null;
+ searchIndexing: Generated;
+ spaceId: string;
+ updatedAt: Generated;
+ workspaceId: string;
+}
+
export interface SpaceMembers {
addedById: string | null;
createdAt: Generated;
@@ -288,6 +302,7 @@ export interface DB {
groupUsers: GroupUsers;
pageHistory: PageHistory;
pages: Pages;
+ shares: Shares;
spaceMembers: SpaceMembers;
spaces: Spaces;
users: Users;
diff --git a/apps/server/src/database/types/entity.types.ts b/apps/server/src/database/types/entity.types.ts
index 8abd9f98..6cb55a11 100644
--- a/apps/server/src/database/types/entity.types.ts
+++ b/apps/server/src/database/types/entity.types.ts
@@ -16,6 +16,7 @@ import {
Billing as BillingSubscription,
AuthProviders,
AuthAccounts,
+ Shares,
} from './db';
// Workspace
@@ -101,3 +102,8 @@ export type UpdatableAuthProvider = Updateable>;
export type AuthAccount = Selectable;
export type InsertableAuthAccount = Insertable;
export type UpdatableAuthAccount = Updateable>;
+
+// Share
+export type Share = Selectable;
+export type InsertableShare = Insertable;
+export type UpdatableShare = Updateable>;
diff --git a/apps/server/src/integrations/export/export.service.ts b/apps/server/src/integrations/export/export.service.ts
index 09fdb5fd..4bb5146f 100644
--- a/apps/server/src/integrations/export/export.service.ts
+++ b/apps/server/src/integrations/export/export.service.ts
@@ -15,10 +15,8 @@ import { StorageService } from '../storage/storage.service';
import {
buildTree,
computeLocalPath,
- getAttachmentIds,
getExportExtension,
getPageTitle,
- getProsemirrorContent,
PageExportTree,
replaceInternalLinks,
updateAttachmentUrlsToLocalPaths,
@@ -29,6 +27,10 @@ import { EditorState } from '@tiptap/pm/state';
// eslint-disable-next-line @typescript-eslint/no-require-imports
import slugify = require('@sindresorhus/slugify');
import { EnvironmentService } from '../environment/environment.service';
+import {
+ getAttachmentIds,
+ getProsemirrorContent,
+} from '../../common/helpers/prosemirror/utils';
@Injectable()
export class ExportService {
@@ -76,8 +78,11 @@ export class ExportService {
`;
}
- if (format === ExportFormat.Markdown) {
- const newPageHtml = pageHtml.replace(/]*>[\s\S]*?<\/colgroup>/gmi, '');
+ if (format === ExportFormat.Markdown) {
+ const newPageHtml = pageHtml.replace(
+ / ]*>[\s\S]*?<\/colgroup>/gim,
+ '',
+ );
return turndown(newPageHtml);
}
@@ -85,7 +90,9 @@ export class ExportService {
}
async exportPageWithChildren(pageId: string, format: string) {
- const pages = await this.pageRepo.getPageAndDescendants(pageId);
+ const pages = await this.pageRepo.getPageAndDescendants(pageId, {
+ includeContent: true,
+ });
if (!pages || pages.length === 0) {
throw new BadRequestException('No pages to export');
@@ -260,14 +267,7 @@ export class ExportService {
const pages = await this.db
.selectFrom('pages')
- .select([
- 'id',
- 'slugId',
- 'title',
- 'creatorId',
- 'spaceId',
- 'workspaceId',
- ])
+ .select(['id', 'slugId', 'title', 'creatorId', 'spaceId', 'workspaceId'])
.select((eb) => this.pageRepo.withSpace(eb))
.where('id', 'in', pageMentionIds)
.where('workspaceId', '=', workspaceId)
diff --git a/apps/server/src/integrations/export/utils.ts b/apps/server/src/integrations/export/utils.ts
index f99f337a..fe1815b0 100644
--- a/apps/server/src/integrations/export/utils.ts
+++ b/apps/server/src/integrations/export/utils.ts
@@ -4,6 +4,7 @@ import { Node } from '@tiptap/pm/model';
import { validate as isValidUUID } from 'uuid';
import * as path from 'path';
import { Page } from '@docmost/db/types/entity.types';
+import { isAttachmentNode } from '../../common/helpers/prosemirror/utils';
export type PageExportTree = Record;
@@ -25,43 +26,6 @@ export function getPageTitle(title: string) {
return title ? title : 'untitled';
}
-export function getProsemirrorContent(content: any) {
- return (
- content ?? {
- type: 'doc',
- content: [{ type: 'paragraph', attrs: { textAlign: 'left' } }],
- }
- );
-}
-
-export function getAttachmentIds(prosemirrorJson: any) {
- const doc = jsonToNode(prosemirrorJson);
- const attachmentIds = [];
-
- doc?.descendants((node: Node) => {
- if (isAttachmentNode(node.type.name)) {
- if (node.attrs.attachmentId && isValidUUID(node.attrs.attachmentId)) {
- if (!attachmentIds.includes(node.attrs.attachmentId)) {
- attachmentIds.push(node.attrs.attachmentId);
- }
- }
- }
- });
-
- return attachmentIds;
-}
-
-export function isAttachmentNode(nodeType: string) {
- const attachmentNodeTypes = [
- 'attachment',
- 'image',
- 'video',
- 'excalidraw',
- 'drawio',
- ];
- return attachmentNodeTypes.includes(nodeType);
-}
-
export function updateAttachmentUrlsToLocalPaths(prosemirrorJson: any) {
const doc = jsonToNode(prosemirrorJson);
if (!doc) return null;
diff --git a/apps/server/src/main.ts b/apps/server/src/main.ts
index 3ceeb789..95df255d 100644
--- a/apps/server/src/main.ts
+++ b/apps/server/src/main.ts
@@ -4,7 +4,12 @@ import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
-import { Logger, NotFoundException, ValidationPipe } from '@nestjs/common';
+import {
+ Logger,
+ NotFoundException,
+ RequestMethod,
+ ValidationPipe,
+} from '@nestjs/common';
import { TransformHttpResponseInterceptor } from './common/interceptors/http-response.interceptor';
import { WsRedisIoAdapter } from './ws/adapter/ws-redis.adapter';
import { InternalLogFilter } from './common/logger/internal-log-filter';
@@ -26,7 +31,9 @@ async function bootstrap() {
},
);
- app.setGlobalPrefix('api', { exclude: ['robots.txt'] });
+ app.setGlobalPrefix('api', {
+ exclude: ['robots.txt', 'share/:shareId/p/:pageSlug'],
+ });
const reflector = app.get(Reflector);
const redisIoAdapter = new WsRedisIoAdapter(app);
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8772d574..2fd73d8b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -419,43 +419,43 @@ importers:
version: 8.1.1
'@nestjs/bullmq':
specifier: ^11.0.2
- version: 11.0.2(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)(bullmq@5.41.3)
+ version: 11.0.2(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)(bullmq@5.41.3)
'@nestjs/common':
- specifier: ^11.0.10
- version: 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ specifier: ^11.0.20
+ version: 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/config':
- specifier: ^4.0.0
- version: 4.0.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(rxjs@7.8.1)
+ specifier: ^4.0.2
+ version: 4.0.2(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(rxjs@7.8.1)
'@nestjs/core':
- specifier: ^11.0.10
- version: 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ specifier: ^11.0.20
+ version: 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/event-emitter':
specifier: ^3.0.0
- version: 3.0.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)
+ version: 3.0.0(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)
'@nestjs/jwt':
specifier: ^11.0.0
- version: 11.0.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))
+ version: 11.0.0(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))
'@nestjs/mapped-types':
specifier: ^2.1.0
- version: 2.1.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)
+ version: 2.1.0(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)
'@nestjs/passport':
specifier: ^11.0.5
- version: 11.0.5(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(passport@0.7.0)
+ version: 11.0.5(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(passport@0.7.0)
'@nestjs/platform-fastify':
- specifier: ^11.0.10
- version: 11.0.10(@fastify/static@8.1.1)(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)
+ specifier: ^11.0.20
+ version: 11.0.20(@fastify/static@8.1.1)(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)
'@nestjs/platform-socket.io':
- specifier: ^11.0.10
- version: 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(rxjs@7.8.1)
+ specifier: ^11.0.20
+ version: 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(rxjs@7.8.1)
'@nestjs/schedule':
specifier: ^5.0.1
- version: 5.0.1(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)
+ version: 5.0.1(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)
'@nestjs/terminus':
specifier: ^11.0.0
- version: 11.0.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ version: 11.0.0(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/websockets':
- specifier: ^11.0.10
- version: 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)(@nestjs/platform-socket.io@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ specifier: ^11.0.20
+ version: 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)(@nestjs/platform-socket.io@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@node-saml/passport-saml':
specifier: ^5.0.1
version: 5.0.1
@@ -509,7 +509,7 @@ importers:
version: 3.3.11
nestjs-kysely:
specifier: ^1.1.0
- version: 1.1.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)(kysely@0.27.5)(reflect-metadata@0.2.2)
+ version: 1.1.0(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)(kysely@0.27.5)(reflect-metadata@0.2.2)
nodemailer:
specifier: ^6.10.0
version: 6.10.0
@@ -564,7 +564,7 @@ importers:
version: 11.0.1(chokidar@4.0.3)(typescript@5.7.3)
'@nestjs/testing':
specifier: ^11.0.10
- version: 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)
+ version: 11.0.10(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)
'@types/bcrypt':
specifier: ^5.0.2
version: 5.0.2
@@ -2083,8 +2083,8 @@ packages:
'@fastify/cookie@11.0.2':
resolution: {integrity: sha512-GWdwdGlgJxyvNv+QcKiGNevSspMQXncjMZ1J8IvuDQk0jvkzgWWZFNC2En3s+nHndZBGV8IbLwOI/sxCZw/mzA==}
- '@fastify/cors@10.0.2':
- resolution: {integrity: sha512-DGdxOG36sS/tZv1NFiCJGi7wGuXOSPL2CmNX5PbOVKx0C6LuIALRMrqLByHTCcX1Rbl8NJ9IWlJex32bzydvlw==}
+ '@fastify/cors@11.0.1':
+ resolution: {integrity: sha512-dmZaE7M1f4SM8ZZuk5RhSsDJ+ezTgI7v3HHRj8Ow9CneczsPLZV6+2j2uwdaSLn8zhTv6QV0F4ZRcqdalGx1pQ==}
'@fastify/deepmerge@2.0.2':
resolution: {integrity: sha512-3wuLdX5iiiYeZWP6bQrjqhrcvBIf0NHbQH1Ur1WbHvoiuTYUEItgygea3zs8aHpiitn0lOB8gX20u1qO+FDm7Q==}
@@ -2566,8 +2566,8 @@ packages:
'@swc/core':
optional: true
- '@nestjs/common@11.0.10':
- resolution: {integrity: sha512-pzGXp14KF2Q4CDZGQgPK4l8zEg7i6cNkb+10yc8ZA5K41cLe3ZbWW1YxtY2e/glHauOJwTLSVjH4tiRVtOTizg==}
+ '@nestjs/common@11.0.20':
+ resolution: {integrity: sha512-/GH8NDCczjn6+6RNEtSNAts/nq/wQE8L1qZ9TRjqjNqEsZNE1vpFuRIhmcO2isQZ0xY5rySnpaRdrOAul3gQ3A==}
peerDependencies:
class-transformer: '*'
class-validator: '*'
@@ -2579,14 +2579,14 @@ packages:
class-validator:
optional: true
- '@nestjs/config@4.0.0':
- resolution: {integrity: sha512-hyhUMtVwlT+tavtPNyekl8iP0QTU1U6awKrgdOSxhMhp3TQMltx7hz2yqGTcARp+19zWPfgJudyxthuD3lPp/Q==}
+ '@nestjs/config@4.0.2':
+ resolution: {integrity: sha512-McMW6EXtpc8+CwTUwFdg6h7dYcBUpH5iUILCclAsa+MbCEvC9ZKu4dCHRlJqALuhjLw97pbQu62l4+wRwGeZqA==}
peerDependencies:
'@nestjs/common': ^10.0.0 || ^11.0.0
rxjs: ^7.1.0
- '@nestjs/core@11.0.10':
- resolution: {integrity: sha512-f0qB8ztNWZeAD4E4fUdHConmNYCa/A78U7WJu5mX9OLYfOAs3ESYCDfsH9MRUvkA4Ft4Y1uMmyJo5L4fg4+beg==}
+ '@nestjs/core@11.0.20':
+ resolution: {integrity: sha512-yUkEzBGiRNSEThVl6vMCXgoA9sDGWoRbJsTLdYdCC7lg7PE1iXBnna1FiBfQjT995pm0fjyM1e3WsXmyWeJXbw==}
engines: {node: '>= 20'}
peerDependencies:
'@nestjs/common': ^11.0.0
@@ -2633,11 +2633,11 @@ packages:
'@nestjs/common': ^10.0.0 || ^11.0.0
passport: ^0.5.0 || ^0.6.0 || ^0.7.0
- '@nestjs/platform-fastify@11.0.10':
- resolution: {integrity: sha512-aOvuFsSUsfGziy6OmJwVDNx6aXougCMeUpEAlphuCLehSwfZQxhpy4SpThxTAtHU7RdmgGO7VfUGH+uUY8vHdQ==}
+ '@nestjs/platform-fastify@11.0.20':
+ resolution: {integrity: sha512-MZnjO77N/XesVzXhn8qnSEcnjXVIHxkh5zTz8SEIr6K2yWgGJZbTlNm7ul6l7QBeaCeNZtZJlvY/F+4Dbx8yCQ==}
peerDependencies:
'@fastify/static': ^8.0.0
- '@fastify/view': ^10.0.0
+ '@fastify/view': ^10.0.0 || ^11.0.0
'@nestjs/common': ^11.0.0
'@nestjs/core': ^11.0.0
peerDependenciesMeta:
@@ -2646,8 +2646,8 @@ packages:
'@fastify/view':
optional: true
- '@nestjs/platform-socket.io@11.0.10':
- resolution: {integrity: sha512-39lAjq0+kZRiMuscDcugoG+onPDciM4jhuf8ZDjVcuSwtib1OGwrFtErSzp/KJsmHPSStgapbNev7eFi32uWQA==}
+ '@nestjs/platform-socket.io@11.0.20':
+ resolution: {integrity: sha512-fUyDjLt0wJ4WK+rXrd5/oSWw5xWpfDOknpP7YNgaFfvYW726KuS5gWysV7JPD2mgH85S6i+qiO3qZvHIs5DvxQ==}
peerDependencies:
'@nestjs/common': ^11.0.0
'@nestjs/websockets': ^11.0.0
@@ -2725,8 +2725,8 @@ packages:
'@nestjs/platform-express':
optional: true
- '@nestjs/websockets@11.0.10':
- resolution: {integrity: sha512-GPIEfqJyAkTHrHGK9w2OU8LJaZAZKW8WpWcTplThLxMelRq7mBkYOaGvc6dpr7fE1wWzWkwY0ZjQEnwnVmmxSg==}
+ '@nestjs/websockets@11.0.20':
+ resolution: {integrity: sha512-qcybahXdrPJFMILhAwJML9D/bExBEBFsfwFiePCeI4f//tiP0rXiLspLVOHClSeUPBaCNrx+Ae/HVe9UP+wtOg==}
peerDependencies:
'@nestjs/common': ^11.0.0
'@nestjs/core': ^11.0.0
@@ -3747,6 +3747,13 @@ packages:
'@tiptap/core': ^2.7.0
'@tiptap/pm': ^2.7.0
+ '@tokenizer/inflate@0.2.7':
+ resolution: {integrity: sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==}
+ engines: {node: '>=18'}
+
+ '@tokenizer/token@0.3.0':
+ resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
+
'@tsconfig/node10@1.0.9':
resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==}
@@ -5134,6 +5141,15 @@ packages:
supports-color:
optional: true
+ debug@4.4.0:
+ resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
decimal.js@10.4.3:
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
@@ -5564,8 +5580,8 @@ packages:
fastify-plugin@5.0.1:
resolution: {integrity: sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ==}
- fastify@5.2.1:
- resolution: {integrity: sha512-rslrNBF67eg8/Gyn7P2URV8/6pz8kSAscFL4EThZJ8JBMaXacVdVE4hmUcnPNKERl5o/xTiBSLfdowBRhVF1WA==}
+ fastify@5.3.0:
+ resolution: {integrity: sha512-vDpCJa4KRkHrdDMpDNtyPaIDi/ptCwoJ0M8RiefuIMvyXTgG63xYGe9DYYiCpydjh0ETIaLoSyKBNKkh7ew1eA==}
fastq@1.17.1:
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
@@ -5581,6 +5597,9 @@ packages:
picomatch:
optional: true
+ fflate@0.8.2:
+ resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==}
+
figures@3.2.0:
resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
engines: {node: '>=8'}
@@ -5592,6 +5611,10 @@ packages:
file-saver@2.0.5:
resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
+ file-type@20.4.1:
+ resolution: {integrity: sha512-hw9gNZXUfZ02Jo0uafWLaFVPter5/k2rfcrjFJJHX/77xtSDOfJuEFb6oKlFV86FLP1SuyHMW1PSk0U9M5tKkQ==}
+ engines: {node: '>=18'}
+
filelist@1.0.4:
resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
@@ -6560,6 +6583,10 @@ packages:
linkifyjs@4.2.0:
resolution: {integrity: sha512-pCj3PrQyATaoTYKHrgWRF3SJwsm61udVh+vuls/Rl6SptiDhgE7ziUIudAedRY9QEfynmM7/RmLEfPUyw1HPCw==}
+ load-esm@1.0.2:
+ resolution: {integrity: sha512-nVAvWk/jeyrWyXEAs84mpQCYccxRqgKY4OznLuJhJCa0XsPSfdOIr2zvBZEj3IHEHbX97jjscKRRV539bW0Gpw==}
+ engines: {node: '>=13.2.0'}
+
loader-runner@4.3.0:
resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==}
engines: {node: '>=6.11.5'}
@@ -6813,9 +6840,6 @@ packages:
mlly@1.7.3:
resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==}
- mnemonist@0.39.8:
- resolution: {integrity: sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ==}
-
ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
@@ -7002,9 +7026,6 @@ packages:
resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==}
engines: {node: '>= 0.4'}
- obliterator@2.0.4:
- resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==}
-
obuf@1.1.2:
resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==}
@@ -7165,6 +7186,10 @@ packages:
peberminta@0.9.0:
resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==}
+ peek-readable@7.0.0:
+ resolution: {integrity: sha512-nri2TO5JE3/mRryik9LlHFT53cgHfRK0Lt0BAZQXku/AW3E6XLt2GaY8siWi7dvW/m1z0ecn+J+bpDa9ZN3IsQ==}
+ engines: {node: '>=18'}
+
pg-cloudflare@1.1.1:
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
@@ -7388,6 +7413,9 @@ packages:
process-warning@4.0.0:
resolution: {integrity: sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==}
+ process-warning@5.0.0:
+ resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==}
+
process@0.11.10:
resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
engines: {node: '>= 0.6.0'}
@@ -7874,6 +7902,9 @@ packages:
secure-json-parse@3.0.2:
resolution: {integrity: sha512-H6nS2o8bWfpFEV6U38sOSjS7bTbdgbCGU9wEM6W14P5H0QOsz94KCusifV44GpHDTu2nqZbuDNhTzu+mjDSw1w==}
+ secure-json-parse@4.0.0:
+ resolution: {integrity: sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==}
+
selderee@0.11.0:
resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==}
@@ -8091,6 +8122,10 @@ packages:
strnum@1.0.5:
resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
+ strtok3@10.2.2:
+ resolution: {integrity: sha512-Xt18+h4s7Z8xyZ0tmBoRmzxcop97R4BAh+dXouUDCYn+Em+1P3qpkUfI5ueWLT8ynC5hZ+q4iPEmGG1urvQGBg==}
+ engines: {node: '>=18'}
+
styled-jsx@5.1.1:
resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==}
engines: {node: '>= 12.0.0'}
@@ -8234,6 +8269,10 @@ packages:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
+ token-types@6.0.0:
+ resolution: {integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==}
+ engines: {node: '>=14.16'}
+
tough-cookie@5.1.0:
resolution: {integrity: sha512-rvZUv+7MoBYTiDmFPBrhL7Ujx9Sk+q9wwm22x8c8T5IJaR+Wsyc7TNxbVxo84kZoRJZZMazowFLqpankBEQrGg==}
engines: {node: '>=16'}
@@ -8432,6 +8471,10 @@ packages:
resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==}
engines: {node: '>=8'}
+ uint8array-extras@1.4.0:
+ resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==}
+ engines: {node: '>=18'}
+
unbox-primitive@1.0.2:
resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
@@ -10906,8 +10949,8 @@ snapshots:
'@fastify/ajv-compiler@4.0.2':
dependencies:
- ajv: 8.12.0
- ajv-formats: 3.0.1(ajv@8.12.0)
+ ajv: 8.17.1
+ ajv-formats: 3.0.1(ajv@8.17.1)
fast-uri: 3.0.6
'@fastify/busboy@3.1.1': {}
@@ -10917,10 +10960,10 @@ snapshots:
cookie: 1.0.2
fastify-plugin: 5.0.1
- '@fastify/cors@10.0.2':
+ '@fastify/cors@11.0.1':
dependencies:
fastify-plugin: 5.0.1
- mnemonist: 0.39.8
+ toad-cache: 3.7.0
'@fastify/deepmerge@2.0.2': {}
@@ -11545,17 +11588,17 @@ snapshots:
'@emnapi/runtime': 1.2.0
'@tybys/wasm-util': 0.9.0
- '@nestjs/bull-shared@11.0.2(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)':
+ '@nestjs/bull-shared@11.0.2(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)':
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/core': 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/core': 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
tslib: 2.8.1
- '@nestjs/bullmq@11.0.2(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)(bullmq@5.41.3)':
+ '@nestjs/bullmq@11.0.2(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)(bullmq@5.41.3)':
dependencies:
- '@nestjs/bull-shared': 11.0.2(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/core': 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/bull-shared': 11.0.2(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/core': 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
bullmq: 5.41.3
tslib: 2.8.1
@@ -11588,9 +11631,11 @@ snapshots:
- uglify-js
- webpack-cli
- '@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)':
+ '@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)':
dependencies:
+ file-type: 20.4.1
iterare: 1.2.1
+ load-esm: 1.0.2
reflect-metadata: 0.2.2
rxjs: 7.8.1
tslib: 2.8.1
@@ -11598,18 +11643,20 @@ snapshots:
optionalDependencies:
class-transformer: 0.5.1
class-validator: 0.14.1
+ transitivePeerDependencies:
+ - supports-color
- '@nestjs/config@4.0.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(rxjs@7.8.1)':
+ '@nestjs/config@4.0.2(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(rxjs@7.8.1)':
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
dotenv: 16.4.7
dotenv-expand: 12.0.1
lodash: 4.17.21
rxjs: 7.8.1
- '@nestjs/core@11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)':
+ '@nestjs/core@11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)':
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nuxt/opencollective': 0.4.1
fast-safe-stringify: 2.1.1
iterare: 1.2.1
@@ -11619,51 +11666,52 @@ snapshots:
tslib: 2.8.1
uid: 2.0.2
optionalDependencies:
- '@nestjs/websockets': 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)(@nestjs/platform-socket.io@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/websockets': 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)(@nestjs/platform-socket.io@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/event-emitter@3.0.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)':
+ '@nestjs/event-emitter@3.0.0(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)':
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/core': 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/core': 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
eventemitter2: 6.4.9
- '@nestjs/jwt@11.0.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))':
+ '@nestjs/jwt@11.0.0(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))':
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@types/jsonwebtoken': 9.0.7
jsonwebtoken: 9.0.2
- '@nestjs/mapped-types@2.1.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)':
+ '@nestjs/mapped-types@2.1.0(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)':
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
reflect-metadata: 0.2.2
optionalDependencies:
class-transformer: 0.5.1
class-validator: 0.14.1
- '@nestjs/passport@11.0.5(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(passport@0.7.0)':
+ '@nestjs/passport@11.0.5(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(passport@0.7.0)':
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
passport: 0.7.0
- '@nestjs/platform-fastify@11.0.10(@fastify/static@8.1.1)(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)':
+ '@nestjs/platform-fastify@11.0.20(@fastify/static@8.1.1)(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)':
dependencies:
- '@fastify/cors': 10.0.2
+ '@fastify/cors': 11.0.1
'@fastify/formbody': 8.0.2
'@fastify/middie': 9.0.3
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/core': 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- fastify: 5.2.1
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/core': 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ fast-querystring: 1.1.2
+ fastify: 5.3.0
light-my-request: 6.6.0
path-to-regexp: 8.2.0
tslib: 2.8.1
optionalDependencies:
'@fastify/static': 8.1.1
- '@nestjs/platform-socket.io@11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(rxjs@7.8.1)':
+ '@nestjs/platform-socket.io@11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(rxjs@7.8.1)':
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/websockets': 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)(@nestjs/platform-socket.io@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/websockets': 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)(@nestjs/platform-socket.io@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
rxjs: 7.8.1
socket.io: 4.8.1
tslib: 2.8.1
@@ -11672,10 +11720,10 @@ snapshots:
- supports-color
- utf-8-validate
- '@nestjs/schedule@5.0.1(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)':
+ '@nestjs/schedule@5.0.1(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)':
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/core': 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/core': 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
cron: 3.5.0
'@nestjs/schematics@11.0.1(chokidar@4.0.3)(typescript@5.7.3)':
@@ -11689,32 +11737,32 @@ snapshots:
transitivePeerDependencies:
- chokidar
- '@nestjs/terminus@11.0.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)':
+ '@nestjs/terminus@11.0.0(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)':
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/core': 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/core': 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
boxen: 5.1.2
check-disk-space: 3.4.0
reflect-metadata: 0.2.2
rxjs: 7.8.1
- '@nestjs/testing@11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)':
+ '@nestjs/testing@11.0.10(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)':
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/core': 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/core': 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
tslib: 2.8.1
- '@nestjs/websockets@11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)(@nestjs/platform-socket.io@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)':
+ '@nestjs/websockets@11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)(@nestjs/platform-socket.io@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)':
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/core': 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/core': 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
iterare: 1.2.1
object-hash: 3.0.0
reflect-metadata: 0.2.2
rxjs: 7.8.1
tslib: 2.8.1
optionalDependencies:
- '@nestjs/platform-socket.io': 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(rxjs@7.8.1)
+ '@nestjs/platform-socket.io': 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(rxjs@7.8.1)
'@next/env@14.2.10': {}
@@ -11798,7 +11846,7 @@ snapshots:
nx: 20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5))
semver: 7.6.3
tmp: 0.2.1
- tslib: 2.8.0
+ tslib: 2.8.1
yargs-parser: 21.1.1
'@nx/js@20.4.5(@babel/traverse@7.27.0)(@swc/core@1.5.25(@swc/helpers@0.5.5))(@types/node@22.13.4)(nx@20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5)))(typescript@5.7.3)':
@@ -11880,7 +11928,7 @@ snapshots:
chalk: 4.1.2
enquirer: 2.3.6
nx: 20.4.5(@swc/core@1.5.25(@swc/helpers@0.5.5))
- tslib: 2.8.0
+ tslib: 2.8.1
yargs-parser: 21.1.1
transitivePeerDependencies:
- '@swc-node/register'
@@ -12797,6 +12845,16 @@ snapshots:
'@tiptap/core': 2.10.3(@tiptap/pm@2.10.3)
'@tiptap/pm': 2.10.3
+ '@tokenizer/inflate@0.2.7':
+ dependencies:
+ debug: 4.4.0
+ fflate: 0.8.2
+ token-types: 6.0.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@tokenizer/token@0.3.0': {}
+
'@tsconfig/node10@1.0.9': {}
'@tsconfig/node12@1.0.11': {}
@@ -13521,10 +13579,6 @@ snapshots:
optionalDependencies:
ajv: 8.12.0
- ajv-formats@3.0.1(ajv@8.12.0):
- optionalDependencies:
- ajv: 8.12.0
-
ajv-formats@3.0.1(ajv@8.17.1):
optionalDependencies:
ajv: 8.17.1
@@ -14459,6 +14513,10 @@ snapshots:
dependencies:
ms: 2.1.3
+ debug@4.4.0:
+ dependencies:
+ ms: 2.1.3
+
decimal.js@10.4.3: {}
dedent@1.5.1(babel-plugin-macros@3.1.0):
@@ -14574,7 +14632,7 @@ snapshots:
dotenv-expand@11.0.6:
dependencies:
- dotenv: 16.4.5
+ dotenv: 16.4.7
dotenv-expand@12.0.1:
dependencies:
@@ -15034,8 +15092,8 @@ snapshots:
fast-json-stringify@6.0.1:
dependencies:
'@fastify/merge-json-schemas': 0.2.1
- ajv: 8.12.0
- ajv-formats: 3.0.1(ajv@8.12.0)
+ ajv: 8.17.1
+ ajv-formats: 3.0.1(ajv@8.17.1)
fast-uri: 3.0.6
json-schema-ref-resolver: 2.0.1
rfdc: 1.3.1
@@ -15058,7 +15116,7 @@ snapshots:
fastify-plugin@5.0.1: {}
- fastify@5.2.1:
+ fastify@5.3.0:
dependencies:
'@fastify/ajv-compiler': 4.0.2
'@fastify/error': 4.0.0
@@ -15070,10 +15128,10 @@ snapshots:
find-my-way: 9.2.0
light-my-request: 6.6.0
pino: 9.1.0
- process-warning: 4.0.0
+ process-warning: 5.0.0
rfdc: 1.3.1
- secure-json-parse: 3.0.2
- semver: 7.6.3
+ secure-json-parse: 4.0.0
+ semver: 7.7.1
toad-cache: 3.7.0
fastq@1.17.1:
@@ -15088,6 +15146,8 @@ snapshots:
optionalDependencies:
picomatch: 4.0.2
+ fflate@0.8.2: {}
+
figures@3.2.0:
dependencies:
escape-string-regexp: 1.0.5
@@ -15098,6 +15158,15 @@ snapshots:
file-saver@2.0.5: {}
+ file-type@20.4.1:
+ dependencies:
+ '@tokenizer/inflate': 0.2.7
+ strtok3: 10.2.2
+ token-types: 6.0.0
+ uint8array-extras: 1.4.0
+ transitivePeerDependencies:
+ - supports-color
+
filelist@1.0.4:
dependencies:
minimatch: 5.1.6
@@ -16293,6 +16362,8 @@ snapshots:
linkifyjs@4.2.0: {}
+ load-esm@1.0.2: {}
+
loader-runner@4.3.0: {}
local-pkg@0.5.1:
@@ -16529,10 +16600,6 @@ snapshots:
pkg-types: 1.2.1
ufo: 1.5.4
- mnemonist@0.39.8:
- dependencies:
- obliterator: 2.0.4
-
ms@2.1.2: {}
ms@2.1.3: {}
@@ -16571,10 +16638,10 @@ snapshots:
neo-async@2.6.2: {}
- nestjs-kysely@1.1.0(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.10)(kysely@0.27.5)(reflect-metadata@0.2.2):
+ nestjs-kysely@1.1.0(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@11.0.20)(kysely@0.27.5)(reflect-metadata@0.2.2):
dependencies:
- '@nestjs/common': 11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
- '@nestjs/core': 11.0.10(@nestjs/common@11.0.10(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.10)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/common': 11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
+ '@nestjs/core': 11.0.20(@nestjs/common@11.0.20(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@11.0.20)(reflect-metadata@0.2.2)(rxjs@7.8.1)
kysely: 0.27.5
reflect-metadata: 0.2.2
@@ -16748,8 +16815,6 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.0.0
- obliterator@2.0.4: {}
-
obuf@1.1.2: {}
oidc-token-hash@5.0.3: {}
@@ -16919,6 +16984,8 @@ snapshots:
peberminta@0.9.0: {}
+ peek-readable@7.0.0: {}
+
pg-cloudflare@1.1.1:
optional: true
@@ -17128,6 +17195,8 @@ snapshots:
process-warning@4.0.0: {}
+ process-warning@5.0.0: {}
+
process@0.11.10: {}
prompts@2.4.2:
@@ -17703,6 +17772,8 @@ snapshots:
secure-json-parse@3.0.2: {}
+ secure-json-parse@4.0.0: {}
+
selderee@0.11.0:
dependencies:
parseley: 0.12.1
@@ -17958,6 +18029,11 @@ snapshots:
strnum@1.0.5: {}
+ strtok3@10.2.2:
+ dependencies:
+ '@tokenizer/token': 0.3.0
+ peek-readable: 7.0.0
+
styled-jsx@5.1.1(@babel/core@7.24.5)(babel-plugin-macros@3.1.0)(react@18.3.1):
dependencies:
client-only: 0.0.1
@@ -18099,6 +18175,11 @@ snapshots:
toidentifier@1.0.1: {}
+ token-types@6.0.0:
+ dependencies:
+ '@tokenizer/token': 0.3.0
+ ieee754: 1.2.1
+
tough-cookie@5.1.0:
dependencies:
tldts: 6.1.72
@@ -18304,6 +18385,8 @@ snapshots:
dependencies:
'@lukeed/csprng': 1.1.0
+ uint8array-extras@1.4.0: {}
+
unbox-primitive@1.0.2:
dependencies:
call-bind: 1.0.7
From 3430f715ec2c3aec9e81a032edcb5b0d20666662 Mon Sep 17 00:00:00 2001
From: Diego Ochoa <88157175+daoch@users.noreply.github.com>
Date: Tue, 22 Apr 2025 14:47:57 -0500
Subject: [PATCH 28/63] feat: remember and restore previous route when exiting
settings (#1046)
Improves user experience by allowing users to return to the previous
page after visiting the Settings section.
Co-authored-by: Philipinho <16838612+Philipinho@users.noreply.github.com>
---
apps/client/src/App.tsx | 4 +++-
.../settings/atoms/settings-origin-atom.ts | 10 ++++++++++
.../src/components/settings/settings-sidebar.tsx | 12 +++++++++---
apps/client/src/hooks/use-settings-navigation.ts | 14 ++++++++++++++
apps/client/src/hooks/use-track-origin.ts | 16 ++++++++++++++++
5 files changed, 52 insertions(+), 4 deletions(-)
create mode 100644 apps/client/src/components/settings/atoms/settings-origin-atom.ts
create mode 100644 apps/client/src/hooks/use-settings-navigation.ts
create mode 100644 apps/client/src/hooks/use-track-origin.ts
diff --git a/apps/client/src/App.tsx b/apps/client/src/App.tsx
index 4399062f..6fab378c 100644
--- a/apps/client/src/App.tsx
+++ b/apps/client/src/App.tsx
@@ -30,10 +30,12 @@ import SharedPage from "@/pages/share/shared-page.tsx";
import Shares from "@/pages/settings/shares/shares.tsx";
import ShareLayout from "@/features/share/components/share-layout.tsx";
import ShareRedirect from '@/pages/share/share-redirect.tsx';
+import { useTrackOrigin } from "@/hooks/use-track-origin";
export default function App() {
const { t } = useTranslation();
useRedirectToCloudSelect();
+ useTrackOrigin();
return (
<>
@@ -59,7 +61,7 @@ export default function App() {
} />
} />
-
+
} />
} />
diff --git a/apps/client/src/components/settings/atoms/settings-origin-atom.ts b/apps/client/src/components/settings/atoms/settings-origin-atom.ts
new file mode 100644
index 00000000..36ea889b
--- /dev/null
+++ b/apps/client/src/components/settings/atoms/settings-origin-atom.ts
@@ -0,0 +1,10 @@
+import { atom, WritableAtom } from "jotai";
+
+export const settingsOriginAtom: WritableAtom = atom(
+ null,
+ (get, set, newValue) => {
+ if (get(settingsOriginAtom) !== newValue) {
+ set(settingsOriginAtom, newValue);
+ }
+ }
+);
diff --git a/apps/client/src/components/settings/settings-sidebar.tsx b/apps/client/src/components/settings/settings-sidebar.tsx
index 483c0026..79ee511d 100644
--- a/apps/client/src/components/settings/settings-sidebar.tsx
+++ b/apps/client/src/components/settings/settings-sidebar.tsx
@@ -13,7 +13,7 @@ import {
IconKey,
IconWorld,
} from "@tabler/icons-react";
-import { Link, useLocation, useNavigate } from "react-router-dom";
+import { Link, useLocation } from "react-router-dom";
import classes from "./settings.module.css";
import { useTranslation } from "react-i18next";
import { isCloud } from "@/lib/config.ts";
@@ -32,6 +32,7 @@ import {
import AppVersion from "@/components/settings/app-version.tsx";
import { mobileSidebarAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
import { useToggleSidebar } from "@/components/layouts/global/hooks/hooks/use-toggle-sidebar.ts";
+import { useSettingsNavigation } from "@/hooks/use-settings-navigation";
interface DataItem {
label: string;
@@ -105,7 +106,7 @@ export default function SettingsSidebar() {
const { t } = useTranslation();
const location = useLocation();
const [active, setActive] = useState(location.pathname);
- const navigate = useNavigate();
+ const { goBack } = useSettingsNavigation();
const { isAdmin } = useUserRole();
const [workspace] = useAtom(workspaceAtom);
const [mobileSidebarOpened] = useAtom(mobileSidebarAtom);
@@ -210,7 +211,12 @@ export default function SettingsSidebar() {
navigate(-1)}
+ onClick={() => {
+ goBack();
+ if (mobileSidebarOpened) {
+ toggleMobileSidebar();
+ }
+ }}
variant="transparent"
c="gray"
aria-label="Back"
diff --git a/apps/client/src/hooks/use-settings-navigation.ts b/apps/client/src/hooks/use-settings-navigation.ts
new file mode 100644
index 00000000..389445c5
--- /dev/null
+++ b/apps/client/src/hooks/use-settings-navigation.ts
@@ -0,0 +1,14 @@
+import { settingsOriginAtom } from "@/components/settings/atoms/settings-origin-atom";
+import { useAtomValue } from "jotai";
+import { useNavigate } from "react-router-dom";
+
+export function useSettingsNavigation() {
+ const navigate = useNavigate();
+ const origin = useAtomValue(settingsOriginAtom);
+
+ const goBack = () => {
+ navigate(origin ?? "/home", { replace: true });
+ };
+
+ return { goBack };
+}
\ No newline at end of file
diff --git a/apps/client/src/hooks/use-track-origin.ts b/apps/client/src/hooks/use-track-origin.ts
new file mode 100644
index 00000000..089dffbe
--- /dev/null
+++ b/apps/client/src/hooks/use-track-origin.ts
@@ -0,0 +1,16 @@
+import { settingsOriginAtom } from "@/components/settings/atoms/settings-origin-atom";
+import { useAtomValue, useSetAtom } from "jotai";
+import { useEffect } from "react";
+import { useLocation } from "react-router-dom";
+
+export function useTrackOrigin() {
+ const location = useLocation();
+ const setOrigin = useSetAtom(settingsOriginAtom);
+
+ useEffect(() => {
+ const isInSettings = location.pathname.startsWith("/settings");
+ if (!isInSettings) {
+ setOrigin(location.pathname);
+ }
+ }, [location.pathname, setOrigin]);
+}
\ No newline at end of file
From 00d92a369057766bf9cd95be52efec8379a094c2 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 22 Apr 2025 20:57:07 +0100
Subject: [PATCH 29/63] New Crowdin updates (#1008)
* New translations translation.json (Russian)
* New translations translation.json (Russian)
* New translations translation.json (Chinese Simplified)
* New translations translation.json (Spanish)
* New translations translation.json (French)
* New translations translation.json (Spanish)
* New translations translation.json (German)
* New translations translation.json (Italian)
* New translations translation.json (Japanese)
* New translations translation.json (Korean)
* New translations translation.json (Dutch)
* New translations translation.json (Russian)
* New translations translation.json (Chinese Simplified)
* New translations translation.json (English)
* New translations translation.json (Portuguese, Brazilian)
---
.../public/locales/de-DE/translation.json | 23 +++++++++-
.../public/locales/es-ES/translation.json | 25 ++++++++++-
.../public/locales/fr-FR/translation.json | 23 +++++++++-
.../public/locales/it-IT/translation.json | 23 +++++++++-
.../public/locales/ja-JP/translation.json | 23 +++++++++-
.../public/locales/ko-KR/translation.json | 23 +++++++++-
.../public/locales/nl-NL/translation.json | 23 +++++++++-
.../public/locales/pt-BR/translation.json | 23 +++++++++-
.../public/locales/ru-RU/translation.json | 45 ++++++++++++++-----
.../public/locales/zh-CN/translation.json | 25 ++++++++++-
10 files changed, 233 insertions(+), 23 deletions(-)
diff --git a/apps/client/public/locales/de-DE/translation.json b/apps/client/public/locales/de-DE/translation.json
index 294bfa79..3ba481d1 100644
--- a/apps/client/public/locales/de-DE/translation.json
+++ b/apps/client/public/locales/de-DE/translation.json
@@ -362,5 +362,26 @@
"Move page to a different space.": "Seite in einen anderen Bereich verschieben.",
"Real-time editor connection lost. Retrying...": "Echtzeit-Editor-Verbindung verloren. Wiederholen...",
"Table of contents": "Inhaltsverzeichnis",
- "Add headings (H1, H2, H3) to generate a table of contents.": "Fügen Sie Überschriften (H1, H2, H3) hinzu, um ein Inhaltsverzeichnis zu erstellen."
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Fügen Sie Überschriften (H1, H2, H3) hinzu, um ein Inhaltsverzeichnis zu erstellen.",
+ "Share": "Teilen",
+ "Public sharing": "Öffentliches Teilen",
+ "Shared by": "Geteilt von",
+ "Shared at": "Geteilt am",
+ "Inherits public sharing from": "Erbt das öffentliche Teilen von",
+ "Share to web": "Im Web teilen",
+ "Shared to web": "Im Web geteilt",
+ "Anyone with the link can view this page": "Jeder mit dem Link kann diese Seite ansehen",
+ "Make this page publicly accessible": "Diese Seite öffentlich zugänglich machen",
+ "Include sub-pages": "Unterseiten einbeziehen",
+ "Make sub-pages public too": "Unterseiten auch öffentlich machen",
+ "Allow search engines to index page": "Suchmaschinen erlauben, die Seite zu indexieren",
+ "Open page": "Seite öffnen",
+ "Page": "Seite",
+ "Delete public share link": "Öffentlichen Freigabelink löschen",
+ "Delete share": "Freigabe löschen",
+ "Are you sure you want to delete this shared link?": "Möchten Sie diesen Freigabelink wirklich löschen?",
+ "Publicly shared pages from spaces you are a member of will appear here": "Öffentlich geteilte Seiten aus Bereichen, in denen Sie Mitglied sind, erscheinen hier",
+ "Share deleted successfully": "Freigabe erfolgreich gelöscht",
+ "Share not found": "Freigabe nicht gefunden",
+ "Failed to share page": "Fehler beim Teilen der Seite"
}
diff --git a/apps/client/public/locales/es-ES/translation.json b/apps/client/public/locales/es-ES/translation.json
index f17d13d9..eed09b2c 100644
--- a/apps/client/public/locales/es-ES/translation.json
+++ b/apps/client/public/locales/es-ES/translation.json
@@ -94,7 +94,7 @@
"Invited members will be granted access to spaces the groups can access": "Los miembros invitados recibirán acceso a los espacios a los que los grupos pueden acceder",
"Join the workspace": "Unirse al espacio de trabajo",
"Language": "Idioma",
- "Light": "Ligero",
+ "Light": "Claro",
"Link copied": "Enlace copiado",
"Login": "Iniciar sesión",
"Logout": "Cerrar sesión",
@@ -362,5 +362,26 @@
"Move page to a different space.": "Mover página a un espacio diferente.",
"Real-time editor connection lost. Retrying...": "Conexión del editor en tiempo real perdida. Reintentando...",
"Table of contents": "Índice de contenidos",
- "Add headings (H1, H2, H3) to generate a table of contents.": "Añadir encabezados (H1, H2, H3) para generar un índice de contenidos."
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Añadir encabezados (H1, H2, H3) para generar un índice de contenidos.",
+ "Share": "Compartir",
+ "Public sharing": "Compartición pública",
+ "Shared by": "Compartido por",
+ "Shared at": "Compartido en",
+ "Inherits public sharing from": "Hereda la compartición pública de",
+ "Share to web": "Compartir en la web",
+ "Shared to web": "Compartido en la web",
+ "Anyone with the link can view this page": "Cualquiera con el enlace puede ver esta página",
+ "Make this page publicly accessible": "Hacer esta página accesible públicamente",
+ "Include sub-pages": "Incluir subpáginas",
+ "Make sub-pages public too": "Hacer públicas también las subpáginas",
+ "Allow search engines to index page": "Permitir a los motores de búsqueda indexar la página",
+ "Open page": "Abrir página",
+ "Page": "Página",
+ "Delete public share link": "Eliminar enlace de compartición pública",
+ "Delete share": "Eliminar compartición",
+ "Are you sure you want to delete this shared link?": "¿Está seguro de que desea eliminar este enlace compartido?",
+ "Publicly shared pages from spaces you are a member of will appear here": "Las páginas compartidas públicamente de los espacios a los que pertenece aparecerán aquí",
+ "Share deleted successfully": "Compartición eliminada con éxito",
+ "Share not found": "Compartición no encontrada",
+ "Failed to share page": "Error al compartir la página"
}
diff --git a/apps/client/public/locales/fr-FR/translation.json b/apps/client/public/locales/fr-FR/translation.json
index 408ff420..4a8b32f7 100644
--- a/apps/client/public/locales/fr-FR/translation.json
+++ b/apps/client/public/locales/fr-FR/translation.json
@@ -362,5 +362,26 @@
"Move page to a different space.": "Déplacer la page vers un autre espace.",
"Real-time editor connection lost. Retrying...": "Connexion avec l'éditeur en temps réel perdue. Nouvelle tentative...",
"Table of contents": "",
- "Add headings (H1, H2, H3) to generate a table of contents.": "Ajoutez des titres (H1, H2, H3) pour générer une table des matières."
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Ajoutez des titres (H1, H2, H3) pour générer une table des matières.",
+ "Share": "Partager",
+ "Public sharing": "Partage public",
+ "Shared by": "Partagé par",
+ "Shared at": "Partagé à",
+ "Inherits public sharing from": "Hérite du partage public de",
+ "Share to web": "Partager sur le web",
+ "Shared to web": "Partagé sur le web",
+ "Anyone with the link can view this page": "Toute personne avec le lien peut voir cette page",
+ "Make this page publicly accessible": "Rendre cette page accessible au public",
+ "Include sub-pages": "Inclure les sous-pages",
+ "Make sub-pages public too": "Rendre également les sous-pages publiques",
+ "Allow search engines to index page": "Autoriser les moteurs de recherche à indexer la page",
+ "Open page": "Ouvrir la page",
+ "Page": "Page",
+ "Delete public share link": "Supprimer le lien de partage public",
+ "Delete share": "Supprimer le partage",
+ "Are you sure you want to delete this shared link?": "Êtes-vous sûr de vouloir supprimer ce lien partagé ?",
+ "Publicly shared pages from spaces you are a member of will appear here": "Les pages partagées publiquement des espaces dont vous êtes membre apparaîtront ici",
+ "Share deleted successfully": "Partage supprimé avec succès",
+ "Share not found": "Partage non trouvé",
+ "Failed to share page": "Échec du partage de la page"
}
diff --git a/apps/client/public/locales/it-IT/translation.json b/apps/client/public/locales/it-IT/translation.json
index b92377c7..28eb6771 100644
--- a/apps/client/public/locales/it-IT/translation.json
+++ b/apps/client/public/locales/it-IT/translation.json
@@ -362,5 +362,26 @@
"Move page to a different space.": "Sposta la pagina in un altro spazio.",
"Real-time editor connection lost. Retrying...": "Connessione all'editor in tempo reale persa. Riprovo...",
"Table of contents": "Indice dei contenuti",
- "Add headings (H1, H2, H3) to generate a table of contents.": "Aggiungi intestazioni (H1, H2, H3) per generare un sommario."
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Aggiungi intestazioni (H1, H2, H3) per generare un sommario.",
+ "Share": "Condividi",
+ "Public sharing": "Condivisione pubblica",
+ "Shared by": "Condiviso da",
+ "Shared at": "Condiviso il",
+ "Inherits public sharing from": "Eredita la condivisione pubblica da",
+ "Share to web": "Condividi su web",
+ "Shared to web": "Condiviso su web",
+ "Anyone with the link can view this page": "Chiunque abbia il link può visualizzare questa pagina",
+ "Make this page publicly accessible": "Rendi questa pagina accessibile pubblicamente",
+ "Include sub-pages": "Includi sotto-pagine",
+ "Make sub-pages public too": "Rendi pubbliche anche le sotto-pagine",
+ "Allow search engines to index page": "Permetti ai motori di ricerca di indicizzare la pagina",
+ "Open page": "Apri pagina",
+ "Page": "Pagina",
+ "Delete public share link": "Elimina il link di condivisione pubblica",
+ "Delete share": "Elimina condivisione",
+ "Are you sure you want to delete this shared link?": "Sei sicuro di voler eliminare questo link condiviso?",
+ "Publicly shared pages from spaces you are a member of will appear here": "Le pagine condivise pubblicamente dagli spazi di cui sei membro appariranno qui",
+ "Share deleted successfully": "Condivisione eliminata con successo",
+ "Share not found": "Condivisione non trovata",
+ "Failed to share page": "Condivisione della pagina fallita"
}
diff --git a/apps/client/public/locales/ja-JP/translation.json b/apps/client/public/locales/ja-JP/translation.json
index cc6141c4..cba12e63 100644
--- a/apps/client/public/locales/ja-JP/translation.json
+++ b/apps/client/public/locales/ja-JP/translation.json
@@ -362,5 +362,26 @@
"Move page to a different space.": "ページを別のスペースに移動します。",
"Real-time editor connection lost. Retrying...": "リアルタイムエディターの接続が失われました。再試行しています…",
"Table of contents": "目次",
- "Add headings (H1, H2, H3) to generate a table of contents.": "見出し(H1、H2、H3)を追加して目次を生成します。"
+ "Add headings (H1, H2, H3) to generate a table of contents.": "見出し(H1、H2、H3)を追加して目次を生成します。",
+ "Share": "共有",
+ "Public sharing": "公開共有",
+ "Shared by": "共有者",
+ "Shared at": "共有日時",
+ "Inherits public sharing from": "から公開共有を継承する",
+ "Share to web": "ウェブで共有",
+ "Shared to web": "ウェブに共有済み",
+ "Anyone with the link can view this page": "リンクを持っている人はこのページを閲覧できます",
+ "Make this page publicly accessible": "このページを公開します",
+ "Include sub-pages": "サブページを含む",
+ "Make sub-pages public too": "サブページも公開する",
+ "Allow search engines to index page": "検索エンジンにページのインデックス作成を許可する",
+ "Open page": "ページを開く",
+ "Page": "ページ",
+ "Delete public share link": "公開リンクを削除",
+ "Delete share": "共有を削除",
+ "Are you sure you want to delete this shared link?": "この共有リンクを削除してもよろしいですか?",
+ "Publicly shared pages from spaces you are a member of will appear here": "メンバーであるスペースからの公開ページがここに表示されます",
+ "Share deleted successfully": "共有が正常に削除されました",
+ "Share not found": "共有が見つかりません",
+ "Failed to share page": "ページの共有に失敗しました"
}
diff --git a/apps/client/public/locales/ko-KR/translation.json b/apps/client/public/locales/ko-KR/translation.json
index 1e87c62e..fd8db95b 100644
--- a/apps/client/public/locales/ko-KR/translation.json
+++ b/apps/client/public/locales/ko-KR/translation.json
@@ -362,5 +362,26 @@
"Move page to a different space.": "페이지를 다른 공간으로 이동합니다.",
"Real-time editor connection lost. Retrying...": "실시간 편집기 연결이 끊어졌습니다. 재시도 중...",
"Table of contents": "목차",
- "Add headings (H1, H2, H3) to generate a table of contents.": "목차를 생성하려면 제목 (H1, H2, H3)을 추가하세요."
+ "Add headings (H1, H2, H3) to generate a table of contents.": "목차를 생성하려면 제목 (H1, H2, H3)을 추가하세요.",
+ "Share": "공유",
+ "Public sharing": "공개 공유",
+ "Shared by": "공유자",
+ "Shared at": "공유 시간",
+ "Inherits public sharing from": "로부터 공개 공유를 상속함",
+ "Share to web": "웹에 공유",
+ "Shared to web": "웹에 공유됨",
+ "Anyone with the link can view this page": "링크가 있는 사람은 이 페이지를 볼 수 있습니다",
+ "Make this page publicly accessible": "이 페이지를 공개적으로 접근 가능하게 만들기",
+ "Include sub-pages": "하위 페이지 포함",
+ "Make sub-pages public too": "하위 페이지도 공개로 설정",
+ "Allow search engines to index page": "검색 엔진이 페이지를 색인할 수 있도록 허용",
+ "Open page": "페이지 열기",
+ "Page": "페이지",
+ "Delete public share link": "공유 링크 삭제",
+ "Delete share": "공유 삭제",
+ "Are you sure you want to delete this shared link?": "이 공유 링크를 삭제하시겠습니까?",
+ "Publicly shared pages from spaces you are a member of will appear here": "회원인 공간의 공개 공유된 페이지가 여기에 표시됩니다",
+ "Share deleted successfully": "공유가 성공적으로 삭제되었습니다",
+ "Share not found": "공유를 찾을 수 없습니다",
+ "Failed to share page": "페이지 공유에 실패했습니다"
}
diff --git a/apps/client/public/locales/nl-NL/translation.json b/apps/client/public/locales/nl-NL/translation.json
index dba2ee9a..1879078e 100644
--- a/apps/client/public/locales/nl-NL/translation.json
+++ b/apps/client/public/locales/nl-NL/translation.json
@@ -362,5 +362,26 @@
"Move page to a different space.": "Verplaats pagina naar een andere ruimte.",
"Real-time editor connection lost. Retrying...": "Realtime editorverbinding verloren. Opnieuw proberen...",
"Table of contents": "Inhoudsopgave",
- "Add headings (H1, H2, H3) to generate a table of contents.": "Voeg koppen (H1, H2, H3) toe om een inhoudsopgave te genereren."
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Voeg koppen (H1, H2, H3) toe om een inhoudsopgave te genereren.",
+ "Share": "Delen",
+ "Public sharing": "Openbaar delen",
+ "Shared by": "Gedeeld door",
+ "Shared at": "Gedeeld op",
+ "Inherits public sharing from": "Erft openbaar delen van",
+ "Share to web": "Delen naar web",
+ "Shared to web": "Gedeeld naar web",
+ "Anyone with the link can view this page": "Iedereen met de link kan deze pagina bekijken",
+ "Make this page publicly accessible": "Maak deze pagina openbaar toegankelijk",
+ "Include sub-pages": "Inclusief subpagina's",
+ "Make sub-pages public too": "Maak subpagina's ook openbaar",
+ "Allow search engines to index page": "Sta zoekmachines toe om pagina te indexeren",
+ "Open page": "Pagina openen",
+ "Page": "Pagina",
+ "Delete public share link": "Verwijder openbare deel-link",
+ "Delete share": "Verwijder deel",
+ "Are you sure you want to delete this shared link?": "Weet u zeker dat u deze gedeelde link wilt verwijderen?",
+ "Publicly shared pages from spaces you are a member of will appear here": "Openbaar gedeelde pagina's van ruimtes waarvan u lid bent, verschijnen hier",
+ "Share deleted successfully": "Delen succesvol verwijderd",
+ "Share not found": "Delen niet gevonden",
+ "Failed to share page": "Pagina delen mislukt"
}
diff --git a/apps/client/public/locales/pt-BR/translation.json b/apps/client/public/locales/pt-BR/translation.json
index 526d298f..0986a2b7 100644
--- a/apps/client/public/locales/pt-BR/translation.json
+++ b/apps/client/public/locales/pt-BR/translation.json
@@ -362,5 +362,26 @@
"Move page to a different space.": "Mover página para um espaço diferente.",
"Real-time editor connection lost. Retrying...": "Conexão do editor em tempo real perdida. Tentando novamente...",
"Table of contents": "Tabela de conteúdos",
- "Add headings (H1, H2, H3) to generate a table of contents.": "Adicionar títulos (H1, H2, H3) para gerar uma tabela de conteúdo."
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Adicionar títulos (H1, H2, H3) para gerar uma tabela de conteúdo.",
+ "Share": "Compartilhar",
+ "Public sharing": "Compartilhamento público",
+ "Shared by": "Compartilhado por",
+ "Shared at": "Compartilhado em",
+ "Inherits public sharing from": "Herdado do compartilhamento público de",
+ "Share to web": "Compartilhar na web",
+ "Shared to web": "Compartilhado na web",
+ "Anyone with the link can view this page": "Qualquer um com o link pode ver esta página",
+ "Make this page publicly accessible": "Tornar esta página publicamente acessível",
+ "Include sub-pages": "Incluir sub-páginas",
+ "Make sub-pages public too": "Tornar as sub-páginas públicas também",
+ "Allow search engines to index page": "Permitir que mecanismos de busca indexem a página",
+ "Open page": "Abrir página",
+ "Page": "Página",
+ "Delete public share link": "Excluir o link público compartilhado",
+ "Delete share": "Excluir compartilhamento",
+ "Are you sure you want to delete this shared link?": "Tem certeza de que deseja excluir este link compartilhado?",
+ "Publicly shared pages from spaces you are a member of will appear here": "Páginas compartilhadas publicamente de espaços que você é membro aparecerão aqui",
+ "Share deleted successfully": "Compartilhamento excluído com sucesso",
+ "Share not found": "Compartilhamento não encontrado",
+ "Failed to share page": "Falha ao compartilhar página"
}
diff --git a/apps/client/public/locales/ru-RU/translation.json b/apps/client/public/locales/ru-RU/translation.json
index dce96d80..27105bfc 100644
--- a/apps/client/public/locales/ru-RU/translation.json
+++ b/apps/client/public/locales/ru-RU/translation.json
@@ -13,11 +13,11 @@
"Are you sure you want to remove this user from the group? The user will lose access to resources this group has access to.": "Вы уверены, что хотите удалить этого пользователя из группы? Пользователь потеряет доступ к материалам, к которым у этой группы есть доступ.",
"Are you sure you want to remove this user from the space? The user will lose all access to this space.": "Вы уверены, что хотите удалить этого пользователя из пространства? Пользователь потеряет весь доступ к этому пространству.",
"Are you sure you want to restore this version? Any changes not versioned will be lost.": "Вы уверены, что хотите восстановить эту версию? Все не зафиксированные изменения будут потеряны.",
- "Can become members of groups and spaces in workspace": "Могут становиться участниками групп и пространств в рабочем пространстве",
+ "Can become members of groups and spaces in workspace": "Могут становиться участниками групп и пространств в рабочей области",
"Can create and edit pages in space.": "Может создавать и редактировать страницы в пространстве.",
"Can edit": "Может изменять",
- "Can manage workspace": "Может управлять рабочим пространством",
- "Can manage workspace but cannot delete it": "Может управлять рабочим пространством, но не может его удалить",
+ "Can manage workspace": "Может управлять рабочей областью",
+ "Can manage workspace but cannot delete it": "Может управлять рабочей областью, но не может ее удалить",
"Can view": "Может просматривать",
"Can view pages in space but not edit.": "Может просматривать страницы в пространстве, но не может их редактировать.",
"Cancel": "Отменить",
@@ -34,7 +34,7 @@
"Create group": "Создать группу",
"Create page": "Создать страницу",
"Create space": "Создать пространство",
- "Create workspace": "Создать рабочее пространство",
+ "Create workspace": "Создать рабочую область",
"Current password": "Текущий пароль",
"Dark": "Темная",
"Date": "Дата",
@@ -92,7 +92,7 @@
"Invite new members": "Пригласить новых участников",
"Invited members who are yet to accept their invitation will appear here.": "Приглашённые участники, которые ещё не приняли приглашение, появятся здесь.",
"Invited members will be granted access to spaces the groups can access": "Приглашённые участники получат доступ к пространствам, доступ к которым есть у группы",
- "Join the workspace": "Присоединиться к рабочему пространству",
+ "Join the workspace": "Присоединиться к рабочей области",
"Language": "Язык",
"Light": "Светлая",
"Link copied": "Ссылка скопирована",
@@ -150,7 +150,7 @@
"Send invitation": "Отправить приглашение",
"Invitation sent": "Приглашение отправлено",
"Settings": "Настройки",
- "Setup workspace": "Настроить рабочее пространство",
+ "Setup workspace": "Настроить рабочую область",
"Sign In": "Вход",
"Sign Up": "Регистрация",
"Slug": "Slug",
@@ -177,9 +177,9 @@
"Untitled": "Без названия",
"Updated successfully": "Обновлено успешно",
"User": "Пользователь",
- "Workspace": "Рабочее пространство",
- "Workspace Name": "Имя рабочего пространства",
- "Workspace settings": "Настройки рабочего пространства",
+ "Workspace": "Рабочая область",
+ "Workspace Name": "Имя рабочей области",
+ "Workspace settings": "Настройки рабочей области",
"You can change your password here.": "Вы можете изменить свой пароль здесь.",
"Your Email": "Ваш адрес электронной почты",
"Your import is complete.": "Ваш импорт завершен.",
@@ -217,9 +217,9 @@
"Revoke invitation": "Отозвать приглашение",
"Revoke": "Отозвать",
"Don't": "Нет",
- "Are you sure you want to revoke this invitation? The user will not be able to join the workspace.": "Вы уверены, что хотите отозвать это приглашение? Пользователь не сможет присоединиться к рабочему пространству.",
+ "Are you sure you want to revoke this invitation? The user will not be able to join the workspace.": "Вы уверены, что хотите отозвать это приглашение? Пользователь не сможет присоединиться к рабочей области.",
"Resend invitation": "Отправить приглашение повторно",
- "Anyone with this link can join this workspace.": "Любой, у кого есть эта ссылка, может присоединиться к этому рабочему пространству.",
+ "Anyone with this link can join this workspace.": "Любой, у кого есть данная ссылка, может присоединиться к этой рабочей области.",
"Invite link": "Ссылка для приглашения",
"Copy": "Копировать",
"Copied": "Скопировано",
@@ -362,5 +362,26 @@
"Move page to a different space.": "Переместите страницу в другое пространство.",
"Real-time editor connection lost. Retrying...": "Соединение с редактором в реальном времени потеряно. Повторная попытка...",
"Table of contents": "Содержание",
- "Add headings (H1, H2, H3) to generate a table of contents.": "Добавьте заголовки (H1, H2, H3), чтобы создать оглавление."
+ "Add headings (H1, H2, H3) to generate a table of contents.": "Добавьте заголовки (H1, H2, H3), чтобы создать оглавление.",
+ "Share": "Поделиться",
+ "Public sharing": "Общий доступ",
+ "Shared by": "Поделился",
+ "Shared at": "Поделился в",
+ "Inherits public sharing from": "Наследует общий доступ от",
+ "Share to web": "Поделиться в интернете",
+ "Shared to web": "Размещено в интернете",
+ "Anyone with the link can view this page": "Любой, у кого есть ссылка, может просмотреть эту страницу",
+ "Make this page publicly accessible": "Сделать эту страницу общедоступной",
+ "Include sub-pages": "Включить подстраницы",
+ "Make sub-pages public too": "Сделать подстраницы также общедоступными",
+ "Allow search engines to index page": "Разрешить поисковым системам индексировать страницу",
+ "Open page": "Открыть страницу",
+ "Page": "Страница",
+ "Delete public share link": "Удалить ссылку на общий доступ",
+ "Delete share": "Удалить общий доступ",
+ "Are you sure you want to delete this shared link?": "Вы уверены, что хотите удалить эту ссылку общего доступа?",
+ "Publicly shared pages from spaces you are a member of will appear here": "Общие страницы из пространств, участником которых вы являетесь, появятся здесь",
+ "Share deleted successfully": "Общий доступ успешно удален",
+ "Share not found": "Общий доступ не найден",
+ "Failed to share page": "Не удалось поделиться страницей"
}
diff --git a/apps/client/public/locales/zh-CN/translation.json b/apps/client/public/locales/zh-CN/translation.json
index 9763c602..94c3007c 100644
--- a/apps/client/public/locales/zh-CN/translation.json
+++ b/apps/client/public/locales/zh-CN/translation.json
@@ -298,7 +298,7 @@
"Heading 2": "2 级标题",
"Heading 3": "3 级标题",
"To-do List": "代办列表",
- "Bullet List": "无需列表",
+ "Bullet List": "无序列表",
"Numbered List": "有序列表",
"Blockquote": "引用块",
"Just start typing with plain text.": "只需开始键入纯文本",
@@ -362,5 +362,26 @@
"Move page to a different space.": "将页面移动到不同的空间。",
"Real-time editor connection lost. Retrying...": "实时编辑器连接丢失。重试中……",
"Table of contents": "目录",
- "Add headings (H1, H2, H3) to generate a table of contents.": "添加标题(H1,H2,H3)以生成目录。"
+ "Add headings (H1, H2, H3) to generate a table of contents.": "添加标题(H1,H2,H3)以生成目录。",
+ "Share": "分享",
+ "Public sharing": "公开分享",
+ "Shared by": "分享者",
+ "Shared at": "分享时间",
+ "Inherits public sharing from": "继承自的公开分享",
+ "Share to web": "分享到网页",
+ "Shared to web": "已分享到网页",
+ "Anyone with the link can view this page": "任何有链接的人都可以查看此页面",
+ "Make this page publicly accessible": "使此页面可公开访问",
+ "Include sub-pages": "包括子页面",
+ "Make sub-pages public too": "将子页面也设为公开",
+ "Allow search engines to index page": "允许搜索引擎索引页面",
+ "Open page": "打开页面",
+ "Page": "页面",
+ "Delete public share link": "删除公开分享链接",
+ "Delete share": "删除分享",
+ "Are you sure you want to delete this shared link?": "您确定要删除此分享链接吗?",
+ "Publicly shared pages from spaces you are a member of will appear here": "您所在空间的公开共享页面会显示在此处",
+ "Share deleted successfully": "分享已成功删除",
+ "Share not found": "未找到分享",
+ "Failed to share page": "页面分享失败"
}
From acffeacdbcb408b7d152b3619f93c404c1907fd5 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 22 Apr 2025 22:47:34 +0100
Subject: [PATCH 30/63] fix TOC
---
apps/client/src/features/share/components/share-shell.tsx | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/apps/client/src/features/share/components/share-shell.tsx b/apps/client/src/features/share/components/share-shell.tsx
index 82863b34..799958d2 100644
--- a/apps/client/src/features/share/components/share-shell.tsx
+++ b/apps/client/src/features/share/components/share-shell.tsx
@@ -55,19 +55,15 @@ export default function ShareShell({
const readOnlyEditor = useAtomValue(readOnlyEditorAtom);
const [navbarOutside, setNavbarOutside] = useState(null);
- const [asideOutside, setAsideOutside] = useState(null);
useClickOutside(
() => {
if (mobileOpened) {
toggleMobile();
}
- if (mobileTocOpened) {
- toggleTocMobile();
- }
},
null,
- [navbarOutside, asideOutside],
+ [navbarOutside],
);
return (
@@ -181,7 +177,6 @@ export default function ShareShell({
p="md"
withBorder={mobileTocOpened}
className={classes.aside}
- ref={setAsideOutside}
>
From 0ec3ff2965880db3d1775b2015f0c684e76a6adc Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 22 Apr 2025 22:48:12 +0100
Subject: [PATCH 31/63] Add empty placeholder text
---
.../components/table-of-contents/table-of-contents.tsx | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/apps/client/src/features/editor/components/table-of-contents/table-of-contents.tsx b/apps/client/src/features/editor/components/table-of-contents/table-of-contents.tsx
index b309d67d..123889f3 100644
--- a/apps/client/src/features/editor/components/table-of-contents/table-of-contents.tsx
+++ b/apps/client/src/features/editor/components/table-of-contents/table-of-contents.tsx
@@ -143,6 +143,12 @@ export const TableOfContents: FC
= (props) => {
{t("Add headings (H1, H2, H3) to generate a table of contents.")}
)}
+
+ {props.isShare && (
+
+ {t("No table of contents.")}
+
+ )}
>
);
}
From de5f90309c5dd3e0615bab3a3ec910422967609e Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 22 Apr 2025 22:49:45 +0100
Subject: [PATCH 32/63] v0.20.0
---
apps/client/package.json | 2 +-
apps/server/package.json | 2 +-
package.json | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/client/package.json b/apps/client/package.json
index ffd94cae..e56b7e68 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -1,7 +1,7 @@
{
"name": "client",
"private": true,
- "version": "0.10.2",
+ "version": "0.20.0",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
diff --git a/apps/server/package.json b/apps/server/package.json
index efd8d8ca..935647ed 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -1,6 +1,6 @@
{
"name": "server",
- "version": "0.10.2",
+ "version": "0.20.0",
"description": "",
"author": "",
"private": true,
diff --git a/package.json b/package.json
index d84046e5..0cafcc3f 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "docmost",
"homepage": "https://docmost.com",
- "version": "0.10.2",
+ "version": "0.20.0",
"private": true,
"scripts": {
"build": "nx run-many -t build",
From c26a851d52394e5c01717bf8674ae953ed7080e8 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 23 Apr 2025 14:32:35 +0100
Subject: [PATCH 33/63] feat: enhance public sharing (#1057)
* fix tree nodes sort
* remove comment mark in shares
* remove clickoutside hook for now
* feat: search in shared pages
* fix user-select
* use Link
* render page icons
---
.../components/search-control.module.css | 44 ++++++++++
.../search/components/search-control.tsx | 56 ++++++++++++
apps/client/src/features/search/constants.ts | 7 ++
.../features/search/queries/search-query.ts | 11 +++
.../src/features/search/search-spotlight.tsx | 21 ++---
.../search/services/search-service.ts | 7 ++
.../search/share-search-spotlight.tsx | 87 +++++++++++++++++++
.../src/features/search/types/search.types.ts | 1 +
.../features/share/components/share-shell.tsx | 46 +++++-----
.../features/share/components/shared-tree.tsx | 16 ++++
apps/client/src/features/share/utils.ts | 20 +++--
.../components/sidebar/space-sidebar.tsx | 12 +--
.../src/common/helpers/prosemirror/utils.ts | 13 +++
apps/server/src/core/search/dto/search.dto.ts | 17 ++++
.../src/core/search/search.controller.ts | 42 +++++++--
apps/server/src/core/search/search.service.ts | 71 +++++++++++++--
apps/server/src/core/share/share.service.ts | 10 +--
17 files changed, 420 insertions(+), 61 deletions(-)
create mode 100644 apps/client/src/features/search/components/search-control.module.css
create mode 100644 apps/client/src/features/search/components/search-control.tsx
create mode 100644 apps/client/src/features/search/constants.ts
create mode 100644 apps/client/src/features/search/share-search-spotlight.tsx
diff --git a/apps/client/src/features/search/components/search-control.module.css b/apps/client/src/features/search/components/search-control.module.css
new file mode 100644
index 00000000..5e5a9c26
--- /dev/null
+++ b/apps/client/src/features/search/components/search-control.module.css
@@ -0,0 +1,44 @@
+.root {
+ height: 34px;
+ padding-left: var(--mantine-spacing-sm);
+ padding-right: 4px;
+ border-radius: var(--mantine-radius-md);
+ color: var(--mantine-color-placeholder);
+ border: 1px solid;
+
+ @mixin light {
+ border-color: var(--mantine-color-gray-3);
+ background-color: var(--mantine-color-white);
+ }
+
+ @mixin dark {
+ border-color: var(--mantine-color-dark-4);
+ background-color: var(--mantine-color-dark-6);
+ }
+
+ @mixin rtl {
+ padding-left: 4px;
+ padding-right: var(--mantine-spacing-sm);
+ }
+}
+
+.shortcut {
+ font-size: 11px;
+ line-height: 1;
+ padding: 4px 7px;
+ border-radius: var(--mantine-radius-sm);
+ border: 1px solid;
+ font-weight: bold;
+
+ @mixin light {
+ color: var(--mantine-color-gray-7);
+ border-color: var(--mantine-color-gray-2);
+ background-color: var(--mantine-color-gray-0);
+ }
+
+ @mixin dark {
+ color: var(--mantine-color-dark-0);
+ border-color: var(--mantine-color-dark-7);
+ background-color: var(--mantine-color-dark-7);
+ }
+}
\ No newline at end of file
diff --git a/apps/client/src/features/search/components/search-control.tsx b/apps/client/src/features/search/components/search-control.tsx
new file mode 100644
index 00000000..3ae74da2
--- /dev/null
+++ b/apps/client/src/features/search/components/search-control.tsx
@@ -0,0 +1,56 @@
+import { IconSearch } from "@tabler/icons-react";
+import cx from "clsx";
+import {
+ ActionIcon,
+ BoxProps,
+ ElementProps,
+ Group,
+ rem,
+ Text,
+ Tooltip,
+ UnstyledButton,
+} from "@mantine/core";
+import classes from "./search-control.module.css";
+import React from "react";
+import { useTranslation } from "react-i18next";
+
+interface SearchControlProps extends BoxProps, ElementProps<"button"> {}
+
+export function SearchControl({ className, ...others }: SearchControlProps) {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+
+ {t("Search")}
+
+
+ Ctrl + K
+
+
+
+ );
+}
+
+interface SearchMobileControlProps {
+ onSearch: () => void;
+}
+
+export function SearchMobileControl({ onSearch }: SearchMobileControlProps) {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/apps/client/src/features/search/constants.ts b/apps/client/src/features/search/constants.ts
new file mode 100644
index 00000000..a4c6c2f7
--- /dev/null
+++ b/apps/client/src/features/search/constants.ts
@@ -0,0 +1,7 @@
+import { createSpotlight } from '@mantine/spotlight';
+
+export const [searchSpotlightStore, searchSpotlight] = createSpotlight();
+
+export const [shareSearchSpotlightStore, shareSearchSpotlight] =
+ createSpotlight();
+
diff --git a/apps/client/src/features/search/queries/search-query.ts b/apps/client/src/features/search/queries/search-query.ts
index 2505e7a2..6b8c0296 100644
--- a/apps/client/src/features/search/queries/search-query.ts
+++ b/apps/client/src/features/search/queries/search-query.ts
@@ -1,6 +1,7 @@
import { useQuery, UseQueryResult } from "@tanstack/react-query";
import {
searchPage,
+ searchShare,
searchSuggestions,
} from "@/features/search/services/search-service";
import {
@@ -30,3 +31,13 @@ export function useSearchSuggestionsQuery(
enabled: !!params.query,
});
}
+
+export function useShareSearchQuery(
+ params: IPageSearchParams,
+): UseQueryResult {
+ return useQuery({
+ queryKey: ["share-search", params],
+ queryFn: () => searchShare(params),
+ enabled: !!params.query,
+ });
+}
diff --git a/apps/client/src/features/search/search-spotlight.tsx b/apps/client/src/features/search/search-spotlight.tsx
index 52e24557..581524fc 100644
--- a/apps/client/src/features/search/search-spotlight.tsx
+++ b/apps/client/src/features/search/search-spotlight.tsx
@@ -2,36 +2,36 @@ import { Group, Center, Text } from "@mantine/core";
import { Spotlight } from "@mantine/spotlight";
import { IconSearch } from "@tabler/icons-react";
import React, { useState } from "react";
-import { useNavigate } from "react-router-dom";
+import { Link } from "react-router-dom";
import { useDebouncedValue } from "@mantine/hooks";
import { usePageSearchQuery } from "@/features/search/queries/search-query";
import { buildPageUrl } from "@/features/page/page.utils.ts";
import { getPageIcon } from "@/lib";
import { useTranslation } from "react-i18next";
+import { searchSpotlightStore } from "./constants";
interface SearchSpotlightProps {
spaceId?: string;
}
export function SearchSpotlight({ spaceId }: SearchSpotlightProps) {
const { t } = useTranslation();
- const navigate = useNavigate();
const [query, setQuery] = useState("");
const [debouncedSearchQuery] = useDebouncedValue(query, 300);
- const {
- data: searchResults,
- isLoading,
- error,
- } = usePageSearchQuery({ query: debouncedSearchQuery, spaceId });
+ const { data: searchResults } = usePageSearchQuery({
+ query: debouncedSearchQuery,
+ spaceId,
+ });
const pages = (
searchResults && searchResults.length > 0 ? searchResults : []
).map((page) => (
- navigate(buildPageUrl(page.space.slug, page.slugId, page.title))
- }
+ component={Link}
+ //@ts-ignore
+ to={buildPageUrl(page.space.slug, page.slugId, page.title)}
+ style={{ userSelect: "none" }}
>
{getPageIcon(page?.icon)}
@@ -54,6 +54,7 @@ export function SearchSpotlight({ spaceId }: SearchSpotlightProps) {
return (
<>
("/search/suggest", params);
return req.data;
}
+
+export async function searchShare(
+ params: IPageSearchParams,
+): Promise {
+ const req = await api.post("/search/share-search", params);
+ return req.data;
+}
diff --git a/apps/client/src/features/search/share-search-spotlight.tsx b/apps/client/src/features/search/share-search-spotlight.tsx
new file mode 100644
index 00000000..bfbced6e
--- /dev/null
+++ b/apps/client/src/features/search/share-search-spotlight.tsx
@@ -0,0 +1,87 @@
+import { Group, Center, Text } from "@mantine/core";
+import { Spotlight } from "@mantine/spotlight";
+import { IconSearch } from "@tabler/icons-react";
+import React, { useState } from "react";
+import { Link } from "react-router-dom";
+import { useDebouncedValue } from "@mantine/hooks";
+import { useShareSearchQuery } from "@/features/search/queries/search-query";
+import { buildSharedPageUrl } from "@/features/page/page.utils.ts";
+import { getPageIcon } from "@/lib";
+import { useTranslation } from "react-i18next";
+import { shareSearchSpotlightStore } from "@/features/search/constants.ts";
+
+interface ShareSearchSpotlightProps {
+ shareId?: string;
+}
+export function ShareSearchSpotlight({ shareId }: ShareSearchSpotlightProps) {
+ const { t } = useTranslation();
+ const [query, setQuery] = useState("");
+ const [debouncedSearchQuery] = useDebouncedValue(query, 300);
+
+ const { data: searchResults } = useShareSearchQuery({
+ query: debouncedSearchQuery,
+ shareId,
+ });
+
+ const pages = (
+ searchResults && searchResults.length > 0 ? searchResults : []
+ ).map((page) => (
+
+
+ {getPageIcon(page?.icon)}
+
+
+ {page.title}
+
+ {page?.highlight && (
+
+ )}
+
+
+
+ ));
+
+ return (
+ <>
+
+ }
+ />
+
+ {query.length === 0 && pages.length === 0 && (
+ {t("Start typing to search...")}
+ )}
+
+ {query.length > 0 && pages.length === 0 && (
+ {t("No results found...")}
+ )}
+
+ {pages.length > 0 && pages}
+
+
+ >
+ );
+}
diff --git a/apps/client/src/features/search/types/search.types.ts b/apps/client/src/features/search/types/search.types.ts
index 5a346f6b..1338e121 100644
--- a/apps/client/src/features/search/types/search.types.ts
+++ b/apps/client/src/features/search/types/search.types.ts
@@ -35,4 +35,5 @@ export interface ISuggestionResult {
export interface IPageSearchParams {
query: string;
spaceId?: string;
+ shareId?: string;
}
diff --git a/apps/client/src/features/share/components/share-shell.tsx b/apps/client/src/features/share/components/share-shell.tsx
index 799958d2..7fa0c941 100644
--- a/apps/client/src/features/share/components/share-shell.tsx
+++ b/apps/client/src/features/share/components/share-shell.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from "react";
+import React from "react";
import {
ActionIcon,
Affix,
@@ -30,7 +30,12 @@ import {
import { IconList } from "@tabler/icons-react";
import { useToggleToc } from "@/features/share/hooks/use-toggle-toc.ts";
import classes from "./share.module.css";
-import { useClickOutside } from "@mantine/hooks";
+import {
+ SearchControl,
+ SearchMobileControl,
+} from "@/features/search/components/search-control.tsx";
+import { ShareSearchSpotlight } from "@/features/search/share-search-spotlight";
+import { shareSearchSpotlight } from "@/features/search/constants";
const MemoizedSharedTree = React.memo(SharedTree);
@@ -54,21 +59,9 @@ export default function ShareShell({
const { data } = useGetSharedPageTreeQuery(shareId);
const readOnlyEditor = useAtomValue(readOnlyEditorAtom);
- const [navbarOutside, setNavbarOutside] = useState(null);
-
- useClickOutside(
- () => {
- if (mobileOpened) {
- toggleMobile();
- }
- },
- null,
- [navbarOutside],
- );
-
return (
1 && {
navbar: {
width: 300,
@@ -91,7 +84,7 @@ export default function ShareShell({
>
-
+
{data?.pageTree?.length > 1 && (
<>
@@ -116,8 +109,21 @@ export default function ShareShell({
>
)}
+
+ {shareId && (
+
+
+
+ )}
+
<>
+ {shareId && (
+
+
+
+ )}
+
{data?.pageTree?.length > 1 && (
-
+
)}
@@ -186,6 +188,8 @@ export default function ShareShell({
+
+
);
}
diff --git a/apps/client/src/features/share/components/shared-tree.tsx b/apps/client/src/features/share/components/shared-tree.tsx
index 5e85ab57..486127b9 100644
--- a/apps/client/src/features/share/components/shared-tree.tsx
+++ b/apps/client/src/features/share/components/shared-tree.tsx
@@ -15,6 +15,7 @@ import clsx from "clsx";
import {
IconChevronDown,
IconChevronRight,
+ IconFileDescription,
IconPointFilled,
} from "@tabler/icons-react";
import { ActionIcon, Box } from "@mantine/core";
@@ -23,6 +24,7 @@ import { OpenMap } from "react-arborist/dist/main/state/open-slice";
import classes from "@/features/page/tree/styles/tree.module.css";
import styles from "./share.module.css";
import { mobileSidebarAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
+import EmojiPicker from "@/components/ui/emoji-picker.tsx";
interface SharedTree {
sharedPageTree: ISharedPageTree;
@@ -141,6 +143,20 @@ function Node({ node, style, tree }: NodeRendererProps) {
}}
>
+
+ {}}
+ icon={
+ node.data.icon ? (
+ node.data.icon
+ ) : (
+
+ )
+ }
+ readOnly={true}
+ removeEmojiAction={() => {}}
+ />
+
{node.data.name || t("untitled")}
>
diff --git a/apps/client/src/features/share/utils.ts b/apps/client/src/features/share/utils.ts
index 74ec349f..cc73eb57 100644
--- a/apps/client/src/features/share/utils.ts
+++ b/apps/client/src/features/share/utils.ts
@@ -11,11 +11,13 @@ export type SharedPageTreeNode = {
parentPageId: string;
hasChildren: boolean;
children: SharedPageTreeNode[];
- label: string,
- value: string,
+ label: string;
+ value: string;
};
-export function buildSharedPageTree(pages: Partial): SharedPageTreeNode[] {
+export function buildSharedPageTree(
+ pages: Partial,
+): SharedPageTreeNode[] {
const pageMap: Record = {};
// Initialize each page as a tree node and store it in a map.
@@ -30,7 +32,7 @@ export function buildSharedPageTree(pages: Partial): SharedPageTreeNode
hasChildren: false,
spaceId: page.spaceId,
parentPageId: page.parentPageId,
- label: page.title || 'untitled',
+ label: page.title || "untitled",
value: page.id,
children: [],
};
@@ -55,6 +57,12 @@ export function buildSharedPageTree(pages: Partial): SharedPageTreeNode
}
});
- // Return the sorted tree.
- return sortPositionKeys(tree);
+ function sortTree(nodes: SharedPageTreeNode[]): SharedPageTreeNode[] {
+ return sortPositionKeys(nodes).map((node: SharedPageTreeNode) => ({
+ ...node,
+ children: sortTree(node.children),
+ }));
+ }
+
+ return sortTree(tree);
}
diff --git a/apps/client/src/features/space/components/sidebar/space-sidebar.tsx b/apps/client/src/features/space/components/sidebar/space-sidebar.tsx
index 528e8051..5dbd420a 100644
--- a/apps/client/src/features/space/components/sidebar/space-sidebar.tsx
+++ b/apps/client/src/features/space/components/sidebar/space-sidebar.tsx
@@ -6,7 +6,6 @@ import {
Tooltip,
UnstyledButton,
} from "@mantine/core";
-import { spotlight } from "@mantine/spotlight";
import {
IconArrowDown,
IconDots,
@@ -16,9 +15,8 @@ import {
IconSearch,
IconSettings,
} from "@tabler/icons-react";
-
import classes from "./space-sidebar.module.css";
-import React, { useMemo } from "react";
+import React from "react";
import { useAtom } from "jotai";
import { SearchSpotlight } from "@/features/search/search-spotlight.tsx";
import { treeApiAtom } from "@/features/page/tree/atoms/tree-api-atom.ts";
@@ -40,6 +38,7 @@ import { SwitchSpace } from "./switch-space";
import ExportModal from "@/components/common/export-modal";
import { mobileSidebarAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
import { useToggleSidebar } from "@/components/layouts/global/hooks/hooks/use-toggle-sidebar.ts";
+import { searchSpotlight } from "@/features/search/constants";
export function SpaceSidebar() {
const { t } = useTranslation();
@@ -51,7 +50,7 @@ export function SpaceSidebar() {
const toggleMobileSidebar = useToggleSidebar(mobileSidebarAtom);
const { spaceSlug } = useParams();
- const { data: space, isLoading, isError } = useGetSpaceBySlugQuery(spaceSlug);
+ const { data: space } = useGetSpaceBySlugQuery(spaceSlug);
const spaceRules = space?.membership?.permissions;
const spaceAbility = useSpaceAbility(spaceRules);
@@ -100,7 +99,10 @@ export function SpaceSidebar() {
-
+
{
if (query.length < 1) {
return;
}
const searchQuery = tsquery(query.trim() + '*');
- const queryResults = await this.db
+ let queryResults = this.db
.selectFrom('pages')
.select([
'id',
@@ -43,18 +49,71 @@ export class SearchService {
'highlight',
),
])
- .select((eb) => this.pageRepo.withSpace(eb))
- .where('spaceId', '=', searchParams.spaceId)
.where('tsv', '@@', sql`to_tsquery(${searchQuery})`)
.$if(Boolean(searchParams.creatorId), (qb) =>
qb.where('creatorId', '=', searchParams.creatorId),
)
.orderBy('rank', 'desc')
.limit(searchParams.limit | 20)
- .offset(searchParams.offset || 0)
- .execute();
+ .offset(searchParams.offset || 0);
- const searchResults = queryResults.map((result) => {
+ if (!searchParams.shareId) {
+ queryResults = queryResults.select((eb) => this.pageRepo.withSpace(eb));
+ }
+
+ if (searchParams.spaceId) {
+ // search by spaceId
+ queryResults = queryResults.where('spaceId', '=', searchParams.spaceId);
+ } else if (opts.userId && !searchParams.spaceId) {
+ // only search spaces the user is a member of
+ const userSpaceIds = await this.spaceMemberRepo.getUserSpaceIds(
+ opts.userId,
+ );
+ if (userSpaceIds.length > 0) {
+ queryResults = queryResults
+ .where('spaceId', 'in', userSpaceIds)
+ .where('workspaceId', '=', opts.workspaceId);
+ } else {
+ return [];
+ }
+ } else if (searchParams.shareId && !searchParams.spaceId && !opts.userId) {
+ // search in shares
+ const shareId = searchParams.shareId;
+ const share = await this.shareRepo.findById(shareId);
+ if (!share || share.workspaceId !== opts.workspaceId) {
+ return [];
+ }
+
+ const pageIdsToSearch = [];
+ if (share.includeSubPages) {
+ const pageList = await this.pageRepo.getPageAndDescendants(
+ share.pageId,
+ {
+ includeContent: false,
+ },
+ );
+
+ pageIdsToSearch.push(...pageList.map((page) => page.id));
+ } else {
+ pageIdsToSearch.push(share.pageId);
+ }
+
+ if (pageIdsToSearch.length > 0) {
+ queryResults = queryResults
+ .where('id', 'in', pageIdsToSearch)
+ .where('workspaceId', '=', opts.workspaceId);
+ } else {
+ return [];
+ }
+ } else {
+ return [];
+ }
+
+ //@ts-ignore
+ queryResults = await queryResults.execute();
+
+ //@ts-ignore
+ const searchResults = queryResults.map((result: SearchResponseDto) => {
if (result.highlight) {
result.highlight = result.highlight
.replace(/\r\n|\r|\n/g, ' ')
diff --git a/apps/server/src/core/share/share.service.ts b/apps/server/src/core/share/share.service.ts
index a9140c0b..d71b6acd 100644
--- a/apps/server/src/core/share/share.service.ts
+++ b/apps/server/src/core/share/share.service.ts
@@ -15,6 +15,7 @@ import {
getAttachmentIds,
getProsemirrorContent,
isAttachmentNode,
+ removeMarkTypeFromDoc,
} from '../../common/helpers/prosemirror/utils';
import { Node } from '@tiptap/pm/model';
import { ShareRepo } from '@docmost/db/repos/share/share.repo';
@@ -223,11 +224,7 @@ export class ShareService {
.end()
.as('found'),
])
- .where(
- isValidUUID(childPageId) ? 'id' : 'slugId',
- '=',
- childPageId,
- )
+ .where(isValidUUID(childPageId) ? 'id' : 'slugId', '=', childPageId)
.unionAll((exp) =>
exp
.selectFrom('pages as p')
@@ -292,6 +289,7 @@ export class ShareService {
updateAttachmentAttr(node, 'url', token);
});
- return doc.toJSON();
+ const removeCommentMarks = removeMarkTypeFromDoc(doc, 'comment');
+ return removeCommentMarks.toJSON();
}
}
From c528f7e8584a144669e0525e83cd9df208442128 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 23 Apr 2025 14:34:28 +0100
Subject: [PATCH 34/63] v0.20.1
---
apps/client/package.json | 2 +-
apps/server/package.json | 2 +-
package.json | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/client/package.json b/apps/client/package.json
index e56b7e68..57e0026a 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -1,7 +1,7 @@
{
"name": "client",
"private": true,
- "version": "0.20.0",
+ "version": "0.20.1",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
diff --git a/apps/server/package.json b/apps/server/package.json
index 935647ed..a1a6f081 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -1,6 +1,6 @@
{
"name": "server",
- "version": "0.20.0",
+ "version": "0.20.1",
"description": "",
"author": "",
"private": true,
diff --git a/package.json b/package.json
index 0cafcc3f..8e9fcead 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "docmost",
"homepage": "https://docmost.com",
- "version": "0.20.0",
+ "version": "0.20.1",
"private": true,
"scripts": {
"build": "nx run-many -t build",
From 08f223899a415b5d95b53a0c1d003401778f0dc2 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 23 Apr 2025 16:07:58 +0100
Subject: [PATCH 35/63] cloud trial refactor
---
apps/client/src/ee/billing/components/billing-trial.tsx | 5 +++--
apps/client/src/ee/hooks/use-trial-end-action.tsx | 4 ++--
apps/client/src/lib/config.ts | 4 ++++
apps/client/vite.config.ts | 2 ++
apps/server/src/ee | 2 +-
apps/server/src/integrations/static/static.module.ts | 3 +++
6 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/apps/client/src/ee/billing/components/billing-trial.tsx b/apps/client/src/ee/billing/components/billing-trial.tsx
index 82dcbb03..38acc17c 100644
--- a/apps/client/src/ee/billing/components/billing-trial.tsx
+++ b/apps/client/src/ee/billing/components/billing-trial.tsx
@@ -1,6 +1,7 @@
import { Alert } from "@mantine/core";
import { useBillingQuery } from "@/ee/billing/queries/billing-query.ts";
import useTrial from "@/ee/hooks/use-trial.tsx";
+import { getBillingTrialDays } from '@/lib/config.ts';
export default function BillingTrial() {
const { data: billing, isLoading } = useBillingQuery();
@@ -15,14 +16,14 @@ export default function BillingTrial() {
{trialDaysLeft > 0 && !billing && (
You have {trialDaysLeft} {trialDaysLeft === 1 ? "day" : "days"} left
- in your 7-day trial. Please subscribe to a plan before your trial
+ in your {getBillingTrialDays()}-day free trial. Please subscribe to a paid plan before your trial
ends.
)}
{trialDaysLeft === 0 && (
- Your 7-day trial has come to an end. Please subscribe to a plan to
+ Your {getBillingTrialDays()}-day free trial has come to an end. Please subscribe to a paid plan to
continue using this service.
)}
diff --git a/apps/client/src/ee/hooks/use-trial-end-action.tsx b/apps/client/src/ee/hooks/use-trial-end-action.tsx
index 931fd6a8..09248c6a 100644
--- a/apps/client/src/ee/hooks/use-trial-end-action.tsx
+++ b/apps/client/src/ee/hooks/use-trial-end-action.tsx
@@ -1,6 +1,6 @@
import { useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom";
-import { isCloud } from "@/lib/config.ts";
+import { getBillingTrialDays, isCloud } from "@/lib/config.ts";
import APP_ROUTE from "@/lib/app-route.ts";
import useUserRole from "@/hooks/use-user-role.tsx";
import { notifications } from "@mantine/notifications";
@@ -18,7 +18,7 @@ export const useTrialEndAction = () => {
notifications.show({
position: "top-right",
color: "red",
- title: "Your 7-day trial has ended",
+ title: `Your ${getBillingTrialDays()}-day trial has ended`,
message:
"Please upgrade to a paid plan or contact your workspace admin.",
autoClose: false,
diff --git a/apps/client/src/lib/config.ts b/apps/client/src/lib/config.ts
index 9e1efc30..2f621b91 100644
--- a/apps/client/src/lib/config.ts
+++ b/apps/client/src/lib/config.ts
@@ -74,6 +74,10 @@ export function getDrawioUrl() {
return getConfigValue("DRAWIO_URL", "https://embed.diagrams.net");
}
+export function getBillingTrialDays() {
+ return getConfigValue("BILLING_TRIAL_DAYS");
+}
+
function getConfigValue(key: string, defaultValue: string = undefined): string {
const rawValue = import.meta.env.DEV
? process?.env?.[key]
diff --git a/apps/client/vite.config.ts b/apps/client/vite.config.ts
index 2e557fe5..a6efc4bc 100644
--- a/apps/client/vite.config.ts
+++ b/apps/client/vite.config.ts
@@ -12,6 +12,7 @@ export default defineConfig(({ mode }) => {
CLOUD,
SUBDOMAIN_HOST,
COLLAB_URL,
+ BILLING_TRIAL_DAYS,
} = loadEnv(mode, envPath, "");
return {
@@ -23,6 +24,7 @@ export default defineConfig(({ mode }) => {
CLOUD,
SUBDOMAIN_HOST,
COLLAB_URL,
+ BILLING_TRIAL_DAYS,
},
APP_VERSION: JSON.stringify(process.env.npm_package_version),
},
diff --git a/apps/server/src/ee b/apps/server/src/ee
index d3095f2d..4e7319ab 160000
--- a/apps/server/src/ee
+++ b/apps/server/src/ee
@@ -1 +1 @@
-Subproject commit d3095f2d8bd2870da7f3b534c83c84e8fb3099bc
+Subproject commit 4e7319ab01f0ea535bb4dd6b98ea996fcd1c3ffc
diff --git a/apps/server/src/integrations/static/static.module.ts b/apps/server/src/integrations/static/static.module.ts
index e5152ef8..15db42b0 100644
--- a/apps/server/src/integrations/static/static.module.ts
+++ b/apps/server/src/integrations/static/static.module.ts
@@ -42,6 +42,9 @@ export class StaticModule implements OnModuleInit {
? this.environmentService.getSubdomainHost()
: undefined,
COLLAB_URL: this.environmentService.getCollabUrl(),
+ BILLING_TRIAL_DAYS: this.environmentService.isCloud()
+ ? this.environmentService.getBillingTrialDays()
+ : undefined,
};
const windowScriptContent = ``;
From 33c314d4e8679f4ced56754208ed51ca49dc3b79 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Thu, 24 Apr 2025 17:56:54 +0100
Subject: [PATCH 36/63] remove clickoutside hook
---
.../src/components/layouts/global/global-app-shell.tsx | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/apps/client/src/components/layouts/global/global-app-shell.tsx b/apps/client/src/components/layouts/global/global-app-shell.tsx
index c8aff4cc..58ff5609 100644
--- a/apps/client/src/components/layouts/global/global-app-shell.tsx
+++ b/apps/client/src/components/layouts/global/global-app-shell.tsx
@@ -14,7 +14,6 @@ import { AppHeader } from "@/components/layouts/global/app-header.tsx";
import Aside from "@/components/layouts/global/aside.tsx";
import classes from "./app-shell.module.css";
import { useTrialEndAction } from "@/ee/hooks/use-trial-end-action.tsx";
-import { useClickOutside, useMergedRef } from "@mantine/hooks";
import { useToggleSidebar } from "@/components/layouts/global/hooks/hooks/use-toggle-sidebar.ts";
export default function GlobalAppShell({
@@ -30,13 +29,6 @@ export default function GlobalAppShell({
const [sidebarWidth, setSidebarWidth] = useAtom(sidebarWidthAtom);
const [isResizing, setIsResizing] = useState(false);
const sidebarRef = useRef(null);
- const navbarOutsideRef = useClickOutside(() => {
- if (mobileOpened) {
- toggleMobile();
- }
- });
-
- const mergedRef = useMergedRef(sidebarRef, navbarOutsideRef);
const startResizing = React.useCallback((mouseDownEvent) => {
mouseDownEvent.preventDefault();
@@ -112,7 +104,7 @@ export default function GlobalAppShell({
{isSpaceRoute && }
From 31e5c0c66046a02012b719b4333213a8a9deeb84 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Thu, 24 Apr 2025 17:57:14 +0100
Subject: [PATCH 37/63] v0.20.2
---
apps/client/package.json | 2 +-
apps/server/package.json | 2 +-
package.json | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/client/package.json b/apps/client/package.json
index 57e0026a..cd731696 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -1,7 +1,7 @@
{
"name": "client",
"private": true,
- "version": "0.20.1",
+ "version": "0.20.2",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
diff --git a/apps/server/package.json b/apps/server/package.json
index a1a6f081..10637756 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -1,6 +1,6 @@
{
"name": "server",
- "version": "0.20.1",
+ "version": "0.20.2",
"description": "",
"author": "",
"private": true,
diff --git a/package.json b/package.json
index 8e9fcead..8547d75f 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "docmost",
"homepage": "https://docmost.com",
- "version": "0.20.1",
+ "version": "0.20.2",
"private": true,
"scripts": {
"build": "nx run-many -t build",
From 7993532111109861d573df648b02e85401f2277b Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Thu, 24 Apr 2025 23:18:54 +0100
Subject: [PATCH 38/63] fix page export (#1081)
---
apps/server/src/database/repos/page/page.repo.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/server/src/database/repos/page/page.repo.ts b/apps/server/src/database/repos/page/page.repo.ts
index 8f06c4d4..52a69707 100644
--- a/apps/server/src/database/repos/page/page.repo.ts
+++ b/apps/server/src/database/repos/page/page.repo.ts
@@ -244,7 +244,7 @@ export class PageRepo {
'p.spaceId',
'p.workspaceId',
])
- .$if(opts?.includeContent, (qb) => qb.select('content'))
+ .$if(opts?.includeContent, (qb) => qb.select('p.content'))
.innerJoin('page_hierarchy as ph', 'p.parentPageId', 'ph.id'),
),
)
From 0289c5cb09af53927bacbaf15931543eed682f84 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Thu, 24 Apr 2025 23:19:39 +0100
Subject: [PATCH 39/63] Reduce markdown checkbox space
---
apps/server/src/integrations/export/turndown-utils.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/server/src/integrations/export/turndown-utils.ts b/apps/server/src/integrations/export/turndown-utils.ts
index ce55c659..44e606f3 100644
--- a/apps/server/src/integrations/export/turndown-utils.ts
+++ b/apps/server/src/integrations/export/turndown-utils.ts
@@ -68,7 +68,7 @@ function taskList(turndownService: TurndownService) {
) as HTMLInputElement;
const isChecked = checkbox.checked;
- return `- ${isChecked ? '[x]' : '[ ]'} ${content.trim()} \n`;
+ return `- ${isChecked ? '[x]' : '[ ]'} ${content.trim()} \n`;
},
});
}
From 9bbd62e0f044e1f5cd85827462823bb563af2148 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Thu, 24 Apr 2025 23:22:53 +0100
Subject: [PATCH 40/63] v0.20.3
---
apps/client/package.json | 2 +-
apps/server/package.json | 2 +-
package.json | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/client/package.json b/apps/client/package.json
index cd731696..cc1c2d0b 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -1,7 +1,7 @@
{
"name": "client",
"private": true,
- "version": "0.20.2",
+ "version": "0.20.3",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
diff --git a/apps/server/package.json b/apps/server/package.json
index 10637756..2f3a99bd 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -1,6 +1,6 @@
{
"name": "server",
- "version": "0.20.2",
+ "version": "0.20.3",
"description": "",
"author": "",
"private": true,
diff --git a/package.json b/package.json
index 8547d75f..4ef488db 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "docmost",
"homepage": "https://docmost.com",
- "version": "0.20.2",
+ "version": "0.20.3",
"private": true,
"scripts": {
"build": "nx run-many -t build",
From e8847bd9cdca23bda532542f4d268c832725821b Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 29 Apr 2025 23:29:00 +0100
Subject: [PATCH 41/63] fix: handle unhandled exceptions (#1116)
* Handle unhandled exceptions
* cleanup
---
.../src/collaboration/collaboration.module.ts | 11 ++++++++++-
.../extensions/persistence.extension.ts | 2 +-
apps/server/src/main.ts | 15 +++++++++------
3 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/apps/server/src/collaboration/collaboration.module.ts b/apps/server/src/collaboration/collaboration.module.ts
index bd5e1e6f..30cb0ccf 100644
--- a/apps/server/src/collaboration/collaboration.module.ts
+++ b/apps/server/src/collaboration/collaboration.module.ts
@@ -1,4 +1,4 @@
-import { Module, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
+import { Logger, Module, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { AuthenticationExtension } from './extensions/authentication.extension';
import { PersistenceExtension } from './extensions/persistence.extension';
import { CollaborationGateway } from './collaboration.gateway';
@@ -22,6 +22,7 @@ import { LoggerExtension } from './extensions/logger.extension';
imports: [TokenModule],
})
export class CollaborationModule implements OnModuleInit, OnModuleDestroy {
+ private readonly logger = new Logger(CollaborationModule.name);
private collabWsAdapter: CollabWsAdapter;
private path = '/collab';
@@ -38,7 +39,15 @@ export class CollaborationModule implements OnModuleInit, OnModuleDestroy {
wss.on('connection', (client: WebSocket, request: IncomingMessage) => {
this.collaborationGateway.handleConnection(client, request);
+
+ client.on('error', (error) => {
+ this.logger.error('WebSocket client error:', error);
+ });
});
+
+ wss.on('error', (error) =>
+ this.logger.log('WebSocket server error:', error),
+ );
}
async onModuleDestroy(): Promise {
diff --git a/apps/server/src/collaboration/extensions/persistence.extension.ts b/apps/server/src/collaboration/extensions/persistence.extension.ts
index a1f9f519..3c206e1a 100644
--- a/apps/server/src/collaboration/extensions/persistence.extension.ts
+++ b/apps/server/src/collaboration/extensions/persistence.extension.ts
@@ -130,7 +130,7 @@ export class PersistenceExtension implements Extension {
);
this.contributors.delete(documentName);
} catch (err) {
- this.logger.log('Contributors error:' + err?.['message']);
+ this.logger.debug('Contributors error:' + err?.['message']);
}
await this.pageRepo.updatePage(
diff --git a/apps/server/src/main.ts b/apps/server/src/main.ts
index 95df255d..a371b9b9 100644
--- a/apps/server/src/main.ts
+++ b/apps/server/src/main.ts
@@ -4,12 +4,7 @@ import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
-import {
- Logger,
- NotFoundException,
- RequestMethod,
- ValidationPipe,
-} from '@nestjs/common';
+import { Logger, NotFoundException, ValidationPipe } from '@nestjs/common';
import { TransformHttpResponseInterceptor } from './common/interceptors/http-response.interceptor';
import { WsRedisIoAdapter } from './ws/adapter/ws-redis.adapter';
import { InternalLogFilter } from './common/logger/internal-log-filter';
@@ -92,6 +87,14 @@ async function bootstrap() {
const logger = new Logger('NestApplication');
+ process.on('unhandledRejection', (reason, promise) => {
+ logger.error(`UnhandledRejection: ${promise}, reason: ${reason}`);
+ });
+
+ process.on('uncaughtException', (error) => {
+ logger.error('UncaughtException:', error);
+ });
+
const port = process.env.PORT || 3000;
await app.listen(port, '0.0.0.0', () => {
logger.log(
From 8327251ab680452579bfe528370e6003c193b641 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 29 Apr 2025 23:30:12 +0100
Subject: [PATCH 42/63] fix typo
---
apps/client/src/ee/security/components/enforce-sso.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/client/src/ee/security/components/enforce-sso.tsx b/apps/client/src/ee/security/components/enforce-sso.tsx
index 4cbbc7ac..31a9f6fa 100644
--- a/apps/client/src/ee/security/components/enforce-sso.tsx
+++ b/apps/client/src/ee/security/components/enforce-sso.tsx
@@ -15,7 +15,7 @@ export default function EnforceSso() {
{t("Enforce SSO")}
{t(
- "Once enforced, members will not able able to login with email and password.",
+ "Once enforced, members will not able to login with email and password.",
)}
From 0402f7efb590d1efbecb5be4dfe20de264186e75 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 30 Apr 2025 14:33:01 +0100
Subject: [PATCH 43/63] sync
---
apps/server/src/ee | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/server/src/ee b/apps/server/src/ee
index 4e7319ab..96404fc1 160000
--- a/apps/server/src/ee
+++ b/apps/server/src/ee
@@ -1 +1 @@
-Subproject commit 4e7319ab01f0ea535bb4dd6b98ea996fcd1c3ffc
+Subproject commit 96404fc121844a707bd0fb1e280df6e2d52e8973
From de7982fe301dfc162ad7ad128ab506882b73ab82 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 30 Apr 2025 14:43:16 +0100
Subject: [PATCH 44/63] feat: copy page to different space (#1118)
* Add copy page to space endpoint
* copy storage function
* copy function
* feat: copy attachments too
* Copy page - WIP
* fix type
* sync
* cleanup
---
.../public/locales/en-US/translation.json | 5 +-
.../page/components/copy-page-modal.tsx | 105 +++++++++++
.../components/header/page-header-menu.tsx | 8 +-
.../page/components/move-page-modal.tsx | 8 +-
.../features/page/services/page-service.ts | 6 +
.../page/tree/components/space-tree.tsx | 24 +++
.../src/features/page/types/page.types.ts | 7 +-
.../src/common/helpers/prosemirror/utils.ts | 25 ++-
.../server/src/core/page/dto/copy-page.dto.ts | 24 +++
.../server/src/core/page/dto/move-page.dto.ts | 10 +-
apps/server/src/core/page/page.controller.ts | 31 ++++
apps/server/src/core/page/page.module.ts | 2 +
.../src/core/page/services/page.service.ts | 166 +++++++++++++++++-
.../storage/drivers/local.driver.ts | 10 ++
.../integrations/storage/drivers/s3.driver.ts | 17 ++
.../interfaces/storage-driver.interface.ts | 2 +
.../integrations/storage/storage.service.ts | 5 +
17 files changed, 441 insertions(+), 14 deletions(-)
create mode 100644 apps/client/src/features/page/components/copy-page-modal.tsx
create mode 100644 apps/server/src/core/page/dto/copy-page.dto.ts
diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json
index 0746ed15..127730d5 100644
--- a/apps/client/public/locales/en-US/translation.json
+++ b/apps/client/public/locales/en-US/translation.json
@@ -383,5 +383,8 @@
"Publicly shared pages from spaces you are a member of will appear here": "Publicly shared pages from spaces you are a member of will appear here",
"Share deleted successfully": "Share deleted successfully",
"Share not found": "Share not found",
- "Failed to share page": "Failed to share page"
+ "Failed to share page": "Failed to share page",
+ "Copy page": "Copy page",
+ "Copy page to a different space.": "Copy page to a different space.",
+ "Page copied successfully": "Page copied successfully"
}
diff --git a/apps/client/src/features/page/components/copy-page-modal.tsx b/apps/client/src/features/page/components/copy-page-modal.tsx
new file mode 100644
index 00000000..e639fbac
--- /dev/null
+++ b/apps/client/src/features/page/components/copy-page-modal.tsx
@@ -0,0 +1,105 @@
+import { Modal, Button, Group, Text } from "@mantine/core";
+import { copyPageToSpace } from "@/features/page/services/page-service.ts";
+import { useState } from "react";
+import { notifications } from "@mantine/notifications";
+import { useTranslation } from "react-i18next";
+import { ISpace } from "@/features/space/types/space.types.ts";
+import { queryClient } from "@/main.tsx";
+import { SpaceSelect } from "@/features/space/components/sidebar/space-select.tsx";
+import { useNavigate } from "react-router-dom";
+import { buildPageUrl } from "@/features/page/page.utils.ts";
+
+interface CopyPageModalProps {
+ pageId: string;
+ currentSpaceSlug: string;
+ open: boolean;
+ onClose: () => void;
+}
+
+export default function CopyPageModal({
+ pageId,
+ currentSpaceSlug,
+ open,
+ onClose,
+}: CopyPageModalProps) {
+ const { t } = useTranslation();
+ const [targetSpace, setTargetSpace] = useState(null);
+ const navigate = useNavigate();
+
+ const handleCopy = async () => {
+ if (!targetSpace) return;
+
+ try {
+ const copiedPage = await copyPageToSpace({
+ pageId,
+ spaceId: targetSpace.id,
+ });
+ queryClient.removeQueries({
+ predicate: (item) =>
+ ["pages", "sidebar-pages", "root-sidebar-pages"].includes(
+ item.queryKey[0] as string,
+ ),
+ });
+
+ const pageUrl = buildPageUrl(
+ copiedPage.space.slug,
+ copiedPage.slugId,
+ copiedPage.title,
+ );
+ navigate(pageUrl);
+ notifications.show({
+ message: t("Page copied successfully"),
+ });
+ onClose();
+ setTargetSpace(null);
+ } catch (err) {
+ notifications.show({
+ message: err.response?.data.message || "An error occurred",
+ color: "red",
+ });
+ console.log(err);
+ }
+ };
+
+ const handleChange = (space: ISpace) => {
+ setTargetSpace(space);
+ };
+
+ return (
+ e.stopPropagation()}
+ >
+
+
+
+ {t("Copy page")}
+
+
+
+
+ {t("Copy page to a different space.")}
+
+
+
+
+
+ {t("Cancel")}
+
+ {t("Copy")}
+
+
+
+
+ );
+}
diff --git a/apps/client/src/features/page/components/header/page-header-menu.tsx b/apps/client/src/features/page/components/header/page-header-menu.tsx
index 9267ad9e..09305491 100644
--- a/apps/client/src/features/page/components/header/page-header-menu.tsx
+++ b/apps/client/src/features/page/components/header/page-header-menu.tsx
@@ -12,7 +12,7 @@ import {
IconTrash,
IconWifiOff,
} from "@tabler/icons-react";
-import React, { useEffect } from "react";
+import React from "react";
import useToggleAside from "@/hooks/use-toggle-aside.tsx";
import { useAtom } from "jotai";
import { historyAtoms } from "@/features/page-history/atoms/history-atoms.ts";
@@ -35,7 +35,7 @@ import {
import { formattedDate, timeAgo } from "@/lib/time.ts";
import MovePageModal from "@/features/page/components/move-page-modal.tsx";
import { useTimeAgo } from "@/hooks/use-time-ago.tsx";
-import ShareModal from '@/features/share/components/share-modal.tsx';
+import ShareModal from "@/features/share/components/share-modal.tsx";
interface PageHeaderMenuProps {
readOnly?: boolean;
@@ -59,7 +59,7 @@ export default function PageHeaderMenu({ readOnly }: PageHeaderMenuProps) {
)}
-
+
{
const pageUrl =
diff --git a/apps/client/src/features/page/components/move-page-modal.tsx b/apps/client/src/features/page/components/move-page-modal.tsx
index 4788951b..74880084 100644
--- a/apps/client/src/features/page/components/move-page-modal.tsx
+++ b/apps/client/src/features/page/components/move-page-modal.tsx
@@ -46,6 +46,7 @@ export default function MovePageModal({
message: t("Page moved successfully"),
});
onClose();
+ setTargetSpace(null);
} catch (err) {
notifications.show({
message: err.response?.data.message || "An error occurred",
@@ -53,7 +54,6 @@ export default function MovePageModal({
});
console.log(err);
}
- setTargetSpace(null);
};
const handleChange = (space: ISpace) => {
@@ -69,7 +69,7 @@ export default function MovePageModal({
yOffset="10vh"
xOffset={0}
mah={400}
- onClick={e => e.stopPropagation()}
+ onClick={(e) => e.stopPropagation()}
>
@@ -78,7 +78,9 @@ export default function MovePageModal({
- {t("Move page to a different space.")}
+
+ {t("Move page to a different space.")}
+
{
await api.post("/pages/move-to-space", data);
}
+export async function copyPageToSpace(data: ICopyPageToSpace): Promise {
+ const req = await api.post("/pages/copy-to-space", data);
+ return req.data;
+}
+
export async function getSidebarPages(
params: SidebarPagesParams,
): Promise> {
diff --git a/apps/client/src/features/page/tree/components/space-tree.tsx b/apps/client/src/features/page/tree/components/space-tree.tsx
index 5a00f258..1df62678 100644
--- a/apps/client/src/features/page/tree/components/space-tree.tsx
+++ b/apps/client/src/features/page/tree/components/space-tree.tsx
@@ -15,6 +15,7 @@ import {
IconArrowRight,
IconChevronDown,
IconChevronRight,
+ IconCopy,
IconDotsVertical,
IconFileDescription,
IconFileExport,
@@ -60,6 +61,7 @@ import ExportModal from "@/components/common/export-modal";
import MovePageModal from "../../components/move-page-modal.tsx";
import { mobileSidebarAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
import { useToggleSidebar } from "@/components/layouts/global/hooks/hooks/use-toggle-sidebar.ts";
+import CopyPageModal from "../../components/copy-page-modal.tsx";
interface SpaceTreeProps {
spaceId: string;
@@ -448,6 +450,10 @@ function NodeMenu({ node, treeApi }: NodeMenuProps) {
movePageModalOpened,
{ open: openMovePageModal, close: closeMoveSpaceModal },
] = useDisclosure(false);
+ const [
+ copyPageModalOpened,
+ { open: openCopyPageModal, close: closeCopySpaceModal },
+ ] = useDisclosure(false);
const handleCopyLink = () => {
const pageUrl =
@@ -511,6 +517,17 @@ function NodeMenu({ node, treeApi }: NodeMenuProps) {
{t("Move")}
+ }
+ onClick={(e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ openCopyPageModal();
+ }}
+ >
+ {t("Copy")}
+
+
+
+
+ ability.cannot(SpaceCaslAction.Edit, SpaceCaslSubject.Page),
+ )
+ ) {
+ throw new ForbiddenException();
+ }
+
+ return this.pageService.copyPageToSpace(copiedPage, dto.spaceId, user);
+ }
+
@HttpCode(HttpStatus.OK)
@Post('move')
async movePage(@Body() dto: MovePageDto, @AuthUser() user: User) {
diff --git a/apps/server/src/core/page/page.module.ts b/apps/server/src/core/page/page.module.ts
index 93f8f719..fd336537 100644
--- a/apps/server/src/core/page/page.module.ts
+++ b/apps/server/src/core/page/page.module.ts
@@ -2,10 +2,12 @@ import { Module } from '@nestjs/common';
import { PageService } from './services/page.service';
import { PageController } from './page.controller';
import { PageHistoryService } from './services/page-history.service';
+import { StorageModule } from '../../integrations/storage/storage.module';
@Module({
controllers: [PageController],
providers: [PageService, PageHistoryService],
exports: [PageService, PageHistoryService],
+ imports: [StorageModule]
})
export class PageModule {}
diff --git a/apps/server/src/core/page/services/page.service.ts b/apps/server/src/core/page/services/page.service.ts
index 5e4553c6..41f3055e 100644
--- a/apps/server/src/core/page/services/page.service.ts
+++ b/apps/server/src/core/page/services/page.service.ts
@@ -1,12 +1,13 @@
import {
BadRequestException,
Injectable,
+ Logger,
NotFoundException,
} from '@nestjs/common';
import { CreatePageDto } from '../dto/create-page.dto';
import { UpdatePageDto } from '../dto/update-page.dto';
import { PageRepo } from '@docmost/db/repos/page/page.repo';
-import { Page } from '@docmost/db/types/entity.types';
+import { InsertablePage, Page, User } from '@docmost/db/types/entity.types';
import { PaginationOptions } from '@docmost/db/pagination/pagination-options';
import {
executeWithPagination,
@@ -21,13 +22,28 @@ import { DB } from '@docmost/db/types/db';
import { generateSlugId } from '../../../common/helpers';
import { executeTx } from '@docmost/db/utils';
import { AttachmentRepo } from '@docmost/db/repos/attachment/attachment.repo';
+import { v7 as uuid7 } from 'uuid';
+import {
+ createYdocFromJson,
+ getAttachmentIds,
+ getProsemirrorContent,
+ isAttachmentNode,
+ removeMarkTypeFromDoc,
+} from '../../../common/helpers/prosemirror/utils';
+import { jsonToNode, jsonToText } from 'src/collaboration/collaboration.util';
+import { CopyPageMapEntry, ICopyPageAttachment } from '../dto/copy-page.dto';
+import { Node as PMNode } from '@tiptap/pm/model';
+import { StorageService } from '../../../integrations/storage/storage.service';
@Injectable()
export class PageService {
+ private readonly logger = new Logger(PageService.name);
+
constructor(
private pageRepo: PageRepo,
private attachmentRepo: AttachmentRepo,
@InjectKysely() private readonly db: KyselyDB,
+ private readonly storageService: StorageService,
) {}
async findById(
@@ -242,6 +258,154 @@ export class PageService {
});
}
+ async copyPageToSpace(rootPage: Page, spaceId: string, authUser: User) {
+ //TODO:
+ // i. maintain internal links within copied pages
+
+ const nextPosition = await this.nextPagePosition(spaceId);
+
+ const pages = await this.pageRepo.getPageAndDescendants(rootPage.id, {
+ includeContent: true,
+ });
+
+ const pageMap = new Map();
+ pages.forEach((page) => {
+ pageMap.set(page.id, {
+ newPageId: uuid7(),
+ newSlugId: generateSlugId(),
+ oldSlugId: page.slugId,
+ });
+ });
+
+ const attachmentMap = new Map();
+
+ const insertablePages: InsertablePage[] = await Promise.all(
+ pages.map(async (page) => {
+ const pageContent = getProsemirrorContent(page.content);
+ const pageFromMap = pageMap.get(page.id);
+
+ const doc = jsonToNode(pageContent);
+ const prosemirrorDoc = removeMarkTypeFromDoc(doc, 'comment');
+
+ const attachmentIds = getAttachmentIds(prosemirrorDoc.toJSON());
+
+ if (attachmentIds.length > 0) {
+ attachmentIds.forEach((attachmentId: string) => {
+ const newPageId = pageFromMap.newPageId;
+ const newAttachmentId = uuid7();
+ attachmentMap.set(attachmentId, {
+ newPageId: newPageId,
+ oldPageId: page.id,
+ oldAttachmentId: attachmentId,
+ newAttachmentId: newAttachmentId,
+ });
+
+ prosemirrorDoc.descendants((node: PMNode) => {
+ if (isAttachmentNode(node.type.name)) {
+ if (node.attrs.attachmentId === attachmentId) {
+ //@ts-ignore
+ node.attrs.attachmentId = newAttachmentId;
+
+ if (node.attrs.src) {
+ //@ts-ignore
+ node.attrs.src = node.attrs.src.replace(
+ attachmentId,
+ newAttachmentId,
+ );
+ }
+ if (node.attrs.src) {
+ //@ts-ignore
+ node.attrs.src = node.attrs.src.replace(
+ attachmentId,
+ newAttachmentId,
+ );
+ }
+ }
+ }
+ });
+ });
+ }
+
+ const prosemirrorJson = prosemirrorDoc.toJSON();
+
+ return {
+ id: pageFromMap.newPageId,
+ slugId: pageFromMap.newSlugId,
+ title: page.title,
+ icon: page.icon,
+ content: prosemirrorJson,
+ textContent: jsonToText(prosemirrorJson),
+ ydoc: createYdocFromJson(prosemirrorJson),
+ position: page.id === rootPage.id ? nextPosition : page.position,
+ spaceId: spaceId,
+ workspaceId: page.workspaceId,
+ creatorId: authUser.id,
+ lastUpdatedById: authUser.id,
+ parentPageId: page.parentPageId
+ ? pageMap.get(page.parentPageId)?.newPageId
+ : null,
+ };
+ }),
+ );
+
+ await this.db.insertInto('pages').values(insertablePages).execute();
+
+ //TODO: best to handle this in a queue
+ const attachmentsIds = Array.from(attachmentMap.keys());
+ if (attachmentsIds.length > 0) {
+ const attachments = await this.db
+ .selectFrom('attachments')
+ .selectAll()
+ .where('id', 'in', attachmentsIds)
+ .where('workspaceId', '=', rootPage.workspaceId)
+ .execute();
+
+ for (const attachment of attachments) {
+ try {
+ const pageAttachment = attachmentMap.get(attachment.id);
+
+ // make sure the copied attachment belongs to the page it was copied from
+ if (attachment.pageId !== pageAttachment.oldPageId) {
+ continue;
+ }
+
+ const newAttachmentId = pageAttachment.newAttachmentId;
+
+ const newPageId = pageAttachment.newPageId;
+
+ const newPathFile = attachment.filePath.replace(
+ attachment.id,
+ newAttachmentId,
+ );
+ await this.storageService.copy(attachment.filePath, newPathFile);
+ await this.db
+ .insertInto('attachments')
+ .values({
+ id: newAttachmentId,
+ type: attachment.type,
+ filePath: newPathFile,
+ fileName: attachment.fileName,
+ fileSize: attachment.fileSize,
+ mimeType: attachment.mimeType,
+ fileExt: attachment.fileExt,
+ creatorId: attachment.creatorId,
+ workspaceId: attachment.workspaceId,
+ pageId: newPageId,
+ spaceId: spaceId,
+ })
+ .execute();
+ } catch (err) {
+ this.logger.log(err);
+ }
+ }
+ }
+
+ const newPageId = pageMap.get(rootPage.id).newPageId;
+ return await this.pageRepo.findById(newPageId, {
+ includeSpace: true,
+ });
+ }
+
async movePage(dto: MovePageDto, movedPage: Page) {
// validate position value by attempting to generate a key
try {
diff --git a/apps/server/src/integrations/storage/drivers/local.driver.ts b/apps/server/src/integrations/storage/drivers/local.driver.ts
index f2553733..e3da7700 100644
--- a/apps/server/src/integrations/storage/drivers/local.driver.ts
+++ b/apps/server/src/integrations/storage/drivers/local.driver.ts
@@ -25,6 +25,16 @@ export class LocalDriver implements StorageDriver {
}
}
+ async copy(fromFilePath: string, toFilePath: string): Promise {
+ try {
+ if (await this.exists(fromFilePath)) {
+ await fs.copy(fromFilePath, toFilePath);
+ }
+ } catch (err) {
+ throw new Error(`Failed to copy file: ${(err as Error).message}`);
+ }
+ }
+
async read(filePath: string): Promise {
try {
return await fs.readFile(this._fullPath(filePath));
diff --git a/apps/server/src/integrations/storage/drivers/s3.driver.ts b/apps/server/src/integrations/storage/drivers/s3.driver.ts
index 78f7548c..41feb365 100644
--- a/apps/server/src/integrations/storage/drivers/s3.driver.ts
+++ b/apps/server/src/integrations/storage/drivers/s3.driver.ts
@@ -1,5 +1,6 @@
import { S3StorageConfig, StorageDriver, StorageOption } from '../interfaces';
import {
+ CopyObjectCommand,
DeleteObjectCommand,
GetObjectCommand,
HeadObjectCommand,
@@ -39,6 +40,22 @@ export class S3Driver implements StorageDriver {
}
}
+ async copy(fromFilePath: string, toFilePath: string): Promise {
+ try {
+ if (await this.exists(fromFilePath)) {
+ await this.s3Client.send(
+ new CopyObjectCommand({
+ Bucket: this.config.bucket,
+ CopySource: `${this.config.bucket}/${fromFilePath}`,
+ Key: toFilePath,
+ }),
+ );
+ }
+ } catch (err) {
+ throw new Error(`Failed to copy file: ${(err as Error).message}`);
+ }
+ }
+
async read(filePath: string): Promise {
try {
const command = new GetObjectCommand({
diff --git a/apps/server/src/integrations/storage/interfaces/storage-driver.interface.ts b/apps/server/src/integrations/storage/interfaces/storage-driver.interface.ts
index 419587f4..6f18ff45 100644
--- a/apps/server/src/integrations/storage/interfaces/storage-driver.interface.ts
+++ b/apps/server/src/integrations/storage/interfaces/storage-driver.interface.ts
@@ -1,6 +1,8 @@
export interface StorageDriver {
upload(filePath: string, file: Buffer): Promise;
+ copy(fromFilePath: string, toFilePath: string): Promise;
+
read(filePath: string): Promise;
exists(filePath: string): Promise;
diff --git a/apps/server/src/integrations/storage/storage.service.ts b/apps/server/src/integrations/storage/storage.service.ts
index acbd2188..fe4c1cb5 100644
--- a/apps/server/src/integrations/storage/storage.service.ts
+++ b/apps/server/src/integrations/storage/storage.service.ts
@@ -14,6 +14,11 @@ export class StorageService {
this.logger.debug(`File uploaded successfully. Path: ${filePath}`);
}
+ async copy(fromFilePath: string, toFilePath: string) {
+ await this.storageDriver.copy(fromFilePath, toFilePath);
+ this.logger.debug(`File copied successfully. Path: ${toFilePath}`);
+ }
+
async read(filePath: string): Promise {
return this.storageDriver.read(filePath);
}
From 7adbf85030c5f7397ebc795f631231fa418bc21d Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 30 Apr 2025 14:44:58 +0100
Subject: [PATCH 45/63] v0.20.4
---
apps/client/package.json | 2 +-
apps/server/package.json | 2 +-
package.json | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/client/package.json b/apps/client/package.json
index cc1c2d0b..586f50a1 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -1,7 +1,7 @@
{
"name": "client",
"private": true,
- "version": "0.20.3",
+ "version": "0.20.4",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
diff --git a/apps/server/package.json b/apps/server/package.json
index 2f3a99bd..5082d129 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -1,6 +1,6 @@
{
"name": "server",
- "version": "0.20.3",
+ "version": "0.20.4",
"description": "",
"author": "",
"private": true,
diff --git a/package.json b/package.json
index 4ef488db..3731015c 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "docmost",
"homepage": "https://docmost.com",
- "version": "0.20.3",
+ "version": "0.20.4",
"private": true,
"scripts": {
"build": "nx run-many -t build",
From bc3cb2d63f942f221bb91b4bde31fd1c93cd79df Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Wed, 7 May 2025 15:10:58 +0100
Subject: [PATCH 46/63] fix: increase random subdomain suffix
---
apps/server/src/core/workspace/services/workspace.service.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/apps/server/src/core/workspace/services/workspace.service.ts b/apps/server/src/core/workspace/services/workspace.service.ts
index eb42f9e9..d6359893 100644
--- a/apps/server/src/core/workspace/services/workspace.service.ts
+++ b/apps/server/src/core/workspace/services/workspace.service.ts
@@ -387,14 +387,14 @@ export class WorkspaceService {
.replace(/[^a-z0-9]/g, '')
.substring(0, 20);
// Ensure we leave room for a random suffix.
- const maxSuffixLength = 3;
+ const maxSuffixLength = 6;
if (subdomain.length < 4) {
subdomain = `${subdomain}-${generateRandomSuffix(maxSuffixLength)}`;
}
if (DISALLOWED_HOSTNAMES.includes(subdomain)) {
- subdomain = `myworkspace-${generateRandomSuffix(maxSuffixLength)}`;
+ subdomain = `workspace-${generateRandomSuffix(maxSuffixLength)}`;
}
let uniqueHostname = subdomain;
From 55d1a2c9326171c091063bf567f3954f3021cb72 Mon Sep 17 00:00:00 2001
From: edo0 <16632292+edo0@users.noreply.github.com>
Date: Fri, 9 May 2025 11:11:02 +0100
Subject: [PATCH 47/63] Fix typo in enforce-sso.tsx (#1145)
---
apps/client/src/ee/security/components/enforce-sso.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/client/src/ee/security/components/enforce-sso.tsx b/apps/client/src/ee/security/components/enforce-sso.tsx
index 31a9f6fa..183046e3 100644
--- a/apps/client/src/ee/security/components/enforce-sso.tsx
+++ b/apps/client/src/ee/security/components/enforce-sso.tsx
@@ -15,7 +15,7 @@ export default function EnforceSso() {
{t("Enforce SSO")}
{t(
- "Once enforced, members will not able to login with email and password.",
+ "Once enforced, members will not be able to login with email and password.",
)}
From c6bca6a602783791428429f4bad312e48133d771 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Fri, 9 May 2025 16:44:33 +0100
Subject: [PATCH 48/63] fix deprecated kysely usage
---
apps/server/src/database/repos/user-token/user-token.repo.ts | 2 +-
apps/server/src/database/repos/workspace/workspace.repo.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/apps/server/src/database/repos/user-token/user-token.repo.ts b/apps/server/src/database/repos/user-token/user-token.repo.ts
index 58971dc4..0137cb0a 100644
--- a/apps/server/src/database/repos/user-token/user-token.repo.ts
+++ b/apps/server/src/database/repos/user-token/user-token.repo.ts
@@ -70,7 +70,7 @@ export class UserTokenRepo {
.where('userId', '=', userId)
.where('workspaceId', '=', workspaceId)
.where('type', '=', tokenType)
- .orderBy('expiresAt desc')
+ .orderBy('expiresAt', 'desc')
.execute();
}
diff --git a/apps/server/src/database/repos/workspace/workspace.repo.ts b/apps/server/src/database/repos/workspace/workspace.repo.ts
index a38d02a7..8b9765f4 100644
--- a/apps/server/src/database/repos/workspace/workspace.repo.ts
+++ b/apps/server/src/database/repos/workspace/workspace.repo.ts
@@ -70,7 +70,7 @@ export class WorkspaceRepo {
return await this.db
.selectFrom('workspaces')
.selectAll()
- .orderBy('createdAt asc')
+ .orderBy('createdAt', 'asc')
.limit(1)
.executeTakeFirst();
}
From 3a75251e75fe6dd52cb7604219e5ed8a829c2c95 Mon Sep 17 00:00:00 2001
From: fuscodev
Date: Fri, 16 May 2025 17:00:47 +0200
Subject: [PATCH 49/63] fix alignment in shared page (#1123)
---
apps/server/src/collaboration/collaboration.util.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/server/src/collaboration/collaboration.util.ts b/apps/server/src/collaboration/collaboration.util.ts
index f91d5722..db2771b2 100644
--- a/apps/server/src/collaboration/collaboration.util.ts
+++ b/apps/server/src/collaboration/collaboration.util.ts
@@ -46,7 +46,7 @@ export const tiptapExtensions = [
codeBlock: false,
}),
Comment,
- TextAlign,
+ TextAlign.configure({ types: ["heading", "paragraph"] }),
TaskList,
TaskItem,
Underline,
From 00f4588c21316e6de541e61687b4e79a0e7202c5 Mon Sep 17 00:00:00 2001
From: fuscodev
Date: Fri, 16 May 2025 17:11:29 +0200
Subject: [PATCH 50/63] fix title update (#1154)
---
.../src/features/editor/title-editor.tsx | 10 +++--
.../src/features/page/queries/page-query.ts | 44 +++++++++++--------
2 files changed, 33 insertions(+), 21 deletions(-)
diff --git a/apps/client/src/features/editor/title-editor.tsx b/apps/client/src/features/editor/title-editor.tsx
index 9cb17aa0..e5ac7da6 100644
--- a/apps/client/src/features/editor/title-editor.tsx
+++ b/apps/client/src/features/editor/title-editor.tsx
@@ -10,7 +10,7 @@ import {
pageEditorAtom,
titleEditorAtom,
} from "@/features/editor/atoms/editor-atoms";
-import { useUpdatePageMutation } from "@/features/page/queries/page-query";
+import { updatePageData, useUpdateTitlePageMutation } from "@/features/page/queries/page-query";
import { useDebouncedCallback } from "@mantine/hooks";
import { useAtom } from "jotai";
import { useQueryEmit } from "@/features/websocket/use-query-emit.ts";
@@ -38,7 +38,7 @@ export function TitleEditor({
editable,
}: TitleEditorProps) {
const { t } = useTranslation();
- const { mutateAsync: updatePageMutationAsync } = useUpdatePageMutation();
+ const { mutateAsync: updateTitlePageMutationAsync } = useUpdateTitlePageMutation();
const pageEditor = useAtomValue(pageEditorAtom);
const [, setTitleEditor] = useAtom(titleEditorAtom);
const emit = useQueryEmit();
@@ -94,7 +94,7 @@ export function TitleEditor({
return;
}
- updatePageMutationAsync({
+ updateTitlePageMutationAsync({
pageId: pageId,
title: titleEditor.getText(),
}).then((page) => {
@@ -106,6 +106,10 @@ export function TitleEditor({
payload: { title: page.title, slugId: page.slugId },
};
+ if (page.title !== titleEditor.getText()) return;
+
+ updatePageData(page);
+
localEmitter.emit("message", event);
emit(event);
});
diff --git a/apps/client/src/features/page/queries/page-query.ts b/apps/client/src/features/page/queries/page-query.ts
index 1e41b519..6842cc9e 100644
--- a/apps/client/src/features/page/queries/page-query.ts
+++ b/apps/client/src/features/page/queries/page-query.ts
@@ -63,28 +63,36 @@ export function useCreatePageMutation() {
});
}
-export function useUpdatePageMutation() {
- const queryClient = useQueryClient();
+export function updatePageData(data: IPage) {
+ const pageBySlug = queryClient.getQueryData([
+ "pages",
+ data.slugId,
+ ]);
+ const pageById = queryClient.getQueryData(["pages", data.id]);
+ if (pageBySlug) {
+ queryClient.setQueryData(["pages", data.slugId], {
+ ...pageBySlug,
+ ...data,
+ });
+ }
+
+ if (pageById) {
+ queryClient.setQueryData(["pages", data.id], { ...pageById, ...data });
+ }
+}
+
+export function useUpdateTitlePageMutation() {
+ return useMutation>({
+ mutationFn: (data) => updatePage(data),
+ });
+}
+
+export function useUpdatePageMutation() {
return useMutation>({
mutationFn: (data) => updatePage(data),
onSuccess: (data) => {
- const pageBySlug = queryClient.getQueryData([
- "pages",
- data.slugId,
- ]);
- const pageById = queryClient.getQueryData(["pages", data.id]);
-
- if (pageBySlug) {
- queryClient.setQueryData(["pages", data.slugId], {
- ...pageBySlug,
- ...data,
- });
- }
-
- if (pageById) {
- queryClient.setQueryData(["pages", data.id], { ...pageById, ...data });
- }
+ updatePage(data);
},
});
}
From 1413033568b31f11adb38cd99e30487aa42ddb11 Mon Sep 17 00:00:00 2001
From: fuscodev
Date: Fri, 16 May 2025 17:18:23 +0200
Subject: [PATCH 51/63] feat: realtime comments (#1144)
* init
* fix: close bubblemenu after comment and wait before scroll
* scroll to comment when click
* highlight comment animation
---
.../comment/components/comment-dialog.tsx | 17 +++++++++-
.../comment/components/comment-editor.tsx | 4 +++
.../comment/components/comment-list-item.tsx | 34 +++++++++++++++++--
.../comment/components/comment-list.tsx | 17 +++++++---
.../comment/components/comment.module.css | 1 +
.../src/features/editor/page-editor.tsx | 9 +++--
.../src/features/editor/styles/core.css | 13 +++++++
.../src/features/websocket/types/types.ts | 7 +++-
.../websocket/use-query-subscription.ts | 6 ++++
9 files changed, 96 insertions(+), 12 deletions(-)
diff --git a/apps/client/src/features/comment/components/comment-dialog.tsx b/apps/client/src/features/comment/components/comment-dialog.tsx
index 2e27f65b..080c731f 100644
--- a/apps/client/src/features/comment/components/comment-dialog.tsx
+++ b/apps/client/src/features/comment/components/comment-dialog.tsx
@@ -15,6 +15,7 @@ import { asideStateAtom } from "@/components/layouts/global/hooks/atoms/sidebar-
import { useEditor } from "@tiptap/react";
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
import { useTranslation } from "react-i18next";
+import { useQueryEmit } from "@/features/websocket/use-query-emit";
interface CommentDialogProps {
editor: ReturnType;
@@ -35,6 +36,8 @@ function CommentDialog({ editor, pageId }: CommentDialogProps) {
const createCommentMutation = useCreateCommentMutation();
const { isPending } = createCommentMutation;
+ const emit = useQueryEmit();
+
const handleDialogClose = () => {
setShowCommentPopup(false);
editor.chain().focus().unsetCommentDecoration().run();
@@ -63,11 +66,23 @@ function CommentDialog({ editor, pageId }: CommentDialogProps) {
.run();
setActiveCommentId(createdComment.id);
+ //unselect text to close bubble menu
+ editor.commands.setTextSelection({ from: editor.view.state.selection.from, to: editor.view.state.selection.from });
+
setAsideState({ tab: "comments", isAsideOpen: true });
setTimeout(() => {
const selector = `div[data-comment-id="${createdComment.id}"]`;
const commentElement = document.querySelector(selector);
- commentElement?.scrollIntoView();
+ commentElement?.scrollIntoView({ behavior: "smooth", block: "center" });
+
+ editor.view.dispatch(
+ editor.state.tr.scrollIntoView()
+ );
+ }, 400);
+
+ emit({
+ operation: "invalidateComment",
+ pageId: pageId,
});
} finally {
setShowCommentPopup(false);
diff --git a/apps/client/src/features/comment/components/comment-editor.tsx b/apps/client/src/features/comment/components/comment-editor.tsx
index 09116f1a..32339a3d 100644
--- a/apps/client/src/features/comment/components/comment-editor.tsx
+++ b/apps/client/src/features/comment/components/comment-editor.tsx
@@ -53,6 +53,10 @@ const CommentEditor = forwardRef(
autofocus: (autofocus && "end") || false,
});
+ useEffect(() => {
+ commentEditor.commands.setContent(defaultContent);
+ }, [defaultContent]);
+
useEffect(() => {
setTimeout(() => {
if (autofocus) {
diff --git a/apps/client/src/features/comment/components/comment-list-item.tsx b/apps/client/src/features/comment/components/comment-list-item.tsx
index 293c4f9e..9e136a1d 100644
--- a/apps/client/src/features/comment/components/comment-list-item.tsx
+++ b/apps/client/src/features/comment/components/comment-list-item.tsx
@@ -1,5 +1,5 @@
import { Group, Text, Box } from "@mantine/core";
-import React, { useState } from "react";
+import React, { useEffect, useState } from "react";
import classes from "./comment.module.css";
import { useAtom, useAtomValue } from "jotai";
import { timeAgo } from "@/lib/time";
@@ -15,12 +15,14 @@ import {
import { IComment } from "@/features/comment/types/comment.types";
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
import { currentUserAtom } from "@/features/user/atoms/current-user-atom.ts";
+import { useQueryEmit } from "@/features/websocket/use-query-emit";
interface CommentListItemProps {
comment: IComment;
+ pageId: string;
}
-function CommentListItem({ comment }: CommentListItemProps) {
+function CommentListItem({ comment, pageId }: CommentListItemProps) {
const { hovered, ref } = useHover();
const [isEditing, setIsEditing] = useState(false);
const [isLoading, setIsLoading] = useState(false);
@@ -29,6 +31,11 @@ function CommentListItem({ comment }: CommentListItemProps) {
const updateCommentMutation = useUpdateCommentMutation();
const deleteCommentMutation = useDeleteCommentMutation(comment.pageId);
const [currentUser] = useAtom(currentUserAtom);
+ const emit = useQueryEmit();
+
+ useEffect(() => {
+ setContent(comment.content)
+ }, [comment]);
async function handleUpdateComment() {
try {
@@ -39,6 +46,11 @@ function CommentListItem({ comment }: CommentListItemProps) {
};
await updateCommentMutation.mutateAsync(commentToUpdate);
setIsEditing(false);
+
+ emit({
+ operation: "invalidateComment",
+ pageId: pageId,
+ });
} catch (error) {
console.error("Failed to update comment:", error);
} finally {
@@ -50,11 +62,27 @@ function CommentListItem({ comment }: CommentListItemProps) {
try {
await deleteCommentMutation.mutateAsync(comment.id);
editor?.commands.unsetComment(comment.id);
+
+ emit({
+ operation: "invalidateComment",
+ pageId: pageId,
+ });
} catch (error) {
console.error("Failed to delete comment:", error);
}
}
+ function handleCommentClick(comment: IComment) {
+ const el = document.querySelector(`.comment-mark[data-comment-id="${comment.id}"]`);
+ if (el) {
+ el.scrollIntoView({ behavior: "smooth", block: "center" });
+ el.classList.add("comment-highlight");
+ setTimeout(() => {
+ el.classList.remove("comment-highlight");
+ }, 3000);
+ }
+ }
+
function handleEditToggle() {
setIsEditing(true);
}
@@ -99,7 +127,7 @@ function CommentListItem({ comment }: CommentListItemProps) {
{!comment.parentCommentId && comment?.selection && (
-
+ handleCommentClick(comment)}>
{comment?.selection}
)}
diff --git a/apps/client/src/features/comment/components/comment-list.tsx b/apps/client/src/features/comment/components/comment-list.tsx
index 3296d5ea..6f0d877a 100644
--- a/apps/client/src/features/comment/components/comment-list.tsx
+++ b/apps/client/src/features/comment/components/comment-list.tsx
@@ -14,6 +14,7 @@ import { usePageQuery } from "@/features/page/queries/page-query.ts";
import { IPagination } from "@/lib/types.ts";
import { extractPageSlugId } from "@/lib";
import { useTranslation } from "react-i18next";
+import { useQueryEmit } from "@/features/websocket/use-query-emit";
function CommentList() {
const { t } = useTranslation();
@@ -26,6 +27,7 @@ function CommentList() {
} = useCommentsQuery({ pageId: page?.id, limit: 100 });
const createCommentMutation = useCreateCommentMutation();
const [isLoading, setIsLoading] = useState(false);
+ const emit = useQueryEmit();
const handleAddReply = useCallback(
async (commentId: string, content: string) => {
@@ -38,6 +40,11 @@ function CommentList() {
};
await createCommentMutation.mutateAsync(commentData);
+
+ emit({
+ operation: "invalidateComment",
+ pageId: page?.id,
+ });
} catch (error) {
console.error("Failed to post comment:", error);
} finally {
@@ -59,8 +66,8 @@ function CommentList() {
data-comment-id={comment.id}
>
-
-
+
+
@@ -99,8 +106,9 @@ function CommentList() {
interface ChildCommentsProps {
comments: IPagination;
parentId: string;
+ pageId: string;
}
-const ChildComments = ({ comments, parentId }: ChildCommentsProps) => {
+const ChildComments = ({ comments, parentId, pageId }: ChildCommentsProps) => {
const getChildComments = useCallback(
(parentId: string) =>
comments.items.filter(
@@ -113,10 +121,11 @@ const ChildComments = ({ comments, parentId }: ChildCommentsProps) => {
{getChildComments(parentId).map((childComment) => (
-
+
))}
diff --git a/apps/client/src/features/comment/components/comment.module.css b/apps/client/src/features/comment/components/comment.module.css
index b3d0a261..5679c9b2 100644
--- a/apps/client/src/features/comment/components/comment.module.css
+++ b/apps/client/src/features/comment/components/comment.module.css
@@ -11,6 +11,7 @@
border-left: 2px solid var(--mantine-color-gray-6);
padding: 8px;
background: var(--mantine-color-gray-light);
+ cursor: pointer;
}
.commentEditor {
diff --git a/apps/client/src/features/editor/page-editor.tsx b/apps/client/src/features/editor/page-editor.tsx
index 32845c6d..07d9da74 100644
--- a/apps/client/src/features/editor/page-editor.tsx
+++ b/apps/client/src/features/editor/page-editor.tsx
@@ -219,9 +219,12 @@ export default function PageEditor({
setActiveCommentId(commentId);
setAsideState({ tab: "comments", isAsideOpen: true });
- const selector = `div[data-comment-id="${commentId}"]`;
- const commentElement = document.querySelector(selector);
- commentElement?.scrollIntoView();
+ //wait if aside is closed
+ setTimeout(() => {
+ const selector = `div[data-comment-id="${commentId}"]`;
+ const commentElement = document.querySelector(selector);
+ commentElement?.scrollIntoView({ behavior: "smooth", block: "center" });
+ }, 400);
};
useEffect(() => {
diff --git a/apps/client/src/features/editor/styles/core.css b/apps/client/src/features/editor/styles/core.css
index 952e91fb..38acb74b 100644
--- a/apps/client/src/features/editor/styles/core.css
+++ b/apps/client/src/features/editor/styles/core.css
@@ -144,6 +144,19 @@
border-bottom: 2px solid rgb(166, 158, 12);
}
+ .comment-highlight {
+ animation: flash-highlight 3s ease-out;
+ }
+
+ @keyframes flash-highlight {
+ 0% {
+ background-color: #ff4d4d;
+ }
+ 100% {
+ background-color: rgba(255, 215, 0, 0.14);
+ }
+ }
+
.resize-cursor {
cursor: ew-resize;
cursor: col-resize;
diff --git a/apps/client/src/features/websocket/types/types.ts b/apps/client/src/features/websocket/types/types.ts
index a3e32ac2..48e7d819 100644
--- a/apps/client/src/features/websocket/types/types.ts
+++ b/apps/client/src/features/websocket/types/types.ts
@@ -7,6 +7,11 @@ export type InvalidateEvent = {
id?: string;
};
+export type InvalidateCommentsEvent = {
+ operation: "invalidateComment";
+ pageId: string;
+};
+
export type UpdateEvent = {
operation: "updateOne";
spaceId: string;
@@ -52,4 +57,4 @@ export type DeleteTreeNodeEvent = {
}
};
-export type WebSocketEvent = InvalidateEvent | UpdateEvent | DeleteEvent | AddTreeNodeEvent | MoveTreeNodeEvent | DeleteTreeNodeEvent;
+export type WebSocketEvent = InvalidateEvent | InvalidateCommentsEvent | UpdateEvent | DeleteEvent | AddTreeNodeEvent | MoveTreeNodeEvent | DeleteTreeNodeEvent;
diff --git a/apps/client/src/features/websocket/use-query-subscription.ts b/apps/client/src/features/websocket/use-query-subscription.ts
index 576b6777..c9e53aa6 100644
--- a/apps/client/src/features/websocket/use-query-subscription.ts
+++ b/apps/client/src/features/websocket/use-query-subscription.ts
@@ -3,6 +3,7 @@ import { socketAtom } from "@/features/websocket/atoms/socket-atom.ts";
import { useAtom } from "jotai";
import { useQueryClient } from "@tanstack/react-query";
import { WebSocketEvent } from "@/features/websocket/types";
+import { RQ_KEY } from "../comment/queries/comment-query";
export const useQuerySubscription = () => {
const queryClient = useQueryClient();
@@ -21,6 +22,11 @@ export const useQuerySubscription = () => {
queryKey: [...data.entity, data.id].filter(Boolean),
});
break;
+ case "invalidateComment":
+ queryClient.invalidateQueries({
+ queryKey: RQ_KEY(data.pageId),
+ });
+ break;
case "updateOne":
entity = data.entity[0];
if (entity === "pages") {
From fb7e4a79569971436b5c2ed068f096f09d6fd5c2 Mon Sep 17 00:00:00 2001
From: fuscodev
Date: Fri, 16 May 2025 17:24:31 +0200
Subject: [PATCH 52/63] fix: copy/move select (#1174)
---
.../src/features/space/components/sidebar/space-select.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/client/src/features/space/components/sidebar/space-select.tsx b/apps/client/src/features/space/components/sidebar/space-select.tsx
index db540474..a20c7e2d 100644
--- a/apps/client/src/features/space/components/sidebar/space-select.tsx
+++ b/apps/client/src/features/space/components/sidebar/space-select.tsx
@@ -81,7 +81,7 @@ export function SpaceSelect({
nothingFoundMessage={t("No space found")}
limit={50}
checkIconPosition="right"
- comboboxProps={{ width, withinPortal: false }}
+ comboboxProps={{ width, withinPortal: true, position: "bottom" }}
dropdownOpened={opened}
/>
);
From 1c200dbd0f23ac4303aeb3fa5c85e786f5d84e77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9E=81=E5=9C=B0?=
Date: Fri, 16 May 2025 23:26:05 +0800
Subject: [PATCH 53/63] fix(table-hover): adjust row height to prevent
unexpected scrollbar on hover (#1124)
fix: Hover table style height error causing scrollbar to appear #1108
---
apps/client/src/features/editor/styles/table.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/client/src/features/editor/styles/table.css b/apps/client/src/features/editor/styles/table.css
index 19a1029b..7d02ef03 100644
--- a/apps/client/src/features/editor/styles/table.css
+++ b/apps/client/src/features/editor/styles/table.css
@@ -47,7 +47,7 @@
.column-resize-handle {
background-color: #adf;
- bottom: -2px;
+ bottom: -1px;
position: absolute;
right: -2px;
pointer-events: none;
From b0491d5da4772285382436beb084daad6c4b1513 Mon Sep 17 00:00:00 2001
From: fuscodev
Date: Fri, 16 May 2025 20:15:11 +0200
Subject: [PATCH 54/63] feat: create new page from mention (#1153)
* init
* create page in relative parent root
---
.../components/mention/mention-list.tsx | 98 +++++++++++++++++--
1 file changed, 90 insertions(+), 8 deletions(-)
diff --git a/apps/client/src/features/editor/components/mention/mention-list.tsx b/apps/client/src/features/editor/components/mention/mention-list.tsx
index 4a4ae74a..389c2ce5 100644
--- a/apps/client/src/features/editor/components/mention/mention-list.tsx
+++ b/apps/client/src/features/editor/components/mention/mention-list.tsx
@@ -3,6 +3,7 @@ import React, {
useCallback,
useEffect,
useImperativeHandle,
+ useMemo,
useRef,
useState,
} from "react";
@@ -18,7 +19,7 @@ import {
import clsx from "clsx";
import classes from "./mention.module.css";
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
-import { IconFileDescription } from "@tabler/icons-react";
+import { IconFileDescription, IconPlus } from "@tabler/icons-react";
import { useSpaceQuery } from "@/features/space/queries/space-query.ts";
import { useParams } from "react-router-dom";
import { v7 as uuid7 } from "uuid";
@@ -28,14 +29,28 @@ import {
MentionListProps,
MentionSuggestionItem,
} from "@/features/editor/components/mention/mention.type.ts";
+import { IPage } from "@/features/page/types/page.types";
+import { useCreatePageMutation, usePageQuery } from "@/features/page/queries/page-query";
+import { treeDataAtom } from "@/features/page/tree/atoms/tree-data-atom";
+import { SimpleTree } from "react-arborist";
+import { SpaceTreeNode } from "@/features/page/tree/types";
+import { useTranslation } from "react-i18next";
+import { useQueryEmit } from "@/features/websocket/use-query-emit";
+import { extractPageSlugId } from "@/lib";
const MentionList = forwardRef((props, ref) => {
const [selectedIndex, setSelectedIndex] = useState(1);
const viewportRef = useRef(null);
- const { spaceSlug } = useParams();
+ const { pageSlug, spaceSlug } = useParams();
+ const { data: page } = usePageQuery({ pageId: extractPageSlugId(pageSlug) });
const { data: space } = useSpaceQuery(spaceSlug);
const [currentUser] = useAtom(currentUserAtom);
const [renderItems, setRenderItems] = useState([]);
+ const { t } = useTranslation();
+ const [data, setData] = useAtom(treeDataAtom);
+ const tree = useMemo(() => new SimpleTree(data), [data]);
+ const createPageMutation = useCreatePageMutation();
+ const emit = useQueryEmit();
const { data: suggestion, isLoading } = useSearchSuggestionsQuery({
query: props.query,
@@ -45,12 +60,23 @@ const MentionList = forwardRef((props, ref) => {
limit: 10,
});
+ const createPageItem = (label: string) : MentionSuggestionItem => {
+ return {
+ id: null,
+ label: label,
+ entityType: "page",
+ entityId: null,
+ slugId: null,
+ icon: null,
+ }
+ }
+
useEffect(() => {
if (suggestion && !isLoading) {
let items: MentionSuggestionItem[] = [];
if (suggestion?.users?.length > 0) {
- items.push({ entityType: "header", label: "Users" });
+ items.push({ entityType: "header", label: t("Users") });
items = items.concat(
suggestion.users.map((user) => ({
@@ -64,7 +90,7 @@ const MentionList = forwardRef((props, ref) => {
}
if (suggestion?.pages?.length > 0) {
- items.push({ entityType: "header", label: "Pages" });
+ items.push({ entityType: "header", label: t("Pages") });
items = items.concat(
suggestion.pages.map((page) => ({
id: uuid7(),
@@ -76,6 +102,7 @@ const MentionList = forwardRef((props, ref) => {
})),
);
}
+ items.push(createPageItem(props.query));
setRenderItems(items);
// update editor storage
@@ -96,7 +123,7 @@ const MentionList = forwardRef((props, ref) => {
creatorId: currentUser?.user.id,
});
}
- if (item.entityType === "page") {
+ if (item.entityType === "page" && item.id!==null) {
props.command({
id: item.id,
label: item.label || "Untitled",
@@ -106,6 +133,9 @@ const MentionList = forwardRef((props, ref) => {
creatorId: currentUser?.user.id,
});
}
+ if (item.entityType === "page" && item.id===null) {
+ createPage(item.label);
+ }
}
},
[renderItems],
@@ -167,6 +197,58 @@ const MentionList = forwardRef((props, ref) => {
},
}));
+ const createPage = async (title: string) => {
+ const payload: { spaceId: string; parentPageId?: string; title: string } = {
+ spaceId: space.id,
+ parentPageId: page.id || null,
+ title: title
+ };
+
+ let createdPage: IPage;
+ try {
+ createdPage = await createPageMutation.mutateAsync(payload);
+ const parentId = page.id || null;
+ const data = {
+ id: createdPage.id,
+ slugId: createdPage.slugId,
+ name: createdPage.title,
+ position: createdPage.position,
+ spaceId: createdPage.spaceId,
+ parentPageId: createdPage.parentPageId,
+ children: [],
+ } as any;
+
+ const lastIndex = tree.data.length;
+
+ tree.create({ parentId, index: lastIndex, data });
+ setData(tree.data);
+
+ props.command({
+ id: uuid7(),
+ label: createdPage.title || "Untitled",
+ entityType: "page",
+ entityId: createdPage.id,
+ slugId: createdPage.slugId,
+ creatorId: currentUser?.user.id,
+ });
+
+ setTimeout(() => {
+ emit({
+ operation: "addTreeNode",
+ spaceId: space.id,
+ payload: {
+ parentId,
+ index: lastIndex,
+ data,
+ },
+ });
+ }, 50);
+
+ } catch (err) {
+ throw new Error("Failed to create page");
+ }
+ }
+
// if no results and enter what to do?
useEffect(() => {
@@ -178,7 +260,7 @@ const MentionList = forwardRef((props, ref) => {
if (renderItems.length === 0) {
return (
- No results
+ { t("No results") }
);
}
@@ -248,14 +330,14 @@ const MentionList = forwardRef((props, ref) => {
color="gray"
size={18}
>
-
+ { (item.id) ? : }
)}
- {item.label}
+ { (item.id) ? item.label : t("Create page") + ': ' + item.label }
From e3ba817723faab9bffa87a4d7fea2863f9425d01 Mon Sep 17 00:00:00 2001
From: fuscodev
Date: Fri, 16 May 2025 21:01:27 +0200
Subject: [PATCH 55/63] feat: comment editor emoji picker and ctrl+enter action
(#1121)
* commenteditor-emoji-picker
* capture Mac command key
* remove tooltip
---------
Co-authored-by: Philipinho <16838612+Philipinho@users.noreply.github.com>
---
.../comment/components/comment-actions.tsx | 4 +--
.../comment/components/comment-dialog.tsx | 1 +
.../comment/components/comment-editor.tsx | 31 +++++++++++++++++++
.../comment/components/comment-list-item.tsx | 1 +
.../comment/components/comment-list.tsx | 1 +
.../comment/components/comment.module.css | 4 ++-
.../emoji-menu/render-emoji-items.ts | 2 +-
7 files changed, 40 insertions(+), 4 deletions(-)
diff --git a/apps/client/src/features/comment/components/comment-actions.tsx b/apps/client/src/features/comment/components/comment-actions.tsx
index e5c4f1a2..882c6f74 100644
--- a/apps/client/src/features/comment/components/comment-actions.tsx
+++ b/apps/client/src/features/comment/components/comment-actions.tsx
@@ -1,4 +1,4 @@
-import { Button, Group } from "@mantine/core";
+import { Button, Group, Tooltip } from "@mantine/core";
import { useTranslation } from "react-i18next";
type CommentActionsProps = {
@@ -15,7 +15,7 @@ function CommentActions({
isCommentEditor,
}: CommentActionsProps) {
const { t } = useTranslation();
-
+
return (
{isCommentEditor && (
diff --git a/apps/client/src/features/comment/components/comment-dialog.tsx b/apps/client/src/features/comment/components/comment-dialog.tsx
index 080c731f..7a4b55aa 100644
--- a/apps/client/src/features/comment/components/comment-dialog.tsx
+++ b/apps/client/src/features/comment/components/comment-dialog.tsx
@@ -124,6 +124,7 @@ function CommentDialog({ editor, pageId }: CommentDialogProps) {
{
+ if (
+ [
+ "ArrowUp",
+ "ArrowDown",
+ "ArrowLeft",
+ "ArrowRight",
+ "Enter",
+ ].includes(event.key)
+ ) {
+ const emojiCommand = document.querySelector("#emoji-command");
+ if (emojiCommand) {
+ return true;
+ }
+ }
+
+ if ((event.ctrlKey || event.metaKey) && event.key === "Enter") {
+ event.preventDefault();
+ if (onSave) onSave();
+
+ return true;
+ }
+ },
+ },
+ },
onUpdate({ editor }) {
if (onUpdate) onUpdate(editor.getJSON());
},
diff --git a/apps/client/src/features/comment/components/comment-list-item.tsx b/apps/client/src/features/comment/components/comment-list-item.tsx
index 9e136a1d..cbf2a4e9 100644
--- a/apps/client/src/features/comment/components/comment-list-item.tsx
+++ b/apps/client/src/features/comment/components/comment-list-item.tsx
@@ -140,6 +140,7 @@ function CommentListItem({ comment, pageId }: CommentListItemProps) {
defaultContent={content}
editable={true}
onUpdate={(newContent: any) => setContent(newContent)}
+ onSave={handleUpdateComment}
autofocus={true}
/>
diff --git a/apps/client/src/features/comment/components/comment-list.tsx b/apps/client/src/features/comment/components/comment-list.tsx
index 6f0d877a..1aded495 100644
--- a/apps/client/src/features/comment/components/comment-list.tsx
+++ b/apps/client/src/features/comment/components/comment-list.tsx
@@ -151,6 +151,7 @@ const CommentEditorWithActions = ({ commentId, onSave, isLoading }) => {
{focused && }
diff --git a/apps/client/src/features/comment/components/comment.module.css b/apps/client/src/features/comment/components/comment.module.css
index 5679c9b2..dad0d94a 100644
--- a/apps/client/src/features/comment/components/comment.module.css
+++ b/apps/client/src/features/comment/components/comment.module.css
@@ -17,17 +17,19 @@
.commentEditor {
.focused {
+ border-radius: var(--mantine-radius-sm);
box-shadow: 0 0 0 2px var(--mantine-color-blue-3);
}
.ProseMirror :global(.ProseMirror){
+ border-radius: var(--mantine-radius-sm);
max-width: 100%;
white-space: pre-wrap;
word-break: break-word;
max-height: 20vh;
padding-left: 6px;
padding-right: 6px;
- margin-top: 2px;
+ margin-top: 10px;
margin-bottom: 2px;
overflow: hidden auto;
}
diff --git a/apps/client/src/features/editor/components/emoji-menu/render-emoji-items.ts b/apps/client/src/features/editor/components/emoji-menu/render-emoji-items.ts
index ba035a8b..82fb24a9 100644
--- a/apps/client/src/features/editor/components/emoji-menu/render-emoji-items.ts
+++ b/apps/client/src/features/editor/components/emoji-menu/render-emoji-items.ts
@@ -33,7 +33,7 @@ const renderEmojiItems = () => {
showOnCreate: true,
interactive: true,
trigger: "manual",
- placement: "bottom-start",
+ placement: "bottom",
});
},
onStart: (props: {
From 4a0b4040edb2dec0e265c36aaab1089c93348333 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Sat, 17 May 2025 18:03:01 +0000
Subject: [PATCH 56/63] Add second plan (#1187)
---
apps/client/src/ee/billing/types/billing.types.ts | 1 +
apps/client/src/ee/hooks/use-plan.tsx | 8 ++++++--
apps/client/src/ee/security/pages/security.tsx | 5 +++--
apps/server/src/ee | 2 +-
4 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/apps/client/src/ee/billing/types/billing.types.ts b/apps/client/src/ee/billing/types/billing.types.ts
index 89d936f0..240e55fd 100644
--- a/apps/client/src/ee/billing/types/billing.types.ts
+++ b/apps/client/src/ee/billing/types/billing.types.ts
@@ -1,5 +1,6 @@
export enum BillingPlan {
STANDARD = "standard",
+ BUSINESS = "business",
}
export interface IBilling {
diff --git a/apps/client/src/ee/hooks/use-plan.tsx b/apps/client/src/ee/hooks/use-plan.tsx
index 52790178..a9296c58 100644
--- a/apps/client/src/ee/hooks/use-plan.tsx
+++ b/apps/client/src/ee/hooks/use-plan.tsx
@@ -2,14 +2,18 @@ import { useAtom } from "jotai";
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
import { BillingPlan } from "@/ee/billing/types/billing.types.ts";
-export const usePlan = () => {
+const usePlan = () => {
const [workspace] = useAtom(workspaceAtom);
const isStandard =
typeof workspace?.plan === "string" &&
workspace?.plan.toLowerCase() === BillingPlan.STANDARD.toLowerCase();
- return { isStandard };
+ const isBusiness =
+ typeof workspace?.plan === "string" &&
+ workspace?.plan.toLowerCase() === BillingPlan.BUSINESS.toLowerCase();
+
+ return { isStandard, isBusiness };
};
export default usePlan;
diff --git a/apps/client/src/ee/security/pages/security.tsx b/apps/client/src/ee/security/pages/security.tsx
index 9a85cff2..de8efc06 100644
--- a/apps/client/src/ee/security/pages/security.tsx
+++ b/apps/client/src/ee/security/pages/security.tsx
@@ -10,11 +10,13 @@ import EnforceSso from "@/ee/security/components/enforce-sso.tsx";
import AllowedDomains from "@/ee/security/components/allowed-domains.tsx";
import { useTranslation } from "react-i18next";
import useLicense from "@/ee/hooks/use-license.tsx";
+import usePlan from "@/ee/hooks/use-plan.tsx";
export default function Security() {
const { t } = useTranslation();
const { isAdmin } = useUserRole();
const { hasLicenseKey } = useLicense();
+ const { isBusiness } = usePlan();
if (!isAdmin) {
return null;
@@ -35,8 +37,7 @@ export default function Security() {
Single sign-on (SSO)
- {/*TODO: revisit when we add a second plan */}
- {!isCloud() && hasLicenseKey ? (
+ {(isCloud() && isBusiness) || (!isCloud() && hasLicenseKey) ? (
<>
diff --git a/apps/server/src/ee b/apps/server/src/ee
index 96404fc1..12f576ce 160000
--- a/apps/server/src/ee
+++ b/apps/server/src/ee
@@ -1 +1 @@
-Subproject commit 96404fc121844a707bd0fb1e280df6e2d52e8973
+Subproject commit 12f576ce721747903a9fadef3d58e0aa4e7ea3da
From 7491224d0ffd0b931137a3b4bc7228ffbdd6ef7a Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Sat, 17 May 2025 18:17:34 +0000
Subject: [PATCH 57/63] hide shared page branding in EE (#1193)
* hide shared page branding in EE
* Hide branding in business plan
---
.../features/share/components/share-branding.tsx | 16 ++++++++++++++++
.../features/share/components/share-shell.tsx | 12 ++----------
.../src/features/share/types/share.types.ts | 2 ++
apps/client/src/pages/share/shared-page.tsx | 5 ++++-
apps/server/src/core/share/share.controller.ts | 16 ++++++++++++++--
apps/server/src/ee | 2 +-
6 files changed, 39 insertions(+), 14 deletions(-)
create mode 100644 apps/client/src/features/share/components/share-branding.tsx
diff --git a/apps/client/src/features/share/components/share-branding.tsx b/apps/client/src/features/share/components/share-branding.tsx
new file mode 100644
index 00000000..4b3dfb3e
--- /dev/null
+++ b/apps/client/src/features/share/components/share-branding.tsx
@@ -0,0 +1,16 @@
+import { Affix, Button } from "@mantine/core";
+
+export default function ShareBranding() {
+ return (
+
+
+ Powered by Docmost
+
+
+ );
+}
diff --git a/apps/client/src/features/share/components/share-shell.tsx b/apps/client/src/features/share/components/share-shell.tsx
index 7fa0c941..8550f59f 100644
--- a/apps/client/src/features/share/components/share-shell.tsx
+++ b/apps/client/src/features/share/components/share-shell.tsx
@@ -36,6 +36,7 @@ import {
} from "@/features/search/components/search-control.tsx";
import { ShareSearchSpotlight } from "@/features/search/share-search-spotlight";
import { shareSearchSpotlight } from "@/features/search/constants";
+import ShareBranding from '@/features/share/components/share-branding.tsx';
const MemoizedSharedTree = React.memo(SharedTree);
@@ -163,16 +164,7 @@ export default function ShareShell({
{children}
-
-
- Powered by Docmost
-
-
+ {data && shareId && !data.hasLicenseKey && }
;
+ hasLicenseKey: boolean;
}
diff --git a/apps/client/src/pages/share/shared-page.tsx b/apps/client/src/pages/share/shared-page.tsx
index a574a614..50e5837d 100644
--- a/apps/client/src/pages/share/shared-page.tsx
+++ b/apps/client/src/pages/share/shared-page.tsx
@@ -7,8 +7,9 @@ import React, { useEffect } from "react";
import ReadonlyPageEditor from "@/features/editor/readonly-page-editor.tsx";
import { extractPageSlugId } from "@/lib";
import { Error404 } from "@/components/ui/error-404.tsx";
+import ShareBranding from "@/features/share/components/share-branding.tsx";
-export default function SingleSharedPage() {
+export default function SharedPage() {
const { t } = useTranslation();
const { pageSlug } = useParams();
const { shareId } = useParams();
@@ -53,6 +54,8 @@ export default function SingleSharedPage() {
content={data.page.content}
/>
+
+ {data && !shareId && !data.hasLicenseKey && }
);
}
diff --git a/apps/server/src/core/share/share.controller.ts b/apps/server/src/core/share/share.controller.ts
index 5e8debe0..b9a9fcbf 100644
--- a/apps/server/src/core/share/share.controller.ts
+++ b/apps/server/src/core/share/share.controller.ts
@@ -30,6 +30,7 @@ import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
import { Public } from '../../common/decorators/public.decorator';
import { ShareRepo } from '@docmost/db/repos/share/share.repo';
import { PaginationOptions } from '@docmost/db/pagination/pagination-options';
+import { EnvironmentService } from '../../integrations/environment/environment.service';
@UseGuards(JwtAuthGuard)
@Controller('shares')
@@ -39,6 +40,7 @@ export class ShareController {
private readonly spaceAbility: SpaceAbilityFactory,
private readonly shareRepo: ShareRepo,
private readonly pageRepo: PageRepo,
+ private readonly environmentService: EnvironmentService,
) {}
@HttpCode(HttpStatus.OK)
@@ -61,7 +63,12 @@ export class ShareController {
throw new BadRequestException();
}
- return this.shareService.getSharedPage(dto, workspace.id);
+ return {
+ ...(await this.shareService.getSharedPage(dto, workspace.id)),
+ hasLicenseKey:
+ Boolean(workspace.licenseKey) ||
+ (this.environmentService.isCloud() && workspace.plan === 'business'),
+ };
}
@Public()
@@ -166,6 +173,11 @@ export class ShareController {
@Body() dto: ShareIdDto,
@AuthWorkspace() workspace: Workspace,
) {
- return this.shareService.getShareTree(dto.shareId, workspace.id);
+ return {
+ ...(await this.shareService.getShareTree(dto.shareId, workspace.id)),
+ hasLicenseKey:
+ Boolean(workspace.licenseKey) ||
+ (this.environmentService.isCloud() && workspace.plan === 'business'),
+ };
}
}
diff --git a/apps/server/src/ee b/apps/server/src/ee
index 12f576ce..77d86e61 160000
--- a/apps/server/src/ee
+++ b/apps/server/src/ee
@@ -1 +1 @@
-Subproject commit 12f576ce721747903a9fadef3d58e0aa4e7ea3da
+Subproject commit 77d86e6119a22981f9fc7658006229dfeb96122b
From 343b2976c2a106c76a770533b450616dff7d4576 Mon Sep 17 00:00:00 2001
From: sanua356 <51795446+sanua356@users.noreply.github.com>
Date: Mon, 19 May 2025 22:05:31 +0300
Subject: [PATCH 58/63] #1186/chore: add support language abap syntax highlight
(#1188)
---
apps/client/package.json | 1 +
apps/client/src/features/editor/extensions/extensions.ts | 3 ++-
pnpm-lock.yaml | 8 ++++++++
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/apps/client/package.json b/apps/client/package.json
index 586f50a1..3a658caf 100644
--- a/apps/client/package.json
+++ b/apps/client/package.json
@@ -29,6 +29,7 @@
"clsx": "^2.1.1",
"emoji-mart": "^5.6.0",
"file-saver": "^2.0.5",
+ "highlightjs-sap-abap": "^0.3.0",
"i18next": "^23.14.0",
"i18next-http-backend": "^2.6.1",
"jotai": "^2.12.1",
diff --git a/apps/client/src/features/editor/extensions/extensions.ts b/apps/client/src/features/editor/extensions/extensions.ts
index c131ad70..eb0e62f2 100644
--- a/apps/client/src/features/editor/extensions/extensions.ts
+++ b/apps/client/src/features/editor/extensions/extensions.ts
@@ -58,6 +58,7 @@ import ExcalidrawView from "@/features/editor/components/excalidraw/excalidraw-v
import EmbedView from "@/features/editor/components/embed/embed-view.tsx";
import plaintext from "highlight.js/lib/languages/plaintext";
import powershell from "highlight.js/lib/languages/powershell";
+import abap from "highlightjs-sap-abap";
import elixir from "highlight.js/lib/languages/elixir";
import erlang from "highlight.js/lib/languages/erlang";
import dockerfile from "highlight.js/lib/languages/dockerfile";
@@ -76,7 +77,7 @@ import { CharacterCount } from "@tiptap/extension-character-count";
const lowlight = createLowlight(common);
lowlight.register("mermaid", plaintext);
lowlight.register("powershell", powershell);
-lowlight.register("powershell", powershell);
+lowlight.register("abap", abap);
lowlight.register("erlang", erlang);
lowlight.register("elixir", elixir);
lowlight.register("dockerfile", dockerfile);
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 2fd73d8b..a57f3fe1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -257,6 +257,9 @@ importers:
file-saver:
specifier: ^2.0.5
version: 2.0.5
+ highlightjs-sap-abap:
+ specifier: ^0.3.0
+ version: 0.3.0
i18next:
specifier: ^23.14.0
version: 23.14.0
@@ -5872,6 +5875,9 @@ packages:
resolution: {integrity: sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==}
engines: {node: '>=12.0.0'}
+ highlightjs-sap-abap@0.3.0:
+ resolution: {integrity: sha512-nSiUvEOCycjtFA3pHaTowrbAAk5+lciBHyoVkDsd6FTRBtW9sT2dt42o2jAKbXjZVUidtacdk+j0Y2xnd233Mw==}
+
hoist-non-react-statics@3.3.2:
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
@@ -15436,6 +15442,8 @@ snapshots:
highlight.js@11.10.0: {}
+ highlightjs-sap-abap@0.3.0: {}
+
hoist-non-react-statics@3.3.2:
dependencies:
react-is: 16.13.1
From 858ff9da068ace1aee359d157aac887f3c66c928 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Tue, 20 May 2025 09:27:30 -0700
Subject: [PATCH 59/63] sync
---
apps/server/src/ee | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/server/src/ee b/apps/server/src/ee
index 77d86e61..b312008b 160000
--- a/apps/server/src/ee
+++ b/apps/server/src/ee
@@ -1 +1 @@
-Subproject commit 77d86e6119a22981f9fc7658006229dfeb96122b
+Subproject commit b312008b4b7ed3d5862436b279d91aeddb6048d7
From ce1503af852aa0e0da95d4db790b12cc09926fde Mon Sep 17 00:00:00 2001
From: fuscodev
Date: Sun, 8 Jun 2025 04:27:09 +0200
Subject: [PATCH 60/63] fix: sidebar list when changing workspace (#1150)
* init
* navigate in overview if current page is in deleted node
* fix: implement pagination in sidebar-pages queries
* fix: appendNodeChildren()
Preserve deeper children if they exist and remove node if deleted
---
.../src/features/editor/title-editor.tsx | 2 +-
.../src/features/page/queries/page-query.ts | 193 +++++++++++++++++-
.../features/page/services/page-service.ts | 27 +++
.../page/tree/atoms/tree-data-atom.ts | 15 ++
.../page/tree/components/space-tree.tsx | 61 +++---
.../page/tree/hooks/use-tree-mutation.ts | 24 ++-
.../src/features/page/tree/utils/utils.ts | 35 +++-
.../src/features/websocket/types/types.ts | 5 +-
.../websocket/use-query-subscription.ts | 23 ++-
9 files changed, 326 insertions(+), 59 deletions(-)
diff --git a/apps/client/src/features/editor/title-editor.tsx b/apps/client/src/features/editor/title-editor.tsx
index e5ac7da6..869cb1eb 100644
--- a/apps/client/src/features/editor/title-editor.tsx
+++ b/apps/client/src/features/editor/title-editor.tsx
@@ -103,7 +103,7 @@ export function TitleEditor({
spaceId: page.spaceId,
entity: ["pages"],
id: page.id,
- payload: { title: page.title, slugId: page.slugId },
+ payload: { title: page.title, slugId: page.slugId, parentPageId: page.parentPageId, icon: page.icon },
};
if (page.title !== titleEditor.getText()) return;
diff --git a/apps/client/src/features/page/queries/page-query.ts b/apps/client/src/features/page/queries/page-query.ts
index 6842cc9e..6a460c68 100644
--- a/apps/client/src/features/page/queries/page-query.ts
+++ b/apps/client/src/features/page/queries/page-query.ts
@@ -1,5 +1,8 @@
import {
+ InfiniteData,
+ QueryKey,
useInfiniteQuery,
+ UseInfiniteQueryResult,
useMutation,
useQuery,
useQueryClient,
@@ -14,6 +17,7 @@ import {
movePage,
getPageBreadcrumbs,
getRecentChanges,
+ getAllSidebarPages,
} from "@/features/page/services/page-service";
import {
IMovePage,
@@ -56,7 +60,9 @@ export function useCreatePageMutation() {
const { t } = useTranslation();
return useMutation>({
mutationFn: (data) => createPage(data),
- onSuccess: (data) => {},
+ onSuccess: (data) => {
+ invalidateOnCreatePage(data);
+ },
onError: (error) => {
notifications.show({ message: t("Failed to create page"), color: "red" });
},
@@ -80,6 +86,8 @@ export function updatePageData(data: IPage) {
if (pageById) {
queryClient.setQueryData(["pages", data.id], { ...pageById, ...data });
}
+
+ invalidateOnUpdatePage(data.spaceId, data.parentPageId, data.id, data.title, data.icon);
}
export function useUpdateTitlePageMutation() {
@@ -93,6 +101,8 @@ export function useUpdatePageMutation() {
mutationFn: (data) => updatePage(data),
onSuccess: (data) => {
updatePage(data);
+
+ invalidateOnUpdatePage(data.spaceId, data.parentPageId, data.id, data.title, data.icon);
},
});
}
@@ -101,8 +111,9 @@ export function useDeletePageMutation() {
const { t } = useTranslation();
return useMutation({
mutationFn: (pageId: string) => deletePage(pageId),
- onSuccess: () => {
+ onSuccess: (data, pageId) => {
notifications.show({ message: t("Page deleted successfully") });
+ invalidateOnDeletePage(pageId);
},
onError: (error) => {
notifications.show({ message: t("Failed to delete page"), color: "red" });
@@ -113,15 +124,21 @@ export function useDeletePageMutation() {
export function useMovePageMutation() {
return useMutation({
mutationFn: (data) => movePage(data),
+ onSuccess: () => {
+ invalidateOnMovePage();
+ },
});
}
-export function useGetSidebarPagesQuery(
- data: SidebarPagesParams,
-): UseQueryResult, Error> {
- return useQuery({
+export function useGetSidebarPagesQuery(data: SidebarPagesParams|null): UseInfiniteQueryResult, unknown>> {
+ return useInfiniteQuery({
queryKey: ["sidebar-pages", data],
- queryFn: () => getSidebarPages(data),
+ queryFn: ({ pageParam }) => getSidebarPages({ ...data, page: pageParam }),
+ initialPageParam: 1,
+ getPreviousPageParam: (firstPage) =>
+ firstPage.meta.hasPrevPage ? firstPage.meta.page - 1 : undefined,
+ getNextPageParam: (lastPage) =>
+ lastPage.meta.hasNextPage ? lastPage.meta.page + 1 : undefined,
});
}
@@ -149,14 +166,16 @@ export function usePageBreadcrumbsQuery(
});
}
-export async function fetchAncestorChildren(params: SidebarPagesParams) {
+export async function fetchAllAncestorChildren(params: SidebarPagesParams) {
// not using a hook here, so we can call it inside a useEffect hook
const response = await queryClient.fetchQuery({
queryKey: ["sidebar-pages", params],
- queryFn: () => getSidebarPages(params),
+ queryFn: () => getAllSidebarPages(params),
staleTime: 30 * 60 * 1000,
});
- return buildTree(response.items);
+
+ const allItems = response.pages.flatMap((page) => page.items);
+ return buildTree(allItems);
}
export function useRecentChangesQuery(
@@ -168,3 +187,157 @@ export function useRecentChangesQuery(
refetchOnMount: true,
});
}
+
+export function invalidateOnCreatePage(data: Partial) {
+ const newPage: Partial = {
+ creatorId: data.creatorId,
+ hasChildren: data.hasChildren,
+ icon: data.icon,
+ id: data.id,
+ parentPageId: data.parentPageId,
+ position: data.position,
+ slugId: data.slugId,
+ spaceId: data.spaceId,
+ title: data.title,
+ };
+
+ let queryKey: QueryKey = null;
+ if (data.parentPageId===null) {
+ queryKey = ['root-sidebar-pages', data.spaceId];
+ }else{
+ queryKey = ['sidebar-pages', {pageId: data.parentPageId, spaceId: data.spaceId}]
+ }
+
+ //update all sidebar pages
+ queryClient.setQueryData>>>(queryKey, (old) => {
+ if (!old) return old;
+ return {
+ ...old,
+ pages: old.pages.map((page,index) => {
+ if (index === old.pages.length - 1) {
+ return {
+ ...page,
+ items: [...page.items, newPage],
+ };
+ }
+ return page;
+ }),
+ };
+ });
+
+ //update sidebar haschildren
+ if (data.parentPageId!==null){
+ //update sub sidebar pages haschildern
+ const subSideBarMatches = queryClient.getQueriesData({
+ queryKey: ['sidebar-pages'],
+ exact: false,
+ });
+
+ subSideBarMatches.forEach(([key, d]) => {
+ queryClient.setQueryData>>(key, (old) => {
+ if (!old) return old;
+ return {
+ ...old,
+ pages: old.pages.map((page) => ({
+ ...page,
+ items: page.items.map((sidebarPage: IPage) =>
+ sidebarPage.id === data.parentPageId ? { ...sidebarPage, hasChildren: true } : sidebarPage
+ )
+ })),
+ };
+ });
+ });
+
+ //update root sidebar pages haschildern
+ const rootSideBarMatches = queryClient.getQueriesData({
+ queryKey: ['root-sidebar-pages', data.spaceId],
+ exact: false,
+ });
+
+ rootSideBarMatches.forEach(([key, d]) => {
+ queryClient.setQueryData>>(key, (old) => {
+ if (!old) return old;
+ return {
+ ...old,
+ pages: old.pages.map((page) => ({
+ ...page,
+ items: page.items.map((sidebarPage: IPage) =>
+ sidebarPage.id === data.parentPageId ? { ...sidebarPage, hasChildren: true } : sidebarPage
+ )
+ })),
+ };
+ });
+ });
+ }
+
+ //update recent changes
+ queryClient.invalidateQueries({
+ queryKey: ["recent-changes", data.spaceId],
+ });
+}
+
+export function invalidateOnUpdatePage(spaceId: string, parentPageId: string, id: string, title: string, icon: string) {
+ let queryKey: QueryKey = null;
+ if(parentPageId===null){
+ queryKey = ['root-sidebar-pages', spaceId];
+ }else{
+ queryKey = ['sidebar-pages', {pageId: parentPageId, spaceId: spaceId}]
+ }
+ //update all sidebar pages
+ queryClient.setQueryData>>(queryKey, (old) => {
+ if (!old) return old;
+ return {
+ ...old,
+ pages: old.pages.map((page) => ({
+ ...page,
+ items: page.items.map((sidebarPage: IPage) =>
+ sidebarPage.id === id ? { ...sidebarPage, title: title, icon: icon } : sidebarPage
+ )
+ })),
+ };
+ });
+
+ //update recent changes
+ queryClient.invalidateQueries({
+ queryKey: ["recent-changes", spaceId],
+ });
+}
+
+export function invalidateOnMovePage() {
+ //for move invalidate all sidebars for now (how to do???)
+ //invalidate all root sidebar pages
+ queryClient.invalidateQueries({
+ queryKey: ["root-sidebar-pages"],
+ });
+ //invalidate all sub sidebar pages
+ queryClient.invalidateQueries({
+ queryKey: ['sidebar-pages'],
+ });
+ // ---
+}
+
+export function invalidateOnDeletePage(pageId: string) {
+ //update all sidebar pages
+ const allSideBarMatches = queryClient.getQueriesData({
+ predicate: (query) =>
+ query.queryKey[0] === 'root-sidebar-pages' || query.queryKey[0] === 'sidebar-pages',
+ });
+
+ allSideBarMatches.forEach(([key, d]) => {
+ queryClient.setQueryData>>(key, (old) => {
+ if (!old) return old;
+ return {
+ ...old,
+ pages: old.pages.map((page) => ({
+ ...page,
+ items: page.items.filter((sidebarPage: IPage) => sidebarPage.id !== pageId),
+ })),
+ };
+ });
+ });
+
+ //update recent changes
+ queryClient.invalidateQueries({
+ queryKey: ["recent-changes"],
+ });
+}
\ No newline at end of file
diff --git a/apps/client/src/features/page/services/page-service.ts b/apps/client/src/features/page/services/page-service.ts
index 5e69a34a..e7e15608 100644
--- a/apps/client/src/features/page/services/page-service.ts
+++ b/apps/client/src/features/page/services/page-service.ts
@@ -10,6 +10,7 @@ import {
} from "@/features/page/types/page.types";
import { IAttachment, IPagination } from "@/lib/types.ts";
import { saveAs } from "file-saver";
+import { InfiniteData } from "@tanstack/react-query";
export async function createPage(data: Partial): Promise {
const req = await api.post("/pages/create", data);
@@ -52,6 +53,32 @@ export async function getSidebarPages(
return req.data;
}
+export async function getAllSidebarPages(
+ params: SidebarPagesParams,
+): Promise, unknown>> {
+ let page = 1;
+ let hasNextPage = false;
+ const pages: IPagination[] = [];
+ const pageParams: number[] = [];
+
+ do {
+ const req = await api.post("/pages/sidebar-pages", { ...params, page: page });
+
+ const data: IPagination = req.data;
+ pages.push(data);
+ pageParams.push(page);
+
+ hasNextPage = data.meta.hasNextPage;
+
+ page += 1;
+ } while (hasNextPage);
+
+ return {
+ pageParams,
+ pages,
+ };
+}
+
export async function getPageBreadcrumbs(
pageId: string,
): Promise> {
diff --git a/apps/client/src/features/page/tree/atoms/tree-data-atom.ts b/apps/client/src/features/page/tree/atoms/tree-data-atom.ts
index e3910cb8..7d0ec503 100644
--- a/apps/client/src/features/page/tree/atoms/tree-data-atom.ts
+++ b/apps/client/src/features/page/tree/atoms/tree-data-atom.ts
@@ -1,4 +1,19 @@
import { atom } from "jotai";
import { SpaceTreeNode } from "@/features/page/tree/types";
+import { appendNodeChildren } from "../utils";
export const treeDataAtom = atom([]);
+
+// Atom
+export const appendNodeChildrenAtom = atom(
+ null,
+ (
+ get,
+ set,
+ { parentId, children }: { parentId: string; children: SpaceTreeNode[] }
+ ) => {
+ const currentTree = get(treeDataAtom);
+ const updatedTree = appendNodeChildren(currentTree, parentId, children);
+ set(treeDataAtom, updatedTree);
+ }
+);
diff --git a/apps/client/src/features/page/tree/components/space-tree.tsx b/apps/client/src/features/page/tree/components/space-tree.tsx
index 1df62678..da5b1832 100644
--- a/apps/client/src/features/page/tree/components/space-tree.tsx
+++ b/apps/client/src/features/page/tree/components/space-tree.tsx
@@ -2,7 +2,7 @@ import { NodeApi, NodeRendererProps, Tree, TreeApi } from "react-arborist";
import { atom, useAtom } from "jotai";
import { treeApiAtom } from "@/features/page/tree/atoms/tree-api-atom.ts";
import {
- fetchAncestorChildren,
+ fetchAllAncestorChildren,
useGetRootSidebarPagesQuery,
usePageQuery,
useUpdatePageMutation,
@@ -24,7 +24,7 @@ import {
IconPointFilled,
IconTrash,
} from "@tabler/icons-react";
-import { treeDataAtom } from "@/features/page/tree/atoms/tree-data-atom.ts";
+import { appendNodeChildrenAtom, treeDataAtom } from "@/features/page/tree/atoms/tree-data-atom.ts";
import clsx from "clsx";
import EmojiPicker from "@/components/ui/emoji-picker.tsx";
import { useTreeMutation } from "@/features/page/tree/hooks/use-tree-mutation.ts";
@@ -140,7 +140,7 @@ export default function SpaceTree({ spaceId, readOnly }: SpaceTreeProps) {
if (ancestor.id === currentPage.id) {
return;
}
- const children = await fetchAncestorChildren({
+ const children = await fetchAllAncestorChildren({
pageId: ancestor.id,
spaceId: ancestor.spaceId,
});
@@ -237,6 +237,7 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps) {
const { t } = useTranslation();
const updatePageMutation = useUpdatePageMutation();
const [treeData, setTreeData] = useAtom(treeDataAtom);
+ const [, appendChildren] = useAtom(appendNodeChildrenAtom);
const emit = useQueryEmit();
const { spaceSlug } = useParams();
const timerRef = useRef(null);
@@ -262,9 +263,10 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps) {
async function handleLoadChildren(node: NodeApi) {
if (!node.data.hasChildren) return;
- if (node.data.children && node.data.children.length > 0) {
- return;
- }
+ // in conflict with use-query-subscription.ts => case "addTreeNode","moveTreeNode" etc with websocket
+ // if (node.data.children && node.data.children.length > 0) {
+ // return;
+ // }
try {
const params: SidebarPagesParams = {
@@ -272,21 +274,12 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps) {
spaceId: node.data.spaceId,
};
- const newChildren = await queryClient.fetchQuery({
- queryKey: ["sidebar-pages", params],
- queryFn: () => getSidebarPages(params),
- staleTime: 10 * 60 * 1000,
+ const childrenTree = await fetchAllAncestorChildren(params);
+
+ appendChildren({
+ parentId: node.data.id,
+ children: childrenTree,
});
-
- const childrenTree = buildTree(newChildren.items);
-
- const updatedTreeData = appendNodeChildren(
- treeData,
- node.data.id,
- childrenTree,
- );
-
- setTreeData(updatedTreeData);
} catch (error) {
console.error("Failed to fetch children:", error);
}
@@ -304,17 +297,17 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps) {
const handleEmojiSelect = (emoji: { native: string }) => {
handleUpdateNodeIcon(node.id, emoji.native);
- updatePageMutation.mutateAsync({ pageId: node.id, icon: emoji.native });
-
- setTimeout(() => {
- emit({
- operation: "updateOne",
- spaceId: node.data.spaceId,
- entity: ["pages"],
- id: node.id,
- payload: { icon: emoji.native },
- });
- }, 50);
+ updatePageMutation.mutateAsync({ pageId: node.id, icon: emoji.native }).then((data) => {
+ setTimeout(() => {
+ emit({
+ operation: "updateOne",
+ spaceId: node.data.spaceId,
+ entity: ["pages"],
+ id: node.id,
+ payload: { icon: emoji.native, parentPageId: data.parentPageId},
+ });
+ }, 50);
+ });
};
const handleRemoveEmoji = () => {
@@ -576,6 +569,12 @@ interface PageArrowProps {
}
function PageArrow({ node, onExpandTree }: PageArrowProps) {
+ useEffect(() => {
+ if(node.isOpen){
+ onExpandTree();
+ }
+ }, []);
+
return (
(spaceId: string) {
return data;
};
- const onMove: MoveHandler = (args: {
+ const onMove: MoveHandler = async (args: {
dragIds: string[];
dragNodes: NodeApi[];
parentId: string | null;
@@ -176,7 +176,7 @@ export function useTreeMutation(spaceId: string) {
};
try {
- movePageMutation.mutateAsync(payload);
+ await movePageMutation.mutateAsync(payload);
setTimeout(() => {
emit({
@@ -206,6 +206,23 @@ export function useTreeMutation(spaceId: string) {
}
};
+ const isPageInNode = (
+ node: { data: SpaceTreeNode; children?: any[] },
+ pageSlug: string
+ ): boolean => {
+ if (node.data.slugId === pageSlug) {
+ return true;
+ }
+ for (const item of node.children) {
+ if (item.data.slugId === pageSlug) {
+ return true;
+ } else {
+ return isPageInNode(item, pageSlug);
+ }
+ }
+ return false;
+ };
+
const onDelete: DeleteHandler = async (args: { ids: string[] }) => {
try {
await deletePageMutation.mutateAsync(args.ids[0]);
@@ -218,8 +235,7 @@ export function useTreeMutation(spaceId: string) {
tree.drop({ id: args.ids[0] });
setData(tree.data);
- // navigate only if the current url is same as the deleted page
- if (pageSlug && node.data.slugId === pageSlug.split("-")[1]) {
+ if (pageSlug && isPageInNode(node, pageSlug.split("-")[1])) {
navigate(getSpaceUrl(spaceSlug));
}
diff --git a/apps/client/src/features/page/tree/utils/utils.ts b/apps/client/src/features/page/tree/utils/utils.ts
index 7ae84e38..910799c8 100644
--- a/apps/client/src/features/page/tree/utils/utils.ts
+++ b/apps/client/src/features/page/tree/utils/utils.ts
@@ -164,16 +164,35 @@ export function appendNodeChildren(
nodeId: string,
children: SpaceTreeNode[],
) {
- return treeItems.map((nodeItem) => {
- if (nodeItem.id === nodeId) {
- return { ...nodeItem, children };
- }
- if (nodeItem.children) {
+ // Preserve deeper children if they exist and remove node if deleted
+ return treeItems.map((node) => {
+ if (node.id === nodeId) {
+ const newIds = new Set(children.map(c => c.id));
+
+ const existingMap = new Map(
+ (node.children ?? []).filter(c => newIds.has(c.id)).map(c => [c.id, c])
+ );
+
+ const merged = children.map((newChild) => {
+ const existing = existingMap.get(newChild.id);
+ return existing && existing.children
+ ? { ...newChild, children: existing.children }
+ : newChild;
+ });
+
return {
- ...nodeItem,
- children: appendNodeChildren(nodeItem.children, nodeId, children),
+ ...node,
+ children: merged,
};
}
- return nodeItem;
+
+ if (node.children) {
+ return {
+ ...node,
+ children: appendNodeChildren(node.children, nodeId, children),
+ };
+ }
+
+ return node;
});
}
diff --git a/apps/client/src/features/websocket/types/types.ts b/apps/client/src/features/websocket/types/types.ts
index 48e7d819..bda76b4e 100644
--- a/apps/client/src/features/websocket/types/types.ts
+++ b/apps/client/src/features/websocket/types/types.ts
@@ -1,4 +1,5 @@
import { SpaceTreeNode } from "@/features/page/tree/types.ts";
+import { IPage } from "@/features/page/types/page.types";
export type InvalidateEvent = {
operation: "invalidate";
@@ -17,7 +18,7 @@ export type UpdateEvent = {
spaceId: string;
entity: Array;
id: string;
- payload: Partial;
+ payload: Partial;
};
export type DeleteEvent = {
@@ -25,7 +26,7 @@ export type DeleteEvent = {
spaceId: string;
entity: Array;
id: string;
- payload?: Partial;
+ payload?: Partial;
};
export type AddTreeNodeEvent = {
diff --git a/apps/client/src/features/websocket/use-query-subscription.ts b/apps/client/src/features/websocket/use-query-subscription.ts
index c9e53aa6..8e3ad569 100644
--- a/apps/client/src/features/websocket/use-query-subscription.ts
+++ b/apps/client/src/features/websocket/use-query-subscription.ts
@@ -1,8 +1,11 @@
import React from "react";
import { socketAtom } from "@/features/websocket/atoms/socket-atom.ts";
import { useAtom } from "jotai";
-import { useQueryClient } from "@tanstack/react-query";
+import { InfiniteData, useQueryClient } from "@tanstack/react-query";
import { WebSocketEvent } from "@/features/websocket/types";
+import { IPage } from "../page/types/page.types";
+import { IPagination } from "@/lib/types";
+import { invalidateOnCreatePage, invalidateOnDeletePage, invalidateOnMovePage, invalidateOnUpdatePage } from "../page/queries/page-query";
import { RQ_KEY } from "../comment/queries/comment-query";
export const useQuerySubscription = () => {
@@ -27,6 +30,16 @@ export const useQuerySubscription = () => {
queryKey: RQ_KEY(data.pageId),
});
break;
+ case "addTreeNode":
+ invalidateOnCreatePage(data.payload.data);
+ break;
+ case "moveTreeNode":
+ invalidateOnMovePage();
+ break;
+ case "deleteTreeNode":
+ const pageId = data.payload.node.id;
+ invalidateOnDeletePage(pageId);
+ break;
case "updateOne":
entity = data.entity[0];
if (entity === "pages") {
@@ -43,7 +56,11 @@ export const useQuerySubscription = () => {
...data.payload,
});
}
-
+
+ if (entity === "pages") {
+ invalidateOnUpdatePage(data.spaceId, data.payload.parentPageId, data.id, data.payload.title, data.payload.icon);
+ }
+
/*
queryClient.setQueriesData(
{ queryKey: [data.entity, data.id] },
@@ -55,7 +72,7 @@ export const useQuerySubscription = () => {
: update(oldData as Record);
},
);
- */
+ */
break;
}
});
From 6d024fc3de140e0d6748abec543dd6670f4b1882 Mon Sep 17 00:00:00 2001
From: Philip Okugbe <16838612+Philipinho@users.noreply.github.com>
Date: Mon, 9 Jun 2025 04:29:27 +0100
Subject: [PATCH 61/63] feat: bulk page imports (#1219)
* refactor imports - WIP
* Add readstream
* WIP
* fix attachmentId render
* fix attachmentId render
* turndown video tag
* feat: add stream upload support and improve file handling
- Add stream upload functionality to storage drivers\n- Improve ZIP file extraction with better encoding handling\n- Fix attachment ID rendering issues\n- Add AWS S3 upload stream support\n- Update dependencies for better compatibility
* WIP
* notion formatter
* move embed parser to editor-ext package
* import embeds
* utility files
* cleanup
* Switch from happy-dom to cheerio
* Refine code
* WIP
* bug fixes and UI
* sync
* WIP
* sync
* keep import modal mounted
* Show modal during upload
* WIP
* WIP
---
.../src/components/icons/confluence-icon.tsx | 20 +
.../editor/components/embed/embed-view.tsx | 7 +-
.../file-task/services/file-task-service.ts | 14 +
.../file-task/types/file-task.types.ts | 17 +
.../page/components/page-import-modal.tsx | 224 +++++++++++-
.../features/page/services/page-service.ts | 22 +-
.../page/tree/components/space-tree.tsx | 54 +--
.../src/features/page/tree/utils/utils.ts | 25 +-
.../src/features/websocket/types/types.ts | 21 +-
.../websocket/use-query-subscription.ts | 38 +-
apps/client/src/lib/config.ts | 5 +
apps/client/vite.config.ts | 2 +
apps/server/package.json | 7 +-
.../extensions/persistence.extension.ts | 2 +-
apps/server/src/common/helpers/utils.ts | 6 +
.../migrations/20250521T154949-file_tasks.ts | 39 ++
apps/server/src/database/types/db.d.ts | 19 +
.../server/src/database/types/entity.types.ts | 6 +
apps/server/src/ee | 2 +-
.../environment/environment.service.ts | 4 +
.../src/integrations/export/turndown-utils.ts | 23 +-
.../integrations/import/dto/file-task-dto.ts | 18 +
.../import/file-task.controller.ts | 79 ++++
.../integrations/import/import.controller.ts | 77 +++-
.../src/integrations/import/import.module.ts | 19 +-
.../import/processors/file-task.processor.ts | 76 ++++
.../import/services/file-task.service.ts | 346 ++++++++++++++++++
.../services/import-attachment.service.ts | 303 +++++++++++++++
.../import/{ => services}/import.service.ts | 104 +++++-
.../integrations/import/utils/file.utils.ts | 187 ++++++++++
.../import/utils/import-formatter.ts | 254 +++++++++++++
.../integrations/import/utils/import.utils.ts | 66 ++++
.../queue/constants/queue.constants.ts | 4 +
.../src/integrations/queue/queue.module.ts | 8 +
.../storage/drivers/local.driver.ts | 23 +-
.../integrations/storage/drivers/s3.driver.ts | 36 ++
.../interfaces/storage-driver.interface.ts | 6 +
.../integrations/storage/storage.service.ts | 10 +
apps/server/src/main.ts | 2 +-
packages/editor-ext/src/index.ts | 3 +-
.../editor-ext/src/lib/embed-provider.ts | 97 ++---
packages/editor-ext/src/lib/image/image.ts | 2 +-
packages/editor-ext/src/lib/trailing-node.ts | 9 +-
packages/editor-ext/src/lib/video/video.ts | 10 +-
pnpm-lock.yaml | 215 +++++++++--
45 files changed, 2362 insertions(+), 149 deletions(-)
create mode 100644 apps/client/src/components/icons/confluence-icon.tsx
create mode 100644 apps/client/src/features/file-task/services/file-task-service.ts
create mode 100644 apps/client/src/features/file-task/types/file-task.types.ts
create mode 100644 apps/server/src/database/migrations/20250521T154949-file_tasks.ts
create mode 100644 apps/server/src/integrations/import/dto/file-task-dto.ts
create mode 100644 apps/server/src/integrations/import/file-task.controller.ts
create mode 100644 apps/server/src/integrations/import/processors/file-task.processor.ts
create mode 100644 apps/server/src/integrations/import/services/file-task.service.ts
create mode 100644 apps/server/src/integrations/import/services/import-attachment.service.ts
rename apps/server/src/integrations/import/{ => services}/import.service.ts (61%)
create mode 100644 apps/server/src/integrations/import/utils/file.utils.ts
create mode 100644 apps/server/src/integrations/import/utils/import-formatter.ts
create mode 100644 apps/server/src/integrations/import/utils/import.utils.ts
rename apps/client/src/features/editor/components/embed/providers.ts => packages/editor-ext/src/lib/embed-provider.ts (58%)
diff --git a/apps/client/src/components/icons/confluence-icon.tsx b/apps/client/src/components/icons/confluence-icon.tsx
new file mode 100644
index 00000000..499f18da
--- /dev/null
+++ b/apps/client/src/components/icons/confluence-icon.tsx
@@ -0,0 +1,20 @@
+import { rem } from "@mantine/core";
+
+interface Props {
+ size?: number | string;
+}
+
+export function ConfluenceIcon({ size }: Props) {
+ return (
+
+
+
+ );
+}
diff --git a/apps/client/src/features/editor/components/embed/embed-view.tsx b/apps/client/src/features/editor/components/embed/embed-view.tsx
index 02ae6edf..77743a07 100644
--- a/apps/client/src/features/editor/components/embed/embed-view.tsx
+++ b/apps/client/src/features/editor/components/embed/embed-view.tsx
@@ -15,13 +15,10 @@ import {
import { IconEdit } from "@tabler/icons-react";
import { z } from "zod";
import { useForm, zodResolver } from "@mantine/form";
-import {
- getEmbedProviderById,
- getEmbedUrlAndProvider,
-} from "@/features/editor/components/embed/providers.ts";
import { notifications } from "@mantine/notifications";
import { useTranslation } from "react-i18next";
import i18n from "i18next";
+import { getEmbedProviderById, getEmbedUrlAndProvider } from '@docmost/editor-ext';
const schema = z.object({
url: z
@@ -101,7 +98,7 @@ export default function EmbedView(props: NodeViewProps) {
{t("Embed {{provider}}", {
- provider: getEmbedProviderById(provider).name,
+ provider: getEmbedProviderById(provider)?.name,
})}
diff --git a/apps/client/src/features/file-task/services/file-task-service.ts b/apps/client/src/features/file-task/services/file-task-service.ts
new file mode 100644
index 00000000..ffccbaae
--- /dev/null
+++ b/apps/client/src/features/file-task/services/file-task-service.ts
@@ -0,0 +1,14 @@
+import api from "@/lib/api-client";
+import { IFileTask } from "@/features/file-task/types/file-task.types.ts";
+
+export async function getFileTaskById(fileTaskId: string): Promise {
+ const req = await api.post("/file-tasks/info", {
+ fileTaskId: fileTaskId,
+ });
+ return req.data;
+}
+
+export async function getFileTasks(): Promise {
+ const req = await api.post("/file-tasks");
+ return req.data;
+}
diff --git a/apps/client/src/features/file-task/types/file-task.types.ts b/apps/client/src/features/file-task/types/file-task.types.ts
new file mode 100644
index 00000000..917e1757
--- /dev/null
+++ b/apps/client/src/features/file-task/types/file-task.types.ts
@@ -0,0 +1,17 @@
+export interface IFileTask {
+ id: string;
+ type: "import" | "export";
+ source: string;
+ status: string;
+ fileName: string;
+ filePath: string;
+ fileSize: number;
+ fileExt: string;
+ errorMessage: string | null;
+ creatorId: string;
+ spaceId: string;
+ workspaceId: string;
+ createdAt: string;
+ updatedAt: string;
+ deletedAt: string | null;
+}
\ No newline at end of file
diff --git a/apps/client/src/features/page/components/page-import-modal.tsx b/apps/client/src/features/page/components/page-import-modal.tsx
index f07fd8a9..90c08bb6 100644
--- a/apps/client/src/features/page/components/page-import-modal.tsx
+++ b/apps/client/src/features/page/components/page-import-modal.tsx
@@ -1,18 +1,38 @@
-import { Modal, Button, SimpleGrid, FileButton } from "@mantine/core";
import {
+ Modal,
+ Button,
+ SimpleGrid,
+ FileButton,
+ Group,
+ Text,
+ Tooltip,
+} from "@mantine/core";
+import {
+ IconBrandNotion,
IconCheck,
IconFileCode,
+ IconFileTypeZip,
IconMarkdown,
IconX,
} from "@tabler/icons-react";
-import { importPage } from "@/features/page/services/page-service.ts";
+import {
+ importPage,
+ importZip,
+} from "@/features/page/services/page-service.ts";
import { notifications } from "@mantine/notifications";
import { treeDataAtom } from "@/features/page/tree/atoms/tree-data-atom.ts";
import { useAtom } from "jotai";
import { buildTree } from "@/features/page/tree/utils";
import { IPage } from "@/features/page/types/page.types.ts";
-import React from "react";
+import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
+import { ConfluenceIcon } from "@/components/icons/confluence-icon.tsx";
+import { getFileImportSizeLimit, isCloud } from "@/lib/config.ts";
+import { formatBytes } from "@/lib";
+import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
+import { getFileTaskById } from "@/features/file-task/services/file-task-service.ts";
+import { queryClient } from "@/main.tsx";
+import { useQueryEmit } from "@/features/websocket/use-query-emit.ts";
interface PageImportModalProps {
spaceId: string;
@@ -36,6 +56,7 @@ export default function PageImportModal({
yOffset="10vh"
xOffset={0}
mah={400}
+ keepMounted={true}
>
@@ -59,6 +80,133 @@ interface ImportFormatSelection {
function ImportFormatSelection({ spaceId, onClose }: ImportFormatSelection) {
const { t } = useTranslation();
const [treeData, setTreeData] = useAtom(treeDataAtom);
+ const [workspace] = useAtom(workspaceAtom);
+ const [fileTaskId, setFileTaskId] = useState(null);
+ const emit = useQueryEmit();
+
+ const canUseConfluence = isCloud() || workspace?.hasLicenseKey;
+
+ const handleZipUpload = async (selectedFile: File, source: string) => {
+ if (!selectedFile) {
+ return;
+ }
+
+ try {
+ onClose();
+
+ notifications.show({
+ id: "import",
+ title: t("Uploading import file"),
+ message: t("Please don't close this tab."),
+ loading: true,
+ withCloseButton: false,
+ autoClose: false,
+ });
+
+ const importTask = await importZip(selectedFile, spaceId, source);
+ notifications.update({
+ id: "import",
+ title: t("Importing pages"),
+ message: t(
+ "Page import is in progress. You can check back later if this takes longer.",
+ ),
+ loading: true,
+ withCloseButton: true,
+ autoClose: false,
+ });
+
+ setFileTaskId(importTask.id);
+ } catch (err) {
+ console.log("Failed to upload import file", err);
+ notifications.update({
+ id: "import",
+ color: "red",
+ title: t("Failed to upload import file"),
+ message: err?.response.data.message,
+ icon: ,
+ loading: false,
+ withCloseButton: true,
+ autoClose: false,
+ });
+ }
+ };
+
+ useEffect(() => {
+ if (!fileTaskId) return;
+
+ const intervalId = setInterval(async () => {
+ try {
+ const fileTask = await getFileTaskById(fileTaskId);
+ const status = fileTask.status;
+
+ if (status === "success") {
+ notifications.update({
+ id: "import",
+ color: "teal",
+ title: t("Import complete"),
+ message: t("Your pages were successfully imported."),
+ icon: ,
+ loading: false,
+ withCloseButton: true,
+ autoClose: false,
+ });
+ clearInterval(intervalId);
+ setFileTaskId(null);
+
+ await queryClient.refetchQueries({
+ queryKey: ["root-sidebar-pages", fileTask.spaceId],
+ });
+
+ setTimeout(() => {
+ emit({
+ operation: "refetchRootTreeNodeEvent",
+ spaceId: spaceId,
+ });
+ }, 50);
+ }
+
+ if (status === "failed") {
+ notifications.update({
+ id: "import",
+ color: "red",
+ title: t("Page import failed"),
+ message: t(
+ "Something went wrong while importing pages: {{reason}}.",
+ {
+ reason: fileTask.errorMessage,
+ },
+ ),
+ icon: ,
+ loading: false,
+ withCloseButton: true,
+ autoClose: false,
+ });
+ clearInterval(intervalId);
+ setFileTaskId(null);
+ console.error(fileTask.errorMessage);
+ }
+ } catch (err) {
+ notifications.update({
+ id: "import",
+ color: "red",
+ title: t("Import failed"),
+ message: t(
+ "Something went wrong while importing pages: {{reason}}.",
+ {
+ reason: err.response?.data.message,
+ },
+ ),
+ icon: ,
+ loading: false,
+ withCloseButton: true,
+ autoClose: false,
+ });
+ clearInterval(intervalId);
+ setFileTaskId(null);
+ console.error("Failed to fetch import status", err);
+ }
+ }, 3000);
+ }, [fileTaskId]);
const handleFileUpload = async (selectedFiles: File[]) => {
if (!selectedFiles) {
@@ -120,6 +268,7 @@ function ImportFormatSelection({ spaceId, onClose }: ImportFormatSelection) {
}
};
+ // @ts-ignore
return (
<>
@@ -148,7 +297,76 @@ function ImportFormatSelection({ spaceId, onClose }: ImportFormatSelection) {
)}
+
+ handleZipUpload(file, "notion")}
+ accept="application/zip"
+ >
+ {(props) => (
+ }
+ {...props}
+ >
+ Notion
+
+ )}
+
+ handleZipUpload(file, "confluence")}
+ accept="application/zip"
+ >
+ {(props) => (
+
+ }
+ {...props}
+ >
+ Confluence
+
+
+ )}
+
+
+
+
+
+ Import zip file
+
+
+ {t(
+ `Upload zip file containing Markdown and HTML files. Max: {{sizeLimit}}`,
+ {
+ sizeLimit: formatBytes(getFileImportSizeLimit()),
+ },
+ )}
+
+ handleZipUpload(file, "generic")}
+ accept="application/zip"
+ >
+ {(props) => (
+
+ }
+ {...props}
+ >
+ {t("Upload file")}
+
+
+ )}
+
+
+
>
);
}
diff --git a/apps/client/src/features/page/services/page-service.ts b/apps/client/src/features/page/services/page-service.ts
index e7e15608..a8e3d256 100644
--- a/apps/client/src/features/page/services/page-service.ts
+++ b/apps/client/src/features/page/services/page-service.ts
@@ -7,10 +7,11 @@ import {
IPage,
IPageInput,
SidebarPagesParams,
-} from "@/features/page/types/page.types";
+} from '@/features/page/types/page.types';
import { IAttachment, IPagination } from "@/lib/types.ts";
import { saveAs } from "file-saver";
import { InfiniteData } from "@tanstack/react-query";
+import { IFileTask } from '@/features/file-task/types/file-task.types.ts';
export async function createPage(data: Partial): Promise {
const req = await api.post("/pages/create", data);
@@ -119,6 +120,25 @@ export async function importPage(file: File, spaceId: string) {
return req.data;
}
+export async function importZip(
+ file: File,
+ spaceId: string,
+ source?: string,
+): Promise {
+ const formData = new FormData();
+ formData.append("spaceId", spaceId);
+ formData.append("source", source);
+ formData.append("file", file);
+
+ const req = await api.post("/pages/import-zip", formData, {
+ headers: {
+ "Content-Type": "multipart/form-data",
+ },
+ });
+
+ return req.data;
+}
+
export async function uploadFile(
file: File,
pageId: string,
diff --git a/apps/client/src/features/page/tree/components/space-tree.tsx b/apps/client/src/features/page/tree/components/space-tree.tsx
index da5b1832..db818518 100644
--- a/apps/client/src/features/page/tree/components/space-tree.tsx
+++ b/apps/client/src/features/page/tree/components/space-tree.tsx
@@ -24,7 +24,10 @@ import {
IconPointFilled,
IconTrash,
} from "@tabler/icons-react";
-import { appendNodeChildrenAtom, treeDataAtom } from "@/features/page/tree/atoms/tree-data-atom.ts";
+import {
+ appendNodeChildrenAtom,
+ treeDataAtom,
+} from "@/features/page/tree/atoms/tree-data-atom.ts";
import clsx from "clsx";
import EmojiPicker from "@/components/ui/emoji-picker.tsx";
import { useTreeMutation } from "@/features/page/tree/hooks/use-tree-mutation.ts";
@@ -32,6 +35,7 @@ import {
appendNodeChildren,
buildTree,
buildTreeWithChildren,
+ mergeRootTrees,
updateTreeNodeIcon,
} from "@/features/page/tree/utils/utils.ts";
import { SpaceTreeNode } from "@/features/page/tree/types.ts";
@@ -104,17 +108,17 @@ export default function SpaceTree({ spaceId, readOnly }: SpaceTreeProps) {
const allItems = pagesData.pages.flatMap((page) => page.items);
const treeData = buildTree(allItems);
- if (data.length < 1 || data?.[0].spaceId !== spaceId) {
- //Thoughts
- // don't reset if there is data in state
- // we only expect to call this once on initial load
- // even if we decide to refetch, it should only update
- // and append root pages instead of resetting the entire tree
- // which looses async loaded children too
- setData(treeData);
- setIsDataLoaded(true);
- setOpenTreeNodes({});
- }
+ setData((prev) => {
+ // fresh space; full reset
+ if (prev.length === 0 || prev[0]?.spaceId !== spaceId) {
+ setIsDataLoaded(true);
+ setOpenTreeNodes({});
+ return treeData;
+ }
+
+ // same space; append only missing roots
+ return mergeRootTrees(prev, treeData);
+ });
}
}, [pagesData, hasNextPage]);
@@ -297,17 +301,19 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps) {
const handleEmojiSelect = (emoji: { native: string }) => {
handleUpdateNodeIcon(node.id, emoji.native);
- updatePageMutation.mutateAsync({ pageId: node.id, icon: emoji.native }).then((data) => {
- setTimeout(() => {
- emit({
- operation: "updateOne",
- spaceId: node.data.spaceId,
- entity: ["pages"],
- id: node.id,
- payload: { icon: emoji.native, parentPageId: data.parentPageId},
- });
- }, 50);
- });
+ updatePageMutation
+ .mutateAsync({ pageId: node.id, icon: emoji.native })
+ .then((data) => {
+ setTimeout(() => {
+ emit({
+ operation: "updateOne",
+ spaceId: node.data.spaceId,
+ entity: ["pages"],
+ id: node.id,
+ payload: { icon: emoji.native, parentPageId: data.parentPageId },
+ });
+ }, 50);
+ });
};
const handleRemoveEmoji = () => {
@@ -570,7 +576,7 @@ interface PageArrowProps {
function PageArrow({ node, onExpandTree }: PageArrowProps) {
useEffect(() => {
- if(node.isOpen){
+ if (node.isOpen) {
onExpandTree();
}
}, []);
diff --git a/apps/client/src/features/page/tree/utils/utils.ts b/apps/client/src/features/page/tree/utils/utils.ts
index 910799c8..8ec1b884 100644
--- a/apps/client/src/features/page/tree/utils/utils.ts
+++ b/apps/client/src/features/page/tree/utils/utils.ts
@@ -121,7 +121,6 @@ export const deleteTreeNode = (
.filter((node) => node !== null);
};
-
export function buildTreeWithChildren(items: SpaceTreeNode[]): SpaceTreeNode[] {
const nodeMap = {};
let result: SpaceTreeNode[] = [];
@@ -167,10 +166,12 @@ export function appendNodeChildren(
// Preserve deeper children if they exist and remove node if deleted
return treeItems.map((node) => {
if (node.id === nodeId) {
- const newIds = new Set(children.map(c => c.id));
+ const newIds = new Set(children.map((c) => c.id));
const existingMap = new Map(
- (node.children ?? []).filter(c => newIds.has(c.id)).map(c => [c.id, c])
+ (node.children ?? [])
+ .filter((c) => newIds.has(c.id))
+ .map((c) => [c.id, c]),
);
const merged = children.map((newChild) => {
@@ -196,3 +197,21 @@ export function appendNodeChildren(
return node;
});
}
+
+/**
+ * Merge root nodes; keep existing ones intact, append new ones,
+ */
+export function mergeRootTrees(
+ prevRoots: SpaceTreeNode[],
+ incomingRoots: SpaceTreeNode[],
+): SpaceTreeNode[] {
+ const seen = new Set(prevRoots.map((r) => r.id));
+
+ // add new roots that were not present before
+ const merged = [...prevRoots];
+ incomingRoots.forEach((node) => {
+ if (!seen.has(node.id)) merged.push(node);
+ });
+
+ return sortPositionKeys(merged);
+}
diff --git a/apps/client/src/features/websocket/types/types.ts b/apps/client/src/features/websocket/types/types.ts
index bda76b4e..25b57df9 100644
--- a/apps/client/src/features/websocket/types/types.ts
+++ b/apps/client/src/features/websocket/types/types.ts
@@ -47,15 +47,28 @@ export type MoveTreeNodeEvent = {
parentId: string;
index: number;
position: string;
- }
+ };
};
export type DeleteTreeNodeEvent = {
operation: "deleteTreeNode";
spaceId: string;
payload: {
- node: SpaceTreeNode
- }
+ node: SpaceTreeNode;
+ };
};
-export type WebSocketEvent = InvalidateEvent | InvalidateCommentsEvent | UpdateEvent | DeleteEvent | AddTreeNodeEvent | MoveTreeNodeEvent | DeleteTreeNodeEvent;
+export type RefetchRootTreeNodeEvent = {
+ operation: "refetchRootTreeNodeEvent";
+ spaceId: string;
+};
+
+export type WebSocketEvent =
+ | InvalidateEvent
+ | InvalidateCommentsEvent
+ | UpdateEvent
+ | DeleteEvent
+ | AddTreeNodeEvent
+ | MoveTreeNodeEvent
+ | DeleteTreeNodeEvent
+ | RefetchRootTreeNodeEvent;
diff --git a/apps/client/src/features/websocket/use-query-subscription.ts b/apps/client/src/features/websocket/use-query-subscription.ts
index 8e3ad569..29a815be 100644
--- a/apps/client/src/features/websocket/use-query-subscription.ts
+++ b/apps/client/src/features/websocket/use-query-subscription.ts
@@ -5,8 +5,14 @@ import { InfiniteData, useQueryClient } from "@tanstack/react-query";
import { WebSocketEvent } from "@/features/websocket/types";
import { IPage } from "../page/types/page.types";
import { IPagination } from "@/lib/types";
-import { invalidateOnCreatePage, invalidateOnDeletePage, invalidateOnMovePage, invalidateOnUpdatePage } from "../page/queries/page-query";
+import {
+ invalidateOnCreatePage,
+ invalidateOnDeletePage,
+ invalidateOnMovePage,
+ invalidateOnUpdatePage,
+} from "../page/queries/page-query";
import { RQ_KEY } from "../comment/queries/comment-query";
+import { queryClient } from "@/main.tsx";
export const useQuerySubscription = () => {
const queryClient = useQueryClient();
@@ -37,8 +43,7 @@ export const useQuerySubscription = () => {
invalidateOnMovePage();
break;
case "deleteTreeNode":
- const pageId = data.payload.node.id;
- invalidateOnDeletePage(pageId);
+ invalidateOnDeletePage(data.payload.node.id);
break;
case "updateOne":
entity = data.entity[0];
@@ -50,17 +55,23 @@ export const useQuerySubscription = () => {
}
// only update if data was already in cache
- if(queryClient.getQueryData([...data.entity, queryKeyId])){
+ if (queryClient.getQueryData([...data.entity, queryKeyId])) {
queryClient.setQueryData([...data.entity, queryKeyId], {
...queryClient.getQueryData([...data.entity, queryKeyId]),
...data.payload,
});
}
-
+
if (entity === "pages") {
- invalidateOnUpdatePage(data.spaceId, data.payload.parentPageId, data.id, data.payload.title, data.payload.icon);
+ invalidateOnUpdatePage(
+ data.spaceId,
+ data.payload.parentPageId,
+ data.id,
+ data.payload.title,
+ data.payload.icon,
+ );
}
-
+
/*
queryClient.setQueriesData(
{ queryKey: [data.entity, data.id] },
@@ -72,8 +83,19 @@ export const useQuerySubscription = () => {
: update(oldData as Record);
},
);
- */
+ */
break;
+ case "refetchRootTreeNodeEvent": {
+ const spaceId = data.spaceId;
+ queryClient.refetchQueries({
+ queryKey: ["root-sidebar-pages", spaceId],
+ });
+
+ queryClient.invalidateQueries({
+ queryKey: ["recent-changes", spaceId],
+ });
+ break;
+ }
}
});
}, [queryClient, socket]);
diff --git a/apps/client/src/lib/config.ts b/apps/client/src/lib/config.ts
index 2f621b91..717bf9ff 100644
--- a/apps/client/src/lib/config.ts
+++ b/apps/client/src/lib/config.ts
@@ -70,6 +70,11 @@ export function getFileUploadSizeLimit() {
return bytes(limit);
}
+export function getFileImportSizeLimit() {
+ const limit = getConfigValue("FILE_IMPORT_SIZE_LIMIT", "200mb");
+ return bytes(limit);
+}
+
export function getDrawioUrl() {
return getConfigValue("DRAWIO_URL", "https://embed.diagrams.net");
}
diff --git a/apps/client/vite.config.ts b/apps/client/vite.config.ts
index a6efc4bc..cc8a01fd 100644
--- a/apps/client/vite.config.ts
+++ b/apps/client/vite.config.ts
@@ -8,6 +8,7 @@ export default defineConfig(({ mode }) => {
const {
APP_URL,
FILE_UPLOAD_SIZE_LIMIT,
+ FILE_IMPORT_SIZE_LIMIT,
DRAWIO_URL,
CLOUD,
SUBDOMAIN_HOST,
@@ -20,6 +21,7 @@ export default defineConfig(({ mode }) => {
"process.env": {
APP_URL,
FILE_UPLOAD_SIZE_LIMIT,
+ FILE_IMPORT_SIZE_LIMIT,
DRAWIO_URL,
CLOUD,
SUBDOMAIN_HOST,
diff --git a/apps/server/package.json b/apps/server/package.json
index 5082d129..d105f20c 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -31,6 +31,7 @@
},
"dependencies": {
"@aws-sdk/client-s3": "3.701.0",
+ "@aws-sdk/lib-storage": "3.701.0",
"@aws-sdk/s3-request-presigner": "3.701.0",
"@casl/ability": "^6.7.3",
"@fastify/cookie": "^11.0.2",
@@ -56,6 +57,7 @@
"bcrypt": "^5.1.1",
"bullmq": "^5.41.3",
"cache-manager": "^6.4.0",
+ "cheerio": "^1.0.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"cookie": "^1.0.2",
@@ -80,7 +82,9 @@
"sanitize-filename-ts": "^1.0.2",
"socket.io": "^4.8.1",
"stripe": "^17.5.0",
- "ws": "^8.18.0"
+ "tmp-promise": "^3.0.3",
+ "ws": "^8.18.0",
+ "yauzl": "^3.2.0"
},
"devDependencies": {
"@eslint/js": "^9.20.0",
@@ -99,6 +103,7 @@
"@types/pg": "^8.11.11",
"@types/supertest": "^6.0.2",
"@types/ws": "^8.5.14",
+ "@types/yauzl": "^2.10.3",
"eslint": "^9.20.1",
"eslint-config-prettier": "^10.0.1",
"globals": "^15.15.0",
diff --git a/apps/server/src/collaboration/extensions/persistence.extension.ts b/apps/server/src/collaboration/extensions/persistence.extension.ts
index 3c206e1a..88284fd2 100644
--- a/apps/server/src/collaboration/extensions/persistence.extension.ts
+++ b/apps/server/src/collaboration/extensions/persistence.extension.ts
@@ -130,7 +130,7 @@ export class PersistenceExtension implements Extension {
);
this.contributors.delete(documentName);
} catch (err) {
- this.logger.debug('Contributors error:' + err?.['message']);
+ //this.logger.debug('Contributors error:' + err?.['message']);
}
await this.pageRepo.updatePage(
diff --git a/apps/server/src/common/helpers/utils.ts b/apps/server/src/common/helpers/utils.ts
index e2a4d5eb..d1748850 100644
--- a/apps/server/src/common/helpers/utils.ts
+++ b/apps/server/src/common/helpers/utils.ts
@@ -1,5 +1,6 @@
import * as path from 'path';
import * as bcrypt from 'bcrypt';
+import { sanitize } from 'sanitize-filename-ts';
export const envPath = path.resolve(process.cwd(), '..', '..', '.env');
@@ -62,3 +63,8 @@ export function extractDateFromUuid7(uuid7: string) {
return new Date(timestamp);
}
+
+export function sanitizeFileName(fileName: string): string {
+ const sanitizedFilename = sanitize(fileName).replace(/ /g, '_');
+ return sanitizedFilename.slice(0, 255);
+}
diff --git a/apps/server/src/database/migrations/20250521T154949-file_tasks.ts b/apps/server/src/database/migrations/20250521T154949-file_tasks.ts
new file mode 100644
index 00000000..523ae86b
--- /dev/null
+++ b/apps/server/src/database/migrations/20250521T154949-file_tasks.ts
@@ -0,0 +1,39 @@
+import { Kysely, sql } from 'kysely';
+
+export async function up(db: Kysely): Promise {
+ await db.schema
+ .createTable('file_tasks')
+ .addColumn('id', 'uuid', (col) =>
+ col.primaryKey().defaultTo(sql`gen_uuid_v7()`),
+ )
+ // type (import, export)
+ .addColumn('type', 'varchar', (col) => col)
+ // source (generic, notion, confluence)
+ .addColumn('source', 'varchar', (col) => col)
+ // status (pending|processing|success|failed),
+ .addColumn('status', 'varchar', (col) => col)
+ .addColumn('file_name', 'varchar', (col) => col.notNull())
+ .addColumn('file_path', 'varchar', (col) => col.notNull())
+ .addColumn('file_size', 'int8', (col) => col)
+ .addColumn('file_ext', 'varchar', (col) => col)
+ .addColumn('error_message', 'varchar', (col) => col)
+ .addColumn('creator_id', 'uuid', (col) => col.references('users.id'))
+ .addColumn('space_id', 'uuid', (col) =>
+ col.references('spaces.id').onDelete('cascade'),
+ )
+ .addColumn('workspace_id', 'uuid', (col) =>
+ col.references('workspaces.id').onDelete('cascade').notNull(),
+ )
+ .addColumn('created_at', 'timestamptz', (col) =>
+ col.notNull().defaultTo(sql`now()`),
+ )
+ .addColumn('updated_at', 'timestamptz', (col) =>
+ col.notNull().defaultTo(sql`now()`),
+ )
+ .addColumn('deleted_at', 'timestamptz', (col) => col)
+ .execute();
+}
+
+export async function down(db: Kysely): Promise {
+ await db.schema.dropTable('file_tasks').execute();
+}
diff --git a/apps/server/src/database/types/db.d.ts b/apps/server/src/database/types/db.d.ts
index 8c4cbd57..4545ebc4 100644
--- a/apps/server/src/database/types/db.d.ts
+++ b/apps/server/src/database/types/db.d.ts
@@ -122,6 +122,24 @@ export interface Comments {
workspaceId: string;
}
+export interface FileTasks {
+ createdAt: Generated;
+ creatorId: string | null;
+ deletedAt: Timestamp | null;
+ errorMessage: string | null;
+ fileExt: string | null;
+ fileName: string;
+ filePath: string;
+ fileSize: Int8 | null;
+ id: Generated;
+ source: string | null;
+ spaceId: string | null;
+ status: string | null;
+ type: string | null;
+ updatedAt: Generated;
+ workspaceId: string;
+}
+
export interface Groups {
createdAt: Generated;
creatorId: string | null;
@@ -298,6 +316,7 @@ export interface DB {
backlinks: Backlinks;
billing: Billing;
comments: Comments;
+ fileTasks: FileTasks;
groups: Groups;
groupUsers: GroupUsers;
pageHistory: PageHistory;
diff --git a/apps/server/src/database/types/entity.types.ts b/apps/server/src/database/types/entity.types.ts
index 6cb55a11..db2c2823 100644
--- a/apps/server/src/database/types/entity.types.ts
+++ b/apps/server/src/database/types/entity.types.ts
@@ -17,6 +17,7 @@ import {
AuthProviders,
AuthAccounts,
Shares,
+ FileTasks,
} from './db';
// Workspace
@@ -107,3 +108,8 @@ export type UpdatableAuthAccount = Updateable>;
export type Share = Selectable;
export type InsertableShare = Insertable;
export type UpdatableShare = Updateable>;
+
+// File Task
+export type FileTask = Selectable;
+export type InsertableFileTask = Insertable;
+export type UpdatableFileTask = Updateable>;
diff --git a/apps/server/src/ee b/apps/server/src/ee
index b312008b..70eb45ea 160000
--- a/apps/server/src/ee
+++ b/apps/server/src/ee
@@ -1 +1 @@
-Subproject commit b312008b4b7ed3d5862436b279d91aeddb6048d7
+Subproject commit 70eb45eaec84f61cb94a83a153915ce443ccc437
diff --git a/apps/server/src/integrations/environment/environment.service.ts b/apps/server/src/integrations/environment/environment.service.ts
index ac26b4fb..d6336993 100644
--- a/apps/server/src/integrations/environment/environment.service.ts
+++ b/apps/server/src/integrations/environment/environment.service.ts
@@ -67,6 +67,10 @@ export class EnvironmentService {
return this.configService.get('FILE_UPLOAD_SIZE_LIMIT', '50mb');
}
+ getFileImportSizeLimit(): string {
+ return this.configService.get('FILE_IMPORT_SIZE_LIMIT', '200mb');
+ }
+
getAwsS3AccessKeyId(): string {
return this.configService.get('AWS_S3_ACCESS_KEY_ID');
}
diff --git a/apps/server/src/integrations/export/turndown-utils.ts b/apps/server/src/integrations/export/turndown-utils.ts
index 44e606f3..54fdef12 100644
--- a/apps/server/src/integrations/export/turndown-utils.ts
+++ b/apps/server/src/integrations/export/turndown-utils.ts
@@ -1,5 +1,6 @@
import * as TurndownService from '@joplin/turndown';
import * as TurndownPluginGfm from '@joplin/turndown-plugin-gfm';
+import * as path from 'path';
export function turndown(html: string): string {
const turndownService = new TurndownService({
@@ -23,6 +24,7 @@ export function turndown(html: string): string {
mathInline,
mathBlock,
iframeEmbed,
+ video,
]);
return turndownService.turndown(html).replaceAll(' ', ' ');
}
@@ -87,8 +89,12 @@ function preserveDetail(turndownService: TurndownService) {
}
const detailsContent = Array.from(node.childNodes)
- .filter(child => child.nodeName !== 'SUMMARY')
- .map(child => (child.nodeType === 1 ? turndownService.turndown((child as HTMLElement).outerHTML) : child.textContent))
+ .filter((child) => child.nodeName !== 'SUMMARY')
+ .map((child) =>
+ child.nodeType === 1
+ ? turndownService.turndown((child as HTMLElement).outerHTML)
+ : child.textContent,
+ )
.join('');
return `\n\n${detailSummary}\n\n${detailsContent}\n\n \n`;
@@ -135,3 +141,16 @@ function iframeEmbed(turndownService: TurndownService) {
},
});
}
+
+function video(turndownService: TurndownService) {
+ turndownService.addRule('video', {
+ filter: function (node: HTMLInputElement) {
+ return node.tagName === 'VIDEO';
+ },
+ replacement: function (content: any, node: HTMLInputElement) {
+ const src = node.getAttribute('src') || '';
+ const name = path.basename(src);
+ return '[' + name + '](' + src + ')';
+ },
+ });
+}
diff --git a/apps/server/src/integrations/import/dto/file-task-dto.ts b/apps/server/src/integrations/import/dto/file-task-dto.ts
new file mode 100644
index 00000000..9cdea395
--- /dev/null
+++ b/apps/server/src/integrations/import/dto/file-task-dto.ts
@@ -0,0 +1,18 @@
+import { IsNotEmpty, IsUUID } from 'class-validator';
+
+export class FileTaskIdDto {
+ @IsNotEmpty()
+ @IsUUID()
+ fileTaskId: string;
+}
+
+export type ImportPageNode = {
+ id: string;
+ slugId: string;
+ name: string;
+ content: string;
+ position?: string | null;
+ parentPageId: string | null;
+ fileExtension: string;
+ filePath: string;
+};
\ No newline at end of file
diff --git a/apps/server/src/integrations/import/file-task.controller.ts b/apps/server/src/integrations/import/file-task.controller.ts
new file mode 100644
index 00000000..305779b4
--- /dev/null
+++ b/apps/server/src/integrations/import/file-task.controller.ts
@@ -0,0 +1,79 @@
+import {
+ Body,
+ Controller,
+ ForbiddenException,
+ HttpCode,
+ HttpStatus,
+ NotFoundException,
+ Post,
+ UseGuards,
+} from '@nestjs/common';
+import SpaceAbilityFactory from '../../core/casl/abilities/space-ability.factory';
+import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
+import { User } from '@docmost/db/types/entity.types';
+import {
+ SpaceCaslAction,
+ SpaceCaslSubject,
+} from '../../core/casl/interfaces/space-ability.type';
+import { InjectKysely } from 'nestjs-kysely';
+import { KyselyDB } from '@docmost/db/types/kysely.types';
+import { AuthUser } from '../../common/decorators/auth-user.decorator';
+import { FileTaskIdDto } from './dto/file-task-dto';
+import { SpaceMemberRepo } from '@docmost/db/repos/space/space-member.repo';
+
+@Controller('file-tasks')
+export class FileTaskController {
+ constructor(
+ private readonly spaceMemberRepo: SpaceMemberRepo,
+ private readonly spaceAbility: SpaceAbilityFactory,
+ @InjectKysely() private readonly db: KyselyDB,
+ ) {}
+
+ @UseGuards(JwtAuthGuard)
+ @HttpCode(HttpStatus.OK)
+ @Post()
+ async getFileTasks(@AuthUser() user: User) {
+ const userSpaceIds = await this.spaceMemberRepo.getUserSpaceIds(user.id);
+
+ if (!userSpaceIds || userSpaceIds.length === 0) {
+ return [];
+ }
+
+ const fileTasks = await this.db
+ .selectFrom('fileTasks')
+ .selectAll()
+ .where('spaceId', 'in', userSpaceIds)
+ .execute();
+
+ if (!fileTasks) {
+ throw new NotFoundException('File task not found');
+ }
+
+ return fileTasks;
+ }
+
+ @UseGuards(JwtAuthGuard)
+ @HttpCode(HttpStatus.OK)
+ @Post('info')
+ async getFileTask(@Body() dto: FileTaskIdDto, @AuthUser() user: User) {
+ const fileTask = await this.db
+ .selectFrom('fileTasks')
+ .selectAll()
+ .where('id', '=', dto.fileTaskId)
+ .executeTakeFirst();
+
+ if (!fileTask || !fileTask.spaceId) {
+ throw new NotFoundException('File task not found');
+ }
+
+ const ability = await this.spaceAbility.createForUser(
+ user,
+ fileTask.spaceId,
+ );
+ if (ability.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
+ throw new ForbiddenException();
+ }
+
+ return fileTask;
+ }
+}
diff --git a/apps/server/src/integrations/import/import.controller.ts b/apps/server/src/integrations/import/import.controller.ts
index 975301af..1adb82eb 100644
--- a/apps/server/src/integrations/import/import.controller.ts
+++ b/apps/server/src/integrations/import/import.controller.ts
@@ -21,8 +21,9 @@ import {
import { FileInterceptor } from '../../common/interceptors/file.interceptor';
import * as bytes from 'bytes';
import * as path from 'path';
-import { ImportService } from './import.service';
+import { ImportService } from './services/import.service';
import { AuthWorkspace } from '../../common/decorators/auth-workspace.decorator';
+import { EnvironmentService } from '../environment/environment.service';
@Controller()
export class ImportController {
@@ -31,6 +32,7 @@ export class ImportController {
constructor(
private readonly importService: ImportService,
private readonly spaceAbility: SpaceAbilityFactory,
+ private readonly environmentService: EnvironmentService,
) {}
@UseInterceptors(FileInterceptor)
@@ -44,18 +46,18 @@ export class ImportController {
) {
const validFileExtensions = ['.md', '.html'];
- const maxFileSize = bytes('100mb');
+ const maxFileSize = bytes('10mb');
let file = null;
try {
file = await req.file({
- limits: { fileSize: maxFileSize, fields: 3, files: 1 },
+ limits: { fileSize: maxFileSize, fields: 4, files: 1 },
});
} catch (err: any) {
this.logger.error(err.message);
if (err?.statusCode === 413) {
throw new BadRequestException(
- `File too large. Exceeds the 100mb import limit`,
+ `File too large. Exceeds the 10mb import limit`,
);
}
}
@@ -73,7 +75,7 @@ export class ImportController {
const spaceId = file.fields?.spaceId?.value;
if (!spaceId) {
- throw new BadRequestException('spaceId or format not found');
+ throw new BadRequestException('spaceId is required');
}
const ability = await this.spaceAbility.createForUser(user, spaceId);
@@ -83,4 +85,69 @@ export class ImportController {
return this.importService.importPage(file, user.id, spaceId, workspace.id);
}
+
+ @UseInterceptors(FileInterceptor)
+ @UseGuards(JwtAuthGuard)
+ @HttpCode(HttpStatus.OK)
+ @Post('pages/import-zip')
+ async importZip(
+ @Req() req: any,
+ @AuthUser() user: User,
+ @AuthWorkspace() workspace: Workspace,
+ ) {
+ const validFileExtensions = ['.zip'];
+
+ const maxFileSize = bytes(this.environmentService.getFileImportSizeLimit());
+
+ let file = null;
+ try {
+ file = await req.file({
+ limits: { fileSize: maxFileSize, fields: 3, files: 1 },
+ });
+ } catch (err: any) {
+ this.logger.error(err.message);
+ if (err?.statusCode === 413) {
+ throw new BadRequestException(
+ `File too large. Exceeds the ${this.environmentService.getFileImportSizeLimit()} import limit`,
+ );
+ }
+ }
+
+ if (!file) {
+ throw new BadRequestException('Failed to upload file');
+ }
+
+ if (
+ !validFileExtensions.includes(path.extname(file.filename).toLowerCase())
+ ) {
+ throw new BadRequestException('Invalid import file extension.');
+ }
+
+ const spaceId = file.fields?.spaceId?.value;
+ const source = file.fields?.source?.value;
+
+ const validZipSources = ['generic', 'notion', 'confluence'];
+ if (!validZipSources.includes(source)) {
+ throw new BadRequestException(
+ 'Invalid import source. Import source must either be generic, notion or confluence.',
+ );
+ }
+
+ if (!spaceId) {
+ throw new BadRequestException('spaceId is required');
+ }
+
+ const ability = await this.spaceAbility.createForUser(user, spaceId);
+ if (ability.cannot(SpaceCaslAction.Edit, SpaceCaslSubject.Page)) {
+ throw new ForbiddenException();
+ }
+
+ return this.importService.importZip(
+ file,
+ source,
+ user.id,
+ spaceId,
+ workspace.id,
+ );
+ }
}
diff --git a/apps/server/src/integrations/import/import.module.ts b/apps/server/src/integrations/import/import.module.ts
index 60498808..40a49023 100644
--- a/apps/server/src/integrations/import/import.module.ts
+++ b/apps/server/src/integrations/import/import.module.ts
@@ -1,9 +1,22 @@
import { Module } from '@nestjs/common';
-import { ImportService } from './import.service';
+import { ImportService } from './services/import.service';
import { ImportController } from './import.controller';
+import { StorageModule } from '../storage/storage.module';
+import { FileTaskService } from './services/file-task.service';
+import { FileTaskProcessor } from './processors/file-task.processor';
+import { ImportAttachmentService } from './services/import-attachment.service';
+import { FileTaskController } from './file-task.controller';
+import { PageModule } from '../../core/page/page.module';
@Module({
- providers: [ImportService],
- controllers: [ImportController],
+ providers: [
+ ImportService,
+ FileTaskService,
+ FileTaskProcessor,
+ ImportAttachmentService,
+ ],
+ exports: [ImportService, ImportAttachmentService],
+ controllers: [ImportController, FileTaskController],
+ imports: [StorageModule, PageModule],
})
export class ImportModule {}
diff --git a/apps/server/src/integrations/import/processors/file-task.processor.ts b/apps/server/src/integrations/import/processors/file-task.processor.ts
new file mode 100644
index 00000000..9431ccec
--- /dev/null
+++ b/apps/server/src/integrations/import/processors/file-task.processor.ts
@@ -0,0 +1,76 @@
+import { Logger, OnModuleDestroy } from '@nestjs/common';
+import { OnWorkerEvent, Processor, WorkerHost } from '@nestjs/bullmq';
+import { Job } from 'bullmq';
+import { QueueJob, QueueName } from 'src/integrations/queue/constants';
+import { FileTaskService } from '../services/file-task.service';
+import { FileTaskStatus } from '../utils/file.utils';
+import { StorageService } from '../../storage/storage.service';
+
+@Processor(QueueName.FILE_TASK_QUEUE)
+export class FileTaskProcessor extends WorkerHost implements OnModuleDestroy {
+ private readonly logger = new Logger(FileTaskProcessor.name);
+
+ constructor(
+ private readonly fileTaskService: FileTaskService,
+ private readonly storageService: StorageService,
+ ) {
+ super();
+ }
+
+ async process(job: Job): Promise {
+ try {
+ switch (job.name) {
+ case QueueJob.IMPORT_TASK:
+ await this.fileTaskService.processZIpImport(job.data.fileTaskId);
+ break;
+ case QueueJob.EXPORT_TASK:
+ // TODO: export task
+ break;
+ }
+ } catch (err) {
+ this.logger.error('File task failed', err);
+ throw err;
+ }
+ }
+
+ @OnWorkerEvent('active')
+ onActive(job: Job) {
+ this.logger.debug(`Processing ${job.name} job`);
+ }
+
+ @OnWorkerEvent('failed')
+ async onFailed(job: Job) {
+ this.logger.error(
+ `Error processing ${job.name} job. Reason: ${job.failedReason}`,
+ );
+
+ try {
+ const fileTaskId = job.data.fileTaskId;
+ await this.fileTaskService.updateTaskStatus(
+ fileTaskId,
+ FileTaskStatus.Failed,
+ job.failedReason,
+ );
+
+ const fileTask = await this.fileTaskService.getFileTask(fileTaskId);
+ if (fileTask) {
+ await this.storageService.delete(fileTask.filePath);
+ }
+ } catch (err) {
+ this.logger.error(err);
+ }
+ }
+
+ @OnWorkerEvent('completed')
+ onCompleted(job: Job) {
+ this.logger.log(
+ `Completed ${job.name} job for File task ID ${job.data.fileTaskId}`,
+ );
+ }
+
+ async onModuleDestroy(): Promise {
+ if (this.worker) {
+ await this.worker.close();
+ }
+ }
+}
diff --git a/apps/server/src/integrations/import/services/file-task.service.ts b/apps/server/src/integrations/import/services/file-task.service.ts
new file mode 100644
index 00000000..f054017d
--- /dev/null
+++ b/apps/server/src/integrations/import/services/file-task.service.ts
@@ -0,0 +1,346 @@
+import { Injectable, Logger } from '@nestjs/common';
+import * as path from 'path';
+import { jsonToText } from '../../../collaboration/collaboration.util';
+import { InjectKysely } from 'nestjs-kysely';
+import { KyselyDB } from '@docmost/db/types/kysely.types';
+import {
+ extractZip,
+ FileImportSource,
+ FileTaskStatus,
+} from '../utils/file.utils';
+import { StorageService } from '../../storage/storage.service';
+import * as tmp from 'tmp-promise';
+import { pipeline } from 'node:stream/promises';
+import { createWriteStream } from 'node:fs';
+import { ImportService } from './import.service';
+import { promises as fs } from 'fs';
+import { generateSlugId } from '../../../common/helpers';
+import { v7 } from 'uuid';
+import { generateJitteredKeyBetween } from 'fractional-indexing-jittered';
+import { FileTask, InsertablePage } from '@docmost/db/types/entity.types';
+import { markdownToHtml } from '@docmost/editor-ext';
+import { getProsemirrorContent } from '../../../common/helpers/prosemirror/utils';
+import { formatImportHtml } from '../utils/import-formatter';
+import {
+ buildAttachmentCandidates,
+ collectMarkdownAndHtmlFiles,
+} from '../utils/import.utils';
+import { executeTx } from '@docmost/db/utils';
+import { BacklinkRepo } from '@docmost/db/repos/backlink/backlink.repo';
+import { ImportAttachmentService } from './import-attachment.service';
+import { ModuleRef } from '@nestjs/core';
+import { PageService } from '../../../core/page/services/page.service';
+import { ImportPageNode } from '../dto/file-task-dto';
+
+@Injectable()
+export class FileTaskService {
+ private readonly logger = new Logger(FileTaskService.name);
+
+ constructor(
+ private readonly storageService: StorageService,
+ private readonly importService: ImportService,
+ private readonly pageService: PageService,
+ private readonly backlinkRepo: BacklinkRepo,
+ @InjectKysely() private readonly db: KyselyDB,
+ private readonly importAttachmentService: ImportAttachmentService,
+ private moduleRef: ModuleRef,
+ ) {}
+
+ async processZIpImport(fileTaskId: string): Promise {
+ const fileTask = await this.db
+ .selectFrom('fileTasks')
+ .selectAll()
+ .where('id', '=', fileTaskId)
+ .executeTakeFirst();
+
+ if (!fileTask) {
+ this.logger.log(`Import file task with ID ${fileTaskId} not found`);
+ return;
+ }
+
+ if (fileTask.status === FileTaskStatus.Failed) {
+ return;
+ }
+
+ if (fileTask.status === FileTaskStatus.Success) {
+ this.logger.log('Imported task already processed.');
+ return;
+ }
+
+ const { path: tmpZipPath, cleanup: cleanupTmpFile } = await tmp.file({
+ prefix: 'docmost-import',
+ postfix: '.zip',
+ discardDescriptor: true,
+ });
+
+ const { path: tmpExtractDir, cleanup: cleanupTmpDir } = await tmp.dir({
+ prefix: 'docmost-extract-',
+ unsafeCleanup: true,
+ });
+
+ try {
+ const fileStream = await this.storageService.readStream(
+ fileTask.filePath,
+ );
+ await pipeline(fileStream, createWriteStream(tmpZipPath));
+ await extractZip(tmpZipPath, tmpExtractDir);
+ } catch (err) {
+ await cleanupTmpFile();
+ await cleanupTmpDir();
+
+ throw err;
+ }
+
+ try {
+ if (
+ fileTask.source === FileImportSource.Generic ||
+ fileTask.source === FileImportSource.Notion
+ ) {
+ await this.processGenericImport({
+ extractDir: tmpExtractDir,
+ fileTask,
+ });
+ }
+
+ if (fileTask.source === FileImportSource.Confluence) {
+ let ConfluenceModule: any;
+ try {
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
+ ConfluenceModule = require('./../../../ee/confluence-import/confluence-import.service');
+ } catch (err) {
+ this.logger.error(
+ 'Confluence import requested but EE module not bundled in this build',
+ );
+ return;
+ }
+ const confluenceImportService = this.moduleRef.get(
+ ConfluenceModule.ConfluenceImportService,
+ { strict: false },
+ );
+
+ await confluenceImportService.processConfluenceImport({
+ extractDir: tmpExtractDir,
+ fileTask,
+ });
+ }
+ try {
+ await this.updateTaskStatus(fileTaskId, FileTaskStatus.Success, null);
+ await cleanupTmpFile();
+ await cleanupTmpDir();
+ // delete stored file on success
+ await this.storageService.delete(fileTask.filePath);
+ } catch (err) {
+ this.logger.error(
+ `Failed to delete import file from storage. Task ID: ${fileTaskId}`,
+ err,
+ );
+ }
+ } catch (err) {
+ await cleanupTmpFile();
+ await cleanupTmpDir();
+
+ throw err;
+ }
+ }
+
+ async processGenericImport(opts: {
+ extractDir: string;
+ fileTask: FileTask;
+ }): Promise {
+ const { extractDir, fileTask } = opts;
+ const allFiles = await collectMarkdownAndHtmlFiles(extractDir);
+ const attachmentCandidates = await buildAttachmentCandidates(extractDir);
+
+ const pagesMap = new Map();
+
+ for (const absPath of allFiles) {
+ const relPath = path
+ .relative(extractDir, absPath)
+ .split(path.sep)
+ .join('/'); // normalize to forward-slashes
+ const ext = path.extname(relPath).toLowerCase();
+ let content = await fs.readFile(absPath, 'utf-8');
+
+ if (ext.toLowerCase() === '.md') {
+ content = await markdownToHtml(content);
+ }
+
+ pagesMap.set(relPath, {
+ id: v7(),
+ slugId: generateSlugId(),
+ name: path.basename(relPath, ext),
+ content,
+ parentPageId: null,
+ fileExtension: ext,
+ filePath: relPath,
+ });
+ }
+
+ // parent/child linking
+ pagesMap.forEach((page, filePath) => {
+ const segments = filePath.split('/');
+ segments.pop();
+ let parentPage = null;
+ while (segments.length) {
+ const tryMd = segments.join('/') + '.md';
+ const tryHtml = segments.join('/') + '.html';
+ if (pagesMap.has(tryMd)) {
+ parentPage = pagesMap.get(tryMd)!;
+ break;
+ }
+ if (pagesMap.has(tryHtml)) {
+ parentPage = pagesMap.get(tryHtml)!;
+ break;
+ }
+ segments.pop();
+ }
+ if (parentPage) page.parentPageId = parentPage.id;
+ });
+
+ // generate position keys
+ const siblingsMap = new Map();
+
+ pagesMap.forEach((page) => {
+ const group = siblingsMap.get(page.parentPageId) ?? [];
+ group.push(page);
+ siblingsMap.set(page.parentPageId, group);
+ });
+
+ // get root pages
+ const rootSibs = siblingsMap.get(null);
+
+ if (rootSibs?.length) {
+ rootSibs.sort((a, b) => a.name.localeCompare(b.name));
+
+ // get first position key from the server
+ const nextPosition = await this.pageService.nextPagePosition(
+ fileTask.spaceId,
+ );
+
+ let prevPos: string | null = null;
+ rootSibs.forEach((page, idx) => {
+ if (idx === 0) {
+ page.position = nextPosition;
+ } else {
+ page.position = generateJitteredKeyBetween(prevPos, null);
+ }
+ prevPos = page.position;
+ });
+ }
+
+ // non-root buckets (children & deeper levels)
+ siblingsMap.forEach((sibs, parentId) => {
+ if (parentId === null) return; // root already done
+
+ sibs.sort((a, b) => a.name.localeCompare(b.name));
+
+ let prevPos: string | null = null;
+ for (const page of sibs) {
+ page.position = generateJitteredKeyBetween(prevPos, null);
+ prevPos = page.position;
+ }
+ });
+
+ // internal page links
+ const filePathToPageMetaMap = new Map<
+ string,
+ { id: string; title: string; slugId: string }
+ >();
+ pagesMap.forEach((page) => {
+ filePathToPageMetaMap.set(page.filePath, {
+ id: page.id,
+ title: page.name,
+ slugId: page.slugId,
+ });
+ });
+
+ const pageResults = await Promise.all(
+ Array.from(pagesMap.values()).map(async (page) => {
+ const htmlContent =
+ await this.importAttachmentService.processAttachments({
+ html: page.content,
+ pageRelativePath: page.filePath,
+ extractDir,
+ pageId: page.id,
+ fileTask,
+ attachmentCandidates,
+ });
+
+ const { html, backlinks } = await formatImportHtml({
+ html: htmlContent,
+ currentFilePath: page.filePath,
+ filePathToPageMetaMap: filePathToPageMetaMap,
+ creatorId: fileTask.creatorId,
+ sourcePageId: page.id,
+ workspaceId: fileTask.workspaceId,
+ });
+
+ const pmState = getProsemirrorContent(
+ await this.importService.processHTML(html),
+ );
+
+ const { title, prosemirrorJson } =
+ this.importService.extractTitleAndRemoveHeading(pmState);
+
+ const insertablePage: InsertablePage = {
+ id: page.id,
+ slugId: page.slugId,
+ title: title || page.name,
+ content: prosemirrorJson,
+ textContent: jsonToText(prosemirrorJson),
+ ydoc: await this.importService.createYdoc(prosemirrorJson),
+ position: page.position!,
+ spaceId: fileTask.spaceId,
+ workspaceId: fileTask.workspaceId,
+ creatorId: fileTask.creatorId,
+ lastUpdatedById: fileTask.creatorId,
+ parentPageId: page.parentPageId,
+ };
+
+ return { insertablePage, backlinks };
+ }),
+ );
+
+ const insertablePages = pageResults.map((r) => r.insertablePage);
+ const insertableBacklinks = pageResults.flatMap((r) => r.backlinks);
+
+ if (insertablePages.length < 1) return;
+ const validPageIds = new Set(insertablePages.map((row) => row.id));
+ const filteredBacklinks = insertableBacklinks.filter(
+ ({ sourcePageId, targetPageId }) =>
+ validPageIds.has(sourcePageId) && validPageIds.has(targetPageId),
+ );
+
+ await executeTx(this.db, async (trx) => {
+ await trx.insertInto('pages').values(insertablePages).execute();
+
+ if (filteredBacklinks.length > 0) {
+ await this.backlinkRepo.insertBacklink(filteredBacklinks, trx);
+ }
+ });
+ }
+
+ async getFileTask(fileTaskId: string) {
+ return this.db
+ .selectFrom('fileTasks')
+ .selectAll()
+ .where('id', '=', fileTaskId)
+ .executeTakeFirst();
+ }
+
+ async updateTaskStatus(
+ fileTaskId: string,
+ status: FileTaskStatus,
+ errorMessage?: string,
+ ) {
+ try {
+ await this.db
+ .updateTable('fileTasks')
+ .set({ status: status, errorMessage, updatedAt: new Date() })
+ .where('id', '=', fileTaskId)
+ .execute();
+ } catch (err) {
+ this.logger.error(err);
+ }
+ }
+}
diff --git a/apps/server/src/integrations/import/services/import-attachment.service.ts b/apps/server/src/integrations/import/services/import-attachment.service.ts
new file mode 100644
index 00000000..cd9039e2
--- /dev/null
+++ b/apps/server/src/integrations/import/services/import-attachment.service.ts
@@ -0,0 +1,303 @@
+import { Injectable, Logger } from '@nestjs/common';
+import * as path from 'path';
+import { InjectKysely } from 'nestjs-kysely';
+import { KyselyDB } from '@docmost/db/types/kysely.types';
+import { cleanUrlString } from '../utils/file.utils';
+import { StorageService } from '../../storage/storage.service';
+import { createReadStream } from 'node:fs';
+import { promises as fs } from 'fs';
+import { getMimeType, sanitizeFileName } from '../../../common/helpers';
+import { v7 } from 'uuid';
+import { FileTask } from '@docmost/db/types/entity.types';
+import { getAttachmentFolderPath } from '../../../core/attachment/attachment.utils';
+import { AttachmentType } from '../../../core/attachment/attachment.constants';
+import { unwrapFromParagraph } from '../utils/import-formatter';
+import { resolveRelativeAttachmentPath } from '../utils/import.utils';
+import { load } from 'cheerio';
+
+@Injectable()
+export class ImportAttachmentService {
+ private readonly logger = new Logger(ImportAttachmentService.name);
+
+ constructor(
+ private readonly storageService: StorageService,
+ @InjectKysely() private readonly db: KyselyDB,
+ ) {}
+
+ async processAttachments(opts: {
+ html: string;
+ pageRelativePath: string;
+ extractDir: string;
+ pageId: string;
+ fileTask: FileTask;
+ attachmentCandidates: Map;
+ }): Promise {
+ const {
+ html,
+ pageRelativePath,
+ extractDir,
+ pageId,
+ fileTask,
+ attachmentCandidates,
+ } = opts;
+
+ const attachmentTasks: Promise[] = [];
+
+ /**
+ * Cache keyed by the *relative* path that appears in the HTML.
+ * Ensures we upload (and DB-insert) each attachment at most once,
+ * even if it’s referenced multiple times on the page.
+ */
+ const processed = new Map<
+ string,
+ {
+ attachmentId: string;
+ storageFilePath: string;
+ apiFilePath: string;
+ fileNameWithExt: string;
+ abs: string;
+ }
+ >();
+
+ const uploadOnce = (relPath: string) => {
+ const abs = attachmentCandidates.get(relPath)!;
+ const attachmentId = v7();
+ const ext = path.extname(abs);
+
+ const fileNameWithExt =
+ sanitizeFileName(path.basename(abs, ext)) + ext.toLowerCase();
+
+ const storageFilePath = `${getAttachmentFolderPath(
+ AttachmentType.File,
+ fileTask.workspaceId,
+ )}/${attachmentId}/${fileNameWithExt}`;
+
+ const apiFilePath = `/api/files/${attachmentId}/${fileNameWithExt}`;
+
+ attachmentTasks.push(
+ (async () => {
+ const fileStream = createReadStream(abs);
+ await this.storageService.uploadStream(storageFilePath, fileStream);
+ const stat = await fs.stat(abs);
+
+ await this.db
+ .insertInto('attachments')
+ .values({
+ id: attachmentId,
+ filePath: storageFilePath,
+ fileName: fileNameWithExt,
+ fileSize: stat.size,
+ mimeType: getMimeType(fileNameWithExt),
+ type: 'file',
+ fileExt: ext,
+ creatorId: fileTask.creatorId,
+ workspaceId: fileTask.workspaceId,
+ pageId,
+ spaceId: fileTask.spaceId,
+ })
+ .execute();
+ })(),
+ );
+
+ return {
+ attachmentId,
+ storageFilePath,
+ apiFilePath,
+ fileNameWithExt,
+ abs,
+ };
+ };
+
+ /**
+ * – Returns cached data if we’ve already processed this path.
+ * – Otherwise calls `uploadOnce`, stores the result, and returns it.
+ */
+ const processFile = (relPath: string) => {
+ const cached = processed.get(relPath);
+ if (cached) return cached;
+
+ const fresh = uploadOnce(relPath);
+ processed.set(relPath, fresh);
+ return fresh;
+ };
+
+ const pageDir = path.dirname(pageRelativePath);
+ const $ = load(html);
+
+ // image
+ for (const imgEl of $('img').toArray()) {
+ const $img = $(imgEl);
+ const src = cleanUrlString($img.attr('src') ?? '')!;
+ if (!src || src.startsWith('http')) continue;
+
+ const relPath = resolveRelativeAttachmentPath(
+ src,
+ pageDir,
+ attachmentCandidates,
+ );
+ if (!relPath) continue;
+
+ const { attachmentId, apiFilePath, abs } = processFile(relPath);
+ const stat = await fs.stat(abs);
+
+ const width = $img.attr('width') ?? '100%';
+ const align = $img.attr('data-align') ?? 'center';
+
+ $img
+ .attr('src', apiFilePath)
+ .attr('data-attachment-id', attachmentId)
+ .attr('data-size', stat.size.toString())
+ .attr('width', width)
+ .attr('data-align', align);
+
+ unwrapFromParagraph($, $img);
+ }
+
+ // video
+ for (const vidEl of $('video').toArray()) {
+ const $vid = $(vidEl);
+ const src = cleanUrlString($vid.attr('src') ?? '')!;
+ if (!src || src.startsWith('http')) continue;
+
+ const relPath = resolveRelativeAttachmentPath(
+ src,
+ pageDir,
+ attachmentCandidates,
+ );
+ if (!relPath) continue;
+
+ const { attachmentId, apiFilePath, abs } = processFile(relPath);
+ const stat = await fs.stat(abs);
+
+ const width = $vid.attr('width') ?? '100%';
+ const align = $vid.attr('data-align') ?? 'center';
+
+ $vid
+ .attr('src', apiFilePath)
+ .attr('data-attachment-id', attachmentId)
+ .attr('data-size', stat.size.toString())
+ .attr('width', width)
+ .attr('data-align', align);
+
+ unwrapFromParagraph($, $vid);
+ }
+
+ //