Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9846af3
Add FidMessage and deprecate TokenMessage
yvonnep165 May 13, 2026
97ac410
Add fids to MulticastMessage interface
yvonnep165 May 13, 2026
7bdf972
Add integration tests
yvonnep165 May 13, 2026
8b5e564
Extract API docstring
yvonnep165 May 13, 2026
208378e
Merge branch 'main' into yp-add-fid-arg
yvonnep165 May 13, 2026
96de332
Change tokens back to required field, add extra docstrings and refact…
yvonnep165 May 14, 2026
ec3fdc4
Fix the lint error
yvonnep165 May 14, 2026
6986cc7
Merge branch 'main' into yp-add-fid-arg
yvonnep165 May 14, 2026
37b2740
Merge branch 'main' into yp-add-fid-arg
yvonnep165 May 14, 2026
cf2163d
Add FidMulticastMessage and Implement Function Overloads on sendEachF…
yvonnep165 May 15, 2026
da81dc2
Extract API doc and remove hyperlink due to duplicate names from func…
yvonnep165 May 15, 2026
d914462
Update sendEachForMulticast docstring
yvonnep165 May 20, 2026
55e645e
Add token deprecation documentation
yvonnep165 May 25, 2026
2316fde
Update integration tests error code for invalid fid target
yvonnep165 May 27, 2026
7854f58
Register new installation-id-not-registered Error Code
yvonnep165 May 28, 2026
9e5d4cf
Extract api docstring
yvonnep165 May 28, 2026
7a802d9
Resolve gemini review comments and add a unit test
yvonnep165 May 28, 2026
4e584c4
Merge remote-tracking branch 'origin/main' into yp-add-fid-arg
yvonnep165 Jun 8, 2026
09f7dd7
Add explicit note in FidMulticastMessage interface to avoid confusion
yvonnep165 Jun 9, 2026
e8febe1
Merge branch 'main' into yp-add-fid-arg
yvonnep165 Jun 9, 2026
2485709
Merge branch 'main' into yp-add-fid-arg
yvonnep165 Jun 18, 2026
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
8 changes: 8 additions & 0 deletions etc/firebase-admin.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ 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 "FidMulticastMessage" needs to be exported by the entry point default-namespace.d.ts
export type FidMulticastMessage = FidMulticastMessage;
// 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 @@ -387,6 +391,8 @@ export namespace messaging {
// Warning: (ae-forgotten-export) The symbol "MessagingTopicManagementResponse" needs to be exported by the entry point default-namespace.d.ts
export type MessagingTopicManagementResponse = MessagingTopicManagementResponse;
// Warning: (ae-forgotten-export) The symbol "MulticastMessage" needs to be exported by the entry point default-namespace.d.ts
//
// @deprecated
export type MulticastMessage = MulticastMessage;
// Warning: (ae-forgotten-export) The symbol "Notification" needs to be exported by the entry point default-namespace.d.ts
export type Notification = Notification;
Expand All @@ -395,6 +401,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
21 changes: 17 additions & 4 deletions etc/firebase-admin.messaging.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,16 @@ export interface FcmOptions {
analyticsLabel?: string;
}

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

// @public
export interface FidMulticastMessage extends BaseMessage {
fids: string[];
}

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

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

