Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions etc/firebase-admin.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,8 @@ export namespace messaging {
export type DataMessagePayload = DataMessagePayload;
// Warning: (ae-forgotten-export) The symbol "FcmOptions" needs to be exported by the entry point default-namespace.d.ts
export type FcmOptions = FcmOptions;
// Warning: (ae-forgotten-export) The symbol "FidMessage" needs to be exported by the entry point default-namespace.d.ts
export type FidMessage = FidMessage;
// Warning: (ae-forgotten-export) The symbol "LightSettings" needs to be exported by the entry point default-namespace.d.ts
export type LightSettings = LightSettings;
// Warning: (ae-forgotten-export) The symbol "Message" needs to be exported by the entry point default-namespace.d.ts
Expand All @@ -395,6 +397,8 @@ export namespace messaging {
// Warning: (ae-forgotten-export) The symbol "SendResponse" needs to be exported by the entry point default-namespace.d.ts
export type SendResponse = SendResponse;
// Warning: (ae-forgotten-export) The symbol "TokenMessage" needs to be exported by the entry point default-namespace.d.ts
//
// @deprecated
export type TokenMessage = TokenMessage;
// Warning: (ae-forgotten-export) The symbol "TopicMessage" needs to be exported by the entry point default-namespace.d.ts
export type TopicMessage = TopicMessage;
Expand Down
15 changes: 11 additions & 4 deletions etc/firebase-admin.messaging.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ export interface FcmOptions {
analyticsLabel?: string;
}

// @public (undocumented)
export interface FidMessage extends BaseMessage {
// (undocumented)
fid: string;
}

// Warning: (ae-forgotten-export) The symbol "PrefixedFirebaseError" needs to be exported by the entry point index.d.ts
//
// @public
Expand All @@ -187,7 +193,7 @@ export interface LightSettings {
}

// @public
export type Message = TokenMessage | TopicMessage | ConditionMessage;
export type Message = FidMessage | TokenMessage | TopicMessage | ConditionMessage;

// @public
export class Messaging {
Expand Down Expand Up @@ -329,8 +335,9 @@ export interface MessagingTopicManagementResponse {

// @public
export interface MulticastMessage extends BaseMessage {
// (undocumented)
tokens: string[];
fids?: string[];
// @deprecated
tokens?: string[];
}

// @public
Expand Down Expand Up @@ -366,7 +373,7 @@ export interface SendResponse {
success: boolean;
}

// @public (undocumented)
// @public @deprecated (undocumented)
export interface TokenMessage extends BaseMessage {
// (undocumented)
token: string;
Expand Down
1 change: 1 addition & 0 deletions src/messaging/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export {
CriticalSound,
ConditionMessage,
FcmOptions,
FidMessage,
LightSettings,
Message,
MessagingTopicManagementResponse,
Expand Down
25 changes: 21 additions & 4 deletions src/messaging/messaging-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ export interface BaseMessage {
fcmOptions?: FcmOptions;
}

export interface FidMessage extends BaseMessage {
fid: string;
}
Comment thread
yvonnep165 marked this conversation as resolved.

/**
* @deprecated Use {@link FidMessage} instead.
*/
export interface TokenMessage extends BaseMessage {
token: string;
}
Expand All @@ -40,16 +47,26 @@ export interface ConditionMessage extends BaseMessage {

/**
* Payload for the {@link Messaging.send} operation. The payload contains all the fields
* in the BaseMessage type, and exactly one of token, topic or condition.
* in the BaseMessage type, and exactly one of fid, token, topic or condition.
*/
export type Message = TokenMessage | TopicMessage | ConditionMessage;
export type Message = FidMessage | TokenMessage | TopicMessage | ConditionMessage;

/**
* Payload for the {@link Messaging.sendEachForMulticast} method. The payload contains all the fields
* in the BaseMessage type, and a list of tokens.
* in the BaseMessage type, and a list of tokens and/or fids.
*/
export interface MulticastMessage extends BaseMessage {
tokens: string[];
/**
* A list of Firebase Installation IDs (FIDs) to target.
*/
fids?: string[];

/**
* A list of registration tokens to target.
*
* @deprecated Use {@link MulticastMessage.fids} instead.
*/
tokens?: string[];
}
Comment thread
yvonnep165 marked this conversation as resolved.

/**
Expand Down
4 changes: 2 additions & 2 deletions src/messaging/messaging-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ export function validateMessage(message: Message): void {
}
}

const targets = [anyMessage.token, anyMessage.topic, anyMessage.condition];
const targets = [anyMessage.fid, anyMessage.token, anyMessage.topic, anyMessage.condition];
if (targets.filter((v) => validator.isNonEmptyString(v)).length !== 1) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_PAYLOAD,
'Exactly one of topic, token or condition is required');
'Exactly one of fid, topic, token or condition is required');
}

validateStringMap(message.data, 'data');
Expand Down
8 changes: 8 additions & 0 deletions src/messaging/messaging-namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
CriticalSound as TCriticalSound,
ConditionMessage as TConditionMessage,
FcmOptions as TFcmOptions,
FidMessage as TFidMessage,
LightSettings as TLightSettings,
Message as TMessage,
MessagingTopicManagementResponse as TMessagingTopicManagementResponse,
Expand Down Expand Up @@ -174,8 +175,15 @@ export namespace messaging {
*/
export type SendResponse = TSendResponse;

/**
* Type alias to {@link firebase-admin.messaging#FidMessage}.
*/
export type FidMessage = TFidMessage;

/**
* Type alias to {@link firebase-admin.messaging#TokenMessage}.
*
* @deprecated Use {@link firebase-admin.messaging#FidMessage} instead.
*/
export type TokenMessage = TTokenMessage;

Expand Down
39 changes: 33 additions & 6 deletions src/messaging/messaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,27 +297,54 @@ export class Messaging {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_ARGUMENT, 'MulticastMessage must be a non-null object');
}
if (!validator.isNonEmptyArray(copy.tokens)) {

const tokens: string[] = copy.tokens || [];
const fids: string[] = copy.fids || [];

if ('tokens' in copy && !validator.isNonEmptyArray(copy.tokens)) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_ARGUMENT, 'tokens must be a non-empty array');
}
if (copy.tokens.length > FCM_MAX_BATCH_SIZE) {
if ('fids' in copy && !validator.isNonEmptyArray(copy.fids)) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_ARGUMENT, 'fids must be a non-empty array');
}
if (tokens.length === 0 && fids.length === 0) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_ARGUMENT, 'Either tokens or fids must be a non-empty array');
}

const totalLength = tokens.length + fids.length;
if (totalLength > FCM_MAX_BATCH_SIZE) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_ARGUMENT,
`tokens list must not contain more than ${FCM_MAX_BATCH_SIZE} items`);
`tokens and fids list must not contain more than ${FCM_MAX_BATCH_SIZE} items in total`);
Comment thread
yvonnep165 marked this conversation as resolved.
Outdated
}

