Compare commits

..

25 Commits

Author SHA1 Message Date
Philipinho a2ae341934 v0.2.5 2024-07-12 18:05:59 +01:00
Philipinho 3c70e40d16 add table header by default 2024-07-12 16:53:33 +01:00
Philipinho 14197d7365 add cookie duration 2024-07-12 14:52:09 +01:00
Philip Okugbe f388540293 feat: Individual page export in Markdown and HTML formats (#80)
* fix maths node

* render default html width

* Add page export module
* with support for html and markdown exports

* Page export UI
* Add PDF print too

* remove unused import
2024-07-12 14:45:09 +01:00
Philipinho b43de81013 cleanup 2024-07-07 16:36:14 +01:00
Philipinho 6659adc7fe v0.2.4 2024-07-07 16:31:28 +01:00
Philip Okugbe 24adff9679 Merge pull request #74 from docmost/remove-redundant-page-slug_id-index
remove redundant page slug_id index
2024-07-07 16:29:21 +01:00
Philipinho e960b8c1a9 create migration 2024-07-07 16:27:43 +01:00
Philipinho 1958067110 Revert "remove redundant slug_id index"
This reverts commit 3e519ebcd8.
2024-07-07 16:16:13 +01:00
Philipinho 3e519ebcd8 remove redundant slug_id index 2024-07-07 16:07:43 +01:00
Philip Okugbe 07cd650205 Merge pull request #73 from docmost/fix/case-insensitive-email
make emails case-insensitive
2024-07-07 15:51:14 +01:00
Philipinho 949d782a28 make emails case-insensitive 2024-07-07 15:49:43 +01:00
Philipinho 295d4325bf update tiptap hocuspocus 2024-07-07 15:36:36 +01:00
Philip Okugbe 40a40bb3c7 Merge pull request #71 from docmost/aws_env_option
Add support for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables
2024-07-07 09:49:31 +01:00
Philipinho bc1579b022 fix condition check 2024-07-07 09:48:43 +01:00
Philip Okugbe 85b3073681 Merge pull request #57 from will2hew/will/url-setup
CORS setup and Vite devServer proxy
2024-07-07 09:42:51 +01:00
Philipinho 4af3a54649 Allow AWS SDK use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY 2024-07-07 09:24:19 +01:00
Philip Okugbe c4c169b17a Merge pull request #64 from docmost/feat/health
Add health check
2024-07-06 01:06:17 +01:00
Philipinho a0536d852f cleanup indicators 2024-07-05 23:05:19 +01:00
Philipinho f12f93b373 increase startup db retry limit 2024-07-05 19:00:55 +01:00
Philipinho 35dcd5f254 refactor health module 2024-07-05 18:59:26 +01:00
Philipinho 9496ec9b57 prevent database error from crashing server 2024-07-05 18:59:16 +01:00
Will H 5ace7616d0 cors setup and dev server proxy 2024-07-05 16:25:00 +12:00
Will H ce6a05ab66 cr - add redis check and logging 2024-07-05 13:40:51 +12:00
Will H 66773dfaca Add health check and dev script 2024-07-05 10:10:08 +12:00
48 changed files with 1132 additions and 148 deletions
+2 -1
View File
@@ -1,7 +1,7 @@
{
"name": "client",
"private": true,
"version": "0.2.3",
"version": "0.2.5",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
@@ -26,6 +26,7 @@
"clsx": "^2.1.1",
"date-fns": "^3.6.0",
"emoji-mart": "^5.6.0",
"file-saver": "^2.0.5",
"jotai": "^2.8.3",
"jotai-optics": "^0.4.0",
"js-cookie": "^3.0.5",
@@ -1,14 +1,17 @@
import Cookies from "js-cookie";
import { createJSONStorage, atomWithStorage } from "jotai/utils";
import { ITokens } from '../types/auth.types';
import { ITokens } from "../types/auth.types";
const cookieStorage = createJSONStorage<ITokens>(() => {
return {
getItem: () => Cookies.get("authTokens"),
setItem: (key, value) => Cookies.set(key, value),
setItem: (key, value) => Cookies.set(key, value, { expires: 30 }),
removeItem: (key) => Cookies.remove(key),
};
});
export const authTokensAtom = atomWithStorage<ITokens | null>("authTokens", null, cookieStorage);
export const authTokensAtom = atomWithStorage<ITokens | null>(
"authTokens",
null,
cookieStorage,
);
@@ -4,11 +4,7 @@ import { useNavigate } from "react-router-dom";
import { useAtom } from "jotai";
import { authTokensAtom } from "@/features/auth/atoms/auth-tokens-atom";
import { currentUserAtom } from "@/features/user/atoms/current-user-atom";
import {
ILogin,
IRegister,
ISetupWorkspace,
} from "@/features/auth/types/auth.types";
import { ILogin, ISetupWorkspace } from "@/features/auth/types/auth.types";
import { notifications } from "@mantine/notifications";
import { IAcceptInvite } from "@/features/workspace/types/workspace.types.ts";
import { acceptInvitation } from "@/features/workspace/services/workspace-service.ts";
@@ -49,7 +45,6 @@ export default function useAuth() {
const res = await acceptInvitation(data);
setIsLoading(false);
console.log(res);
setAuthToken(res.tokens);
navigate(APP_ROUTE.HOME);
@@ -184,7 +184,7 @@ const CommandGroups: SlashMenuGroupedItemsType = {
.chain()
.focus()
.deleteRange(range)
.insertTable({ rows: 3, cols: 3, withHeaderRow: false })
.insertTable({ rows: 3, cols: 3, withHeaderRow: true })
.run(),
},
{
@@ -3,7 +3,7 @@ import React from "react";
import { TitleEditor } from "@/features/editor/title-editor";
import PageEditor from "@/features/editor/page-editor";
import { Container } from "@mantine/core";
import { useAtom } from "jotai/index";
import { useAtom } from "jotai";
import { userAtom } from "@/features/user/atoms/current-user-atom.ts";
const MemoizedTitleEditor = React.memo(TitleEditor);
@@ -163,3 +163,4 @@
.actionIconGroup {
background: var(--mantine-color-body);
}
@@ -2,5 +2,10 @@
height: 100%;
padding: 8px 20px;
margin: 64px auto;
@media print {
padding: 0;
margin: 0;
}
}
@@ -8,5 +8,7 @@
@import "./youtube.css";
@import "./media.css";
@import "./code.css";
@import "./print.css";
@@ -4,6 +4,10 @@
color: #adb5bd;
pointer-events: none;
height: 0;
@media print {
display: none;
}
}
.ProseMirror .is-empty::before {
@@ -12,9 +16,17 @@
color: #adb5bd;
pointer-events: none;
height: 0;
@media print {
display: none;
}
}
.ProseMirror table .is-editor-empty:first-child::before,
.ProseMirror table .is-empty::before {
content: '';
@media print {
display: none;
}
}
@@ -0,0 +1,11 @@
@media print {
.mantine-AppShell-header,
.mantine-AppShell-navbar,
.mantine-AppShell-aside{
display: none !important;
}
.mantine-AppShell-main {
padding-top: 0 !important;
}
}
@@ -17,5 +17,9 @@
&.ProseMirror-selectednode {
background-color: transparent;
}
@media print {
display: none;
}
}
}
@@ -2,16 +2,18 @@ import { ActionIcon, Group, Menu, Tooltip } from "@mantine/core";
import {
IconArrowsHorizontal,
IconDots,
IconDownload,
IconHistory,
IconLink,
IconMessage,
IconPrinter,
IconTrash,
} from "@tabler/icons-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";
import { useClipboard } from "@mantine/hooks";
import { useClipboard, useDisclosure } from "@mantine/hooks";
import { useParams } from "react-router-dom";
import { usePageQuery } from "@/features/page/queries/page-query.ts";
import { buildPageUrl } from "@/features/page/page.utils.ts";
@@ -21,6 +23,7 @@ import { extractPageSlugId } from "@/lib";
import { treeApiAtom } from "@/features/page/tree/atoms/tree-api-atom.ts";
import { useDeletePageModal } from "@/features/page/hooks/use-delete-page-modal.tsx";
import { PageWidthToggle } from "@/features/user/components/page-width-pref.tsx";
import PageExportModal from "@/features/page/components/page-export-modal.tsx";
interface PageHeaderMenuProps {
readOnly?: boolean;
@@ -57,6 +60,8 @@ function PageActionMenu({ readOnly }: PageActionMenuProps) {
});
const { openDeleteModal } = useDeletePageModal();
const [tree] = useAtom(treeApiAtom);
const [opened, { open: openExportModal, close: closeExportModal }] =
useDisclosure(false);
const handleCopyLink = () => {
const pageUrl =
@@ -66,6 +71,12 @@ function PageActionMenu({ readOnly }: PageActionMenuProps) {
notifications.show({ message: "Link copied" });
};
const handlePrint = () => {
setTimeout(() => {
window.print();
}, 250);
};
const openHistoryModal = () => {
setHistoryModalOpen(true);
};
@@ -75,55 +86,79 @@ function PageActionMenu({ readOnly }: PageActionMenuProps) {
};
return (
<Menu
shadow="xl"
position="bottom-end"
offset={20}
width={200}
withArrow
arrowPosition="center"
>
<Menu.Target>
<ActionIcon variant="default" style={{ border: "none" }}>
<IconDots size={20} stroke={2} />
</ActionIcon>
</Menu.Target>
<>
<Menu
shadow="xl"
position="bottom-end"
offset={20}
width={200}
withArrow
arrowPosition="center"
>
<Menu.Target>
<ActionIcon variant="default" style={{ border: "none" }}>
<IconDots size={20} />
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item
leftSection={<IconLink size={16} stroke={2} />}
onClick={handleCopyLink}
>
Copy link
</Menu.Item>
<Menu.Divider />
<Menu.Dropdown>
<Menu.Item
leftSection={<IconLink size={16} />}
onClick={handleCopyLink}
>
Copy link
</Menu.Item>
<Menu.Divider />
<Menu.Item leftSection={<IconArrowsHorizontal size={16} stroke={2} />}>
<Group wrap="nowrap">
<PageWidthToggle label="Full width" />
</Group>
</Menu.Item>
<Menu.Item leftSection={<IconArrowsHorizontal size={16} />}>
<Group wrap="nowrap">
<PageWidthToggle label="Full width" />
</Group>
</Menu.Item>
<Menu.Item
leftSection={<IconHistory size={16} stroke={2} />}
onClick={openHistoryModal}
>
Page history
</Menu.Item>
<Menu.Item
leftSection={<IconHistory size={16} />}
onClick={openHistoryModal}
>
Page history
</Menu.Item>
{!readOnly && (
<>
<Menu.Divider />
<Menu.Item
color={"red"}
leftSection={<IconTrash size={16} stroke={2} />}
onClick={handleDeletePage}
>
Delete
</Menu.Item>
</>
)}
</Menu.Dropdown>
</Menu>
<Menu.Divider />
<Menu.Item
leftSection={<IconDownload size={16} />}
onClick={openExportModal}
>
Export
</Menu.Item>
<Menu.Item
leftSection={<IconPrinter size={16} />}
onClick={handlePrint}
>
Print PDF
</Menu.Item>
{!readOnly && (
<>
<Menu.Divider />
<Menu.Item
color={"red"}
leftSection={<IconTrash size={16} />}
onClick={handleDeletePage}
>
Delete
</Menu.Item>
</>
)}
</Menu.Dropdown>
</Menu>
<PageExportModal
pageId={page.id}
open={opened}
onClose={closeExportModal}
/>
</>
);
}
@@ -8,4 +8,8 @@
top: var(--app-shell-header-offset, 0rem);
inset-inline-start: var(--app-shell-navbar-offset, 0rem);
inset-inline-end: var(--app-shell-aside-offset, 0rem);
@media print {
display: none;
}
}
@@ -0,0 +1,84 @@
import { Modal, Button, Group, Text, Select } from "@mantine/core";
import { exportPage } from "@/features/page/services/page-service.ts";
import { useState } from "react";
import * as React from "react";
import { ExportFormat } from "@/features/page/types/page.types.ts";
import { notifications } from "@mantine/notifications";
interface PageExportModalProps {
pageId: string;
open: boolean;
onClose: () => void;
}
export default function PageExportModal({
pageId,
open,
onClose,
}: PageExportModalProps) {
const [format, setFormat] = useState<ExportFormat>(ExportFormat.Markdown);
const handleExport = async () => {
try {
await exportPage({ pageId: pageId, format });
onClose();
} catch (err) {
notifications.show({
message: "Export failed:" + err.response?.data.message,
color: "red",
});
console.error("export error", err);
}
};
const handleChange = (format: ExportFormat) => {
setFormat(format);
};
return (
<>
<Modal
opened={open}
onClose={onClose}
size="350"
centered
withCloseButton={false}
>
<Group justify="space-between" wrap="nowrap">
<div>
<Text size="md">Export format</Text>
</div>
<ExportFormatSelection onChange={handleChange} />
</Group>
<Group justify="flex-start" mt="md">
<Button onClick={onClose} variant="default">
Cancel
</Button>
<Button onClick={handleExport}>Export</Button>
</Group>
</Modal>
</>
);
}
interface ExportFormatSelection {
onChange: (value: string) => void;
}
function ExportFormatSelection({ onChange }: ExportFormatSelection) {
return (
<Select
data={[
{ value: "markdown", label: "Markdown" },
{ value: "html", label: "HTML" },
]}
defaultValue={ExportFormat.Markdown}
onChange={onChange}
styles={{ wrapper: { maxWidth: 120 } }}
comboboxProps={{ width: "120" }}
allowDeselect={false}
withCheckIcon={false}
aria-label="Select export format"
/>
);
}
@@ -1,11 +1,13 @@
import api from "@/lib/api-client";
import {
IExportPageParams,
IMovePage,
IPage,
IPageInput,
SidebarPagesParams,
} from "@/features/page/types/page.types";
import { IAttachment, IPagination } from "@/lib/types.ts";
import { saveAs } from "file-saver";
export async function createPage(data: Partial<IPage>): Promise<IPage> {
const req = await api.post<IPage>("/pages/create", data);
@@ -53,18 +55,28 @@ export async function getRecentChanges(
return req.data;
}
export async function exportPage(data: IExportPageParams): Promise<void> {
const req = await api.post("/pages/export", data, {
responseType: "blob",
});
const fileName = req?.headers["content-disposition"]
.split("filename=")[1]
.replace(/"/g, "");
saveAs(req.data, fileName);
}
export async function uploadFile(file: File, pageId: string) {
const formData = new FormData();
formData.append("pageId", pageId);
formData.append("file", file);
// should be file endpoint
const req = await api.post<IAttachment>("/files/upload", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
// console.log("req", req);
return req;
}
@@ -44,3 +44,13 @@ export interface IPageInput {
coverPhoto: string;
position: string;
}
export interface IExportPageParams {
pageId: string;
format: ExportFormat;
}
export enum ExportFormat {
HTML = "html",
Markdown = "markdown",
}
@@ -95,9 +95,11 @@ function ChangePasswordForm({ onClose }: ChangePasswordFormProps) {
{...form.getInputProps("newPassword")}
/>
<Button type="submit" disabled={isLoading} loading={isLoading}>
Change password
</Button>
<Group justify="flex-end" mt="md">
<Button type="submit" disabled={isLoading} loading={isLoading}>
Change password
</Button>
</Group>
</form>
);
}
+6 -2
View File
@@ -1,10 +1,9 @@
import axios, { AxiosInstance } from "axios";
import Cookies from "js-cookie";
import Routes from "@/lib/app-route.ts";
import { getBackendUrl } from "@/lib/config.ts";
const api: AxiosInstance = axios.create({
baseURL: getBackendUrl(),
baseURL: "/api",
withCredentials: true,
});
@@ -32,6 +31,11 @@ api.interceptors.request.use(
api.interceptors.response.use(
(response) => {
// we need the response headers
if (response.request.responseURL.includes("/api/pages/export")) {
return response;
}
return response.data;
},
(error) => {
+4
View File
@@ -22,6 +22,10 @@ export interface IRoleData {
description: string;
}
export interface ApiResponse<T> {
data: T;
}
export type IPaginationMeta = {
limit: number;
page: number;
+8
View File
@@ -19,5 +19,13 @@ export default defineConfig(({ mode }) => {
"@": "/src",
},
},
server: {
proxy: {
"/api": {
target: APP_URL,
changeOrigin: true,
},
},
},
};
});
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "server",
"version": "0.2.3",
"version": "0.2.5",
"description": "",
"author": "",
"private": true,
@@ -44,6 +44,7 @@
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-fastify": "^10.3.9",
"@nestjs/platform-socket.io": "^10.3.9",
"@nestjs/terminus": "^10.2.3",
"@nestjs/websockets": "^10.3.9",
"@react-email/components": "0.0.19",
"@react-email/render": "^0.0.15",
+4
View File
@@ -11,6 +11,8 @@ import { MailModule } from './integrations/mail/mail.module';
import { QueueModule } from './integrations/queue/queue.module';
import { StaticModule } from './integrations/static/static.module';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { HealthModule } from './integrations/health/health.module';
import { ExportModule } from './integrations/export/export.module';
@Module({
imports: [
@@ -21,6 +23,8 @@ import { EventEmitterModule } from '@nestjs/event-emitter';
WsModule,
QueueModule,
StaticModule,
HealthModule,
ExportModule,
StorageModule.forRootAsync({
imports: [EnvironmentModule],
}),
@@ -60,7 +60,7 @@ export const tiptapExtensions = [
Callout,
] as any;
export function jsonToHtml(tiptapJson: JSONContent) {
export function jsonToHtml(tiptapJson: any) {
return generateHTML(tiptapJson, tiptapExtensions);
}
@@ -16,7 +16,15 @@ export class TransformHttpResponseInterceptor<T>
intercept(
context: ExecutionContext,
next: CallHandler<T>,
): Observable<Response<T>> {
): Observable<Response<T> | any> {
const request = context.switchToHttp().getRequest();
const path = request.url;
// Skip interceptor for the /api/health path
if (path === '/api/health') {
return next.handle();
}
return next.handle().pipe(
map((data) => {
const status = context.switchToHttp().getResponse().statusCode;
+4 -1
View File
@@ -34,7 +34,10 @@ export class CoreModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(DomainMiddleware)
.exclude({ path: 'auth/setup', method: RequestMethod.POST })
.exclude(
{ path: 'auth/setup', method: RequestMethod.POST },
{ path: 'health', method: RequestMethod.GET },
)
.forRoutes('*');
}
}
+3 -1
View File
@@ -36,6 +36,8 @@ types.setTypeParser(types.builtins.INT8, (val) => Number(val));
dialect: new PostgresDialect({
pool: new Pool({
connectionString: environmentService.getDatabaseURL(),
}).on('error', (err) => {
console.error('Database error:', err.message);
}),
}),
plugins: [new CamelCasePlugin()],
@@ -102,7 +104,7 @@ export class DatabaseModule implements OnModuleDestroy, OnApplicationBootstrap {
}
async establishConnection() {
const retryAttempts = 10;
const retryAttempts = 15;
const retryDelay = 3000;
this.logger.log('Establishing database connection');
@@ -0,0 +1,7 @@
import { type Kysely } from 'kysely';
export async function up(db: Kysely<any>): Promise<void> {
await db.schema.dropIndex('pages_slug_id_idx').ifExists().execute();
}
export async function down(db: Kysely<any>): Promise<void> {}
@@ -6,15 +6,11 @@ import { hashPassword } from '../../../common/helpers';
import { dbOrTx } from '@docmost/db/utils';
import {
InsertableUser,
Space,
UpdatableUser,
User,
} from '@docmost/db/types/entity.types';
import { PaginationOptions } from '../../pagination/pagination-options';
import {
executeWithPagination,
PaginationResult,
} from '@docmost/db/pagination/pagination';
import { executeWithPagination } from '@docmost/db/pagination/pagination';
import { sql } from 'kysely';
@Injectable()
@@ -66,7 +62,7 @@ export class UserRepo {
.selectFrom('users')
.select(this.baseFields)
.$if(includePassword, (qb) => qb.select('password'))
.where('email', '=', email)
.where(sql`LOWER(email)`, '=', sql`LOWER(${email})`)
.where('workspaceId', '=', workspaceId)
.executeTakeFirst();
}
@@ -0,0 +1,26 @@
import {
IsBoolean,
IsIn,
IsNotEmpty,
IsOptional,
IsString,
} from 'class-validator';
export enum ExportFormat {
HTML = 'html',
Markdown = 'markdown',
}
export class ExportPageDto {
@IsString()
@IsNotEmpty()
pageId: string;
@IsString()
@IsIn(['html', 'markdown'])
format: ExportFormat;
@IsOptional()
@IsBoolean()
includeFiles?: boolean;
}
@@ -0,0 +1,69 @@
import {
Body,
Controller,
ForbiddenException,
HttpCode,
HttpStatus,
NotFoundException,
Post,
Res,
UseGuards,
} from '@nestjs/common';
import { ExportService } from './export.service';
import { ExportPageDto } from './dto/export-dto';
import { AuthUser } from '../../common/decorators/auth-user.decorator';
import { User } from '@docmost/db/types/entity.types';
import SpaceAbilityFactory from '../../core/casl/abilities/space-ability.factory';
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
import { PageRepo } from '@docmost/db/repos/page/page.repo';
import {
SpaceCaslAction,
SpaceCaslSubject,
} from '../../core/casl/interfaces/space-ability.type';
import { FastifyReply } from 'fastify';
import { sanitize } from 'sanitize-filename-ts';
import { getExportExtension } from './utils';
import { getMimeType } from '../../common/helpers';
@Controller()
export class ImportController {
constructor(
private readonly importService: ExportService,
private readonly pageRepo: PageRepo,
private readonly spaceAbility: SpaceAbilityFactory,
) {}
@UseGuards(JwtAuthGuard)
@HttpCode(HttpStatus.OK)
@Post('pages/export')
async exportPage(
@Body() dto: ExportPageDto,
@AuthUser() user: User,
@Res() res: FastifyReply,
) {
const page = await this.pageRepo.findById(dto.pageId, {
includeContent: true,
});
if (!page) {
throw new NotFoundException('Page not found');
}
const ability = await this.spaceAbility.createForUser(user, page.spaceId);
if (ability.cannot(SpaceCaslAction.Read, SpaceCaslSubject.Page)) {
throw new ForbiddenException();
}
const rawContent = await this.importService.exportPage(dto.format, page);
const fileExt = getExportExtension(dto.format);
const fileName = sanitize(page.title || 'Untitled') + fileExt;
res.headers({
'Content-Type': getMimeType(fileExt),
'Content-Disposition': 'attachment; filename="' + fileName + '"',
});
res.send(rawContent);
}
}
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { ExportService } from './export.service';
import { ImportController } from './export.controller';
@Module({
providers: [ExportService],
controllers: [ImportController],
})
export class ExportModule {}
@@ -0,0 +1,34 @@
import { Injectable } from '@nestjs/common';
import { jsonToHtml } from '../../collaboration/collaboration.util';
import { turndown } from './turndown-utils';
import { ExportFormat } from './dto/export-dto';
import { Page } from '@docmost/db/types/entity.types';
@Injectable()
export class ExportService {
async exportPage(format: string, page: Page) {
const titleNode = {
type: 'heading',
attrs: { level: 1 },
content: [{ type: 'text', text: page.title }],
};
let prosemirrorJson: any = page.content || { type: 'doc', content: [] };
if (page.title) {
prosemirrorJson.content.unshift(titleNode);
}
const pageHtml = jsonToHtml(prosemirrorJson);
if (format === ExportFormat.HTML) {
return `<!DOCTYPE html><html><head><title>${page.title}</title></head><body>${pageHtml}</body></html>`;
}
if (format === ExportFormat.Markdown) {
return turndown(pageHtml);
}
return;
}
}
@@ -0,0 +1,100 @@
import * as TurndownService from '@joplin/turndown';
import * as TurndownPluginGfm from '@joplin/turndown-plugin-gfm';
export function turndown(html: string): string {
const turndownService = new TurndownService({
headingStyle: 'atx',
codeBlockStyle: 'fenced',
hr: '---',
bulletListMarker: '-',
});
const tables = TurndownPluginGfm.tables;
const strikethrough = TurndownPluginGfm.strikethrough;
const highlightedCodeBlock = TurndownPluginGfm.highlightedCodeBlock;
turndownService.use([
tables,
strikethrough,
highlightedCodeBlock,
taskList,
callout,
toggleListTitle,
toggleListBody,
listParagraph,
]);
return turndownService.turndown(html).replaceAll('<br>', ' ');
}
function listParagraph(turndownService: TurndownService) {
turndownService.addRule('paragraph', {
filter: ['p'],
replacement: (content: any, node: HTMLInputElement) => {
if (node.parentElement?.nodeName === 'LI') {
return content;
}
return `\n\n${content}\n\n`;
},
});
}
function callout(turndownService: TurndownService) {
turndownService.addRule('callout', {
filter: function (node: HTMLInputElement) {
return (
node.nodeName === 'DIV' && node.getAttribute('data-type') === 'callout'
);
},
replacement: function (content: any, node: HTMLInputElement) {
const calloutType = node.getAttribute('data-callout-type');
return `\n\n:::${calloutType}\n${content.trim()}\n:::\n\n`;
},
});
}
function taskList(turndownService: TurndownService) {
turndownService.addRule('taskListItem', {
filter: function (node: HTMLInputElement) {
return (
node.getAttribute('data-type') === 'taskItem' &&
node.parentNode.nodeName === 'UL'
);
},
replacement: function (content: any, node: HTMLInputElement) {
const checkbox = node.querySelector(
'input[type="checkbox"]',
) as HTMLInputElement;
const isChecked = checkbox.checked;
return `- ${isChecked ? '[x]' : '[ ]'} ${content.trim()} \n`;
},
});
}
function toggleListTitle(turndownService: TurndownService) {
turndownService.addRule('toggleListTitle', {
filter: function (node: HTMLInputElement) {
return (
node.nodeName === 'SUMMARY' && node.parentNode.nodeName === 'DETAILS'
);
},
replacement: function (content: any, node: HTMLInputElement) {
return '- ' + content;
},
});
}
function toggleListBody(turndownService: TurndownService) {
turndownService.addRule('toggleListContent', {
filter: function (node: HTMLInputElement) {
return (
node.getAttribute('data-type') === 'detailsContent' &&
node.parentNode.nodeName === 'DETAILS'
);
},
replacement: function (content: any, node: HTMLInputElement) {
return ` ${content.replace(/\n/g, '\n ')} `;
},
});
}
@@ -0,0 +1,12 @@
import { ExportFormat } from './dto/export-dto';
export function getExportExtension(format: string) {
if (format === ExportFormat.HTML) {
return '.html';
}
if (format === ExportFormat.Markdown) {
return '.md';
}
return;
}
@@ -0,0 +1,22 @@
import { Controller, Get } from '@nestjs/common';
import { HealthCheck, HealthCheckService } from '@nestjs/terminus';
import { PostgresHealthIndicator } from './postgres.health';
import { RedisHealthIndicator } from './redis.health';
@Controller('health')
export class HealthController {
constructor(
private health: HealthCheckService,
private postgres: PostgresHealthIndicator,
private redis: RedisHealthIndicator,
) {}
@Get()
@HealthCheck()
async check() {
return this.health.check([
() => this.postgres.pingCheck('database'),
() => this.redis.pingCheck('redis'),
]);
}
}
@@ -0,0 +1,13 @@
import { Global, Module } from '@nestjs/common';
import { HealthController } from './health.controller';
import { TerminusModule } from '@nestjs/terminus';
import { PostgresHealthIndicator } from './postgres.health';
import { RedisHealthIndicator } from './redis.health';
@Global()
@Module({
controllers: [HealthController],
providers: [PostgresHealthIndicator, RedisHealthIndicator],
imports: [TerminusModule],
})
export class HealthModule {}
@@ -0,0 +1,31 @@
import { InjectKysely } from 'nestjs-kysely';
import {
HealthCheckError,
HealthIndicator,
HealthIndicatorResult,
} from '@nestjs/terminus';
import { Injectable, Logger } from '@nestjs/common';
import { sql } from 'kysely';
import { KyselyDB } from '@docmost/db/types/kysely.types';
@Injectable()
export class PostgresHealthIndicator extends HealthIndicator {
private readonly logger = new Logger(PostgresHealthIndicator.name);
constructor(@InjectKysely() private readonly db: KyselyDB) {
super();
}
async pingCheck(key: string): Promise<HealthIndicatorResult> {
try {
await sql`SELECT 1=1`.execute(this.db);
return this.getStatus(key, true);
} catch (e) {
this.logger.error(JSON.stringify(e));
throw new HealthCheckError(
`${key} is not available`,
this.getStatus(key, false),
);
}
}
}
@@ -0,0 +1,34 @@
import {
HealthCheckError,
HealthIndicator,
HealthIndicatorResult,
} from '@nestjs/terminus';
import { Injectable, Logger } from '@nestjs/common';
import { EnvironmentService } from '../environment/environment.service';
import { Redis } from 'ioredis';
@Injectable()
export class RedisHealthIndicator extends HealthIndicator {
private readonly logger = new Logger(RedisHealthIndicator.name);
constructor(private environmentService: EnvironmentService) {
super();
}
async pingCheck(key: string): Promise<HealthIndicatorResult> {
try {
const redis = new Redis(this.environmentService.getRedisUrl(), {
maxRetriesPerRequest: 15,
});
await redis.ping();
return this.getStatus(key, true);
} catch (e) {
this.logger.error(e);
throw new HealthCheckError(
`${key} is not available`,
this.getStatus(key, false),
);
}
}
}
@@ -34,9 +34,6 @@ export class S3Driver implements StorageDriver {
});
await this.s3Client.send(command);
// we can get the path from location
console.log(`File uploaded successfully: ${filePath}`);
} catch (err) {
throw new Error(`Failed to upload file: ${(err as Error).message}`);
}
@@ -41,20 +41,34 @@ export const storageDriverConfigProvider = {
};
case StorageOption.S3:
return {
const s3Config = {
driver,
config: {
region: environmentService.getAwsS3Region(),
endpoint: environmentService.getAwsS3Endpoint(),
bucket: environmentService.getAwsS3Bucket(),
baseUrl: environmentService.getAwsS3Url(),
credentials: {
accessKeyId: environmentService.getAwsS3AccessKeyId(),
secretAccessKey: environmentService.getAwsS3SecretAccessKey(),
},
credentials: undefined,
},
};
/**
* This makes use of AWS_S3_ACCESS_KEY_ID and AWS_S3_SECRET_ACCESS_KEY if present,
* If not present, it makes it lenient for the AWS SDK to use
* AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY if they are present in the environment
*/
if (
environmentService.getAwsS3AccessKeyId() ||
environmentService.getAwsS3SecretAccessKey()
) {
s3Config.config.credentials = {
accessKeyId: environmentService.getAwsS3AccessKeyId(),
secretAccessKey: environmentService.getAwsS3SecretAccessKey(),
};
}
return s3Config;
default:
throw new Error(`Unknown storage driver: ${driver}`);
}
@@ -1,15 +1,17 @@
import { Inject, Injectable } from '@nestjs/common';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { STORAGE_DRIVER_TOKEN } from './constants/storage.constants';
import { StorageDriver } from './interfaces';
@Injectable()
export class StorageService {
private readonly logger = new Logger(StorageService.name);
constructor(
@Inject(STORAGE_DRIVER_TOKEN) private storageDriver: StorageDriver,
) {}
async upload(filePath: string, fileContent: Buffer | any) {
await this.storageDriver.upload(filePath, fileContent);
this.logger.debug(`File uploaded successfully. Path: ${filePath}`);
}
async read(filePath: string): Promise<Buffer> {
+3 -10
View File
@@ -40,7 +40,8 @@ async function bootstrap() {
.addHook('preHandler', function (req, reply, done) {
if (
req.originalUrl.startsWith('/api') &&
!req.originalUrl.startsWith('/api/auth/setup')
!req.originalUrl.startsWith('/api/auth/setup') &&
!req.originalUrl.startsWith('/api/health')
) {
if (!req.raw?.['workspaceId']) {
throw new NotFoundException('Workspace not found');
@@ -59,15 +60,7 @@ async function bootstrap() {
}),
);
if (process.env.NODE_ENV !== 'production') {
// make development easy
app.enableCors({
origin: ['http://localhost:5173'],
credentials: true,
});
} else {
app.enableCors();
}
app.enableCors();
app.useGlobalInterceptors(new TransformHttpResponseInterceptor());
app.enableShutdownHooks();
+10 -6
View File
@@ -1,7 +1,7 @@
{
"name": "docmost",
"homepage": "https://docmost.com",
"version": "0.2.3",
"version": "0.2.5",
"private": true,
"scripts": {
"build": "nx run-many -t build",
@@ -12,14 +12,17 @@
"client:dev": "nx run client:dev",
"server:dev": "nx run server:start:dev",
"server:start": "nx run server:start:prod",
"email:dev": "nx run @docmost/transactional:dev"
"email:dev": "nx run @docmost/transactional:dev",
"dev": "pnpm concurrently -n \"frontend,backend\" -c \"cyan,green\" \"pnpm run client:dev\" \"pnpm run server:dev\""
},
"dependencies": {
"@docmost/editor-ext": "workspace:*",
"@hocuspocus/extension-redis": "^2.13.2",
"@hocuspocus/provider": "^2.13.2",
"@hocuspocus/server": "^2.13.2",
"@hocuspocus/transformer": "^2.13.2",
"@hocuspocus/extension-redis": "^2.13.5",
"@hocuspocus/provider": "^2.13.5",
"@hocuspocus/server": "^2.13.5",
"@hocuspocus/transformer": "^2.13.5",
"@joplin/turndown": "^4.0.74",
"@joplin/turndown-plugin-gfm": "^1.0.56",
"@sindresorhus/slugify": "^2.2.1",
"@tiptap/core": "^2.4.0",
"@tiptap/extension-code-block": "^2.4.0",
@@ -65,6 +68,7 @@
"devDependencies": {
"@nx/js": "19.3.2",
"@types/uuid": "^10.0.0",
"concurrently": "^8.2.2",
"nx": "19.3.2",
"tsx": "^4.15.7"
},
+2 -2
View File
@@ -57,9 +57,9 @@ export const TiptapImage = Image.extend<ImageOptions>({
},
width: {
default: "100%",
parseHTML: (element) => element.getAttribute("data-width"),
parseHTML: (element) => element.getAttribute("width"),
renderHTML: (attributes: ImageAttributes) => ({
"data-width": attributes.width,
width: attributes.width,
}),
},
align: {
@@ -56,7 +56,7 @@ export const MathBlock = Node.create({
return [
"div",
{},
["div", { "data-katex": true }, `$${HTMLAttributes.text}$`],
["div", { "data-katex": true }, `$$${HTMLAttributes.text}$$`],
];
},
@@ -64,10 +64,6 @@ export const MathBlock = Node.create({
return ReactNodeViewRenderer(this.options.view);
},
renderText({ node }) {
return node.attrs.text;
},
addCommands() {
return {
setMathBlock:
@@ -54,15 +54,7 @@ export const MathInline = Node.create<MathInlineOption>({
},
renderHTML({ HTMLAttributes }) {
return [
"div",
{},
["span", { "data-katex": true }, `$${HTMLAttributes.text}$`],
];
},
renderText({ node }) {
return node.attrs.text;
return ["span", { "data-katex": true }, `$${HTMLAttributes.text}$` || {}];
},
addNodeView() {
+2 -2
View File
@@ -62,9 +62,9 @@ export const TiptapVideo = Node.create<VideoOptions>({
},
width: {
default: "100%",
parseHTML: (element) => element.getAttribute("data-width"),
parseHTML: (element) => element.getAttribute("width"),
renderHTML: (attributes: VideoAttributes) => ({
"data-width": attributes.width,
width: attributes.width,
}),
},
size: {
+445 -27
View File
@@ -12,17 +12,23 @@ importers:
specifier: workspace:*
version: link:packages/editor-ext
'@hocuspocus/extension-redis':
specifier: ^2.13.2
version: 2.13.2(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
specifier: ^2.13.5
version: 2.13.5(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
'@hocuspocus/provider':
specifier: ^2.13.2
version: 2.13.2(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
specifier: ^2.13.5
version: 2.13.5(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
'@hocuspocus/server':
specifier: ^2.13.2
version: 2.13.2(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
specifier: ^2.13.5
version: 2.13.5(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
'@hocuspocus/transformer':
specifier: ^2.13.2
version: 2.13.2(@tiptap/pm@2.4.0)(y-prosemirror@1.2.3(prosemirror-model@1.19.4)(prosemirror-state@1.4.3)(prosemirror-view@1.32.7)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))(yjs@13.6.18)
specifier: ^2.13.5
version: 2.13.5(@tiptap/pm@2.4.0)(y-prosemirror@1.2.3(prosemirror-model@1.19.4)(prosemirror-state@1.4.3)(prosemirror-view@1.32.7)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))(yjs@13.6.18)
'@joplin/turndown':
specifier: ^4.0.74
version: 4.0.74
'@joplin/turndown-plugin-gfm':
specifier: ^1.0.56
version: 1.0.56
'@sindresorhus/slugify':
specifier: ^2.2.1
version: 2.2.1
@@ -153,6 +159,9 @@ importers:
'@types/uuid':
specifier: ^10.0.0
version: 10.0.0
concurrently:
specifier: ^8.2.2
version: 8.2.2
nx:
specifier: 19.3.2
version: 19.3.2(@swc/core@1.5.25(@swc/helpers@0.5.11))
@@ -213,6 +222,9 @@ importers:
emoji-mart:
specifier: ^5.6.0
version: 5.6.0
file-saver:
specifier: ^2.0.5
version: 2.0.5
jotai:
specifier: ^2.8.3
version: 2.8.3(@types/react@18.3.3)(react@18.3.1)
@@ -370,6 +382,9 @@ importers:
'@nestjs/platform-socket.io':
specifier: ^10.3.9
version: 10.3.9(@nestjs/common@10.3.9(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.3.9)(rxjs@7.8.1)
'@nestjs/terminus':
specifier: ^10.2.3
version: 10.2.3(@nestjs/common@10.3.9(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.9(@nestjs/common@10.3.9(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.3.9)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/websockets':
specifier: ^10.3.9
version: 10.3.9(@nestjs/common@10.3.9(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.9)(@nestjs/platform-socket.io@10.3.9)(reflect-metadata@0.2.2)(rxjs@7.8.1)
@@ -560,6 +575,9 @@ packages:
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
engines: {node: '>=0.10.0'}
'@adobe/css-tools@4.3.3':
resolution: {integrity: sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==}
'@alloc/quick-lru@5.2.0':
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
@@ -1932,29 +1950,29 @@ packages:
'@floating-ui/utils@0.2.1':
resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==}
'@hocuspocus/common@2.13.2':
resolution: {integrity: sha512-NMsXx/Dl9xu1KlhNbGzLYLOjKtUOVmU+zA/br+EA4DhNDEtGWvHAmqY5r9SBTr2mGtGJagt+GEqZydSzBUFj4g==}
'@hocuspocus/common@2.13.5':
resolution: {integrity: sha512-8D9FzhZFlt0WsgXw5yT2zwSxi6z9d4V2vUz6co2vo3Cj+Y2bvGZsdDiTvU/MerGcCLME5k/w6PwLPojLYH/4pg==}
'@hocuspocus/extension-redis@2.13.2':
resolution: {integrity: sha512-QZJKMcMDl3KqDKrwJ65a47aB6scNcmhUN3AqoaeDy8gE3Z3RHo8GCGNcrZCy7MT/+U4KzgRl2rbdJLHciGsAew==}
'@hocuspocus/extension-redis@2.13.5':
resolution: {integrity: sha512-2wShUgOVXOUd2jd+ncmK3Wd/PUUwrIWNp17XZg/YD6L6kNSNvqPKo0vPmaT4uCekhVO6qPYX3fsLgX2j2hMyUQ==}
peerDependencies:
y-protocols: ^1.0.6
yjs: ^13.6.8
'@hocuspocus/provider@2.13.2':
resolution: {integrity: sha512-Pi+b8gcXHomSDRzohbmVW4dwo5OIqEBoLVrsuEG/pCCS13gBAeUCKCxfrl0q5XCNhK1nu3/j6UW9lxuExqiY+g==}
'@hocuspocus/provider@2.13.5':
resolution: {integrity: sha512-G3S0OiFSYkmbOwnbhV7FyJs4OBqB/+1YT9c44Ujux1RKowGm5H8+0p3FUHfXwd/3v9V0jE+E1FnFKoGonJSQwA==}
peerDependencies:
y-protocols: ^1.0.6
yjs: ^13.6.8
'@hocuspocus/server@2.13.2':
resolution: {integrity: sha512-crUuMJaK8Ql6zC9x+N0kwKlHTZ2pXV7hG2yOQj5ieGxnQtX4uExU77yS9vji9R7w10YcPnkDwvwPMgeyWhwRfQ==}
'@hocuspocus/server@2.13.5':
resolution: {integrity: sha512-gDYax5ruaj30mMtFjq5+o5USXQD31hDOxBVU8eTAzezS6hpVllaP7HmM8iRda+UmQoeybHxzqsWAf74JCmYDug==}
peerDependencies:
y-protocols: ^1.0.6
yjs: ^13.6.8
'@hocuspocus/transformer@2.13.2':
resolution: {integrity: sha512-F6dCg3cCNB1QPXtkNvlYuVESTy5VJglNF6AbUAx1yh5zXRz9CMzxZs7tjVCdarZtjYmyu/dtYctub7uyA2RefA==}
'@hocuspocus/transformer@2.13.5':
resolution: {integrity: sha512-G5QWvV4K7lussF4lSWPFjtqSTZjiq1tkU4WEn1u8OdKQUF0GtfNcnrGWMlCeJdz5Ucpp4qJHWt4TTPI1Lpw/9Q==}
peerDependencies:
'@tiptap/pm': ^2.1.12
y-prosemirror: ^1.2.1
@@ -2049,6 +2067,12 @@ packages:
resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
'@joplin/turndown-plugin-gfm@1.0.56':
resolution: {integrity: sha512-q9Pul+xfmjXNHgNgB+ksRkwcBf13X7C89CDxT4sShrh17dmGsc7AUy+GbnwlmavauMDvsdiDIG8pvGqa1L002g==}
'@joplin/turndown@4.0.74':
resolution: {integrity: sha512-yISsLt6wQCVtJHWf6XaSQv3hw4FxzmL8jLa7GJNZAIpFSg9cWBp9f9+tIbEwT6fzCFt1Vs9dQJSVujUYP/hTzA==}
'@jridgewell/gen-mapping@0.3.5':
resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==}
engines: {node: '>=6.0.0'}
@@ -2289,6 +2313,54 @@ packages:
peerDependencies:
typescript: '>=4.8.2'
'@nestjs/terminus@10.2.3':
resolution: {integrity: sha512-iX7gXtAooePcyQqFt57aDke5MzgdkBeYgF5YsFNNFwOiAFdIQEhfv3PR0G+HlH9F6D7nBCDZt9U87Pks/qHijg==}
peerDependencies:
'@grpc/grpc-js': '*'
'@grpc/proto-loader': '*'
'@mikro-orm/core': '*'
'@mikro-orm/nestjs': '*'
'@nestjs/axios': ^1.0.0 || ^2.0.0 || ^3.0.0
'@nestjs/common': ^9.0.0 || ^10.0.0
'@nestjs/core': ^9.0.0 || ^10.0.0
'@nestjs/microservices': ^9.0.0 || ^10.0.0
'@nestjs/mongoose': ^9.0.0 || ^10.0.0
'@nestjs/sequelize': ^9.0.0 || ^10.0.0
'@nestjs/typeorm': ^9.0.0 || ^10.0.0
'@prisma/client': '*'
mongoose: '*'
reflect-metadata: 0.1.x || 0.2.x
rxjs: 7.x
sequelize: '*'
typeorm: '*'
peerDependenciesMeta:
'@grpc/grpc-js':
optional: true
'@grpc/proto-loader':
optional: true
'@mikro-orm/core':
optional: true
'@mikro-orm/nestjs':
optional: true
'@nestjs/axios':
optional: true
'@nestjs/microservices':
optional: true
'@nestjs/mongoose':
optional: true
'@nestjs/sequelize':
optional: true
'@nestjs/typeorm':
optional: true
'@prisma/client':
optional: true
mongoose:
optional: true
sequelize:
optional: true
typeorm:
optional: true
'@nestjs/testing@10.3.9':
resolution: {integrity: sha512-z24SdpZIRtYyM5s2vnu7rbBosXJY/KcAP7oJlwgFa/h/z/wg8gzyoKy5lhibH//OZNO+pYKajV5wczxuy5WeAg==}
peerDependencies:
@@ -4145,6 +4217,10 @@ packages:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
agent-base@7.1.1:
resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==}
engines: {node: '>= 14'}
ajv-formats@2.1.1:
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
peerDependencies:
@@ -4164,6 +4240,9 @@ packages:
ajv@8.12.0:
resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
ansi-align@3.0.1:
resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
ansi-colors@4.1.3:
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
engines: {node: '>=6'}
@@ -4349,6 +4428,10 @@ packages:
bowser@2.11.0:
resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==}
boxen@5.1.2:
resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==}
engines: {node: '>=10'}
brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
@@ -4443,6 +4526,10 @@ packages:
chardet@0.7.0:
resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
check-disk-space@3.4.0:
resolution: {integrity: sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw==}
engines: {node: '>=16'}
chokidar@3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'}
@@ -4472,6 +4559,10 @@ packages:
class-validator@0.14.1:
resolution: {integrity: sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==}
cli-boxes@2.2.1:
resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==}
engines: {node: '>=6'}
cli-cursor@3.1.0:
resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
engines: {node: '>=8'}
@@ -4584,6 +4675,11 @@ packages:
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
concurrently@8.2.2:
resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==}
engines: {node: ^14.13.0 || >=16.0.0}
hasBin: true
config-chain@1.1.13:
resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
@@ -4680,12 +4776,24 @@ packages:
engines: {node: '>=4'}
hasBin: true
cssstyle@3.0.0:
resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==}
engines: {node: '>=14'}
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
dash-get@1.0.2:
resolution: {integrity: sha512-4FbVrHDwfOASx7uQVxeiCTo7ggSdYZbqs8lH+WU6ViypPlDbe9y6IP5VVUDQBv9DcnyaiPT5XT0UWHgJ64zLeQ==}
data-urls@5.0.0:
resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
engines: {node: '>=18'}
date-fns@2.30.0:
resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
engines: {node: '>=0.11'}
date-fns@3.6.0:
resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==}
@@ -4702,6 +4810,9 @@ packages:
supports-color:
optional: true
decimal.js@10.4.3:
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
dedent@1.5.1:
resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==}
peerDependencies:
@@ -5145,6 +5256,9 @@ packages:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'}
file-saver@2.0.5:
resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
filelist@1.0.4:
resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==}
@@ -5401,6 +5515,13 @@ packages:
resolution: {integrity: sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==}
engines: {node: ^16.14.0 || >=18.0.0}
html-encoding-sniffer@4.0.0:
resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
engines: {node: '>=18'}
html-entities@1.4.0:
resolution: {integrity: sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==}
html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
@@ -5415,10 +5536,18 @@ packages:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}
http-proxy-agent@7.0.2:
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
engines: {node: '>= 14'}
https-proxy-agent@5.0.1:
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
engines: {node: '>= 6'}
https-proxy-agent@7.0.5:
resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==}
engines: {node: '>= 14'}
human-signals@2.1.0:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
@@ -5543,6 +5672,9 @@ packages:
resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
engines: {node: '>=0.10.0'}
is-potential-custom-element-name@1.0.1:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
is-stream@2.0.1:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
@@ -5784,6 +5916,15 @@ packages:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
jsdom@23.0.1:
resolution: {integrity: sha512-2i27vgvlUsGEBO9+/kJQRbtqtm+191b5zAZrU/UezVmnC2dlDAFLgDYJvAEi94T4kjsRKkezEtLQTgsNEsW2lQ==}
engines: {node: '>=18'}
peerDependencies:
canvas: ^2.11.2
peerDependenciesMeta:
canvas:
optional: true
jsesc@0.5.0:
resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==}
hasBin: true
@@ -6320,6 +6461,9 @@ packages:
npmlog@5.0.1:
resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
nwsapi@2.2.10:
resolution: {integrity: sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==}
nx@19.3.2:
resolution: {integrity: sha512-eKWs+ahkTKnq9EeWJCE4u8JLeq1cOHnq5DKoiisy2nwUg4KGy1odReegxUMLeEgNBcMI40EUtEJFiTMJSXZQeg==}
hasBin: true
@@ -6433,6 +6577,9 @@ packages:
resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==}
engines: {node: '>= 0.10'}
parse5@7.1.2:
resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==}
parseley@0.12.1:
resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==}
@@ -6784,6 +6931,9 @@ packages:
prr@1.0.1:
resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
psl@1.9.0:
resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
@@ -6799,6 +6949,9 @@ packages:
resolution: {integrity: sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==}
engines: {node: '>=0.6'}
querystringify@2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -7042,6 +7195,9 @@ packages:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
requires-port@1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
resolve-cwd@3.0.0:
resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
engines: {node: '>=8'}
@@ -7097,6 +7253,9 @@ packages:
rope-sequence@1.3.4:
resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==}
rrweb-cssom@0.6.0:
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
run-async@2.4.1:
resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
engines: {node: '>=0.12.0'}
@@ -7130,6 +7289,10 @@ packages:
sax@1.4.1:
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
saxes@6.0.0:
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
engines: {node: '>=v12.22.7'}
scheduler@0.23.2:
resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
@@ -7191,6 +7354,9 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
shell-quote@1.8.1:
resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==}
shelljs.exec@1.1.8:
resolution: {integrity: sha512-vFILCw+lzUtiwBAHV8/Ex8JsFjelFMdhONIsgKNLgTzeRckp2AOYRQtHJE/9LhNvdMmE27AGtzWx0+DHpwIwSw==}
engines: {node: '>= 4.0.0'}
@@ -7275,6 +7441,9 @@ packages:
resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
engines: {node: '>= 8'}
spawn-command@0.0.2:
resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==}
split2@4.2.0:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
@@ -7404,6 +7573,9 @@ packages:
resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==}
engines: {node: '>=0.10'}
symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
synckit@0.8.8:
resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==}
engines: {node: ^14.18.0 || >=16.0.0}
@@ -7506,9 +7678,17 @@ packages:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
tough-cookie@4.1.4:
resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
engines: {node: '>=6'}
tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
tr46@5.0.0:
resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==}
engines: {node: '>=18'}
tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
@@ -7608,6 +7788,10 @@ packages:
resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
engines: {node: '>=4'}
type-fest@0.20.2:
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
engines: {node: '>=10'}
type-fest@0.21.3:
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
engines: {node: '>=10'}
@@ -7669,6 +7853,10 @@ packages:
resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==}
engines: {node: '>=4'}
universalify@0.2.0:
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
engines: {node: '>= 4.0.0'}
universalify@2.0.1:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
@@ -7682,6 +7870,9 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
url-parse@1.5.10:
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
use-callback-ref@1.3.1:
resolution: {integrity: sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==}
engines: {node: '>=10'}
@@ -7798,6 +7989,10 @@ packages:
w3c-keyname@2.2.8:
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
w3c-xmlserializer@5.0.0:
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
engines: {node: '>=18'}
walker@1.0.8:
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
@@ -7811,6 +8006,10 @@ packages:
webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
webidl-conversions@7.0.0:
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
engines: {node: '>=12'}
webpack-node-externals@3.0.0:
resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==}
engines: {node: '>=6'}
@@ -7839,6 +8038,18 @@ packages:
webpack-cli:
optional: true
whatwg-encoding@3.1.1:
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
engines: {node: '>=18'}
whatwg-mimetype@4.0.0:
resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
engines: {node: '>=18'}
whatwg-url@14.0.0:
resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==}
engines: {node: '>=18'}
whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
@@ -7850,6 +8061,10 @@ packages:
wide-align@1.1.5:
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
widest-line@3.1.0:
resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==}
engines: {node: '>=8'}
wrap-ansi@6.2.0:
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
engines: {node: '>=8'}
@@ -7893,6 +8108,13 @@ packages:
utf-8-validate:
optional: true
xml-name-validator@5.0.0:
resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
engines: {node: '>=18'}
xmlchars@2.2.0:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
xmlhttprequest-ssl@2.0.0:
resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==}
engines: {node: '>=0.4.0'}
@@ -7973,6 +8195,8 @@ snapshots:
'@aashutoshrathi/word-wrap@1.2.6': {}
'@adobe/css-tools@4.3.3': {}
'@alloc/quick-lru@5.2.0': {}
'@ampproject/remapping@2.3.0':
@@ -9884,13 +10108,13 @@ snapshots:
'@floating-ui/utils@0.2.1': {}
'@hocuspocus/common@2.13.2':
'@hocuspocus/common@2.13.5':
dependencies:
lib0: 0.2.93
'@hocuspocus/extension-redis@2.13.2(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)':
'@hocuspocus/extension-redis@2.13.5(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)':
dependencies:
'@hocuspocus/server': 2.13.2(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
'@hocuspocus/server': 2.13.5(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)
ioredis: 4.28.5
kleur: 4.1.5
lodash.debounce: 4.0.8
@@ -9903,9 +10127,9 @@ snapshots:
- supports-color
- utf-8-validate
'@hocuspocus/provider@2.13.2(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)':
'@hocuspocus/provider@2.13.5(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)':
dependencies:
'@hocuspocus/common': 2.13.2
'@hocuspocus/common': 2.13.5
'@lifeomic/attempt': 3.0.3
lib0: 0.2.93
ws: 8.17.1
@@ -9915,9 +10139,9 @@ snapshots:
- bufferutil
- utf-8-validate
'@hocuspocus/server@2.13.2(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)':
'@hocuspocus/server@2.13.5(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18)':
dependencies:
'@hocuspocus/common': 2.13.2
'@hocuspocus/common': 2.13.5
async-lock: 1.4.1
kleur: 4.1.5
lib0: 0.2.93
@@ -9929,7 +10153,7 @@ snapshots:
- bufferutil
- utf-8-validate
'@hocuspocus/transformer@2.13.2(@tiptap/pm@2.4.0)(y-prosemirror@1.2.3(prosemirror-model@1.19.4)(prosemirror-state@1.4.3)(prosemirror-view@1.32.7)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))(yjs@13.6.18)':
'@hocuspocus/transformer@2.13.5(@tiptap/pm@2.4.0)(y-prosemirror@1.2.3(prosemirror-model@1.19.4)(prosemirror-state@1.4.3)(prosemirror-view@1.32.7)(y-protocols@1.0.6(yjs@13.6.18))(yjs@13.6.18))(yjs@13.6.18)':
dependencies:
'@tiptap/core': 2.4.0(@tiptap/pm@2.4.0)
'@tiptap/pm': 2.4.0
@@ -10124,6 +10348,19 @@ snapshots:
'@types/yargs': 17.0.32
chalk: 4.1.2
'@joplin/turndown-plugin-gfm@1.0.56': {}
'@joplin/turndown@4.0.74':
dependencies:
'@adobe/css-tools': 4.3.3
html-entities: 1.4.0
jsdom: 23.0.1
transitivePeerDependencies:
- bufferutil
- canvas
- supports-color
- utf-8-validate
'@jridgewell/gen-mapping@0.3.5':
dependencies:
'@jridgewell/set-array': 1.2.1
@@ -10404,6 +10641,15 @@ snapshots:
transitivePeerDependencies:
- chokidar
'@nestjs/terminus@10.2.3(@nestjs/common@10.3.9(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.9(@nestjs/common@10.3.9(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.3.9)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)(rxjs@7.8.1)':
dependencies:
'@nestjs/common': 10.3.9(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
'@nestjs/core': 10.3.9(@nestjs/common@10.3.9(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.3.9)(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@10.3.9(@nestjs/common@10.3.9(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.3.9(@nestjs/common@10.3.9(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/websockets@10.3.9)(reflect-metadata@0.2.2)(rxjs@7.8.1))':
dependencies:
'@nestjs/common': 10.3.9(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)
@@ -12444,6 +12690,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
agent-base@7.1.1:
dependencies:
debug: 4.3.4
transitivePeerDependencies:
- supports-color
ajv-formats@2.1.1(ajv@8.12.0):
optionalDependencies:
ajv: 8.12.0
@@ -12466,6 +12718,10 @@ snapshots:
require-from-string: 2.0.2
uri-js: 4.4.1
ansi-align@3.0.1:
dependencies:
string-width: 4.2.3
ansi-colors@4.1.3: {}
ansi-escapes@4.3.2:
@@ -12721,6 +12977,17 @@ snapshots:
bowser@2.11.0: {}
boxen@5.1.2:
dependencies:
ansi-align: 3.0.1
camelcase: 6.3.0
chalk: 4.1.2
cli-boxes: 2.2.1
string-width: 4.2.3
type-fest: 0.20.2
widest-line: 3.1.0
wrap-ansi: 7.0.0
brace-expansion@1.1.11:
dependencies:
balanced-match: 1.0.2
@@ -12822,6 +13089,8 @@ snapshots:
chardet@0.7.0: {}
check-disk-space@3.4.0: {}
chokidar@3.5.3:
dependencies:
anymatch: 3.1.3
@@ -12862,6 +13131,8 @@ snapshots:
libphonenumber-js: 1.10.58
validator: 13.12.0
cli-boxes@2.2.1: {}
cli-cursor@3.1.0:
dependencies:
restore-cursor: 3.1.0
@@ -12947,6 +13218,18 @@ snapshots:
concat-map@0.0.1: {}
concurrently@8.2.2:
dependencies:
chalk: 4.1.2
date-fns: 2.30.0
lodash: 4.17.21
rxjs: 7.8.1
shell-quote: 1.8.1
spawn-command: 0.0.2
supports-color: 8.1.1
tree-kill: 1.2.2
yargs: 17.7.2
config-chain@1.1.13:
dependencies:
ini: 1.3.8
@@ -13049,10 +13332,23 @@ snapshots:
cssesc@3.0.0: {}
cssstyle@3.0.0:
dependencies:
rrweb-cssom: 0.6.0
csstype@3.1.3: {}
dash-get@1.0.2: {}
data-urls@5.0.0:
dependencies:
whatwg-mimetype: 4.0.0
whatwg-url: 14.0.0
date-fns@2.30.0:
dependencies:
'@babel/runtime': 7.23.7
date-fns@3.6.0: {}
debounce@2.0.0: {}
@@ -13061,6 +13357,8 @@ snapshots:
dependencies:
ms: 2.1.2
decimal.js@10.4.3: {}
dedent@1.5.1(babel-plugin-macros@2.8.0):
optionalDependencies:
babel-plugin-macros: 2.8.0
@@ -13590,6 +13888,8 @@ snapshots:
dependencies:
flat-cache: 4.0.1
file-saver@2.0.5: {}
filelist@1.0.4:
dependencies:
minimatch: 5.1.6
@@ -13862,6 +14162,12 @@ snapshots:
dependencies:
lru-cache: 10.2.0
html-encoding-sniffer@4.0.0:
dependencies:
whatwg-encoding: 3.1.1
html-entities@1.4.0: {}
html-escaper@2.0.2: {}
html-to-text@9.0.5:
@@ -13887,6 +14193,13 @@ snapshots:
statuses: 2.0.1
toidentifier: 1.0.1
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.1
debug: 4.3.4
transitivePeerDependencies:
- supports-color
https-proxy-agent@5.0.1:
dependencies:
agent-base: 6.0.2
@@ -13894,6 +14207,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
https-proxy-agent@7.0.5:
dependencies:
agent-base: 7.1.1
debug: 4.3.4
transitivePeerDependencies:
- supports-color
human-signals@2.1.0: {}
iconv-lite@0.4.24:
@@ -13903,7 +14223,6 @@ snapshots:
iconv-lite@0.6.3:
dependencies:
safer-buffer: 2.1.2
optional: true
ieee754@1.2.1: {}
@@ -14043,6 +14362,8 @@ snapshots:
dependencies:
isobject: 3.0.1
is-potential-custom-element-name@1.0.1: {}
is-stream@2.0.1: {}
is-unicode-supported@0.1.0: {}
@@ -14466,6 +14787,34 @@ snapshots:
dependencies:
argparse: 2.0.1
jsdom@23.0.1:
dependencies:
cssstyle: 3.0.0
data-urls: 5.0.0
decimal.js: 10.4.3
form-data: 4.0.0
html-encoding-sniffer: 4.0.0
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.5
is-potential-custom-element-name: 1.0.1
nwsapi: 2.2.10
parse5: 7.1.2
rrweb-cssom: 0.6.0
saxes: 6.0.0
symbol-tree: 3.2.4
tough-cookie: 4.1.4
w3c-xmlserializer: 5.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 3.1.1
whatwg-mimetype: 4.0.0
whatwg-url: 14.0.0
ws: 8.17.1
xml-name-validator: 5.0.0
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
jsesc@0.5.0: {}
jsesc@2.5.2: {}
@@ -14939,6 +15288,8 @@ snapshots:
gauge: 3.0.2
set-blocking: 2.0.0
nwsapi@2.2.10: {}
nx@19.3.2(@swc/core@1.5.25(@swc/helpers@0.5.11)):
dependencies:
'@nrwl/tao': 19.3.2(@swc/core@1.5.25(@swc/helpers@0.5.11))
@@ -15100,6 +15451,10 @@ snapshots:
parse-node-version@1.0.1:
optional: true
parse5@7.1.2:
dependencies:
entities: 4.5.0
parseley@0.12.1:
dependencies:
leac: 0.6.0
@@ -15474,6 +15829,8 @@ snapshots:
prr@1.0.1:
optional: true
psl@1.9.0: {}
punycode.js@2.3.1: {}
punycode@2.3.1: {}
@@ -15484,6 +15841,8 @@ snapshots:
dependencies:
side-channel: 1.0.6
querystringify@2.2.0: {}
queue-microtask@1.2.3: {}
quick-format-unescaped@4.0.4: {}
@@ -15807,6 +16166,8 @@ snapshots:
require-from-string@2.0.2: {}
requires-port@1.0.0: {}
resolve-cwd@3.0.0:
dependencies:
resolve-from: 5.0.0
@@ -15867,6 +16228,8 @@ snapshots:
rope-sequence@1.3.4: {}
rrweb-cssom@0.6.0: {}
run-async@2.4.1: {}
run-async@3.0.0: {}
@@ -15896,6 +16259,10 @@ snapshots:
sax@1.4.1:
optional: true
saxes@6.0.0:
dependencies:
xmlchars: 2.2.0
scheduler@0.23.2:
dependencies:
loose-envify: 1.4.0
@@ -15963,6 +16330,8 @@ snapshots:
shebang-regex@3.0.0: {}
shell-quote@1.8.1: {}
shelljs.exec@1.1.8: {}
shelljs@0.8.5:
@@ -16084,6 +16453,8 @@ snapshots:
source-map@0.7.4: {}
spawn-command@0.0.2: {}
split2@4.2.0: {}
sprintf-js@1.0.3: {}
@@ -16208,6 +16579,8 @@ snapshots:
symbol-observable@4.0.0: {}
symbol-tree@3.2.4: {}
synckit@0.8.8:
dependencies:
'@pkgr/core': 0.1.1
@@ -16342,8 +16715,19 @@ snapshots:
toidentifier@1.0.1: {}
tough-cookie@4.1.4:
dependencies:
psl: 1.9.0
punycode: 2.3.1
universalify: 0.2.0
url-parse: 1.5.10
tr46@0.0.3: {}
tr46@5.0.0:
dependencies:
punycode: 2.3.1
tree-kill@1.2.2: {}
truncate-utf8-bytes@1.0.2:
@@ -16451,6 +16835,8 @@ snapshots:
type-detect@4.0.8: {}
type-fest@0.20.2: {}
type-fest@0.21.3: {}
type-fest@0.7.1: {}
@@ -16486,6 +16872,8 @@ snapshots:
unicode-property-aliases-ecmascript@2.1.0: {}
universalify@0.2.0: {}
universalify@2.0.1: {}
update-browserslist-db@1.0.13(browserslist@4.23.0):
@@ -16498,6 +16886,11 @@ snapshots:
dependencies:
punycode: 2.3.1
url-parse@1.5.10:
dependencies:
querystringify: 2.2.0
requires-port: 1.0.0
use-callback-ref@1.3.1(@types/react@18.3.3)(react@18.3.1):
dependencies:
react: 18.3.1
@@ -16574,6 +16967,10 @@ snapshots:
w3c-keyname@2.2.8: {}
w3c-xmlserializer@5.0.0:
dependencies:
xml-name-validator: 5.0.0
walker@1.0.8:
dependencies:
makeerror: 1.0.12
@@ -16589,6 +16986,8 @@ snapshots:
webidl-conversions@3.0.1: {}
webidl-conversions@7.0.0: {}
webpack-node-externals@3.0.0: {}
webpack-sources@3.2.3: {}
@@ -16655,6 +17054,17 @@ snapshots:
- esbuild
- uglify-js
whatwg-encoding@3.1.1:
dependencies:
iconv-lite: 0.6.3
whatwg-mimetype@4.0.0: {}
whatwg-url@14.0.0:
dependencies:
tr46: 5.0.0
webidl-conversions: 7.0.0
whatwg-url@5.0.0:
dependencies:
tr46: 0.0.3
@@ -16668,6 +17078,10 @@ snapshots:
dependencies:
string-width: 4.2.3
widest-line@3.1.0:
dependencies:
string-width: 4.2.3
wrap-ansi@6.2.0:
dependencies:
ansi-styles: 4.3.0
@@ -16697,6 +17111,10 @@ snapshots:
ws@8.17.1: {}
xml-name-validator@5.0.0: {}
xmlchars@2.2.0: {}
xmlhttprequest-ssl@2.0.0: {}
xtend@4.0.2: {}