* feat: Push notifications * feat: Feature-detect push notifications support * feat: Prompt user to reauthenticate when missing push scope * fix(service-worker): Add tags to notifications * feat: Push notification actions for mentions
		
			
				
	
	
		
			89 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			89 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
import { getSubscription, deleteSubscription, postSubscription, putSubscription } from '../_api/pushSubscription'
 | 
						|
import { store } from '../_store/store'
 | 
						|
import { urlBase64ToUint8Array } from '../_utils/base64'
 | 
						|
 | 
						|
const dummyApplicationServerKey = 'BImgAz4cF_yvNFp8uoBJCaGpCX4d0atNIFMHfBvAAXCyrnn9IMAFQ10DW_ZvBCzGeR4fZI5FnEi2JVcRE-L88jY='
 | 
						|
 | 
						|
export async function updatePushSubscriptionForInstance (instanceName) {
 | 
						|
  const { loggedInInstances, pushSubscription } = store.get()
 | 
						|
  const accessToken = loggedInInstances[instanceName].access_token
 | 
						|
 | 
						|
  if (pushSubscription === null) {
 | 
						|
    return
 | 
						|
  }
 | 
						|
 | 
						|
  const registration = await navigator.serviceWorker.ready
 | 
						|
  const subscription = await registration.pushManager.getSubscription()
 | 
						|
 | 
						|
  if (subscription === null) {
 | 
						|
    store.set({ pushSubscription: null })
 | 
						|
    store.save()
 | 
						|
    return
 | 
						|
  }
 | 
						|
 | 
						|
  try {
 | 
						|
    const backendSubscription = await getSubscription(instanceName, accessToken)
 | 
						|
 | 
						|
    // Check if applicationServerKey changed (need to get another subscription from the browser)
 | 
						|
    if (btoa(urlBase64ToUint8Array(backendSubscription.server_key).buffer) !== btoa(subscription.options.applicationServerKey)) {
 | 
						|
      await subscription.unsubscribe()
 | 
						|
      await deleteSubscription(instanceName, accessToken)
 | 
						|
      await updateAlerts(instanceName, pushSubscription.alerts)
 | 
						|
    } else {
 | 
						|
      store.set({ pushSubscription: backendSubscription })
 | 
						|
      store.save()
 | 
						|
    }
 | 
						|
  } catch (e) {
 | 
						|
    // TODO: Better way to detect 404
 | 
						|
    if (e.message.startsWith('404:')) {
 | 
						|
      await subscription.unsubscribe()
 | 
						|
      store.set({ pushSubscription: null })
 | 
						|
      store.save()
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export async function updateAlerts (instanceName, alerts) {
 | 
						|
  const { loggedInInstances } = store.get()
 | 
						|
  const accessToken = loggedInInstances[instanceName].access_token
 | 
						|
 | 
						|
  const registration = await navigator.serviceWorker.ready
 | 
						|
  let subscription = await registration.pushManager.getSubscription()
 | 
						|
 | 
						|
  if (subscription === null) {
 | 
						|
    // We need applicationServerKey in order to register a push subscription
 | 
						|
    // but the API doesn't expose it as a constant (as it should).
 | 
						|
    // So we need to register a subscription with a dummy applicationServerKey,
 | 
						|
    // send it to the backend saves it and return applicationServerKey, which
 | 
						|
    // we use to register a new subscription.
 | 
						|
    // https://github.com/tootsuite/mastodon/issues/8785
 | 
						|
    subscription = await registration.pushManager.subscribe({
 | 
						|
      applicationServerKey: urlBase64ToUint8Array(dummyApplicationServerKey),
 | 
						|
      userVisibleOnly: true
 | 
						|
    })
 | 
						|
 | 
						|
    let backendSubscription = await postSubscription(instanceName, accessToken, subscription, alerts)
 | 
						|
 | 
						|
    await subscription.unsubscribe()
 | 
						|
 | 
						|
    subscription = await registration.pushManager.subscribe({
 | 
						|
      applicationServerKey: urlBase64ToUint8Array(backendSubscription.server_key),
 | 
						|
      userVisibleOnly: true
 | 
						|
    })
 | 
						|
 | 
						|
    backendSubscription = await postSubscription(instanceName, accessToken, subscription, alerts)
 | 
						|
 | 
						|
    store.set({ pushSubscription: backendSubscription })
 | 
						|
    store.save()
 | 
						|
  } else {
 | 
						|
    try {
 | 
						|
      const backendSubscription = await putSubscription(instanceName, accessToken, alerts)
 | 
						|
      store.set({ pushSubscription: backendSubscription })
 | 
						|
      store.save()
 | 
						|
    } catch (e) {
 | 
						|
      const backendSubscription = await postSubscription(instanceName, accessToken, subscription, alerts)
 | 
						|
      store.set({ pushSubscription: backendSubscription })
 | 
						|
      store.save()
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |