Skip to content

Commit a6f9851

Browse files
authored
Finish refactor of HTTPS code (#917)
* Moves most of https pacakge into /common/providers/https. The actual encoding/decoding/error logic etc. of callable functions will stay the same between v1 and v2, so they should be in a /common file. The rest of /v1 is about trigger options, cors, etc. onCall's CORS options are part of the v1 namespace because v2 adds a "cors" option to HttpsOptions. In the v2 API, we will default to `"cors": true`, but a customer could say `"cors": "my.firebase.app"` and we will respsect it. I wish there was a way to make this diff not so noisy. Most of this is cut & paste. * Finish refactor of HTTPS code Builds upon #915 Creates the first bits of v2/ setGlobalOptions allows customers to set options that will be preserved across any function written in the v2 API. v2/https has webhook and callable function support. In addition to previous features, customers can now specifiy `cors` as a shorthand for using CORS middleware. We will probably eventually support scheduled functions in the HTTPS namespace but that will have to wait for another day. * Export logger * run formatter * Revert pacakge-lock.json
1 parent 641cae8 commit a6f9851

File tree

7 files changed

+549
-2
lines changed

7 files changed

+549
-2
lines changed

package.json

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,29 @@
2929
"./logger": "./lib/logger/index.js",
3030
"./logger/compat": "./lib/logger/compat.js",
3131
"./lib/logger": "./lib/logger/index.js",
32-
"./lib/logger/compat": "./lib/logger/compat.js"
32+
"./lib/logger/compat": "./lib/logger/compat.js",
33+
"./v2": "./lib/v2/index.js",
34+
"./v2/options": "./lib/v2/options.js",
35+
"./v2/https": "./lib/v2/providers/https.js"
36+
},
37+
"typesVersions": {
38+
"*": {
39+
"logger/*": [
40+
"lib/logger/*"
41+
],
42+
"v1": [
43+
"lib/v1"
44+
],
45+
"v2": [
46+
"lib/v2"
47+
],
48+
"v2/options": [
49+
"lib/v2/options"
50+
],
51+
"v2/https": [
52+
"lib/v2/providers/https"
53+
]
54+
}
3355
},
3456
"publishConfig": {
3557
"registry": "https://wombat-dressing-room.appspot.com"

src/index.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,23 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2021 Firebase
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
123
export * from './v1';

src/v2/base.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2021 Firebase
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
/** @internal */
24+
export interface TriggerAnnotation {
25+
availableMemoryMb?: number;
26+
eventTrigger?: {
27+
eventType: string;
28+
resource: string;
29+
service: string;
30+
};
31+
failurePolicy?: { retry: boolean };
32+
httpsTrigger?: {};
33+
labels?: { [key: string]: string };
34+
regions?: string[];
35+
timeout?: string;
36+
vpcConnector?: string;
37+
vpcConnectorEgressSettings?: string;
38+
serviceAccountEmail?: string;
39+
ingressSettings?: string;
40+
41+
// TODO: schedule
42+
}

src/v2/index.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2021 Firebase
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
import * as https from './providers/https';
24+
import * as logger from '../logger';
25+
26+
export { https, logger };
27+
28+
export { setGlobalOptions, GlobalOptions } from './options';

src/v2/options.ts

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2021 Firebase
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
import {
24+
durationFromSeconds,
25+
serviceAccountFromShorthand,
26+
} from '../common/encoding';
27+
import * as logger from '../logger';
28+
import { TriggerAnnotation } from './base';
29+
import { copyIfPresent, convertIfPresent } from '../common/encoding';
30+
31+
/**
32+
* List of all regions supported by Cloud Functions v2
33+
*/
34+
export const SUPPORTED_REGIONS = ['us-west1'] as const;
35+
36+
/**
37+
* A region known to be supported by CloudFunctions v2
38+
*/
39+
export type SupportedRegion = typeof SUPPORTED_REGIONS[number];
40+
41+
/**
42+
* Cloud Functions v2 min timeout value.
43+
*/
44+
export const MIN_TIMEOUT_SECONDS = 1;
45+
46+
/**
47+
* Cloud Functions v2 max timeout value for event handlers.
48+
*/
49+
export const MAX_EVENT_TIMEOUT_SECONDS = 540;
50+
51+
/**
52+
* Cloud Functions v2 max timeout for HTTPS functions.
53+
*/
54+
export const MAX_HTTPS_TIMEOUT_SECONDS = 36_000;
55+
56+
/**
57+
* Maximum number of requests to serve on a single instance.
58+
*/
59+
export const MAX_CONCURRENCY = 1_000;
60+
61+
/**
62+
* List of available memory options supported by Cloud Functions.
63+
*/
64+
export const SUPPORTED_MEMORY_OPTIONS = [
65+
'256MB',
66+
'512MB',
67+
'1GB',
68+
'2GB',
69+
'4GB',
70+
'8GB',
71+
] as const;
72+
73+
const MemoryOptionToMB: Record<MemoryOption, number> = {
74+
'256MB': 256,
75+
'512MB': 512,
76+
'1GB': 1024,
77+
'2GB': 2048,
78+
'4GB': 4096,
79+
'8GB': 8192,
80+
};
81+
82+
/**
83+
* A supported memory option.
84+
*/
85+
export type MemoryOption = typeof SUPPORTED_MEMORY_OPTIONS[number];
86+
87+
/**
88+
* List of available options for VpcConnectorEgressSettings.
89+
*/
90+
export const SUPPORTED_VPC_EGRESS_SETTINGS = [
91+
'PRIVATE_RANGES_ONLY',
92+
'ALL_TRAFFIC',
93+
] as const;
94+
95+
/**
96+
* A valid VPC Egress setting.
97+
*/
98+
export type VpcEgressSetting = typeof SUPPORTED_VPC_EGRESS_SETTINGS[number];
99+
100+
/**
101+
* List of available options for IngressSettings.
102+
*/
103+
export const SUPPORTED_INGRESS_SETTINGS = [
104+
'ALLOW_ALL',
105+
'ALLOW_INTERNAL_ONLY',
106+
'ALLOW_INTERNAL_AND_GCLB',
107+
] as const;
108+
109+
export type IngressSetting = typeof SUPPORTED_INGRESS_SETTINGS[number];
110+
111+
/**
112+
* GlobalOptions are options that can be set across an entire project.
113+
* These options are common to HTTPS and Event handling functions.
114+
*/
115+
export interface GlobalOptions {
116+
/**
117+
* Region where functions should be deployed.
118+
* HTTP functions can override and specify more than one region.
119+
*/
120+
region?: SupportedRegion | string;
121+
122+
/**
123+
* Amount of memory to allocate to a function.
124+
* A value of null restores the defaults of 256MB.
125+
*/
126+
memory?: MemoryOption | null;
127+
128+
/**
129+
* Timeout for the function in sections, possible values are 0 to 540.
130+
* HTTPS functions can specify a higher timeout.
131+
* A value of null restores the default of 60s
132+
*/
133+
timeoutSeconds?: number | null;
134+
135+
/**
136+
* Min number of actual instances to be running at a given time.
137+
* Instances will be billed for memory allocation and 10% of CPU allocation
138+
* while idle.
139+
* A value of null restores the default min instances.
140+
*/
141+
minInstances?: number | null;
142+
143+
/**
144+
* Max number of instances to be running in parallel.
145+
* A value of null restores the default max instances.
146+
*/
147+
maxInstances?: number | null;
148+
149+
/**
150+
* Number of requests a function can serve at once.
151+
* Can only be applied to functions running on Cloud Functions v2.
152+
* A value of null restores the default concurrency.
153+
*/
154+
concurrency?: number | null;
155+
/**
156+
* Connect cloud function to specified VPC connector.
157+
* A value of null removes the VPC connector
158+
*/
159+
vpcConnector?: string | null;
160+
161+
/**
162+
* Egress settings for VPC connector.
163+
* A value of null turns off VPC connector egress settings
164+
*/
165+
vpcConnectorEgressSettings?: VpcEgressSetting | null;
166+
167+
/**
168+
* Specific service account for the function to run as.
169+
* A value of null restores the default service account.
170+
*/
171+
serviceAccount?: string | null;
172+
173+
/**
174+
* Ingress settings which control where this function can be called from.
175+
* A value of null turns off ingress settings.
176+
*/
177+
ingressSettings?: IngressSetting | null;
178+
179+
/**
180+
* User labels to set on the function.
181+
*/
182+
labels?: Record<string, string>;
183+
}
184+
185+
let globalOptions: GlobalOptions | undefined;
186+
187+
/**
188+
* Sets default options for all functions written using the v2 SDK.
189+
* @param options Options to set as default
190+
*/
191+
export function setGlobalOptions(options: GlobalOptions) {
192+
if (globalOptions) {
193+
logger.warn('Calling setGlobalOptions twice leads to undefined behavior');
194+
}
195+
globalOptions = options;
196+
}
197+
198+
/**
199+
* Get the currently set default options.
200+
* Used only for trigger generation.
201+
* @internal
202+
*/
203+
export function getGlobalOptions(): GlobalOptions {
204+
return globalOptions || {};
205+
}
206+
207+
/**
208+
* Options that can be set on an individual event-handling Cloud Function.
209+
*/
210+
export interface EventHandlerOptions extends GlobalOptions {
211+
retry?: boolean;
212+
}
213+
214+
/**
215+
* Apply GlobalOptions to trigger definitions.
216+
* @internal
217+
*/
218+
export function optionsToTriggerAnnotations(
219+
opts: GlobalOptions | EventHandlerOptions
220+
): TriggerAnnotation {
221+
const annotation: TriggerAnnotation = {};
222+
copyIfPresent(
223+
annotation,
224+
opts,
225+
'ingressSettings',
226+
'labels',
227+
'vpcConnector',
228+
'vpcConnectorEgressSettings'
229+
);
230+
convertIfPresent(
231+
annotation,
232+
opts,
233+
'availableMemoryMb',
234+
'memory',
235+
(mem: MemoryOption) => {
236+
return MemoryOptionToMB[mem];
237+
}
238+
);
239+
convertIfPresent(annotation, opts, 'regions', 'region', (region) => {
240+
if (typeof 'region' === 'string') {
241+
return [region];
242+
}
243+
return region;
244+
});
245+
convertIfPresent(
246+
annotation,
247+
opts,
248+
'serviceAccountEmail',
249+
'serviceAccount',
250+
serviceAccountFromShorthand
251+
);
252+
convertIfPresent(
253+
annotation,
254+
opts,
255+
'timeout',
256+
'timeoutSeconds',
257+
durationFromSeconds
258+
);
259+
convertIfPresent(
260+
annotation,
261+
(opts as any) as EventHandlerOptions,
262+
'failurePolicy',
263+
'retry',
264+
(retry: boolean) => {
265+
return retry ? { retry: true } : null;
266+
}
267+
);
268+
269+
return annotation;
270+
}

0 commit comments

Comments
 (0)