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