Socket
Socket
Sign inDemoInstall

expo-server-sdk

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

expo-server-sdk - npm Package Compare versions

Comparing version 3.5.0 to 3.5.1

build/__mocks__/node-fetch.d.ts

6

build/ExpoClient.d.ts

@@ -12,3 +12,3 @@ /// <reference types="node" />

*/
static isExpoPushToken(token: ExpoPushToken): boolean;
static isExpoPushToken(token: unknown): token is ExpoPushToken;
/**

@@ -54,3 +54,3 @@ * Sends the given messages to their recipients via push notifications and returns an array of

to: ExpoPushToken | ExpoPushToken[];
data?: Object;
data?: object;
title?: string;

@@ -79,3 +79,3 @@ subtitle?: string;

status: 'ok';
details?: Object;
details?: object;
__debug?: any;

@@ -82,0 +82,0 @@ };

@@ -12,2 +12,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.Expo = void 0;
/**

@@ -71,3 +72,3 @@ * expo-server-sdk

const actualMessagesCount = Expo._getActualMessageCount(messages);
let data = yield this.requestAsync(`${BASE_API_URL}/push/send`, {
const data = yield this.requestAsync(`${BASE_API_URL}/push/send`, {
httpMethod: 'post',

@@ -80,3 +81,3 @@ body: messages,

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}`);
const apiError = new Error(`Expected Expo to respond with ${actualMessagesCount} ${actualMessagesCount === 1 ? 'ticket' : 'tickets'} but got ${data.length}`);
apiError.data = data;

@@ -90,3 +91,3 @@ throw apiError;

return __awaiter(this, void 0, void 0, function* () {
let data = yield this.requestAsync(`${BASE_API_URL}/push/getReceipts`, {
const data = yield this.requestAsync(`${BASE_API_URL}/push/getReceipts`, {
httpMethod: 'post',

@@ -99,3 +100,3 @@ body: { ids: receiptIds },

if (!data || typeof data !== 'object' || Array.isArray(data)) {
let apiError = new Error(`Expected Expo to respond with a map from receipt IDs to receipts but received data of another type`);
const apiError = new Error(`Expected Expo to respond with a map from receipt IDs to receipts but received data of another type`);
apiError.data = data;

@@ -108,9 +109,9 @@ throw apiError;

chunkPushNotifications(messages) {
let chunks = [];
const chunks = [];
let chunk = [];
let chunkMessagesCount = 0;
for (let message of messages) {
for (const message of messages) {
if (Array.isArray(message.to)) {
let partialTo = [];
for (let recipient of message.to) {
for (const recipient of message.to) {
partialTo.push(recipient);

@@ -155,5 +156,5 @@ chunkMessagesCount++;

chunkItems(items, chunkSize) {
let chunks = [];
const chunks = [];
let chunk = [];
for (let item of items) {
for (const item of items) {
chunk.push(item);

@@ -173,4 +174,4 @@ if (chunk.length >= chunkSize) {

let requestBody;
let sdkVersion = require('../package.json').version;
let requestHeaders = new node_fetch_1.Headers({
const sdkVersion = require('../package.json').version;
const requestHeaders = new node_fetch_1.Headers({
Accept: 'application/json',

@@ -181,3 +182,3 @@ 'Accept-Encoding': 'gzip, deflate',

if (options.body != null) {
let json = JSON.stringify(options.body);
const json = JSON.stringify(options.body);
assert(json != null, `JSON request body must not be null`);

@@ -193,3 +194,3 @@ if (options.shouldCompress(json)) {

}
let response = yield this.limitConcurrentRequests(() => node_fetch_1.default(url, {
const response = yield this.limitConcurrentRequests(() => node_fetch_1.default(url, {
method: options.httpMethod,

@@ -201,6 +202,6 @@ body: requestBody,

if (response.status !== 200) {
let apiError = yield this.parseErrorResponseAsync(response);
const apiError = yield this.parseErrorResponseAsync(response);
throw apiError;
}
let textBody = yield response.text();
const textBody = yield response.text();
// We expect the API response body to be JSON

@@ -212,7 +213,7 @@ let result;

catch (e) {
let apiError = yield this.getTextResponseErrorAsync(response, textBody);
const apiError = yield this.getTextResponseErrorAsync(response, textBody);
throw apiError;
}
if (result.errors) {
let apiError = this.getErrorFromResult(result);
const apiError = this.getErrorFromResult(result);
throw apiError;

@@ -225,3 +226,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
let textBody = yield response.text();
const textBody = yield response.text();
let result;

@@ -235,3 +236,3 @@ try {

if (!result.errors || !Array.isArray(result.errors) || !result.errors.length) {
let apiError = yield this.getTextResponseErrorAsync(response, textBody);
const apiError = yield this.getTextResponseErrorAsync(response, textBody);
apiError.errorData = result;

@@ -245,3 +246,3 @@ return apiError;

return __awaiter(this, void 0, void 0, function* () {
let apiError = new Error(`Expo responded with an error with status code ${response.status}: ` + text);
const apiError = new Error(`Expo responded with an error with status code ${response.status}: ` + text);
apiError.statusCode = response.status;

@@ -258,6 +259,6 @@ apiError.errorText = text;

assert(result.errors && result.errors.length > 0, `Expected at least one error from Expo`);
let [errorData, ...otherErrorData] = result.errors;
let error = this.getErrorFromResultError(errorData);
const [errorData, ...otherErrorData] = result.errors;
const error = this.getErrorFromResultError(errorData);
if (otherErrorData.length) {
error.others = otherErrorData.map(data => this.getErrorFromResultError(data));
error.others = otherErrorData.map((data) => this.getErrorFromResultError(data));
}

@@ -270,3 +271,3 @@ return error;

getErrorFromResultError(errorData) {
let error = new Error(errorData.message);
const error = new Error(errorData.message);
error.code = errorData.code;

@@ -273,0 +274,0 @@ if (errorData.details != null) {

{
"name": "expo-server-sdk",
"version": "3.5.0",
"description": "Server side library for working with Expo using Node.js",
"version": "3.5.1",
"description": "Server-side library for working with Expo using Node.js",
"main": "build/ExpoClient.js",

@@ -12,5 +12,5 @@ "types": "build/ExpoClient.d.ts",

"scripts": {
"babel": "babel",
"build": "./build.sh",
"prepublish": "npm run build",
"lint": "eslint src",
"prepare": "yarn build",
"test": "jest",

@@ -20,20 +20,15 @@ "tsc": "tsc",

},
"eslintConfig": {
"extends": "universe/node",
"settings": {
"react": {
"version": "999.999.0"
}
}
},
"jest": {
"coverageDirectory": "<rootDir>/../coverage",
"preset": "ts-jest",
"roots": [
"<rootDir>/src/"
],
"moduleFileExtensions": [
"ts",
"js"
],
"globals": {
"ts-jest": {
"tsConfig": "tsconfig.json"
}
},
"testEnvironment": "node",
"testMatch": [
"**/__tests__/*.+(js|ts)"
]
"rootDir": "src",
"testEnvironment": "node"
},

@@ -59,9 +54,12 @@ "repository": {

"devDependencies": {
"@types/invariant": "^2.2.31",
"@types/jest": "^25.1.4",
"@types/node-fetch": "^2.5.5",
"jest": "^25.2.4",
"ts-jest": "~25.3.0",
"typescript": "^3.8.3"
"@types/jest": "^26.0.3",
"@types/node-fetch": "^2.5.7",
"eslint": "^7.3.1",
"eslint-config-universe": "^3.0.2",
"fetch-mock": "^9.10.3",
"jest": "^26.1.0",
"prettier": "^2.0.5",
"ts-jest": "~26.1.1",
"typescript": "^3.9.5"
}
}

@@ -1,2 +0,2 @@

# expo-server-sdk-node [![CircleCI](https://circleci.com/gh/expo/expo-server-sdk-node.svg?style=svg)](https://circleci.com/gh/expo/expo-server-sdk-node) [![codecov](https://codecov.io/gh/expo/expo-server-sdk-node/branch/master/graph/badge.svg)](https://codecov.io/gh/expo/expo-server-sdk-node)
# expo-server-sdk-node ![Tests](https://github.com/expo/expo-server-sdk-node/workflows/Tests/badge.svg) [![codecov](https://codecov.io/gh/expo/expo-server-sdk-node/branch/master/graph/badge.svg)](https://codecov.io/gh/expo/expo-server-sdk-node)
Server-side library for working with Expo using Node.js.

@@ -20,3 +20,3 @@

// Create the messages that you want to send to clents
// Create the messages that you want to send to clients
let messages = [];

@@ -136,9 +136,5 @@ for (let pushToken of somePushTokens) {

## TODO
* Need to add tests
## See Also
* https://github.com/expo/expo-server-sdk-ruby
* https://github.com/expo/expo-server-sdk-python
* https://github.com/expo-community/expo-server-sdk-ruby
* https://github.com/expo-community/expo-server-sdk-python

@@ -0,68 +1,277 @@

import fetch from 'node-fetch';
import ExpoClient, { ExpoPushMessage } from '../ExpoClient';
test('chunks lists of push notification messages', () => {
let client = new ExpoClient();
let messages = new Array(999).fill({ to: '?' });
let chunks = client.chunkPushNotifications(messages);
let totalMessageCount = 0;
for (let chunk of chunks) {
totalMessageCount += chunk.length;
}
expect(totalMessageCount).toBe(messages.length);
afterEach(() => {
(fetch as any).reset();
});
test('can chunk small lists of push notification messages', () => {
let client = new ExpoClient();
let messages = new Array(10).fill({ to: '?' });
let chunks = client.chunkPushNotifications(messages);
expect(chunks.length).toBe(1);
expect(chunks[0].length).toBe(10);
test('limits the number of concurrent requests', async () => {
(fetch as any).mock('https://exp.host/--/api/v2/push/send', { data: [] });
expect((fetch as any).calls().length).toBe(0);
const client = new ExpoClient({ maxConcurrentRequests: 1 });
const sendPromise1 = client.sendPushNotificationsAsync([]);
const sendPromise2 = client.sendPushNotificationsAsync([]);
expect((fetch as any).calls().length).toBe(1);
await sendPromise1;
expect((fetch as any).calls().length).toBe(2);
await sendPromise2;
expect((fetch as any).calls().length).toBe(2);
});
test('chunks single push notification message with lists of recipients', () => {
const messagesLength = 999;
describe('sending push notification messages', () => {
test('sends requests to the Expo API server', async () => {
const mockTickets = [
{ status: 'ok', id: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' },
{ status: 'ok', id: 'YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY' },
];
(fetch as any).mock('https://exp.host/--/api/v2/push/send', { data: mockTickets });
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 = countAndValidateMessages(chunks);
expect(totalMessageCount).toBe(messagesLength);
const client = new ExpoClient();
const tickets = await client.sendPushNotificationsAsync([{ to: 'a' }, { to: 'b' }]);
expect(tickets).toEqual(mockTickets);
const [, options] = (fetch as any).lastCall('https://exp.host/--/api/v2/push/send');
expect(options.headers.get('accept')).toContain('application/json');
expect(options.headers.get('accept-encoding')).toContain('gzip');
expect(options.headers.get('content-type')).toContain('application/json');
expect(options.headers.get('user-agent')).toMatch(/^expo-server-sdk-node\//);
});
test('compresses request bodies over 1 KiB', async () => {
const mockTickets = [{ status: 'ok', id: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' }];
(fetch as any).mock('https://exp.host/--/api/v2/push/send', { data: mockTickets });
const client = new ExpoClient();
const messages = [{ to: 'a', body: new Array(1500).join('?') }];
expect(JSON.stringify(messages).length).toBeGreaterThan(1024);
const tickets = await client.sendPushNotificationsAsync(messages);
expect(tickets).toEqual(mockTickets);
// Ensure the request body was compressed
const [, options] = (fetch as any).lastCall('https://exp.host/--/api/v2/push/send');
expect(options.body.length).toBeLessThan(JSON.stringify(messages).length);
expect(options.headers.get('content-encoding')).toContain('gzip');
});
test(`throws an error when the number of tickets doesn't match the number of messages`, async () => {
const mockTickets = [
{ status: 'ok', id: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' },
{ status: 'ok', id: 'YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY' },
];
(fetch as any).mock('https://exp.host/--/api/v2/push/send', { data: mockTickets });
const client = new ExpoClient();
await expect(client.sendPushNotificationsAsync([{ to: 'a' }])).rejects.toThrowError(
`Expected Expo to respond with 1 ticket but got 2`
);
await expect(
client.sendPushNotificationsAsync([{ to: 'a' }, { to: 'b' }, { to: 'c' }])
).rejects.toThrowError(`Expected Expo to respond with 3 tickets but got 2`);
});
test('handles 200 HTTP responses with well-formed API errors', async () => {
(fetch as any).mock('https://exp.host/--/api/v2/push/send', {
status: 200,
errors: [{ code: 'TEST_API_ERROR', message: `This is a test error` }],
});
const client = new ExpoClient();
const rejection = expect(client.sendPushNotificationsAsync([])).rejects;
await rejection.toThrowError(`This is a test error`);
await rejection.toMatchObject({ code: 'TEST_API_ERROR' });
});
test('handles 200 HTTP responses with malformed JSON', async () => {
(fetch as any).mock('https://exp.host/--/api/v2/push/send', {
status: 200,
body: '<!DOCTYPE html><body>Not JSON</body>',
});
const client = new ExpoClient();
await expect(client.sendPushNotificationsAsync([])).rejects.toThrowError(
`Expo responded with an error`
);
});
test('handles non-200 HTTP responses with well-formed API errors', async () => {
(fetch as any).mock('https://exp.host/--/api/v2/push/send', {
status: 400,
body: {
errors: [{ code: 'TEST_API_ERROR', message: `This is a test error` }],
},
});
const client = new ExpoClient();
const rejection = expect(client.sendPushNotificationsAsync([])).rejects;
await rejection.toThrowError(`This is a test error`);
await rejection.toMatchObject({ code: 'TEST_API_ERROR' });
});
test('handles non-200 HTTP responses with arbitrary JSON', async () => {
(fetch as any).mock('https://exp.host/--/api/v2/push/send', {
status: 400,
body: { clowntown: true },
});
const client = new ExpoClient();
await expect(client.sendPushNotificationsAsync([])).rejects.toThrowError(
`Expo responded with an error`
);
});
test('handles non-200 HTTP responses with arbitrary text', async () => {
(fetch as any).mock('https://exp.host/--/api/v2/push/send', {
status: 400,
body: '<!DOCTYPE html><body>Not JSON</body>',
});
const client = new ExpoClient();
await expect(client.sendPushNotificationsAsync([])).rejects.toThrowError(
`Expo responded with an error`
);
});
test('handles well-formed API responses with multiple errors and extra details', async () => {
(fetch as any).mock('https://exp.host/--/api/v2/push/send', {
status: 400,
body: {
errors: [
{
code: 'TEST_API_ERROR',
message: `This is a test error`,
details: { __debug: 'test debug information' },
stack:
'Error: This is a test error\n' +
' at SomeServerModule.method (SomeServerModule.js:131:20)',
},
{
code: 'SYSTEM_ERROR',
message: `This is another error`,
},
],
},
});
const client = new ExpoClient();
const rejection = expect(client.sendPushNotificationsAsync([])).rejects;
await rejection.toThrowError(`This is a test error`);
await rejection.toMatchObject({
code: 'TEST_API_ERROR',
details: { __debug: 'test debug information' },
serverStack: expect.any(String),
others: expect.arrayContaining([expect.any(Error)]),
});
});
});
test('can chunk single push notification message with small lists of recipients', () => {
const messagesLength = 10;
describe('retrieving push notification receipts', () => {
test('gets receipts from the Expo API server', async () => {
const mockReceipts = {
'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX': { status: 'ok' },
'YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY': { status: 'ok' },
};
(fetch as any).mock('https://exp.host/--/api/v2/push/getReceipts', { data: mockReceipts });
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);
const client = new ExpoClient();
const receipts = await client.getPushNotificationReceiptsAsync([
'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
'YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY',
]);
expect(receipts).toEqual(mockReceipts);
const [, options] = (fetch as any).lastCall('https://exp.host/--/api/v2/push/getReceipts');
expect(options.headers.get('accept')).toContain('application/json');
expect(options.headers.get('accept-encoding')).toContain('gzip');
expect(options.headers.get('content-type')).toContain('application/json');
});
test('throws an error if the response is not a map', async () => {
const mockReceipts = [{ status: 'ok' }];
(fetch as any).mock('https://exp.host/--/api/v2/push/getReceipts', { data: mockReceipts });
const client = new ExpoClient();
const rejection = expect(
client.getPushNotificationReceiptsAsync(['XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'])
).rejects;
await rejection.toThrowError(`Expected Expo to respond with a map`);
await rejection.toMatchObject({ data: mockReceipts });
});
});
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 = countAndValidateMessages(chunks);
expect(totalMessageCount).toBe(888 + 999 + 90 + 10);
describe('chunking push notification messages', () => {
test('defines the push notification chunk size', () => {
expect(ExpoClient.pushNotificationChunkSizeLimit).toBeDefined();
});
test('chunks lists of push notification messages', () => {
const client = new ExpoClient();
const messages = new Array(999).fill({ to: '?' });
const chunks = client.chunkPushNotifications(messages);
let totalMessageCount = 0;
for (const chunk of chunks) {
totalMessageCount += chunk.length;
}
expect(totalMessageCount).toBe(messages.length);
});
test('can chunk small lists of push notification messages', () => {
const client = new ExpoClient();
const messages = new Array(10).fill({ to: '?' });
const chunks = client.chunkPushNotifications(messages);
expect(chunks.length).toBe(1);
expect(chunks[0].length).toBe(10);
});
test('chunks single push notification message with lists of recipients', () => {
const messagesLength = 999;
const client = new ExpoClient();
const messages = [{ to: new Array(messagesLength).fill('?') }];
const chunks = client.chunkPushNotifications(messages);
for (const chunk of chunks) {
// Each chunk should only contain a single message with 100 recipients
expect(chunk.length).toBe(1);
}
const totalMessageCount = countAndValidateMessages(chunks);
expect(totalMessageCount).toBe(messagesLength);
});
test('can chunk single push notification message with small lists of recipients', () => {
const messagesLength = 10;
const client = new ExpoClient();
const messages = [{ to: new Array(messagesLength).fill('?') }];
const 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', () => {
const client = new ExpoClient();
const messages = [
{ to: new Array(888).fill('?') },
...new Array(999).fill({
to: '?',
}),
{ to: new Array(90).fill('?') },
...new Array(10).fill({ to: '?' }),
];
const chunks = client.chunkPushNotifications(messages);
const totalMessageCount = countAndValidateMessages(chunks);
expect(totalMessageCount).toBe(888 + 999 + 90 + 10);
});
});
describe('chunking a single push notification message with multiple recipients', () => {
let client = new ExpoClient();
const client = new ExpoClient();
test('one message with 100 recipients', () => {
let messages = [{ to: new Array(100).fill('?') }];
let chunks = client.chunkPushNotifications(messages);
const messages = [{ to: new Array(100).fill('?') }];
const chunks = client.chunkPushNotifications(messages);
expect(chunks.length).toBe(1);

@@ -74,8 +283,8 @@ expect(chunks[0].length).toBe(1);

test('one message with 101 recipients', () => {
let messages = [{ to: new Array(101).fill('?') }];
let chunks = client.chunkPushNotifications(messages);
const messages = [{ to: new Array(101).fill('?') }];
const chunks = client.chunkPushNotifications(messages);
expect(chunks.length).toBe(2);
expect(chunks[0].length).toBe(1);
expect(chunks[1].length).toBe(1);
let totalMessageCount = countAndValidateMessages(chunks);
const totalMessageCount = countAndValidateMessages(chunks);
expect(totalMessageCount).toBe(101);

@@ -85,8 +294,8 @@ });

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);
const messages = [{ to: new Array(99).fill('?') }, ...new Array(2).fill({ to: '?' })];
const chunks = client.chunkPushNotifications(messages);
expect(chunks.length).toBe(2);
expect(chunks[0].length).toBe(2);
expect(chunks[1].length).toBe(1);
let totalMessageCount = countAndValidateMessages(chunks);
const totalMessageCount = countAndValidateMessages(chunks);
expect(totalMessageCount).toBe(99 + 2);

@@ -96,8 +305,8 @@ });

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);
const messages = [{ to: new Array(100).fill('?') }, ...new Array(2).fill({ to: '?' })];
const chunks = client.chunkPushNotifications(messages);
expect(chunks.length).toBe(2);
expect(chunks[0].length).toBe(1);
expect(chunks[1].length).toBe(2);
let totalMessageCount = countAndValidateMessages(chunks);
const totalMessageCount = countAndValidateMessages(chunks);
expect(totalMessageCount).toBe(100 + 2);

@@ -107,8 +316,8 @@ });

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);
const messages = [...new Array(99).fill({ to: '?' }), { to: new Array(2).fill('?') }];
const chunks = client.chunkPushNotifications(messages);
expect(chunks.length).toBe(2);
expect(chunks[0].length).toBe(100);
expect(chunks[1].length).toBe(1);
let totalMessageCount = countAndValidateMessages(chunks);
const totalMessageCount = countAndValidateMessages(chunks);
expect(totalMessageCount).toBe(99 + 2);

@@ -118,4 +327,4 @@ });

test('no message', () => {
let messages: ExpoPushMessage[] = [];
let chunks = client.chunkPushNotifications(messages);
const messages: ExpoPushMessage[] = [];
const chunks = client.chunkPushNotifications(messages);
expect(chunks.length).toBe(0);

@@ -125,14 +334,14 @@ });

test('one message with no recipient', () => {
let messages = [{ to: [] }];
let chunks = client.chunkPushNotifications(messages);
const messages = [{ to: [] }];
const 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);
test('two messages and one additional message with no recipient', () => {
const messages = [...new Array(2).fill({ to: '?' }), { to: [] }];
const 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 = countAndValidateMessages(chunks);
const totalMessageCount = countAndValidateMessages(chunks);
expect(totalMessageCount).toBe(2);

@@ -142,21 +351,19 @@ });

test('defines the push notification chunk size', () => {
expect(ExpoClient.pushNotificationChunkSizeLimit).toBeDefined();
});
describe('chunking push notification receipt IDs', () => {
test('defines the push notification receipt ID chunk size', () => {
expect(ExpoClient.pushNotificationReceiptChunkSizeLimit).toBeDefined();
});
test('chunks lists of push notification receipt IDs', () => {
let client = new ExpoClient();
let receiptIds = new Array(2999).fill('F5741A13-BCDA-434B-A316-5DC0E6FFA94F');
let chunks = client.chunkPushNotificationReceiptIds(receiptIds);
let totalReceiptIdCount = 0;
for (let chunk of chunks) {
totalReceiptIdCount += chunk.length;
}
expect(totalReceiptIdCount).toBe(receiptIds.length);
test('chunks lists of push notification receipt IDs', () => {
const client = new ExpoClient();
const receiptIds = new Array(2999).fill('F5741A13-BCDA-434B-A316-5DC0E6FFA94F');
const chunks = client.chunkPushNotificationReceiptIds(receiptIds);
let totalReceiptIdCount = 0;
for (const chunk of chunks) {
totalReceiptIdCount += chunk.length;
}
expect(totalReceiptIdCount).toBe(receiptIds.length);
});
});
test('defines the push notification receipt ID chunk size', () => {
expect(ExpoClient.pushNotificationReceiptChunkSizeLimit).toBeDefined();
});
test('can detect an Expo push token', () => {

@@ -180,6 +387,6 @@ expect(ExpoClient.isExpoPushToken('ExpoPushToken[xxxxxxxxxxxxxxxxxxxxxx]')).toBe(true);

function countAndValidateMessages(chunks: ExpoPushMessage[][]) {
function countAndValidateMessages(chunks: ExpoPushMessage[][]): number {
let totalMessageCount = 0;
for (let chunk of chunks) {
let chunkMessagesCount = ExpoClient._getActualMessageCount(chunk);
for (const chunk of chunks) {
const chunkMessagesCount = ExpoClient._getActualMessageCount(chunk);
expect(chunkMessagesCount).toBeLessThanOrEqual(ExpoClient.pushNotificationChunkSizeLimit);

@@ -186,0 +393,0 @@ totalMessageCount += chunkMessagesCount;

@@ -54,3 +54,3 @@ /**

*/
static isExpoPushToken(token: ExpoPushToken): boolean {
static isExpoPushToken(token: unknown): token is ExpoPushToken {
return (

@@ -78,3 +78,3 @@ typeof token === 'string' &&

let data = await this.requestAsync(`${BASE_API_URL}/push/send`, {
const data = await this.requestAsync(`${BASE_API_URL}/push/send`, {
httpMethod: 'post',

@@ -88,3 +88,3 @@ body: messages,

if (!Array.isArray(data) || data.length !== actualMessagesCount) {
let apiError: ExtensibleError = new Error(
const apiError: ExtensibleError = new Error(
`Expected Expo to respond with ${actualMessagesCount} ${

@@ -104,3 +104,3 @@ actualMessagesCount === 1 ? 'ticket' : 'tickets'

): Promise<{ [id: string]: ExpoPushReceipt }> {
let data = await this.requestAsync(`${BASE_API_URL}/push/getReceipts`, {
const data = await this.requestAsync(`${BASE_API_URL}/push/getReceipts`, {
httpMethod: 'post',

@@ -114,3 +114,3 @@ body: { ids: receiptIds },

if (!data || typeof data !== 'object' || Array.isArray(data)) {
let apiError: ExtensibleError = new Error(
const apiError: ExtensibleError = new Error(
`Expected Expo to respond with a map from receipt IDs to receipts but received data of another type`

@@ -126,10 +126,10 @@ );

chunkPushNotifications(messages: ExpoPushMessage[]): ExpoPushMessage[][] {
let chunks: ExpoPushMessage[][] = [];
const chunks: ExpoPushMessage[][] = [];
let chunk: ExpoPushMessage[] = [];
let chunkMessagesCount = 0;
for (let message of messages) {
for (const message of messages) {
if (Array.isArray(message.to)) {
let partialTo: ExpoPushToken[] = [];
for (let recipient of message.to) {
for (const recipient of message.to) {
partialTo.push(recipient);

@@ -177,5 +177,5 @@ chunkMessagesCount++;

private chunkItems<T>(items: T[], chunkSize: number): T[][] {
let chunks: T[][] = [];
const chunks: T[][] = [];
let chunk: T[] = [];
for (let item of items) {
for (const item of items) {
chunk.push(item);

@@ -198,4 +198,4 @@ if (chunk.length >= chunkSize) {

let sdkVersion = require('../package.json').version;
let requestHeaders = new Headers({
const sdkVersion = require('../package.json').version;
const requestHeaders = new Headers({
Accept: 'application/json',

@@ -207,3 +207,3 @@ 'Accept-Encoding': 'gzip, deflate',

if (options.body != null) {
let json = JSON.stringify(options.body);
const json = JSON.stringify(options.body);
assert(json != null, `JSON request body must not be null`);

@@ -220,3 +220,3 @@ if (options.shouldCompress(json)) {

let response = await this.limitConcurrentRequests(() =>
const response = await this.limitConcurrentRequests(() =>
fetch(url, {

@@ -231,7 +231,7 @@ method: options.httpMethod,

if (response.status !== 200) {
let apiError = await this.parseErrorResponseAsync(response);
const apiError = await this.parseErrorResponseAsync(response);
throw apiError;
}
let textBody = await response.text();
const textBody = await response.text();
// We expect the API response body to be JSON

@@ -242,3 +242,3 @@ let result: ApiResult;

} catch (e) {
let apiError = await this.getTextResponseErrorAsync(response, textBody);
const apiError = await this.getTextResponseErrorAsync(response, textBody);
throw apiError;

@@ -248,3 +248,3 @@ }

if (result.errors) {
let apiError = this.getErrorFromResult(result);
const apiError = this.getErrorFromResult(result);
throw apiError;

@@ -257,3 +257,3 @@ }

private async parseErrorResponseAsync(response: FetchResponse): Promise<Error> {
let textBody = await response.text();
const textBody = await response.text();
let result: ApiResult;

@@ -267,3 +267,3 @@ try {

if (!result.errors || !Array.isArray(result.errors) || !result.errors.length) {
let apiError: ExtensibleError = await this.getTextResponseErrorAsync(response, textBody);
const apiError: ExtensibleError = await this.getTextResponseErrorAsync(response, textBody);
apiError.errorData = result;

@@ -277,3 +277,3 @@ return apiError;

private async getTextResponseErrorAsync(response: FetchResponse, text: string): Promise<Error> {
let apiError: ExtensibleError = new Error(
const apiError: ExtensibleError = new Error(
`Expo responded with an error with status code ${response.status}: ` + text

@@ -292,6 +292,6 @@ );

assert(result.errors && result.errors.length > 0, `Expected at least one error from Expo`);
let [errorData, ...otherErrorData] = result.errors!;
let error: ExtensibleError = this.getErrorFromResultError(errorData);
const [errorData, ...otherErrorData] = result.errors!;
const error: ExtensibleError = this.getErrorFromResultError(errorData);
if (otherErrorData.length) {
error.others = otherErrorData.map(data => this.getErrorFromResultError(data));
error.others = otherErrorData.map((data) => this.getErrorFromResultError(data));
}

@@ -305,3 +305,3 @@ return error;

private getErrorFromResultError(errorData: ApiResultError): Error {
let error: ExtensibleError = new Error(errorData.message);
const error: ExtensibleError = new Error(errorData.message);
error.code = errorData.code;

@@ -355,3 +355,3 @@

to: ExpoPushToken | ExpoPushToken[];
data?: Object;
data?: object;
title?: string;

@@ -388,3 +388,3 @@ subtitle?: string;

status: 'ok';
details?: Object;
details?: object;
// Internal field used only by developers working on Expo

@@ -391,0 +391,0 @@ __debug?: any;

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc