Skip to content

Commit c09f92b

Browse files
Merge branch 'master' into add-interruption-level-clean
2 parents 967f3e7 + e76d706 commit c09f92b

33 files changed

+7099
-18336
lines changed

.babelrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"@babel/preset-env",
55
{
66
"targets": {
7-
"node": "6"
7+
"node": "14"
88
}
99
}
1010
]

.eslintrc

Lines changed: 0 additions & 6 deletions
This file was deleted.

.github/copilot-instructions.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copilot Instructions for AI Agents
2+
3+
## Project Overview
4+
5+
This repository implements a Node.js module for sending push notifications across multiple platforms: Apple (APN), Google (GCM/FCM), Windows (WNS), Amazon (ADM), and Web-Push. The core logic is in `lib/` and `src/`, with each platform handled by a dedicated file (e.g., `sendAPN.js`, `sendFCM.js`).
6+
7+
## Architecture & Data Flow
8+
9+
- **Entry Point:** Use `PushNotifications` from `lib/index.js` or `src/index.js`.
10+
- **Settings:** Each platform's credentials/config are passed to the constructor. See the example in `README.md`.
11+
- **Sending:** The main method is `push.send(registrationIds, data, callback)` or as a Promise. It auto-detects device type and routes to the correct sender.
12+
- **Platform Senders:** Each sender (e.g., `sendAPN.js`, `sendFCM.js`) implements the logic for its platform. Shared utilities are in `lib/utils/` and `src/utils/`.
13+
- **RegId Detection:** Device type is inferred from the registration ID structure. See `PN.getPushMethodByRegId` for details.
14+
15+
## Developer Workflows
16+
17+
- **Install:** `npm install`
18+
- **Test:** Run all tests with `npm test`. Tests are in `test/` and cover basic flows and platform-specific cases.
19+
- **Debug:** Use the callback or Promise error/result from `push.send`. Each result object includes method, success/failure counts, and error details per device.
20+
- **Build:** No build step required for basic usage. ES6 is used, but compatible with ES5 via Babel if needed.
21+
22+
## Conventions & Patterns
23+
24+
- **Platform-specific files:** Each push service has its own file for isolation and clarity.
25+
- **Unified Data Model:** The `data` object for notifications is normalized across platforms. See `README.md` for all supported fields.
26+
- **Error Handling:** Errors are unified and returned in the result array from `push.send`.
27+
- **RegId Format:** Prefer object format for registration IDs (`{id, type}`), but string format is supported for legacy reasons.
28+
- **Chunking:** Android tokens are chunked in batches of 1,000 automatically.
29+
- **Constants:** Use constants from `constants.js` for platform types.
30+
31+
## Integration Points
32+
33+
- **External Libraries:**
34+
- APN: `node-apn`
35+
- FCM: `firebase-admin`
36+
- GCM: `node-gcm`
37+
- ADM: `node-adm`
38+
- WNS: `wns`
39+
- Web-Push: `web-push`
40+
- **Credentials:** Place service account keys and certificates in appropriate locations (see `README.md` for examples).
41+
42+
## Key Files & Directories
43+
44+
- `lib/` and `src/`: Main implementation (mirrored structure)
45+
- `test/`: Test cases and sample credentials
46+
- `README.md`: Usage, configuration, and data model reference
47+
48+
## Example Usage
49+
50+
See `README.md` for a full example of settings, registration ID formats, and sending notifications.
51+
52+
---
53+
54+
For unclear or incomplete sections, please provide feedback or specify which workflows, patterns, or integrations need further documentation.

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88

99
strategy:
1010
matrix:
11-
node-version: [14.x, 16.x, 18.x, 20.x]
11+
node-version: [18.x, 20.x, 22.x, 24.x]
1212

1313
steps:
1414
- uses: actions/checkout@v4

.prettierrc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
{
2-
"singleQuote": true,
3-
"trailingComma": "es5"
2+
"semi": true,
3+
"trailingComma": "es5",
4+
"printWidth": 100,
5+
"tabWidth": 2,
6+
"useTabs": false,
7+
"arrowParens": "always",
8+
"bracketSpacing": true,
9+
"endOfLine": "lf"
410
}

