From c4430a4842e7ba11f26c7dc1f2e8e164d9c7b4b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodor=20K=C3=A4llman?= <94024065+RedPhoenixQ@users.noreply.github.com> Date: Thu, 8 Jan 2026 15:00:59 +0000 Subject: [PATCH 1/3] feat: Add `apns-id` header to client return value --- lib/client.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/client.js b/lib/client.js index 7e8b5e9e..8189e187 100644 --- a/lib/client.js +++ b/lib/client.js @@ -503,7 +503,8 @@ module.exports = function (dependencies) { Client.prototype.createHeaderObject = function createHeaderObject( uniqueId, requestId, - channelId + channelId, + notificationId ) { const header = {}; if (uniqueId) { @@ -515,6 +516,9 @@ module.exports = function (dependencies) { if (channelId) { header['apns-channel-id'] = channelId; } + if (notificationId) { + header['apns-id'] = notificationId; + } return header; }; @@ -531,6 +535,7 @@ module.exports = function (dependencies) { let uniqueId = null; let requestId = null; let channelId = null; + let notificationId = null; let responseData = ''; const headers = extend( @@ -561,6 +566,7 @@ module.exports = function (dependencies) { uniqueId = headers['apns-unique-id']; requestId = headers['apns-request-id']; channelId = headers['apns-channel-id']; + notificationId = headers['apns-id']; }); request.on('data', data => { @@ -577,7 +583,7 @@ module.exports = function (dependencies) { if (this.logger.enabled) { this.logger(`Request ended with status ${status} and responseData: ${responseData}`); } - const headerObject = this.createHeaderObject(uniqueId, requestId, channelId); + const headerObject = this.createHeaderObject(uniqueId, requestId, channelId, notificationId); if (status === 200 || status === 201 || status === 204) { const body = responseData !== '' ? JSON.parse(responseData) : {}; From 15c24d26d8556db1a4d93cc1e3a827963834de81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Teodor=20K=C3=A4llman?= <94024065+RedPhoenixQ@users.noreply.github.com> Date: Sat, 10 Jan 2026 13:50:23 +0000 Subject: [PATCH 2/3] style: fix formatting in client.js --- lib/client.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/client.js b/lib/client.js index 8189e187..8703e9b1 100644 --- a/lib/client.js +++ b/lib/client.js @@ -583,7 +583,12 @@ module.exports = function (dependencies) { if (this.logger.enabled) { this.logger(`Request ended with status ${status} and responseData: ${responseData}`); } - const headerObject = this.createHeaderObject(uniqueId, requestId, channelId, notificationId); + const headerObject = this.createHeaderObject( + uniqueId, + requestId, + channelId, + notificationId + ); if (status === 200 || status === 201 || status === 204) { const body = responseData !== '' ? JSON.parse(responseData) : {}; From 9ea743a46de4b8f4ca989fa23ebcfa634db348b1 Mon Sep 17 00:00:00 2001 From: RedPhoenixQ Date: Fri, 30 Jan 2026 23:48:14 +0100 Subject: [PATCH 3/3] test: check for apns-id in response --- test/client.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/client.js b/test/client.js index 3b9f5d5e..06902ca1 100644 --- a/test/client.js +++ b/test/client.js @@ -356,6 +356,27 @@ describe('Client', () => { expect(errorMessages).to.be.empty; }); + it('Returns APNs notification ID in responses', async () => { + const notificationId = '7dc35f9f-58d4-40dd-8c08-38ab811f57df'; + + server = createAndStartMockServer(TEST_PORT, (req, res) => { + res.writeHead(200, { 'apns-id': notificationId }); + res.end(''); + }); + await new Promise(resolve => server.on('listening', resolve)); + + client = createClient(CLIENT_TEST_PORT); + + const mockNotification = { + headers: { 'apns-someheader': 'somevalue' }, + body: MOCK_BODY, + }; + const device = MOCK_DEVICE_TOKEN; + const result = await client.write(mockNotification, device, 'device', 'post'); + + expect(result).to.deep.equal({ 'apns-id': notificationId, device }); + }); + // https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/handling_notification_responses_from_apns it('JSON decodes HTTP 400 responses', async () => { let didRequest = false;