@idealyst/notifications 1.2.114

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 ADDED
@@ -0,0 +1,77 @@
1
+ # @idealyst/notifications
2
+
3
+ Cross-platform push and local notifications for React Native and web.
4
+
5
+ - **Push**: Firebase Cloud Messaging (native) / Web Push API (web)
6
+ - **Local**: Notifee (native) / Notification API (web)
7
+ - **Backend-agnostic**: gives you device tokens — your server sends via any push service
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ yarn add @idealyst/notifications
13
+
14
+ # Native push (required for push on iOS/Android):
15
+ yarn add @react-native-firebase/app @react-native-firebase/messaging
16
+
17
+ # Native local (required for local notifications on iOS/Android):
18
+ yarn add @notifee/react-native
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ```tsx
24
+ import {
25
+ usePushNotifications,
26
+ useLocalNotifications,
27
+ useNotificationPermissions,
28
+ } from '@idealyst/notifications';
29
+
30
+ function App() {
31
+ const { status, requestPermission } = useNotificationPermissions();
32
+ const { token, register } = usePushNotifications({ autoRegister: true });
33
+ const { displayNotification } = useLocalNotifications();
34
+
35
+ return (
36
+ <Button
37
+ onPress={async () => {
38
+ await requestPermission();
39
+ const pushToken = await register();
40
+ console.log('Push token:', pushToken);
41
+ await displayNotification({
42
+ title: 'Hello',
43
+ body: 'Notifications are working!',
44
+ });
45
+ }}
46
+ >
47
+ Enable Notifications
48
+ </Button>
49
+ );
50
+ }
51
+ ```
52
+
53
+ ## API
54
+
55
+ ### Hooks
56
+
57
+ - `usePushNotifications(options?)` — token management, message listeners
58
+ - `useLocalNotifications(options?)` — display, schedule, channels, badges
59
+ - `useNotificationPermissions(options?)` — check/request permissions
60
+
61
+ ### Standalone Functions
62
+
63
+ Push: `requestPushPermission()`, `getPushToken()`, `deletePushToken()`, `onForegroundMessage()`, `onNotificationOpened()`, `onTokenRefresh()`, `setBackgroundMessageHandler()`, `subscribeToTopic()`, `unsubscribeFromTopic()`
64
+
65
+ Local: `displayNotification()`, `scheduleNotification()`, `cancelNotification()`, `cancelAllNotifications()`, `createChannel()`, `deleteChannel()`, `getChannels()`, `setCategories()`, `setBadgeCount()`, `getBadgeCount()`
66
+
67
+ Permissions: `checkPermission()`, `requestPermission()`, `openNotificationSettings()`
68
+
69
+ Web-only: `configurePush({ vapidKey, serviceWorkerPath? })` — required before push registration on web
70
+
71
+ ## Native Setup
72
+
73
+ See `get_install_guide('notifications')` via the MCP server for full iOS/Android configuration (Firebase, APNs, Gradle, permissions).
74
+
75
+ ## License
76
+
77
+ MIT
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@idealyst/notifications",
3
+ "version": "1.2.114",
4
+ "description": "Cross-platform push and local notifications for React and React Native",
5
+ "documentation": "https://github.com/IdealystIO/idealyst-framework/tree/main/packages/notifications#readme",
6
+ "readme": "README.md",
7
+ "main": "src/index.ts",
8
+ "module": "src/index.ts",
9
+ "types": "src/index.ts",
10
+ "react-native": "src/index.native.ts",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/IdealystIO/idealyst-framework.git",
14
+ "directory": "packages/notifications"
15
+ },
16
+ "author": "Idealyst <contact@idealyst.io>",
17
+ "license": "MIT",
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "exports": {
22
+ ".": {
23
+ "react-native": "./src/index.native.ts",
24
+ "browser": {
25
+ "types": "./src/index.web.ts",
26
+ "import": "./src/index.web.ts",
27
+ "require": "./src/index.web.ts"
28
+ },
29
+ "default": {
30
+ "types": "./src/index.ts",
31
+ "import": "./src/index.ts",
32
+ "require": "./src/index.ts"
33
+ }
34
+ }
35
+ },
36
+ "scripts": {
37
+ "prepublishOnly": "echo 'Publishing TypeScript source directly'",
38
+ "publish:npm": "npm publish"
39
+ },
40
+ "peerDependencies": {
41
+ "@notifee/react-native": ">=9.0.0",
42
+ "@react-native-firebase/app": ">=21.0.0",
43
+ "@react-native-firebase/messaging": ">=21.0.0",
44
+ "react": ">=16.8.0",
45
+ "react-native": ">=0.60.0"
46
+ },
47
+ "peerDependenciesMeta": {
48
+ "react-native": {
49
+ "optional": true
50
+ },
51
+ "@notifee/react-native": {
52
+ "optional": true
53
+ },
54
+ "@react-native-firebase/app": {
55
+ "optional": true
56
+ },
57
+ "@react-native-firebase/messaging": {
58
+ "optional": true
59
+ }
60
+ },
61
+ "devDependencies": {
62
+ "@types/react": "^19.1.0",
63
+ "typescript": "^5.0.0"
64
+ },
65
+ "files": [
66
+ "src",
67
+ "README.md"
68
+ ],
69
+ "keywords": [
70
+ "react",
71
+ "react-native",
72
+ "notifications",
73
+ "push-notifications",
74
+ "local-notifications",
75
+ "fcm",
76
+ "firebase-messaging",
77
+ "apns",
78
+ "web-push",
79
+ "notifee",
80
+ "cross-platform"
81
+ ]
82
+ }
@@ -0,0 +1,86 @@
1
+ import type {
2
+ PermissionResult,
3
+ AndroidChannel,
4
+ NotificationImportance,
5
+ } from './types';
6
+
7
+ // ============================================================================
8
+ // Default States
9
+ // ============================================================================
10
+
11
+ export const DEFAULT_PERMISSION_RESULT: PermissionResult = {
12
+ status: 'undetermined',
13
+ canNotify: false,
14
+ };
15
+
16
+ // ============================================================================
17
+ // Default Android Channel
18
+ // ============================================================================
19
+
20
+ export const DEFAULT_CHANNEL_ID = 'default';
21
+
22
+ export const DEFAULT_CHANNEL: AndroidChannel = {
23
+ id: DEFAULT_CHANNEL_ID,
24
+ name: 'Default',
25
+ description: 'Default notification channel',
26
+ importance: 'high',
27
+ vibration: true,
28
+ badge: true,
29
+ visibility: 'private',
30
+ };
31
+
32
+ // ============================================================================
33
+ // Channel Presets
34
+ // ============================================================================
35
+
36
+ export const CHANNEL_PRESETS = {
37
+ alerts: {
38
+ id: 'alerts',
39
+ name: 'Alerts',
40
+ description: 'Important alerts and messages',
41
+ importance: 'high' as NotificationImportance,
42
+ vibration: true,
43
+ lights: true,
44
+ badge: true,
45
+ visibility: 'private' as const,
46
+ },
47
+
48
+ silent: {
49
+ id: 'silent',
50
+ name: 'Silent Updates',
51
+ description: 'Background updates without sound or vibration',
52
+ importance: 'low' as NotificationImportance,
53
+ vibration: false,
54
+ lights: false,
55
+ badge: false,
56
+ visibility: 'private' as const,
57
+ },
58
+
59
+ marketing: {
60
+ id: 'marketing',
61
+ name: 'Promotions',
62
+ description: 'Promotional offers and updates',
63
+ importance: 'default' as NotificationImportance,
64
+ vibration: false,
65
+ badge: true,
66
+ visibility: 'public' as const,
67
+ },
68
+
69
+ chat: {
70
+ id: 'chat',
71
+ name: 'Messages',
72
+ description: 'Chat messages and conversations',
73
+ importance: 'high' as NotificationImportance,
74
+ vibration: true,
75
+ lights: true,
76
+ badge: true,
77
+ sound: 'default',
78
+ visibility: 'private' as const,
79
+ },
80
+ } as const satisfies Record<string, AndroidChannel>;
81
+
82
+ // ============================================================================
83
+ // Web Push Defaults
84
+ // ============================================================================
85
+
86
+ export const DEFAULT_SERVICE_WORKER_PATH = '/sw.js';
package/src/errors.ts ADDED
@@ -0,0 +1,92 @@
1
+ import type { NotificationError, NotificationErrorCode } from './types';
2
+
3
+ export function createNotificationError(
4
+ code: NotificationErrorCode,
5
+ message: string,
6
+ originalError?: unknown,
7
+ ): NotificationError {
8
+ return { code, message, originalError };
9
+ }
10
+
11
+ /**
12
+ * Normalize errors from @react-native-firebase/messaging into NotificationError.
13
+ */
14
+ export function normalizeFirebaseError(error: unknown): NotificationError {
15
+ if (error && typeof error === 'object' && 'code' in error) {
16
+ const fbError = error as { code?: string; message?: string };
17
+
18
+ switch (fbError.code) {
19
+ case 'messaging/permission-blocked':
20
+ case 'messaging/permission-denied':
21
+ return createNotificationError(
22
+ 'permission_denied',
23
+ 'Notification permission was denied by the user',
24
+ error,
25
+ );
26
+ case 'messaging/token-subscribe-failed':
27
+ case 'messaging/token-unsubscribe-failed':
28
+ return createNotificationError(
29
+ 'token_failed',
30
+ fbError.message || 'Failed to manage push token',
31
+ error,
32
+ );
33
+ case 'messaging/topic-subscribe-failed':
34
+ case 'messaging/topic-unsubscribe-failed':
35
+ return createNotificationError(
36
+ 'topic_failed',
37
+ fbError.message || 'Failed to manage topic subscription',
38
+ error,
39
+ );
40
+ case 'messaging/unknown':
41
+ default:
42
+ return createNotificationError(
43
+ 'unknown',
44
+ fbError.message || 'An unknown messaging error occurred',
45
+ error,
46
+ );
47
+ }
48
+ }
49
+
50
+ if (error instanceof Error) {
51
+ return createNotificationError('unknown', error.message, error);
52
+ }
53
+
54
+ return createNotificationError('unknown', String(error), error);
55
+ }
56
+
57
+ /**
58
+ * Normalize errors from @notifee/react-native into NotificationError.
59
+ */
60
+ export function normalizeNotifeeError(error: unknown): NotificationError {
61
+ if (error && typeof error === 'object' && 'code' in error) {
62
+ const nError = error as { code?: string; message?: string };
63
+
64
+ if (nError.code?.includes('permission')) {
65
+ return createNotificationError(
66
+ 'permission_denied',
67
+ nError.message || 'Notification permission denied',
68
+ error,
69
+ );
70
+ }
71
+
72
+ if (nError.code?.includes('channel')) {
73
+ return createNotificationError(
74
+ 'channel_failed',
75
+ nError.message || 'Failed to manage notification channel',
76
+ error,
77
+ );
78
+ }
79
+
80
+ return createNotificationError(
81
+ 'unknown',
82
+ nError.message || 'A notification error occurred',
83
+ error,
84
+ );
85
+ }
86
+
87
+ if (error instanceof Error) {
88
+ return createNotificationError('unknown', error.message, error);
89
+ }
90
+
91
+ return createNotificationError('unknown', String(error), error);
92
+ }
@@ -0,0 +1,120 @@
1
+ export * from './types';
2
+ export {
3
+ DEFAULT_PERMISSION_RESULT,
4
+ DEFAULT_CHANNEL,
5
+ DEFAULT_CHANNEL_ID,
6
+ CHANNEL_PRESETS,
7
+ } from './constants';
8
+ export { createNotificationError } from './errors';
9
+
10
+ // Push
11
+ export {
12
+ requestPushPermission,
13
+ getPushToken,
14
+ deletePushToken,
15
+ hasPermission,
16
+ onForegroundMessage,
17
+ onNotificationOpened,
18
+ onTokenRefresh,
19
+ setBackgroundMessageHandler,
20
+ subscribeToTopic,
21
+ unsubscribeFromTopic,
22
+ getAPNsToken,
23
+ } from './push/push.native';
24
+
25
+ // Local
26
+ export {
27
+ displayNotification,
28
+ scheduleNotification,
29
+ cancelNotification,
30
+ cancelAllNotifications,
31
+ cancelDisplayedNotifications,
32
+ cancelPendingNotifications,
33
+ createChannel,
34
+ deleteChannel,
35
+ getChannels,
36
+ setCategories,
37
+ getDisplayedNotifications,
38
+ getPendingNotifications,
39
+ setBadgeCount,
40
+ getBadgeCount,
41
+ onNotificationEvent,
42
+ } from './local/local.native';
43
+
44
+ // Permissions
45
+ export {
46
+ checkPermission,
47
+ requestPermission,
48
+ openNotificationSettings,
49
+ } from './permissions/permissions.native';
50
+
51
+ // Hooks — bound to native implementations
52
+ import { createUsePushNotificationsHook } from './push/usePushNotifications';
53
+ import { createUseLocalNotificationsHook } from './local/useLocalNotifications';
54
+ import { createUseNotificationPermissionsHook } from './permissions/useNotificationPermissions';
55
+
56
+ import {
57
+ requestPushPermission,
58
+ getPushToken,
59
+ deletePushToken,
60
+ onForegroundMessage,
61
+ onNotificationOpened,
62
+ onTokenRefresh,
63
+ subscribeToTopic,
64
+ unsubscribeFromTopic,
65
+ } from './push/push.native';
66
+
67
+ import {
68
+ displayNotification,
69
+ scheduleNotification,
70
+ cancelNotification,
71
+ cancelAllNotifications,
72
+ createChannel,
73
+ deleteChannel,
74
+ getChannels,
75
+ setCategories,
76
+ getDisplayedNotifications,
77
+ getPendingNotifications,
78
+ setBadgeCount,
79
+ getBadgeCount,
80
+ onNotificationEvent,
81
+ } from './local/local.native';
82
+
83
+ import {
84
+ checkPermission,
85
+ requestPermission,
86
+ openNotificationSettings,
87
+ } from './permissions/permissions.native';
88
+
89
+ export const usePushNotifications = createUsePushNotificationsHook({
90
+ requestPushPermission,
91
+ getPushToken,
92
+ deletePushToken,
93
+ onForegroundMessage,
94
+ onNotificationOpened,
95
+ onTokenRefresh,
96
+ subscribeToTopic,
97
+ unsubscribeFromTopic,
98
+ });
99
+
100
+ export const useLocalNotifications = createUseLocalNotificationsHook({
101
+ displayNotification,
102
+ scheduleNotification,
103
+ cancelNotification,
104
+ cancelAllNotifications,
105
+ createChannel,
106
+ deleteChannel,
107
+ getChannels,
108
+ setCategories,
109
+ getDisplayedNotifications,
110
+ getPendingNotifications,
111
+ setBadgeCount,
112
+ getBadgeCount,
113
+ onNotificationEvent,
114
+ });
115
+
116
+ export const useNotificationPermissions = createUseNotificationPermissionsHook({
117
+ checkPermission,
118
+ requestPermission,
119
+ openNotificationSettings,
120
+ });
package/src/index.ts ADDED
@@ -0,0 +1,123 @@
1
+ // Default entry — re-exports web implementation.
2
+ // Platform-specific entry points (index.native.ts, index.web.ts) are resolved by bundlers.
3
+ export * from './types';
4
+ export {
5
+ DEFAULT_PERMISSION_RESULT,
6
+ DEFAULT_CHANNEL,
7
+ DEFAULT_CHANNEL_ID,
8
+ CHANNEL_PRESETS,
9
+ DEFAULT_SERVICE_WORKER_PATH,
10
+ } from './constants';
11
+ export { createNotificationError } from './errors';
12
+
13
+ // Push
14
+ export {
15
+ configurePush,
16
+ requestPushPermission,
17
+ getPushToken,
18
+ deletePushToken,
19
+ hasPermission,
20
+ onForegroundMessage,
21
+ onNotificationOpened,
22
+ onTokenRefresh,
23
+ setBackgroundMessageHandler,
24
+ subscribeToTopic,
25
+ unsubscribeFromTopic,
26
+ } from './push/push.web';
27
+
28
+ // Local
29
+ export {
30
+ displayNotification,
31
+ scheduleNotification,
32
+ cancelNotification,
33
+ cancelAllNotifications,
34
+ cancelDisplayedNotifications,
35
+ cancelPendingNotifications,
36
+ createChannel,
37
+ deleteChannel,
38
+ getChannels,
39
+ setCategories,
40
+ getDisplayedNotifications,
41
+ getPendingNotifications,
42
+ setBadgeCount,
43
+ getBadgeCount,
44
+ onNotificationEvent,
45
+ } from './local/local.web';
46
+
47
+ // Permissions
48
+ export {
49
+ checkPermission,
50
+ requestPermission,
51
+ openNotificationSettings,
52
+ } from './permissions/permissions.web';
53
+
54
+ // Hooks — bound to web implementations
55
+ import { createUsePushNotificationsHook } from './push/usePushNotifications';
56
+ import { createUseLocalNotificationsHook } from './local/useLocalNotifications';
57
+ import { createUseNotificationPermissionsHook } from './permissions/useNotificationPermissions';
58
+
59
+ import {
60
+ requestPushPermission,
61
+ getPushToken,
62
+ deletePushToken,
63
+ onForegroundMessage,
64
+ onNotificationOpened,
65
+ onTokenRefresh,
66
+ subscribeToTopic,
67
+ unsubscribeFromTopic,
68
+ } from './push/push.web';
69
+
70
+ import {
71
+ displayNotification,
72
+ scheduleNotification,
73
+ cancelNotification,
74
+ cancelAllNotifications,
75
+ createChannel,
76
+ deleteChannel,
77
+ getChannels,
78
+ setCategories,
79
+ getDisplayedNotifications,
80
+ getPendingNotifications,
81
+ setBadgeCount,
82
+ getBadgeCount,
83
+ onNotificationEvent,
84
+ } from './local/local.web';
85
+
86
+ import {
87
+ checkPermission,
88
+ requestPermission,
89
+ openNotificationSettings,
90
+ } from './permissions/permissions.web';
91
+
92
+ export const usePushNotifications = createUsePushNotificationsHook({
93
+ requestPushPermission,
94
+ getPushToken,
95
+ deletePushToken,
96
+ onForegroundMessage,
97
+ onNotificationOpened,
98
+ onTokenRefresh,
99
+ subscribeToTopic,
100
+ unsubscribeFromTopic,
101
+ });
102
+
103
+ export const useLocalNotifications = createUseLocalNotificationsHook({
104
+ displayNotification,
105
+ scheduleNotification,
106
+ cancelNotification,
107
+ cancelAllNotifications,
108
+ createChannel,
109
+ deleteChannel,
110
+ getChannels,
111
+ setCategories,
112
+ getDisplayedNotifications,
113
+ getPendingNotifications,
114
+ setBadgeCount,
115
+ getBadgeCount,
116
+ onNotificationEvent,
117
+ });
118
+
119
+ export const useNotificationPermissions = createUseNotificationPermissionsHook({
120
+ checkPermission,
121
+ requestPermission,
122
+ openNotificationSettings,
123
+ });
@@ -0,0 +1,2 @@
1
+ // Web entry — identical to index.ts.
2
+ export * from './index';