npm package: @microsoft/user-notifications-client
Description: The web app client library for Microsoft Graph notifications.
Author: Microsoft
Latest version: 0.1.7

# Microsoft Graph notifications SDK
Using the new and improved, lightweight Microsoft Graph notifications client SDK within your application, you can update the state of a notification and sync that state across all endpoints. With the client-side SDK, your app will initiate a subscription with the Microsoft Graph notification service.  This allows your app to start receiving notifications that are published by your application server & targeted at the currently signed-in user. The SDK then manages the notifications on the client side, including receiving new incoming notifications, managing the state of notifications for scenarios like universal dismiss, as well as retrieving full notification history.

> **Note:** The preview version of the Web SDK is now available and we welcome your feedback. The client SDKs for Windows, iOS and Android platforms are coming shortly so please check back soon for updates.

## Integrate your Web app with the client-side SDK

### Development environment and requirements
The library is intended to be used in browser-like environments. It supports the following major browsers: Microsoft Edge (both EdgeHTML-based and Chromium-based versions), Google Chrome, and Mozilla Firefox. The latest version is recommended. Specific supported versions will be specified in the future.

### Adding the SDK to your project
``npm install @microsoft/user-notifications-client``

### Signing in your user
Microsoft Graph notifications, like many other resource types in Microsoft Graph, are centralized around users. In order for your app to subscribe to and start receiving notifications for the signed in user, you first need to obtain a valid OAuth token to be used in the registration process. You can use your preferred method of generating and managing the OAuth tokens. The recommanded library is [Msal.js](https://www.npmjs.com/package/msal).

The following scopes should be included in the sign-in request (based on the **end user's** account type):
  - ``https://activity.windows.com/useractivity.readwrite.createdbyapp`` for personal Microsoft accounts
  - ``https://activity.microsoft.com/useractivity.readwrite.createdbyapp`` for Azure Active Directory accounts

### Subscribing to receive a user's notifications
1. Create an instance of ``UserNotificationApiImpl``.
2. Call the method ``userNotificationApiImpl.subscribeToUserNotificationsAsync(crossDeviceAppDomain, appDisplayNameForMicrosoftAnalytics, webPushSubscription)``.

Example using modern JavaScript (with async/await):
```javascript
accessToken = ...; // the access token obtained from "Signing in your user" section
// create an instance of UserNotificationApiImpl
let userNotificationApiImpl = new UserNotificationApiImpl(token);
// create a new Graph Notifications push notification subscription and set it as the current one for this client instance, or update the current subscription if one already exists.
let userNotificationSubscriptionResult = await userNotificationApiImpl.subscribeToUserNotificationsAsync(crossDeviceAppDomain, appDisplayNameForMicrosoftAnalytics, webPushSubscription);
```
### Receiving and managing user notifications
Web push notifications can be received only within the context of a service worker.
For more details about how web push works please see [Web Push Notifications](https://developers.google.com/web/fundamentals/push-notifications).

#### Handling incoming push notification signals
Once a service worker and web push subscription are created, your application can receive push notifications.
As described in [Handling push events](https://developers.google.com/web/fundamentals/push-notifications/handling-messages) a push event handler can be created for receiving the push notification (into the service worker).

When a push notification is received the method ``userNotificationApiImpl.processPushNotificationAsync(notificationPayload: string)`` can be called, which will try to parse the given push notification payload from the web push service as a Graph Notifications push notification, and do additional processing as needed (see notes).

Below is sample code which runs inside the service worker. It registers an event handler for the web ``push`` event which calls the method ``userNotificationApiImpl.processPushNotificationAsync(notificationPayload)`` just described. If the push notification came from Graph notifications, the sample code then displays a pop-up notification on the client device.

```javascript
self.addEventListener('push', function(event) {
  event.waitUntil((async () => {
    let payloadText = event.data != null ? event.data.text() : "";
    let processedPushNotification = await userNotificationApiImpl.processPushNotificationAsync(payloadText);

    if (processedPushNotification.isUserNotificationPush) {
       // this push notification came from Graph notifications.
       // show a pop-up notification. if status is success and at least one
       // Graph notification was present, show it. otherwise show an error message.
       const title = 'Notification received';
       let body = 'there were some problems. Open the console for more details!';
       if (processedPushNotification.status === UserNotificationApiResultStatus.Succeeded &&
           processedPushNotifications.userNotifications.length !== 0) {
         body = processedPushNotification.userNotifications[0].payload.rawContent || body;
       }
       let options = { body: body };
       await registration.showNotification(title, options);
    } else {
       // this push notification did NOT come from Graph notifications.
       // so do something else with it.
    }
  })());
});
```
Notes:
- `userNotificationApiImpl.processPushNotificationAsync(notificationPayload)` may call back to the Graph notification server to fetch notification data if it was not embedded already in `notificationPayload`. The fetch is done on a best effort basis; it may fail, not retrieve all notifications, *or retrieve more notifications than were referred to*.

  - In particular, `processPushNotificationAsync()` could return Graph notifications that duplicate ones already returned by a previous call to `processPushNotificationAsync()`. If you use the results of `processPushNotificationAsync()` to create a history of received Graph notifications, you need to deduplicate the results based on the notification id. (This is an example only; there may be other scenarios where you also need to deduplicate notifications.)

- `userNotificationApiImpl` keeps a timestamp of the last time `processPushNotificationAsync(notificationPayload)` was called, in an attempt to avoid fetching more notifications than each push notification refers to. When you subscribe for notifications, this timestamp is initialized to approximately 30 days before subscription time.
  
#### Update state of a notification
If a notification state change is initiated from this app client instance (for example, if the toast notification popup on this device is activated by the user), the app needs to call the SDK to update the notification's state in order to have this state change synced across all devices used by the same user.
There are 2 types of state change: user action state (e.g.: Dismissed) and read (i.e.: true or false).  
The following sample code is an example of initiating a request for updating the read state of a notification:

```javascript
let userNotificationApiImpl = ...; // create an instance of the UserNotificationApiImpl
let notificationId = ...; // obtain the notification id for which the read state needs to be changed
let readState = true; // change the read state to true
let userNotificationUpdateResult = await userNotificationApiImpl.updateNotificationReadStateAsync(notificationId, readState);
```

#### Delete a notification

If a notification deletion is initiated from this app client instance (for example, if the task corresponding to this notification is marked as complete and is removed from your app's database), the app needs to call the SDK to delete the notification in order to have this delete operation synced across all devices used by the same user.

A notification is removed from the user notification store only if it is expired or explicitly deleted. A user notification is not deleted when you update the UserActionState to be Dismissed, because the semantic definition of UserActionState is defined by the application itself.

The following sample code is an example of initiating a request for deleting a notification:

```javascript
let userNotificationApiImpl = ...; // create an instance of the UserNotificationApiImpl
let notificationId = ...; // obtain the notification id for which the read state needs to be changed
let userNotificationUpdateResult = await userNotificationApiImpl.deleteNotificationAsync(notificationId);
```

## Privacy
See [Microsoft's privacy statement](https://privacy.microsoft.com/en-us/privacystatement/) for more information.

## License
Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License (the "License").

## Microsoft Open Source Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact opencode@microsoft.com with any additional questions or comments.