// @public
export class Messaging {
Expand All @@ -196,7 +206,9 @@ export class Messaging {
enableLegacyHttpTransport(): void;
send(message: Message, dryRun?: boolean): Promise<string>;
sendEach(messages: Message[], dryRun?: boolean): Promise<BatchResponse>;
// @deprecated
sendEachForMulticast(message: MulticastMessage, dryRun?: boolean): Promise<BatchResponse>;
sendEachForMulticast(message: FidMulticastMessage, dryRun?: boolean): Promise<BatchResponse>;
subscribeToTopic(registrationTokenOrTokens: string | string[], topic: string): Promise<MessagingTopicManagementResponse>;
unsubscribeFromTopic(registrationTokenOrTokens: string | string[], topic: string): Promise<MessagingTopicManagementResponse>;
}
Expand Down Expand Up @@ -327,9 +339,10 @@ export interface MessagingTopicManagementResponse {
successCount: number;
}

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

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

// @public (undocumented)
// @public @deprecated (undocumented)
export interface TokenMessage extends BaseMessage {
// (undocumented)
token: string;
Expand Down
2 changes: 2 additions & 0 deletions src/messaging/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export {
CriticalSound,
ConditionMessage,
FcmOptions,
FidMessage,
FidMulticastMessage,
LightSettings,
Message,
MessagingTopicManagementResponse,
Expand Down
43 changes: 38 additions & 5 deletions src/messaging/messaging-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ export interface BaseMessage {
fcmOptions?: FcmOptions;
}

/**
* Interface representing a message that targets a Firebase Installation ID (FID).
*/
export interface FidMessage extends BaseMessage {
/**
* The Firebase Installation ID (FID) to which the message should be sent.
*/
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,18 +53,38 @@ 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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we mention that token is deprecated here as well?

in the BaseMessage type, and exactly one of fid, token (deprecated, use fid instead), topic or condition.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Added, Thanks!

*/
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.
* Payload for the `sendEachForMulticast` method.
*
* @deprecated Use {@link FidMulticastMessage} instead.
*/
export interface MulticastMessage extends BaseMessage {
/**
* A list of Firebase Installation IDs (FIDs) to target.
*/
fids?: string[];
/**
* A list of registration tokens to target.
*
* @deprecated Use `fids` in {@link FidMulticastMessage} instead.
*/
tokens: string[];
}

/**
* Payload for the `sendEachForMulticast` method containing only FIDs.
*/
export interface FidMulticastMessage extends BaseMessage {
/**
* A list of Firebase Installation IDs (FIDs) to target.
*/
fids: string[];
}
Comment thread
yvonnep165 marked this conversation as resolved.

/**
* A notification that can be included in {@link Message}.
*/
Expand Down Expand Up @@ -1001,7 +1034,7 @@ export interface MessagingTopicManagementResponse {

/**
* Interface representing the server response from the
* {@link Messaging.sendEach} and {@link Messaging.sendEachForMulticast} methods.
* {@link Messaging.sendEach} and `sendEachForMulticast` methods.
*/
export interface BatchResponse {

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
16 changes: 16 additions & 0 deletions src/messaging/messaging-namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import {
CriticalSound as TCriticalSound,
ConditionMessage as TConditionMessage,
FcmOptions as TFcmOptions,
FidMessage as TFidMessage,
FidMulticastMessage as TFidMulticastMessage,
LightSettings as TLightSettings,
Message as TMessage,
MessagingTopicManagementResponse as TMessagingTopicManagementResponse,
Expand Down Expand Up @@ -161,9 +163,16 @@ export namespace messaging {

/**
* Type alias to {@link firebase-admin.messaging#MulticastMessage}.
*
* @deprecated Use {@link firebase-admin.messaging#FidMulticastMessage} instead.
*/
export type MulticastMessage = TMulticastMessage;

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

/**
* Type alias to {@link firebase-admin.messaging#Notification}.
*/
Expand All @@ -174,8 +183,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
79 changes: 56 additions & 23 deletions src/messaging/messaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { FirebaseMessagingRequestHandler } from './messaging-api-request-interna

import {
BatchResponse,
FidMulticastMessage,
Message,
MessagingTopicManagementResponse,
MulticastMessage,
Expand Down Expand Up @@ -274,50 +275,82 @@ export class Messaging {
}

/**
* Sends the given multicast message to all the FCM registration tokens
* Sends the given multicast message to all the FCM registration tokens or fids
* specified in it.
*
* This method uses the {@link Messaging.sendEach} API under the hood to send the given
* message to all the target recipients. The responses list obtained from the
* return value corresponds to the order of tokens in the `MulticastMessage`.
* return value corresponds to the order of tokens/fids in the `MulticastMessage`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Maybe clarify that tokens take precedence if both are provided.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, added!

* An error from this method or a `BatchResponse` with all failures indicates a total
* failure, meaning that the messages in the list could be sent. Partial failures or
* failures are only indicated by a `BatchResponse` return value.
* failure, meaning that the messages in the list could not be sent. Partial failures
* are only indicated by a `BatchResponse` return value.
*
* @param message - A multicast message
* containing up to 500 tokens.
* @deprecated Use the overload accepting {@link FidMulticastMessage} instead.
*
* @param message - A multicast message containing up to 500 tokens and/or fids.
* @param dryRun - Whether to send the message in the dry-run
* (validation only) mode.
* @returns A Promise fulfilled with an object representing the result of the
* send operation.
*/
public sendEachForMulticast(message: MulticastMessage, dryRun?: boolean): Promise<BatchResponse> {
const copy: MulticastMessage = deepCopy(message);
public sendEachForMulticast(message: MulticastMessage, dryRun?: boolean): Promise<BatchResponse>;

/**
* Sends the given multicast message to all the FCM fids specified in it.
*
* This method uses the {@link Messaging.sendEach} API under the hood to send the given
* message to all the target recipients. The responses list obtained from the
* return value corresponds to the order of fids in the `FidMulticastMessage`.
* An error from this method or a `BatchResponse` with all failures indicates a total
* failure, meaning that the messages in the list could not be sent. Partial failures
* are only indicated by a `BatchResponse` return value.
*
* @param message - A multicast message containing up to 500 fids.
* @param dryRun - Whether to send the message in the dry-run (validation only) mode.
* @returns A Promise fulfilled with an object representing the result of the send operation.
*/
public sendEachForMulticast(message: FidMulticastMessage, dryRun?: boolean): Promise<BatchResponse>;

public sendEachForMulticast(
message: MulticastMessage | FidMulticastMessage,
dryRun?: boolean,
): Promise<BatchResponse> {
const copy: any = deepCopy(message);
if (!validator.isNonNullObject(copy)) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_ARGUMENT, 'MulticastMessage must be a non-null object');
}
if (!validator.isNonEmptyArray(copy.tokens)) {

const { tokens, fids, ...baseMessage } = copy;

const tokenList: string[] = tokens || [];
const fidList: string[] = fids || [];

if ('tokens' in copy && !validator.isArray(copy.tokens)) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_ARGUMENT, 'tokens must be a valid array');
}
if ('fids' in copy && !validator.isArray(copy.fids)) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_ARGUMENT, 'tokens must be a non-empty array');
MessagingClientErrorCode.INVALID_ARGUMENT, 'fids must be a valid array');
}
Comment thread
yvonnep165 marked this conversation as resolved.
if (copy.tokens.length > FCM_MAX_BATCH_SIZE) {
if (tokenList.length === 0 && fidList.length === 0) {
throw new FirebaseMessagingError(
MessagingClientErrorCode.INVALID_ARGUMENT, 'Either tokens or fids must be a non-empty array');
}

const totalLength = tokenList.length + fidList.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`);
`The total number of tokens and fids must not exceed ${FCM_MAX_BATCH_SIZE}.`);
}

const messages: Message[] = copy.tokens.map((token) => {
return {
token,
android: copy.android,
apns: copy.apns,
data: copy.data,
notification: copy.notification,
webpush: copy.webpush,
fcmOptions: copy.fcmOptions,
};
});
const messages: Message[] = [
...tokenList.map((token) => ({ ...baseMessage, token } as Message)),
...fidList.map((fid) => ({ ...baseMessage, fid } as Message)),
];

return this.sendEach(messages, dryRun);
}

Expand Down
Loading
Loading