From 5750f2b4778e83a4d4d70f4e1a433a3c76b0ac92 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Wed, 15 Jan 2025 13:46:45 +1100 Subject: [PATCH] feat: add prisma json types (#1583) --- apps/documentation/package.json | 2 +- apps/openpage-api/package.json | 6 +- apps/web/package.json | 6 +- package-lock.json | 171 ++++++------------ package.json | 3 +- packages/api/v1/implementation.ts | 4 +- .../create-document-from-template.spec.ts | 2 +- packages/app-tests/package.json | 2 +- packages/eslint-config/package.json | 4 +- packages/lib/server-only/2fa/setup-2fa.ts | 2 +- .../lib/server-only/field/update-field.ts | 7 +- packages/lib/types/document-form-values.ts | 8 + packages/lib/types/field-meta.ts | 59 +++--- packages/prisma/index.ts | 1 + packages/prisma/package.json | 3 +- packages/prisma/schema.prisma | 24 ++- packages/prisma/types/types.d.ts | 25 +++ .../helpers/update-signing-placeholder.ts | 6 +- .../signing/transports/google-cloud-hsm.ts | 15 +- packages/signing/transports/local-cert.ts | 10 +- packages/ui/package.json | 2 +- 21 files changed, 174 insertions(+), 188 deletions(-) create mode 100644 packages/lib/types/document-form-values.ts create mode 100644 packages/prisma/types/types.d.ts diff --git a/apps/documentation/package.json b/apps/documentation/package.json index c5f5bee5a..fc06f6547 100644 --- a/apps/documentation/package.json +++ b/apps/documentation/package.json @@ -27,6 +27,6 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", - "typescript": "^5" + "typescript": "5.6.2" } } \ No newline at end of file diff --git a/apps/openpage-api/package.json b/apps/openpage-api/package.json index 349bc356f..1a8816acb 100644 --- a/apps/openpage-api/package.json +++ b/apps/openpage-api/package.json @@ -16,8 +16,8 @@ "next": "14.2.6" }, "devDependencies": { - "@types/node": "20.16.5", + "@types/node": "^20", "@types/react": "18.3.5", - "typescript": "5.5.4" + "typescript": "5.6.2" } -} +} \ No newline at end of file diff --git a/apps/web/package.json b/apps/web/package.json index 3fa724b7a..9659be4bc 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -68,11 +68,11 @@ "@simplewebauthn/types": "^9.0.1", "@types/formidable": "^2.0.6", "@types/luxon": "^3.3.1", - "@types/node": "20.1.0", + "@types/node": "^20", "@types/papaparse": "^5.3.14", "@types/react": "^18", "@types/react-dom": "^18", "@types/ua-parser-js": "^0.7.39", - "typescript": "5.2.2" + "typescript": "5.6.2" } -} +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6e073e849..0b91a723d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "mupdf": "^1.0.0", "next-runtime-env": "^3.2.0", "react": "^18", + "typescript": "5.6.2", "zod": "3.24.1" }, "devDependencies": { @@ -63,7 +64,7 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", - "typescript": "^5" + "typescript": "5.6.2" } }, "apps/documentation/node_modules/next-plausible": { @@ -88,18 +89,9 @@ "next": "14.2.6" }, "devDependencies": { - "@types/node": "20.16.5", + "@types/node": "^20", "@types/react": "18.3.5", - "typescript": "5.5.4" - } - }, - "apps/openpage-api/node_modules/@types/node": { - "version": "20.16.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", - "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==", - "dev": true, - "dependencies": { - "undici-types": "~6.19.2" + "typescript": "5.6.2" } }, "apps/openpage-api/node_modules/@types/react": { @@ -112,25 +104,6 @@ "csstype": "^3.0.2" } }, - "apps/openpage-api/node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "apps/openpage-api/node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true - }, "apps/web": { "name": "@documenso/web", "version": "1.9.0-rc.8", @@ -190,20 +163,14 @@ "@simplewebauthn/types": "^9.0.1", "@types/formidable": "^2.0.6", "@types/luxon": "^3.3.1", - "@types/node": "20.1.0", + "@types/node": "^20", "@types/papaparse": "^5.3.14", "@types/react": "^18", "@types/react-dom": "^18", "@types/ua-parser-js": "^0.7.39", - "typescript": "5.2.2" + "typescript": "5.6.2" } }, - "apps/web/node_modules/@types/node": { - "version": "20.1.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.0.tgz", - "integrity": "sha512-O+z53uwx64xY7D6roOi4+jApDGFg0qn6WHcxe5QeqjMaTezBO/mxdfFXIVAVVyNWKx84OmPB3L8kbVYOTeN34A==", - "dev": true - }, "apps/web/node_modules/next-axiom": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/next-axiom/-/next-axiom-1.5.1.tgz", @@ -221,19 +188,6 @@ "react": ">=18.0.0" } }, - "apps/web/node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", @@ -10205,7 +10159,8 @@ "node_modules/@types/node": { "version": "20.5.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz", - "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==" + "integrity": "sha512-4tT2UrL5LBqDwoed9wZ6N3umC4Yhz3W3FloMmiiG4JwmUJWpie0c7lcnUNd4gtMKuDEO4wRVS8B6Xa0uMRsMKg==", + "license": "MIT" }, "node_modules/@types/node-fetch": { "version": "2.6.11", @@ -32257,9 +32212,10 @@ } }, "node_modules/typescript": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", - "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -34132,24 +34088,10 @@ "@documenso/prisma": "*", "@documenso/web": "*", "@playwright/test": "^1.18.1", - "@types/node": "^20.8.2", + "@types/node": "^20", "pdf-lib": "^1.17.1" } }, - "packages/app-tests/node_modules/@types/node": { - "version": "20.8.4", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.25.1" - } - }, - "packages/app-tests/node_modules/undici-types": { - "version": "5.25.3", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", - "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", - "dev": true - }, "packages/assets": { "name": "@documenso/assets", "version": "0.1.0" @@ -34239,7 +34181,7 @@ "eslint-plugin-package-json": "^0.10.4", "eslint-plugin-react": "^7.34.0", "eslint-plugin-unused-imports": "^3.1.0", - "typescript": "5.2.2" + "typescript": "5.6.2" } }, "packages/eslint-config/node_modules/@eslint/eslintrc": { @@ -35301,18 +35243,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "packages/eslint-config/node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "packages/eslint-config/node_modules/which-typed-array": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", @@ -35445,9 +35375,10 @@ "devDependencies": { "dotenv": "^16.3.1", "dotenv-cli": "^7.3.0", + "prisma-json-types-generator": "^3.2.2", "prisma-kysely": "^1.8.0", "tsx": "^4.11.0", - "typescript": "5.2.2", + "typescript": "5.6.2", "zod-prisma-types": "3.1.9" } }, @@ -35468,23 +35399,54 @@ "@prisma/debug": "5.22.0" } }, + "packages/prisma/node_modules/prisma-json-types-generator": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/prisma-json-types-generator/-/prisma-json-types-generator-3.2.2.tgz", + "integrity": "sha512-kvEbJPIP5gxk65KmLs0nAvY+CxpqVMWb4OsEvXlyXZmp2IGfi5f52BUV7ezTYQNjRPZyR4QlayWJXffoqVVAfA==", + "dev": true, + "dependencies": { + "@prisma/generator-helper": "6.0.0", + "tslib": "2.8.1" + }, + "bin": { + "prisma-json-types-generator": "index.js" + }, + "engines": { + "node": ">=14.0" + }, + "funding": { + "url": "https://github.com/arthurfiorette/prisma-json-types-generator?sponsor=1" + }, + "peerDependencies": { + "prisma": "^5 || ^6", + "typescript": "^5.6.2" + } + }, + "packages/prisma/node_modules/prisma-json-types-generator/node_modules/@prisma/debug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.0.0.tgz", + "integrity": "sha512-eUjoNThlDXdyJ1iQ2d7U6aTVwm59EwvODb5zFVNJEokNoSiQmiYWNzZIwZyDmZ+j51j42/0iTaHIJ4/aZPKFRg==", + "dev": true + }, + "packages/prisma/node_modules/prisma-json-types-generator/node_modules/@prisma/generator-helper": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@prisma/generator-helper/-/generator-helper-6.0.0.tgz", + "integrity": "sha512-5DkG7hspZo6U4OtqI2W0JcgtY37sr7HgT8Q0W/sjL4VoV4px6ivzK6Eif5bKM7q+S4yFUHtjUt/3s69ErfLn7A==", + "dev": true, + "dependencies": { + "@prisma/debug": "6.0.0" + } + }, "packages/prisma/node_modules/ts-pattern": { "version": "5.0.6", "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-5.0.6.tgz", "integrity": "sha512-Y+jOjihlFriWzcBjncPCf2/am+Hgz7LtsWs77pWg5vQQKLQj07oNrJryo/wK2G0ndNaoVn2ownFMeoeAuReu3Q==" }, - "packages/prisma/node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } + "packages/prisma/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true }, "packages/prisma/node_modules/zod-prisma-types": { "version": "3.1.9", @@ -35639,7 +35601,7 @@ "@types/react": "^18", "@types/react-dom": "^18", "react": "^18", - "typescript": "5.2.2" + "typescript": "5.6.2" } }, "packages/ui/node_modules/react-pdf": { @@ -35678,19 +35640,6 @@ "engines": { "node": ">=6" } - }, - "packages/ui/node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } } } } diff --git a/package.json b/package.json index 3f53e3842..015d079e4 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "dependencies": { "@documenso/pdf-sign": "^0.1.0", "@documenso/prisma": "^0.0.0", + "typescript": "5.6.2", "@lingui/core": "^4.11.3", "inngest-cli": "^0.29.1", "luxon": "^3.5.0", @@ -80,4 +81,4 @@ "trigger.dev": { "endpointId": "documenso-app" } -} +} \ No newline at end of file diff --git a/packages/api/v1/implementation.ts b/packages/api/v1/implementation.ts index c3e5da673..0f13150c7 100644 --- a/packages/api/v1/implementation.ts +++ b/packages/api/v1/implementation.ts @@ -1053,12 +1053,12 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, { .with('TEXT', () => ZTextFieldMeta.safeParse(fieldMeta)) .with('SIGNATURE', 'INITIALS', 'DATE', 'EMAIL', 'NAME', () => ({ success: true, - data: {}, + data: undefined, })) .with('FREE_SIGNATURE', () => ({ success: false, error: 'FREE_SIGNATURE is not supported', - data: {}, + data: undefined, })) .exhaustive(); diff --git a/packages/app-tests/e2e/templates/create-document-from-template.spec.ts b/packages/app-tests/e2e/templates/create-document-from-template.spec.ts index 8f5038d6a..7e5219390 100644 --- a/packages/app-tests/e2e/templates/create-document-from-template.spec.ts +++ b/packages/app-tests/e2e/templates/create-document-from-template.spec.ts @@ -27,7 +27,7 @@ function createTempPdfFile() { '%PDF-1.4\n1 0 obj<>endobj 2 0 obj<>endobj 3 0 obj<>endobj\nxref\n0 4\n0000000000 65535 f\n0000000009 00000 n\n0000000052 00000 n\n0000000101 00000 n\ntrailer<>\nstartxref\n178\n%%EOF', ); - fs.writeFileSync(tempFilePath, pdfContent); + fs.writeFileSync(tempFilePath, new Uint8Array(pdfContent)); return tempFilePath; } diff --git a/packages/app-tests/package.json b/packages/app-tests/package.json index a5d809e39..2b0bd3468 100644 --- a/packages/app-tests/package.json +++ b/packages/app-tests/package.json @@ -13,7 +13,7 @@ "author": "", "devDependencies": { "@playwright/test": "^1.18.1", - "@types/node": "^20.8.2", + "@types/node": "^20", "@documenso/lib": "*", "@documenso/prisma": "*", "@documenso/web": "*", diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index 4d25e1bd8..6049dd7c7 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -15,6 +15,6 @@ "eslint-plugin-package-json": "^0.10.4", "eslint-plugin-react": "^7.34.0", "eslint-plugin-unused-imports": "^3.1.0", - "typescript": "5.2.2" + "typescript": "5.6.2" } -} +} \ No newline at end of file diff --git a/packages/lib/server-only/2fa/setup-2fa.ts b/packages/lib/server-only/2fa/setup-2fa.ts index cc08510d0..b5ae47861 100644 --- a/packages/lib/server-only/2fa/setup-2fa.ts +++ b/packages/lib/server-only/2fa/setup-2fa.ts @@ -33,7 +33,7 @@ export const setupTwoFactorAuthentication = async ({ const accountName = user.email; const uri = createTOTPKeyURI(ISSUER, accountName, secret); - const encodedSecret = base32.encode(secret); + const encodedSecret = base32.encode(new Uint8Array(secret)); await prisma.user.update({ where: { diff --git a/packages/lib/server-only/field/update-field.ts b/packages/lib/server-only/field/update-field.ts index fb806ecf0..baf04bca8 100644 --- a/packages/lib/server-only/field/update-field.ts +++ b/packages/lib/server-only/field/update-field.ts @@ -65,11 +65,6 @@ export const updateField = async ({ }, }); - const newFieldMeta = { - ...(oldField.fieldMeta as FieldMeta), - ...fieldMeta, - }; - const field = prisma.$transaction(async (tx) => { const updatedField = await tx.field.update({ where: { @@ -83,7 +78,7 @@ export const updateField = async ({ positionY: pageY, width: pageWidth, height: pageHeight, - fieldMeta: newFieldMeta, + fieldMeta, }, include: { recipient: true, diff --git a/packages/lib/types/document-form-values.ts b/packages/lib/types/document-form-values.ts new file mode 100644 index 000000000..90dc19e36 --- /dev/null +++ b/packages/lib/types/document-form-values.ts @@ -0,0 +1,8 @@ +import { z } from 'zod'; + +export const ZDocumentFormValuesSchema = z.record( + z.string(), + z.union([z.string(), z.boolean(), z.number()]), +); + +export type TDocumentFormValues = z.infer; diff --git a/packages/lib/types/field-meta.ts b/packages/lib/types/field-meta.ts index 135edc95d..5d4835b74 100644 --- a/packages/lib/types/field-meta.ts +++ b/packages/lib/types/field-meta.ts @@ -9,36 +9,36 @@ export const ZBaseFieldMeta = z.object({ export type TBaseFieldMeta = z.infer; -export const ZInitialsFieldMeta = z.object({ - type: z.literal('initials').default('initials'), +export const ZInitialsFieldMeta = ZBaseFieldMeta.extend({ + type: z.literal('initials'), fontSize: z.number().min(8).max(96).optional(), }); export type TInitialsFieldMeta = z.infer; -export const ZNameFieldMeta = z.object({ - type: z.literal('name').default('name'), +export const ZNameFieldMeta = ZBaseFieldMeta.extend({ + type: z.literal('name'), fontSize: z.number().min(8).max(96).optional(), }); export type TNameFieldMeta = z.infer; -export const ZEmailFieldMeta = z.object({ - type: z.literal('email').default('email'), +export const ZEmailFieldMeta = ZBaseFieldMeta.extend({ + type: z.literal('email'), fontSize: z.number().min(8).max(96).optional(), }); export type TEmailFieldMeta = z.infer; -export const ZDateFieldMeta = z.object({ - type: z.literal('date').default('date'), +export const ZDateFieldMeta = ZBaseFieldMeta.extend({ + type: z.literal('date'), fontSize: z.number().min(8).max(96).optional(), }); export type TDateFieldMeta = z.infer; export const ZTextFieldMeta = ZBaseFieldMeta.extend({ - type: z.literal('text').default('text'), + type: z.literal('text'), text: z.string().optional(), characterLimit: z.number().optional(), fontSize: z.number().min(8).max(96).optional(), @@ -47,7 +47,7 @@ export const ZTextFieldMeta = ZBaseFieldMeta.extend({ export type TTextFieldMeta = z.infer; export const ZNumberFieldMeta = ZBaseFieldMeta.extend({ - type: z.literal('number').default('number'), + type: z.literal('number'), numberFormat: z.string().optional(), value: z.string().optional(), minValue: z.number().optional(), @@ -58,7 +58,7 @@ export const ZNumberFieldMeta = ZBaseFieldMeta.extend({ export type TNumberFieldMeta = z.infer; export const ZRadioFieldMeta = ZBaseFieldMeta.extend({ - type: z.literal('radio').default('radio'), + type: z.literal('radio'), values: z .array( z.object({ @@ -73,7 +73,7 @@ export const ZRadioFieldMeta = ZBaseFieldMeta.extend({ export type TRadioFieldMeta = z.infer; export const ZCheckboxFieldMeta = ZBaseFieldMeta.extend({ - type: z.literal('checkbox').default('checkbox'), + type: z.literal('checkbox'), values: z .array( z.object({ @@ -90,30 +90,27 @@ export const ZCheckboxFieldMeta = ZBaseFieldMeta.extend({ export type TCheckboxFieldMeta = z.infer; export const ZDropdownFieldMeta = ZBaseFieldMeta.extend({ - type: z.literal('dropdown').default('dropdown'), + type: z.literal('dropdown'), values: z.array(z.object({ value: z.string() })).optional(), defaultValue: z.string().optional(), }); export type TDropdownFieldMeta = z.infer; -/** - * This will parse empty objects to { "type": "initials" } - * - * Todo: Fix. - */ -export const ZFieldMetaSchema = z - .union([ - ZBaseFieldMeta.extend(ZInitialsFieldMeta.shape), - ZBaseFieldMeta.extend(ZNameFieldMeta.shape), - ZBaseFieldMeta.extend(ZEmailFieldMeta.shape), - ZBaseFieldMeta.extend(ZDateFieldMeta.shape), - ZTextFieldMeta, - ZNumberFieldMeta, - ZRadioFieldMeta, - ZCheckboxFieldMeta, - ZDropdownFieldMeta, - ]) - .optional(); +export const ZFieldMetaNotOptionalSchema = z.discriminatedUnion('type', [ + ZInitialsFieldMeta, + ZNameFieldMeta, + ZEmailFieldMeta, + ZDateFieldMeta, + ZTextFieldMeta, + ZNumberFieldMeta, + ZRadioFieldMeta, + ZCheckboxFieldMeta, + ZDropdownFieldMeta, +]); + +export type TFieldMetaNotOptionalSchema = z.infer; + +export const ZFieldMetaSchema = ZFieldMetaNotOptionalSchema.optional(); export type TFieldMetaSchema = z.infer; diff --git a/packages/prisma/index.ts b/packages/prisma/index.ts index 6851111d3..b9c1600b7 100644 --- a/packages/prisma/index.ts +++ b/packages/prisma/index.ts @@ -1,3 +1,4 @@ +/// import { PrismaClient } from '@prisma/client'; import { Kysely, PostgresAdapter, PostgresIntrospector, PostgresQueryCompiler } from 'kysely'; import kyselyExtension from 'prisma-extension-kysely'; diff --git a/packages/prisma/package.json b/packages/prisma/package.json index c78e5a18c..5cc8497a6 100644 --- a/packages/prisma/package.json +++ b/packages/prisma/package.json @@ -30,9 +30,10 @@ "devDependencies": { "dotenv": "^16.3.1", "dotenv-cli": "^7.3.0", + "prisma-json-types-generator": "^3.2.2", "prisma-kysely": "^1.8.0", "tsx": "^4.11.0", - "typescript": "5.2.2", + "typescript": "5.6.2", "zod-prisma-types": "3.1.9" } } \ No newline at end of file diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index a65692f37..013ab034e 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -6,6 +6,10 @@ generator client { provider = "prisma-client-js" } +generator json { + provider = "prisma-json-types-generator" +} + generator zod { provider = "zod-prisma-types" createInputTypes = false @@ -297,14 +301,14 @@ enum DocumentVisibility { ADMIN } -/// @zod.import(["import { ZDocumentAuthOptionsSchema } from '@documenso/lib/types/document-auth';"]) +/// @zod.import(["import { ZDocumentAuthOptionsSchema } from '@documenso/lib/types/document-auth';", "import { ZDocumentFormValuesSchema } from '@documenso/lib/types/document-form-values';"]) model Document { id Int @id @default(autoincrement()) externalId String? /// @zod.string.describe("A custom external ID you can use to identify the document.") userId Int /// @zod.number.describe("The ID of the user that created this document.") user User @relation(fields: [userId], references: [id], onDelete: Cascade) - authOptions Json? /// Todo: zod.custom.use(ZDocumentAuthOptionsSchema.describe("Hello")) - formValues Json? + authOptions Json? /// [DocumentAuthOptions] @zod.custom.use(ZDocumentAuthOptionsSchema) + formValues Json? /// [DocumentFormValues] @zod.custom.use(ZDocumentFormValuesSchema) visibility DocumentVisibility @default(EVERYONE) title String status DocumentStatus @default(DRAFT) @@ -373,6 +377,7 @@ enum DocumentDistributionMethod { NONE } +/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';"]) model DocumentMeta { id String @id @default(cuid()) subject String? @@ -387,7 +392,7 @@ model DocumentMeta { typedSignatureEnabled Boolean @default(true) language String @default("en") distributionMethod DocumentDistributionMethod @default(EMAIL) - emailSettings Json? + emailSettings Json? /// [DocumentEmailSettings] @zod.custom.use(ZDocumentEmailSettingsSchema) } enum ReadStatus { @@ -424,7 +429,7 @@ model Recipient { documentDeletedAt DateTime? expired DateTime? signedAt DateTime? - authOptions Json? /// Todo: zod.custom.use(ZRecipientAuthOptionsSchema) + authOptions Json? /// [RecipientAuthOptions] @zod.custom.use(ZRecipientAuthOptionsSchema) signingOrder Int? /// @zod.number.describe("The order in which the recipient should sign the document. Only works if the document is set to sequential signing.") rejectionReason String? role RecipientRole @default(SIGNER) @@ -457,6 +462,7 @@ enum FieldType { DROPDOWN } +/// @zod.import(["import { ZFieldMetaNotOptionalSchema } from '@documenso/lib/types/field-meta';"]) model Field { id Int @id @default(autoincrement()) secondaryId String @unique @default(cuid()) @@ -475,7 +481,7 @@ model Field { template Template? @relation(fields: [templateId], references: [id], onDelete: Cascade) recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade) signature Signature? - fieldMeta Json? // Todo: Fix ZFieldMetaSchema before using it here. + fieldMeta Json? /// [FieldMeta] @zod.custom.use(ZFieldMetaNotOptionalSchema) @@index([documentId]) @@index([templateId]) @@ -640,6 +646,7 @@ enum TemplateType { PRIVATE } +/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';"]) model TemplateMeta { id String @id @default(cuid()) subject String? @@ -655,9 +662,10 @@ model TemplateMeta { template Template @relation(fields: [templateId], references: [id], onDelete: Cascade) redirectUrl String? language String @default("en") - emailSettings Json? + emailSettings Json? /// [DocumentEmailSettings] @zod.custom.use(ZDocumentEmailSettingsSchema) } +/// @zod.import(["import { ZDocumentAuthOptionsSchema } from '@documenso/lib/types/document-auth';"]) model Template { id Int @id @default(autoincrement()) externalId String? @@ -666,7 +674,7 @@ model Template { userId Int teamId Int? visibility DocumentVisibility @default(EVERYONE) - authOptions Json? + authOptions Json? /// [DocumentAuthOptions] @zod.custom.use(ZDocumentAuthOptionsSchema) templateMeta TemplateMeta? templateDocumentDataId String createdAt DateTime @default(now()) diff --git a/packages/prisma/types/types.d.ts b/packages/prisma/types/types.d.ts new file mode 100644 index 000000000..4cdd6278b --- /dev/null +++ b/packages/prisma/types/types.d.ts @@ -0,0 +1,25 @@ +/* eslint-disable @typescript-eslint/no-namespace */ +import type { + TDocumentAuthOptions, + TRecipientAuthOptions, +} from '@documenso/lib/types/document-auth'; +import type { TDocumentEmailSettings } from '@documenso/lib/types/document-email'; +import type { TDocumentFormValues } from '@documenso/lib/types/document-form-values'; +import type { TFieldMetaNotOptionalSchema } from '@documenso/lib/types/field-meta'; + +/** + * Global types for Prisma.Json instances. + */ +declare global { + namespace PrismaJson { + type DocumentFormValues = TDocumentFormValues; + type DocumentAuthOptions = TDocumentAuthOptions; + type DocumentEmailSettings = TDocumentEmailSettings; + + type RecipientAuthOptions = TRecipientAuthOptions; + + type FieldMeta = TFieldMetaNotOptionalSchema; + } +} + +export {}; diff --git a/packages/signing/helpers/update-signing-placeholder.ts b/packages/signing/helpers/update-signing-placeholder.ts index c0c95f859..18875737d 100644 --- a/packages/signing/helpers/update-signing-placeholder.ts +++ b/packages/signing/helpers/update-signing-placeholder.ts @@ -26,9 +26,9 @@ export const updateSigningPlaceholder = ({ pdf }: UpdateSigningPlaceholderOption const newByteRange = `[${byteRange.join(' ')}]`.padEnd(byteRangeSlice.length, ' '); const updatedPdf = Buffer.concat([ - pdf.subarray(0, byteRangeStart), - Buffer.from(newByteRange), - pdf.subarray(byteRangeEnd + 1), + new Uint8Array(pdf.subarray(0, byteRangeStart)), + new Uint8Array(Buffer.from(newByteRange)), + new Uint8Array(pdf.subarray(byteRangeEnd + 1)), ]); if (updatedPdf.length !== length) { diff --git a/packages/signing/transports/google-cloud-hsm.ts b/packages/signing/transports/google-cloud-hsm.ts index b327c7901..000ee80c5 100644 --- a/packages/signing/transports/google-cloud-hsm.ts +++ b/packages/signing/transports/google-cloud-hsm.ts @@ -23,13 +23,14 @@ export const signWithGoogleCloudHSM = async ({ pdf }: SignWithGoogleCloudHSMOpti process.env.NEXT_PRIVATE_SIGNING_GCLOUD_APPLICATION_CREDENTIALS_CONTENTS ) { if (!fs.existsSync(process.env.GOOGLE_APPLICATION_CREDENTIALS)) { - fs.writeFileSync( - process.env.GOOGLE_APPLICATION_CREDENTIALS, + const contents = new Uint8Array( Buffer.from( process.env.NEXT_PRIVATE_SIGNING_GCLOUD_APPLICATION_CREDENTIALS_CONTENTS, 'base64', ), ); + + fs.writeFileSync(process.env.GOOGLE_APPLICATION_CREDENTIALS, contents); } } @@ -38,8 +39,8 @@ export const signWithGoogleCloudHSM = async ({ pdf }: SignWithGoogleCloudHSMOpti }); const pdfWithoutSignature = Buffer.concat([ - pdfWithPlaceholder.subarray(0, byteRange[1]), - pdfWithPlaceholder.subarray(byteRange[2]), + new Uint8Array(pdfWithPlaceholder.subarray(0, byteRange[1])), + new Uint8Array(pdfWithPlaceholder.subarray(byteRange[2])), ]); const signatureLength = byteRange[2] - byteRange[1]; @@ -70,9 +71,9 @@ export const signWithGoogleCloudHSM = async ({ pdf }: SignWithGoogleCloudHSMOpti const signatureAsHex = signature.toString('hex'); const signedPdf = Buffer.concat([ - pdfWithPlaceholder.subarray(0, byteRange[1]), - Buffer.from(`<${signatureAsHex.padEnd(signatureLength - 2, '0')}>`), - pdfWithPlaceholder.subarray(byteRange[2]), + new Uint8Array(pdfWithPlaceholder.subarray(0, byteRange[1])), + new Uint8Array(Buffer.from(`<${signatureAsHex.padEnd(signatureLength - 2, '0')}>`)), + new Uint8Array(pdfWithPlaceholder.subarray(byteRange[2])), ]); return signedPdf; diff --git a/packages/signing/transports/local-cert.ts b/packages/signing/transports/local-cert.ts index 7ed2f5f8b..6b88288b6 100644 --- a/packages/signing/transports/local-cert.ts +++ b/packages/signing/transports/local-cert.ts @@ -15,8 +15,8 @@ export const signWithLocalCert = async ({ pdf }: SignWithLocalCertOptions) => { }); const pdfWithoutSignature = Buffer.concat([ - pdfWithPlaceholder.subarray(0, byteRange[1]), - pdfWithPlaceholder.subarray(byteRange[2]), + new Uint8Array(pdfWithPlaceholder.subarray(0, byteRange[1])), + new Uint8Array(pdfWithPlaceholder.subarray(byteRange[2])), ]); const signatureLength = byteRange[2] - byteRange[1]; @@ -51,9 +51,9 @@ export const signWithLocalCert = async ({ pdf }: SignWithLocalCertOptions) => { const signatureAsHex = signature.toString('hex'); const signedPdf = Buffer.concat([ - pdfWithPlaceholder.subarray(0, byteRange[1]), - Buffer.from(`<${signatureAsHex.padEnd(signatureLength - 2, '0')}>`), - pdfWithPlaceholder.subarray(byteRange[2]), + new Uint8Array(pdfWithPlaceholder.subarray(0, byteRange[1])), + new Uint8Array(Buffer.from(`<${signatureAsHex.padEnd(signatureLength - 2, '0')}>`)), + new Uint8Array(pdfWithPlaceholder.subarray(byteRange[2])), ]); return signedPdf; diff --git a/packages/ui/package.json b/packages/ui/package.json index 858edca87..6fe04365f 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -23,7 +23,7 @@ "@types/react": "^18", "@types/react-dom": "^18", "react": "^18", - "typescript": "5.2.2" + "typescript": "5.6.2" }, "dependencies": { "@documenso/lib": "*",