tack-up-now/app/worker.ts

225 lines
5.7 KiB
TypeScript

import Dexie, { EntityTable } from "dexie"
import urlB64ToUint8Array from "../b64ToUInt8"
import pushPublicKey from "../pushPublicKey"
interface SubscriptionRecord {
id: number
subscriptionId: number
}
export default function start(self: ServiceWorkerGlobalScope) {
self.addEventListener("install", (event) => {
event.waitUntil(self.skipWaiting())
})
self.addEventListener("activate", (event) => {
event.waitUntil(self.clients.claim())
})
// self.addEventListener("push", function (event: PushEvent) {
// console.log("[Service Worker] Push Received.")
// console.log(`[Service Worker] Push had this data: "${event.data?.text()}"`)
// const title = "Push Codelab"
// const options = {
// body: "Yay it works.",
// icon: "images/icon.png",
// badge: "images/badge.png",
// }
// event.waitUntil(self.registration.showNotification(title, options))
// })
// self.addEventListener("notificationclick", function (event) {
// console.log("[Service Worker] Notification click Received.")
// event.notification.close()
// event.waitUntil(
// self.clients.openWindow("https://developers.google.com/web/")
// )
// })
async function sendMessage(message: any) {
const clients = await self.clients.matchAll()
await Promise.all(
clients.map(async (client) => client.postMessage(message))
)
}
self.addEventListener("message", function (event) {
const waitEvent = event as ExtendableEvent
waitEvent.waitUntil(
(async () => {
await sendMessage({
message: "Got message",
data: event.data,
})
if (
"type" in event.data &&
event.data.type === "subscribed" &&
"subscription" in event.data
) {
try {
await event.waitUntil(
submitSubscription(
self.registration,
event.data.subscription as PushSubscription
)
)
} catch (e) {
await sendMessage({
message: "Got error processing subscription",
error: (e as Error).toString(),
})
}
}
await sendMessage({
message: "Processed subscription",
})
})()
)
})
self.addEventListener("pushsubscriptionchange", function (event) {
const waitEvent = event as ExtendableEvent
waitEvent.waitUntil(
(async () => {
const existingSubscription =
await self.registration.pushManager.getSubscription()
const newSubscription = await submitSubscription(
self.registration,
existingSubscription
)
await sendMessage({ type: "sent subscription", newSubscription })
})()
)
})
async function submitSubscription(
registration: ServiceWorkerRegistration,
subscription: PushSubscription | null
) {
const db = database()
await sendMessage({
message: `Is subscription null? ${subscription === null}`,
})
if (subscription === null) return
const existingSubscriptionId = await db.subscriptions.get(1)
await sendMessage({
message: `Existing subscription ID ${existingSubscriptionId}`,
})
await sendMessage({
message: `pushPublicKey ${pushPublicKey}`,
})
let applicationServerKey
try {
applicationServerKey = urlB64ToUint8Array(pushPublicKey)
} catch (error) {
await sendMessage({
message: `B64 error ${(error as Error).toString()}`,
})
}
await sendMessage({
message: `Converted public key`,
})
const newSubscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey,
})
await sendMessage({
message: `subscribed via pushManager`,
})
const stupid =
existingSubscriptionId === undefined
? postSubscription(newSubscription.toJSON(), db)
: putSubscription(
newSubscription.toJSON(),
existingSubscriptionId.subscriptionId
)
await stupid
return newSubscription
}
async function postSubscription(
subscription: PushSubscriptionJSON,
db: ReturnType<typeof database>
) {
await sendMessage({
message: "Log something you piece of garbage",
})
try {
await sendMessage({
message: `URL ${process.env.BASE_URL}/api/subscription/`,
})
await sendMessage({
message: `Submitting subscription ${subscription}`,
})
await sendMessage({
message: `JSON formatted: ${JSON.stringify(subscription)}`,
})
const response = await fetch(
`${process.env.BASE_URL}/api/subscription/`,
{
method: "POST",
body: JSON.stringify(subscription),
headers: {
"Content-Type": "application/json",
},
}
)
await sendMessage({
message: `Response status ${response.status}`,
})
db.subscriptions.put({
id: 1,
subscriptionId: (await response.json()).subscriptionId,
})
} catch (error) {
await sendMessage({
message: `ERRRROR ${(error as Error).toString()}}`,
})
}
}
function putSubscription(subscription: PushSubscriptionJSON, id: number) {
return fetch(`${process.env.BASE_URL}/api/subscription/${id}`, {
method: "PUT",
body: JSON.stringify(subscription),
headers: {
"Content-Type": "application/json",
},
})
}
}
function database() {
const db = new Dexie("tack-up-now", { indexedDB }) as Dexie & {
subscriptions: EntityTable<SubscriptionRecord, "id">
}
db.version(1).stores({ subscriptions: "id++, subscriptionId&" })
return db
}