Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,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: '...' }])"
);
});
});
Expand Down
16 changes: 15 additions & 1 deletion firestore-send-email/functions/src/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -182,10 +185,21 @@ function formatZodError(
const path = issue.path.length > 0 ? issue.path.join(".") : context;
switch (issue.code) {
case "invalid_type":
if (issue.received === "undefined") {
return `Field '${path}' must be a ${issue.expected}`;
}

Copy link
Contributor

@cabljac cabljac Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually i think a cleaner fix is I think in here we need

case "invalid_type":
  
  // Missing required field (received undefined)
  if (issue.received === "undefined") {
    return `Field '${path}' must be a ${issue.expected}`;
  }

  // Type mismatch cases
  if (issue.expected === "string") {
    return `Field '${path}' must be a string`;
  }
  if (issue.expected === "array") {
    return `Field '${path}' must be an array`;
  }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HassanBahati did you push changes taking this approach? i dont see them

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`;
}
if (issue.expected === "object") {
Expand Down
5 changes: 5 additions & 0 deletions storage-resize-images/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## Version 0.3.1

fix - add missing recordStartEvent call (#2546)
feat - add new onStartResize event

## Version 0.3.0

fix! - remove backfill, due to architectural flaws.
Expand Down
8 changes: 7 additions & 1 deletion storage-resize-images/extension.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

name: storage-resize-images
version: 0.3.0
version: 0.3.1
specVersion: v1beta

displayName: Resize Images
Expand Down Expand Up @@ -426,6 +426,12 @@ events:
description:
Occurs when the function is settled. Provides no customized data other
than the context.

- type: firebase.extensions.storage-resize-images.v1.onStartResize
description:
Occurs when an image resize operation completes successfully. This event
is only triggered when shouldResize returns true and the resize operation
succeeds.
# Lifecycle events disabled - backfill feature commented out
# lifecycleEvents:
# onInstall:
Expand Down
16 changes: 16 additions & 0 deletions storage-resize-images/functions/src/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,19 @@ export const recordCompletionEvent = async (data: string | object) => {
data,
});
};

export const recordStartResizeEvent = async ({
subject,
data,
}: {
subject: string;
data: string | object;
}) => {
if (!eventChannel) return;

return eventChannel.publish({
type: getEventType("onStartResize"),
subject,
data,
});
};
6 changes: 6 additions & 0 deletions storage-resize-images/functions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ const generateResizedImageHandler = async (
return;
}

await events.recordStartResizeEvent({
subject: object.name,
data: { input: object },
});

const bucket = admin.storage().bucket(object.bucket);
const filePath = object.name; // File path in the bucket.
const parsedPath = path.parse(filePath);
Expand Down Expand Up @@ -149,6 +154,7 @@ const generateResizedImageHandler = async (
export const generateResizedImage = functions.storage
.object()
.onFinalize(async (object, context) => {
await events.recordStartEvent(object);
await generateResizedImageHandler(object);
await events.recordCompletionEvent({ context });
});
Expand Down
Loading