expo-server-sdk
Advanced tools
Comparing version 3.3.0 to 3.4.0
@@ -44,2 +44,3 @@ /// <reference types="node" /> | ||
_getErrorFromResultError(errorData: ApiResultError): Error; | ||
static _getActualMessagesCount(messages: ExpoPushMessage[]): number; | ||
} | ||
@@ -53,3 +54,3 @@ export default Expo; | ||
export declare type ExpoPushMessage = { | ||
to: ExpoPushToken; | ||
to: ExpoPushToken | ExpoPushToken[]; | ||
data?: Object; | ||
@@ -56,0 +57,0 @@ title?: string; |
@@ -68,2 +68,3 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const actualMessagesCount = Expo._getActualMessagesCount(messages); | ||
let data = yield this._requestAsync(`${BASE_API_URL}/push/send`, { | ||
@@ -76,4 +77,4 @@ httpMethod: 'post', | ||
}); | ||
if (!Array.isArray(data) || data.length !== messages.length) { | ||
let apiError = new Error(`Expected Expo to respond with ${messages.length} ${messages.length === 1 ? 'ticket' : 'tickets'} but got ${data.length}`); | ||
if (!Array.isArray(data) || data.length !== actualMessagesCount) { | ||
let apiError = new Error(`Expected Expo to respond with ${actualMessagesCount} ${actualMessagesCount === 1 ? 'ticket' : 'tickets'} but got ${data.length}`); | ||
apiError.data = data; | ||
@@ -103,3 +104,43 @@ throw apiError; | ||
chunkPushNotifications(messages) { | ||
return this._chunkItems(messages, PUSH_NOTIFICATION_CHUNK_LIMIT); | ||
let chunks = []; | ||
let chunk = []; | ||
let chunkMessagesCount = 0; | ||
for (let message of messages) { | ||
if (Array.isArray(message.to)) { | ||
let partialTo = []; | ||
for (let recipient of message.to) { | ||
partialTo.push(recipient); | ||
chunkMessagesCount++; | ||
if (chunkMessagesCount >= PUSH_NOTIFICATION_CHUNK_LIMIT) { | ||
// Cap this chunk here if it already exceeds PUSH_NOTIFICATION_CHUNK_LIMIT. | ||
// Then create a new chunk to continue on the remaining recipients for this message. | ||
chunk.push(Object.assign({}, message, { to: partialTo })); | ||
chunks.push(chunk); | ||
chunk = []; | ||
chunkMessagesCount = 0; | ||
partialTo = []; | ||
} | ||
} | ||
if (partialTo.length) { | ||
// Add remaining `partialTo` to the chunk. | ||
chunk.push(Object.assign({}, message, { to: partialTo })); | ||
} | ||
} | ||
else { | ||
chunk.push(message); | ||
chunkMessagesCount++; | ||
} | ||
if (chunkMessagesCount >= PUSH_NOTIFICATION_CHUNK_LIMIT) { | ||
// Cap this chunk if it exceeds PUSH_NOTIFICATION_CHUNK_LIMIT. | ||
// Then create a new chunk to continue on the remaining messages. | ||
chunks.push(chunk); | ||
chunk = []; | ||
chunkMessagesCount = 0; | ||
} | ||
} | ||
if (chunkMessagesCount) { | ||
// Add the remaining chunk to the chunks. | ||
chunks.push(chunk); | ||
} | ||
return chunks; | ||
} | ||
@@ -225,2 +266,13 @@ chunkPushNotificationReceiptIds(receiptIds) { | ||
} | ||
static _getActualMessagesCount(messages) { | ||
return messages.reduce((acc, cur) => { | ||
if (Array.isArray(cur.to)) { | ||
acc += cur.to.length; | ||
} | ||
else { | ||
acc++; | ||
} | ||
return acc; | ||
}, 0); | ||
} | ||
} | ||
@@ -227,0 +279,0 @@ Expo.pushNotificationChunkSizeLimit = PUSH_NOTIFICATION_CHUNK_LIMIT; |
{ | ||
"name": "expo-server-sdk", | ||
"version": "3.3.0", | ||
"version": "3.4.0", | ||
"description": "Server side library for working with Expo using Node.js", | ||
@@ -5,0 +5,0 @@ "main": "build/ExpoClient.js", |
@@ -1,4 +0,14 @@ | ||
import ExpoClient from '../ExpoClient'; | ||
import ExpoClient, { ExpoPushMessage } from '../ExpoClient'; | ||
it('chunks lists of push notification messages', () => { | ||
function _coundAndValidateMessages(chunks: ExpoPushMessage[][]) { | ||
let totalMessageCount = 0; | ||
for (let chunk of chunks) { | ||
let chunkMessagesCount = ExpoClient._getActualMessagesCount(chunk); | ||
expect(chunkMessagesCount).toBeLessThanOrEqual(ExpoClient.pushNotificationChunkSizeLimit); | ||
totalMessageCount += chunkMessagesCount; | ||
} | ||
return totalMessageCount; | ||
} | ||
test('chunks lists of push notification messages', () => { | ||
let client = new ExpoClient(); | ||
@@ -14,3 +24,3 @@ let messages = new Array(999).fill({ to: '?' }); | ||
it('can chunk small lists of push notification messages', () => { | ||
test('can chunk small lists of push notification messages', () => { | ||
let client = new ExpoClient(); | ||
@@ -23,7 +33,121 @@ let messages = new Array(10).fill({ to: '?' }); | ||
it('defines the push notification chunk size', () => { | ||
test('chunks single push notification message with lists of recipients', () => { | ||
const messagesLength = 999; | ||
let client = new ExpoClient(); | ||
let messages = [{ to: new Array(messagesLength).fill('?') }]; | ||
let chunks = client.chunkPushNotifications(messages); | ||
for (let chunk of chunks) { | ||
// Each chunk should only contain a single message with 100 recipients | ||
expect(chunk.length).toBe(1); | ||
} | ||
let totalMessageCount = _coundAndValidateMessages(chunks); | ||
expect(totalMessageCount).toBe(messagesLength); | ||
}); | ||
test('can chunk single push notification message with small lists of recipients', () => { | ||
const messagesLength = 10; | ||
let client = new ExpoClient(); | ||
let messages = [{ to: new Array(messagesLength).fill('?') }]; | ||
let chunks = client.chunkPushNotifications(messages); | ||
expect(chunks.length).toBe(1); | ||
expect(chunks[0].length).toBe(1); | ||
expect(chunks[0][0].to.length).toBe(messagesLength); | ||
}); | ||
test('chunks push notification messages mixed with lists of recipients and single recipient', () => { | ||
let client = new ExpoClient(); | ||
let messages = [ | ||
{ to: new Array(888).fill('?') }, | ||
...new Array(999).fill({ | ||
to: '?', | ||
}), | ||
{ to: new Array(90).fill('?') }, | ||
...new Array(10).fill({ to: '?' }), | ||
]; | ||
let chunks = client.chunkPushNotifications(messages); | ||
let totalMessageCount = _coundAndValidateMessages(chunks); | ||
expect(totalMessageCount).toBe(888 + 999 + 90 + 10); | ||
}); | ||
describe('chunking a single push notification message with multiple recipients', () => { | ||
let client = new ExpoClient(); | ||
test('one message with 100 recipients', () => { | ||
let messages = [{ to: new Array(100).fill('?') }]; | ||
let chunks = client.chunkPushNotifications(messages); | ||
expect(chunks.length).toBe(1); | ||
expect(chunks[0].length).toBe(1); | ||
expect(chunks[0][0].to.length).toBe(100); | ||
}); | ||
test('one message with 101 recipients', () => { | ||
let messages = [{ to: new Array(101).fill('?') }]; | ||
let chunks = client.chunkPushNotifications(messages); | ||
expect(chunks.length).toBe(2); | ||
expect(chunks[0].length).toBe(1); | ||
expect(chunks[1].length).toBe(1); | ||
let totalMessageCount = _coundAndValidateMessages(chunks); | ||
expect(totalMessageCount).toBe(101); | ||
}); | ||
test('one message with 99 recipients and two additional messages', () => { | ||
let messages = [{ to: new Array(99).fill('?') }, ...new Array(2).fill({ to: '?' })]; | ||
let chunks = client.chunkPushNotifications(messages); | ||
expect(chunks.length).toBe(2); | ||
expect(chunks[0].length).toBe(2); | ||
expect(chunks[1].length).toBe(1); | ||
let totalMessageCount = _coundAndValidateMessages(chunks); | ||
expect(totalMessageCount).toBe(99 + 2); | ||
}); | ||
test('one message with 100 recipients and two additional messages', () => { | ||
let messages = [{ to: new Array(100).fill('?') }, ...new Array(2).fill({ to: '?' })]; | ||
let chunks = client.chunkPushNotifications(messages); | ||
expect(chunks.length).toBe(2); | ||
expect(chunks[0].length).toBe(1); | ||
expect(chunks[1].length).toBe(2); | ||
let totalMessageCount = _coundAndValidateMessages(chunks); | ||
expect(totalMessageCount).toBe(100 + 2); | ||
}); | ||
test('99 messages and one additional message with with two recipients', () => { | ||
let messages = [...new Array(99).fill({ to: '?' }), { to: new Array(2).fill('?') }]; | ||
let chunks = client.chunkPushNotifications(messages); | ||
expect(chunks.length).toBe(2); | ||
expect(chunks[0].length).toBe(100); | ||
expect(chunks[1].length).toBe(1); | ||
let totalMessageCount = _coundAndValidateMessages(chunks); | ||
expect(totalMessageCount).toBe(99 + 2); | ||
}); | ||
test('no message', () => { | ||
let messages: ExpoPushMessage[] = []; | ||
let chunks = client.chunkPushNotifications(messages); | ||
expect(chunks.length).toBe(0); | ||
}); | ||
test('one message with no recipient', () => { | ||
let messages = [{ to: [] }]; | ||
let chunks = client.chunkPushNotifications(messages); | ||
expect(chunks.length).toBe(0); | ||
}); | ||
test('two message and one additional message with no recipient', () => { | ||
let messages = [...new Array(2).fill({ to: '?' }), { to: [] }]; | ||
let chunks = client.chunkPushNotifications(messages); | ||
expect(chunks.length).toBe(1); | ||
// The message with no recipient should be removed. | ||
expect(chunks[0].length).toBe(2); | ||
let totalMessageCount = _coundAndValidateMessages(chunks); | ||
expect(totalMessageCount).toBe(2); | ||
}); | ||
}); | ||
test('defines the push notification chunk size', () => { | ||
expect(ExpoClient.pushNotificationChunkSizeLimit).toBeDefined(); | ||
}); | ||
it('chunks lists of push notification receipt IDs', () => { | ||
test('chunks lists of push notification receipt IDs', () => { | ||
let client = new ExpoClient(); | ||
@@ -39,7 +163,7 @@ let receiptIds = new Array(2999).fill('F5741A13-BCDA-434B-A316-5DC0E6FFA94F'); | ||
it('defines the push notification receipt ID chunk size', () => { | ||
test('defines the push notification receipt ID chunk size', () => { | ||
expect(ExpoClient.pushNotificationReceiptChunkSizeLimit).toBeDefined(); | ||
}); | ||
it('can detect an Expo push token', () => { | ||
test('can detect an Expo push token', () => { | ||
expect(ExpoClient.isExpoPushToken('ExpoPushToken[xxxxxxxxxxxxxxxxxxxxxx]')).toBe(true); | ||
@@ -46,0 +170,0 @@ expect(ExpoClient.isExpoPushToken('ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]')).toBe(true); |
@@ -75,2 +75,4 @@ /** | ||
async sendPushNotificationsAsync(messages: ExpoPushMessage[]): Promise<ExpoPushTicket[]> { | ||
const actualMessagesCount = Expo._getActualMessagesCount(messages); | ||
let data = await this._requestAsync(`${BASE_API_URL}/push/send`, { | ||
@@ -84,6 +86,6 @@ httpMethod: 'post', | ||
if (!Array.isArray(data) || data.length !== messages.length) { | ||
if (!Array.isArray(data) || data.length !== actualMessagesCount) { | ||
let apiError: ExtensibleError = new Error( | ||
`Expected Expo to respond with ${messages.length} ${ | ||
messages.length === 1 ? 'ticket' : 'tickets' | ||
`Expected Expo to respond with ${actualMessagesCount} ${ | ||
actualMessagesCount === 1 ? 'ticket' : 'tickets' | ||
} but got ${data.length}` | ||
@@ -121,3 +123,45 @@ ); | ||
chunkPushNotifications(messages: ExpoPushMessage[]): ExpoPushMessage[][] { | ||
return this._chunkItems(messages, PUSH_NOTIFICATION_CHUNK_LIMIT); | ||
let chunks: ExpoPushMessage[][] = []; | ||
let chunk: ExpoPushMessage[] = []; | ||
let chunkMessagesCount = 0; | ||
for (let message of messages) { | ||
if (Array.isArray(message.to)) { | ||
let partialTo: ExpoPushToken[] = []; | ||
for (let recipient of message.to) { | ||
partialTo.push(recipient); | ||
chunkMessagesCount++; | ||
if (chunkMessagesCount >= PUSH_NOTIFICATION_CHUNK_LIMIT) { | ||
// Cap this chunk here if it already exceeds PUSH_NOTIFICATION_CHUNK_LIMIT. | ||
// Then create a new chunk to continue on the remaining recipients for this message. | ||
chunk.push({ ...message, to: partialTo }); | ||
chunks.push(chunk); | ||
chunk = []; | ||
chunkMessagesCount = 0; | ||
partialTo = []; | ||
} | ||
} | ||
if (partialTo.length) { | ||
// Add remaining `partialTo` to the chunk. | ||
chunk.push({ ...message, to: partialTo }); | ||
} | ||
} else { | ||
chunk.push(message); | ||
chunkMessagesCount++; | ||
} | ||
if (chunkMessagesCount >= PUSH_NOTIFICATION_CHUNK_LIMIT) { | ||
// Cap this chunk if it exceeds PUSH_NOTIFICATION_CHUNK_LIMIT. | ||
// Then create a new chunk to continue on the remaining messages. | ||
chunks.push(chunk); | ||
chunk = []; | ||
chunkMessagesCount = 0; | ||
} | ||
} | ||
if (chunkMessagesCount) { | ||
// Add the remaining chunk to the chunks. | ||
chunks.push(chunk); | ||
} | ||
return chunks; | ||
} | ||
@@ -260,2 +304,13 @@ | ||
} | ||
static _getActualMessagesCount(messages: ExpoPushMessage[]): number { | ||
return messages.reduce((acc, cur) => { | ||
if (Array.isArray(cur.to)) { | ||
acc += cur.to.length; | ||
} else { | ||
acc++; | ||
} | ||
return acc; | ||
}, 0); | ||
} | ||
} | ||
@@ -285,3 +340,3 @@ | ||
export type ExpoPushMessage = { | ||
to: ExpoPushToken; | ||
to: ExpoPushToken | ExpoPushToken[]; | ||
data?: Object; | ||
@@ -288,0 +343,0 @@ title?: string; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
49804
902