UNPKG

5.68 kBJavaScriptView Raw
1/*! firebase-admin v12.0.0 */
2"use strict";
3/*!
4 * @license
5 * Copyright 2022 Google Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19Object.defineProperty(exports, "__esModule", { value: true });
20exports.EventarcApiClient = void 0;
21const validator = require("../utils/validator");
22const eventarc_utils_1 = require("./eventarc-utils");
23const api_request_1 = require("../utils/api-request");
24const utils = require("../utils");
25const error_1 = require("../utils/error");
26const EVENTARC_API = 'https://eventarcpublishing.googleapis.com/v1';
27const FIREBASE_VERSION_HEADER = {
28 'X-Firebase-Client': `fire-admin-node/${utils.getSdkVersion()}`,
29};
30const CHANNEL_NAME_REGEX = /^(projects\/([^/]+)\/)?locations\/([^/]+)\/channels\/([^/]+)$/;
31const DEFAULT_CHANNEL_REGION = 'us-central1';
32/**
33 * Class that facilitates sending requests to the Eventarc backend API.
34 *
35 * @internal
36 */
37class EventarcApiClient {
38 constructor(app, channel) {
39 this.app = app;
40 this.channel = channel;
41 if (!validator.isNonNullObject(app) || !('options' in app)) {
42 throw new eventarc_utils_1.FirebaseEventarcError('invalid-argument', 'First argument passed to Channel() must be a valid Eventarc service instance.');
43 }
44 this.httpClient = new api_request_1.AuthorizedHttpClient(app);
45 this.resolvedChannelName = this.resolveChannelName(channel.name);
46 }
47 getProjectId() {
48 if (this.projectId) {
49 return Promise.resolve(this.projectId);
50 }
51 return utils.findProjectId(this.app)
52 .then((projectId) => {
53 if (!validator.isNonEmptyString(projectId)) {
54 throw new eventarc_utils_1.FirebaseEventarcError('unknown-error', 'Failed to determine project ID. Initialize the '
55 + 'SDK with service account credentials or set project ID as an app option. '
56 + 'Alternatively, set the GOOGLE_CLOUD_PROJECT environment variable.');
57 }
58 this.projectId = projectId;
59 return projectId;
60 });
61 }
62 /**
63 * Publishes provided events to this channel. If channel was created with `allowedEventsTypes` and event type
64 * is not on that list, the event is ignored.
65 *
66 * The following CloudEvent fields are auto-populated if not set:
67 * * specversion - `1.0`
68 * * id - uuidv4()
69 * * source - populated with `process.env.EVENTARC_CLOUD_EVENT_SOURCE` and
70 * if not set an error is thrown.
71 *
72 * @param events - CloudEvent to publish to the channel.
73 */
74 async publish(events) {
75 if (!Array.isArray(events)) {
76 events = [events];
77 }
78 return this.publishToEventarcApi(await this.resolvedChannelName, events
79 .filter(e => typeof this.channel.allowedEventTypes === 'undefined' ||
80 this.channel.allowedEventTypes.includes(e.type))
81 .map(eventarc_utils_1.toCloudEventProtoFormat));
82 }
83 async publishToEventarcApi(channel, events) {
84 if (events.length === 0) {
85 return;
86 }
87 const request = {
88 method: 'POST',
89 url: `${this.getEventarcHost()}/${channel}:publishEvents`,
90 data: JSON.stringify({ events }),
91 };
92 return this.sendRequest(request);
93 }
94 sendRequest(request) {
95 request.headers = FIREBASE_VERSION_HEADER;
96 return this.httpClient.send(request)
97 .then(() => undefined)
98 .catch((err) => {
99 throw this.toFirebaseError(err);
100 });
101 }
102 toFirebaseError(err) {
103 if (err instanceof error_1.PrefixedFirebaseError) {
104 return err;
105 }
106 const response = err.response;
107 return new eventarc_utils_1.FirebaseEventarcError('unknown-error', `Unexpected response with status: ${response.status} and body: ${response.text}`);
108 }
109 resolveChannelName(name) {
110 if (!name.includes('/')) {
111 const location = DEFAULT_CHANNEL_REGION;
112 const channelId = name;
113 return this.resolveChannelNameProjectId(location, channelId);
114 }
115 else {
116 const match = CHANNEL_NAME_REGEX.exec(name);
117 if (match === null || match.length < 4) {
118 throw new eventarc_utils_1.FirebaseEventarcError('invalid-argument', 'Invalid channel name format.');
119 }
120 const projectId = match[2];
121 const location = match[3];
122 const channelId = match[4];
123 if (validator.isNonEmptyString(projectId)) {
124 return Promise.resolve(`projects/${projectId}/locations/${location}/channels/${channelId}`);
125 }
126 else {
127 return this.resolveChannelNameProjectId(location, channelId);
128 }
129 }
130 }
131 async resolveChannelNameProjectId(location, channelId) {
132 const projectId = await this.getProjectId();
133 return `projects/${projectId}/locations/${location}/channels/${channelId}`;
134 }
135 getEventarcHost() {
136 return process.env.CLOUD_EVENTARC_EMULATOR_HOST ?? EVENTARC_API;
137 }
138}
139exports.EventarcApiClient = EventarcApiClient;