Compare commits

..

6 Commits

Author SHA1 Message Date
Lucas Smith eeeee2fa0e v2.3.1 2025-12-18 12:02:04 +11:00
Lucas Smith c50a31a503 fix: use cpu for field rendering (#2337) 2025-12-18 10:48:46 +11:00
Lucas Smith 7360709795 fix: use gemimi 3 flash preview (#2336) 2025-12-18 10:48:16 +11:00
Lucas Smith df678d7d69 v2.3.0 2025-12-17 22:10:47 +11:00
Lucas Smith 6739242554 fix: use cpu for skia-canvas rendering (#2334)
Seems there's a memory leak in gpu rendering with skia canvas
where contexts can live for much longer than expected escaping gc
cleanup

CPU rendering seems better albeit a bit slower.

Synthetic tests were ran with `--expose-gc` to simulate load over time.
2025-12-17 14:48:21 +11:00
Konrad a5e5eecf8b fix: mark links for translation (#2333) 2025-12-17 12:02:12 +11:00
13 changed files with 71 additions and 14 deletions
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useState, useTransition } from 'react';
import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';
import { Trans } from '@lingui/react/macro';
import type { Role, Subscription } from '@prisma/client';
import { Edit, Loader } from 'lucide-react';
import { Link } from 'react-router';
@@ -82,7 +83,7 @@ export const AdminDashboardUsersTable = ({
<Button className="w-24" asChild>
<Link to={`/admin/users/${row.original.id}`}>
<Edit className="-ml-1 mr-2 h-4 w-4" />
Edit
<Trans>Edit</Trans>
</Link>
</Button>
);
@@ -82,7 +82,9 @@ export const OrganisationGroupsDataTable = () => {
cell: ({ row }) => (
<div className="flex justify-end space-x-2">
<Button asChild variant="outline">
<Link to={`/o/${organisation.url}/settings/groups/${row.original.id}`}>Manage</Link>
<Link to={`/o/${organisation.url}/settings/groups/${row.original.id}`}>
<Trans>Manage</Trans>
</Link>
</Button>
<OrganisationGroupDeleteDialog
@@ -120,7 +120,9 @@ export default function OrganisationSettingsTeamsPage() {
</div>
<Button asChild>
<Link to={`/o/${organisation.url}/settings`}>Manage Organisation</Link>
<Link to={`/o/${organisation.url}/settings`}>
<Trans>Manage Organisation</Trans>
</Link>
</Button>
</div>
@@ -115,7 +115,9 @@ export default function RejectedSigningPage({ loaderData }: Route.ComponentProps
{user && (
<Button className="mt-6" asChild>
<Link to={`/`}>Return Home</Link>
<Link to={`/`}>
<Trans>Return Home</Trans>
</Link>
</Button>
)}
</div>
@@ -98,7 +98,9 @@ export default function WaitingForTurnToSignPage({ loaderData }: Route.Component
</Button>
) : (
<Button variant="link" asChild>
<Link to="/">Return Home</Link>
<Link to="/">
<Trans>Return Home</Trans>
</Link>
</Button>
)}
</div>
+1 -1
View File
@@ -107,5 +107,5 @@
"vite-plugin-babel-macros": "^1.0.6",
"vite-tsconfig-paths": "^5.1.4"
},
"version": "2.2.8"
"version": "2.3.1"
}
+3 -3
View File
@@ -1,12 +1,12 @@
{
"name": "@documenso/root",
"version": "2.2.8",
"version": "2.3.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@documenso/root",
"version": "2.2.8",
"version": "2.3.1",
"hasInstallScript": true,
"workspaces": [
"apps/*",
@@ -109,7 +109,7 @@
},
"apps/remix": {
"name": "@documenso/remix",
"version": "2.2.8",
"version": "2.3.1",
"dependencies": {
"@cantoo/pdf-lib": "^2.5.3",
"@documenso/api": "*",
+1 -1
View File
@@ -5,7 +5,7 @@
"apps/*",
"packages/*"
],
"version": "2.2.8",
"version": "2.3.1",
"scripts": {
"postinstall": "patch-package",
"build": "turbo run build",
@@ -286,7 +286,7 @@ const detectFieldsFromPage = async ({
});
const result = await generateObject({
model: vertex('gemini-3-pro-preview'),
model: vertex('gemini-3-flash-preview'),
system: SYSTEM_PROMPT,
schema: ZSubmitDetectedFieldsInputSchema,
messages,
@@ -207,7 +207,7 @@ const detectRecipientsFromImages = async ({
});
const result = await generateObject({
model: vertex('gemini-2.5-flash'),
model: vertex('gemini-3-flash-preview'),
system: SYSTEM_PROMPT,
schema: ZDetectedRecipientsSchema,
messages,
+6 -1
View File
@@ -9,7 +9,10 @@ globalThis.Image = Image;
class SkiaCanvasFactory {
_createCanvas(width: number, height: number) {
return new Canvas(width, height);
const canvas = new Canvas(width, height);
canvas.gpu = false;
return canvas;
}
create(width: number, height: number) {
@@ -60,6 +63,8 @@ export const pdfToImages = async (pdfBytes: Uint8Array, options: PdfToImagesOpti
const viewport = page.getViewport({ scale });
const canvas = new Canvas(viewport.width, viewport.height);
canvas.gpu = false;
const canvasContext = canvas.getContext('2d');
await page.render({
@@ -0,0 +1,42 @@
/**
* !: This is a workaround to fix the memory leak in the skia-canvas library.
* !: Internals are ported from the original `konva/skia-backend.js` file.
*/
import { Konva } from 'konva/lib/_CoreInternals';
import { Canvas, DOMMatrix, Image, Path2D } from 'skia-canvas';
// @ts-expect-error skia-canvas satisfies the requirements
global.DOMMatrix = DOMMatrix;
// @ts-expect-error skia-canvas satisfies the requirements
global.Path2D = Path2D;
Path2D.prototype.toString = () => '[object Path2D]';
Konva.Util['createCanvasElement'] = () => {
const node = new Canvas(300, 300);
node.gpu = false;
if (!('style' in node) || !node['style']) {
Object.assign(node, { style: {} });
}
node.toString = () => '[object HTMLCanvasElement]';
const ctx = node.getContext('2d');
Object.defineProperty(ctx, 'canvas', {
get: () => node,
});
return node as unknown as HTMLCanvasElement;
};
Konva.Util.createImageElement = () => {
const node = new Image();
node.toString = () => '[object HTMLImageElement]';
return node as unknown as HTMLImageElement;
};
Konva._renderBackend = 'skia-canvas';
export default Konva;
@@ -1,5 +1,5 @@
// sort-imports-ignore
import 'konva/skia-backend';
import '../konva/skia-backend';
import Konva from 'konva';
import path from 'node:path';
@@ -23,6 +23,7 @@ export const insertFieldInPDFV2 = async ({
}: InsertFieldInPDFV2Options) => {
const fontPath = path.join(process.cwd(), 'public/fonts');
// eslint-disable-next-line react-hooks/rules-of-hooks
FontLibrary.use({
['Caveat']: [path.join(fontPath, 'caveat.ttf')],
['Noto Sans']: [path.join(fontPath, 'noto-sans.ttf')],