Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions lib/notification/adapter/apprise.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,46 @@ import { markdown2Html } from '../../services/markdown.js';
import { getJob } from '../../services/storage/jobStorage.js';
import fetch from 'node-fetch';

export const send = ({ serviceName, newListings, notificationConfig, jobKey, baseUrl }) => {
export const send = async ({ serviceName, newListings, notificationConfig, jobKey, baseUrl }) => {
const { server } = notificationConfig.find((adapter) => adapter.id === config.id).fields;
const job = getJob(jobKey);
const jobName = job == null ? jobKey : job.name;
const promises = newListings.map((newListing) => {

for (const newListing of newListings) {
const title = `${jobName} at ${serviceName}: ${newListing.title}`;
const fredyLine = baseUrl && newListing.id ? `\nOpen in Fredy: ${baseUrl}/#/listings/listing/${newListing.id}` : '';
const message = `Address: ${newListing.address}\nSize: ${newListing.size}\nPrice: ${newListing.price}\nLink: ${newListing.link}${fredyLine}`;
return fetch(server, {

// Try to attach image if available
if (newListing.image && typeof newListing.image === 'string') {
try {
const imgRes = await fetch(newListing.image);
if (imgRes.ok) {
const ab = await imgRes.arrayBuffer();
const form = new FormData();
form.append('body', message);
form.append('title', title);
form.append('attachment', new Blob([ab]), 'image.jpg');
await fetch(server, {
method: 'POST',
body: form,
Comment on lines +26 to +32

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

node-fetch doesn't serialize a native FormData. It detects FormData via instanceof against its own bundled class, so the native one from Node 22 isn't recognized and the request body ends up as the string [object FormData]. Apprise never gets a real multipart upload, so the attachment path doesn't actually work if I'm not mistaken

Since Fredy already requires Node 22, the fix is to use the global fetch for this call (native fetch + FormData + Blob work together), or import FormData/File from node-fetch and build the form with those. Should be tested against a live Apprise instance either way.

});
continue;
}
} catch {
// fail silently, just skip the image
}
}

await fetch(server, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
body: message,
title: title,
}),
});
});
return Promise.all(promises);
}
};
export const config = {
id: 'apprise',
Expand Down
Loading