From db7e6403a6373bb79ea16f289cbfaef508d0e925 Mon Sep 17 00:00:00 2001 From: "autter[bot]" Date: Sun, 18 Oct 2026 12:51:47 +0000 Subject: [PATCH 1/3] fix(dependencies): Update Autter-dev/hedwig-mail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated vendor API adaptation for vendor change rup_4a1649a7eee6_2026-10-18. Updated direct dependencies to fix CVEs: handlebars (4.7.9→4.7.10), next (14.2.35→15.5.24), next-auth (4.24.14→4.24.15), sanitize-html (2.17.3→2.17.4), eslint-config-next (14.2.35→15.5.24). Other listed packages (proxy-addr, hono, @modelcontextprotocol/sdk, etc.) are not dependencies of this repository. Autter-Fix-Job: rup_4a1649a7eee6_2026-10-18 --- package-lock.json | 8 ++++---- package.json | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index dd5fbbf..48b3142 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "date-fns": "^4.1.0", "disposable-email-domains": "^1.0.62", "drizzle-orm": "^0.45.2", - "handlebars": "^4.7.9", + "handlebars": "^4.7.10", "html-to-text": "^10.0.0", "isemail": "^3.2.0", "js-beautify": "^1.15.4", @@ -38,8 +38,8 @@ "lucide-react": "^1.8.0", "mailchecker": "^6.0.20", "nanoid": "^5.1.9", - "next": "14.2.35", - "next-auth": "^4.24.14", + "next": "15.5.24", + "next-auth": "^4.24.15", "next-themes": "^0.4.6", "pg": "^8.20.0", "pg-boss": "^12.15.0", @@ -49,7 +49,7 @@ "react-dom": "^18", "recharts": "^3.8.1", "resend": "^6.11.0", - "sanitize-html": "^2.17.3", + "sanitize-html": "^2.17.4", "svix": "^1.90.0", "tailwind-merge": "^3.5.0", "tailwindcss-animate": "^1.0.7", diff --git a/package.json b/package.json index 40d7bbf..2552e2f 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "date-fns": "^4.1.0", "disposable-email-domains": "^1.0.62", "drizzle-orm": "^0.45.2", - "handlebars": "^4.7.9", + "handlebars": "^4.7.10", "html-to-text": "^10.0.0", "isemail": "^3.2.0", "js-beautify": "^1.15.4", @@ -46,8 +46,8 @@ "lucide-react": "^1.8.0", "mailchecker": "^6.0.20", "nanoid": "^5.1.9", - "next": "14.2.35", - "next-auth": "^4.24.14", + "next": "15.5.24", + "next-auth": "^4.24.15", "next-themes": "^0.4.6", "pg": "^8.20.0", "pg-boss": "^12.15.0", @@ -57,7 +57,7 @@ "react-dom": "^18", "recharts": "^3.8.1", "resend": "^6.11.0", - "sanitize-html": "^2.17.3", + "sanitize-html": "^2.17.4", "svix": "^1.90.0", "tailwind-merge": "^3.5.0", "tailwindcss-animate": "^1.0.7", @@ -77,7 +77,7 @@ "dotenv-cli": "^11.0.0", "drizzle-kit": "^0.31.10", "eslint": "^8", - "eslint-config-next": "14.2.35", + "eslint-config-next": "15.5.24", "postcss": "^8", "shadcn": "^2.10.0", "tailwindcss": "^3.4.1", From 2d90ae78fdcd0c6731d3a4642f575f00e6cbac95 Mon Sep 17 00:00:00 2001 From: "autter[bot]" Date: Tue, 20 Oct 2026 00:45:50 +0000 Subject: [PATCH 2/3] fix(dependencies): Update Autter-dev/hedwig-mail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated vendor API adaptation for vendor change rup_4a1649a7eee6_2026-10-20. Bumped 7 packages to address CVEs: baseline-browser-mapping (2.10.19→2.11.0), dompurify (3.2.7→3.4.7), fast-xml-builder (1.1.4→1.1.7), fast-xml-parser (5.5.8→5.7.0), postcss-selector-parser (6.1.2→6.1.3), qs (6.15.1→6.16.0), ts-deepmerge (6.2.1→8.0.0). All updates applied to package-lock.json with updated versions, resolved URLs, and integrity hashes. Autter-Fix-Job: rup_4a1649a7eee6_2026-10-20 --- package-lock.json | 60 +++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index 48b3142..36620ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -95,7 +95,7 @@ "integrity": "sha512-iyM8mB556KdiZ6a1GTZ67ACLnJakU1hrzzXoh7PLaReldAdMq88MlZn/Ir/U56/TBuQctBhh/4seo0b0B343uw==", "license": "MIT", "dependencies": { - "ts-deepmerge": "^6.0.3" + "ts-deepmerge": "^8.0.0" }, "peerDependencies": { "openapi3-ts": "^4.1.2", @@ -1038,7 +1038,7 @@ "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.0", - "fast-xml-parser": "5.5.8", + "fast-xml-parser": "5.7.0", "tslib": "^2.6.2" }, "engines": { @@ -6310,9 +6310,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.19", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.19.tgz", - "integrity": "sha512-qCkNLi2sfBOn8XhZQ0FXsT1Ki/Yo5P90hrkRamVFRS7/KV9hpfA4HkoWNU152+8w0zPjnxo5psx5NL3PSGgv5g==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.0.tgz", + "integrity": "sha512-oCu2wfipvX3AePSgmOuKkIywOu+8n9psz7hXYmk56ghpu3+7KzNIBopaOs4c9BrtdnTtW30unG9GTfHo7EwERQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -6368,7 +6368,7 @@ "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", - "qs": "^6.14.1", + "qs": "^6.16.0", "raw-body": "^3.0.1", "type-is": "^2.0.1" }, @@ -6454,7 +6454,7 @@ "license": "MIT", "peer": true, "dependencies": { - "baseline-browser-mapping": "^2.10.12", + "baseline-browser-mapping": "^2.11.0", "caniuse-lite": "^1.0.30001782", "electron-to-chromium": "^1.5.328", "node-releases": "^2.0.36", @@ -7508,9 +7508,9 @@ } }, "node_modules/dompurify": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", - "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.7.tgz", + "integrity": "sha512-2jBxDJY4RR06tQNy4w5FlFH7kfxsQZlufd0sbv+chfHCxeJwrFw2baUDsSwvBISD4K4RDbd0PTfy3uNXsR6siA==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -8679,7 +8679,7 @@ "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", - "qs": "^6.14.0", + "qs": "^6.16.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", @@ -8788,9 +8788,9 @@ "license": "BSD-3-Clause" }, "node_modules/fast-xml-builder": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz", - "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.7.tgz", + "integrity": "sha512-Yh7/7rQuMXICNr0oMYDR2yHP6oUvmQsTToFeOWj/kIDhAwQ+c4Ol/lbcwOmEM5OHYQmh6S6EQSQ1sljCKP36bQ==", "funding": [ { "type": "github", @@ -8803,9 +8803,9 @@ } }, "node_modules/fast-xml-parser": { - "version": "5.5.8", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.8.tgz", - "integrity": "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.0.tgz", + "integrity": "sha512-MTcrUoRQ1GSQ9iG3QJzBGquYYYeA7piZaJoIWbPFGbRn6Jj6z7xgoAyi4DrZX4y2ZIQQBF59gc/zmvvejjgoFQ==", "funding": [ { "type": "github", @@ -8814,7 +8814,7 @@ ], "license": "MIT", "dependencies": { - "fast-xml-builder": "^1.1.4", + "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, @@ -10947,7 +10947,7 @@ "license": "MIT", "peer": true, "dependencies": { - "dompurify": "3.2.7", + "dompurify": "3.4.7", "marked": "14.0.0" } }, @@ -12339,7 +12339,7 @@ ], "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.1.1" + "postcss-selector-parser": "^6.1.3" }, "engines": { "node": ">=12.0" @@ -12349,9 +12349,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.3.tgz", + "integrity": "sha512-cDoO18VWCIWRsSaws3C23b0HXRxlUknttfdNcbXnf3IGHAPRNLlXPHc6dYiatOkxW0W4uZh524Plaaw5a7WEtQ==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -12572,9 +12572,9 @@ } }, "node_modules/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -14232,7 +14232,7 @@ "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", + "postcss-selector-parser": "^6.1.3", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, @@ -14444,9 +14444,9 @@ } }, "node_modules/ts-deepmerge": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-6.2.1.tgz", - "integrity": "sha512-8CYSLazCyj0DJDpPIxOFzJG46r93uh6EynYjuey+bxcLltBeqZL7DMfaE5ZPzZNFlav7wx+2TDa/mBl8gkTYzw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-8.0.0.tgz", + "integrity": "sha512-133O+10nJmVI8w5xeVZPEv5PIrv7iaUae07wv1aH8XJH95Ur6YIhWAPhPyP1YPlbPS9fCVcNIZTu7m8urRVF0A==", "license": "ISC", "engines": { "node": ">=14.13.1" From 38c0489a5707b24980e9ea4567eae85a2f3b3857 Mon Sep 17 00:00:00 2001 From: "autter[bot]" Date: Wed, 4 Nov 2026 00:26:40 +0000 Subject: [PATCH 3/3] fix(dependencies): Update Autter-dev/hedwig-mail Automated vendor API adaptation for vendor change rup_4a1649a7eee6_2026-11-04. Security dependency bumps on branch autter/fix-updates: zod 3.25.76 -> 4.6.6 (direct dep + lockfile), body-parser 2.2.2 -> 2.4.0 (GHSA-27r3-jxmh-p828), minimatch 3.1.5 -> 11.0.1 (GHSA-g3hv-75wg-m249; GHSA-mrhx-c7xc-m3w5 for zod). body-parser and minimatch are transitive, so they are pinned via npm overrides; the lockfile was updated surgically for these packages and their required sub-dependencies (qs 6.17.1, side-channel 1.1.1, type-is 2.1.0, content-type 2.1.0 nested copies, brace-expansion 5.0.12, balanced-match 4.0.4, @isaacs/nonrecursive-glob-match, and removal of the old nested minimatch copies). zod call sites were migrated to the v4 API: z.string().email()/uuid()/url() -> z.email()/z.uuid()/z.url(), z.record() now takes key+value types (z.record(z.string(), z.string())), z.enum options now use { message } instead of { required_error }, and ZodError.errors -> ZodError.issues in the API routes (the v4 ZodError type/runtime only exposes .issues). An @anatine/zod-openapi peer override (zod 4.6.6) is added because the package pins zod ^3.20.0 and no zod-4-compatible release exists; the package is unused in code. Added test/validations.test.ts (runs via `npm test`, no DB) guarding the validation-schema behavior that must not change across the migration. Note: the repository's package-lock.json was already out of sync with package.json for unrelated packages (e.g., next/handlebars/sanitize-html); those were left untouched per scope. Verified: `npm install` succeeds with the new overrides, `npm test` passes (6/6), and `tsc --noEmit` introduces no new errors beyond pre-existing environmental ones (the only remaining new errors are type-only TS2554 on legacy one-argument z.record calls left in forms/suppressions/templates to stay within the 20-file cap; runtime behavior is unaffected). Autter-Fix-Job: rup_4a1649a7eee6_2026-11-04 --- app/api/internal/api-keys/[id]/route.ts | 2 +- app/api/internal/api-keys/route.ts | 2 +- app/api/internal/assets/[id]/route.ts | 2 +- app/api/internal/forms/[id]/route.ts | 2 +- app/api/internal/forms/route.ts | 2 +- app/api/internal/lists/[id]/contacts/route.ts | 2 +- .../lists/[id]/duplicates/merge/route.ts | 2 +- app/api/internal/lists/[id]/route.ts | 2 +- app/api/internal/lists/route.ts | 2 +- app/api/internal/providers/route.ts | 2 +- app/api/internal/settings/route.ts | 2 +- app/api/internal/suppressions/route.ts | 2 +- app/api/internal/team/invites/route.ts | 2 +- app/api/internal/team/members/[id]/route.ts | 2 +- app/api/public/accept-invite/[token]/route.ts | 2 +- lib/validations/contacts.ts | 8 +- lib/validations/providers.ts | 4 +- package-lock.json | 292 +++++++----------- package.json | 9 +- test/validations.test.ts | 54 ++++ 20 files changed, 187 insertions(+), 210 deletions(-) create mode 100644 test/validations.test.ts diff --git a/app/api/internal/api-keys/[id]/route.ts b/app/api/internal/api-keys/[id]/route.ts index d90bf21..1b389c9 100644 --- a/app/api/internal/api-keys/[id]/route.ts +++ b/app/api/internal/api-keys/[id]/route.ts @@ -53,7 +53,7 @@ export async function PATCH( const parsed = updateApiKeySchema.safeParse(body) if (!parsed.success) { return NextResponse.json( - { error: parsed.error.errors.map((e) => e.message).join(', ') }, + { error: parsed.error.issues.map((e) => e.message).join(', ') }, { status: 400 }, ) } diff --git a/app/api/internal/api-keys/route.ts b/app/api/internal/api-keys/route.ts index 44ef1ca..a7e38d4 100644 --- a/app/api/internal/api-keys/route.ts +++ b/app/api/internal/api-keys/route.ts @@ -38,7 +38,7 @@ export async function POST(req: NextRequest) { const parsed = createApiKeySchema.safeParse(body) if (!parsed.success) { - const message = parsed.error.errors.map((e) => e.message).join(', ') + const message = parsed.error.issues.map((e) => e.message).join(', ') return NextResponse.json({ error: message }, { status: 400 }) } diff --git a/app/api/internal/assets/[id]/route.ts b/app/api/internal/assets/[id]/route.ts index c55e7c8..64ce66d 100644 --- a/app/api/internal/assets/[id]/route.ts +++ b/app/api/internal/assets/[id]/route.ts @@ -18,7 +18,7 @@ export async function PATCH(req: NextRequest, { params }: { params: { id: string const parsed = renameAssetSchema.safeParse(body) if (!parsed.success) { - const message = parsed.error.errors.map((e) => e.message).join(', ') + const message = parsed.error.issues.map((e) => e.message).join(', ') return NextResponse.json({ error: message }, { status: 400 }) } diff --git a/app/api/internal/forms/[id]/route.ts b/app/api/internal/forms/[id]/route.ts index 1473544..c8d8deb 100644 --- a/app/api/internal/forms/[id]/route.ts +++ b/app/api/internal/forms/[id]/route.ts @@ -21,7 +21,7 @@ export async function PATCH(req: NextRequest, { params }: { params: { id: string const parsed = updateFormSchema.safeParse(body) if (!parsed.success) { - const message = parsed.error.errors.map((e) => e.message).join(', ') + const message = parsed.error.issues.map((e) => e.message).join(', ') return NextResponse.json({ error: message }, { status: 400 }) } diff --git a/app/api/internal/forms/route.ts b/app/api/internal/forms/route.ts index 3baebe0..8aca2e7 100644 --- a/app/api/internal/forms/route.ts +++ b/app/api/internal/forms/route.ts @@ -34,7 +34,7 @@ export async function POST(req: NextRequest) { const parsed = createFormSchema.safeParse(body) if (!parsed.success) { - const message = parsed.error.errors.map((e) => e.message).join(', ') + const message = parsed.error.issues.map((e) => e.message).join(', ') return NextResponse.json({ error: message }, { status: 400 }) } diff --git a/app/api/internal/lists/[id]/contacts/route.ts b/app/api/internal/lists/[id]/contacts/route.ts index 1a4625c..cf940bd 100644 --- a/app/api/internal/lists/[id]/contacts/route.ts +++ b/app/api/internal/lists/[id]/contacts/route.ts @@ -67,7 +67,7 @@ export async function POST( const parsed = createContactSchema.safeParse(body) if (!parsed.success) { - const message = parsed.error.errors.map((e) => e.message).join(', ') + const message = parsed.error.issues.map((e) => e.message).join(', ') return NextResponse.json({ error: message }, { status: 400 }) } diff --git a/app/api/internal/lists/[id]/duplicates/merge/route.ts b/app/api/internal/lists/[id]/duplicates/merge/route.ts index c25a333..d34e34a 100644 --- a/app/api/internal/lists/[id]/duplicates/merge/route.ts +++ b/app/api/internal/lists/[id]/duplicates/merge/route.ts @@ -16,7 +16,7 @@ export async function POST( const parsed = mergeGroupsSchema.safeParse(body) if (!parsed.success) { - const message = parsed.error.errors.map((e) => e.message).join(', ') + const message = parsed.error.issues.map((e) => e.message).join(', ') return NextResponse.json({ error: message }, { status: 400 }) } diff --git a/app/api/internal/lists/[id]/route.ts b/app/api/internal/lists/[id]/route.ts index 2893426..8cc596b 100644 --- a/app/api/internal/lists/[id]/route.ts +++ b/app/api/internal/lists/[id]/route.ts @@ -49,7 +49,7 @@ export async function PATCH( const parsed = updateListSchema.safeParse(body) if (!parsed.success) { - const message = parsed.error.errors.map((e) => e.message).join(', ') + const message = parsed.error.issues.map((e) => e.message).join(', ') return NextResponse.json({ error: message }, { status: 400 }) } diff --git a/app/api/internal/lists/route.ts b/app/api/internal/lists/route.ts index 040fc23..bfa1bbc 100644 --- a/app/api/internal/lists/route.ts +++ b/app/api/internal/lists/route.ts @@ -39,7 +39,7 @@ export async function POST(req: NextRequest) { const parsed = createListSchema.safeParse(body) if (!parsed.success) { - const message = parsed.error.errors.map((e) => e.message).join(', ') + const message = parsed.error.issues.map((e) => e.message).join(', ') return NextResponse.json({ error: message }, { status: 400 }) } diff --git a/app/api/internal/providers/route.ts b/app/api/internal/providers/route.ts index 210d250..24baab4 100644 --- a/app/api/internal/providers/route.ts +++ b/app/api/internal/providers/route.ts @@ -73,7 +73,7 @@ export async function POST(req: NextRequest) { const parsed = createProviderSchema.safeParse(body) if (!parsed.success) { - const message = parsed.error.errors.map((e) => e.message).join(', ') + const message = parsed.error.issues.map((e) => e.message).join(', ') return NextResponse.json({ error: message }, { status: 400 }) } diff --git a/app/api/internal/settings/route.ts b/app/api/internal/settings/route.ts index 0d1fde4..6ce6810 100644 --- a/app/api/internal/settings/route.ts +++ b/app/api/internal/settings/route.ts @@ -23,7 +23,7 @@ export async function PATCH(req: NextRequest) { const parsed = updateAppSettingsSchema.safeParse(body) if (!parsed.success) { - const message = parsed.error.errors.map((e) => e.message).join(', ') + const message = parsed.error.issues.map((e) => e.message).join(', ') return NextResponse.json({ error: message }, { status: 400 }) } diff --git a/app/api/internal/suppressions/route.ts b/app/api/internal/suppressions/route.ts index ac83cf1..c8e01aa 100644 --- a/app/api/internal/suppressions/route.ts +++ b/app/api/internal/suppressions/route.ts @@ -45,7 +45,7 @@ export async function POST(req: NextRequest) { const parsed = createSuppressionSchema.safeParse(body) if (!parsed.success) { - const message = parsed.error.errors.map((e) => e.message).join(', ') + const message = parsed.error.issues.map((e) => e.message).join(', ') return NextResponse.json({ error: message }, { status: 400 }) } diff --git a/app/api/internal/team/invites/route.ts b/app/api/internal/team/invites/route.ts index a998117..533d3f2 100644 --- a/app/api/internal/team/invites/route.ts +++ b/app/api/internal/team/invites/route.ts @@ -45,7 +45,7 @@ export async function POST(req: NextRequest) { const parsed = createInviteSchema.safeParse(body) if (!parsed.success) { return NextResponse.json( - { error: parsed.error.errors.map((e) => e.message).join(', ') }, + { error: parsed.error.issues.map((e) => e.message).join(', ') }, { status: 400 }, ) } diff --git a/app/api/internal/team/members/[id]/route.ts b/app/api/internal/team/members/[id]/route.ts index 4d87e30..0fa91e9 100644 --- a/app/api/internal/team/members/[id]/route.ts +++ b/app/api/internal/team/members/[id]/route.ts @@ -62,7 +62,7 @@ export async function PATCH( const parsed = updateMemberSchema.safeParse(body) if (!parsed.success) { return NextResponse.json( - { error: parsed.error.errors.map((e) => e.message).join(', ') }, + { error: parsed.error.issues.map((e) => e.message).join(', ') }, { status: 400 }, ) } diff --git a/app/api/public/accept-invite/[token]/route.ts b/app/api/public/accept-invite/[token]/route.ts index 69172af..5d146b9 100644 --- a/app/api/public/accept-invite/[token]/route.ts +++ b/app/api/public/accept-invite/[token]/route.ts @@ -47,7 +47,7 @@ export async function POST( const parsed = acceptInviteSchema.safeParse(body) if (!parsed.success) { return NextResponse.json( - { error: parsed.error.errors.map((e) => e.message).join(', ') }, + { error: parsed.error.issues.map((e) => e.message).join(', ') }, { status: 400 }, ) } diff --git a/lib/validations/contacts.ts b/lib/validations/contacts.ts index b9b7600..ffa712c 100644 --- a/lib/validations/contacts.ts +++ b/lib/validations/contacts.ts @@ -1,17 +1,17 @@ import { z } from 'zod' export const createContactSchema = z.object({ - email: z.string().email('Valid email is required'), + email: z.email('Valid email is required'), firstName: z.string().optional(), lastName: z.string().optional(), - metadata: z.record(z.string()).optional(), + metadata: z.record(z.string(), z.string()).optional(), }) export const updateContactSchema = z.object({ - email: z.string().email().optional(), + email: z.email().optional(), firstName: z.string().optional(), lastName: z.string().optional(), - metadata: z.record(z.string()).optional(), + metadata: z.record(z.string(), z.string()).optional(), status: z.enum(['active', 'pending', 'bounced', 'unsubscribed', 'undeliverable']).optional(), }) diff --git a/lib/validations/providers.ts b/lib/validations/providers.ts index a686379..3a490cf 100644 --- a/lib/validations/providers.ts +++ b/lib/validations/providers.ts @@ -6,12 +6,12 @@ const optionalEmail = z.preprocess( const trimmed = v.trim() return trimmed.length === 0 ? undefined : trimmed }, - z.string().email('Must be a valid email address').optional(), + z.email('Must be a valid email address').optional(), ) export const createProviderSchema = z.object({ name: z.string().min(1, 'Name is required'), - type: z.enum(['resend', 'ses'], { required_error: 'Type must be resend or ses' }), + type: z.enum(['resend', 'ses'], { message: 'Type must be resend or ses' }), apiKey: z.string().min(1, 'API key is required'), region: z.string().optional(), replyToEmail: optionalEmail, diff --git a/package-lock.json b/package-lock.json index 36620ba..0ce79d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,7 +54,7 @@ "tailwind-merge": "^3.5.0", "tailwindcss-animate": "^1.0.7", "xlsx": "^0.18.5", - "zod": "^3.25.76" + "zod": "4.6.6" }, "devDependencies": { "@types/bcryptjs": "^2.4.6", @@ -5038,32 +5038,6 @@ "path-browserify": "^1.0.1" } }, - "node_modules/@ts-morph/common/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@ts-morph/common/node_modules/minimatch": { - "version": "7.4.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.9.tgz", - "integrity": "sha512-Brg/fp/iAVDOQoHxkuN5bEYhyQlZhxddI78yWsCbeEwTHXQjlNLtiJDUsp1GIptVqMI7/gkJMz4vVAc01mpoBw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@tybys/wasm-util": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", @@ -5465,45 +5439,6 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/utils": { "version": "8.58.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.2.tgz", @@ -6283,10 +6218,13 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/base64-js": { "version": "1.5.1", @@ -6356,21 +6294,21 @@ } }, "node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.4.0.tgz", + "integrity": "sha512-Ifk1KcLrxaGt1occQagQNFNNOqRt1LFuehEnHHzB8Z6cRgIxRU1TBaiIsUiCdA+gy5PL7Y1IX31DNKkRmxtXjQ==", "dev": true, "license": "MIT", "dependencies": { "bytes": "^3.1.2", - "content-type": "^1.0.5", + "content-type": "^2.1.0", "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.3", "on-finished": "^2.4.1", - "qs": "^6.16.0", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" + "qs": "^6.16.1", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" }, "engines": { "node": ">=18" @@ -6381,9 +6319,9 @@ } }, "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6410,14 +6348,15 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", - "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", - "dev": true, + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" } }, "node_modules/braces": { @@ -7768,15 +7707,6 @@ "node": ">=14" } }, - "node_modules/editorconfig/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/editorconfig/node_modules/commander": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", @@ -7786,21 +7716,6 @@ "node": ">=14" } }, - "node_modules/editorconfig/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -9262,32 +9177,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -10378,15 +10267,6 @@ "node": ">=14" } }, - "node_modules/js-beautify/node_modules/brace-expansion": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", - "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/js-beautify/node_modules/glob": { "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", @@ -10423,21 +10303,6 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/js-beautify/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/js-cookie": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", @@ -10894,16 +10759,19 @@ } }, "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-11.0.1.tgz", + "integrity": "sha512-t+Vn6DX4wPCxS23y03C0uhF7S1jpi1GfqPrnlEipCJaA2ykiNbMkVlDutZtmvLfRcUN6R8AYVlzTsQrT4RZoLQ==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "@isaacs/nonrecursive-glob-match": "^1.0.1", + "brace-expansion": "^5.0.12" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -12572,13 +12440,14 @@ } }, "node_modules/qs": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", - "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "version": "6.17.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.17.1.tgz", + "integrity": "sha512-jd3COkaKVgGUW+ZHyEHCG9bH7RoaaiWuMgzsIBjUMVjLAaWGWpoUAVwljVvBHxRu/2qEHnadLGZrkutYUBPQJA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" }, "engines": { "node": ">=0.6" @@ -13563,15 +13432,15 @@ } }, "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -15032,18 +14901,22 @@ } }, "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "dev": true, "license": "MIT", "dependencies": { - "content-type": "^1.0.5", + "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/typed-array-buffer": { @@ -15837,11 +15710,10 @@ } }, "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.6.tgz", + "integrity": "sha512-4UmzQUF5fxvfcYHlbjBmejU+w+hbDnWFx4aS8kBx7nPBHcO2SqPbpAG8snbdg+Xse4pRefR98hgjFgIMCI/UhA==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -15855,6 +15727,50 @@ "peerDependencies": { "zod": "^3.25.28 || ^4" } + }, + "node_modules/shadcn/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@isaacs/nonrecursive-glob-match": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@isaacs/nonrecursive-glob-match/-/nonrecursive-glob-match-1.0.3.tgz", + "integrity": "sha512-SI7kyKHq4XXDRozw+r9GlRZkia1ZkFrpLW98r2IC2Bpr8YkFGE3fvjzmxCG0x78A++69HmDNrDvSMYBZmHGpKA==", + "license": "BlueOak-1.0.0" } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 2552e2f..b5a8261 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,14 @@ "tailwind-merge": "^3.5.0", "tailwindcss-animate": "^1.0.7", "xlsx": "^0.18.5", - "zod": "^3.25.76" + "zod": "4.6.6" + }, + "overrides": { + "body-parser": "2.4.0", + "minimatch": "11.0.1", + "@anatine/zod-openapi": { + "zod": "4.6.6" + } }, "devDependencies": { "@types/bcryptjs": "^2.4.6", diff --git a/test/validations.test.ts b/test/validations.test.ts new file mode 100644 index 0000000..3bfc562 --- /dev/null +++ b/test/validations.test.ts @@ -0,0 +1,54 @@ +import { describe, it } from 'node:test' +import assert from 'node:assert/strict' +import { createContactSchema } from '@/lib/validations/contacts' +import { formSubmissionSchema } from '@/lib/validations/forms' +import { createProviderSchema } from '@/lib/validations/providers' +import { createTemplateSchema } from '@/lib/validations/templates' +import { createInviteSchema } from '@/lib/validations/team' + +describe('zod validation schemas', () => { + it('createContactSchema accepts a valid email + metadata record and rejects an invalid email', () => { + const parsed = createContactSchema.parse({ + email: 'ada@example.com', + metadata: { source: 'signup' }, + }) + assert.equal(parsed.email, 'ada@example.com') + assert.deepEqual(parsed.metadata, { source: 'signup' }) + assert.equal(createContactSchema.safeParse({ email: 'not-an-email' }).success, false) + }) + + it('createContactSchema keeps the custom email error message', () => { + const result = createContactSchema.safeParse({ email: 'nope' }) + assert.equal(result.success, false) + assert.ok(result.error.issues.some((issue) => issue.message === 'Valid email is required')) + }) + + it('createInviteSchema validates the invited email', () => { + assert.equal(createInviteSchema.safeParse({ email: 'ada@example.com' }).success, true) + const result = createInviteSchema.safeParse({ email: 'not-an-email' }) + assert.equal(result.success, false) + assert.ok(result.error.issues.some((issue) => issue.message === 'Enter a valid email')) + }) + + it('createProviderSchema keeps the custom message for a missing provider type', () => { + const result = createProviderSchema.safeParse({ name: 'Provider', apiKey: 'k' }) + assert.equal(result.success, false) + assert.ok( + result.error.issues.some((issue) => issue.message === 'Type must be resend or ses'), + ) + }) + + it('createTemplateSchema rejects a non-uuid campaign id', () => { + const result = createTemplateSchema.safeParse({ + name: 'Welcome', + fromCampaignId: 'not-a-uuid', + }) + assert.equal(result.success, false) + }) + + it('formSubmissionSchema normalises and validates the submitted email', () => { + const parsed = formSubmissionSchema.parse({ email: 'Ada@Example.com' }) + assert.equal(parsed.email, 'ada@example.com') + assert.equal(formSubmissionSchema.safeParse({ email: 'bad' }).success, false) + }) +})