75 lines
1.9 KiB
TypeScript
75 lines
1.9 KiB
TypeScript
import { getAccessToken, getServiceAccount } from './fcmAuth.ts'
|
|
|
|
export async function handleFcmPush(req: Request): Promise<Response> {
|
|
const secret = Deno.env.get('SIDECAR_SECRET')
|
|
if (secret && req.headers.get('x-sidecar-secret') !== secret) {
|
|
return new Response('Unauthorized', { status: 401 })
|
|
}
|
|
|
|
let body: {
|
|
tokens: string[]
|
|
title: string
|
|
body: string
|
|
data?: Record<string, string>
|
|
}
|
|
|
|
try {
|
|
body = await req.json()
|
|
} catch {
|
|
return new Response('Invalid JSON', { status: 400 })
|
|
}
|
|
|
|
const { tokens, title, body: messageBody, data } = body
|
|
|
|
if (!tokens?.length) {
|
|
return new Response('No tokens provided', { status: 400 })
|
|
}
|
|
|
|
const { project_id } = getServiceAccount()
|
|
const accessToken = await getAccessToken()
|
|
|
|
const results = await Promise.allSettled(
|
|
tokens.map(token =>
|
|
fetch(
|
|
`https://fcm.googleapis.com/v1/projects/${project_id}/messages:send`,
|
|
{
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': `Bearer ${accessToken}`,
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
message: {
|
|
token,
|
|
notification: { title, body: messageBody },
|
|
...(data ? { data } : {})
|
|
}
|
|
})
|
|
}
|
|
).then(async (r) => {
|
|
if (!r.ok) {
|
|
const err = await r.json()
|
|
throw new Error(err.error?.message ?? r.statusText)
|
|
}
|
|
return r.json()
|
|
})
|
|
)
|
|
)
|
|
|
|
let successCount = 0
|
|
let failureCount = 0
|
|
|
|
results.forEach((result, i) => {
|
|
if (result.status === 'fulfilled') {
|
|
successCount++
|
|
} else {
|
|
failureCount++
|
|
console.error(`FCM failed for token ${tokens[i]}:`, result.reason)
|
|
}
|
|
})
|
|
|
|
console.log(`FCM: ${successCount} sent, ${failureCount} failed`)
|
|
|
|
return Response.json({ successCount, failureCount })
|
|
}
|