Skip to content

Commit c32db65

Browse files
authored
Added eventarc onCustomEventPublished API (#1061)
1 parent 6fac2f0 commit c32db65

File tree

5 files changed

+309
-2
lines changed

5 files changed

+309
-2
lines changed

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@
6363
"./v2/alerts": "./lib/v2/providers/alerts/index.js",
6464
"./v2/alerts/appDistribution": "./lib/v2/providers/alerts/appDistribution.js",
6565
"./v2/alerts/billing": "./lib/v2/providers/alerts/billing.js",
66-
"./v2/alerts/crashlytics": "./lib/v2/providers/alerts/crashlytics.js"
66+
"./v2/alerts/crashlytics": "./lib/v2/providers/alerts/crashlytics.js",
67+
"./v2/eventarc": "./lib/v2/providers/eventarc.js"
6768
},
6869
"typesVersions": {
6970
"*": {
@@ -124,6 +125,9 @@
124125
"v2/base": [
125126
"lib/v2/base"
126127
],
128+
"v2/eventarc": [
129+
"lib/v2/providers/eventarc"
130+
],
127131
"v2/options": [
128132
"lib/v2/options"
129133
],

spec/v2/providers/eventarc.spec.ts

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2022 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 { expect } from 'chai';
24+
import * as options from '../../../src/v2/options';
25+
import * as eventarc from '../../../src/v2/providers/eventarc';
26+
import { FULL_OPTIONS } from './fixtures';
27+
28+
const ENDPOINT_EVENT_TRIGGER = {
29+
eventType: 'event-type',
30+
retry: false,
31+
eventFilters: {},
32+
};
33+
34+
describe('v2/eventarc', () => {
35+
describe('onCustomEventPublished', () => {
36+
beforeEach(() => {
37+
process.env.GCLOUD_PROJECT = 'aProject';
38+
});
39+
40+
afterEach(() => {
41+
options.setGlobalOptions({});
42+
delete process.env.GCLOUD_PROJECT;
43+
});
44+
45+
it('should create a minimal trigger/endpoint with default channel', () => {
46+
const result = eventarc.onCustomEventPublished('event-type', () => 42);
47+
48+
expect(result.__endpoint).to.deep.equal({
49+
platform: 'gcfv2',
50+
labels: {},
51+
eventTrigger: {
52+
...ENDPOINT_EVENT_TRIGGER,
53+
channel: 'locations/us-central1/channels/firebase',
54+
},
55+
});
56+
});
57+
58+
it('should create a minimal trigger/endpoint with opts', () => {
59+
const result = eventarc.onCustomEventPublished(
60+
{ eventType: 'event-type', region: 'us-west1' },
61+
() => 42
62+
);
63+
64+
expect(result.__endpoint).to.deep.equal({
65+
platform: 'gcfv2',
66+
labels: {},
67+
eventTrigger: {
68+
...ENDPOINT_EVENT_TRIGGER,
69+
channel: 'locations/us-central1/channels/firebase',
70+
},
71+
region: ['us-west1'],
72+
});
73+
});
74+
75+
it('should create a minimal trigger with channel with opts', () => {
76+
const result = eventarc.onCustomEventPublished(
77+
{
78+
eventType: 'event-type',
79+
channel: 'locations/us-west1/channels/my-channel',
80+
filters: { foo: 'bar' },
81+
},
82+
() => 42
83+
);
84+
85+
expect(result.__endpoint).to.deep.equal({
86+
platform: 'gcfv2',
87+
labels: {},
88+
eventTrigger: {
89+
...ENDPOINT_EVENT_TRIGGER,
90+
channel: 'locations/us-west1/channels/my-channel',
91+
eventFilters: {
92+
foo: 'bar',
93+
},
94+
},
95+
});
96+
});
97+
98+
it('should create a complex trigger/endpoint with appropriate values', () => {
99+
const result = eventarc.onCustomEventPublished(
100+
{
101+
...FULL_OPTIONS,
102+
eventType: 'event-type',
103+
channel: 'locations/us-west1/channels/my-channel',
104+
},
105+
() => 42
106+
);
107+
108+
expect(result.__endpoint).to.deep.equal({
109+
platform: 'gcfv2',
110+
region: ['us-west1'],
111+
availableMemoryMb: 512,
112+
timeoutSeconds: 60,
113+
minInstances: 1,
114+
maxInstances: 3,
115+
concurrency: 20,
116+
vpc: {
117+
connector: 'aConnector',
118+
egressSettings: 'ALL_TRAFFIC',
119+
},
120+
serviceAccountEmail: 'root@',
121+
ingressSettings: 'ALLOW_ALL',
122+
labels: {
123+
hello: 'world',
124+
},
125+
eventTrigger: {
126+
...ENDPOINT_EVENT_TRIGGER,
127+
channel: 'locations/us-west1/channels/my-channel',
128+
},
129+
});
130+
});
131+
132+
it('should merge options and globalOptions', () => {
133+
options.setGlobalOptions({
134+
concurrency: 20,
135+
region: 'europe-west1',
136+
minInstances: 1,
137+
});
138+
139+
const result = eventarc.onCustomEventPublished(
140+
{
141+
eventType: 'event-type',
142+
channel: 'locations/us-west1/channels/my-channel',
143+
region: 'us-west1',
144+
minInstances: 3,
145+
},
146+
() => 42
147+
);
148+
149+
expect(result.__endpoint).to.deep.equal({
150+
platform: 'gcfv2',
151+
concurrency: 20,
152+
minInstances: 3,
153+
region: ['us-west1'],
154+
labels: {},
155+
eventTrigger: {
156+
...ENDPOINT_EVENT_TRIGGER,
157+
channel: 'locations/us-west1/channels/my-channel',
158+
},
159+
});
160+
});
161+
});
162+
});

src/v2/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ import * as https from './providers/https';
2727
import * as pubsub from './providers/pubsub';
2828
import * as storage from './providers/storage';
2929
import * as tasks from './providers/tasks';
30+
import * as eventarc from './providers/eventarc';
3031

31-
export { alerts, https, pubsub, storage, logger, params, tasks };
32+
export { alerts, https, pubsub, storage, logger, params, tasks, eventarc };
3233

3334
export { setGlobalOptions, GlobalOptions } from './options';
3435

src/v2/providers/eventarc.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2022 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 options from '../options';
24+
import { CloudEvent, CloudFunction } from '../core';
25+
import { copyIfPresent, convertIfPresent } from '../../common/encoding';
26+
import { ManifestEndpoint } from '../../runtime/manifest';
27+
28+
/** Options that can be set on an Eventarc trigger. */
29+
export interface EventarcTriggerOptions extends options.EventHandlerOptions {
30+
/**
31+
* Type of the event.
32+
*/
33+
eventType: string;
34+
35+
/**
36+
* ID of the channel. Can be either:
37+
* * fully qualified channel resource name:
38+
* `projects/{project}/locations/{location}/channels/{channel-id}`
39+
* * partial resource name with location and channel ID, in which case
40+
* the runtime project ID of the function will be used:
41+
* `locations/{location}/channels/{channel-id}`
42+
* * partial channel ID, in which case the runtime project ID of the
43+
* function and `us-central1` as location will be used:
44+
* `{channel-id}`
45+
*
46+
* If not specified, the default Firebase channel will be used:
47+
* `projects/{project}/locations/us-central1/channels/firebase`
48+
*/
49+
channel?: string;
50+
51+
/**
52+
* Eventarc event exact match filter.
53+
*/
54+
filters?: Record<string, string>;
55+
}
56+
57+
export type CloudEventHandler = (event: CloudEvent<any>) => any | Promise<any>;
58+
59+
/** Handle an Eventarc event published on the default channel. */
60+
export function onCustomEventPublished<T = any>(
61+
eventType: string,
62+
handler: CloudEventHandler
63+
): CloudFunction<CloudEvent<T>>;
64+
65+
export function onCustomEventPublished<T = any>(
66+
opts: EventarcTriggerOptions,
67+
handler: CloudEventHandler
68+
): CloudFunction<CloudEvent<T>>;
69+
70+
export function onCustomEventPublished<T = any>(
71+
eventTypeOrOpts: string | EventarcTriggerOptions,
72+
handler: CloudEventHandler
73+
): CloudFunction<CloudEvent<T>> {
74+
let opts: EventarcTriggerOptions;
75+
if (typeof eventTypeOrOpts === 'string') {
76+
opts = {
77+
eventType: eventTypeOrOpts as string,
78+
};
79+
} else if (typeof eventTypeOrOpts === 'object') {
80+
opts = eventTypeOrOpts as EventarcTriggerOptions;
81+
}
82+
const func = (raw: CloudEvent<unknown>) => {
83+
return handler(raw as CloudEvent<T>);
84+
};
85+
86+
func.run = handler;
87+
88+
const channel = opts.channel ?? 'locations/us-central1/channels/firebase';
89+
90+
const baseOpts = options.optionsToEndpoint(options.getGlobalOptions());
91+
const specificOpts = options.optionsToEndpoint(opts);
92+
93+
const endpoint: ManifestEndpoint = {
94+
platform: 'gcfv2',
95+
...baseOpts,
96+
...specificOpts,
97+
labels: {
98+
...baseOpts?.labels,
99+
...specificOpts?.labels,
100+
},
101+
eventTrigger: {
102+
eventType: opts.eventType,
103+
eventFilters: {},
104+
retry: false,
105+
channel,
106+
},
107+
};
108+
convertIfPresent(endpoint.eventTrigger, opts, 'eventFilters', 'filters');
109+
copyIfPresent(endpoint.eventTrigger, opts, 'retry');
110+
111+
func.__endpoint = endpoint;
112+
113+
return func;
114+
}

v2/eventarc.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2022 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+
// This file is not part of the firebase-functions SDK. It is used to silence the
24+
// imports eslint plugin until it can understand import paths defined by node
25+
// package exports.
26+
// For more information, see github.com/import-js/eslint-plugin-import/issues/1810

0 commit comments

Comments
 (0)