Skip to content

Commit fa623e0

Browse files
committed
Pass fetch implementation to functions service
1 parent bd58a1f commit fa623e0

File tree

13 files changed

+74
-78
lines changed

13 files changed

+74
-78
lines changed

packages-exp/functions-exp/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@
5555
"@firebase/messaging-types": "0.5.0",
5656
"@firebase/util": "0.3.2",
5757
"node-fetch": "2.6.1",
58-
"tslib": "^1.11.1",
59-
"whatwg-fetch": "3.4.1"
58+
"tslib": "^1.11.1"
6059
},
6160
"nyc": {
6261
"extension": [

packages-exp/functions-exp/src/config.ts

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,31 @@ import { FUNCTIONS_TYPE } from './constants';
2727

2828
export const DEFAULT_REGION = 'us-central1';
2929

30-
const factory: InstanceFactory<'functions'> = (
31-
container: ComponentContainer,
32-
region?: string
33-
) => {
34-
// Dependencies
35-
const app = container.getProvider('app-exp').getImmediate();
36-
const authProvider = container.getProvider('auth-internal');
37-
const messagingProvider = container.getProvider('messaging');
38-
39-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
40-
return new FunctionsService(app, authProvider, messagingProvider, region);
41-
};
42-
43-
export function registerFunctions(): void {
30+
export function registerFunctions(fetchImpl: typeof fetch): void {
4431
const namespaceExports = {
4532
// no-inline
4633
Functions: FunctionsService
4734
};
4835

36+
const factory: InstanceFactory<'functions'> = (
37+
container: ComponentContainer,
38+
region?: string
39+
) => {
40+
// Dependencies
41+
const app = container.getProvider('app-exp').getImmediate();
42+
const authProvider = container.getProvider('auth-internal');
43+
const messagingProvider = container.getProvider('messaging');
44+
45+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
46+
return new FunctionsService(
47+
app,
48+
authProvider,
49+
messagingProvider,
50+
region,
51+
fetchImpl
52+
);
53+
};
54+
4955
_registerComponent(
5056
new Component(FUNCTIONS_TYPE, factory, ComponentType.PUBLIC)
5157
.setServiceProps(namespaceExports)

packages-exp/functions-exp/src/index.node.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,12 @@
1616
*/
1717
import { registerVersion } from '@firebase/app-exp';
1818
import { registerFunctions } from './config';
19-
import 'whatwg-fetch';
2019
import nodeFetch from 'node-fetch';
2120

2221
import { name, version } from '../package.json';
2322

24-
/**
25-
* Patch global object with node-fetch. whatwg-fetch polyfill patches other global
26-
* fetch types such as Headers. Then we override the implemenation of `fetch()`
27-
* itself with node-fetch.
28-
* https://github.com/node-fetch/node-fetch#loading-and-configuring-the-module
29-
* node-fetch type deviates somewhat from fetch spec:
30-
* https://github.com/apollographql/apollo-link/issues/513#issuecomment-548219023
31-
*/
32-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
33-
(global as any).fetch = (nodeFetch as unknown) as typeof fetch;
34-
3523
export * from './api';
3624

37-
registerFunctions();
25+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
26+
registerFunctions(nodeFetch as any);
3827
registerVersion(name, version, 'node');

packages-exp/functions-exp/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ import { name, version } from '../package.json';
2121

2222
export * from './api';
2323

24-
registerFunctions();
24+
registerFunctions(fetch);
2525
registerVersion(name, version);

packages-exp/functions-exp/src/service.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ export class FunctionsService implements _FirebaseService {
8484
readonly app: FirebaseApp,
8585
authProvider: Provider<FirebaseAuthInternalName>,
8686
messagingProvider: Provider<FirebaseMessagingName>,
87-
readonly region: string = DEFAULT_REGION
87+
readonly region: string = DEFAULT_REGION,
88+
readonly fetchImpl: typeof fetch
8889
) {
8990
this.contextProvider = new ContextProvider(authProvider, messagingProvider);
9091
// Cancels all ongoing requests when resolved.
@@ -155,13 +156,14 @@ export function httpsCallable(
155156
async function postJSON(
156157
url: string,
157158
body: unknown,
158-
headers: Headers
159+
headers: { [key: string]: string },
160+
fetchImpl: typeof fetch
159161
): Promise<HttpResponse> {
160-
headers.append('Content-Type', 'application/json');
162+
headers['Content-Type'] = 'application/json';
161163

162164
let response: Response;
163165
try {
164-
response = await fetch(url, {
166+
response = await fetchImpl(url, {
165167
method: 'POST',
166168
body: JSON.stringify(body),
167169
headers
@@ -206,20 +208,20 @@ async function call(
206208
const body = { data };
207209

208210
// Add a header for the authToken.
209-
const headers = new Headers();
211+
const headers: { [key: string]: string } = {};
210212
const context = await functionsInstance.contextProvider.getContext();
211213
if (context.authToken) {
212-
headers.append('Authorization', 'Bearer ' + context.authToken);
214+
headers['Authorization'] = 'Bearer ' + context.authToken;
213215
}
214216
if (context.messagingToken) {
215-
headers.append('Firebase-Instance-ID-Token', context.messagingToken);
217+
headers['Firebase-Instance-ID-Token'] = context.messagingToken;
216218
}
217219

218220
// Default timeout to 70s, but let the options override it.
219221
const timeout = options.timeout || 70000;
220222

221223
const response = await Promise.race([
222-
postJSON(url, body, headers),
224+
postJSON(url, body, headers, functionsInstance.fetchImpl),
223225
failAfter(timeout),
224226
functionsInstance.cancelAllRequests
225227
]);

packages-exp/functions-exp/test/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { FirebaseAuthInternalName } from '@firebase/auth-interop-types';
2121
import { FirebaseMessagingName } from '@firebase/messaging-types';
2222
import { FunctionsService } from '../src/service';
2323
import { useFunctionsEmulator } from '../src/api';
24+
import nodeFetch from 'node-fetch';
2425

2526
export function makeFakeApp(options: FirebaseOptions = {}): FirebaseApp {
2627
options = {
@@ -52,11 +53,14 @@ export function createTestService(
5253
new ComponentContainer('test')
5354
)
5455
): FunctionsService {
56+
const fetchImpl: typeof fetch =
57+
typeof window !== 'undefined' ? fetch.bind(window) : (nodeFetch as any);
5558
const functions = new FunctionsService(
5659
app,
5760
authProvider,
5861
messagingProvider,
59-
region
62+
region,
63+
fetchImpl
6064
);
6165
const useEmulator = !!process.env.FIREBASE_FUNCTIONS_EMULATOR_ORIGIN;
6266
if (useEmulator) {

packages/functions/index.node.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,10 @@
1717
import firebase from '@firebase/app';
1818
import { _FirebaseNamespace } from '@firebase/app-types/private';
1919
import { registerFunctions } from './src/config';
20-
import 'whatwg-fetch';
2120
import nodeFetch from 'node-fetch';
2221

2322
import { name, version } from './package.json';
2423

25-
/**
26-
* Patch global object with node-fetch. whatwg-fetch polyfill patches other global
27-
* fetch types such as Headers. Then we override the implemenation of `fetch()`
28-
* itself with node-fetch.
29-
* https://github.com/node-fetch/node-fetch#loading-and-configuring-the-module
30-
* node-fetch type deviates somewhat from fetch spec:
31-
* https://github.com/apollographql/apollo-link/issues/513#issuecomment-548219023
32-
*/
3324
// eslint-disable-next-line @typescript-eslint/no-explicit-any
34-
(global as any).fetch = (nodeFetch as unknown) as typeof fetch;
35-
36-
registerFunctions(firebase as _FirebaseNamespace);
25+
registerFunctions(firebase as _FirebaseNamespace, nodeFetch as any);
3726
firebase.registerVersion(name, version, 'node');

packages/functions/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { registerFunctions } from './src/config';
2121

2222
import { name, version } from './package.json';
2323

24-
registerFunctions(firebase as _FirebaseNamespace);
24+
registerFunctions(firebase as _FirebaseNamespace, fetch);
2525
firebase.registerVersion(name, version);
2626

2727
declare module '@firebase/app-types' {

packages/functions/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@
5151
"@firebase/functions-types": "0.3.17",
5252
"@firebase/messaging-types": "0.5.0",
5353
"node-fetch": "2.6.1",
54-
"tslib": "^1.11.1",
55-
"whatwg-fetch": "3.4.1"
54+
"tslib": "^1.11.1"
5655
},
5756
"nyc": {
5857
"extension": [

packages/functions/src/api/service.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ export class Service implements FirebaseFunctions, FirebaseService {
9696
private app_: FirebaseApp,
9797
authProvider: Provider<FirebaseAuthInternalName>,
9898
messagingProvider: Provider<FirebaseMessagingName>,
99-
private region_: string = 'us-central1'
99+
private region_: string = 'us-central1',
100+
readonly fetchImpl: typeof fetch
100101
) {
101102
this.contextProvider = new ContextProvider(authProvider, messagingProvider);
102103
// Cancels all ongoing requests when resolved.
@@ -162,13 +163,13 @@ export class Service implements FirebaseFunctions, FirebaseService {
162163
private async postJSON(
163164
url: string,
164165
body: {},
165-
headers: Headers
166+
headers: { [key: string]: string }
166167
): Promise<HttpResponse> {
167-
headers.append('Content-Type', 'application/json');
168+
headers['Content-Type'] = 'application/json';
168169

169170
let response: Response;
170171
try {
171-
response = await fetch(url, {
172+
response = await this.fetchImpl(url, {
172173
method: 'POST',
173174
body: JSON.stringify(body),
174175
headers
@@ -212,13 +213,13 @@ export class Service implements FirebaseFunctions, FirebaseService {
212213
const body = { data };
213214

214215
// Add a header for the authToken.
215-
const headers = new Headers();
216+
const headers: { [key: string]: string } = {};
216217
const context = await this.contextProvider.getContext();
217218
if (context.authToken) {
218-
headers.append('Authorization', 'Bearer ' + context.authToken);
219+
headers['Authorization'] = 'Bearer ' + context.authToken;
219220
}
220221
if (context.instanceIdToken) {
221-
headers.append('Firebase-Instance-ID-Token', context.instanceIdToken);
222+
headers['Firebase-Instance-ID-Token'] = context.instanceIdToken;
222223
}
223224

224225
// Default timeout to 70s, but let the options override it.

packages/functions/src/config.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,24 @@ import { _FirebaseNamespace } from '@firebase/app-types/private';
2828
*/
2929
const FUNCTIONS_TYPE = 'functions';
3030

31-
function factory(container: ComponentContainer, region?: string): Service {
32-
// Dependencies
33-
const app = container.getProvider('app').getImmediate();
34-
const authProvider = container.getProvider('auth-internal');
35-
const messagingProvider = container.getProvider('messaging');
36-
37-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
38-
return new Service(app, authProvider, messagingProvider, region);
39-
}
40-
41-
export function registerFunctions(instance: _FirebaseNamespace): void {
31+
export function registerFunctions(
32+
instance: _FirebaseNamespace,
33+
fetchImpl: typeof fetch
34+
): void {
4235
const namespaceExports = {
4336
// no-inline
4437
Functions: Service
4538
};
39+
40+
function factory(container: ComponentContainer, region?: string): Service {
41+
// Dependencies
42+
const app = container.getProvider('app').getImmediate();
43+
const authProvider = container.getProvider('auth-internal');
44+
const messagingProvider = container.getProvider('messaging');
45+
46+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
47+
return new Service(app, authProvider, messagingProvider, region, fetchImpl);
48+
}
4649
instance.INTERNAL.registerComponent(
4750
new Component(FUNCTIONS_TYPE, factory, ComponentType.PUBLIC)
4851
.setServiceProps(namespaceExports)

packages/functions/test/utils.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { Provider, ComponentContainer } from '@firebase/component';
2020
import { FirebaseAuthInternalName } from '@firebase/auth-interop-types';
2121
import { FirebaseMessagingName } from '@firebase/messaging-types';
2222
import { Service } from '../src/api/service';
23+
import nodeFetch from 'node-fetch';
2324

2425
export function makeFakeApp(options: FirebaseOptions = {}): FirebaseApp {
2526
options = {
@@ -52,7 +53,15 @@ export function createTestService(
5253
new ComponentContainer('test')
5354
)
5455
): Service {
55-
const functions = new Service(app, authProvider, messagingProvider, region);
56+
const fetchImpl: typeof fetch =
57+
typeof window !== 'undefined' ? fetch.bind(window) : (nodeFetch as any);
58+
const functions = new Service(
59+
app,
60+
authProvider,
61+
messagingProvider,
62+
region,
63+
fetchImpl
64+
);
5665
const useEmulator = !!process.env.FIREBASE_FUNCTIONS_EMULATOR_ORIGIN;
5766
if (useEmulator) {
5867
functions.useFunctionsEmulator(

yarn.lock

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15666,11 +15666,6 @@ [email protected]:
1566615666
resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f"
1566715667
integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==
1566815668

15669-
15670-
version "3.4.1"
15671-
resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz#e5f871572d6879663fa5674c8f833f15a8425ab3"
15672-
integrity sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ==
15673-
1567415669
whatwg-mimetype@^2.3.0:
1567515670
version "2.3.0"
1567615671
resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"

0 commit comments

Comments
 (0)