From 5c84c3417d81efed2be6dd6f189036127b6a4ab7 Mon Sep 17 00:00:00 2001 From: HassanBahati Date: Mon, 12 Jan 2026 13:39:09 +0300 Subject: [PATCH 01/11] fix(firestore-send-email): improve attachments validation error message --- firestore-send-email/functions/__tests__/validation.test.ts | 2 +- firestore-send-email/functions/src/validation.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/firestore-send-email/functions/__tests__/validation.test.ts b/firestore-send-email/functions/__tests__/validation.test.ts index e54990b3c..d0f7ffa84 100644 --- a/firestore-send-email/functions/__tests__/validation.test.ts +++ b/firestore-send-email/functions/__tests__/validation.test.ts @@ -657,7 +657,7 @@ describe("validatePayload", () => { }; expect(() => validatePayload(invalidPayload)).toThrow(ValidationError); expect(() => validatePayload(invalidPayload)).toThrow( - "Invalid message configuration: Field 'message.attachments' must be an array" + "Field 'message.attachments' must be an array. If you have a single attachment object, wrap it in an array (e.g., [{ filename: '...', path: '...' }])" ); }); }); diff --git a/firestore-send-email/functions/src/validation.ts b/firestore-send-email/functions/src/validation.ts index 98f4e4ca7..c5ac43d57 100644 --- a/firestore-send-email/functions/src/validation.ts +++ b/firestore-send-email/functions/src/validation.ts @@ -53,7 +53,10 @@ export const attachmentSchema = z }); export const attachmentsSchema = z - .array(attachmentSchema) + .array(attachmentSchema, { + invalid_type_error: + "Field 'attachments' must be an array. If you have a single attachment object, wrap it in an array (e.g., [{ filename: '...', path: '...' }])", + }) .optional() .transform((attachments) => attachments From 6401197e635539c6c670f20dc8b0cb312d786b59 Mon Sep 17 00:00:00 2001 From: HassanBahati Date: Mon, 12 Jan 2026 13:43:48 +0300 Subject: [PATCH 02/11] fix(firestore-send-email): improve attachments validation error message --- firestore-send-email/functions/__tests__/validation.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firestore-send-email/functions/__tests__/validation.test.ts b/firestore-send-email/functions/__tests__/validation.test.ts index d0f7ffa84..18448153d 100644 --- a/firestore-send-email/functions/__tests__/validation.test.ts +++ b/firestore-send-email/functions/__tests__/validation.test.ts @@ -657,7 +657,7 @@ describe("validatePayload", () => { }; expect(() => validatePayload(invalidPayload)).toThrow(ValidationError); expect(() => validatePayload(invalidPayload)).toThrow( - "Field 'message.attachments' must be an array. If you have a single attachment object, wrap it in an array (e.g., [{ filename: '...', path: '...' }])" + "Invalid message configuration: Field 'message.attachments' must be an array. If you have a single attachment object, wrap it in an array (e.g., [{ filename: '...', path: '...' }])" ); }); }); From 428ab001c58336712111a9abd2e90dd14c5676d8 Mon Sep 17 00:00:00 2001 From: HassanBahati Date: Mon, 12 Jan 2026 14:16:28 +0300 Subject: [PATCH 03/11] tests(firestore-send-email): fix tests --- firestore-send-email/functions/src/validation.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/firestore-send-email/functions/src/validation.ts b/firestore-send-email/functions/src/validation.ts index c5ac43d57..c617ec93d 100644 --- a/firestore-send-email/functions/src/validation.ts +++ b/firestore-send-email/functions/src/validation.ts @@ -187,6 +187,10 @@ function formatZodError( const path = issue.path.length > 0 ? issue.path.join(".") : context; switch (issue.code) { case "invalid_type": + if (issue.message && !issue.message.startsWith("Expected")) { + return issue.message; + } + if (issue.expected === "string") { return `Field '${path}' must be a string`; } From 78ed835fd9c77812dd5f6485f5ad0a5a3c6612a4 Mon Sep 17 00:00:00 2001 From: HassanBahati Date: Mon, 12 Jan 2026 14:48:11 +0300 Subject: [PATCH 04/11] tests(firestore-send-email): fix tests --- firestore-send-email/functions/src/validation.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/firestore-send-email/functions/src/validation.ts b/firestore-send-email/functions/src/validation.ts index c617ec93d..9eafc7259 100644 --- a/firestore-send-email/functions/src/validation.ts +++ b/firestore-send-email/functions/src/validation.ts @@ -188,7 +188,11 @@ function formatZodError( switch (issue.code) { case "invalid_type": if (issue.message && !issue.message.startsWith("Expected")) { - return issue.message; + const customMessage = issue.message.replace( + /Field 'attachments'/g, + `Field '${path}'` + ); + return customMessage; } if (issue.expected === "string") { From 29070393502d1393b23b7f071fcf4fa05276b57c Mon Sep 17 00:00:00 2001 From: HassanBahati Date: Mon, 12 Jan 2026 15:12:06 +0300 Subject: [PATCH 05/11] tests(firestore-send-email): refactor tests --- firestore-send-email/functions/src/validation.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/firestore-send-email/functions/src/validation.ts b/firestore-send-email/functions/src/validation.ts index 9eafc7259..c7fd5d311 100644 --- a/firestore-send-email/functions/src/validation.ts +++ b/firestore-send-email/functions/src/validation.ts @@ -187,12 +187,8 @@ function formatZodError( const path = issue.path.length > 0 ? issue.path.join(".") : context; switch (issue.code) { case "invalid_type": - if (issue.message && !issue.message.startsWith("Expected")) { - const customMessage = issue.message.replace( - /Field 'attachments'/g, - `Field '${path}'` - ); - return customMessage; + if (issue.received === "undefined") { + return `Field '${path}' must be a ${issue.expected}`; } if (issue.expected === "string") { From 6f2dc3dd7e813dcd7aca482635913f1939d6f2d9 Mon Sep 17 00:00:00 2001 From: HassanBahati Date: Mon, 12 Jan 2026 15:20:06 +0300 Subject: [PATCH 06/11] tests(firestore-send-email): fix tests --- firestore-send-email/functions/__tests__/validation.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firestore-send-email/functions/__tests__/validation.test.ts b/firestore-send-email/functions/__tests__/validation.test.ts index 18448153d..e54990b3c 100644 --- a/firestore-send-email/functions/__tests__/validation.test.ts +++ b/firestore-send-email/functions/__tests__/validation.test.ts @@ -657,7 +657,7 @@ describe("validatePayload", () => { }; expect(() => validatePayload(invalidPayload)).toThrow(ValidationError); expect(() => validatePayload(invalidPayload)).toThrow( - "Invalid message configuration: Field 'message.attachments' must be an array. If you have a single attachment object, wrap it in an array (e.g., [{ filename: '...', path: '...' }])" + "Invalid message configuration: Field 'message.attachments' must be an array" ); }); }); From 4f5dfb6f1c4483db5a8c529a6bbaf6c834ea8eae Mon Sep 17 00:00:00 2001 From: HassanBahati Date: Mon, 12 Jan 2026 15:56:36 +0300 Subject: [PATCH 07/11] tests(firestore-send-email): refactor tests --- .../functions/__tests__/validation.test.ts | 2 +- firestore-send-email/functions/src/validation.ts | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/firestore-send-email/functions/__tests__/validation.test.ts b/firestore-send-email/functions/__tests__/validation.test.ts index e54990b3c..18448153d 100644 --- a/firestore-send-email/functions/__tests__/validation.test.ts +++ b/firestore-send-email/functions/__tests__/validation.test.ts @@ -657,7 +657,7 @@ describe("validatePayload", () => { }; expect(() => validatePayload(invalidPayload)).toThrow(ValidationError); expect(() => validatePayload(invalidPayload)).toThrow( - "Invalid message configuration: Field 'message.attachments' must be an array" + "Invalid message configuration: Field 'message.attachments' must be an array. If you have a single attachment object, wrap it in an array (e.g., [{ filename: '...', path: '...' }])" ); }); }); diff --git a/firestore-send-email/functions/src/validation.ts b/firestore-send-email/functions/src/validation.ts index c7fd5d311..a2cad94ef 100644 --- a/firestore-send-email/functions/src/validation.ts +++ b/firestore-send-email/functions/src/validation.ts @@ -195,6 +195,13 @@ function formatZodError( return `Field '${path}' must be a string`; } if (issue.expected === "array") { + if (issue.message && !issue.message.startsWith("Expected")) { + const customMessage = issue.message.replace( + /Field 'attachments'/g, + `Field '${path}'` + ); + return customMessage; + } return `Field '${path}' must be an array`; } if (issue.expected === "object") { From 5b812c45dfc2babecaa37b1dda803225a289e52c Mon Sep 17 00:00:00 2001 From: Izaak Gough Date: Mon, 20 Apr 2026 16:00:55 +0100 Subject: [PATCH 08/11] refactor: improve invalid_type case handling --- .../functions/src/validation.ts | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/firestore-send-email/functions/src/validation.ts b/firestore-send-email/functions/src/validation.ts index a2cad94ef..ab8e2d8c3 100644 --- a/firestore-send-email/functions/src/validation.ts +++ b/firestore-send-email/functions/src/validation.ts @@ -187,23 +187,25 @@ function formatZodError( const path = issue.path.length > 0 ? issue.path.join(".") : context; switch (issue.code) { case "invalid_type": + if (issue.message && issue.message.startsWith("Expected")) { + return issue.message.replace(/Field '.*?/g, `Field '${path}'`); + } + if (issue.received === "undefined") { - return `Field '${path}' must be a ${issue.expected}`; + const expected = issue.expected === "object" ? "map" : issue.expected; + const article = ["a", "e", "i", "o", "u"].includes(expected[0]) + ? "an" + : "a"; + return `Field '${path}' must be ${article} ${expected}`; } if (issue.expected === "string") { return `Field '${path}' must be a string`; } if (issue.expected === "array") { - if (issue.message && !issue.message.startsWith("Expected")) { - const customMessage = issue.message.replace( - /Field 'attachments'/g, - `Field '${path}'` - ); - return customMessage; - } - return `Field '${path}' must be an array`; + return `Field '${path} must be an array`; } + if (issue.expected === "object") { return `Field '${path}' must be a map`; } From 8b782747c15c76b989e2b82a00d817054531608c Mon Sep 17 00:00:00 2001 From: Izaak Gough Date: Mon, 20 Apr 2026 16:04:47 +0100 Subject: [PATCH 09/11] chore: fix typo --- firestore-send-email/functions/src/validation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firestore-send-email/functions/src/validation.ts b/firestore-send-email/functions/src/validation.ts index ab8e2d8c3..f11f9f87a 100644 --- a/firestore-send-email/functions/src/validation.ts +++ b/firestore-send-email/functions/src/validation.ts @@ -203,7 +203,7 @@ function formatZodError( return `Field '${path}' must be a string`; } if (issue.expected === "array") { - return `Field '${path} must be an array`; + return `Field '${path}' must be an array`; } if (issue.expected === "object") { From 7530f009e454330897d98276e7293c521f6caaa4 Mon Sep 17 00:00:00 2001 From: Izaak Gough Date: Mon, 20 Apr 2026 16:43:21 +0100 Subject: [PATCH 10/11] tests: fix test --- firestore-send-email/functions/__tests__/validation.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firestore-send-email/functions/__tests__/validation.test.ts b/firestore-send-email/functions/__tests__/validation.test.ts index 18448153d..e54990b3c 100644 --- a/firestore-send-email/functions/__tests__/validation.test.ts +++ b/firestore-send-email/functions/__tests__/validation.test.ts @@ -657,7 +657,7 @@ describe("validatePayload", () => { }; expect(() => validatePayload(invalidPayload)).toThrow(ValidationError); expect(() => validatePayload(invalidPayload)).toThrow( - "Invalid message configuration: Field 'message.attachments' must be an array. If you have a single attachment object, wrap it in an array (e.g., [{ filename: '...', path: '...' }])" + "Invalid message configuration: Field 'message.attachments' must be an array" ); }); }); From dc5a69a6fa69a32645b736368a2aa04e92738ce9 Mon Sep 17 00:00:00 2001 From: Izaak Gough Date: Mon, 20 Apr 2026 16:45:09 +0100 Subject: [PATCH 11/11] fix: remove unnecessary check --- firestore-send-email/functions/src/validation.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/firestore-send-email/functions/src/validation.ts b/firestore-send-email/functions/src/validation.ts index f11f9f87a..cbc6441dd 100644 --- a/firestore-send-email/functions/src/validation.ts +++ b/firestore-send-email/functions/src/validation.ts @@ -187,10 +187,6 @@ function formatZodError( const path = issue.path.length > 0 ? issue.path.join(".") : context; switch (issue.code) { case "invalid_type": - if (issue.message && issue.message.startsWith("Expected")) { - return issue.message.replace(/Field '.*?/g, `Field '${path}'`); - } - if (issue.received === "undefined") { const expected = issue.expected === "object" ? "map" : issue.expected; const article = ["a", "e", "i", "o", "u"].includes(expected[0])