feat: pushover client
This commit is contained in:
33
src/lib/pushover.ts
Normal file
33
src/lib/pushover.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
export interface PushOpts {
|
||||||
|
title: string
|
||||||
|
message: string
|
||||||
|
url?: string
|
||||||
|
urlTitle?: string
|
||||||
|
priority?: -2 | -1 | 0 | 1 | 2
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendPush(opts: PushOpts): Promise<void> {
|
||||||
|
const token = process.env.PUSHOVER_TOKEN
|
||||||
|
const user = process.env.PUSHOVER_USER
|
||||||
|
if (!token || !user) throw new Error('PUSHOVER_TOKEN/PUSHOVER_USER not set')
|
||||||
|
|
||||||
|
const body = new URLSearchParams({
|
||||||
|
token,
|
||||||
|
user,
|
||||||
|
title: opts.title,
|
||||||
|
message: opts.message,
|
||||||
|
priority: String(opts.priority ?? 0),
|
||||||
|
})
|
||||||
|
if (opts.url) body.set('url', opts.url)
|
||||||
|
if (opts.urlTitle) body.set('url_title', opts.urlTitle)
|
||||||
|
|
||||||
|
const res = await fetch('https://api.pushover.net/1/messages.json', {
|
||||||
|
method: 'POST',
|
||||||
|
body,
|
||||||
|
signal: AbortSignal.timeout(10_000),
|
||||||
|
})
|
||||||
|
if (!res.ok) {
|
||||||
|
const txt = await res.text().catch(() => '')
|
||||||
|
throw new Error(`Pushover ${res.status}: ${txt}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
28
tests/pushover.test.ts
Normal file
28
tests/pushover.test.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||||
|
import { sendPush } from '@/lib/pushover'
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
process.env.PUSHOVER_TOKEN = 'tok'
|
||||||
|
process.env.PUSHOVER_USER = 'user'
|
||||||
|
global.fetch = vi.fn().mockResolvedValue({ ok: true, status: 200, json: async () => ({ status: 1 }) }) as unknown as typeof fetch
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('sendPush', () => {
|
||||||
|
it('posts to pushover with token/user/payload', async () => {
|
||||||
|
await sendPush({ title: 'T', message: 'M', url: 'https://x' })
|
||||||
|
const fetchMock = global.fetch as unknown as ReturnType<typeof vi.fn>
|
||||||
|
const [url, init] = fetchMock.mock.calls[0]
|
||||||
|
expect(url).toBe('https://api.pushover.net/1/messages.json')
|
||||||
|
const body = init.body as URLSearchParams
|
||||||
|
expect(body.get('token')).toBe('tok')
|
||||||
|
expect(body.get('user')).toBe('user')
|
||||||
|
expect(body.get('title')).toBe('T')
|
||||||
|
expect(body.get('message')).toBe('M')
|
||||||
|
expect(body.get('url')).toBe('https://x')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws if env vars missing', async () => {
|
||||||
|
delete process.env.PUSHOVER_TOKEN
|
||||||
|
await expect(sendPush({ title: 'T', message: 'M' })).rejects.toThrow(/PUSHOVER/)
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user