chore: merge main

This commit is contained in:
Catalin Pit
2025-07-03 12:47:37 +03:00
95 changed files with 2448 additions and 946 deletions

View File

@ -1,26 +0,0 @@
import React from 'react';
import { Badge } from '@documenso/ui/primitives/badge';
export type DocumentHistorySheetChangesProps = {
values: {
key: string | React.ReactNode;
value: string | React.ReactNode;
}[];
};
export const DocumentHistorySheetChanges = ({ values }: DocumentHistorySheetChangesProps) => {
return (
<Badge
className="text-muted-foreground mt-3 block w-full space-y-0.5 text-xs"
variant="neutral"
>
{values.map(({ key, value }, i) => (
<p key={typeof key === 'string' ? key : i}>
<span>{key}: </span>
<span className="font-normal">{value}</span>
</p>
))}
</Badge>
);
};

View File

@ -1,7 +1,7 @@
import { useLingui } from '@lingui/react';
import { Plural, Trans } from '@lingui/react/macro';
import { DocumentStatus, TeamMemberRole } from '@prisma/client';
import { ChevronLeft, Clock9, Users2 } from 'lucide-react';
import { ChevronLeft, Users2 } from 'lucide-react';
import { Link, redirect } from 'react-router';
import { match } from 'ts-pattern';
@ -13,11 +13,9 @@ import { DocumentVisibility } from '@documenso/lib/types/document-visibility';
import { formatDocumentsPath } from '@documenso/lib/utils/teams';
import { DocumentReadOnlyFields } from '@documenso/ui/components/document/document-read-only-fields';
import { Badge } from '@documenso/ui/primitives/badge';
import { Button } from '@documenso/ui/primitives/button';
import { Card, CardContent } from '@documenso/ui/primitives/card';
import { PDFViewer } from '@documenso/ui/primitives/pdf-viewer';
import { DocumentHistorySheet } from '~/components/general/document/document-history-sheet';
import { DocumentPageViewButton } from '~/components/general/document/document-page-view-button';
import { DocumentPageViewDropdown } from '~/components/general/document/document-page-view-dropdown';
import { DocumentPageViewInformation } from '~/components/general/document/document-page-view-information';
@ -101,9 +99,6 @@ export default function DocumentPage() {
const { recipients, documentData, documentMeta } = document;
// This was a feature flag. Leave to false since it's not ready.
const isDocumentHistoryEnabled = false;
return (
<div className="mx-auto -mt-4 w-full max-w-screen-xl px-4 md:px-8">
{document.status === DocumentStatus.PENDING && (
@ -154,17 +149,6 @@ export default function DocumentPage() {
)}
</div>
</div>
{isDocumentHistoryEnabled && (
<div className="self-end">
<DocumentHistorySheet documentId={document.id} userId={user.id}>
<Button variant="outline">
<Clock9 className="mr-1.5 h-4 w-4" />
<Trans>Document history</Trans>
</Button>
</DocumentHistorySheet>
</div>
)}
</div>
<div className="mt-6 grid w-full grid-cols-12 gap-8">

View File

@ -41,6 +41,7 @@
"colord": "^2.9.3",
"framer-motion": "^10.12.8",
"hono": "4.7.0",
"hono-rate-limiter": "^0.4.2",
"hono-react-router-adapter": "^0.6.2",
"input-otp": "^1.2.4",
"isbot": "^5.1.17",
@ -100,5 +101,5 @@
"vite-plugin-babel-macros": "^1.0.6",
"vite-tsconfig-paths": "^5.1.4"
},
"version": "1.12.0-rc.4"
"version": "1.12.2-rc.0"
}

View File

@ -1,10 +1,16 @@
import { Hono } from 'hono';
import { rateLimiter } from 'hono-rate-limiter';
import { contextStorage } from 'hono/context-storage';
import { requestId } from 'hono/request-id';
import type { RequestIdVariables } from 'hono/request-id';
import type { Logger } from 'pino';
import { tsRestHonoApp } from '@documenso/api/hono';
import { auth } from '@documenso/auth/server';
import { API_V2_BETA_URL } from '@documenso/lib/constants/app';
import { jobsClient } from '@documenso/lib/jobs/client';
import { getIpAddress } from '@documenso/lib/universal/get-ip-address';
import { logger } from '@documenso/lib/utils/logger';
import { openApiDocument } from '@documenso/trpc/server/open-api';
import { filesRoute } from './api/files';
@ -14,13 +20,33 @@ import { openApiTrpcServerHandler } from './trpc/hono-trpc-open-api';
import { reactRouterTrpcServer } from './trpc/hono-trpc-remix';
export interface HonoEnv {
Variables: {
Variables: RequestIdVariables & {
context: AppContext;
logger: Logger;
};
}
const app = new Hono<HonoEnv>();
/**
* Rate limiting for v1 and v2 API routes only.
* - 100 requests per minute per IP address
*/
const rateLimitMiddleware = rateLimiter({
windowMs: 60 * 1000, // 1 minute
limit: 100, // 100 requests per window
keyGenerator: (c) => {
try {
return getIpAddress(c.req.raw);
} catch (error) {
return 'unknown';
}
},
message: {
error: 'Too many requests, please try again later.',
},
});
/**
* Attach session and context to requests.
*/
@ -31,6 +57,24 @@ app.use(appContext);
* RR7 app middleware.
*/
app.use('*', appMiddleware);
app.use('*', requestId());
app.use(async (c, next) => {
const metadata = c.get('context').requestMetadata;
const honoLogger = logger.child({
requestId: c.var.requestId,
ipAddress: metadata.ipAddress,
userAgent: metadata.userAgent,
});
c.set('logger', honoLogger);
await next();
});
// Apply rate limit to /api/v1/*
app.use('/api/v1/*', rateLimitMiddleware);
app.use('/api/v2/*', rateLimitMiddleware);
// Auth server.
app.route('/api/auth', auth);