expo-pusher-push-notifications 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # expo-pusher-push-notifications
2
2
 
3
- Push notifications for Expo and React Native, powered by [Pusher Beams](https://pusher.com/beams). Subscribe devices to topics, bind them to your signed-in users, and get custom sounds, Android channels, badges, and local notifications along the way.
3
+ Push notifications for Expo and React Native. Two ways to use it:
4
+
5
+ 1. **Pusher Beams** — subscribe devices to interests (topics) and/or bind them to your signed-in users. Uses [Pusher Beams](https://pusher.com/beams).
6
+ 2. **Device token** — get the raw FCM (Android) / APNs (iOS) token for your own push path. No Beams, no `expo-notifications`, no EAS.
7
+
8
+ Both get custom sounds, Android channels, badges, and local notifications.
4
9
 
5
10
  ```sh
6
11
  npx expo install expo-pusher-push-notifications
@@ -27,7 +32,9 @@ await Interests.subscribe('news');
27
32
 
28
33
  That device now gets pushes sent to `news`. Full console steps (APNs, Firebase, Beams) are in [Setup](docs/setup.md).
29
34
 
30
- ## Subscribe to interests (topics)
35
+ ## Path 1: Pusher Beams
36
+
37
+ ### Subscribe to interests (topics)
31
38
 
32
39
  Interests are topics like `news`, `order-42`, or `team-7`. Every device subscribed to one gets the push.
33
40
 
@@ -38,7 +45,7 @@ await Interests.unsubscribe('order-42');
38
45
 
39
46
  More in [Interests](docs/interests.md).
40
47
 
41
- ## Bind a device to a user
48
+ ### Bind a device to a user
42
49
 
43
50
  To get pushes meant for a specific signed-in user on all their devices, bind the device to that user.
44
51
 
@@ -59,6 +66,20 @@ await Users.logout();
59
66
 
60
67
  You can use interests and users together. More in [Users](docs/users.md).
61
68
 
69
+ ## Path 2: Device token
70
+
71
+ No Beams instance needed (leave `instanceId` out of the plugin config).
72
+
73
+ ```ts
74
+ import { DeviceToken } from 'expo-pusher-push-notifications';
75
+
76
+ const token = await DeviceToken.start(); // { type: 'fcm' | 'apns', platform, token }
77
+ DeviceToken.onChange((t) => { /* token rotated */ });
78
+ await DeviceToken.delete(); // on sign-out
79
+ ```
80
+
81
+ You get the token in the app; sending it to your backend and pushing from there is up to you. More in [Device token](docs/direct.md).
82
+
62
83
  ## Extras
63
84
 
64
85
  ```ts
@@ -77,6 +98,7 @@ Custom sounds go in the plugin's `sounds` option. Details in [Extras](docs/extra
77
98
  - [Setup](docs/setup.md)
78
99
  - [Interests](docs/interests.md)
79
100
  - [Users](docs/users.md)
101
+ - [Device token](docs/direct.md)
80
102
  - [Sounds, channels, badges, local notifications](docs/extras.md)
81
103
  - [Full API](docs/api.md)
82
104
  - [Migrating from react-native-pusher-push-notifications](docs/migrating.md)
@@ -84,7 +106,6 @@ Custom sounds go in the plugin's `sounds` option. Details in [Extras](docs/extra
84
106
  ## Good to know
85
107
 
86
108
  - This module owns the iOS notification delegate and the Android FCM service, so don't run it alongside `expo-notifications` or `@react-native-firebase/messaging`.
87
- - Want a raw FCM / APNs token without Beams? Use [`expo-notifications`](https://docs.expo.dev/versions/latest/sdk/notifications/) instead.
88
109
  - Need realtime Pusher **Channels** (websockets)? Use [`pusher-js`](https://github.com/pusher/pusher-js).
89
110
 
90
111
  ## License
@@ -9,6 +9,7 @@ import android.content.Intent
9
9
  import android.os.Build
10
10
  import android.os.SystemClock
11
11
  import androidx.core.app.NotificationManagerCompat
12
+ import com.google.firebase.messaging.FirebaseMessaging
12
13
  import com.pusher.pushnotifications.BeamsCallback
13
14
  import com.pusher.pushnotifications.PushNotifications
14
15
  import com.pusher.pushnotifications.PusherCallbackError
@@ -75,6 +76,24 @@ class ExpoPusherPushNotificationsModule : Module() {
75
76
  AsyncFunction("clearAllState") { PushNotifications.clearAllState() }
76
77
  AsyncFunction("stop") { PushNotifications.stop() }
77
78
 
79
+ // ---- Raw device token (FCM) ----
80
+ AsyncFunction("registerForDeviceToken") { promise: Promise ->
81
+ FirebaseMessaging.getInstance().token.addOnCompleteListener { t ->
82
+ if (t.isSuccessful && t.result != null) {
83
+ NotificationHelper.saveToken(context, t.result)
84
+ sendEvent("registered", mapOf("deviceToken" to t.result, "type" to "fcm"))
85
+ promise.resolve(tokenMap(t.result))
86
+ } else promise.reject("E_FCM_TOKEN", t.exception?.message ?: "Failed to get FCM token", t.exception)
87
+ }
88
+ }
89
+ AsyncFunction("getDevicePushToken") { -> NotificationHelper.savedToken(context)?.let { tokenMap(it) } }
90
+ AsyncFunction("deleteDevicePushToken") { promise: Promise ->
91
+ FirebaseMessaging.getInstance().deleteToken().addOnCompleteListener { t ->
92
+ NotificationHelper.saveToken(context, null)
93
+ if (t.isSuccessful) promise.resolve(null) else promise.reject("E_FCM_DELETE", t.exception?.message, t.exception)
94
+ }
95
+ }
96
+
78
97
  // ---- Permissions ----
79
98
  AsyncFunction("requestPermission") { promise: Promise ->
80
99
  val perms = appContext.permissions
@@ -140,6 +159,8 @@ class ExpoPusherPushNotificationsModule : Module() {
140
159
  override fun onFailure(error: PusherCallbackError) = promise.reject("E_SET_USER_ID", error.message, null)
141
160
  }
142
161
 
162
+ private fun tokenMap(token: String) = mapOf("type" to "fcm", "platform" to "android", "token" to token)
163
+
143
164
  private fun status(): String =
144
165
  if (NotificationManagerCompat.from(context).areNotificationsEnabled()) PermissionsStatus.GRANTED.status
145
166
  else if (Build.VERSION.SDK_INT >= 33) PermissionsStatus.UNDETERMINED.status else PermissionsStatus.DENIED.status
@@ -106,6 +106,10 @@ object NotificationHelper {
106
106
  if (n <= 0) NotificationManagerCompat.from(ctx).cancelAll()
107
107
  }
108
108
 
109
+ fun saveToken(ctx: Context, token: String?) =
110
+ ctx.getSharedPreferences(PREFS, Context.MODE_PRIVATE).edit().putString("fcm_token", token).apply()
111
+ fun savedToken(ctx: Context) = ctx.getSharedPreferences(PREFS, Context.MODE_PRIVATE).getString("fcm_token", null)
112
+
109
113
  fun show(ctx: Context, id: Int, title: String?, body: String?, data: Map<String, String>, sound: String?, channelId: String?) {
110
114
  ensureChannels(ctx)
111
115
  val launch = ctx.packageManager.getLaunchIntentForPackage(ctx.packageName)?.apply {
@@ -4,8 +4,8 @@ import com.google.firebase.messaging.RemoteMessage
4
4
  import com.pusher.pushnotifications.fcm.MessagingService
5
5
 
6
6
  /**
7
- * The app's FCM service. Extends the Beams MessagingService so Beams keeps working,
8
- * and adds foreground display, custom sounds/channels and badge handling on top.
7
+ * Single FCM service for all three modes. Extends the Beams MessagingService so Beams keeps working
8
+ * in `interests`/`users` mode; in `device` mode it simply receives raw FCM messages from your server.
9
9
  */
10
10
  class PusherMessagingService : MessagingService() {
11
11
  companion object { @Volatile var module: ExpoPusherPushNotificationsModule? = null }
@@ -39,6 +39,7 @@ class PusherMessagingService : MessagingService() {
39
39
 
40
40
  override fun onNewToken(token: String) {
41
41
  super.onNewToken(token)
42
+ NotificationHelper.saveToken(this, token)
42
43
  module?.emit("registered", mapOf("deviceToken" to token, "type" to "fcm"))
43
44
  }
44
45
  }
@@ -1,14 +1,16 @@
1
1
  /**
2
- * Which Beams auth path the app uses.
2
+ * Delivery mode.
3
3
  *
4
- * - `interests`: devices subscribe to named interests; your server calls Beams `publishToInterests`.
5
- * - `users`: the device is bound to a user via `setUserId`; your server calls Beams `publishToUsers`.
4
+ * - `interests`: Pusher Beams interests. Devices subscribe to named interests; server calls Beams `publishToInterests`.
5
+ * - `users`: Pusher Beams Authenticated Users. Device is bound to a user via `setUserId`; server calls Beams `publishToUsers`.
6
+ * - `device`: Raw device-token push. Beams is NOT started. The module obtains the native FCM (Android) /
7
+ * APNs (iOS) device token and hands it to you; your server sends directly to FCM / APNs.
6
8
  */
7
- export type PusherTransportMode = 'interests' | 'users';
9
+ export type PusherTransportMode = 'interests' | 'users' | 'device';
8
10
  export interface PusherConfig {
9
- /** Pusher Beams instance ID. */
10
- instanceId: string;
11
- /** Beams auth path: `interests` (default) or `users`. */
11
+ /** Pusher Beams instance ID. Required for `interests` and `users`; ignored for `device`. */
12
+ instanceId?: string;
13
+ /** Defaults to `interests`. */
12
14
  mode?: PusherTransportMode;
13
15
  /** Ask for notification permission (iOS alert/sound/badge, Android 13+ POST_NOTIFICATIONS) during start. Default true. */
14
16
  requestPermission?: boolean;
@@ -25,6 +27,13 @@ export interface BeamsTokenProvider {
25
27
  * (the b8ne `setUserId(userId, token)` style).
26
28
  */
27
29
  export type BeamsAuth = BeamsTokenProvider | string;
30
+ export type DevicePushTokenType = 'fcm' | 'apns';
31
+ export interface DevicePushToken {
32
+ type: DevicePushTokenType;
33
+ /** FCM registration token (Android) or hex-encoded APNs token (iOS). */
34
+ token: string;
35
+ platform: 'android' | 'ios';
36
+ }
28
37
  export interface PusherNotification {
29
38
  title?: string;
30
39
  body?: string;
@@ -33,9 +42,9 @@ export interface PusherNotification {
33
42
  appState: 'foreground' | 'background' | 'opened';
34
43
  }
35
44
  export interface RegisteredEvent {
36
- /** Native token the device registered with (FCM on Android, hex APNs on iOS). Beams handles it for you. */
45
+ /** Native device token. In `device` mode this is the token your server sends to. */
37
46
  deviceToken: string;
38
- type: 'fcm' | 'apns';
47
+ type: DevicePushTokenType;
39
48
  }
40
49
  export interface SubscriptionsChangedEvent {
41
50
  interests: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoPusherPushNotifications.types.d.ts","sourceRoot":"","sources":["../src/ExpoPusherPushNotifications.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ExpoPusherPushNotifications.types.d.ts","sourceRoot":"","sources":["../src/ExpoPusherPushNotifications.types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoPusherPushNotifications.types.js","sourceRoot":"","sources":["../src/ExpoPusherPushNotifications.types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Which Beams auth path the app uses.\n *\n * - `interests`: devices subscribe to named interests; your server calls Beams `publishToInterests`.\n * - `users`: the device is bound to a user via `setUserId`; your server calls Beams `publishToUsers`.\n */\nexport type PusherTransportMode = 'interests' | 'users';\n\nexport interface PusherConfig {\n /** Pusher Beams instance ID. */\n instanceId: string;\n /** Beams auth path: `interests` (default) or `users`. */\n mode?: PusherTransportMode;\n /** Ask for notification permission (iOS alert/sound/badge, Android 13+ POST_NOTIFICATIONS) during start. Default true. */\n requestPermission?: boolean;\n}\n\n/** Remote token endpoint used by the Beams SDK when binding a device to a user. */\nexport interface BeamsTokenProvider {\n /** HTTPS endpoint on your backend that returns `{ token: string }`. */\n url: string;\n headers?: Record<string, string>;\n queryParams?: Record<string, string>;\n}\n\n/**\n * User auth: either a remote token provider (recommended), or a pre-fetched Beams token string\n * (the b8ne `setUserId(userId, token)` style).\n */\nexport type BeamsAuth = BeamsTokenProvider | string;\n\nexport interface PusherNotification {\n title?: string;\n body?: string;\n data: Record<string, unknown>;\n /** `foreground`: received while running; `background`: received in background; `opened`: user tapped it. */\n appState: 'foreground' | 'background' | 'opened';\n}\n\nexport interface RegisteredEvent {\n /** Native token the device registered with (FCM on Android, hex APNs on iOS). Beams handles it for you. */\n deviceToken: string;\n type: 'fcm' | 'apns';\n}\n\nexport interface SubscriptionsChangedEvent {\n interests: string[];\n}\n\nexport interface PusherErrorEvent {\n code: string;\n message: string;\n}\n\nexport type PermissionStatus = 'granted' | 'denied' | 'undetermined' | 'provisional';\n\nexport type AndroidImportance = 'min' | 'low' | 'default' | 'high' | 'max';\n\nexport interface AndroidNotificationChannel {\n id: string;\n name: string;\n description?: string;\n importance?: AndroidImportance;\n /** Bundled sound file name WITHOUT path, e.g. `ding.wav` or `ding`. Must be listed in the plugin's `sounds`. `null` = silent. */\n sound?: string | null;\n vibrate?: boolean;\n lightColor?: string;\n showBadge?: boolean;\n}\n\nexport interface LocalNotification {\n title?: string;\n body?: string;\n data?: Record<string, string>;\n /** Bundled sound file name, e.g. `ding.wav`; `default` for system sound. On Android 8+ the channel's sound wins. */\n sound?: string;\n /** Android channel id. Defaults to the plugin's default channel. */\n channelId?: string;\n /** iOS badge to set with this notification. */\n badge?: number;\n}\n\nexport interface ScheduledNotification extends LocalNotification {\n /** Stable id; reuse to replace. Generated if omitted. */\n id?: string;\n /** Fire after this many seconds (>= 1). */\n seconds: number;\n}\n\nexport type ExpoPusherPushNotificationsModuleEvents = {\n notification: (event: PusherNotification) => void;\n registered: (event: RegisteredEvent) => void;\n subscriptionsChanged: (event: SubscriptionsChangedEvent) => void;\n error: (event: PusherErrorEvent) => void;\n};\n\nexport type PusherEventName = keyof ExpoPusherPushNotificationsModuleEvents;\n"]}
1
+ {"version":3,"file":"ExpoPusherPushNotifications.types.js","sourceRoot":"","sources":["../src/ExpoPusherPushNotifications.types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Delivery mode.\n *\n * - `interests`: Pusher Beams interests. Devices subscribe to named interests; server calls Beams `publishToInterests`.\n * - `users`: Pusher Beams Authenticated Users. Device is bound to a user via `setUserId`; server calls Beams `publishToUsers`.\n * - `device`: Raw device-token push. Beams is NOT started. The module obtains the native FCM (Android) /\n * APNs (iOS) device token and hands it to you; your server sends directly to FCM / APNs.\n */\nexport type PusherTransportMode = 'interests' | 'users' | 'device';\n\nexport interface PusherConfig {\n /** Pusher Beams instance ID. Required for `interests` and `users`; ignored for `device`. */\n instanceId?: string;\n /** Defaults to `interests`. */\n mode?: PusherTransportMode;\n /** Ask for notification permission (iOS alert/sound/badge, Android 13+ POST_NOTIFICATIONS) during start. Default true. */\n requestPermission?: boolean;\n}\n\n/** Remote token endpoint used by the Beams SDK when binding a device to a user. */\nexport interface BeamsTokenProvider {\n /** HTTPS endpoint on your backend that returns `{ token: string }`. */\n url: string;\n headers?: Record<string, string>;\n queryParams?: Record<string, string>;\n}\n\n/**\n * User auth: either a remote token provider (recommended), or a pre-fetched Beams token string\n * (the b8ne `setUserId(userId, token)` style).\n */\nexport type BeamsAuth = BeamsTokenProvider | string;\n\nexport type DevicePushTokenType = 'fcm' | 'apns';\n\nexport interface DevicePushToken {\n type: DevicePushTokenType;\n /** FCM registration token (Android) or hex-encoded APNs token (iOS). */\n token: string;\n platform: 'android' | 'ios';\n}\n\nexport interface PusherNotification {\n title?: string;\n body?: string;\n data: Record<string, unknown>;\n /** `foreground`: received while running; `background`: received in background; `opened`: user tapped it. */\n appState: 'foreground' | 'background' | 'opened';\n}\n\nexport interface RegisteredEvent {\n /** Native device token. In `device` mode this is the token your server sends to. */\n deviceToken: string;\n type: DevicePushTokenType;\n}\n\nexport interface SubscriptionsChangedEvent {\n interests: string[];\n}\n\nexport interface PusherErrorEvent {\n code: string;\n message: string;\n}\n\nexport type PermissionStatus = 'granted' | 'denied' | 'undetermined' | 'provisional';\n\nexport type AndroidImportance = 'min' | 'low' | 'default' | 'high' | 'max';\n\nexport interface AndroidNotificationChannel {\n id: string;\n name: string;\n description?: string;\n importance?: AndroidImportance;\n /** Bundled sound file name WITHOUT path, e.g. `ding.wav` or `ding`. Must be listed in the plugin's `sounds`. `null` = silent. */\n sound?: string | null;\n vibrate?: boolean;\n lightColor?: string;\n showBadge?: boolean;\n}\n\nexport interface LocalNotification {\n title?: string;\n body?: string;\n data?: Record<string, string>;\n /** Bundled sound file name, e.g. `ding.wav`; `default` for system sound. On Android 8+ the channel's sound wins. */\n sound?: string;\n /** Android channel id. Defaults to the plugin's default channel. */\n channelId?: string;\n /** iOS badge to set with this notification. */\n badge?: number;\n}\n\nexport interface ScheduledNotification extends LocalNotification {\n /** Stable id; reuse to replace. Generated if omitted. */\n id?: string;\n /** Fire after this many seconds (>= 1). */\n seconds: number;\n}\n\nexport type ExpoPusherPushNotificationsModuleEvents = {\n notification: (event: PusherNotification) => void;\n registered: (event: RegisteredEvent) => void;\n subscriptionsChanged: (event: SubscriptionsChangedEvent) => void;\n error: (event: PusherErrorEvent) => void;\n};\n\nexport type PusherEventName = keyof ExpoPusherPushNotificationsModuleEvents;\n"]}
@@ -1,5 +1,5 @@
1
1
  import { NativeModule } from 'expo';
2
- import type { AndroidNotificationChannel, BeamsTokenProvider, ExpoPusherPushNotificationsModuleEvents, LocalNotification, PermissionStatus, PusherNotification, ScheduledNotification } from './ExpoPusherPushNotifications.types';
2
+ import type { AndroidNotificationChannel, BeamsTokenProvider, DevicePushToken, ExpoPusherPushNotificationsModuleEvents, LocalNotification, PermissionStatus, PusherNotification, ScheduledNotification } from './ExpoPusherPushNotifications.types';
3
3
  declare class ExpoPusherPushNotificationsNativeModule extends NativeModule<ExpoPusherPushNotificationsModuleEvents> {
4
4
  start(instanceId: string): Promise<void>;
5
5
  addDeviceInterest(interest: string): Promise<void>;
@@ -11,6 +11,9 @@ declare class ExpoPusherPushNotificationsNativeModule extends NativeModule<ExpoP
11
11
  setUserIdWithToken(userId: string, token: string): Promise<void>;
12
12
  clearAllState(): Promise<void>;
13
13
  stop(): Promise<void>;
14
+ registerForDeviceToken(): Promise<DevicePushToken>;
15
+ getDevicePushToken(): Promise<DevicePushToken | null>;
16
+ deleteDevicePushToken(): Promise<void>;
14
17
  requestPermission(): Promise<PermissionStatus>;
15
18
  getPermissionStatus(): Promise<PermissionStatus>;
16
19
  createChannel(channel: AndroidNotificationChannel): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoPusherPushNotificationsModule.d.ts","sourceRoot":"","sources":["../src/ExpoPusherPushNotificationsModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,KAAK,EACV,0BAA0B,EAC1B,kBAAkB,EAClB,uCAAuC,EACvC,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,OAAO,uCAAwC,SAAQ,YAAY,CAAC,uCAAuC,CAAC;IACjH,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACxC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAClD,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACrD,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IACtD,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IACvC,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IACrC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3E,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAChE,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAC9B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAErB,iBAAiB,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAC9C,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAEhD,aAAa,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;IACjE,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACxC,WAAW,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAEpD,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAChC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAE3C,wBAAwB,CAAC,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAC/D,yBAAyB,CAAC,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IACpE,2BAA2B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACtD,+BAA+B,IAAI,OAAO,CAAC,IAAI,CAAC;IAChD,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC;IACxC,sBAAsB,IAAI,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;CAC7D;;AAED,wBAA2G"}
1
+ {"version":3,"file":"ExpoPusherPushNotificationsModule.d.ts","sourceRoot":"","sources":["../src/ExpoPusherPushNotificationsModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,KAAK,EACV,0BAA0B,EAC1B,kBAAkB,EAClB,eAAe,EACf,uCAAuC,EACvC,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,OAAO,uCAAwC,SAAQ,YAAY,CAAC,uCAAuC,CAAC;IACjH,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACxC,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAClD,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACrD,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IACtD,kBAAkB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IACvC,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IACrC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3E,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAChE,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAC9B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAErB,sBAAsB,IAAI,OAAO,CAAC,eAAe,CAAC;IAClD,kBAAkB,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IACrD,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAEtC,iBAAiB,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAC9C,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAEhD,aAAa,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,IAAI,CAAC;IACjE,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACxC,WAAW,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAEpD,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAChC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAE3C,wBAAwB,CAAC,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAC/D,yBAAyB,CAAC,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC;IACpE,2BAA2B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IACtD,+BAA+B,IAAI,OAAO,CAAC,IAAI,CAAC;IAChD,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC;IACxC,sBAAsB,IAAI,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;CAC7D;;AAED,wBAA2G"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoPusherPushNotificationsModule.js","sourceRoot":"","sources":["../src/ExpoPusherPushNotificationsModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AA0CzD,eAAe,mBAAmB,CAA0C,6BAA6B,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\nimport type {\n AndroidNotificationChannel,\n BeamsTokenProvider,\n ExpoPusherPushNotificationsModuleEvents,\n LocalNotification,\n PermissionStatus,\n PusherNotification,\n ScheduledNotification,\n} from './ExpoPusherPushNotifications.types';\n\ndeclare class ExpoPusherPushNotificationsNativeModule extends NativeModule<ExpoPusherPushNotificationsModuleEvents> {\n start(instanceId: string): Promise<void>;\n addDeviceInterest(interest: string): Promise<void>;\n removeDeviceInterest(interest: string): Promise<void>;\n setDeviceInterests(interests: string[]): Promise<void>;\n getDeviceInterests(): Promise<string[]>;\n clearDeviceInterests(): Promise<void>;\n setUserId(userId: string, tokenProvider: BeamsTokenProvider): Promise<void>;\n setUserIdWithToken(userId: string, token: string): Promise<void>;\n clearAllState(): Promise<void>;\n stop(): Promise<void>;\n // permissions\n requestPermission(): Promise<PermissionStatus>;\n getPermissionStatus(): Promise<PermissionStatus>;\n // channels (Android; no-ops on iOS)\n createChannel(channel: AndroidNotificationChannel): Promise<void>;\n deleteChannel(id: string): Promise<void>;\n getChannels(): Promise<AndroidNotificationChannel[]>;\n // badge\n getBadgeCount(): Promise<number>;\n setBadgeCount(count: number): Promise<void>;\n // local\n presentLocalNotification(n: LocalNotification): Promise<string>;\n scheduleLocalNotification(n: ScheduledNotification): Promise<string>;\n cancelScheduledNotification(id: string): Promise<void>;\n cancelAllScheduledNotifications(): Promise<void>;\n dismissAllNotifications(): Promise<void>;\n getInitialNotification(): Promise<PusherNotification | null>;\n}\n\nexport default requireNativeModule<ExpoPusherPushNotificationsNativeModule>('ExpoPusherPushNotifications');\n"]}
1
+ {"version":3,"file":"ExpoPusherPushNotificationsModule.js","sourceRoot":"","sources":["../src/ExpoPusherPushNotificationsModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AA+CzD,eAAe,mBAAmB,CAA0C,6BAA6B,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\nimport type {\n AndroidNotificationChannel,\n BeamsTokenProvider,\n DevicePushToken,\n ExpoPusherPushNotificationsModuleEvents,\n LocalNotification,\n PermissionStatus,\n PusherNotification,\n ScheduledNotification,\n} from './ExpoPusherPushNotifications.types';\n\ndeclare class ExpoPusherPushNotificationsNativeModule extends NativeModule<ExpoPusherPushNotificationsModuleEvents> {\n start(instanceId: string): Promise<void>;\n addDeviceInterest(interest: string): Promise<void>;\n removeDeviceInterest(interest: string): Promise<void>;\n setDeviceInterests(interests: string[]): Promise<void>;\n getDeviceInterests(): Promise<string[]>;\n clearDeviceInterests(): Promise<void>;\n setUserId(userId: string, tokenProvider: BeamsTokenProvider): Promise<void>;\n setUserIdWithToken(userId: string, token: string): Promise<void>;\n clearAllState(): Promise<void>;\n stop(): Promise<void>;\n // device-token mode\n registerForDeviceToken(): Promise<DevicePushToken>;\n getDevicePushToken(): Promise<DevicePushToken | null>;\n deleteDevicePushToken(): Promise<void>;\n // permissions\n requestPermission(): Promise<PermissionStatus>;\n getPermissionStatus(): Promise<PermissionStatus>;\n // channels (Android; no-ops on iOS)\n createChannel(channel: AndroidNotificationChannel): Promise<void>;\n deleteChannel(id: string): Promise<void>;\n getChannels(): Promise<AndroidNotificationChannel[]>;\n // badge\n getBadgeCount(): Promise<number>;\n setBadgeCount(count: number): Promise<void>;\n // local\n presentLocalNotification(n: LocalNotification): Promise<string>;\n scheduleLocalNotification(n: ScheduledNotification): Promise<string>;\n cancelScheduledNotification(id: string): Promise<void>;\n cancelAllScheduledNotifications(): Promise<void>;\n dismissAllNotifications(): Promise<void>;\n getInitialNotification(): Promise<PusherNotification | null>;\n}\n\nexport default requireNativeModule<ExpoPusherPushNotificationsNativeModule>('ExpoPusherPushNotifications');\n"]}
package/build/index.d.ts CHANGED
@@ -1,8 +1,13 @@
1
1
  import type { EventSubscription } from 'expo-modules-core';
2
- import type { AndroidNotificationChannel, BeamsAuth, ExpoPusherPushNotificationsModuleEvents, LocalNotification, PermissionStatus, PusherConfig, PusherEventName, PusherNotification, PusherTransportMode, ScheduledNotification } from './ExpoPusherPushNotifications.types';
2
+ import type { AndroidNotificationChannel, BeamsAuth, DevicePushToken, ExpoPusherPushNotificationsModuleEvents, LocalNotification, PermissionStatus, PusherConfig, PusherEventName, PusherNotification, PusherTransportMode, ScheduledNotification } from './ExpoPusherPushNotifications.types';
3
3
  export * from './ExpoPusherPushNotifications.types';
4
- /** Starts Pusher Beams. */
5
- export declare function start(config: PusherConfig): Promise<void>;
4
+ /**
5
+ * Starts the module.
6
+ * - Pusher Beams (`interests` / `users`): starts the Beams SDK (requires `instanceId`).
7
+ * - Device token (`device`): does NOT start Beams; registers with FCM/APNs and resolves the raw device token.
8
+ * Resolves with the device token in `device` mode, otherwise `null`.
9
+ */
10
+ export declare function start(config: PusherConfig): Promise<DevicePushToken | null>;
6
11
  export declare function getMode(): PusherTransportMode;
7
12
  export declare function subscribe(interest: string): Promise<void>;
8
13
  export declare function unsubscribe(interest: string): Promise<void>;
@@ -11,6 +16,12 @@ export declare function getSubscriptions(): Promise<string[]>;
11
16
  export declare function clearSubscriptions(): Promise<void>;
12
17
  /** Pass a token provider `{ url, headers?, queryParams? }` or a pre-fetched Beams token string. */
13
18
  export declare function setUserId(userId: string, auth: BeamsAuth): Promise<void>;
19
+ /** Registers with FCM/APNs (if needed) and returns the native token. Works in any mode. */
20
+ export declare function registerForDeviceToken(): Promise<DevicePushToken>;
21
+ /** Last known native token, or null if not registered yet. */
22
+ export declare function getDevicePushToken(): Promise<DevicePushToken | null>;
23
+ /** Android: deletes the FCM token (a new one is issued on next register). iOS: unregisters from APNs. */
24
+ export declare function deleteDevicePushToken(): Promise<void>;
14
25
  export declare function requestPermission(): Promise<PermissionStatus>;
15
26
  export declare function getPermissionStatus(): Promise<PermissionStatus>;
16
27
  export declare function createChannel(channel: AndroidNotificationChannel): Promise<void>;
@@ -41,7 +52,7 @@ export declare const Interests: {
41
52
  /** Start Beams. */
42
53
  readonly start: (instanceId: string, opts?: {
43
54
  requestPermission?: boolean;
44
- }) => Promise<void>;
55
+ }) => Promise<undefined>;
45
56
  readonly subscribe: typeof subscribe;
46
57
  readonly unsubscribe: typeof unsubscribe;
47
58
  readonly set: typeof setSubscriptions;
@@ -60,19 +71,35 @@ export declare const Users: {
60
71
  /** Start Beams. Call `login()` after your own sign-in. */
61
72
  readonly start: (instanceId: string, opts?: {
62
73
  requestPermission?: boolean;
63
- }) => Promise<void>;
74
+ }) => Promise<undefined>;
64
75
  /** Bind this device to `userId`. `auth` is your token endpoint, or a Beams token you already fetched. */
65
76
  readonly login: typeof setUserId;
66
77
  /** Unbind the device (call on sign-out). */
67
78
  readonly logout: typeof clearAllState;
68
79
  readonly stop: typeof stop;
69
80
  };
81
+ /**
82
+ * Mode 3 — **direct FCM / APNs** (no Pusher at all).
83
+ * Use when your server already talks to FCM HTTP v1 / APNs, or you use another provider.
84
+ * You get the raw native token; send it to your backend and keep it fresh via the `registered` event.
85
+ */
86
+ export declare const DeviceToken: {
87
+ /** Register with FCM/APNs and resolve the native token. */
88
+ readonly start: (opts?: {
89
+ requestPermission?: boolean;
90
+ }) => Promise<DevicePushToken>;
91
+ readonly get: typeof getDevicePushToken;
92
+ /** Fires whenever the token is issued or rotated. */
93
+ readonly onChange: (cb: (token: DevicePushToken) => void) => EventSubscription;
94
+ /** Delete the token (call on sign-out). */
95
+ readonly delete: typeof deleteDevicePushToken;
96
+ };
70
97
  declare const _default: {
71
98
  readonly Interests: {
72
99
  /** Start Beams. */
73
100
  readonly start: (instanceId: string, opts?: {
74
101
  requestPermission?: boolean;
75
- }) => Promise<void>;
102
+ }) => Promise<undefined>;
76
103
  readonly subscribe: typeof subscribe;
77
104
  readonly unsubscribe: typeof unsubscribe;
78
105
  readonly set: typeof setSubscriptions;
@@ -86,13 +113,24 @@ declare const _default: {
86
113
  /** Start Beams. Call `login()` after your own sign-in. */
87
114
  readonly start: (instanceId: string, opts?: {
88
115
  requestPermission?: boolean;
89
- }) => Promise<void>;
116
+ }) => Promise<undefined>;
90
117
  /** Bind this device to `userId`. `auth` is your token endpoint, or a Beams token you already fetched. */
91
118
  readonly login: typeof setUserId;
92
119
  /** Unbind the device (call on sign-out). */
93
120
  readonly logout: typeof clearAllState;
94
121
  readonly stop: typeof stop;
95
122
  };
123
+ readonly DeviceToken: {
124
+ /** Register with FCM/APNs and resolve the native token. */
125
+ readonly start: (opts?: {
126
+ requestPermission?: boolean;
127
+ }) => Promise<DevicePushToken>;
128
+ readonly get: typeof getDevicePushToken;
129
+ /** Fires whenever the token is issued or rotated. */
130
+ readonly onChange: (cb: (token: DevicePushToken) => void) => EventSubscription;
131
+ /** Delete the token (call on sign-out). */
132
+ readonly delete: typeof deleteDevicePushToken;
133
+ };
96
134
  readonly start: typeof start;
97
135
  readonly getMode: typeof getMode;
98
136
  readonly subscribe: typeof subscribe;
@@ -101,6 +139,9 @@ declare const _default: {
101
139
  readonly getSubscriptions: typeof getSubscriptions;
102
140
  readonly clearSubscriptions: typeof clearSubscriptions;
103
141
  readonly setUserId: typeof setUserId;
142
+ readonly registerForDeviceToken: typeof registerForDeviceToken;
143
+ readonly getDevicePushToken: typeof getDevicePushToken;
144
+ readonly deleteDevicePushToken: typeof deleteDevicePushToken;
104
145
  readonly requestPermission: typeof requestPermission;
105
146
  readonly getPermissionStatus: typeof getPermissionStatus;
106
147
  readonly createChannel: typeof createChannel;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/build/index.js CHANGED
@@ -6,16 +6,31 @@ const PREFIX = 'expo-pusher-push-notifications';
6
6
  function assertBeams(fn) {
7
7
  if (!started)
8
8
  throw new Error(`${PREFIX}: call start() before ${fn}().`);
9
+ if (currentMode === 'device') {
10
+ throw new Error(`${PREFIX}: ${fn}() is a Pusher Beams API and is unavailable in 'device' mode.`);
11
+ }
9
12
  }
10
- /** Starts Pusher Beams. */
13
+ /**
14
+ * Starts the module.
15
+ * - Pusher Beams (`interests` / `users`): starts the Beams SDK (requires `instanceId`).
16
+ * - Device token (`device`): does NOT start Beams; registers with FCM/APNs and resolves the raw device token.
17
+ * Resolves with the device token in `device` mode, otherwise `null`.
18
+ */
11
19
  export async function start(config) {
12
- if (!config.instanceId)
13
- throw new Error(`${PREFIX}: instanceId is required.`);
20
+ const mode = config.mode ?? 'interests';
14
21
  if (config.requestPermission !== false)
15
22
  await Native.requestPermission();
16
- currentMode = config.mode ?? 'interests';
23
+ currentMode = mode;
24
+ if (mode === 'device') {
25
+ const token = await Native.registerForDeviceToken();
26
+ started = true;
27
+ return token;
28
+ }
29
+ if (!config.instanceId)
30
+ throw new Error(`${PREFIX}: instanceId is required for '${mode}' mode.`);
17
31
  await Native.start(config.instanceId);
18
32
  started = true;
33
+ return null;
19
34
  }
20
35
  export function getMode() {
21
36
  return currentMode;
@@ -50,6 +65,19 @@ export async function setUserId(userId, auth) {
50
65
  else
51
66
  await Native.setUserId(userId, auth);
52
67
  }
68
+ // ---- Mode 3: raw device token (direct FCM / APNs) ----
69
+ /** Registers with FCM/APNs (if needed) and returns the native token. Works in any mode. */
70
+ export async function registerForDeviceToken() {
71
+ return Native.registerForDeviceToken();
72
+ }
73
+ /** Last known native token, or null if not registered yet. */
74
+ export async function getDevicePushToken() {
75
+ return Native.getDevicePushToken();
76
+ }
77
+ /** Android: deletes the FCM token (a new one is issued on next register). iOS: unregisters from APNs. */
78
+ export async function deleteDevicePushToken() {
79
+ await Native.deleteDevicePushToken();
80
+ }
53
81
  // ---- Permissions ----
54
82
  export function requestPermission() {
55
83
  return Native.requestPermission();
@@ -103,10 +131,14 @@ export function getInitialNotification() {
103
131
  }
104
132
  // ---- Common ----
105
133
  export async function clearAllState() {
106
- await Native.clearAllState();
134
+ if (currentMode !== 'device')
135
+ await Native.clearAllState();
107
136
  }
108
137
  export async function stop() {
109
- await Native.stop();
138
+ if (currentMode === 'device')
139
+ await Native.deleteDevicePushToken();
140
+ else
141
+ await Native.stop();
110
142
  started = false;
111
143
  }
112
144
  /** Adds an event listener. Events fire for interests and users alike. */
@@ -116,8 +148,8 @@ export function addListener(eventName, listener) {
116
148
  /** Alias for `addListener` (old package's `on()`). */
117
149
  export const on = addListener;
118
150
  // ---------------------------------------------------------------------------
119
- // Convenience objects. Use either or both; everything else (sounds,
120
- // channels, badges, local notifications, events) works the same either way.
151
+ // Two paths: Pusher Beams (Interests / Users) or DeviceToken (raw FCM/APNs).
152
+ // Sounds, channels, badges, local notifications and events work on both.
121
153
  // ---------------------------------------------------------------------------
122
154
  /**
123
155
  * Pusher Beams **interests** (topic broadcast).
@@ -126,7 +158,7 @@ export const on = addListener;
126
158
  */
127
159
  export const Interests = {
128
160
  /** Start Beams. */
129
- start: (instanceId, opts = {}) => start({ ...opts, instanceId, mode: 'interests' }),
161
+ start: (instanceId, opts = {}) => start({ ...opts, instanceId, mode: 'interests' }).then(() => undefined),
130
162
  subscribe,
131
163
  unsubscribe,
132
164
  set: setSubscriptions,
@@ -143,18 +175,33 @@ export const Interests = {
143
175
  */
144
176
  export const Users = {
145
177
  /** Start Beams. Call `login()` after your own sign-in. */
146
- start: (instanceId, opts = {}) => start({ ...opts, instanceId, mode: 'users' }),
178
+ start: (instanceId, opts = {}) => start({ ...opts, instanceId, mode: 'users' }).then(() => undefined),
147
179
  /** Bind this device to `userId`. `auth` is your token endpoint, or a Beams token you already fetched. */
148
180
  login: setUserId,
149
181
  /** Unbind the device (call on sign-out). */
150
182
  logout: clearAllState,
151
183
  stop,
152
184
  };
185
+ /**
186
+ * Mode 3 — **direct FCM / APNs** (no Pusher at all).
187
+ * Use when your server already talks to FCM HTTP v1 / APNs, or you use another provider.
188
+ * You get the raw native token; send it to your backend and keep it fresh via the `registered` event.
189
+ */
190
+ export const DeviceToken = {
191
+ /** Register with FCM/APNs and resolve the native token. */
192
+ start: async (opts = {}) => (await start({ ...opts, mode: 'device' })),
193
+ get: getDevicePushToken,
194
+ /** Fires whenever the token is issued or rotated. */
195
+ onChange: (cb) => addListener('registered', ({ deviceToken, type }) => cb({ token: deviceToken, type, platform: type === 'fcm' ? 'android' : 'ios' })),
196
+ /** Delete the token (call on sign-out). */
197
+ delete: deleteDevicePushToken,
198
+ };
153
199
  export default {
154
- Interests, Users,
200
+ Interests, Users, DeviceToken,
155
201
  start, getMode,
156
202
  subscribe, unsubscribe, setSubscriptions, getSubscriptions, clearSubscriptions,
157
203
  setUserId,
204
+ registerForDeviceToken, getDevicePushToken, deleteDevicePushToken,
158
205
  requestPermission, getPermissionStatus,
159
206
  createChannel, deleteChannel, getChannels,
160
207
  getBadgeCount, setBadgeCount, incrementBadgeCount,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EventSubscription } from 'expo-modules-core';\n\nimport Native from './ExpoPusherPushNotificationsModule';\nimport type {\n AndroidNotificationChannel,\n BeamsAuth,\n ExpoPusherPushNotificationsModuleEvents,\n LocalNotification,\n PermissionStatus,\n PusherConfig,\n PusherEventName,\n PusherNotification,\n PusherTransportMode,\n ScheduledNotification,\n} from './ExpoPusherPushNotifications.types';\n\nexport * from './ExpoPusherPushNotifications.types';\n\nlet currentMode: PusherTransportMode = 'interests';\nlet started = false;\n\nconst PREFIX = 'expo-pusher-push-notifications';\n\nfunction assertBeams(fn: string): void {\n if (!started) throw new Error(`${PREFIX}: call start() before ${fn}().`);\n}\n\n/** Starts Pusher Beams. */\nexport async function start(config: PusherConfig): Promise<void> {\n if (!config.instanceId) throw new Error(`${PREFIX}: instanceId is required.`);\n if (config.requestPermission !== false) await Native.requestPermission();\n currentMode = config.mode ?? 'interests';\n await Native.start(config.instanceId);\n started = true;\n}\n\nexport function getMode(): PusherTransportMode {\n return currentMode;\n}\n\n// ---- Interests (topics) ----\nexport async function subscribe(interest: string): Promise<void> {\n assertBeams('subscribe');\n await Native.addDeviceInterest(interest);\n}\nexport async function unsubscribe(interest: string): Promise<void> {\n assertBeams('unsubscribe');\n await Native.removeDeviceInterest(interest);\n}\nexport async function setSubscriptions(interests: string[]): Promise<void> {\n assertBeams('setSubscriptions');\n await Native.setDeviceInterests(interests);\n}\nexport async function getSubscriptions(): Promise<string[]> {\n assertBeams('getSubscriptions');\n return Native.getDeviceInterests();\n}\nexport async function clearSubscriptions(): Promise<void> {\n assertBeams('clearSubscriptions');\n await Native.clearDeviceInterests();\n}\n\n// ---- Bind a device to a user ----\n/** Pass a token provider `{ url, headers?, queryParams? }` or a pre-fetched Beams token string. */\nexport async function setUserId(userId: string, auth: BeamsAuth): Promise<void> {\n assertBeams('setUserId');\n if (typeof auth === 'string') await Native.setUserIdWithToken(userId, auth);\n else await Native.setUserId(userId, auth);\n}\n\n// ---- Permissions ----\nexport function requestPermission(): Promise<PermissionStatus> {\n return Native.requestPermission();\n}\nexport function getPermissionStatus(): Promise<PermissionStatus> {\n return Native.getPermissionStatus();\n}\n\n// ---- Android notification channels (no-ops on iOS) ----\nexport function createChannel(channel: AndroidNotificationChannel): Promise<void> {\n return Native.createChannel(channel);\n}\nexport function deleteChannel(id: string): Promise<void> {\n return Native.deleteChannel(id);\n}\nexport function getChannels(): Promise<AndroidNotificationChannel[]> {\n return Native.getChannels();\n}\n\n// ---- Badge ----\nexport function getBadgeCount(): Promise<number> {\n return Native.getBadgeCount();\n}\nexport function setBadgeCount(count: number): Promise<void> {\n return Native.setBadgeCount(Math.max(0, Math.floor(count)));\n}\nexport async function incrementBadgeCount(by = 1): Promise<number> {\n const next = (await Native.getBadgeCount()) + by;\n await setBadgeCount(next);\n return Math.max(0, next);\n}\n\n// ---- Local notifications ----\nexport function presentLocalNotification(n: LocalNotification): Promise<string> {\n return Native.presentLocalNotification(n);\n}\nexport function scheduleLocalNotification(n: ScheduledNotification): Promise<string> {\n if (!(n.seconds >= 1)) throw new Error(`${PREFIX}: seconds must be >= 1.`);\n return Native.scheduleLocalNotification(n);\n}\nexport function cancelScheduledNotification(id: string): Promise<void> {\n return Native.cancelScheduledNotification(id);\n}\nexport function cancelAllScheduledNotifications(): Promise<void> {\n return Native.cancelAllScheduledNotifications();\n}\nexport function dismissAllNotifications(): Promise<void> {\n return Native.dismissAllNotifications();\n}\n/** The notification whose tap launched the app (cold start), if any. */\nexport function getInitialNotification(): Promise<PusherNotification | null> {\n return Native.getInitialNotification();\n}\n\n// ---- Common ----\nexport async function clearAllState(): Promise<void> {\n await Native.clearAllState();\n}\nexport async function stop(): Promise<void> {\n await Native.stop();\n started = false;\n}\n\n/** Adds an event listener. Events fire for interests and users alike. */\nexport function addListener<E extends PusherEventName>(\n eventName: E,\n listener: ExpoPusherPushNotificationsModuleEvents[E]\n): EventSubscription {\n return Native.addListener(eventName, listener);\n}\n/** Alias for `addListener` (old package's `on()`). */\nexport const on = addListener;\n\n// ---------------------------------------------------------------------------\n// Convenience objects. Use either or both; everything else (sounds,\n// channels, badges, local notifications, events) works the same either way.\n// ---------------------------------------------------------------------------\n\n/**\n * Pusher Beams **interests** (topic broadcast).\n * Use when many devices should get the same push: \"news\", \"order-42\", \"team-7\".\n * Server: `beams.publishToInterests([...], payload)`.\n */\nexport const Interests = {\n /** Start Beams. */\n start: (instanceId: string, opts: { requestPermission?: boolean } = {}) =>\n start({ ...opts, instanceId, mode: 'interests' }),\n subscribe,\n unsubscribe,\n set: setSubscriptions,\n get: getSubscriptions,\n clear: clearSubscriptions,\n /** Forget everything (call on logout). */\n reset: clearAllState,\n stop,\n} as const;\n\n/**\n * Pusher Beams **authenticated users** (push to a person, across all their devices).\n * Use when your backend thinks in user ids: \"send to user-123\".\n * Server: `beams.publishToUsers(['user-123'], payload)` + a token endpoint (`beams.generateToken`).\n */\nexport const Users = {\n /** Start Beams. Call `login()` after your own sign-in. */\n start: (instanceId: string, opts: { requestPermission?: boolean } = {}) =>\n start({ ...opts, instanceId, mode: 'users' }),\n /** Bind this device to `userId`. `auth` is your token endpoint, or a Beams token you already fetched. */\n login: setUserId,\n /** Unbind the device (call on sign-out). */\n logout: clearAllState,\n stop,\n} as const;\n\nexport default {\n Interests, Users,\n start, getMode,\n subscribe, unsubscribe, setSubscriptions, getSubscriptions, clearSubscriptions,\n setUserId,\n requestPermission, getPermissionStatus,\n createChannel, deleteChannel, getChannels,\n getBadgeCount, setBadgeCount, incrementBadgeCount,\n presentLocalNotification, scheduleLocalNotification, cancelScheduledNotification,\n cancelAllScheduledNotifications, dismissAllNotifications, getInitialNotification,\n clearAllState, stop, addListener, on,\n} as const;\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EventSubscription } from 'expo-modules-core';\n\nimport Native from './ExpoPusherPushNotificationsModule';\nimport type {\n AndroidNotificationChannel,\n BeamsAuth,\n DevicePushToken,\n ExpoPusherPushNotificationsModuleEvents,\n LocalNotification,\n PermissionStatus,\n PusherConfig,\n PusherEventName,\n PusherNotification,\n PusherTransportMode,\n ScheduledNotification,\n} from './ExpoPusherPushNotifications.types';\n\nexport * from './ExpoPusherPushNotifications.types';\n\nlet currentMode: PusherTransportMode = 'interests';\nlet started = false;\n\nconst PREFIX = 'expo-pusher-push-notifications';\n\nfunction assertBeams(fn: string): void {\n if (!started) throw new Error(`${PREFIX}: call start() before ${fn}().`);\n if (currentMode === 'device') {\n throw new Error(`${PREFIX}: ${fn}() is a Pusher Beams API and is unavailable in 'device' mode.`);\n }\n}\n\n/**\n * Starts the module.\n * - Pusher Beams (`interests` / `users`): starts the Beams SDK (requires `instanceId`).\n * - Device token (`device`): does NOT start Beams; registers with FCM/APNs and resolves the raw device token.\n * Resolves with the device token in `device` mode, otherwise `null`.\n */\nexport async function start(config: PusherConfig): Promise<DevicePushToken | null> {\n const mode = config.mode ?? 'interests';\n if (config.requestPermission !== false) await Native.requestPermission();\n currentMode = mode;\n if (mode === 'device') {\n const token = await Native.registerForDeviceToken();\n started = true;\n return token;\n }\n if (!config.instanceId) throw new Error(`${PREFIX}: instanceId is required for '${mode}' mode.`);\n await Native.start(config.instanceId);\n started = true;\n return null;\n}\n\nexport function getMode(): PusherTransportMode {\n return currentMode;\n}\n\n// ---- Interests (topics) ----\nexport async function subscribe(interest: string): Promise<void> {\n assertBeams('subscribe');\n await Native.addDeviceInterest(interest);\n}\nexport async function unsubscribe(interest: string): Promise<void> {\n assertBeams('unsubscribe');\n await Native.removeDeviceInterest(interest);\n}\nexport async function setSubscriptions(interests: string[]): Promise<void> {\n assertBeams('setSubscriptions');\n await Native.setDeviceInterests(interests);\n}\nexport async function getSubscriptions(): Promise<string[]> {\n assertBeams('getSubscriptions');\n return Native.getDeviceInterests();\n}\nexport async function clearSubscriptions(): Promise<void> {\n assertBeams('clearSubscriptions');\n await Native.clearDeviceInterests();\n}\n\n// ---- Bind a device to a user ----\n/** Pass a token provider `{ url, headers?, queryParams? }` or a pre-fetched Beams token string. */\nexport async function setUserId(userId: string, auth: BeamsAuth): Promise<void> {\n assertBeams('setUserId');\n if (typeof auth === 'string') await Native.setUserIdWithToken(userId, auth);\n else await Native.setUserId(userId, auth);\n}\n\n// ---- Mode 3: raw device token (direct FCM / APNs) ----\n/** Registers with FCM/APNs (if needed) and returns the native token. Works in any mode. */\nexport async function registerForDeviceToken(): Promise<DevicePushToken> {\n return Native.registerForDeviceToken();\n}\n/** Last known native token, or null if not registered yet. */\nexport async function getDevicePushToken(): Promise<DevicePushToken | null> {\n return Native.getDevicePushToken();\n}\n/** Android: deletes the FCM token (a new one is issued on next register). iOS: unregisters from APNs. */\nexport async function deleteDevicePushToken(): Promise<void> {\n await Native.deleteDevicePushToken();\n}\n\n// ---- Permissions ----\nexport function requestPermission(): Promise<PermissionStatus> {\n return Native.requestPermission();\n}\nexport function getPermissionStatus(): Promise<PermissionStatus> {\n return Native.getPermissionStatus();\n}\n\n// ---- Android notification channels (no-ops on iOS) ----\nexport function createChannel(channel: AndroidNotificationChannel): Promise<void> {\n return Native.createChannel(channel);\n}\nexport function deleteChannel(id: string): Promise<void> {\n return Native.deleteChannel(id);\n}\nexport function getChannels(): Promise<AndroidNotificationChannel[]> {\n return Native.getChannels();\n}\n\n// ---- Badge ----\nexport function getBadgeCount(): Promise<number> {\n return Native.getBadgeCount();\n}\nexport function setBadgeCount(count: number): Promise<void> {\n return Native.setBadgeCount(Math.max(0, Math.floor(count)));\n}\nexport async function incrementBadgeCount(by = 1): Promise<number> {\n const next = (await Native.getBadgeCount()) + by;\n await setBadgeCount(next);\n return Math.max(0, next);\n}\n\n// ---- Local notifications ----\nexport function presentLocalNotification(n: LocalNotification): Promise<string> {\n return Native.presentLocalNotification(n);\n}\nexport function scheduleLocalNotification(n: ScheduledNotification): Promise<string> {\n if (!(n.seconds >= 1)) throw new Error(`${PREFIX}: seconds must be >= 1.`);\n return Native.scheduleLocalNotification(n);\n}\nexport function cancelScheduledNotification(id: string): Promise<void> {\n return Native.cancelScheduledNotification(id);\n}\nexport function cancelAllScheduledNotifications(): Promise<void> {\n return Native.cancelAllScheduledNotifications();\n}\nexport function dismissAllNotifications(): Promise<void> {\n return Native.dismissAllNotifications();\n}\n/** The notification whose tap launched the app (cold start), if any. */\nexport function getInitialNotification(): Promise<PusherNotification | null> {\n return Native.getInitialNotification();\n}\n\n// ---- Common ----\nexport async function clearAllState(): Promise<void> {\n if (currentMode !== 'device') await Native.clearAllState();\n}\nexport async function stop(): Promise<void> {\n if (currentMode === 'device') await Native.deleteDevicePushToken();\n else await Native.stop();\n started = false;\n}\n\n/** Adds an event listener. Events fire for interests and users alike. */\nexport function addListener<E extends PusherEventName>(\n eventName: E,\n listener: ExpoPusherPushNotificationsModuleEvents[E]\n): EventSubscription {\n return Native.addListener(eventName, listener);\n}\n/** Alias for `addListener` (old package's `on()`). */\nexport const on = addListener;\n\n// ---------------------------------------------------------------------------\n// Two paths: Pusher Beams (Interests / Users) or DeviceToken (raw FCM/APNs).\n// Sounds, channels, badges, local notifications and events work on both.\n// ---------------------------------------------------------------------------\n\n/**\n * Pusher Beams **interests** (topic broadcast).\n * Use when many devices should get the same push: \"news\", \"order-42\", \"team-7\".\n * Server: `beams.publishToInterests([...], payload)`.\n */\nexport const Interests = {\n /** Start Beams. */\n start: (instanceId: string, opts: { requestPermission?: boolean } = {}) =>\n start({ ...opts, instanceId, mode: 'interests' }).then(() => undefined),\n subscribe,\n unsubscribe,\n set: setSubscriptions,\n get: getSubscriptions,\n clear: clearSubscriptions,\n /** Forget everything (call on logout). */\n reset: clearAllState,\n stop,\n} as const;\n\n/**\n * Pusher Beams **authenticated users** (push to a person, across all their devices).\n * Use when your backend thinks in user ids: \"send to user-123\".\n * Server: `beams.publishToUsers(['user-123'], payload)` + a token endpoint (`beams.generateToken`).\n */\nexport const Users = {\n /** Start Beams. Call `login()` after your own sign-in. */\n start: (instanceId: string, opts: { requestPermission?: boolean } = {}) =>\n start({ ...opts, instanceId, mode: 'users' }).then(() => undefined),\n /** Bind this device to `userId`. `auth` is your token endpoint, or a Beams token you already fetched. */\n login: setUserId,\n /** Unbind the device (call on sign-out). */\n logout: clearAllState,\n stop,\n} as const;\n\n/**\n * Mode 3 — **direct FCM / APNs** (no Pusher at all).\n * Use when your server already talks to FCM HTTP v1 / APNs, or you use another provider.\n * You get the raw native token; send it to your backend and keep it fresh via the `registered` event.\n */\nexport const DeviceToken = {\n /** Register with FCM/APNs and resolve the native token. */\n start: async (opts: { requestPermission?: boolean } = {}): Promise<DevicePushToken> =>\n (await start({ ...opts, mode: 'device' })) as DevicePushToken,\n get: getDevicePushToken,\n /** Fires whenever the token is issued or rotated. */\n onChange: (cb: (token: DevicePushToken) => void): EventSubscription =>\n addListener('registered', ({ deviceToken, type }) =>\n cb({ token: deviceToken, type, platform: type === 'fcm' ? 'android' : 'ios' })\n ),\n /** Delete the token (call on sign-out). */\n delete: deleteDevicePushToken,\n} as const;\n\nexport default {\n Interests, Users, DeviceToken,\n start, getMode,\n subscribe, unsubscribe, setSubscriptions, getSubscriptions, clearSubscriptions,\n setUserId,\n registerForDeviceToken, getDevicePushToken, deleteDevicePushToken,\n requestPermission, getPermissionStatus,\n createChannel, deleteChannel, getChannels,\n getBadgeCount, setBadgeCount, incrementBadgeCount,\n presentLocalNotification, scheduleLocalNotification, cancelScheduledNotification,\n cancelAllScheduledNotifications, dismissAllNotifications, getInitialNotification,\n clearAllState, stop, addListener, on,\n} as const;\n"]}
package/docs/api.md CHANGED
@@ -1,19 +1,20 @@
1
1
  # Full API
2
2
 
3
- `Interests` and `Users` are thin wrappers over these flat functions. Use whichever you like. The flat ones are kept for people coming from the old packages.
3
+ `Interests`, `Users` and `DeviceToken` are thin wrappers over these flat functions. Use whichever you like. The flat ones are kept for people coming from the old packages.
4
4
 
5
5
  | Function | Used for | Notes |
6
6
  |---|---|---|
7
- | `start({ instanceId, mode?, requestPermission? })` | everything | `mode` (optional) is the Beams auth path: `interests` (default) or `users`. |
7
+ | `start({ instanceId?, mode?, requestPermission? })` | everything | `mode`: `interests` (default) or `users` for Beams, `device` for a raw token (no `instanceId`). Resolves the token in `device` mode, otherwise `null`. |
8
8
  | `getMode()` | everything | |
9
9
  | `subscribe` / `unsubscribe` / `setSubscriptions` / `getSubscriptions` / `clearSubscriptions` | interests | Work on both platforms. |
10
10
  | `setUserId(userId, { url, headers?, queryParams? } \| token)` | binding a user | |
11
+ | `registerForDeviceToken()` / `getDevicePushToken()` / `deleteDevicePushToken()` | device token | |
11
12
  | `requestPermission()` / `getPermissionStatus()` | everything | |
12
13
  | `createChannel` / `deleteChannel` / `getChannels` | Android only | |
13
14
  | `getBadgeCount` / `setBadgeCount` / `incrementBadgeCount` | everything | |
14
15
  | `presentLocalNotification` / `scheduleLocalNotification` / `cancelScheduledNotification` / `cancelAllScheduledNotifications` / `dismissAllNotifications` | everything | |
15
16
  | `getInitialNotification()` | everything | |
16
- | `clearAllState()` / `stop()` | everything | |
17
+ | `clearAllState()` / `stop()` | everything | In `device` mode, `stop()` deletes the device token. |
17
18
  | `addListener(event, cb)` / `on(event, cb)` | everything | Return an `EventSubscription`. |
18
19
 
19
20
 
package/docs/direct.md ADDED
@@ -0,0 +1,42 @@
1
+ # Device token (raw FCM / APNs, no Beams)
2
+
3
+ **Use this when** your app has its own push path: your backend (or another provider) sends to FCM and APNs directly.
4
+ No Beams instance needed. You get the raw native token and do what you want with it.
5
+
6
+ ## Client
7
+
8
+ ```ts
9
+ import { DeviceToken } from 'expo-pusher-push-notifications';
10
+
11
+ const token = await DeviceToken.start();
12
+ // { type: 'fcm', platform: 'android', token: 'dYz…' }
13
+ // { type: 'apns', platform: 'ios', token: 'a1b2…' }
14
+ await api.saveDevice(token);
15
+
16
+ // Tokens rotate. Keep your backend in sync.
17
+ DeviceToken.onChange((t) => api.saveDevice(t));
18
+
19
+ await DeviceToken.get(); // last known token, or null
20
+ await DeviceToken.delete(); // on sign-out
21
+ ```
22
+
23
+ Calling a Beams function (`Interests.*`, `Users.*`) in this mode throws.
24
+
25
+ ## Sending
26
+
27
+ Your backend stores the token and sends to FCM (Android) or APNs (iOS) itself. This module only gets the token and shows the notifications it receives; it doesn't need Beams, `expo-notifications`, or EAS.
28
+
29
+ Data-only FCM messages with `title`/`body` in `data` (plus optional `sound`, `android_channel_id`, `incrementBadge: "true"`) are shown with the right channel and sound, including in the background.
30
+
31
+ ## API
32
+
33
+ | Call | What it does |
34
+ |---|---|
35
+ | `DeviceToken.start({ requestPermission? })` | Registers with FCM/APNs, resolves the token. |
36
+ | `DeviceToken.get()` | Last known token or `null`. |
37
+ | `DeviceToken.onChange(cb)` | Fires when the token is issued or rotated. |
38
+ | `DeviceToken.delete()` | Android: FCM `deleteToken`. iOS: unregister. |
39
+
40
+
41
+ ---
42
+ [← Back to README](../README.md)
package/docs/migrating.md CHANGED
@@ -19,9 +19,9 @@ Here is what the ZeptInc and b8ne packages had, and where it lives now:
19
19
 
20
20
  Neither original had custom sounds, notification channels, or local and scheduled notifications. Those are new here.
21
21
 
22
- ## Coming from 0.3
22
+ ## Coming from 0.4
23
23
 
24
- 0.4 removes raw device-token support (`DeviceToken`, `registerForDeviceToken`, `getDevicePushToken`, `deleteDevicePushToken`, and `mode: 'device'`). This package is Pusher Beams only now. If you need a raw FCM / APNs token, use [`expo-notifications`](https://docs.expo.dev/versions/latest/sdk/notifications/) and `getDevicePushTokenAsync()` instead.
24
+ 0.5 brings back device-token support (`DeviceToken`, `registerForDeviceToken`, `getDevicePushToken`, `deleteDevicePushToken`, and `mode: 'device'`), same API as 0.3. Beams code from 0.4 keeps working unchanged.
25
25
 
26
26
  ## Steps
27
27
 
package/docs/setup.md CHANGED
@@ -37,8 +37,8 @@ Then run `npx expo prebuild` and build a development build. Expo Go cannot load
37
37
 
38
38
  | Option | Default | What it does |
39
39
  |---|---|---|
40
- | `mode` | `interests` | Which Beams auth path your app uses: `interests`, or `users` if you bind devices to signed-in users. Written to Info.plist and the manifest. You can leave it out. |
41
- | `instanceId` | none | Beams instance ID. |
40
+ | `mode` | `interests` | `interests` or `users` for Beams, or `device` for a raw device token. Written to Info.plist and the manifest. You can leave it out. |
41
+ | `instanceId` | none | Beams instance ID. Not needed for `device`. |
42
42
  | `apsEnvironment` | `development` | Sets the `aps-environment` entitlement. Use `production` for TestFlight and App Store builds. |
43
43
  | `sounds` | `[]` | Sound files to bundle. **Android:** copied to `res/raw` with names lower-cased to `[a-z0-9_]`. **iOS:** copied into the app target and added to its resources. iOS needs `.wav`, `.caf`, or `.aiff` under 30 s. |
44
44
  | `androidChannels` | `[]` | Channels created at startup. Set `sound` to a file name from `sounds`, or `null` for a silent channel. |
@@ -51,7 +51,7 @@ The plugin also adds the `remote-notification` background mode on iOS. On Androi
51
51
 
52
52
  1. **iOS:** enable the Push Notifications capability. The plugin sets the entitlement. Create an APNs auth key (.p8).
53
53
  2. **Android:** create a Firebase project, download `google-services.json`, and point `android.googleServicesFile` at it.
54
- 3. **Beams:** create a Beams instance in the [Pusher dashboard](https://dashboard.pusher.com/beams), then upload your APNs key and your FCM service account to it.
54
+ 3. **Beams path only:** create a Beams instance in the [Pusher dashboard](https://dashboard.pusher.com/beams), then upload your APNs key and your FCM service account to it.
55
55
 
56
56
  ## Permissions
57
57
 
@@ -26,6 +26,7 @@ struct LocalNotificationRecord: Record {
26
26
  public class ExpoPusherPushNotificationsModule: Module {
27
27
  private let beams = PushNotifications.shared
28
28
  private var beamsStarted = false
29
+ private var tokenWaiters: [Promise] = []
29
30
  private var initialNotification: [String: Any]?
30
31
  private lazy var centerDelegate = NotificationCenterDelegate(module: self)
31
32
 
@@ -39,6 +40,8 @@ public class ExpoPusherPushNotificationsModule: Module {
39
40
  ExpoPusherAppDelegateSubscriber.onTokenError = { [weak self] error in
40
41
  guard let self = self else { return }
41
42
  self.sendEvent("error", ["code": "E_APNS_REGISTRATION", "message": error.localizedDescription])
43
+ let waiters = self.tokenWaiters; self.tokenWaiters = []
44
+ waiters.forEach { $0.reject("E_APNS_REGISTRATION", error.localizedDescription) }
42
45
  }
43
46
  ExpoPusherAppDelegateSubscriber.onNotification = { [weak self] userInfo, state in
44
47
  self?.handleRemote(userInfo, state: state)
@@ -84,6 +87,22 @@ public class ExpoPusherPushNotificationsModule: Module {
84
87
  self.beams.stop { self.beamsStarted = false; promise.resolve(nil) }
85
88
  }
86
89
 
90
+ // ---- Raw device token (APNs) ----
91
+ AsyncFunction("registerForDeviceToken") { (promise: Promise) in
92
+ if let token = ExpoPusherAppDelegateSubscriber.lastToken {
93
+ promise.resolve(Self.tokenDict(token)); return
94
+ }
95
+ self.tokenWaiters.append(promise)
96
+ DispatchQueue.main.async { UIApplication.shared.registerForRemoteNotifications() }
97
+ }
98
+ AsyncFunction("getDevicePushToken") { () -> [String: Any]? in
99
+ ExpoPusherAppDelegateSubscriber.lastToken.map(Self.tokenDict)
100
+ }
101
+ AsyncFunction("deleteDevicePushToken") {
102
+ ExpoPusherAppDelegateSubscriber.lastToken = nil
103
+ DispatchQueue.main.async { UIApplication.shared.unregisterForRemoteNotifications() }
104
+ }
105
+
87
106
  // ---- Permissions ----
88
107
  AsyncFunction("requestPermission") { (promise: Promise) in
89
108
  UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { _, _ in
@@ -130,8 +149,10 @@ public class ExpoPusherPushNotificationsModule: Module {
130
149
 
131
150
  private func handleToken(_ token: Data) {
132
151
  if beamsStarted { beams.registerDeviceToken(token) }
133
- let hex = token.map { String(format: "%02x", $0) }.joined()
134
- sendEvent("registered", ["deviceToken": hex, "type": "apns"])
152
+ let dict = Self.tokenDict(token)
153
+ sendEvent("registered", ["deviceToken": dict["token"]!, "type": "apns"])
154
+ let waiters = tokenWaiters; tokenWaiters = []
155
+ waiters.forEach { $0.resolve(dict) }
135
156
  }
136
157
 
137
158
  fileprivate func handleRemote(_ userInfo: [AnyHashable: Any], state: String) {
@@ -176,6 +197,10 @@ public class ExpoPusherPushNotificationsModule: Module {
176
197
  return UNNotificationSound(named: UNNotificationSoundName(rawValue: name))
177
198
  }
178
199
 
200
+ static func tokenDict(_ token: Data) -> [String: Any] {
201
+ ["type": "apns", "platform": "ios", "token": token.map { String(format: "%02x", $0) }.joined()]
202
+ }
203
+
179
204
  static func payload(userInfo: [AnyHashable: Any], state: String) -> [String: Any] {
180
205
  let alertAny = (userInfo["aps"] as? [String: Any])?["alert"]
181
206
  let alert = alertAny as? [String: Any]
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "expo-pusher-push-notifications",
3
- "version": "0.4.2",
4
- "description": "Pusher Beams push notifications for Expo (interests and authenticated users), with custom sounds, Android channels, badges and local notifications",
3
+ "version": "0.5.0",
4
+ "description": "Push notifications for Expo: Pusher Beams (interests / users) or raw FCM/APNs device tokens (no EAS needed), with custom sounds, channels, badges and local notifications",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
7
7
  "scripts": {
@@ -24,7 +24,8 @@
24
24
  "push-notifications",
25
25
  "config-plugin",
26
26
  "fcm",
27
- "apns"
27
+ "apns",
28
+ "device-token"
28
29
  ],
29
30
  "repository": "https://github.com/baraa-rasheed/expo-pusher-push-notifications",
30
31
  "bugs": {
@@ -10,12 +10,12 @@ export interface PusherPluginChannel {
10
10
  showBadge?: boolean;
11
11
  }
12
12
  export interface PusherPluginProps {
13
- /** Pusher Beams instance ID. */
13
+ /** Pusher Beams instance ID (not needed for `device` mode). */
14
14
  instanceId?: string;
15
15
  /** APNs environment for the aps-environment entitlement. Defaults to "development". */
16
16
  apsEnvironment?: 'development' | 'production';
17
- /** Beams auth path written to native config (`interests` or `users`). Defaults to "interests". */
18
- mode?: 'interests' | 'users';
17
+ /** Default mode written to native config. Defaults to "interests". */
18
+ mode?: 'interests' | 'users' | 'device';
19
19
  /**
20
20
  * Sound files (paths relative to the project root) to bundle. Android: copied to res/raw
21
21
  * (lower-cased, must be [a-z0-9_]). iOS: added to the main bundle. Use .wav/.caf/.aiff for iOS (<30s).