README.md

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ A node.js module for interfacing with Apple Push Notification, Google Cloud Mess
2121
- [ADM](#adm)
2222
- [Web-Push](#web-push)
2323
- [Resources](#resources)
24+
- [Proxy](#proxy)
2425
- [LICENSE](#license)
2526

2627
## Installation
@@ -118,12 +119,12 @@ You can send to multiple devices, independently of platform, creating an array w
118119

119120
```js
120121
// Single destination
121-
const registrationIds = 'INSERT_YOUR_DEVICE_ID';
122+
const registrationIds = "INSERT_YOUR_DEVICE_ID";
122123

123124
// Multiple destinations
124125
const registrationIds = [];
125-
registrationIds.push('INSERT_YOUR_DEVICE_ID');
126-
registrationIds.push('INSERT_OTHER_DEVICE_ID');
126+
registrationIds.push("INSERT_YOUR_DEVICE_ID");
127+
registrationIds.push("INSERT_OTHER_DEVICE_ID");
127128
```
128129

129130
The `PN.send()` method later detects device type and therefore used push method, based on the id stucture. Check out the method `PN.getPushMethodByRegId` how this detection works.
@@ -146,10 +147,10 @@ It can be of 2 types:
146147
Where type can be one of: 'apn', 'gcm', 'adm', 'wns', 'webPush'. The types are available as constants:
147148

148149
```js
149-
import { WEB, WNS, ADM, GCM, APN } from 'node-pushnotifications';
150+
import { WEB, WNS, ADM, GCM, APN } from "node-pushnotifications";
150151

151152
const regId = {
152-
id: 'INSERT_YOUR_DEVICE_ID',
153+
id: "INSERT_YOUR_DEVICE_ID",
153154
type: APN,
154155
};
155156
```
@@ -457,7 +458,7 @@ you can use the `phonegap` setting in order to adapt to the recommended behaviou
457458
```js
458459
const settings = {
459460
gcm: {
460-
id: '<yourId>',
461+
id: "<yourId>",
461462
phonegap: true,
462463
},
463464
};
@@ -542,16 +543,14 @@ Settings:
542543
Note: one of `serviceAccountKey`, `credential` fcm options is required
543544
544545
```js
545-
const tokens = [
546-
'e..Gwso:APA91.......7r910HljzGUVS_f...kbyIFk2sK6......D2s6XZWn2E21x',
547-
];
546+
const tokens = ["e..Gwso:APA91.......7r910HljzGUVS_f...kbyIFk2sK6......D2s6XZWn2E21x"];
548547

549548
const notifications = {
550-
collapseKey: Math.random().toString().replace('0.', ''),
551-
priority: 'high',
552-
sound: 'default',
553-
title: 'Title 1',
554-
body: 'Body 2',
549+
collapseKey: Math.random().toString().replace("0.", ""),
550+
priority: "high",
551+
sound: "default",
552+
title: "Title 1",
553+
body: "Body 2",
555554
// titleLocKey: 'GREETING',
556555
// titleLocArgs: ['Smith', 'M'],
557556
// fcm_notification: {
@@ -566,16 +565,16 @@ const notifications = {
566565
// },
567566
custom: {
568567
friend_id: 54657,
569-
list_id: 'N7jSif1INyZkA7r910HljzGUVS',
568+
list_id: "N7jSif1INyZkA7r910HljzGUVS",
570569
},
571570
};
572571

573572
pushNotifications.send(tokens, notifications, (error, result) => {
574573
if (error) {
575-
console.log('[error]', error);
574+
console.log("[error]", error);
576575
throw error;
577576
} else {
578-
console.log('[result]', result, result.at(0));
577+
console.log("[result]", result, result.at(0));
579578
}
580579
});
581580
```
@@ -619,9 +618,7 @@ Fcm object that will be sent to provider ([Fcm message format](https://firebase.
619618
}
620619
}
621620
},
622-
"tokens": [
623-
"e..Gwso:APA91.......7r910HljzGUVS_f...kbyIFk2sK6......D2s6XZWn2E21x"
624-
]
621+
"tokens": ["e..Gwso:APA91.......7r910HljzGUVS_f...kbyIFk2sK6......D2s6XZWn2E21x"]
625622
}
626623
```
627624
@@ -666,8 +663,7 @@ delete data.expiry;
666663
delete data.timeToLive;
667664

668665
const ADMmesssage = {
669-
expiresAfter:
670-
expiry - Math.floor(Date.now() / 1000) || timeToLive || 28 * 86400,
666+
expiresAfter: expiry - Math.floor(Date.now() / 1000) || timeToLive || 28 * 86400,
671667
consolidationKey,
672668
data,
673669
};
@@ -683,12 +679,34 @@ Data can be passed as a simple string payload. If you do not pass a string, the
683679
Settings are directly forwarded to `webPush.sendNotification`.
684680
685681
```js
686-
const payload = typeof data === 'string' ? data : JSON.stringify(data);
682+
const payload = typeof data === "string" ? data : JSON.stringify(data);
687683
webPush.sendNotification(regId, payload, settings.web);
688684
```
689685
690686
A working server example implementation can be found at [https://github.com/alex-friedl/webpush-example/blob/master/server/index.js](https://github.com/alex-friedl/webpush-example/blob/master/server/index.js)
691687
688+
## Proxy
689+
690+
To use the module with a proxy:
691+
692+
```
693+
import { HttpsProxyAgent } from 'https-proxy-agent';
694+
...
695+
const settings = {
696+
fcm: {
697+
...,
698+
httpAgent = new HttpsProxyAgent(`http://${env.proxy.host}:${env.proxy.port}`);
699+
},
700+
apn: {
701+
...
702+
proxy: {
703+
host: <proxy_address>,
704+
port: <proxy_port>
705+
}
706+
}
707+
};
708+
```
709+
692710
## Resources
693711
694712
- [Crossplatform integration example using this library and a React Native app](https://github.com/alex-friedl/crossplatform-push-notifications-example)

eslint.config.mjs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import js from '@eslint/js';
2+
import importPlugin from 'eslint-plugin-import';
3+
import prettier from 'eslint-plugin-prettier/recommended';
4+
5+
export default [
6+
{
7+
ignores: ['node_modules/', 'lib/', 'coverage/'],
8+
},
9+
js.configs.recommended,
10+
{
11+
files: ['src/**/*.js'],
12+
plugins: {
13+
import: importPlugin,
14+
},
15+
languageOptions: {
16+
ecmaVersion: 2021,
17+
sourceType: 'commonjs',
18+
globals: {
19+
console: 'readonly',
20+
process: 'readonly',
21+
Buffer: 'readonly',
22+
__dirname: 'readonly',
23+
__filename: 'readonly',
24+
},
25+
},
26+
rules: {
27+
'no-console': 'off',
28+
'no-use-before-define': ['error', { functions: false }],
29+
'import/no-extraneous-dependencies': 'error',
30+
'import/no-unresolved': 'error',
31+
},
32+
},
33+
{
34+
files: ['test/**/*.js'],
35+
plugins: {
36+
import: importPlugin,
37+
},
38+
languageOptions: {
39+
ecmaVersion: 2021,
40+
sourceType: 'module',
41+
globals: {
42+
console: 'readonly',
43+
process: 'readonly',
44+
Buffer: 'readonly',
45+
__dirname: 'readonly',
46+
__filename: 'readonly',
47+
describe: 'readonly',
48+
it: 'readonly',
49+
before: 'readonly',
50+
after: 'readonly',
51+
beforeEach: 'readonly',
52+
afterEach: 'readonly',
53+
},
54+
},
55+
rules: {
56+
'no-console': 'off',
57+
'global-require': 'off',
58+
'import/no-extraneous-dependencies': 'off',
59+
'import/no-dynamic-require': 'off',
60+
},
61+
},
62+
prettier,
63+
];

index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
module.exports = require('./lib/push-notifications');
1+
module.exports = require("./lib/push-notifications");

0 commit comments

Comments
 (0)