mirror of
https://github.com/docmost/docmost.git
synced 2026-05-08 07:13:06 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c354bc7be3 |
+2
-4
@@ -1,4 +1,4 @@
|
||||
FROM node:22-slim AS base
|
||||
FROM node:22-alpine AS base
|
||||
LABEL org.opencontainers.image.source="https://github.com/docmost/docmost"
|
||||
|
||||
FROM base AS builder
|
||||
@@ -13,9 +13,7 @@ RUN pnpm build
|
||||
|
||||
FROM base AS installer
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends curl bash \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
RUN apk add --no-cache curl bash
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "client",
|
||||
"private": true,
|
||||
"version": "0.24.1",
|
||||
"version": "0.23.2",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
"Delete group": "Gruppe löschen",
|
||||
"Are you sure you want to delete this page? This will delete its children and page history. This action is irreversible.": "Sind Sie sicher, dass Sie diese Seite löschen möchten? Dadurch werden ihre Unterseiten und die Seitengeschichte gelöscht. Diese Aktion ist unwiderruflich.",
|
||||
"Description": "Beschreibung",
|
||||
"Details": "Details",
|
||||
"Details": "Einzelheiten",
|
||||
"e.g ACME": "z.B. ACME",
|
||||
"e.g ACME Inc": "z.B. ACME Inc.",
|
||||
"e.g Developers": "z.B. Entwickler",
|
||||
@@ -525,47 +525,5 @@
|
||||
"Delete SSO provider": "SSO-Anbieter löschen",
|
||||
"Are you sure you want to delete this SSO provider?": "Sind Sie sicher, dass Sie diesen SSO-Anbieter löschen möchten?",
|
||||
"Action": "Aktion",
|
||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}}-Konfiguration",
|
||||
"Icon": "Icon",
|
||||
"Upload image": "Bild hochladen",
|
||||
"Remove image": "Bild entfernen",
|
||||
"Failed to remove image": "Fehler beim Entfernen des Bildes",
|
||||
"Image exceeds 10MB limit.": "Bild überschreitet das Limit von 10 MB.",
|
||||
"Image removed successfully": "Bild erfolgreich entfernt",
|
||||
"API key": "API-Schlüssel",
|
||||
"API key created successfully": "API-Schlüssel erfolgreich erstellt",
|
||||
"API keys": "API-Schlüssel",
|
||||
"API management": "API-Verwaltung",
|
||||
"Are you sure you want to revoke this API key": "Sind Sie sicher, dass Sie diesen API-Schlüssel widerrufen möchten?",
|
||||
"Create API Key": "API-Schlüssel erstellen",
|
||||
"Custom expiration date": "Benutzerdefiniertes Ablaufdatum",
|
||||
"Enter a descriptive token name": "Geben Sie einen beschreibenden Token-Namen ein",
|
||||
"Expiration": "Ablauf",
|
||||
"Expired": "Abgelaufen",
|
||||
"Expires": "Läuft ab",
|
||||
"I've saved my API key": "Ich habe meinen API-Schlüssel gespeichert",
|
||||
"Last use": "Zuletzt verwendet",
|
||||
"No API keys found": "Keine API-Schlüssel gefunden",
|
||||
"No expiration": "Kein Ablauf",
|
||||
"Revoke API key": "API-Schlüssel widerrufen",
|
||||
"Revoked successfully": "Erfolgreich widerrufen",
|
||||
"Select expiration date": "Ablaufdatum wählen",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Diese Aktion kann nicht rückgängig gemacht werden. Alle Anwendungen, die diesen API-Schlüssel verwenden, werden nicht mehr funktionieren.",
|
||||
"Update API key": "API-Schlüssel aktualisieren",
|
||||
"Manage API keys for all users in the workspace": "Verwalten Sie API-Schlüssel für alle Benutzer im Arbeitsbereich",
|
||||
"AI settings": "KI-Einstellungen",
|
||||
"AI search": "KI-Suche",
|
||||
"AI Answer": "KI-Antwort",
|
||||
"Ask AI": "KI fragen",
|
||||
"AI is thinking...": "Die KI überlegt...",
|
||||
"Ask a question...": "Fragen stellen...",
|
||||
"AI-powered search (Ask AI)": "KI-gestützte Suche (KI fragen)",
|
||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "Die KI-Suche verwendet Vektor-Einbettungen, um semantische Suchfunktionen in Ihrem Arbeitsbereich bereitzustellen.",
|
||||
"Toggle AI search": "KI-Suche umschalten",
|
||||
"Sources": "Quellen",
|
||||
"Ask AI not available for attachments": "KI fragen nicht für Anhänge verfügbar",
|
||||
"No answer available": "Keine Antwort verfügbar",
|
||||
"Background color": "Hintergrundfarbe",
|
||||
"Highlight color": "Hervorhebungsfarbe",
|
||||
"Remove color": "Farbe entfernen"
|
||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}}-Konfiguration"
|
||||
}
|
||||
|
||||
@@ -527,47 +527,5 @@
|
||||
"Delete SSO provider": "Eliminar proveedor de SSO",
|
||||
"Are you sure you want to delete this SSO provider?": "¿Está seguro de que desea eliminar este proveedor de SSO?",
|
||||
"Action": "Acción",
|
||||
"{{ssoProviderType}} configuration": "Configuración de {{ssoProviderType}}",
|
||||
"Icon": "Icono",
|
||||
"Upload image": "Subir imagen",
|
||||
"Remove image": "Eliminar imagen",
|
||||
"Failed to remove image": "No se ha podido eliminar la imagen",
|
||||
"Image exceeds 10MB limit.": "La imagen excede del límite de 10 MB",
|
||||
"Image removed successfully": "Imagen eliminada correctamente",
|
||||
"API key": "Clave API",
|
||||
"API key created successfully": "Clave API creada correctamente",
|
||||
"API keys": "Claves API",
|
||||
"API management": "Gestión de API",
|
||||
"Are you sure you want to revoke this API key": "¿Está seguro de que desea revocar esta clave API? ",
|
||||
"Create API Key": "Crear clave API",
|
||||
"Custom expiration date": "Fecha de vencimiento personalizada",
|
||||
"Enter a descriptive token name": "Introduce un nombre descriptivo del token",
|
||||
"Expiration": "Vencimiento",
|
||||
"Expired": "Vencido",
|
||||
"Expires": "Vence",
|
||||
"I've saved my API key": "He guardado mi clave API",
|
||||
"Last use": "Último uso",
|
||||
"No API keys found": "No se han encontrado claves API",
|
||||
"No expiration": "Sin vencimiento",
|
||||
"Revoke API key": "Revocar clave API",
|
||||
"Revoked successfully": "Revocada correctamente",
|
||||
"Select expiration date": "Seleccionar fecha de vencimiento",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Esta acción no se puede deshacer. Las aplicaciones que utilicen esta clave API dejarán de funcionar.",
|
||||
"Update API key": "Actualizar clave API",
|
||||
"Manage API keys for all users in the workspace": "Gestionar claves API para todos los usuarios en el espacio de trabajo",
|
||||
"AI settings": "Configuración de IA",
|
||||
"AI search": "Búsqueda de IA",
|
||||
"AI Answer": "Respuesta de IA",
|
||||
"Ask AI": "Preguntar a IA",
|
||||
"AI is thinking...": "IA está pensando...",
|
||||
"Ask a question...": "Haz una pregunta...",
|
||||
"AI-powered search (Ask AI)": "Búsqueda impulsada por IA (Preguntar a IA)",
|
||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "La búsqueda de IA utiliza incrustaciones vectoriales para proporcionar capacidades de búsqueda semántica en todo el contenido de su espacio de trabajo.",
|
||||
"Toggle AI search": "Alternar búsqueda de IA",
|
||||
"Sources": "Fuentes",
|
||||
"Ask AI not available for attachments": "Preguntar a IA no está disponible para adjuntos",
|
||||
"No answer available": "No hay respuesta disponible",
|
||||
"Background color": "Color de fondo",
|
||||
"Highlight color": "Color de resaltado",
|
||||
"Remove color": "Eliminar color"
|
||||
"{{ssoProviderType}} configuration": "Configuración de {{ssoProviderType}}"
|
||||
}
|
||||
|
||||
@@ -527,47 +527,5 @@
|
||||
"Delete SSO provider": "Supprimer le fournisseur SSO",
|
||||
"Are you sure you want to delete this SSO provider?": "Êtes-vous sûr de vouloir supprimer ce fournisseur SSO ?",
|
||||
"Action": "Action",
|
||||
"{{ssoProviderType}} configuration": "Configuration {{ssoProviderType}}",
|
||||
"Icon": "Icône",
|
||||
"Upload image": "Téléverser une image",
|
||||
"Remove image": "Supprimer l'image",
|
||||
"Failed to remove image": "Échec de la suppression de l'image",
|
||||
"Image exceeds 10MB limit.": "L'image dépasse la limite de 10 Mo.",
|
||||
"Image removed successfully": "Image supprimée avec succès",
|
||||
"API key": "Clé API",
|
||||
"API key created successfully": "Clé API créée avec succès",
|
||||
"API keys": "Clés API",
|
||||
"API management": "Gestion des API",
|
||||
"Are you sure you want to revoke this API key": "Êtes-vous sûr de vouloir révoquer cette clé API",
|
||||
"Create API Key": "Créer une clé API",
|
||||
"Custom expiration date": "Date d'expiration personnalisée",
|
||||
"Enter a descriptive token name": "Entrez un nom descriptif pour le jeton",
|
||||
"Expiration": "Expiration",
|
||||
"Expired": "Expiré(e)",
|
||||
"Expires": "Expire",
|
||||
"I've saved my API key": "J'ai enregistré ma clé API",
|
||||
"Last use": "Dernière utilisation",
|
||||
"No API keys found": "Aucune clé API trouvée",
|
||||
"No expiration": "Pas d'expiration",
|
||||
"Revoke API key": "Révoquer la clé API",
|
||||
"Revoked successfully": "Révoqué(e) avec succès",
|
||||
"Select expiration date": "Sélectionnez la date d'expiration",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Cette action ne peut pas être annulée. Toutes les applications utilisant cette clé API cesseront de fonctionner.",
|
||||
"Update API key": "Mettre à jour la clé API",
|
||||
"Manage API keys for all users in the workspace": "Gérer les clés API pour tous les utilisateurs dans l'espace de travail",
|
||||
"AI settings": "Paramètres de l'IA",
|
||||
"AI search": "Recherche IA",
|
||||
"AI Answer": "Réponse IA",
|
||||
"Ask AI": "Demander à l'IA",
|
||||
"AI is thinking...": "L'IA réfléchit...",
|
||||
"Ask a question...": "Posez une question...",
|
||||
"AI-powered search (Ask AI)": "Recherche assistée par l'IA (Demander à l'IA)",
|
||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "La recherche IA utilise des incorporations vectorielles pour fournir des capacités de recherche sémantique à travers le contenu de votre espace de travail.",
|
||||
"Toggle AI search": "Basculer la recherche IA",
|
||||
"Sources": "Sources",
|
||||
"Ask AI not available for attachments": "Demande à l'IA non disponible pour les pièces jointes",
|
||||
"No answer available": "Pas de réponse disponible",
|
||||
"Background color": "Couleur de fond",
|
||||
"Highlight color": "Couleur de surbrillance",
|
||||
"Remove color": "Supprimer la couleur"
|
||||
"{{ssoProviderType}} configuration": "Configuration {{ssoProviderType}}"
|
||||
}
|
||||
|
||||
@@ -527,47 +527,5 @@
|
||||
"Delete SSO provider": "Elimina provider SSO",
|
||||
"Are you sure you want to delete this SSO provider?": "Sei sicuro di voler eliminare questo provider SSO?",
|
||||
"Action": "Azione",
|
||||
"{{ssoProviderType}} configuration": "Configurazione {{ssoProviderType}}",
|
||||
"Icon": "Icona",
|
||||
"Upload image": "Carica immagine",
|
||||
"Remove image": "Rimuovi immagine",
|
||||
"Failed to remove image": "Rimozione immagine fallita",
|
||||
"Image exceeds 10MB limit.": "L'immagine supera il limite di 10MB.",
|
||||
"Image removed successfully": "Immagine rimossa con successo",
|
||||
"API key": "Chiave API",
|
||||
"API key created successfully": "Chiave API creata con successo",
|
||||
"API keys": "Chiavi API",
|
||||
"API management": "Gestione API",
|
||||
"Are you sure you want to revoke this API key": "Sei sicuro di voler revocare questa chiave API",
|
||||
"Create API Key": "Crea Chiave API",
|
||||
"Custom expiration date": "Data di scadenza personalizzata",
|
||||
"Enter a descriptive token name": "Inserisci un nome descrittivo del token",
|
||||
"Expiration": "Scadenza",
|
||||
"Expired": "Scaduto",
|
||||
"Expires": "Scade",
|
||||
"I've saved my API key": "Ho salvato la mia chiave API",
|
||||
"Last use": "Ultimo utilizzo",
|
||||
"No API keys found": "Nessuna chiave API trovata",
|
||||
"No expiration": "Nessuna scadenza",
|
||||
"Revoke API key": "Revoca chiave API",
|
||||
"Revoked successfully": "Revocata con successo",
|
||||
"Select expiration date": "Seleziona la data di scadenza",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Questa azione non può essere annullata. Qualsiasi applicazione che utilizza questa chiave API smetterà di funzionare.",
|
||||
"Update API key": "Aggiorna chiave API",
|
||||
"Manage API keys for all users in the workspace": "Gestisci le chiavi API per tutti gli utenti nell'area di lavoro",
|
||||
"AI settings": "Impostazioni AI",
|
||||
"AI search": "Ricerca AI",
|
||||
"AI Answer": "Risposta AI",
|
||||
"Ask AI": "Chiedi all'AI",
|
||||
"AI is thinking...": "L'AI sta pensando...",
|
||||
"Ask a question...": "Fai una domanda...",
|
||||
"AI-powered search (Ask AI)": "Ricerca potenziata dall'AI (Chiedi all'AI)",
|
||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "La ricerca AI utilizza embeddings vettoriali per fornire capacità di ricerca semantica nel contenuto della tua area di lavoro.",
|
||||
"Toggle AI search": "Attiva/disattiva ricerca AI",
|
||||
"Sources": "Fonti",
|
||||
"Ask AI not available for attachments": "Chiedere all'AI non è disponibile per gli allegati",
|
||||
"No answer available": "Nessuna risposta disponibile",
|
||||
"Background color": "Colore di sfondo",
|
||||
"Highlight color": "Colore evidenziato",
|
||||
"Remove color": "Rimuovi colore"
|
||||
"{{ssoProviderType}} configuration": "Configurazione {{ssoProviderType}}"
|
||||
}
|
||||
|
||||
@@ -527,47 +527,5 @@
|
||||
"Delete SSO provider": "SSOプロバイダーを削除する",
|
||||
"Are you sure you want to delete this SSO provider?": "このSSOプロバイダーを削除してもよろしいですか?",
|
||||
"Action": "アクション",
|
||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}}の構成",
|
||||
"Icon": "アイコン",
|
||||
"Upload image": "画像をアップロード",
|
||||
"Remove image": "画像を削除",
|
||||
"Failed to remove image": "画像の削除に失敗しました",
|
||||
"Image exceeds 10MB limit.": "画像が10MBの制限を超えています。",
|
||||
"Image removed successfully": "画像が正常に削除されました",
|
||||
"API key": "APIキー",
|
||||
"API key created successfully": "APIキーが正常に作成されました",
|
||||
"API keys": "APIキー",
|
||||
"API management": "API管理",
|
||||
"Are you sure you want to revoke this API key": "このAPIキーを無効にしてもよろしいですか",
|
||||
"Create API Key": "APIキーを作成",
|
||||
"Custom expiration date": "カスタム有効期限",
|
||||
"Enter a descriptive token name": "説明的なトークン名を入力してください",
|
||||
"Expiration": "有効期限",
|
||||
"Expired": "期限切れ",
|
||||
"Expires": "期限が切れます",
|
||||
"I've saved my API key": "APIキーを保存しました",
|
||||
"Last use": "最終使用",
|
||||
"No API keys found": "APIキーが見つかりません",
|
||||
"No expiration": "期限なし",
|
||||
"Revoke API key": "APIキーを無効にする",
|
||||
"Revoked successfully": "正常に無効化されました",
|
||||
"Select expiration date": "有効期限を選択してください",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "この操作は元に戻せません。このAPIキーを使用しているアプリケーションは動作を停止します。",
|
||||
"Update API key": "APIキーを更新",
|
||||
"Manage API keys for all users in the workspace": "ワークスペース内のすべてのユーザーのAPIキーを管理",
|
||||
"AI settings": "AI設定",
|
||||
"AI search": "AI検索",
|
||||
"AI Answer": "AI回答",
|
||||
"Ask AI": "AIに質問する",
|
||||
"AI is thinking...": "AIが考え中...",
|
||||
"Ask a question...": "質問を入力...",
|
||||
"AI-powered search (Ask AI)": "AIによる検索(AIに質問)",
|
||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "AI検索はベクター埋め込みを使用して、ワークスペースコンテンツ全体にわたって意味検索機能を提供します。",
|
||||
"Toggle AI search": "AI検索を切り替え",
|
||||
"Sources": "ソース",
|
||||
"Ask AI not available for attachments": "添付ファイルにはAI質問は利用できません",
|
||||
"No answer available": "回答がありません",
|
||||
"Background color": "背景色",
|
||||
"Highlight color": "ハイライト色",
|
||||
"Remove color": "色を削除"
|
||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}}の構成"
|
||||
}
|
||||
|
||||
@@ -527,47 +527,5 @@
|
||||
"Delete SSO provider": "SSO 제공자 삭제",
|
||||
"Are you sure you want to delete this SSO provider?": "이 SSO 제공자를 삭제하시겠습니까?",
|
||||
"Action": "작업",
|
||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}} 구성",
|
||||
"Icon": "아이콘",
|
||||
"Upload image": "이미지 업로드",
|
||||
"Remove image": "이미지 제거",
|
||||
"Failed to remove image": "이미지 제거 실패",
|
||||
"Image exceeds 10MB limit.": "이미지가 10MB 용량 제한을 초과합니다.",
|
||||
"Image removed successfully": "이미지가 성공적으로 제거되었습니다",
|
||||
"API key": "API 키",
|
||||
"API key created successfully": "API 키 생성 완료",
|
||||
"API keys": "API 키",
|
||||
"API management": "API 관리",
|
||||
"Are you sure you want to revoke this API key": "이 API 키를 취소하시겠습니까?",
|
||||
"Create API Key": "API 키 생성",
|
||||
"Custom expiration date": "사용자 정의 만료일",
|
||||
"Enter a descriptive token name": "토큰 이름을 입력하세요",
|
||||
"Expiration": "만료",
|
||||
"Expired": "만료됨",
|
||||
"Expires": "만료일",
|
||||
"I've saved my API key": "API 키를 저장했습니다",
|
||||
"Last use": "최근 사용",
|
||||
"No API keys found": "API 키를 찾을 수 없습니다",
|
||||
"No expiration": "유효기간 없음",
|
||||
"Revoke API key": "API 키 취소",
|
||||
"Revoked successfully": "성공적으로 취소되었습니다",
|
||||
"Select expiration date": "만료일 선택",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "이 작업은 되돌릴 수 없습니다. 이 API 키를 사용하는 모든 응용 프로그램이 작동을 멈출 것입니다.",
|
||||
"Update API key": "API 키 갱신",
|
||||
"Manage API keys for all users in the workspace": "워크스페이스 내 모든 사용자의 API 키 관리",
|
||||
"AI settings": "AI 설정",
|
||||
"AI search": "AI 검색",
|
||||
"AI Answer": "AI 답변",
|
||||
"Ask AI": "AI에게 묻기",
|
||||
"AI is thinking...": "AI가 생각 중입니다...",
|
||||
"Ask a question...": "질문하세요...",
|
||||
"AI-powered search (Ask AI)": "AI 지원 검색 (AI에게 묻기)",
|
||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "AI 검색은 벡터 임베딩을 사용하여 작업공간 콘텐츠에 대한 의미 검색 기능을 제공합니다.",
|
||||
"Toggle AI search": "AI 검색 전환",
|
||||
"Sources": "출처",
|
||||
"Ask AI not available for attachments": "AI에게 묻기 기능은 첨부 파일에 대해 사용할 수 없습니다",
|
||||
"No answer available": "답변을 제공할 수 없습니다",
|
||||
"Background color": "배경 색",
|
||||
"Highlight color": "강조 색",
|
||||
"Remove color": "색 제거"
|
||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}} 구성"
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"Create group": "Groep aanmaken",
|
||||
"Create page": "Pagina aanmaken",
|
||||
"Create space": "Ruimte aanmaken",
|
||||
"Create workspace": "Werkruimte aanmaken",
|
||||
"Create workspace": "Wwerkruimte aanmaken",
|
||||
"Current password": "Huidig wachtwoord",
|
||||
"Dark": "Donker",
|
||||
"Date": "Datum",
|
||||
@@ -91,7 +91,7 @@
|
||||
"Invite by email": "Uitnodigen via e-mail",
|
||||
"Invite members": "Leden uitnodigen",
|
||||
"Invite new members": "Nieuwe leden uitnodigen",
|
||||
"Invited members who are yet to accept their invitation will appear here.": "Uitgenodigde leden die hun uitnodiging nog moeten accepteren zullen hier worden getoond.",
|
||||
"Invited members who are yet to accept their invitation will appear here.": "Uigenodigde leden die hun uitnodiging nog moeten accepteren zullen hier worden getoond.",
|
||||
"Invited members will be granted access to spaces the groups can access": "Uitgenodigde leden wordt toegang gegeven tot ruimtes de groepen toegang toe heeft",
|
||||
"Join the workspace": "Word lid van de werkruimte",
|
||||
"Language": "Taal",
|
||||
@@ -527,47 +527,5 @@
|
||||
"Delete SSO provider": "Verwijder SSO-provider",
|
||||
"Are you sure you want to delete this SSO provider?": "Weet u zeker dat u deze SSO-provider wilt verwijderen?",
|
||||
"Action": "Actie",
|
||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}} configuratie",
|
||||
"Icon": "Icoon",
|
||||
"Upload image": "Afbeelding uploaden",
|
||||
"Remove image": "Afbeelding verwijderen",
|
||||
"Failed to remove image": "Afbeelding verwijderen mislukt",
|
||||
"Image exceeds 10MB limit.": "Afbeelding overschrijdt de limiet van 10MB.",
|
||||
"Image removed successfully": "Afbeelding succesvol verwijderd",
|
||||
"API key": "API-sleutel",
|
||||
"API key created successfully": "API-sleutel succesvol aangemaakt",
|
||||
"API keys": "API-sleutels",
|
||||
"API management": "API-beheer",
|
||||
"Are you sure you want to revoke this API key": "Weet u zeker dat u deze API-sleutel wilt intrekken",
|
||||
"Create API Key": "API-sleutel aanmaken",
|
||||
"Custom expiration date": "Aangepaste vervaldatum",
|
||||
"Enter a descriptive token name": "Voer een beschrijvende tokennaam in",
|
||||
"Expiration": "Vervaldatum",
|
||||
"Expired": "Verlopen",
|
||||
"Expires": "Verloopt",
|
||||
"I've saved my API key": "Ik heb mijn API-sleutel opgeslagen",
|
||||
"Last use": "Laatst gebruikt",
|
||||
"No API keys found": "Geen API-sleutels gevonden",
|
||||
"No expiration": "Geen vervaldatum",
|
||||
"Revoke API key": "API-sleutel intrekken",
|
||||
"Revoked successfully": "Succesvol ingetrokken",
|
||||
"Select expiration date": "Selecteer vervaldatum",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Deze actie kan niet ongedaan worden gemaakt. Alle toepassingen die deze API-sleutel gebruiken, zullen niet meer werken.",
|
||||
"Update API key": "API-sleutel bijwerken",
|
||||
"Manage API keys for all users in the workspace": "Beheer API-sleutels voor alle gebruikers in de werkruimte",
|
||||
"AI settings": "AI-instellingen",
|
||||
"AI search": "AI-zoekopdracht",
|
||||
"AI Answer": "AI Antwoord",
|
||||
"Ask AI": "Vraag AI",
|
||||
"AI is thinking...": "AI is aan het nadenken...",
|
||||
"Ask a question...": "Stel een vraag...",
|
||||
"AI-powered search (Ask AI)": "AI-ondersteunde zoekopdracht (Vraag AI)",
|
||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "AI-zoekopdracht maakt gebruik van vectorembeddings om semantische zoekmogelijkheden te bieden in uw werkruimte-inhoud.",
|
||||
"Toggle AI search": "Schakel AI-zoekopdracht in/uit",
|
||||
"Sources": "Bronnen",
|
||||
"Ask AI not available for attachments": "Vraag AI is niet beschikbaar voor bijlages",
|
||||
"No answer available": "Geen antwoord beschikbaar",
|
||||
"Background color": "Achtergrondkleur",
|
||||
"Highlight color": "Markeerkleur",
|
||||
"Remove color": "Kleur verwijderen"
|
||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}} configuratie"
|
||||
}
|
||||
|
||||
@@ -527,47 +527,5 @@
|
||||
"Delete SSO provider": "Excluir provedor de SSO",
|
||||
"Are you sure you want to delete this SSO provider?": "Tem certeza de que deseja excluir este provedor de SSO?",
|
||||
"Action": "Ação",
|
||||
"{{ssoProviderType}} configuration": "Configuração de {{ssoProviderType}}",
|
||||
"Icon": "Ícone",
|
||||
"Upload image": "Fazer upload da imagem",
|
||||
"Remove image": "Remover imagem",
|
||||
"Failed to remove image": "Falha ao remover imagem",
|
||||
"Image exceeds 10MB limit.": "A imagem excede o limite de 10MB.",
|
||||
"Image removed successfully": "Imagem removida com sucesso",
|
||||
"API key": "Chave API",
|
||||
"API key created successfully": "Chave API criada com sucesso",
|
||||
"API keys": "Chaves API",
|
||||
"API management": "Gestão de API",
|
||||
"Are you sure you want to revoke this API key": "Tem certeza de que deseja revogar esta chave API",
|
||||
"Create API Key": "Criar Chave API",
|
||||
"Custom expiration date": "Data de expiração personalizada",
|
||||
"Enter a descriptive token name": "Insira um nome descritivo para o token",
|
||||
"Expiration": "Expiração",
|
||||
"Expired": "Expirado",
|
||||
"Expires": "Expira",
|
||||
"I've saved my API key": "Salvei minha chave API",
|
||||
"Last use": "Último uso",
|
||||
"No API keys found": "Nenhuma chave API encontrada",
|
||||
"No expiration": "Sem expiração",
|
||||
"Revoke API key": "Revogar chave API",
|
||||
"Revoked successfully": "Revogada com sucesso",
|
||||
"Select expiration date": "Selecionar data de expiração",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Esta ação não pode ser desfeita. Qualquer aplicação usando esta chave API deixará de funcionar.",
|
||||
"Update API key": "Atualizar chave API",
|
||||
"Manage API keys for all users in the workspace": "Gerenciar chaves API para todos os usuários no espaço de trabalho",
|
||||
"AI settings": "Configurações de IA",
|
||||
"AI search": "Pesquisa IA",
|
||||
"AI Answer": "Resposta de IA",
|
||||
"Ask AI": "Pergunte à IA",
|
||||
"AI is thinking...": "IA está pensando...",
|
||||
"Ask a question...": "Faça uma pergunta...",
|
||||
"AI-powered search (Ask AI)": "Pesquisa com IA (Pergunte à IA)",
|
||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "A pesquisa IA usa vetores de incorporação para fornecer capacidades de pesquisa semântica em todo o conteúdo do seu espaço de trabalho.",
|
||||
"Toggle AI search": "Alternar pesquisa de IA",
|
||||
"Sources": "Fontes",
|
||||
"Ask AI not available for attachments": "Perguntar à IA não está disponível para anexos",
|
||||
"No answer available": "Nenhuma resposta disponível",
|
||||
"Background color": "Cor de fundo",
|
||||
"Highlight color": "Cor de destaque",
|
||||
"Remove color": "Remover cor"
|
||||
"{{ssoProviderType}} configuration": "Configuração de {{ssoProviderType}}"
|
||||
}
|
||||
|
||||
@@ -498,10 +498,10 @@
|
||||
"Deleted at": "Удалено в",
|
||||
"Preview": "Предпросмотр",
|
||||
"Subpages": "Подстраницы",
|
||||
"Failed to load subpages": "Не удалось загрузить под страницы",
|
||||
"Failed to load subpages": "Не удалось загрузить подстраницы",
|
||||
"No subpages": "Нет подстраниц",
|
||||
"Subpages (Child pages)": "Подстраницы (вложенные страницы)",
|
||||
"List all subpages of the current page": "Показать все под страницы",
|
||||
"List all subpages of the current page": "Показать все подстраницы текущей страницы",
|
||||
"Attachments": "Вложения",
|
||||
"All spaces": "Все пространства",
|
||||
"Unknown": "Неизвестно",
|
||||
@@ -527,47 +527,5 @@
|
||||
"Delete SSO provider": "Удалить поставщика SSO",
|
||||
"Are you sure you want to delete this SSO provider?": "Вы уверены, что хотите удалить этого поставщика SSO?",
|
||||
"Action": "Действие",
|
||||
"{{ssoProviderType}} configuration": "Настройка {{ssoProviderType}}",
|
||||
"Icon": "Иконка",
|
||||
"Upload image": "Загрузить изображение",
|
||||
"Remove image": "Удалить изображение",
|
||||
"Failed to remove image": "Не удалось удалить изображение",
|
||||
"Image exceeds 10MB limit.": "Изображение превышает предел 10MB.",
|
||||
"Image removed successfully": "Изображение успешно удалено",
|
||||
"API key": "API ключ",
|
||||
"API key created successfully": "API ключ успешно создан",
|
||||
"API keys": "API ключи",
|
||||
"API management": "Управление API",
|
||||
"Are you sure you want to revoke this API key": "Вы уверены, что хотите отозвать этот API ключ",
|
||||
"Create API Key": "Создать API ключ",
|
||||
"Custom expiration date": "Пользовательская дата срока действия",
|
||||
"Enter a descriptive token name": "Введите понятное имя токена",
|
||||
"Expiration": "Срок действия",
|
||||
"Expired": "Истек",
|
||||
"Expires": "Истекает",
|
||||
"I've saved my API key": "Я сохранил мой API ключ",
|
||||
"Last use": "Последнее использование",
|
||||
"No API keys found": "API ключи не найдены",
|
||||
"No expiration": "Не истекает",
|
||||
"Revoke API key": "Отозвать API ключ",
|
||||
"Revoked successfully": "Отозван успешно",
|
||||
"Select expiration date": "Выберете срок действия",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Это действие необратимо. Любые приложения, использующие этот API ключ, перестанут работать.",
|
||||
"Update API key": "Обновить API ключ",
|
||||
"Manage API keys for all users in the workspace": "Управлять API ключами для всех пользователей в рабочей области",
|
||||
"AI settings": "Настройки ИИ",
|
||||
"AI search": "Поиск ИИ",
|
||||
"AI Answer": "Ответ ИИ",
|
||||
"Ask AI": "Спросить ИИ",
|
||||
"AI is thinking...": "ИИ обрабатывает запрос...",
|
||||
"Ask a question...": "Задайте вопрос...",
|
||||
"AI-powered search (Ask AI)": "Поиск на базе ИИ (Спросить ИИ)",
|
||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "Поиск ИИ использует векторные встраивания для обеспечения семантического поиска по содержимому вашего рабочего пространства.",
|
||||
"Toggle AI search": "Переключить поиск ИИ",
|
||||
"Sources": "Источники",
|
||||
"Ask AI not available for attachments": "Функция \"Спросить ИИ\" недоступна для вложений",
|
||||
"No answer available": "Ответ недоступен",
|
||||
"Background color": "Цвет фона",
|
||||
"Highlight color": "Цвет выделения",
|
||||
"Remove color": "Удалить цвет"
|
||||
"{{ssoProviderType}} configuration": "Настройка {{ssoProviderType}}"
|
||||
}
|
||||
|
||||
@@ -527,47 +527,5 @@
|
||||
"Delete SSO provider": "Видалити постачальника SSO",
|
||||
"Are you sure you want to delete this SSO provider?": "Ви впевнені, що хочете видалити цього постачальника SSO?",
|
||||
"Action": "Дія",
|
||||
"{{ssoProviderType}} configuration": "Конфігурація {{ssoProviderType}}",
|
||||
"Icon": "Іконка",
|
||||
"Upload image": "Завантажити зображення",
|
||||
"Remove image": "Видалити зображення",
|
||||
"Failed to remove image": "Не вдалося видалити зображення",
|
||||
"Image exceeds 10MB limit.": "Зображення має займати менше, ніж 10 МБ.",
|
||||
"Image removed successfully": "Зображення видалено",
|
||||
"API key": "Ключ API",
|
||||
"API key created successfully": "Ключ API успішно створено",
|
||||
"API keys": "Ключі API",
|
||||
"API management": "Управління API",
|
||||
"Are you sure you want to revoke this API key": "Ви впевнені, що хочете відкликати цей ключ API",
|
||||
"Create API Key": "Створити ключ API",
|
||||
"Custom expiration date": "Користувацька дата закінчення",
|
||||
"Enter a descriptive token name": "Введіть описову назву токена",
|
||||
"Expiration": "Термін дії",
|
||||
"Expired": "Закінчився",
|
||||
"Expires": "Закінчується",
|
||||
"I've saved my API key": "Я зберіг свій ключ API",
|
||||
"Last use": "Останнє використання",
|
||||
"No API keys found": "Ключі API не знайдено",
|
||||
"No expiration": "Без терміну дії",
|
||||
"Revoke API key": "Відкликати ключ API",
|
||||
"Revoked successfully": "Успішно відкликано",
|
||||
"Select expiration date": "Виберіть дату закінчення",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "Цю дію не можна скасувати. Будь-які додатки, що використовують цей ключ API, перестануть працювати.",
|
||||
"Update API key": "Оновити ключ API",
|
||||
"Manage API keys for all users in the workspace": "Керувати ключами API для всіх користувачів у робочій області",
|
||||
"AI settings": "Налаштування ШІ",
|
||||
"AI search": "Пошук з ШІ",
|
||||
"AI Answer": "Відповідь ШІ",
|
||||
"Ask AI": "Запитати ШІ",
|
||||
"AI is thinking...": "ШІ думає...",
|
||||
"Ask a question...": "Задайте питання...",
|
||||
"AI-powered search (Ask AI)": "Пошук на базі ШІ (Запитати ШІ)",
|
||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "Пошук з ШІ використовує векторні вбудовування для надання можливостей семантичного пошуку у вашому робочому вмісті.",
|
||||
"Toggle AI search": "Переключити пошук з ШІ",
|
||||
"Sources": "Джерела",
|
||||
"Ask AI not available for attachments": "Запитати ШІ недоступно для вкладень",
|
||||
"No answer available": "Відповідь недоступна",
|
||||
"Background color": "Колір фону",
|
||||
"Highlight color": "Колір підсвічування",
|
||||
"Remove color": "Видалити колір"
|
||||
"{{ssoProviderType}} configuration": "Конфігурація {{ssoProviderType}}"
|
||||
}
|
||||
|
||||
@@ -527,47 +527,5 @@
|
||||
"Delete SSO provider": "删除SSO提供商",
|
||||
"Are you sure you want to delete this SSO provider?": "您确定要删除此SSO提供商吗?",
|
||||
"Action": "操作",
|
||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}} 配置",
|
||||
"Icon": "图标",
|
||||
"Upload image": "上传图片",
|
||||
"Remove image": "删除图片",
|
||||
"Failed to remove image": "无法删除图片",
|
||||
"Image exceeds 10MB limit.": "图片超过10MB限制。",
|
||||
"Image removed successfully": "图片删除成功",
|
||||
"API key": "API密钥",
|
||||
"API key created successfully": "API密钥创建成功",
|
||||
"API keys": "API密钥",
|
||||
"API management": "API管理",
|
||||
"Are you sure you want to revoke this API key": "确定要撤销此API密钥吗",
|
||||
"Create API Key": "创建API密钥",
|
||||
"Custom expiration date": "自定义到期日期",
|
||||
"Enter a descriptive token name": "输入描述性令牌名称",
|
||||
"Expiration": "到期",
|
||||
"Expired": "已过期",
|
||||
"Expires": "到期",
|
||||
"I've saved my API key": "我已保存我的API密钥",
|
||||
"Last use": "上次使用",
|
||||
"No API keys found": "找不到API密钥",
|
||||
"No expiration": "无到期",
|
||||
"Revoke API key": "撤销API密钥",
|
||||
"Revoked successfully": "撤销成功",
|
||||
"Select expiration date": "选择到期日期",
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "此操作无法撤销。使用此API密钥的任何应用程序将停止工作。",
|
||||
"Update API key": "更新API密钥",
|
||||
"Manage API keys for all users in the workspace": "管理工作空间中所有用户的API密钥",
|
||||
"AI settings": "AI设置",
|
||||
"AI search": "AI搜索",
|
||||
"AI Answer": "AI回答",
|
||||
"Ask AI": "询问AI",
|
||||
"AI is thinking...": "AI正在思考...",
|
||||
"Ask a question...": "提问...",
|
||||
"AI-powered search (Ask AI)": "AI驱动的搜索(询问AI)",
|
||||
"AI search uses vector embeddings to provide semantic search capabilities across your workspace content.": "AI搜索使用向量嵌入提供跨工作空间内容的语义搜索功能。",
|
||||
"Toggle AI search": "切换AI搜索",
|
||||
"Sources": "来源",
|
||||
"Ask AI not available for attachments": "附件不支持询问AI",
|
||||
"No answer available": "无可用答案",
|
||||
"Background color": "背景颜色",
|
||||
"Highlight color": "突出显示颜色",
|
||||
"Remove color": "移除颜色"
|
||||
"{{ssoProviderType}} configuration": "{{ssoProviderType}} 配置"
|
||||
}
|
||||
|
||||
@@ -37,18 +37,14 @@ export async function askAi(
|
||||
|
||||
let answer = "";
|
||||
let sources: any[] = [];
|
||||
let buffer = "";
|
||||
|
||||
if (reader) {
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
const lines = buffer.split("\n");
|
||||
|
||||
// Keep the last incomplete line in the buffer
|
||||
buffer = lines.pop() || "";
|
||||
const chunk = decoder.decode(value);
|
||||
const lines = chunk.split("\n");
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith("data: ")) {
|
||||
|
||||
@@ -5,7 +5,6 @@ import { v4 as uuidv4 } from "uuid";
|
||||
import classes from "./code-block.module.css";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useComputedColorScheme } from "@mantine/core";
|
||||
import DOMPurify from "dompurify";
|
||||
|
||||
interface MermaidViewProps {
|
||||
props: NodeViewProps;
|
||||
@@ -38,7 +37,7 @@ export default function MermaidView({ props }: MermaidViewProps) {
|
||||
.catch((err) => {
|
||||
if (props.editor.isEditable) {
|
||||
setPreview(
|
||||
`<div class="${classes.error}">${t("Mermaid diagram error:")} ${DOMPurify.sanitize(err)}</div>`,
|
||||
`<div class="${classes.error}">${t("Mermaid diagram error:")} ${err}</div>`,
|
||||
);
|
||||
} else {
|
||||
setPreview(
|
||||
|
||||
@@ -87,7 +87,7 @@ export default function DrawioView(props: NodeViewProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<NodeViewWrapper data-drag-handle>
|
||||
<NodeViewWrapper>
|
||||
<Modal.Root opened={opened} onClose={close} fullScreen>
|
||||
<Modal.Overlay />
|
||||
<Modal.Content style={{ overflow: "hidden" }}>
|
||||
|
||||
@@ -85,7 +85,7 @@ export default function EmbedView(props: NodeViewProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<NodeViewWrapper data-drag-handle>
|
||||
<NodeViewWrapper>
|
||||
{embedUrl ? (
|
||||
<ResizableWrapper
|
||||
initialHeight={nodeHeight || 480}
|
||||
|
||||
@@ -118,7 +118,7 @@ export default function ExcalidrawView(props: NodeViewProps) {
|
||||
};
|
||||
|
||||
return (
|
||||
<NodeViewWrapper data-drag-handle>
|
||||
<NodeViewWrapper>
|
||||
<ReactClearModal
|
||||
style={{
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
|
||||
@@ -16,7 +16,7 @@ export default function ImageView(props: NodeViewProps) {
|
||||
}, [align]);
|
||||
|
||||
return (
|
||||
<NodeViewWrapper data-drag-handle>
|
||||
<NodeViewWrapper>
|
||||
<Image
|
||||
radius="md"
|
||||
fit="contain"
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function MentionView(props: NodeViewProps) {
|
||||
});
|
||||
|
||||
return (
|
||||
<NodeViewWrapper style={{ display: "inline" }} data-drag-handle>
|
||||
<NodeViewWrapper style={{ display: "inline" }}>
|
||||
{entityType === "user" && (
|
||||
<Text className={classes.userMention} component="span">
|
||||
@{label}
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
IconCalendar,
|
||||
IconAppWindow,
|
||||
IconSitemap,
|
||||
IconPageBreak,
|
||||
} from "@tabler/icons-react";
|
||||
import {
|
||||
CommandProps,
|
||||
@@ -153,6 +154,19 @@ const CommandGroups: SlashMenuGroupedItemsType = {
|
||||
command: ({ editor, range }: CommandProps) =>
|
||||
editor.chain().focus().deleteRange(range).setHorizontalRule().run(),
|
||||
},
|
||||
{
|
||||
title: "Page break",
|
||||
description: "Insert page break",
|
||||
searchTerms: ["page break", "hr"],
|
||||
icon: IconPageBreak,
|
||||
command: ({ editor, range }: CommandProps) =>
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.insertContent('<hr data-type="pagebreak" /><p></p>')
|
||||
.run(),
|
||||
},
|
||||
{
|
||||
title: "Image",
|
||||
description: "Upload any image from your device.",
|
||||
|
||||
@@ -52,7 +52,7 @@ export default function SubpagesView(props: NodeViewProps) {
|
||||
|
||||
if (error && !shareId) {
|
||||
return (
|
||||
<NodeViewWrapper data-drag-handle>
|
||||
<NodeViewWrapper>
|
||||
<Text c="dimmed" size="md" py="md">
|
||||
{t("Failed to load subpages")}
|
||||
</Text>
|
||||
@@ -62,7 +62,7 @@ export default function SubpagesView(props: NodeViewProps) {
|
||||
|
||||
if (subpages.length === 0) {
|
||||
return (
|
||||
<NodeViewWrapper data-drag-handle>
|
||||
<NodeViewWrapper>
|
||||
<div className={classes.container}>
|
||||
<Text c="dimmed" size="md" py="md">
|
||||
{t("No subpages")}
|
||||
@@ -73,7 +73,7 @@ export default function SubpagesView(props: NodeViewProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<NodeViewWrapper data-drag-handle>
|
||||
<NodeViewWrapper>
|
||||
<div className={classes.container}>
|
||||
<Stack gap={5}>
|
||||
{subpages.map((page) => (
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function VideoView(props: NodeViewProps) {
|
||||
}, [align]);
|
||||
|
||||
return (
|
||||
<NodeViewWrapper data-drag-handle>
|
||||
<NodeViewWrapper>
|
||||
<video
|
||||
preload="metadata"
|
||||
width={width}
|
||||
|
||||
@@ -46,6 +46,7 @@ import {
|
||||
Heading,
|
||||
Highlight,
|
||||
UniqueID,
|
||||
HorizontalRule,
|
||||
} from "@docmost/editor-ext";
|
||||
import {
|
||||
randomElement,
|
||||
@@ -108,7 +109,9 @@ export const mainExtensions = [
|
||||
spellcheck: false,
|
||||
},
|
||||
},
|
||||
horizontalRule: false,
|
||||
}),
|
||||
HorizontalRule,
|
||||
Heading,
|
||||
UniqueID.configure({
|
||||
types: ["heading", "paragraph"],
|
||||
|
||||
@@ -110,6 +110,14 @@
|
||||
border-top: 1px solid #68cef8;
|
||||
}
|
||||
|
||||
hr[data-type="pagebreak"] {
|
||||
border-top: 1px dashed var(--mantine-color-dark-2) !important;
|
||||
}
|
||||
|
||||
.ProseMirror[contenteditable="false"] hr[data-type="pagebreak"] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ProseMirror-selectednode {
|
||||
outline: 2px solid #70cff8;
|
||||
}
|
||||
@@ -186,7 +194,6 @@
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.ProseMirror > h1,
|
||||
@@ -195,13 +202,11 @@
|
||||
.ProseMirror > h4,
|
||||
.ProseMirror > h5,
|
||||
.ProseMirror > h6 {
|
||||
|
||||
> .link-btn {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
}
|
||||
|
||||
|
||||
> .link-btn > .link-btn-content {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
@@ -213,7 +218,7 @@
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
&:hover > .link-btn > .link-btn-content {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -20,4 +20,10 @@
|
||||
.tableWrapper {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
hr[data-type="pagebreak"] {
|
||||
break-before: always;
|
||||
page-break-before: always;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,17 +62,14 @@ export default function SpaceSettingsModal({
|
||||
</Tabs.List>
|
||||
|
||||
<Tabs.Panel value="general">
|
||||
<ScrollArea h={580} scrollbarSize={5} pr={8}>
|
||||
<div style={{ paddingBottom: "100px"}}>
|
||||
<SpaceDetails
|
||||
spaceId={space?.id}
|
||||
readOnly={spaceAbility.cannot(
|
||||
SpaceCaslAction.Manage,
|
||||
SpaceCaslSubject.Settings,
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ScrollArea h={550} scrollbarSize={4} pr={8}>
|
||||
<SpaceDetails
|
||||
spaceId={space?.id}
|
||||
readOnly={spaceAbility.cannot(
|
||||
SpaceCaslAction.Manage,
|
||||
SpaceCaslSubject.Settings,
|
||||
)}
|
||||
/>
|
||||
</ScrollArea>
|
||||
</Tabs.Panel>
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ export default function SpaceMembersList({
|
||||
return (
|
||||
<>
|
||||
<SearchInput onSearch={handleSearch} />
|
||||
<ScrollArea h={450}>
|
||||
<ScrollArea h={400}>
|
||||
<Table.ScrollContainer minWidth={500}>
|
||||
<Table highlightOnHover verticalSpacing={8}>
|
||||
<Table.Thead>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "server",
|
||||
"version": "0.24.1",
|
||||
"version": "0.23.2",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
@@ -44,7 +44,6 @@
|
||||
"@nestjs-labs/nestjs-ioredis": "^11.0.4",
|
||||
"@nestjs/bullmq": "^11.0.4",
|
||||
"@nestjs/common": "^11.1.9",
|
||||
"nestjs-cls": "^4.5.0",
|
||||
"@nestjs/config": "^4.0.2",
|
||||
"@nestjs/core": "^11.1.9",
|
||||
"@nestjs/event-emitter": "^3.0.1",
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { APP_INTERCEPTOR } from '@nestjs/core';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { AuditActorInterceptor } from './common/interceptors/audit-actor.interceptor';
|
||||
import { CoreModule } from './core/core.module';
|
||||
import { EnvironmentModule } from './integrations/environment/environment.module';
|
||||
import { CollaborationModule } from './collaboration/collaboration.module';
|
||||
@@ -20,7 +18,6 @@ import { SecurityModule } from './integrations/security/security.module';
|
||||
import { TelemetryModule } from './integrations/telemetry/telemetry.module';
|
||||
import { RedisModule } from '@nestjs-labs/nestjs-ioredis';
|
||||
import { RedisConfigService } from './integrations/redis/redis-config.service';
|
||||
import { ClsModule } from 'nestjs-cls';
|
||||
|
||||
const enterpriseModules = [];
|
||||
try {
|
||||
@@ -38,10 +35,6 @@ try {
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ClsModule.forRoot({
|
||||
global: true,
|
||||
middleware: { mount: true },
|
||||
}),
|
||||
CoreModule,
|
||||
DatabaseModule,
|
||||
EnvironmentModule,
|
||||
@@ -67,12 +60,6 @@ try {
|
||||
...enterpriseModules,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [
|
||||
AppService,
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useClass: AuditActorInterceptor,
|
||||
},
|
||||
],
|
||||
providers: [AppService],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
Highlight,
|
||||
UniqueID,
|
||||
addUniqueIdsToDoc,
|
||||
HorizontalRule,
|
||||
} from '@docmost/editor-ext';
|
||||
import { generateText, getSchema, JSONContent } from '@tiptap/core';
|
||||
import { generateHTML, generateJSON } from '../common/helpers/prosemirror/html';
|
||||
@@ -48,7 +49,9 @@ export const tiptapExtensions = [
|
||||
StarterKit.configure({
|
||||
codeBlock: false,
|
||||
heading: false,
|
||||
horizontalRule: false,
|
||||
}),
|
||||
HorizontalRule,
|
||||
Heading,
|
||||
UniqueID.configure({
|
||||
types: ['heading', 'paragraph'],
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
export const AuditEvent = {
|
||||
// Workspace Invitations
|
||||
WORKSPACE_CREATED: 'workspace.created',
|
||||
WORKSPACE_INVITE_CREATED: 'workspace.invite_created',
|
||||
WORKSPACE_INVITE_REVOKED: 'workspace.invite_revoked',
|
||||
|
||||
WORKSPACE_INVITE_ACCEPTED: 'workspace.invite_accepted',
|
||||
|
||||
WORKSPACE_USER_CREATED: 'workspace.user_created',
|
||||
WORKSPACE_USER_DEACTIVATED: 'workspace.user_deactivated',
|
||||
|
||||
WORKSPACE_ALLOWED_DOMAIN_UPDATED: 'workspace.allowed_domain_updated',
|
||||
WORKSPACE_ICON_CHANGED: 'workspace.icon_changed',
|
||||
WORKSPACE_NAME_CHANGED: 'workspace.name_changed',
|
||||
|
||||
WORKSPACE_AI_TOGGLED: 'workspace.ai_toggled',
|
||||
|
||||
USER_CREATED: 'user.created',
|
||||
USER_DELETED: 'user.deleted',
|
||||
USER_LOGIN: 'user.login',
|
||||
USER_LOGOUT: 'user.logout',
|
||||
USER_ROLE_CHANGED: 'user.user_role_changed',
|
||||
USER_PASSWORD_CHANGED: 'user.password_changed',
|
||||
USER_PASSWORD_RESET: 'user.reset_password',
|
||||
USER_PHOTO_CHANGED: 'user.reset_password',
|
||||
USER_NAME_CHANGED: 'user.name_changed',
|
||||
USER_EMAIL_CHANGED: 'user.email_changed',
|
||||
USER_MFA_SETUP: 'user.mfa_setup',
|
||||
USER_MFA_BACKUP_CODE_GENERATED: 'user.mfa_backup_code_generated',
|
||||
|
||||
// API Keys
|
||||
API_KEY_CREATED: 'api_key.created',
|
||||
API_KEY_UPDATED: 'api_key.updated',
|
||||
API_KEY_DELETED: 'api_key.deleted',
|
||||
|
||||
// Space
|
||||
SPACE_CREATED: 'space.created',
|
||||
SPACE_UPDATED: 'space.updated',
|
||||
SPACE_DELETED: 'space.deleted',
|
||||
|
||||
SPACE_MEMBER_ADDED: 'space.member_added',
|
||||
SPACE_MEMBER_REMOVED: 'space.member_removed',
|
||||
SPACE_MEMBER_ROLE_CHANGED: 'space.member_role_changed',
|
||||
|
||||
// OR SPACE_USER_ADDED: 'space.user_added',
|
||||
// SPACE_GROUP_ADDED: 'space.group_added',
|
||||
|
||||
// GROUP
|
||||
GROUP_CREATED: 'group.created',
|
||||
GROUP_UPDATED: 'group.updated',
|
||||
GROUP_DELETED: 'group.deleted',
|
||||
|
||||
GROUP_MEMBER_ADDED: 'group.member_added',
|
||||
GROUP_MEMBER_REMOVED: 'group.member_removed',
|
||||
|
||||
// Comments
|
||||
COMMENT_CREATED: 'comment.created',
|
||||
COMMENT_UPDATED: 'comment.updated',
|
||||
COMMENT_DELETED: 'comment.deleted',
|
||||
COMMENT_RESOLVED: 'comment.resolved',
|
||||
COMMENT_REOPENED: 'comment.reopened',
|
||||
|
||||
// PAGE
|
||||
PAGE_CREATED: 'page.created',
|
||||
PAGE_UPDATED: 'page.updated',
|
||||
PAGE_TRASHED: 'page.trash',
|
||||
PAGE_DELETED: 'page.deleted',
|
||||
PAGE_SHARED: 'page.shared',
|
||||
|
||||
ATTACHMENT_UPLOADED: 'attachment.uploaded',
|
||||
|
||||
PAGE_IMPORTED: 'page.imported',
|
||||
PAGE_RESTORED: 'page.restored',
|
||||
PAGE_EXPORTED: 'page.exported',
|
||||
SPACE_EXPORTED: 'space.imported',
|
||||
|
||||
// SSO EVENTS
|
||||
} as const;
|
||||
|
||||
export type AuditEventType = (typeof AuditEvent)[keyof typeof AuditEvent];
|
||||
|
||||
export type ActorType = 'user' | 'system' | 'api_key';
|
||||
|
||||
export interface AuditLogPayload {
|
||||
event: AuditEventType;
|
||||
resourceType: string;
|
||||
resourceId?: string;
|
||||
changes?: {
|
||||
before?: Record<string, any>;
|
||||
after?: Record<string, any>;
|
||||
};
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface AuditLogData extends AuditLogPayload {
|
||||
workspaceId: string;
|
||||
actorId?: string;
|
||||
actorType: ActorType;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import {
|
||||
CallHandler,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
NestInterceptor,
|
||||
} from '@nestjs/common';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ClsService } from 'nestjs-cls';
|
||||
import { AuditContext, AUDIT_CONTEXT_KEY } from '../middlewares/audit-context.middleware';
|
||||
|
||||
@Injectable()
|
||||
export class AuditActorInterceptor implements NestInterceptor {
|
||||
constructor(private readonly cls: ClsService) {}
|
||||
|
||||
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
const user = request.user?.user;
|
||||
|
||||
if (user?.id) {
|
||||
const auditContext = this.cls.get<AuditContext>(AUDIT_CONTEXT_KEY);
|
||||
if (auditContext) {
|
||||
auditContext.actorId = user.id;
|
||||
this.cls.set(AUDIT_CONTEXT_KEY, auditContext);
|
||||
}
|
||||
}
|
||||
|
||||
return next.handle();
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||
import { FastifyRequest, FastifyReply } from 'fastify';
|
||||
import { ClsService } from 'nestjs-cls';
|
||||
|
||||
export interface AuditContext {
|
||||
workspaceId: string | null;
|
||||
actorId: string | null;
|
||||
actorType: 'user' | 'system' | 'api_key';
|
||||
ipAddress: string | null;
|
||||
}
|
||||
|
||||
export const AUDIT_CONTEXT_KEY = 'auditContext';
|
||||
|
||||
@Injectable()
|
||||
export class AuditContextMiddleware implements NestMiddleware {
|
||||
constructor(private readonly cls: ClsService) {}
|
||||
|
||||
use(req: FastifyRequest['raw'], res: FastifyReply['raw'], next: () => void) {
|
||||
const workspaceId = (req as any).workspaceId ?? null;
|
||||
const ipAddress = this.extractIpAddress(req);
|
||||
|
||||
const auditContext: AuditContext = {
|
||||
workspaceId,
|
||||
actorId: null,
|
||||
actorType: 'user',
|
||||
ipAddress,
|
||||
};
|
||||
|
||||
this.cls.set(AUDIT_CONTEXT_KEY, auditContext);
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
private extractIpAddress(req: FastifyRequest['raw']): string | null {
|
||||
const xForwardedFor = req.headers['x-forwarded-for'];
|
||||
if (xForwardedFor) {
|
||||
const ips = Array.isArray(xForwardedFor)
|
||||
? xForwardedFor[0]
|
||||
: xForwardedFor.split(',')[0];
|
||||
return ips?.trim() ?? null;
|
||||
}
|
||||
|
||||
const xRealIp = req.headers['x-real-ip'];
|
||||
if (xRealIp) {
|
||||
return Array.isArray(xRealIp) ? xRealIp[0] : xRealIp;
|
||||
}
|
||||
|
||||
return (req as any).socket?.remoteAddress ?? null;
|
||||
}
|
||||
}
|
||||
@@ -15,13 +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 { AuditContextMiddleware } from '../common/middlewares/audit-context.middleware';
|
||||
import { ShareModule } from './share/share.module';
|
||||
import {
|
||||
AUDIT_SERVICE,
|
||||
NoopAuditService,
|
||||
} from '../integrations/audit/audit.service';
|
||||
import { ClsMiddleware } from 'nestjs-cls';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -37,31 +31,17 @@ import { ClsMiddleware } from 'nestjs-cls';
|
||||
CaslModule,
|
||||
ShareModule,
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: AUDIT_SERVICE,
|
||||
useClass: NoopAuditService,
|
||||
},
|
||||
],
|
||||
exports: [AUDIT_SERVICE],
|
||||
})
|
||||
export class CoreModule implements NestModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
const excludedRoutes = [
|
||||
{ path: 'auth/setup', method: RequestMethod.POST },
|
||||
{ path: 'health', method: RequestMethod.GET },
|
||||
{ path: 'health/live', method: RequestMethod.GET },
|
||||
{ path: 'billing/stripe/webhook', method: RequestMethod.POST },
|
||||
];
|
||||
|
||||
consumer
|
||||
.apply(DomainMiddleware)
|
||||
.exclude(...excludedRoutes)
|
||||
.forRoutes('*');
|
||||
|
||||
consumer
|
||||
.apply(AuditContextMiddleware)
|
||||
.exclude(...excludedRoutes)
|
||||
.exclude(
|
||||
{ path: 'auth/setup', method: RequestMethod.POST },
|
||||
{ path: 'health', method: RequestMethod.GET },
|
||||
{ path: 'health/live', method: RequestMethod.GET },
|
||||
{ path: 'billing/stripe/webhook', method: RequestMethod.POST },
|
||||
)
|
||||
.forRoutes('*');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,8 +69,8 @@ export class ShareService {
|
||||
return await this.shareRepo.insertShare({
|
||||
key: nanoIdGen().toLowerCase(),
|
||||
pageId: page.id,
|
||||
includeSubPages: createShareDto.includeSubPages ?? false,
|
||||
searchIndexing: createShareDto.searchIndexing ?? false,
|
||||
includeSubPages: createShareDto.includeSubPages || true,
|
||||
searchIndexing: createShareDto.searchIndexing || true,
|
||||
creatorId: authUserId,
|
||||
spaceId: page.spaceId,
|
||||
workspaceId,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
Inject,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
@@ -15,11 +14,6 @@ import { RemoveSpaceMemberDto } from '../dto/remove-space-member.dto';
|
||||
import { UpdateSpaceMemberRoleDto } from '../dto/update-space-member-role.dto';
|
||||
import { SpaceRole } from '../../../common/helpers/types/permission';
|
||||
import { PaginationResult } from '@docmost/db/pagination/pagination';
|
||||
import { AuditEvent } from '../../../common/events/audit-events';
|
||||
import {
|
||||
AUDIT_SERVICE,
|
||||
IAuditService,
|
||||
} from '../../../integrations/audit/audit.service';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceMemberService {
|
||||
@@ -27,7 +21,6 @@ export class SpaceMemberService {
|
||||
private spaceMemberRepo: SpaceMemberRepo,
|
||||
private spaceRepo: SpaceRepo,
|
||||
@InjectKysely() private readonly db: KyselyDB,
|
||||
@Inject(AUDIT_SERVICE) private readonly auditService: IAuditService,
|
||||
) {}
|
||||
|
||||
async addUserToSpace(
|
||||
@@ -168,43 +161,8 @@ export class SpaceMemberService {
|
||||
|
||||
if (membersToAdd.length > 0) {
|
||||
await this.spaceMemberRepo.insertSpaceMember(membersToAdd);
|
||||
|
||||
// Audit log for each member added
|
||||
for (const user of validUsers) {
|
||||
this.auditService.log({
|
||||
event: AuditEvent.SPACE_MEMBER_ADDED,
|
||||
resourceType: 'space_members',
|
||||
resourceId: dto.spaceId,
|
||||
changes: {
|
||||
after: { role: dto.role },
|
||||
},
|
||||
metadata: {
|
||||
spaceId: dto.spaceId,
|
||||
spaceName: space.name,
|
||||
userId: user.id,
|
||||
userName: user.name,
|
||||
memberType: 'user',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (const group of validGroups) {
|
||||
this.auditService.log({
|
||||
event: AuditEvent.SPACE_MEMBER_ADDED,
|
||||
resourceType: 'space_members',
|
||||
resourceId: dto.spaceId,
|
||||
changes: {
|
||||
after: { role: dto.role },
|
||||
},
|
||||
metadata: {
|
||||
spaceId: dto.spaceId,
|
||||
spaceName: space.name,
|
||||
groupId: group.id,
|
||||
groupName: group.name,
|
||||
memberType: 'group',
|
||||
},
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// either they are already members or do not exist on the workspace
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,22 +209,6 @@ export class SpaceMemberService {
|
||||
spaceMember.id,
|
||||
dto.spaceId,
|
||||
);
|
||||
|
||||
this.auditService.log({
|
||||
event: AuditEvent.SPACE_MEMBER_REMOVED,
|
||||
resourceType: 'space_member',
|
||||
resourceId: dto.spaceId,
|
||||
changes: {
|
||||
before: { role: spaceMember.role },
|
||||
},
|
||||
metadata: {
|
||||
spaceId: dto.spaceId,
|
||||
spaceName: space.name,
|
||||
userId: spaceMember.userId,
|
||||
groupId: spaceMember.groupId,
|
||||
memberType: spaceMember.userId ? 'user' : 'group',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async updateSpaceMemberRole(
|
||||
@@ -317,23 +259,6 @@ export class SpaceMemberService {
|
||||
spaceMember.id,
|
||||
dto.spaceId,
|
||||
);
|
||||
|
||||
this.auditService.log({
|
||||
event: AuditEvent.SPACE_MEMBER_ROLE_CHANGED,
|
||||
resourceType: 'space_members',
|
||||
resourceId: dto.spaceId,
|
||||
changes: {
|
||||
before: { role: spaceMember.role },
|
||||
after: { role: dto.role },
|
||||
},
|
||||
metadata: {
|
||||
spaceId: dto.spaceId,
|
||||
spaceName: space.name,
|
||||
userId: spaceMember.userId,
|
||||
groupId: spaceMember.groupId,
|
||||
memberType: spaceMember.userId ? 'user' : 'group',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async validateLastAdmin(spaceId: string): Promise<void> {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
Inject,
|
||||
Injectable,
|
||||
Logger,
|
||||
NotFoundException,
|
||||
@@ -34,11 +33,6 @@ import {
|
||||
validateAllowedEmail,
|
||||
validateSsoEnforcement,
|
||||
} from '../../auth/auth.util';
|
||||
import { AuditEvent } from '../../../common/events/audit-events';
|
||||
import {
|
||||
AUDIT_SERVICE,
|
||||
IAuditService,
|
||||
} from '../../../integrations/audit/audit.service';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceInvitationService {
|
||||
@@ -52,7 +46,6 @@ export class WorkspaceInvitationService {
|
||||
@InjectKysely() private readonly db: KyselyDB,
|
||||
@InjectQueue(QueueName.BILLING_QUEUE) private billingQueue: Queue,
|
||||
private readonly environmentService: EnvironmentService,
|
||||
@Inject(AUDIT_SERVICE) private readonly auditService: IAuditService,
|
||||
) {}
|
||||
|
||||
async getInvitations(workspaceId: string, pagination: PaginationOptions) {
|
||||
@@ -186,24 +179,6 @@ export class WorkspaceInvitationService {
|
||||
workspace.hostname,
|
||||
);
|
||||
});
|
||||
|
||||
// Audit log for each invitation created
|
||||
for (const invitation of invites) {
|
||||
this.auditService.log({
|
||||
event: AuditEvent.WORKSPACE_INVITE_CREATED,
|
||||
resourceType: 'workspace_invitation',
|
||||
resourceId: invitation.id,
|
||||
changes: {
|
||||
after: {
|
||||
email: invitation.email,
|
||||
role: invitation.role,
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
groupIds: invitation.groupIds,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,32 +344,11 @@ export class WorkspaceInvitationService {
|
||||
invitationId: string,
|
||||
workspaceId: string,
|
||||
): Promise<void> {
|
||||
const invitation = await this.db
|
||||
.selectFrom('workspaceInvitations')
|
||||
.select(['id', 'email', 'role'])
|
||||
.where('id', '=', invitationId)
|
||||
.where('workspaceId', '=', workspaceId)
|
||||
.executeTakeFirst();
|
||||
|
||||
await this.db
|
||||
.deleteFrom('workspaceInvitations')
|
||||
.where('id', '=', invitationId)
|
||||
.where('workspaceId', '=', workspaceId)
|
||||
.execute();
|
||||
|
||||
if (invitation) {
|
||||
this.auditService.log({
|
||||
event: AuditEvent.WORKSPACE_INVITE_REVOKED,
|
||||
resourceType: 'workspace_invitation',
|
||||
resourceId: invitation.id,
|
||||
changes: {
|
||||
before: {
|
||||
email: invitation.email,
|
||||
role: invitation.role,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async getInvitationLinkById(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
ForbiddenException,
|
||||
Inject,
|
||||
Injectable,
|
||||
Logger,
|
||||
NotFoundException,
|
||||
@@ -35,11 +34,6 @@ import { QueueJob, QueueName } from '../../../integrations/queue/constants';
|
||||
import { Queue } from 'bullmq';
|
||||
import { generateRandomSuffixNumbers } from '../../../common/helpers';
|
||||
import { isPageEmbeddingsTableExists } from '@docmost/db/helpers/helpers';
|
||||
import { AuditEvent } from '../../../common/events/audit-events';
|
||||
import {
|
||||
AUDIT_SERVICE,
|
||||
IAuditService,
|
||||
} from '../../../integrations/audit/audit.service';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceService {
|
||||
@@ -58,7 +52,6 @@ export class WorkspaceService {
|
||||
@InjectQueue(QueueName.ATTACHMENT_QUEUE) private attachmentQueue: Queue,
|
||||
@InjectQueue(QueueName.BILLING_QUEUE) private billingQueue: Queue,
|
||||
@InjectQueue(QueueName.AI_QUEUE) private aiQueue: Queue,
|
||||
@Inject(AUDIT_SERVICE) private readonly auditService: IAuditService,
|
||||
) {}
|
||||
|
||||
async findById(workspaceId: string) {
|
||||
@@ -435,20 +428,6 @@ export class WorkspaceService {
|
||||
user.id,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
this.auditService.log({
|
||||
event: AuditEvent.USER_ROLE_CHANGED,
|
||||
resourceType: 'users',
|
||||
resourceId: user.id,
|
||||
changes: {
|
||||
before: { role: user.role },
|
||||
after: { role: newRole },
|
||||
},
|
||||
metadata: {
|
||||
userName: user.name,
|
||||
userEmail: user.email,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async generateHostname(
|
||||
@@ -552,19 +531,6 @@ export class WorkspaceService {
|
||||
.execute();
|
||||
});
|
||||
|
||||
this.auditService.log({
|
||||
event: AuditEvent.USER_DELETED,
|
||||
resourceType: 'users',
|
||||
resourceId: user.id,
|
||||
changes: {
|
||||
before: {
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
await this.attachmentQueue.add(QueueJob.DELETE_USER_AVATARS, user);
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { Kysely, sql } from 'kysely';
|
||||
|
||||
export async function up(db: Kysely<any>): Promise<void> {
|
||||
await db.schema
|
||||
.createTable('audit_logs')
|
||||
.addColumn('id', 'uuid', (col) =>
|
||||
col.primaryKey().defaultTo(sql`gen_uuid_v7()`),
|
||||
)
|
||||
.addColumn('workspace_id', 'uuid', (col) =>
|
||||
col.notNull().references('workspaces.id').onDelete('cascade'),
|
||||
)
|
||||
.addColumn('actor_id', 'uuid', (col) =>
|
||||
col.references('users.id').onDelete('set null'),
|
||||
)
|
||||
.addColumn('actor_type', 'varchar', (col) =>
|
||||
col.notNull().defaultTo('user'),
|
||||
)
|
||||
.addColumn('event', 'varchar', (col) => col.notNull())
|
||||
.addColumn('resource_type', 'varchar', (col) => col.notNull())
|
||||
.addColumn('resource_id', 'uuid')
|
||||
.addColumn('changes', 'jsonb')
|
||||
.addColumn('metadata', 'jsonb')
|
||||
.addColumn('ip_address', sql `inet`)
|
||||
.addColumn('created_at', 'timestamptz', (col) =>
|
||||
col.notNull().defaultTo(sql`now()`),
|
||||
)
|
||||
.execute();
|
||||
}
|
||||
|
||||
export async function down(db: Kysely<any>): Promise<void> {
|
||||
await db.schema.dropTable('audit_logs').execute();
|
||||
}
|
||||
+15
-28
@@ -3,13 +3,18 @@
|
||||
* Please do not edit it manually.
|
||||
*/
|
||||
|
||||
import type { ColumnType } from "kysely";
|
||||
import type { ColumnType } from 'kysely';
|
||||
|
||||
export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
|
||||
? ColumnType<S, I | undefined, U>
|
||||
: ColumnType<T, T | undefined, T>;
|
||||
export type Generated<T> =
|
||||
T extends ColumnType<infer S, infer I, infer U>
|
||||
? ColumnType<S, I | undefined, U>
|
||||
: ColumnType<T, T | undefined, T>;
|
||||
|
||||
export type Int8 = ColumnType<string, bigint | number | string, bigint | number | string>;
|
||||
export type Int8 = ColumnType<
|
||||
string,
|
||||
bigint | number | string,
|
||||
bigint | number | string
|
||||
>;
|
||||
|
||||
export type Json = JsonValue;
|
||||
|
||||
@@ -27,13 +32,13 @@ export type Timestamp = ColumnType<Date, Date | string, Date | string>;
|
||||
|
||||
export interface ApiKeys {
|
||||
createdAt: Generated<Timestamp>;
|
||||
creatorId: string;
|
||||
deletedAt: Timestamp | null;
|
||||
expiresAt: Timestamp | null;
|
||||
id: Generated<string>;
|
||||
lastUsedAt: Timestamp | null;
|
||||
name: string | null;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
creatorId: string;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
@@ -56,20 +61,6 @@ export interface Attachments {
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export interface AuditLogs {
|
||||
actorId: string | null;
|
||||
actorType: Generated<string>;
|
||||
changes: Json | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
event: string;
|
||||
id: Generated<string>;
|
||||
ipAddress: string | null;
|
||||
metadata: Json | null;
|
||||
resourceId: string | null;
|
||||
resourceType: string;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
export interface AuthAccounts {
|
||||
authProviderId: string | null;
|
||||
createdAt: Generated<Timestamp>;
|
||||
@@ -86,25 +77,25 @@ export interface AuthProviders {
|
||||
createdAt: Generated<Timestamp>;
|
||||
creatorId: string | null;
|
||||
deletedAt: Timestamp | null;
|
||||
groupSync: Generated<boolean>;
|
||||
id: Generated<string>;
|
||||
isEnabled: Generated<boolean>;
|
||||
groupSync: Generated<boolean>;
|
||||
ldapBaseDn: string | null;
|
||||
ldapBindDn: string | null;
|
||||
ldapBindPassword: string | null;
|
||||
ldapConfig: Json | null;
|
||||
ldapTlsCaCert: string | null;
|
||||
ldapTlsEnabled: Generated<boolean | null>;
|
||||
ldapUrl: string | null;
|
||||
ldapUserAttributes: Json | null;
|
||||
ldapUserSearchFilter: string | null;
|
||||
ldapConfig: Json | null;
|
||||
settings: Json | null;
|
||||
name: string;
|
||||
oidcClientId: string | null;
|
||||
oidcClientSecret: string | null;
|
||||
oidcIssuer: string | null;
|
||||
samlCertificate: string | null;
|
||||
samlUrl: string | null;
|
||||
settings: Json | null;
|
||||
type: string;
|
||||
updatedAt: Generated<Timestamp>;
|
||||
workspaceId: string;
|
||||
@@ -234,11 +225,9 @@ export interface Pages {
|
||||
icon: string | null;
|
||||
id: Generated<string>;
|
||||
isLocked: Generated<boolean>;
|
||||
isRestricted: Generated<boolean>;
|
||||
lastUpdatedById: string | null;
|
||||
parentPageId: string | null;
|
||||
position: string | null;
|
||||
restrictedById: string | null;
|
||||
slugId: string;
|
||||
spaceId: string;
|
||||
textContent: string | null;
|
||||
@@ -309,12 +298,12 @@ export interface Users {
|
||||
deletedAt: Timestamp | null;
|
||||
email: string;
|
||||
emailVerifiedAt: Timestamp | null;
|
||||
hasGeneratedPassword: Generated<boolean | null>;
|
||||
id: Generated<string>;
|
||||
invitedById: string | null;
|
||||
lastActiveAt: Timestamp | null;
|
||||
lastLoginAt: Timestamp | null;
|
||||
locale: string | null;
|
||||
hasGeneratedPassword: Generated<boolean | null>;
|
||||
name: string | null;
|
||||
password: string | null;
|
||||
role: string | null;
|
||||
@@ -374,7 +363,6 @@ export interface Workspaces {
|
||||
export interface DB {
|
||||
apiKeys: ApiKeys;
|
||||
attachments: Attachments;
|
||||
auditLogs: AuditLogs;
|
||||
authAccounts: AuthAccounts;
|
||||
authProviders: AuthProviders;
|
||||
backlinks: Backlinks;
|
||||
@@ -384,7 +372,6 @@ export interface DB {
|
||||
groups: Groups;
|
||||
groupUsers: GroupUsers;
|
||||
pageHistory: PageHistory;
|
||||
AuditLog: PagePermissions;
|
||||
pages: Pages;
|
||||
shares: Shares;
|
||||
spaceMembers: SpaceMembers;
|
||||
|
||||
@@ -1,6 +1,47 @@
|
||||
import { DB } from '@docmost/db/types/db';
|
||||
import {
|
||||
ApiKeys,
|
||||
Attachments,
|
||||
AuthAccounts,
|
||||
AuthProviders,
|
||||
Backlinks,
|
||||
Billing,
|
||||
Comments,
|
||||
FileTasks,
|
||||
Groups,
|
||||
GroupUsers,
|
||||
PageHistory,
|
||||
Pages,
|
||||
Shares,
|
||||
SpaceMembers,
|
||||
Spaces,
|
||||
UserMfa,
|
||||
Users,
|
||||
UserTokens,
|
||||
WorkspaceInvitations,
|
||||
Workspaces,
|
||||
} from '@docmost/db/types/db';
|
||||
import { PageEmbeddings } from '@docmost/db/types/embeddings.types';
|
||||
|
||||
export interface DbInterface extends DB {
|
||||
export interface DbInterface {
|
||||
attachments: Attachments;
|
||||
authAccounts: AuthAccounts;
|
||||
authProviders: AuthProviders;
|
||||
backlinks: Backlinks;
|
||||
billing: Billing;
|
||||
comments: Comments;
|
||||
fileTasks: FileTasks;
|
||||
groups: Groups;
|
||||
groupUsers: GroupUsers;
|
||||
pageEmbeddings: PageEmbeddings;
|
||||
pageHistory: PageHistory;
|
||||
pages: Pages;
|
||||
shares: Shares;
|
||||
spaceMembers: SpaceMembers;
|
||||
spaces: Spaces;
|
||||
userMfa: UserMfa;
|
||||
users: Users;
|
||||
userTokens: UserTokens;
|
||||
workspaceInvitations: WorkspaceInvitations;
|
||||
workspaces: Workspaces;
|
||||
apiKeys: ApiKeys;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import {
|
||||
FileTasks,
|
||||
UserMfa as _UserMFA,
|
||||
ApiKeys,
|
||||
AuditLogs,
|
||||
} from './db';
|
||||
import { PageEmbeddings } from '@docmost/db/types/embeddings.types';
|
||||
|
||||
@@ -132,8 +131,3 @@ export type UpdatableApiKey = Updateable<Omit<ApiKeys, 'id'>>;
|
||||
export type PageEmbedding = Selectable<PageEmbeddings>;
|
||||
export type InsertablePageEmbedding = Insertable<PageEmbeddings>;
|
||||
export type UpdatablePageEmbedding = Updateable<Omit<PageEmbeddings, 'id'>>;
|
||||
|
||||
// Audit Log
|
||||
export type AuditLog = Selectable<AuditLogs>;
|
||||
export type InsertableAuditLog = Insertable<AuditLogs>;
|
||||
export type UpdatableAuditLog = Updateable<Omit<AuditLogs, 'id'>>;
|
||||
|
||||
+1
-1
Submodule apps/server/src/ee updated: 741c15eba3...18e00b1866
@@ -1,48 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AuditLogPayload, ActorType } from '../../common/events/audit-events';
|
||||
|
||||
export type IAuditService = {
|
||||
log(payload: AuditLogPayload): void | Promise<void>;
|
||||
logWithContext(
|
||||
payload: AuditLogPayload,
|
||||
context: {
|
||||
workspaceId: string;
|
||||
actorId?: string;
|
||||
actorType?: ActorType;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
},
|
||||
): void | Promise<void>;
|
||||
setActorId(actorId: string): void;
|
||||
setActorType(actorType: ActorType): void;
|
||||
};
|
||||
|
||||
export const AUDIT_SERVICE = Symbol('AUDIT_SERVICE');
|
||||
|
||||
@Injectable()
|
||||
export class NoopAuditService implements IAuditService {
|
||||
log(_payload: AuditLogPayload): void {
|
||||
// No-op: swallow the log when EE module is not available
|
||||
}
|
||||
|
||||
logWithContext(
|
||||
_payload: AuditLogPayload,
|
||||
_context: {
|
||||
workspaceId: string;
|
||||
actorId?: string;
|
||||
actorType?: ActorType;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
},
|
||||
): void {
|
||||
// No-op: swallow the log when EE module is not available
|
||||
}
|
||||
|
||||
setActorId(_actorId: string): void {
|
||||
// No-op
|
||||
}
|
||||
|
||||
setActorType(_actorType: ActorType): void {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,7 @@ export class EnvironmentVariables {
|
||||
|
||||
@IsOptional()
|
||||
@ValidateIf((obj) => obj.AI_EMBEDDING_DIMENSION)
|
||||
@IsIn(['768', '1024', '1536', '2000'])
|
||||
@IsIn(['768', '1024', '1536'])
|
||||
@IsString()
|
||||
AI_EMBEDDING_DIMENSION: string;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ export enum QueueName {
|
||||
FILE_TASK_QUEUE = '{file-task-queue}',
|
||||
SEARCH_QUEUE = '{search-queue}',
|
||||
AI_QUEUE = '{ai-queue}',
|
||||
AUDIT_QUEUE = '{audit-queue}',
|
||||
}
|
||||
|
||||
export enum QueueJob {
|
||||
@@ -59,7 +58,4 @@ export enum QueueJob {
|
||||
|
||||
GENERATE_PAGE_EMBEDDINGS = 'generate-page-embeddings',
|
||||
DELETE_PAGE_EMBEDDINGS = 'delete-page-embeddings',
|
||||
|
||||
AUDIT_LOG = 'audit-log',
|
||||
AUDIT_CLEANUP = 'audit-cleanup',
|
||||
}
|
||||
|
||||
@@ -73,14 +73,6 @@ import { BacklinksProcessor } from './processors/backlinks.processor';
|
||||
attempts: 1,
|
||||
},
|
||||
}),
|
||||
BullModule.registerQueue({
|
||||
name: QueueName.AUDIT_QUEUE,
|
||||
defaultJobOptions: {
|
||||
removeOnComplete: true,
|
||||
removeOnFail: true,
|
||||
attempts: 3,
|
||||
},
|
||||
}),
|
||||
],
|
||||
exports: [BullModule],
|
||||
providers: [BacklinksProcessor],
|
||||
|
||||
@@ -15,12 +15,10 @@ async function bootstrap() {
|
||||
const app = await NestFactory.create<NestFastifyApplication>(
|
||||
AppModule,
|
||||
new FastifyAdapter({
|
||||
ignoreTrailingSlash: true,
|
||||
ignoreDuplicateSlashes: true,
|
||||
maxParamLength: 1000,
|
||||
trustProxy: true,
|
||||
routerOptions: {
|
||||
maxParamLength: 1000,
|
||||
ignoreTrailingSlash: true,
|
||||
ignoreDuplicateSlashes: true,
|
||||
},
|
||||
}),
|
||||
{
|
||||
rawBody: true,
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "docmost",
|
||||
"homepage": "https://docmost.com",
|
||||
"version": "0.24.1",
|
||||
"version": "0.23.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "nx run-many -t build",
|
||||
@@ -38,6 +38,7 @@
|
||||
"@tiptap/extension-heading": "2.27.1",
|
||||
"@tiptap/extension-highlight": "2.27.1",
|
||||
"@tiptap/extension-history": "2.27.1",
|
||||
"@tiptap/extension-horizontal-rule": "2.27.1",
|
||||
"@tiptap/extension-image": "2.27.1",
|
||||
"@tiptap/extension-link": "2.27.1",
|
||||
"@tiptap/extension-list-item": "2.27.1",
|
||||
@@ -100,7 +101,6 @@
|
||||
},
|
||||
"overrides": {
|
||||
"jsdom": "25.0.1",
|
||||
"jsonwebtoken": "9.0.3",
|
||||
"y-prosemirror": "1.3.7"
|
||||
},
|
||||
"neverBuiltDependencies": []
|
||||
|
||||
@@ -23,3 +23,4 @@ export * from "./lib/subpages";
|
||||
export * from "./lib/highlight";
|
||||
export * from "./lib/heading/heading";
|
||||
export * from "./lib/unique-id";
|
||||
export * from "./lib/hr";
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { HorizontalRule as TiptapHorizontalRule } from "@tiptap/extension-horizontal-rule";
|
||||
|
||||
export type HorizontalRuleType = "pageBreak";
|
||||
|
||||
export const HorizontalRule = TiptapHorizontalRule.extend({
|
||||
addAttributes() {
|
||||
return {
|
||||
type: {
|
||||
default: null,
|
||||
parseHTML: (element) => element.getAttribute("data-type"),
|
||||
renderHTML: (attributes) => {
|
||||
if (attributes.type) {
|
||||
return {
|
||||
"data-type": attributes.type,
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -165,7 +165,6 @@ export const Mention = Node.create<MentionOptions>({
|
||||
inline: true,
|
||||
selectable: true,
|
||||
atom: true,
|
||||
draggable: true,
|
||||
|
||||
addAttributes() {
|
||||
return {
|
||||
|
||||
@@ -28,7 +28,7 @@ export const Subpages = Node.create<SubpagesOptions>({
|
||||
|
||||
group: "block",
|
||||
atom: true,
|
||||
draggable: true,
|
||||
draggable: false,
|
||||
|
||||
parseHTML() {
|
||||
return [
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Editor, findParentNode, isTextSelection } from "@tiptap/core";
|
||||
import { Selection, Transaction } from "@tiptap/pm/state";
|
||||
import { CellSelection, TableMap } from "@tiptap/pm/tables";
|
||||
import { Node, ResolvedPos } from "@tiptap/pm/model";
|
||||
import Table from "@tiptap/extension-table";
|
||||
import { sanitizeUrl as braintreeSanitizeUrl } from "@braintree/sanitize-url";
|
||||
import { customAlphabet } from "nanoid";
|
||||
|
||||
@@ -288,7 +289,7 @@ export const isColumnGripSelected = ({
|
||||
const node = nodeDOM || domAtPos;
|
||||
|
||||
if (
|
||||
!editor.isActive("table") ||
|
||||
!editor.isActive(Table.name) ||
|
||||
!node ||
|
||||
isTableSelected(state.selection)
|
||||
) {
|
||||
|
||||
Generated
+18
-35
@@ -6,7 +6,6 @@ settings:
|
||||
|
||||
overrides:
|
||||
jsdom: 25.0.1
|
||||
jsonwebtoken: 9.0.3
|
||||
y-prosemirror: 1.3.7
|
||||
|
||||
patchedDependencies:
|
||||
@@ -78,6 +77,9 @@ importers:
|
||||
'@tiptap/extension-history':
|
||||
specifier: 2.27.1
|
||||
version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-horizontal-rule':
|
||||
specifier: 2.27.1
|
||||
version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
|
||||
'@tiptap/extension-image':
|
||||
specifier: 2.27.1
|
||||
version: 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
|
||||
@@ -558,8 +560,8 @@ importers:
|
||||
specifier: ^5.4.1
|
||||
version: 5.4.1
|
||||
jsonwebtoken:
|
||||
specifier: 9.0.3
|
||||
version: 9.0.3
|
||||
specifier: ^9.0.2
|
||||
version: 9.0.2
|
||||
kysely:
|
||||
specifier: ^0.28.2
|
||||
version: 0.28.2
|
||||
@@ -578,9 +580,6 @@ importers:
|
||||
nanoid:
|
||||
specifier: 3.3.11
|
||||
version: 3.3.11
|
||||
nestjs-cls:
|
||||
specifier: ^4.5.0
|
||||
version: 4.5.0(@nestjs/common@11.1.9(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.9)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
nestjs-kysely:
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0(@nestjs/common@11.1.9(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.9)(kysely@0.28.2)(reflect-metadata@0.2.2)
|
||||
@@ -7408,8 +7407,8 @@ packages:
|
||||
jsonfile@6.1.0:
|
||||
resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
|
||||
|
||||
jsonwebtoken@9.0.3:
|
||||
resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==}
|
||||
jsonwebtoken@9.0.2:
|
||||
resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
|
||||
engines: {node: '>=12', npm: '>=6'}
|
||||
|
||||
jsx-ast-utils@3.3.5:
|
||||
@@ -7419,11 +7418,11 @@ packages:
|
||||
jszip@3.10.1:
|
||||
resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
|
||||
|
||||
jwa@2.0.1:
|
||||
resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==}
|
||||
jwa@1.4.1:
|
||||
resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==}
|
||||
|
||||
jws@4.0.1:
|
||||
resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==}
|
||||
jws@3.2.2:
|
||||
resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
|
||||
|
||||
jwt-decode@4.0.0:
|
||||
resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==}
|
||||
@@ -7985,15 +7984,6 @@ packages:
|
||||
neo-async@2.6.2:
|
||||
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
||||
|
||||
nestjs-cls@4.5.0:
|
||||
resolution: {integrity: sha512-oi3GNCc5pnsnVI5WJKMDwmg4NP+JyEw+edlwgepyUba5+RGGtJzpbVaaxXGW1iPbDuQde3/fA8Jdjq9j88BVcQ==}
|
||||
engines: {node: '>=16'}
|
||||
peerDependencies:
|
||||
'@nestjs/common': '> 7.0.0 < 11'
|
||||
'@nestjs/core': '> 7.0.0 < 11'
|
||||
reflect-metadata: '*'
|
||||
rxjs: '>= 7'
|
||||
|
||||
nestjs-kysely@1.2.0:
|
||||
resolution: {integrity: sha512-KseCGb0SXCzIYC+Hx3Z3d+kPAfSZCSK6j9UoqUV/gcBCPad9utC7itmoUw0/w5sV+Jf9pc1DKpgClP1IkflA4w==}
|
||||
peerDependencies:
|
||||
@@ -13426,7 +13416,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@nestjs/common': 11.1.9(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
'@types/jsonwebtoken': 9.0.7
|
||||
jsonwebtoken: 9.0.3
|
||||
jsonwebtoken: 9.0.2
|
||||
|
||||
'@nestjs/mapped-types@2.1.0(@nestjs/common@11.1.9(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)':
|
||||
dependencies:
|
||||
@@ -18483,9 +18473,9 @@ snapshots:
|
||||
optionalDependencies:
|
||||
graceful-fs: 4.2.11
|
||||
|
||||
jsonwebtoken@9.0.3:
|
||||
jsonwebtoken@9.0.2:
|
||||
dependencies:
|
||||
jws: 4.0.1
|
||||
jws: 3.2.2
|
||||
lodash.includes: 4.3.0
|
||||
lodash.isboolean: 3.0.3
|
||||
lodash.isinteger: 4.0.4
|
||||
@@ -18510,15 +18500,15 @@ snapshots:
|
||||
readable-stream: 2.3.8
|
||||
setimmediate: 1.0.5
|
||||
|
||||
jwa@2.0.1:
|
||||
jwa@1.4.1:
|
||||
dependencies:
|
||||
buffer-equal-constant-time: 1.0.1
|
||||
ecdsa-sig-formatter: 1.0.11
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
jws@4.0.1:
|
||||
jws@3.2.2:
|
||||
dependencies:
|
||||
jwa: 2.0.1
|
||||
jwa: 1.4.1
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
jwt-decode@4.0.0: {}
|
||||
@@ -19143,13 +19133,6 @@ snapshots:
|
||||
|
||||
neo-async@2.6.2: {}
|
||||
|
||||
nestjs-cls@4.5.0(@nestjs/common@11.1.9(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.9)(reflect-metadata@0.2.2)(rxjs@7.8.2):
|
||||
dependencies:
|
||||
'@nestjs/common': 11.1.9(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
'@nestjs/core': 11.1.9(@nestjs/common@11.1.9(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.9)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
reflect-metadata: 0.2.2
|
||||
rxjs: 7.8.2
|
||||
|
||||
nestjs-kysely@1.2.0(@nestjs/common@11.1.9(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.9)(kysely@0.28.2)(reflect-metadata@0.2.2):
|
||||
dependencies:
|
||||
'@nestjs/common': 11.1.9(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
@@ -19498,7 +19481,7 @@ snapshots:
|
||||
|
||||
passport-jwt@4.0.1:
|
||||
dependencies:
|
||||
jsonwebtoken: 9.0.3
|
||||
jsonwebtoken: 9.0.2
|
||||
passport-strategy: 1.0.0
|
||||
|
||||
passport-oauth2@1.8.0:
|
||||
|
||||
Reference in New Issue
Block a user