const messages: Message[] = copy.tokens.map((token) => {
return {
const messages: Message[] = [];
tokens.forEach((token) => {
messages.push({
token,
android: copy.android,
apns: copy.apns,
data: copy.data,
notification: copy.notification,
webpush: copy.webpush,
fcmOptions: copy.fcmOptions,
};
});
});
fids.forEach((fid) => {
messages.push({
fid,
android: copy.android,
apns: copy.apns,
data: copy.data,
notification: copy.notification,
webpush: copy.webpush,
fcmOptions: copy.fcmOptions,
});
});
Comment thread
yvonnep165 marked this conversation as resolved.
Outdated

return this.sendEach(messages, dryRun);
}

Expand Down
53 changes: 53 additions & 0 deletions test/integration/messaging.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const topic = 'mock-topic';

const invalidTopic = 'topic-$%#^';

const mockFid = 'mock-fid';

const message: Message = {
data: {
foo: 'bar',
Expand Down Expand Up @@ -80,6 +82,13 @@ const message: Message = {
topic: 'foo-bar',
};

const fidMessage: Message = {
data: message.data,
android: message.android,
apns: message.apns,
fid: mockFid,
};

describe('admin.messaging', () => {
it('send(message, dryRun) returns a message ID', () => {
return getMessaging().send(message, true)
Expand All @@ -88,6 +97,11 @@ describe('admin.messaging', () => {
});
});

it('send(message with fid, dryRun) fails with invalid-argument', () => {
return getMessaging().send(fidMessage, true)
.should.eventually.be.rejected.and.have.property('code', 'messaging/invalid-argument');
});

it('sendEach()', () => {
const messages: Message[] = [message, message, message];
return getMessaging().sendEach(messages, true)
Expand Down Expand Up @@ -138,6 +152,45 @@ describe('admin.messaging', () => {
});
});

it('sendEachForMulticast() with fids', () => {
const multicastMessage: MulticastMessage = {
data: message.data,
android: message.android,
fids: ['not-a-fid', 'also-not-a-fid'],
};
return getMessaging().sendEachForMulticast(multicastMessage, true)
.then((response) => {
expect(response.responses.length).to.equal(2);
expect(response.successCount).to.equal(0);
expect(response.failureCount).to.equal(2);
response.responses.forEach((resp) => {
expect(resp.success).to.be.false;
expect(resp.messageId).to.be.undefined;
expect(resp.error).to.have.property('code', 'messaging/invalid-argument');
});
});
});

it('sendEachForMulticast() with mixed tokens and fids', () => {
const multicastMessage: MulticastMessage = {
data: message.data,
android: message.android,
tokens: ['not-a-token'],
fids: ['not-a-fid'],
};
return getMessaging().sendEachForMulticast(multicastMessage, true)
.then((response) => {
expect(response.responses.length).to.equal(2);
expect(response.successCount).to.equal(0);
expect(response.failureCount).to.equal(2);
response.responses.forEach((resp) => {
expect(resp.success).to.be.false;
expect(resp.messageId).to.be.undefined;
expect(resp.error).to.have.property('code', 'messaging/invalid-argument');
});
});
});

it('subscribeToTopic() returns a response with success count', () => {
return getMessaging().subscribeToTopic(registrationToken, topic)
.then((response) => {
Expand Down
Loading
Loading