133 lines
3.5 KiB
TypeScript
133 lines
3.5 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) {
|
|
const { title, body, badge, icon, destination } = event.data?.json() ?? {
|
|
title: "It was missing yo",
|
|
badge: "image/blah",
|
|
icon: "image/blah",
|
|
destination: "https://tackupnow.com",
|
|
}
|
|
|
|
event.waitUntil(
|
|
self.registration.showNotification(title, {
|
|
body,
|
|
badge,
|
|
icon,
|
|
data: { destination },
|
|
})
|
|
)
|
|
})
|
|
|
|
self.addEventListener("notificationclick", function (event) {
|
|
event.notification.close()
|
|
const destination = event.notification.data.destination
|
|
|
|
event.waitUntil(
|
|
(async () => {
|
|
const clients = await self.clients.matchAll({
|
|
type: "window",
|
|
includeUncontrolled: true,
|
|
})
|
|
|
|
const existingClient = clients.find(
|
|
(client) => client.url === event.notification.data.destination
|
|
)
|
|
|
|
if (existingClient === undefined) {
|
|
await self.clients.openWindow(destination)
|
|
} else {
|
|
await existingClient.focus()
|
|
}
|
|
})()
|
|
)
|
|
})
|
|
|
|
self.addEventListener("message", function (event) {
|
|
const waitEvent = event as ExtendableEvent
|
|
|
|
if ("type" in event.data && event.data.type === "subscribed") {
|
|
waitEvent.waitUntil(submitSubscription(event.data.subscription))
|
|
}
|
|
})
|
|
|
|
self.addEventListener("pushsubscriptionchange", function (event) {
|
|
const waitEvent = event as ExtendableEvent
|
|
|
|
waitEvent.waitUntil(
|
|
(async () => {
|
|
const applicationServerKey = urlB64ToUint8Array(pushPublicKey)
|
|
const newSubscription = await self.registration.pushManager.subscribe({
|
|
userVisibleOnly: true,
|
|
applicationServerKey: applicationServerKey,
|
|
})
|
|
|
|
await submitSubscription(newSubscription.toJSON())
|
|
})()
|
|
)
|
|
})
|
|
}
|
|
|
|
async function submitSubscription(subscription: PushSubscriptionJSON) {
|
|
const db = database()
|
|
|
|
const existingSubscriptionId = await db.subscriptions.get(1)
|
|
|
|
await (existingSubscriptionId === undefined
|
|
? postSubscription(subscription, db)
|
|
: putSubscription(subscription, existingSubscriptionId.subscriptionId))
|
|
}
|
|
|
|
async function postSubscription(
|
|
subscription: PushSubscriptionJSON,
|
|
db: ReturnType<typeof database>
|
|
) {
|
|
const response = await fetch(`${process.env.BASE_URL}/api/subscription/`, {
|
|
method: "POST",
|
|
body: JSON.stringify(subscription),
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
})
|
|
|
|
db.subscriptions.put({
|
|
id: 1,
|
|
subscriptionId: (await response.json()).subscriptionId,
|
|
})
|
|
}
|
|
|
|
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
|
|
}
|