about summary refs log tree commit diff
path: root/src/lib/notifications/notifications.ts
blob: 38c18bf3fe59c49bea58d04d25935541fd03c284 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import * as Notifications from 'expo-notifications'
import {BskyAgent} from '@atproto/api'

import {logger} from '#/logger'
import {SessionAccount} from '#/state/session'
import {devicePlatform} from 'platform/detection'

const SERVICE_DID = (serviceUrl?: string) =>
  serviceUrl?.includes('staging')
    ? 'did:web:api.staging.bsky.dev'
    : 'did:web:api.bsky.app'

export async function requestPermissionsAndRegisterToken(
  getAgent: () => BskyAgent,
  account: SessionAccount,
) {
  // request notifications permission once the user has logged in
  const perms = await Notifications.getPermissionsAsync()
  if (!perms.granted) {
    await Notifications.requestPermissionsAsync()
  }

  // register the push token with the server
  const token = await Notifications.getDevicePushTokenAsync()
  try {
    await getAgent().api.app.bsky.notification.registerPush({
      serviceDid: SERVICE_DID(account.service),
      platform: devicePlatform,
      token: token.data,
      appId: 'xyz.blueskyweb.app',
    })
    logger.debug(
      'Notifications: Sent push token (init)',
      {
        tokenType: token.type,
        token: token.data,
      },
      logger.DebugContext.notifications,
    )
  } catch (error) {
    logger.error('Notifications: Failed to set push token', {message: error})
  }
}

export function registerTokenChangeHandler(
  getAgent: () => BskyAgent,
  account: SessionAccount,
): () => void {
  // listens for new changes to the push token
  // In rare situations, a push token may be changed by the push notification service while the app is running. When a token is rolled, the old one becomes invalid and sending notifications to it will fail. A push token listener will let you handle this situation gracefully by registering the new token with your backend right away.
  const sub = Notifications.addPushTokenListener(async newToken => {
    logger.debug(
      'Notifications: Push token changed',
      {tokenType: newToken.data, token: newToken.type},
      logger.DebugContext.notifications,
    )
    try {
      await getAgent().api.app.bsky.notification.registerPush({
        serviceDid: SERVICE_DID(account.service),
        platform: devicePlatform,
        token: newToken.data,
        appId: 'xyz.blueskyweb.app',
      })
      logger.debug(
        'Notifications: Sent push token (event)',
        {
          tokenType: newToken.type,
          token: newToken.data,
        },
        logger.DebugContext.notifications,
      )
    } catch (error) {
      logger.error('Notifications: Failed to set push token', {message: error})
    }
  })
  return () => {
    sub.remove()
  }
}