UNPKG

ntfy

Version:
158 lines (157 loc) 5.28 kB
import fs from 'node:fs/promises'; import { URL } from 'node:url'; const defaultServerURL = 'https://ntfy.sh'; export class NtfyClient { constructor(config) { this.config = config; } publish(config) { return publish({ server: defaultServerURL, ...this.config, ...config, }); } } export async function publish(publishConfig) { const requestConfig = { headers: {} }; let postData; if (publishConfig.actions && publishConfig.actions.length) { requestConfig.headers['X-Actions'] = publishConfig.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 (publishConfig.authorization) { requestConfig.withCredentials = true; if (typeof publishConfig.authorization === 'string') { requestConfig.headers.Authorization = `Bearer ${publishConfig.authorization}`; } else { const credentials = `${publishConfig.authorization.username}:${publishConfig.authorization.password}`; requestConfig.headers.Authorization = `Basic ${Buffer.from(credentials).toString('base64')}`; } } if (publishConfig.delay) { requestConfig.headers['X-Delay'] = publishConfig.delay; } if (publishConfig.disableCache) { requestConfig.headers['X-Cache'] = 'no'; } if (publishConfig.disableFirebase) { requestConfig.headers['X-Firebase'] = 'no'; } if (publishConfig.emailAddress) { requestConfig.headers['X-Email'] = publishConfig.emailAddress; } if (publishConfig.markdown) { requestConfig.headers['X-Markdown'] = publishConfig.markdown.toString(); } if (ConfigHasMessage(publishConfig) && publishConfig.fileURL) { if (typeof publishConfig.fileURL === 'string') { requestConfig.headers['X-Attach'] = publishConfig.fileURL; } else { requestConfig.headers['X-Attach'] = publishConfig.fileURL.url; requestConfig.headers['X-Filename'] = publishConfig.fileURL.filename; } } if (ConfigHasAttachment(publishConfig)) { try { postData = await fs.readFile(publishConfig.fileAttachment); } catch (error) { console.error('Error while reading file:', error.message); } } else if (publishConfig.message) { postData = publishConfig.message; } else { throw new Error('No message or file attachment specified'); } if (publishConfig.iconURL) { requestConfig.headers['X-Icon'] = publishConfig.iconURL; } if (publishConfig.priority) { requestConfig.headers['X-Priority'] = publishConfig.priority.toString(); } if (publishConfig.tags && publishConfig.tags.length) { requestConfig.headers['X-Tags'] = typeof publishConfig.tags === 'string' ? publishConfig.tags : publishConfig.tags.join(','); } if (publishConfig.title) { requestConfig.headers['X-Title'] = publishConfig.title; } const url = new URL(publishConfig.topic, publishConfig.server || defaultServerURL); const response = await fetch(url.href, { body: postData, credentials: requestConfig.withCredentials ? 'include' : 'omit', headers: requestConfig.headers, method: 'POST', }); if (!response.ok) { throw new Error(`Error while publishing message: ${response.statusText}`); } return response.json(); } 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 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; } function ConfigHasAttachment(config) { return !!config.fileAttachment; } function ConfigHasMessage(config) { return !!config.message; }