UNPKG

ntfy

Version:

Send notifications over ntfy.sh.

144 lines (143 loc) 4.48 kB
import { URL } from 'node:url'; import { promises as fs } from 'node:fs'; import axios, { AxiosHeaders } from 'axios'; const defaultServerURL = 'https://ntfy.sh'; export class NtfyClient { constructor(config) { this.config = config; } publish(config) { return publish({ server: defaultServerURL, ...this.config, ...config, }); } } function buildBroadcastActionString(action) { let str = `${action.type}, ${action.label}`; if (action.clear) { str += ', clear=true'; } if (action.extras && Object.keys(action.extras).length) { str += `, ${Object.entries(action.extras) .map(([key, value]) => `extras.${key}=${value}`) .join(', ')}`; } if (action.intent) { str += `, intent=${action.intent}`; } return str; } function ConfigHasAttachment(config) { return !!config.fileAttachment; } function ConfigHasMessage(config) { return !!config.message; } function buildHTTPActionString(action) { let str = `${action.type}, ${action.label}, ${action.url}`; if (action.method) { str += `, method=${action.method.toUpperCase()}`; } if (action.clear) { str += ', clear=true'; } if (action.headers && Object.keys(action.headers).length) { str += `, ${Object.entries(action.headers) .map(([key, value]) => `headers.${key}=${value}`) .join(', ')}`; } if (action.body) { str += `, ${action.body}`; } return str; } function buildViewActionString(action) { let str = `${action.type}, ${action.label}, ${action.url}`; if (action.clear) { str += ', clear=true'; } return str; } export async function publish(config) { const axiosConfig = { headers: new AxiosHeaders() }; let postData; if (config.actions && config.actions.length) { axiosConfig.headers.set('X-Actions', config.actions .map(action => { switch (action.type) { case 'broadcast': { return buildBroadcastActionString(action); } case 'http': { return buildHTTPActionString(action); } case 'view': { return buildViewActionString(action); } default: { return ''; } } }) .join('; ')); } if (config.authorization) { axiosConfig.withCredentials = true; if (typeof config.authorization === 'string') { axiosConfig.headers.Authorization = config.authorization; } else { axiosConfig.auth = config.authorization; } } if (config.delay) { axiosConfig.headers.set('X-Delay', config.delay); } if (config.disableCache) { axiosConfig.headers.set('X-Cache', 'no'); } if (config.disableFirebase) { axiosConfig.headers.set('X-Firebase', 'no'); } if (config.emailAddress) { axiosConfig.headers.set('X-Email', config.emailAddress); } if (ConfigHasMessage(config) && config.fileURL) { if (typeof config.fileURL === 'string') { axiosConfig.headers.set('X-Attach', config.fileURL); } axiosConfig.headers.set('X-Attach', config.fileURL.url); axiosConfig.headers.set('X-Filename', config.fileURL.filename); } if (ConfigHasAttachment(config)) { try { postData = await fs.readFile(config.fileAttachment); } catch (error) { console.error('Error while reading file:', error.message); } } else if (config.message) { postData = config.message; } else { throw new Error('No message or file attachment specified'); } if (config.iconURL) { axiosConfig.headers.set('X-Icon', config.iconURL); } if (config.priority) { axiosConfig.headers.set('X-Priority', config.priority); } if (config.tags && config.tags.length) { axiosConfig.headers.set('X-Tags', typeof config.tags === 'string' ? config.tags : config.tags.join(',')); } if (config.title) { axiosConfig.headers.set('X-Title', config.title); } const url = new URL(config.topic, config.server || defaultServerURL); const { data } = await axios.post(url.href, postData, axiosConfig); return data; }