{"id":13553513,"url":"https://github.com/parse-community/node-apn","last_synced_at":"2025-04-03T05:31:00.140Z","repository":{"id":27953721,"uuid":"112770106","full_name":"parse-community/node-apn","owner":"parse-community","description":"Apple Push Notification module for Node.js","archived":false,"fork":true,"pushed_at":"2023-10-20T23:36:18.000Z","size":1722,"stargazers_count":165,"open_issues_count":24,"forks_count":57,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-04-14T13:08:30.854Z","etag":null,"topics":["nodejs","parse-server","push-notifications"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"node-apn/node-apn","license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/parse-community.png","metadata":{"funding":{"github":"parse-community","patreon":null,"open_collective":"parse-server","ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null},"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-12-01T17:53:29.000Z","updated_at":"2024-01-21T20:39:14.000Z","dependencies_parsed_at":"2024-02-06T04:31:02.030Z","dependency_job_id":null,"html_url":"https://github.com/parse-community/node-apn","commit_stats":{"total_commits":1124,"total_committers":94,"mean_commits":"11.957446808510639","dds":"0.21174377224199292","last_synced_commit":"fdf6d23247af066a148b0c4d40a9b43e618e00d2"},"previous_names":[],"tags_count":85,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parse-community%2Fnode-apn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parse-community%2Fnode-apn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parse-community%2Fnode-apn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parse-community%2Fnode-apn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/parse-community","download_url":"https://codeload.github.com/parse-community/node-apn/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246907300,"owners_count":20853062,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["nodejs","parse-server","push-notifications"],"created_at":"2024-08-01T12:02:26.966Z","updated_at":"2025-04-03T05:31:00.118Z","avatar_url":"https://github.com/parse-community.png","language":"JavaScript","funding_links":["https://github.com/sponsors/parse-community","https://opencollective.com/parse-server"],"categories":["JavaScript"],"sub_categories":[],"readme":"# Node APN \u003c!-- omit in toc --\u003e\n\n[![Build Status](https://github.com/parse-community/node-apn/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/parse-community/node-apn/actions/workflows/ci.yml?query=workflow%3Aci+branch%3Amaster)\n[![Snyk Badge](https://snyk.io/test/github/parse-community/node-apn/badge.svg)](https://snyk.io/test/github/parse-community/parse-server-push-adapter)\n[![Coverage](https://codecov.io/github/parse-community/node-apn/branch/master/graph/badge.svg)](https://app.codecov.io/github/parse-community/node-apn/tree/master)\n[![auto-release](https://img.shields.io/badge/%F0%9F%9A%80-auto--release-9e34eb.svg)](https://github.com/parse-community/node-apn/releases)\n\n[![npm latest version](https://img.shields.io/npm/v/@parse/node-apn.svg)](https://www.npmjs.com/package/@parse/node-apn)\n\n---\n\nA Node.js module for interfacing with the Apple Push Notification service.\n\n---\n\n- [Features](#features)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n  - [Load in the module](#load-in-the-module)\n  - [Connecting](#connecting)\n    - [Connecting through an HTTP proxy](#connecting-through-an-http-proxy)\n    - [Using a pool of http/2 connections](#using-a-pool-of-http2-connections)\n  - [Sending a notification](#sending-a-notification)\n  - [Managing channels](#manage-channels)\n  - [Sending a broadcast notification](#sending-a-broadcast-notification)\n\n# Features\n\n- Based on HTTP/2 based provider API\n- Maintains a connection to the server to maximize notification batching and throughput.\n- Automatically re-sends unsent notifications if an error occurs\n\n# Installation\n\n```bash\n$ npm install @parse/node-apn --save\n```\n\n# Quick Start\n\nThis readme is a brief introduction; please refer to the full [documentation](doc/apn.markdown) in `doc/` for more details.\n\nIf you have previously used v1.x and wish to learn more about what's changed in v2.0, please see [What's New](doc/whats-new.markdown)\n\n## Load in the module\n\n```javascript\nvar apn = require('@parse/node-apn');\n```\n\n## Connecting\nCreate a new connection to the Apple Push Notification provider API, passing a dictionary of options to the constructor. You must supply your token credentials in the options.\n\n```javascript\nvar options = {\n  token: {\n    key: \"path/to/APNsAuthKey_XXXXXXXXXX.p8\",\n    keyId: \"key-id\",\n    teamId: \"developer-team-id\"\n  },\n  production: false\n};\n\nconst apnProvider = new apn.Provider(options);\n```\n\nBy default, the provider will connect to the sandbox unless the environment variable `NODE_ENV=production` is set.\n\nFor more information about configuration options, consult the [provider documentation](doc/provider.markdown).\n\nHelp with preparing the key and certificate files for connection can be found in the [wiki][certificateWiki]\n\n\u003e [!WARNING] \n\u003e You should only create one `Provider` per-process for each certificate/key pair you have. You do not need to create a new `Provider` for each notification. If you are only sending notifications to one app, there is no need for more than one `Provider`.\n\u003e\n\u003e If you are constantly creating `Provider` instances in your app, make sure to call `Provider.shutdown()` when you are done with each provider to release its resources and memory.\n\n### Connecting through an HTTP proxy\n\nIf you need to connect through an HTTP proxy, you simply need to provide the `proxy: {host, port}` option when creating the provider. For example:\n\n```javascript\nvar options = {\n  token: {\n    key: \"path/to/APNsAuthKey_XXXXXXXXXX.p8\",\n    keyId: \"key-id\",\n    teamId: \"developer-team-id\"\n  },\n  proxy: {\n    host: \"192.168.10.92\",\n    port: 8080\n  }\n  production: false\n};\n\nconst apnProvider = new apn.Provider(options);\n```\n\nThe provider will first send an HTTP CONNECT request to the specified proxy in order to establish an HTTP tunnel. Once established, it will create a new secure connection to the Apple Push Notification provider API through the tunnel.\n\n### Using a pool of http/2 connections\n\nBecause http/2 already uses multiplexing, you probably don't need to use more than one client unless you are hitting http/2 concurrent request limits.\n\n```javascript\nvar options = {\n  // Round robin pool with 2 clients. More can be used if needed.\n  clientCount: 2,\n  token: {\n    key: \"path/to/APNsAuthKey_XXXXXXXXXX.p8\",\n    keyId: \"key-id\",\n    teamId: \"developer-team-id\"\n  },\n  proxy: {\n    host: \"192.168.10.92\",\n    port: 8080\n  },\n  production: false\n};\n\nconst apnProvider = new apn.MultiProvider(options);\n```\n\n## Sending a notification\nTo send a notification, you will first need a device token from your app as a string.\n\n```javascript\nlet deviceToken = \"a9d0ed10e9cfd022a61cb08753f49c5a0b0dfb383697bf9f9d750a1003da19c7\"\n```\n\nCreate a notification object, configuring it with the relevant parameters (See the [notification documentation](doc/notification.markdown) for more details.)\n\n```javascript\nlet note = new apn.Notification();\n\nnote.expiry = Math.floor(Date.now() / 1000) + 3600; // Expires 1 hour from now.\nnote.badge = 3;\nnote.sound = \"ping.aiff\";\nnote.alert = \"\\uD83D\\uDCE7 \\u2709 You have a new message\";\nnote.payload = {'messageFrom': 'John Appleseed'};\nnote.topic = \"\u003cyour-app-bundle-id\u003e\";\n```\n\nSend the notification to the API with `send`, which returns a promise.\n\n```javascript\ntry {\n  const result = apnProvider.send(note, deviceToken);\n  // see documentation for an explanation of result\n} catch(error) {\n  // Handle error...\n}\n```\n\nThis will result in the following notification payload being sent to the device.\n\n```json\n{\"messageFrom\":\"John Appelseed\",\"aps\":{\"badge\":3,\"sound\":\"ping.aiff\",\"alert\":\"\\uD83D\\uDCE7 \\u2709 You have a new message\"}}\n```\n\nCreate a Live Activity notification object and configure it with the relevant parameters (See the [notification documentation](doc/notification.markdown) for more details.)\n\n```javascript\nlet note = new apn.Notification();\n\nnote.topic = \"\u003cyour-app-bundle-id\u003e.push-type.liveactivity\";\nnote.expiry = Math.floor(Date.now() / 1000) + 3600; // Expires 1 hour from now.\nnote.pushType = \"liveactivity\",\nnote.badge = 3;\nnote.sound = \"ping.aiff\";\nnote.alert = \"\\uD83D\\uDCE7 \\u2709 You have a new message\";\nnote.payload = {'messageFrom': 'John Appleseed'};\nnote.relevanceScore = 75,\nnote.timestamp = Math.floor(Date.now() / 1000); // Current time\nnote.staleDate = Math.floor(Date.now() / 1000) + (8 * 3600); // Expires 8 hour from now.\nnote.event = \"update\"\nnote.contentState = {}\n```\n\nSend the notification to the API with `send`, which returns a promise.\n\n```javascript\ntry {\n  const result = await apnProvider.send(note, deviceToken);\n  // see the documentation for an explanation of the result\n} catch (error) {\n  // Handle error...\n}\n```\n\nThis will result in the following notification payload being sent to the device.\n\n\n```json\n{\"messageFrom\":\"John Appleseed\",\"aps\":{\"badge\":3,\"sound\":\"ping.aiff\",\"alert\":\"\\uD83D\\uDCE7 \\u2709 You have a new message\", \"relevance-score\":75,\"timestamp\":1683129662,\"stale-date\":1683216062,\"event\":\"update\",\"content-state\":{}}}\n```\n\n## Manage Channels\nStarting in iOS 18 and iPadOS 18 Live Activities can be used to broadcast push notifications over channels. To do so, you will need your apps' `bundleId`. \n\n```javascript\nlet bundleId = \"com.node.apn\";\n```\n\nCreate a notification object, configuring it with the relevant parameters (See the [notification documentation](doc/notification.markdown) for more details.)\n\n```javascript\nlet note = new apn.Notification();\n\nnote.requestId = \"0309F412-AA57-46A8-9AC6-B5AECA8C4594\"; // Optional\nnote.payload = {'message-storage-policy': '1', 'push-type': 'liveactivity'}; // Required\n```\n\nCreate a channel with `manageChannels` and the `create` action, which returns a promise.\n\n```javascript\ntry {\n  const result = await apnProvider.manageChannels(note, bundleId, 'create');\n  // see the documentation for an explanation of the result\n} catch (error) {\n  // Handle error...\n}\n```\n\nIf the channel is created successfully, the result will look like the following:\n```javascript\n{ \n  apns-request-id: '0309F412-AA57-46A8-9AC6-B5AECA8C4594', \n  apns-channel-id: 'dHN0LXNyY2gtY2hubA==' // The new channel\n}\n```\n\nSimilarly, `manageChannels` has additional `action`s that allow you to `read`, `readAll`, and `delete` channels. The `read` and `delete` actions require similar information to the `create` example above, with the exception that they require `note.channelId` to be populated. To request all active channel id's, you can use the `readAll` action:\n\n```javascript\ntry {\n  const result = await apnProvider.manageChannels(note, bundleId, 'readAll');\n  // see the documentation for an explanation of the result\n} catch (error) {\n  // Handle error...\n}\n```\n\nAfter the promise is fulfilled, `result` will look like the following:\n\n```javascript\n{ \n  apns-request-id: 'some id value', \n  channels: ['dHN0LXNyY2gtY2hubA==', 'eCN0LXNyY2gtY2hubA==' ...] // A list of active channels\n}\n```\n\nFurther information about managing channels can be found in [Apple's documentation](https://developer.apple.com/documentation/usernotifications/sending-channel-management-requests-to-apns).\n\n## Sending A Broadcast Notification\nStarting in iOS 18 and iPadOS 18, after a channel is created using `manageChannels`, broadcast push notifications can be sent to any device subscribed to the respective `channelId` created for a `bundleId`. A broadcast notification looks similar to a standard Live Activity notification mentioned above but requires `note.channelId` to be populated. An example is below:\n\n```javascript\nlet note = new apn.Notification();\n\nnote.channelId = \"dHN0LXNyY2gtY2hubA==\"; // Required\nnote.expiry = Math.floor(Date.now() / 1000) + 3600; // Expires 1 hour from now.\nnote.pushType = \"liveactivity\",\nnote.badge = 3;\nnote.sound = \"ping.aiff\";\nnote.alert = \"\\uD83D\\uDCE7 \\u2709 You have a new message\";\nnote.payload = {'messageFrom': 'John Appleseed'};\nnote.relevanceScore = 75,\nnote.timestamp = Math.floor(Date.now() / 1000); // Current time\nnote.staleDate = Math.floor(Date.now() / 1000) + (8 * 3600); // Expires 8 hour from now.\nnote.event = \"update\"\nnote.contentState = {}\n```\n\nSend the broadcast notification to the API with `broadcast`, which returns a promise.\n\n```javascript\ntry {\n  const result = await apnProvider.broadcast(note, bundleId);\n  // see documentation for an explanation of result\n} catch (error) {\n  // Handle error...\n}\n```\n\nFurther information about broadcast notifications can be found in [Apple's documentation](https://developer.apple.com/documentation/usernotifications/sending-broadcast-push-notification-requests-to-apns).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparse-community%2Fnode-apn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fparse-community%2Fnode-apn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparse-community%2Fnode-apn/lists"}