diff --git a/spec/cloudevent/generate.ts b/spec/cloudevent/generate.ts index fd0cfdf..f245887 100644 --- a/spec/cloudevent/generate.ts +++ b/spec/cloudevent/generate.ts @@ -20,39 +20,39 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import {expect} from 'chai'; +import { expect } from 'chai'; -import {alerts, storage} from 'firebase-functions/v2'; -import {generateMockCloudEvent} from '../../src/cloudevent/generate'; +import { alerts, storage } from 'firebase-functions/v2'; +import { generateMockCloudEvent } from '../../src/cloudevent/generate'; describe('generate (CloudEvent)', () => { describe('#generateMockCloudEvent', () => { describe('alerts.billing.onPlanAutomatedUpdatePublished()', () => { it('should create CloudEvent with appropriate fields', () => { - const cloudFn = alerts.billing.onPlanAutomatedUpdatePublished(() => { - }); - const cloudEvent = - generateMockCloudEvent(cloudFn); + const cloudFn = alerts.billing.onPlanAutomatedUpdatePublished(() => {}); + const cloudEvent = generateMockCloudEvent(cloudFn); expect(cloudEvent.type).equal( - 'google.firebase.firebasealerts.alerts.v1.published'); + 'google.firebase.firebasealerts.alerts.v1.published' + ); expect(cloudEvent.source).equal( - '//firebasealerts.googleapis.com/projects/42'); + '//firebasealerts.googleapis.com/projects/42' + ); expect(cloudEvent.subject).equal(undefined); }); }); describe('storage.onObjectArchived', () => { it('should create CloudEvent with appropriate fields', () => { const bucketName = 'bucket_name'; - const cloudFn = storage.onObjectArchived(bucketName, () => { - }); - const cloudEvent = - generateMockCloudEvent(cloudFn); + const cloudFn = storage.onObjectArchived(bucketName, () => {}); + const cloudEvent = generateMockCloudEvent(cloudFn); expect(cloudEvent.type).equal( - 'google.cloud.storage.object.v1.archived'); + 'google.cloud.storage.object.v1.archived' + ); expect(cloudEvent.source).equal( - `//storage.googleapis.com/projects/_/buckets/${bucketName}`); + `//storage.googleapis.com/projects/_/buckets/${bucketName}` + ); expect(cloudEvent.subject).equal('objects/file_name'); }); }); diff --git a/spec/main.spec.ts b/spec/main.spec.ts index efa5e60..d1e3a40 100644 --- a/spec/main.spec.ts +++ b/spec/main.spec.ts @@ -33,8 +33,8 @@ import { } from '../src/main'; import { features } from '../src/features'; import { FirebaseFunctionsTest } from '../src/lifecycle'; -import {alerts} from 'firebase-functions/v2'; -import {wrapV2} from '../src/v2'; +import { alerts } from 'firebase-functions/v2'; +import { wrapV2 } from '../src/v2'; describe('main', () => { describe('#wrap', () => { @@ -230,12 +230,13 @@ describe('main', () => { describe('v2 functions', () => { it('should invoke wrapV2 wrapper', () => { - const handler = (cloudEvent) => ({cloudEvent}); + const handler = (cloudEvent) => ({ cloudEvent }); const cloudFn = alerts.billing.onPlanAutomatedUpdatePublished(handler); const cloudFnWrap = wrapV2(cloudFn); - const expectedType = 'google.firebase.firebasealerts.alerts.v1.published'; - expect(cloudFnWrap().cloudEvent).to.include({type: expectedType}); + const expectedType = + 'google.firebase.firebasealerts.alerts.v1.published'; + expect(cloudFnWrap().cloudEvent).to.include({ type: expectedType }); }); }); diff --git a/spec/v2.spec.ts b/spec/v2.spec.ts index 9cc0449..ed22077 100644 --- a/spec/v2.spec.ts +++ b/spec/v2.spec.ts @@ -20,19 +20,22 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import {expect} from 'chai'; +import { expect } from 'chai'; -import { - wrapV2, -} from '../src/v2'; +import { wrapV2 } from '../src/v2'; import { - CloudFunction, CloudEvent, alerts, pubsub, storage, eventarc + CloudFunction, + alerts, + pubsub, + storage, + eventarc, + https, } from 'firebase-functions/v2'; describe('v2', () => { describe('#wrapV2', () => { - const handler = (cloudEvent) => ({cloudEvent}); + const handler = (cloudEvent) => ({ cloudEvent }); describe('alerts', () => { describe('alerts.onAlertPublished()', () => { @@ -58,21 +61,27 @@ describe('v2', () => { }); describe('alerts.crashlytics.onNewNonfatalIssuePublished()', () => { it('should update CloudEvent appropriately', () => { - const cloudFn = alerts.crashlytics.onNewNonfatalIssuePublished(handler); + const cloudFn = alerts.crashlytics.onNewNonfatalIssuePublished( + handler + ); const cloudFnWrap = wrapV2(cloudFn); expect(cloudFnWrap().cloudEvent).to.include({}); }); }); describe('alerts.crashlytics.onRegressionAlertPublished()', () => { it('should update CloudEvent appropriately', () => { - const cloudFn = alerts.crashlytics.onRegressionAlertPublished(handler); + const cloudFn = alerts.crashlytics.onRegressionAlertPublished( + handler + ); const cloudFnWrap = wrapV2(cloudFn); expect(cloudFnWrap().cloudEvent).to.include({}); }); }); describe('alerts.crashlytics.onStabilityDigestPublished()', () => { it('should update CloudEvent appropriately', () => { - const cloudFn = alerts.crashlytics.onStabilityDigestPublished(handler); + const cloudFn = alerts.crashlytics.onStabilityDigestPublished( + handler + ); const cloudFnWrap = wrapV2(cloudFn); expect(cloudFnWrap().cloudEvent).to.include({}); }); @@ -86,14 +95,18 @@ describe('v2', () => { }); describe('alerts.appDistribution.onNewTesterIosDevicePublished()', () => { it('should update CloudEvent appropriately', () => { - const cloudFn = alerts.appDistribution.onNewTesterIosDevicePublished(handler); + const cloudFn = alerts.appDistribution.onNewTesterIosDevicePublished( + handler + ); const cloudFnWrap = wrapV2(cloudFn); expect(cloudFnWrap().cloudEvent).to.include({}); }); }); describe('alerts.billing.onPlanAutomatedUpdatePublished()', () => { it('should update CloudEvent appropriately', () => { - const cloudFn = alerts.billing.onPlanAutomatedUpdatePublished(handler); + const cloudFn = alerts.billing.onPlanAutomatedUpdatePublished( + handler + ); const cloudFnWrap = wrapV2(cloudFn); expect(cloudFnWrap().cloudEvent).to.include({}); }); @@ -113,7 +126,7 @@ describe('v2', () => { const eventType = 'EVENT_TYPE'; const cloudFn = eventarc.onCustomEventPublished(eventType, handler); const cloudFnWrap = wrapV2(cloudFn); - expect(cloudFnWrap().cloudEvent).to.include({type: eventType}); + expect(cloudFnWrap().cloudEvent).to.include({ type: eventType }); }); }); }); @@ -162,44 +175,50 @@ describe('v2', () => { it('should update CloudEvent with json data override', () => { const data = { message: { - json: {firebase: 'test'} + json: { firebase: 'test' }, }, - subscription: 'subscription' + subscription: 'subscription', }; const cloudFn = pubsub.onMessagePublished('topic', handler); const cloudFnWrap = wrapV2(cloudFn); - const cloudEventPartial = {data}; + const cloudEventPartial = { data }; - expect(cloudFnWrap(cloudEventPartial).cloudEvent.data.message).to.include({ + expect( + cloudFnWrap(cloudEventPartial).cloudEvent.data.message + ).to.include({ data: 'eyJoZWxsbyI6IndvcmxkIn0=', // Note: This is a mismatch from the json }); - expect(cloudFnWrap(cloudEventPartial).cloudEvent.data.message.json).to.include({firebase: 'test'}); + expect( + cloudFnWrap(cloudEventPartial).cloudEvent.data.message.json + ).to.include({ firebase: 'test' }); }); it('should update CloudEvent with json and data string overrides', () => { const data = { message: { data: 'eyJmaXJlYmFzZSI6Im5vbl9qc29uX3Rlc3QifQ==', - json: {firebase: 'non_json_test'}, + json: { firebase: 'non_json_test' }, }, - subscription: 'subscription' + subscription: 'subscription', }; const cloudFn = pubsub.onMessagePublished('topic', handler); const cloudFnWrap = wrapV2(cloudFn); - const cloudEventPartial = {data}; + const cloudEventPartial = { data }; - expect(cloudFnWrap(cloudEventPartial).cloudEvent.data.message).to.include({ + expect( + cloudFnWrap(cloudEventPartial).cloudEvent.data.message + ).to.include({ data: 'eyJmaXJlYmFzZSI6Im5vbl9qc29uX3Rlc3QifQ==', }); - expect(cloudFnWrap(cloudEventPartial).cloudEvent.data.message.json) - .to.include({firebase: 'non_json_test'}); + expect( + cloudFnWrap(cloudEventPartial).cloudEvent.data.message.json + ).to.include({ firebase: 'non_json_test' }); }); }); }); describe('callable functions', () => { it('return an error because they are not supported', () => { - const cloudFunction = (input) => input; - cloudFunction.run = (cloudEvent: CloudEvent) => ({cloudEvent}); + const cloudFunction = https.onCall((data) => data); cloudFunction.__endpoint = { platform: 'gcfv2', labels: {}, @@ -210,11 +229,12 @@ describe('v2', () => { }; try { - const wrappedCF = wrapV2(cloudFunction as CloudFunction); + const wrappedCF = wrapV2(cloudFunction as any); wrappedCF(); } catch (e) { expect(e.message).to.equal( - 'Wrap function is not available for callableTriggers functions.'); + 'Wrap function is not available for callableTriggers functions.' + ); } }); }); @@ -223,17 +243,18 @@ describe('v2', () => { it('should create CloudEvent with appropriate fields for pubsub.onMessagePublished()', () => { const data = { message: { - json: '{"hello_firebase": "world_firebase"}' + json: '{"hello_firebase": "world_firebase"}', }, - subscription: 'subscription' + subscription: 'subscription', }; const cloudFn = pubsub.onMessagePublished('topic', handler); - const cloudEvent = wrapV2(cloudFn)({data}).cloudEvent; + const cloudEvent = wrapV2(cloudFn)({ data }).cloudEvent; expect(cloudEvent.type).equal( - 'google.cloud.pubsub.topic.v1.messagePublished'); + 'google.cloud.pubsub.topic.v1.messagePublished' + ); expect(cloudEvent.data.message).to.include({ - json: '{"hello_firebase": "world_firebase"}' + json: '{"hello_firebase": "world_firebase"}', }); }); it('should generate source from original CloudFunction', () => { @@ -283,7 +304,7 @@ describe('v2', () => { const cloudEventOverride = { data: { contentType: 'application/octet-stream', - } + }, }; const bucketName = 'bucket_name'; @@ -291,7 +312,9 @@ describe('v2', () => { const mergedCloudEvent = wrapV2(cloudFn)(cloudEventOverride).cloudEvent; expect(mergedCloudEvent.data?.size).equal(42); - expect(mergedCloudEvent.data?.contentType).equal('application/octet-stream'); + expect(mergedCloudEvent.data?.contentType).equal( + 'application/octet-stream' + ); }); }); }); diff --git a/src/cloudevent/generate.ts b/src/cloudevent/generate.ts index b7927b6..a87c8ef 100644 --- a/src/cloudevent/generate.ts +++ b/src/cloudevent/generate.ts @@ -1,46 +1,62 @@ -import {CloudEvent} from 'firebase-functions/v2'; -import {CloudFunction} from 'firebase-functions/v2'; -import {LIST_OF_MOCK_CLOUD_EVENT_PARTIALS} from './partials/partials'; -import {DeepPartial} from './types'; +import { CloudEvent } from 'firebase-functions/v2'; +import { CloudFunction } from 'firebase-functions/v2'; +import { LIST_OF_MOCK_CLOUD_EVENT_PARTIALS } from './partials/partials'; +import { DeepPartial, MockCloudEventPartials } from './types'; import merge from 'ts-deepmerge'; -import {getEventType} from './partials/helpers'; +import { getEventType } from './partials/helpers'; /** * @return {CloudEvent} Generated Mock CloudEvent */ -export function generateCombinedCloudEvent( +export function generateCombinedCloudEvent< + EventType extends CloudEvent +>( cloudFunction: CloudFunction, - cloudEventPartial?: DeepPartial): CloudEvent { + cloudEventPartial?: DeepPartial +): EventType { const generatedCloudEvent = generateMockCloudEvent(cloudFunction); - return cloudEventPartial ? merge(generatedCloudEvent, cloudEventPartial) : generatedCloudEvent; + return cloudEventPartial + ? (merge(generatedCloudEvent, cloudEventPartial) as EventType) + : generatedCloudEvent; } /** @internal */ -export function generateMockCloudEvent( - cloudFunction: CloudFunction): CloudEvent { +export function generateMockCloudEvent>( + cloudFunction: CloudFunction +): EventType { return { ...generateBaseCloudEvent(cloudFunction), - ...generateMockCloudEventPartial(cloudFunction) + ...generateMockCloudEventPartial(cloudFunction), }; } /** @internal */ -function generateBaseCloudEvent(cloudFunction: CloudFunction): CloudEvent { +function generateBaseCloudEvent>( + cloudFunction: CloudFunction +): EventType { + // TODO: Consider refactoring so that we don't use this utility function. This + // is not type safe because EventType may require additional fields, which this + // function does not know how to satisfy. + // This could possibly be augmented to take a CloudEvent and AdditionalFields + // where AdditionalFields uses the keyof operator to make only new fields required. return { specversion: '1.0', id: makeEventId(), data: {}, source: '', // Required field that will get overridden by Provider-specific MockCloudEventPartials type: getEventType(cloudFunction), - time: new Date().toISOString() - }; + time: new Date().toISOString(), + } as any; } -function generateMockCloudEventPartial( - cloudFunction: CloudFunction): DeepPartial> { +function generateMockCloudEventPartial>( + cloudFunction: CloudFunction +): DeepPartial { for (const mockCloudEventPartial of LIST_OF_MOCK_CLOUD_EVENT_PARTIALS) { if (mockCloudEventPartial.match(cloudFunction)) { - return mockCloudEventPartial.generatePartial(cloudFunction); + return (mockCloudEventPartial as MockCloudEventPartials< + EventType + >).generatePartial(cloudFunction); } } // No matches were found diff --git a/src/cloudevent/partials/alerts/alerts-on-alert-published.ts b/src/cloudevent/partials/alerts/alerts-on-alert-published.ts index df1bbaf..599801f 100644 --- a/src/cloudevent/partials/alerts/alerts-on-alert-published.ts +++ b/src/cloudevent/partials/alerts/alerts-on-alert-published.ts @@ -1,10 +1,14 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudFunction, alerts} from 'firebase-functions/v2'; -import {APP_ID, getEventType, PROJECT_ID} from '../helpers'; +import { DeepPartial, MockCloudEventPartials } from '../../types'; +import { CloudFunction } from 'firebase-functions/v2'; +import { APP_ID, getEventType, PROJECT_ID } from '../helpers'; +import { FirebaseAlertData, AlertEvent } from 'firebase-functions/v2/alerts'; -export const alertsOnAlertPublished: - MockCloudEventPartials = { - generatePartial(_: CloudFunction): DeepPartial> { +export const alertsOnAlertPublished: MockCloudEventPartials> = { + generatePartial( + _: CloudFunction> + ): DeepPartial> { const source = `//firebasealerts.googleapis.com/projects/${PROJECT_ID}`; const alertType = 'appDistribution.newTesterIosDevice'; @@ -17,19 +21,22 @@ export const alertsOnAlertPublished: source, }; }, - match(cloudFunction: CloudFunction): boolean { - return getEventType(cloudFunction) === 'google.firebase.firebasealerts.alerts.v1.published'; + match(cloudFunction: CloudFunction>): boolean { + return ( + getEventType(cloudFunction) === + 'google.firebase.firebasealerts.alerts.v1.published' + ); }, }; /** Alert Published Data */ -function getOnAlertPublishedData(): alerts.FirebaseAlertData { +function getOnAlertPublishedData(): FirebaseAlertData { const now = new Date().toISOString(); - return ({ + return { // '@type': 'type.googleapis.com/google.events.firebase.firebasealerts.v1.AlertData', createTime: now, endTime: now, - payload: {} - }); + payload: {}, + }; } diff --git a/src/cloudevent/partials/alerts/app-distribution-on-new-tester-ios-device-published.ts b/src/cloudevent/partials/alerts/app-distribution-on-new-tester-ios-device-published.ts index 790e48f..4d8a22d 100644 --- a/src/cloudevent/partials/alerts/app-distribution-on-new-tester-ios-device-published.ts +++ b/src/cloudevent/partials/alerts/app-distribution-on-new-tester-ios-device-published.ts @@ -1,12 +1,17 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudFunction, alerts} from 'firebase-functions/v2'; -import {getEventFilters, getEventType, PROJECT_ID} from '../helpers'; +import { DeepPartial, MockCloudEventPartials } from '../../types'; +import { CloudFunction } from 'firebase-functions/v2'; +import { getEventFilters, getEventType, PROJECT_ID } from '../helpers'; +import { + AppDistributionEvent, + NewTesterDevicePayload, +} from 'firebase-functions/v2/alerts/appDistribution'; -export const alertsAppDistributionOnNewTesterIosDevicePublished: - MockCloudEventPartials> = { +export const alertsAppDistributionOnNewTesterIosDevicePublished: MockCloudEventPartials> = { generatePartial( - _: CloudFunction>): - DeepPartial> { + _: CloudFunction> + ): DeepPartial> { const source = `//firebasealerts.googleapis.com/projects/${PROJECT_ID}`; const now = new Date().toISOString(); @@ -16,18 +21,24 @@ export const alertsAppDistributionOnNewTesterIosDevicePublished: createTime: now, endTime: now, payload: { - ['@type']: 'com.google.firebase.firebasealerts.NewTesterDevicePayload', + ['@type']: + 'type.googleapis.com/google.events.firebase.firebasealerts.v1.AppDistroNewTesterIosDevicePayload', testerName: 'tester name', testerEmail: 'test@test.com', testerDeviceModelName: 'tester device model name', testerDeviceIdentifier: 'tester device identifier', - } - } + }, + }, }; }, match( - cloudFunction: CloudFunction>): boolean { - return getEventType(cloudFunction) === 'google.firebase.firebasealerts.alerts.v1.published' && - getEventFilters(cloudFunction)?.alerttype === 'appDistribution.newTesterIosDevice'; + cloudFunction: CloudFunction> + ): boolean { + return ( + getEventType(cloudFunction) === + 'google.firebase.firebasealerts.alerts.v1.published' && + getEventFilters(cloudFunction)?.alerttype === + 'appDistribution.newTesterIosDevice' + ); }, }; diff --git a/src/cloudevent/partials/alerts/billing-on-plan-automated-update-published.ts b/src/cloudevent/partials/alerts/billing-on-plan-automated-update-published.ts index 518c8c0..8b8ef1b 100644 --- a/src/cloudevent/partials/alerts/billing-on-plan-automated-update-published.ts +++ b/src/cloudevent/partials/alerts/billing-on-plan-automated-update-published.ts @@ -1,12 +1,18 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudFunction, alerts} from 'firebase-functions/v2'; -import {getEventFilters, getEventType, PROJECT_ID} from '../helpers'; +import { DeepPartial, MockCloudEventPartials } from '../../types'; +import { CloudFunction } from 'firebase-functions/v2'; +import { FirebaseAlertData } from 'firebase-functions/v2/alerts'; +import { + BillingEvent, + PlanAutomatedUpdatePayload, +} from 'firebase-functions/v2/alerts/billing'; +import { getEventFilters, getEventType, PROJECT_ID } from '../helpers'; -export const alertsBillingOnPlanAutomatedUpdatePublished: - MockCloudEventPartials> = { +export const alertsBillingOnPlanAutomatedUpdatePublished: MockCloudEventPartials> = { generatePartial( - _: CloudFunction>): - DeepPartial> { + _: CloudFunction> + ): DeepPartial> { const source = `//firebasealerts.googleapis.com/projects/${PROJECT_ID}`; return { @@ -14,22 +20,31 @@ export const alertsBillingOnPlanAutomatedUpdatePublished: data: getBillingPlanAutomatedUpdateData(), }; }, - match(cloudFunction: CloudFunction>): boolean { - return getEventType(cloudFunction) === 'google.firebase.firebasealerts.alerts.v1.published' && - getEventFilters(cloudFunction)?.alerttype === 'billing.planAutomatedUpdate'; + match( + cloudFunction: CloudFunction> + ): boolean { + return ( + getEventType(cloudFunction) === + 'google.firebase.firebasealerts.alerts.v1.published' && + getEventFilters(cloudFunction)?.alerttype === + 'billing.planAutomatedUpdate' + ); }, }; -function getBillingPlanAutomatedUpdateData(): alerts.FirebaseAlertData { +function getBillingPlanAutomatedUpdateData(): FirebaseAlertData< + PlanAutomatedUpdatePayload +> { const now = new Date().toISOString(); - return ({ + return { // '@type': 'type.googleapis.com/google.events.firebase.firebasealerts.v1.AlertData', createTime: now, endTime: now, payload: { - '@type': 'com.google.firebase.firebasealerts.PlanAutomatedUpdatePayload', - 'billingPlan': 'flame', - // 'notificationType': 'upgrade' - } - }); + '@type': + 'type.googleapis.com/google.events.firebase.firebasealerts.v1.BillingPlanAutomatedUpdatePayload', + billingPlan: 'flame', + notificationType: 'upgrade', + }, + }; } diff --git a/src/cloudevent/partials/alerts/billing-on-plan-update-published.ts b/src/cloudevent/partials/alerts/billing-on-plan-update-published.ts index cbb9855..4a7bf02 100644 --- a/src/cloudevent/partials/alerts/billing-on-plan-update-published.ts +++ b/src/cloudevent/partials/alerts/billing-on-plan-update-published.ts @@ -1,12 +1,18 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudFunction, alerts} from 'firebase-functions/v2'; -import {getEventFilters, getEventType, PROJECT_ID} from '../helpers'; +import { DeepPartial, MockCloudEventPartials } from '../../types'; +import { CloudFunction } from 'firebase-functions/v2'; +import { FirebaseAlertData } from 'firebase-functions/v2/alerts'; +import { + BillingEvent, + PlanUpdatePayload, +} from 'firebase-functions/v2/alerts/billing'; +import { getEventFilters, getEventType, PROJECT_ID } from '../helpers'; -export const alertsBillingOnPlanUpdatePublished: - MockCloudEventPartials> = { +export const alertsBillingOnPlanUpdatePublished: MockCloudEventPartials> = { generatePartial( - _: CloudFunction>): - DeepPartial> { + _: CloudFunction> + ): DeepPartial> { const source = `//firebasealerts.googleapis.com/projects/${PROJECT_ID}`; return { @@ -14,24 +20,30 @@ export const alertsBillingOnPlanUpdatePublished: data: getBillingPlanUpdateData(), }; }, - match(cloudFunction: CloudFunction>): boolean { - return getEventType(cloudFunction) === 'google.firebase.firebasealerts.alerts.v1.published' && - getEventFilters(cloudFunction)?.alerttype === 'billing.planUpdate'; + match( + cloudFunction: CloudFunction> + ): boolean { + return ( + getEventType(cloudFunction) === + 'google.firebase.firebasealerts.alerts.v1.published' && + getEventFilters(cloudFunction)?.alerttype === 'billing.planUpdate' + ); }, }; /** Alert Billing Data */ -function getBillingPlanUpdateData(): alerts.FirebaseAlertData { +function getBillingPlanUpdateData(): FirebaseAlertData { const now = new Date().toISOString(); - return ({ + return { // '@type': 'type.googleapis.com/google.events.firebase.firebasealerts.v1.AlertData', createTime: now, endTime: now, payload: { - '@type': 'com.google.firebase.firebasealerts.PlanUpdatePayload', - 'billingPlan': 'flame', - 'principalEmail': 'test@test.com', - // 'notificationType': 'upgrade' - } - }); + '@type': + 'type.googleapis.com/google.events.firebase.firebasealerts.v1.BillingPlanUpdatePayload', + billingPlan: 'flame', + principalEmail: 'test@test.com', + notificationType: 'upgrade', + }, + }; } diff --git a/src/cloudevent/partials/alerts/crashlytics-on-new-anr-issue-published.ts b/src/cloudevent/partials/alerts/crashlytics-on-new-anr-issue-published.ts index 1895326..1493a85 100644 --- a/src/cloudevent/partials/alerts/crashlytics-on-new-anr-issue-published.ts +++ b/src/cloudevent/partials/alerts/crashlytics-on-new-anr-issue-published.ts @@ -1,39 +1,53 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudFunction, alerts} from 'firebase-functions/v2'; -import {getEventFilters, getEventType, PROJECT_ID} from '../helpers'; +import { DeepPartial, MockCloudEventPartials } from '../../types'; +import { CloudFunction } from 'firebase-functions/v2'; +import { getEventFilters, getEventType, PROJECT_ID } from '../helpers'; +import { + CrashlyticsEvent, + NewAnrIssuePayload, +} from 'firebase-functions/v2/alerts/crashlytics'; +import { FirebaseAlertData } from 'firebase-functions/v2/alerts'; -export const alertsCrashlyticsOnNewAnrIssuePublished: - MockCloudEventPartials> = { +export const alertsCrashlyticsOnNewAnrIssuePublished: MockCloudEventPartials> = { generatePartial( - _: CloudFunction>): - DeepPartial> { + _: CloudFunction> + ): DeepPartial> { const source = `//firebasealerts.googleapis.com/projects/${PROJECT_ID}`; return { source, - data: getCrashlyticsNewAnrIssueData() + data: getCrashlyticsNewAnrIssueData(), }; }, - match(cloudFunction: CloudFunction>): boolean { - return getEventType(cloudFunction) === 'google.firebase.firebasealerts.alerts.v1.published' && - getEventFilters(cloudFunction)?.alerttype === 'crashlytics.newAnrIssue'; + match( + cloudFunction: CloudFunction> + ): boolean { + return ( + getEventType(cloudFunction) === + 'google.firebase.firebasealerts.alerts.v1.published' && + getEventFilters(cloudFunction)?.alerttype === 'crashlytics.newAnrIssue' + ); }, }; -function getCrashlyticsNewAnrIssueData(): alerts.FirebaseAlertData { +function getCrashlyticsNewAnrIssueData(): FirebaseAlertData< + NewAnrIssuePayload +> { const now = new Date().toISOString(); - return ({ + return { // '@type': 'type.googleapis.com/google.events.firebase.firebasealerts.v1.AlertData', createTime: now, endTime: now, payload: { - '@type': 'com.google.firebase.firebasealerts.NewAnrIssuePayload', - 'issue': { + '@type': + 'type.googleapis.com/google.events.firebase.firebasealerts.v1.CrashlyticsNewAnrIssuePayload', + issue: { id: 'crashlytics_issue_id', title: 'crashlytics_issue_title', subtitle: 'crashlytics_issue_subtitle', - appVersion: 'crashlytics_issue_app_version' + appVersion: 'crashlytics_issue_app_version', }, - } - }); + }, + }; } diff --git a/src/cloudevent/partials/alerts/crashlytics-on-new-fatal-issue-published.ts b/src/cloudevent/partials/alerts/crashlytics-on-new-fatal-issue-published.ts index 45bebcf..3b0283b 100644 --- a/src/cloudevent/partials/alerts/crashlytics-on-new-fatal-issue-published.ts +++ b/src/cloudevent/partials/alerts/crashlytics-on-new-fatal-issue-published.ts @@ -1,39 +1,53 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudFunction, alerts} from 'firebase-functions/v2'; -import {getEventFilters, getEventType, PROJECT_ID} from '../helpers'; +import { DeepPartial, MockCloudEventPartials } from '../../types'; +import { CloudFunction } from 'firebase-functions/v2'; +import { getEventFilters, getEventType, PROJECT_ID } from '../helpers'; +import { + CrashlyticsEvent, + NewFatalIssuePayload, +} from 'firebase-functions/v2/alerts/crashlytics'; +import { FirebaseAlertData } from 'firebase-functions/v2/alerts'; -export const alertsCrashlyticsOnNewFatalIssuePublished: - MockCloudEventPartials> = { +export const alertsCrashlyticsOnNewFatalIssuePublished: MockCloudEventPartials> = { generatePartial( - _: CloudFunction>): - DeepPartial> { + _: CloudFunction> + ): DeepPartial> { const source = `//firebasealerts.googleapis.com/projects/${PROJECT_ID}`; return { source, - data: getCrashlyticsNewFatalIssueData() + data: getCrashlyticsNewFatalIssueData(), }; }, - match(cloudFunction: CloudFunction>): boolean { - return getEventType(cloudFunction) === 'google.firebase.firebasealerts.alerts.v1.published' && - getEventFilters(cloudFunction)?.alerttype === 'crashlytics.newFatalIssue'; + match( + cloudFunction: CloudFunction> + ): boolean { + return ( + getEventType(cloudFunction) === + 'google.firebase.firebasealerts.alerts.v1.published' && + getEventFilters(cloudFunction)?.alerttype === 'crashlytics.newFatalIssue' + ); }, }; -function getCrashlyticsNewFatalIssueData(): alerts.FirebaseAlertData { +function getCrashlyticsNewFatalIssueData(): FirebaseAlertData< + NewFatalIssuePayload +> { const now = new Date().toISOString(); - return ({ + return { // '@type': 'type.googleapis.com/google.events.firebase.firebasealerts.v1.AlertData', createTime: now, endTime: now, payload: { - '@type': 'com.google.firebase.firebasealerts.CrashlyticsNewFatalIssuePayload', - 'issue': { + '@type': + 'type.googleapis.com/google.events.firebase.firebasealerts.v1.CrashlyticsNewFatalIssuePayload', + issue: { id: 'crashlytics_issue_id', title: 'crashlytics_issue_title', subtitle: 'crashlytics_issue_subtitle', - appVersion: 'crashlytics_issue_app_version' + appVersion: 'crashlytics_issue_app_version', }, - } - }); + }, + }; } diff --git a/src/cloudevent/partials/alerts/crashlytics-on-new-nonfatal-issue-published.ts b/src/cloudevent/partials/alerts/crashlytics-on-new-nonfatal-issue-published.ts index f7beec3..2c58215 100644 --- a/src/cloudevent/partials/alerts/crashlytics-on-new-nonfatal-issue-published.ts +++ b/src/cloudevent/partials/alerts/crashlytics-on-new-nonfatal-issue-published.ts @@ -1,39 +1,54 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudFunction, alerts} from 'firebase-functions/v2'; -import {getEventFilters, getEventType, PROJECT_ID} from '../helpers'; +import { DeepPartial, MockCloudEventPartials } from '../../types'; +import { CloudFunction } from 'firebase-functions/v2'; +import { getEventFilters, getEventType, PROJECT_ID } from '../helpers'; +import { + CrashlyticsEvent, + NewNonfatalIssuePayload, +} from 'firebase-functions/v2/alerts/crashlytics'; +import { FirebaseAlertData } from 'firebase-functions/v2/alerts'; -export const alertsCrashlyticsOnNewNonfatalIssuePublished: - MockCloudEventPartials> = { +export const alertsCrashlyticsOnNewNonfatalIssuePublished: MockCloudEventPartials> = { generatePartial( - _: CloudFunction>): - DeepPartial> { + _: CloudFunction> + ): DeepPartial> { const source = `//firebasealerts.googleapis.com/projects/${PROJECT_ID}`; return { source, - data: getCrashlyticsNewNonfatalIssueData() + data: getCrashlyticsNewNonfatalIssueData(), }; }, - match(cloudFunction: CloudFunction>): boolean { - return getEventType(cloudFunction) === 'google.firebase.firebasealerts.alerts.v1.published' && - getEventFilters(cloudFunction)?.alerttype === 'crashlytics.newNonfatalIssue'; + match( + cloudFunction: CloudFunction> + ): boolean { + return ( + getEventType(cloudFunction) === + 'google.firebase.firebasealerts.alerts.v1.published' && + getEventFilters(cloudFunction)?.alerttype === + 'crashlytics.newNonfatalIssue' + ); }, }; -function getCrashlyticsNewNonfatalIssueData(): alerts.FirebaseAlertData { +function getCrashlyticsNewNonfatalIssueData(): FirebaseAlertData< + NewNonfatalIssuePayload +> { const now = new Date().toISOString(); - return ({ + return { // '@type': 'type.googleapis.com/google.events.firebase.firebasealerts.v1.AlertData', createTime: now, endTime: now, payload: { - '@type': 'com.google.firebase.firebasealerts.CrashlyticsNewNonfatalIssuePayload', - 'issue': { + '@type': + 'type.googleapis.com/google.events.firebase.firebasealerts.v1.CrashlyticsNewNonfatalIssuePayload', + issue: { id: 'crashlytics_issue_id', title: 'crashlytics_issue_title', subtitle: 'crashlytics_issue_subtitle', - appVersion: 'crashlytics_issue_app_version' + appVersion: 'crashlytics_issue_app_version', }, - } - }); + }, + }; } diff --git a/src/cloudevent/partials/alerts/crashlytics-on-regression-alert-published.ts b/src/cloudevent/partials/alerts/crashlytics-on-regression-alert-published.ts index 72a529a..d69bd9c 100644 --- a/src/cloudevent/partials/alerts/crashlytics-on-regression-alert-published.ts +++ b/src/cloudevent/partials/alerts/crashlytics-on-regression-alert-published.ts @@ -1,12 +1,18 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudFunction, alerts} from 'firebase-functions/v2'; -import {getEventFilters, getEventType, PROJECT_ID} from '../helpers'; +import { DeepPartial, MockCloudEventPartials } from '../../types'; +import { CloudFunction } from 'firebase-functions/v2'; +import { getEventFilters, getEventType, PROJECT_ID } from '../helpers'; +import { + CrashlyticsEvent, + RegressionAlertPayload, +} from 'firebase-functions/v2/alerts/crashlytics'; +import { FirebaseAlertData } from 'firebase-functions/v2/alerts'; -export const alertsCrashlyticsOnRegressionAlertPublished: - MockCloudEventPartials> = { +export const alertsCrashlyticsOnRegressionAlertPublished: MockCloudEventPartials> = { generatePartial( - _: CloudFunction>): - DeepPartial> { + _: CloudFunction> + ): DeepPartial> { const source = `//firebasealerts.googleapis.com/projects/${PROJECT_ID}`; return { @@ -14,29 +20,37 @@ export const alertsCrashlyticsOnRegressionAlertPublished: data: getCrashlyticsRegressionAlertPayload(), }; }, - match(cloudFunction: CloudFunction>): boolean { - return getEventType(cloudFunction) === 'google.firebase.firebasealerts.alerts.v1.published' && - getEventFilters(cloudFunction)?.alerttype === 'crashlytics.regression'; + match( + cloudFunction: CloudFunction> + ): boolean { + return ( + getEventType(cloudFunction) === + 'google.firebase.firebasealerts.alerts.v1.published' && + getEventFilters(cloudFunction)?.alerttype === 'crashlytics.regression' + ); }, }; /** Alert Crashlytics Data */ -function getCrashlyticsRegressionAlertPayload(): alerts.FirebaseAlertData { +function getCrashlyticsRegressionAlertPayload(): FirebaseAlertData< + RegressionAlertPayload +> { const now = new Date().toISOString(); - return ({ + return { // ['@type']: 'type.googleapis.com/google.events.firebase.firebasealerts.v1.AlertData', createTime: now, endTime: now, payload: { - '@type': 'com.google.firebase.firebasealerts.CrashlyticsRegressionAlertPayload', - 'issue': { + '@type': + 'type.googleapis.com/google.events.firebase.firebasealerts.v1.CrashlyticsRegressionAlertPayload', + issue: { id: 'crashlytics_issue_id', title: 'crashlytics_issue_title', subtitle: 'crashlytics_issue_subtitle', - appVersion: 'crashlytics_issue_app_version' + appVersion: 'crashlytics_issue_app_version', }, - 'type': 'test type', - 'resolveTime': now - } - }); + type: 'test type', + resolveTime: now, + }, + }; } diff --git a/src/cloudevent/partials/alerts/crashlytics-on-stability-digest-published.ts b/src/cloudevent/partials/alerts/crashlytics-on-stability-digest-published.ts index b3b0eb2..a482e10 100644 --- a/src/cloudevent/partials/alerts/crashlytics-on-stability-digest-published.ts +++ b/src/cloudevent/partials/alerts/crashlytics-on-stability-digest-published.ts @@ -1,35 +1,50 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudFunction, alerts} from 'firebase-functions/v2'; -import {getEventFilters, getEventType, PROJECT_ID} from '../helpers'; +import { DeepPartial, MockCloudEventPartials } from '../../types'; +import { CloudFunction } from 'firebase-functions/v2'; +import { getEventFilters, getEventType, PROJECT_ID } from '../helpers'; +import { + CrashlyticsEvent, + StabilityDigestPayload, +} from 'firebase-functions/v2/alerts/crashlytics'; +import { FirebaseAlertData } from 'firebase-functions/v2/alerts'; -export const alertsCrashlyticsOnStabilityDigestPublished: - MockCloudEventPartials> = { +export const alertsCrashlyticsOnStabilityDigestPublished: MockCloudEventPartials> = { generatePartial( - _: CloudFunction>): - DeepPartial> { + _: CloudFunction> + ): DeepPartial> { const source = `//firebasealerts.googleapis.com/projects/${PROJECT_ID}`; return { source, - data: getCrashlyticsStabilityData() + data: getCrashlyticsStabilityData(), }; }, - match(cloudFunction: CloudFunction>): boolean { - return getEventType(cloudFunction) === 'google.firebase.firebasealerts.alerts.v1.published' && - getEventFilters(cloudFunction)?.alerttype === 'crashlytics.stabilityDigest'; + match( + cloudFunction: CloudFunction> + ): boolean { + return ( + getEventType(cloudFunction) === + 'google.firebase.firebasealerts.alerts.v1.published' && + getEventFilters(cloudFunction)?.alerttype === + 'crashlytics.stabilityDigest' + ); }, }; -function getCrashlyticsStabilityData(): alerts.FirebaseAlertData { +function getCrashlyticsStabilityData(): FirebaseAlertData< + StabilityDigestPayload +> { const now = new Date().toISOString(); - return ({ + return { // '@type': 'type.googleapis.com/google.events.firebase.firebasealerts.v1.AlertData', createTime: now, endTime: now, payload: { - '@type': 'com.google.firebase.firebasealerts.CrashlyticsStabilityDigestPayload', - 'digestDate': new Date().toISOString(), - 'trendingIssues': [ + '@type': + 'type.googleapis.com/google.events.firebase.firebasealerts.v1.CrashlyticsStabilityDigestPayload', + digestDate: new Date().toISOString(), + trendingIssues: [ { type: 'type', eventCount: 100, @@ -38,10 +53,10 @@ function getCrashlyticsStabilityData(): alerts.FirebaseAlertData> = { +export const alertsCrashlyticsOnVelocityAlertPublished: MockCloudEventPartials> = { generatePartial( - _: CloudFunction>): - DeepPartial> { + _: CloudFunction> + ): DeepPartial> { const source = `//firebasealerts.googleapis.com/projects/${PROJECT_ID}`; return { @@ -14,30 +20,38 @@ export const alertsCrashlyticsOnVelocityAlertPublished: data: getCrashlyticsVelocityAlertData(), }; }, - match(cloudFunction: CloudFunction>): boolean { - return getEventType(cloudFunction) === 'google.firebase.firebasealerts.alerts.v1.published' && - getEventFilters(cloudFunction)?.alerttype === 'crashlytics.velocity'; + match( + cloudFunction: CloudFunction> + ): boolean { + return ( + getEventType(cloudFunction) === + 'google.firebase.firebasealerts.alerts.v1.published' && + getEventFilters(cloudFunction)?.alerttype === 'crashlytics.velocity' + ); }, }; -function getCrashlyticsVelocityAlertData(): alerts.FirebaseAlertData { +function getCrashlyticsVelocityAlertData(): FirebaseAlertData< + VelocityAlertPayload +> { const now = new Date().toISOString(); - return ({ + return { // '@type': 'type.googleapis.com/google.events.firebase.firebasealerts.v1.AlertData', createTime: now, endTime: now, payload: { - '@type': 'com.google.firebase.firebasealerts.VelocityAlertPayload', - 'crashCount': 100, - 'issue': { + '@type': + 'type.googleapis.com/google.events.firebase.firebasealerts.v1.CrashlyticsVelocityAlertPayload', + crashCount: 100, + issue: { id: 'crashlytics_issue_id', title: 'crashlytics_issue_title', subtitle: 'crashlytics_issue_subtitle', - appVersion: 'crashlytics_issue_app_version' + appVersion: 'crashlytics_issue_app_version', }, - 'createTime': now, - 'firstVersion': '1.1', - 'crashPercentage': 50.0 - } - }); + createTime: now, + firstVersion: '1.1', + crashPercentage: 50.0, + }, + }; } diff --git a/src/cloudevent/partials/eventarc/eventarc-on-custom-event-published.ts b/src/cloudevent/partials/eventarc/eventarc-on-custom-event-published.ts index ebe998e..7c55bb3 100644 --- a/src/cloudevent/partials/eventarc/eventarc-on-custom-event-published.ts +++ b/src/cloudevent/partials/eventarc/eventarc-on-custom-event-published.ts @@ -1,9 +1,10 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudEvent, CloudFunction} from 'firebase-functions/v2'; +import { DeepPartial, MockCloudEventPartials } from '../../types'; +import { CloudEvent, CloudFunction } from 'firebase-functions/v2'; -export const eventarcOnCustomEventPublished: - MockCloudEventPartials = { - generatePartial(_: CloudFunction): DeepPartial { +export const eventarcOnCustomEventPublished: MockCloudEventPartials = { + generatePartial( + _: CloudFunction> + ): DeepPartial> { const source = 'eventarc_source'; const subject = 'eventarc_subject'; @@ -13,7 +14,7 @@ export const eventarcOnCustomEventPublished: subject, }; }, - match(_: CloudFunction): boolean { + match(_: CloudFunction>): boolean { return true; }, }; diff --git a/src/cloudevent/partials/helpers.ts b/src/cloudevent/partials/helpers.ts index 2bfc60b..19f61fb 100644 --- a/src/cloudevent/partials/helpers.ts +++ b/src/cloudevent/partials/helpers.ts @@ -1,13 +1,15 @@ -import {CloudFunction} from 'firebase-functions/v2'; +import { CloudEvent, CloudFunction } from 'firebase-functions/v2'; export const APP_ID = '__APP_ID__'; export const PROJECT_ID = '42'; export const FILENAME = 'file_name'; -export function getEventType(cloudFunction: CloudFunction): string { +export function getEventType(cloudFunction: CloudFunction): string { return cloudFunction?.__endpoint?.eventTrigger?.eventType || ''; } -export function getEventFilters(cloudFunction: CloudFunction): Record { +export function getEventFilters( + cloudFunction: CloudFunction +): Record { return cloudFunction?.__endpoint?.eventTrigger?.eventFilters || {}; } diff --git a/src/cloudevent/partials/partials.ts b/src/cloudevent/partials/partials.ts index dffdee2..b06ce45 100644 --- a/src/cloudevent/partials/partials.ts +++ b/src/cloudevent/partials/partials.ts @@ -1,22 +1,17 @@ -import {MockCloudEventPartials} from '../types'; -import {alertsOnAlertPublished} from './alerts/alerts-on-alert-published'; -import {alertsCrashlyticsOnNewAnrIssuePublished} from './alerts/crashlytics-on-new-anr-issue-published'; -import {alertsCrashlyticsOnNewFatalIssuePublished} from './alerts/crashlytics-on-new-fatal-issue-published'; -import {alertsCrashlyticsOnNewNonfatalIssuePublished} from './alerts/crashlytics-on-new-nonfatal-issue-published'; -import {alertsCrashlyticsOnRegressionAlertPublished} from './alerts/crashlytics-on-regression-alert-published'; -import {alertsCrashlyticsOnStabilityDigestPublished} from './alerts/crashlytics-on-stability-digest-published'; -import {alertsCrashlyticsOnVelocityAlertPublished} from './alerts/crashlytics-on-velocity-alert-published'; -import { - alertsAppDistributionOnNewTesterIosDevicePublished -} from './alerts/app-distribution-on-new-tester-ios-device-published'; -import {alertsBillingOnPlanAutomatedUpdatePublished} from './alerts/billing-on-plan-automated-update-published'; -import {alertsBillingOnPlanUpdatePublished} from './alerts/billing-on-plan-update-published'; -import {eventarcOnCustomEventPublished} from './eventarc/eventarc-on-custom-event-published'; -import {storageOnObjectArchived} from './storage/storage-on-object-archived'; -import {storageOnObjectDeleted} from './storage/storage-on-object-deleted'; -import {storageOnObjectFinalized} from './storage/storage-on-object-finalized'; -import {storageOnObjectMetadataUpdated} from './storage/storage-on-object-metadata-updated'; -import {pubsubOnMessagePublished} from './pubsub/pubsub-on-message-published'; +import { MockCloudEventPartials } from '../types'; +import { alertsOnAlertPublished } from './alerts/alerts-on-alert-published'; +import { alertsCrashlyticsOnNewAnrIssuePublished } from './alerts/crashlytics-on-new-anr-issue-published'; +import { alertsCrashlyticsOnNewFatalIssuePublished } from './alerts/crashlytics-on-new-fatal-issue-published'; +import { alertsCrashlyticsOnNewNonfatalIssuePublished } from './alerts/crashlytics-on-new-nonfatal-issue-published'; +import { alertsCrashlyticsOnRegressionAlertPublished } from './alerts/crashlytics-on-regression-alert-published'; +import { alertsCrashlyticsOnStabilityDigestPublished } from './alerts/crashlytics-on-stability-digest-published'; +import { alertsCrashlyticsOnVelocityAlertPublished } from './alerts/crashlytics-on-velocity-alert-published'; +import { alertsAppDistributionOnNewTesterIosDevicePublished } from './alerts/app-distribution-on-new-tester-ios-device-published'; +import { alertsBillingOnPlanAutomatedUpdatePublished } from './alerts/billing-on-plan-automated-update-published'; +import { alertsBillingOnPlanUpdatePublished } from './alerts/billing-on-plan-update-published'; +import { eventarcOnCustomEventPublished } from './eventarc/eventarc-on-custom-event-published'; +import { pubsubOnMessagePublished } from './pubsub/pubsub-on-message-published'; +import { storageV1 } from './storage'; /** * @internal @@ -24,8 +19,9 @@ import {pubsubOnMessagePublished} from './pubsub/pubsub-on-message-published'; * (eg {@link alertsOnAlertPublished}). In addition, * {@link eventarcOnCustomEventPublished} acts as a catch-all. */ -export const LIST_OF_MOCK_CLOUD_EVENT_PARTIALS: - Array> = [ +export const LIST_OF_MOCK_CLOUD_EVENT_PARTIALS: Array> = [ alertsCrashlyticsOnNewAnrIssuePublished, alertsCrashlyticsOnNewFatalIssuePublished, alertsCrashlyticsOnNewNonfatalIssuePublished, @@ -36,10 +32,7 @@ export const LIST_OF_MOCK_CLOUD_EVENT_PARTIALS: alertsBillingOnPlanAutomatedUpdatePublished, alertsBillingOnPlanUpdatePublished, alertsOnAlertPublished, // Note: alert.onAlertPublished matching is more generic - storageOnObjectArchived, - storageOnObjectDeleted, - storageOnObjectFinalized, - storageOnObjectMetadataUpdated, + storageV1, pubsubOnMessagePublished, eventarcOnCustomEventPublished, ]; diff --git a/src/cloudevent/partials/pubsub/pubsub-on-message-published.ts b/src/cloudevent/partials/pubsub/pubsub-on-message-published.ts index 39adbdc..cbb0bbe 100644 --- a/src/cloudevent/partials/pubsub/pubsub-on-message-published.ts +++ b/src/cloudevent/partials/pubsub/pubsub-on-message-published.ts @@ -1,11 +1,13 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudEvent, CloudFunction, pubsub} from 'firebase-functions/v2'; -import {getEventFilters, getEventType, PROJECT_ID} from '../helpers'; +import { DeepPartial, MockCloudEventPartials } from '../../types'; +import { CloudEvent, CloudFunction, pubsub } from 'firebase-functions/v2'; +import { getEventFilters, getEventType, PROJECT_ID } from '../helpers'; -export const pubsubOnMessagePublished: - MockCloudEventPartials = { +export const pubsubOnMessagePublished: MockCloudEventPartials> = { generatePartial( - cloudFunction: CloudFunction): DeepPartial> { + cloudFunction: CloudFunction> + ): DeepPartial> { const topicId = getEventFilters(cloudFunction)?.topic || ''; const source = `//pubsub.googleapis.com/projects/${PROJECT_ID}/topics/${topicId}`; const subscription = `projects/${PROJECT_ID}/subscriptions/pubsubexample-1`; @@ -20,7 +22,7 @@ export const pubsubOnMessagePublished: source, data: { message: { - attributes: {'sample-attribute': 'I am an attribute'}, + attributes: { 'sample-attribute': 'I am an attribute' }, data: dataMessageData, // Buffer base64 encoded messageId: 'messageId', publishTime: new Date().toISOString(), @@ -29,7 +31,10 @@ export const pubsubOnMessagePublished: }, }; }, - match(cloudFunction: CloudFunction): boolean { - return getEventType(cloudFunction) === 'google.cloud.pubsub.topic.v1.messagePublished'; + match(cloudFunction: CloudFunction>): boolean { + return ( + getEventType(cloudFunction) === + 'google.cloud.pubsub.topic.v1.messagePublished' + ); }, }; diff --git a/src/cloudevent/partials/storage/index.ts b/src/cloudevent/partials/storage/index.ts new file mode 100644 index 0000000..3b82493 --- /dev/null +++ b/src/cloudevent/partials/storage/index.ts @@ -0,0 +1,26 @@ +import { DeepPartial, MockCloudEventPartials } from '../../types'; +import { CloudFunction, CloudEvent } from 'firebase-functions/v2'; +import { StorageEvent } from 'firebase-functions/v2/storage'; +import { FILENAME, getEventFilters, getEventType } from '../helpers'; +import { getStorageObjectData } from './storage-data'; + +export const storageV1: MockCloudEventPartials = { + generatePartial( + cloudFunction: CloudFunction + ): DeepPartial { + const bucket = getEventFilters(cloudFunction)?.bucket || 'bucket_name'; + const source = `//storage.googleapis.com/projects/_/buckets/${bucket}`; + const subject = `objects/${FILENAME}`; + + return { + source, + subject, + data: getStorageObjectData(bucket, FILENAME, 1), + }; + }, + match(cloudFunction: CloudFunction>): boolean { + return getEventType(cloudFunction).startsWith( + 'google.cloud.storage.object.v1' + ); + }, +}; diff --git a/src/cloudevent/partials/storage/storage-data.ts b/src/cloudevent/partials/storage/storage-data.ts index 20390f2..fb3d524 100644 --- a/src/cloudevent/partials/storage/storage-data.ts +++ b/src/cloudevent/partials/storage/storage-data.ts @@ -1,13 +1,17 @@ -import {storage} from 'firebase-functions/v2'; -import {FILENAME} from '../helpers'; +import { storage } from 'firebase-functions/v2'; +import { FILENAME } from '../helpers'; /** Storage Data */ -export function getStorageObjectData(bucket: string, filename: string, generation: number): storage.StorageObjectData { +export function getStorageObjectData( + bucket: string, + filename: string, + generation: number +): storage.StorageObjectData { const now = new Date().toISOString(); return { metageneration: 1, metadata: { - firebaseStorageDownloadTokens: '00000000-0000-0000-0000-000000000000' + firebaseStorageDownloadTokens: '00000000-0000-0000-0000-000000000000', }, kind: 'storage#object', mediaLink: `https://www.googleapis.com/download/storage/v1/b/${bucket}/o/${FILENAME}?generation=${generation}&alt=media`, @@ -25,6 +29,6 @@ export function getStorageObjectData(bucket: string, filename: string, generatio contentType: 'image/gif', timeCreated: now, id: `${bucket}/${FILENAME}/${generation}`, - bucket + bucket, }; } diff --git a/src/cloudevent/partials/storage/storage-on-object-archived.ts b/src/cloudevent/partials/storage/storage-on-object-archived.ts deleted file mode 100644 index 291244b..0000000 --- a/src/cloudevent/partials/storage/storage-on-object-archived.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudEvent, CloudFunction, storage} from 'firebase-functions/v2'; -import {FILENAME, getEventFilters, getEventType} from '../helpers'; -import {getStorageObjectData} from './storage-data'; - -export const storageOnObjectArchived: - MockCloudEventPartials = { - generatePartial( - cloudFunction: CloudFunction): DeepPartial> { - const bucket = getEventFilters(cloudFunction)?.bucket || 'bucket_name'; - const source = `//storage.googleapis.com/projects/_/buckets/${bucket}`; - const subject = `objects/${FILENAME}`; - - return { - source, - subject, - data: getStorageObjectData(bucket, FILENAME, 1), - }; - }, - match(cloudFunction: CloudFunction): boolean { - return getEventType(cloudFunction) === 'google.cloud.storage.object.v1.archived'; - }, -}; diff --git a/src/cloudevent/partials/storage/storage-on-object-deleted.ts b/src/cloudevent/partials/storage/storage-on-object-deleted.ts deleted file mode 100644 index 4ee70a6..0000000 --- a/src/cloudevent/partials/storage/storage-on-object-deleted.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudEvent, CloudFunction, storage} from 'firebase-functions/v2'; -import {FILENAME, getEventFilters, getEventType} from '../helpers'; -import {getStorageObjectData} from './storage-data'; - -export const storageOnObjectDeleted: - MockCloudEventPartials = { - generatePartial( - cloudFunction: CloudFunction): DeepPartial> { - const bucket = getEventFilters(cloudFunction)?.bucket || 'bucket_name'; - const source = `//storage.googleapis.com/projects/_/buckets/${bucket}`; - const subject = `objects/${FILENAME}`; - - return { - source, - subject, - data: getStorageObjectData(bucket, FILENAME, 1), - }; - }, - match(cloudFunction: CloudFunction): boolean { - return getEventType(cloudFunction) === 'google.cloud.storage.object.v1.deleted'; - }, -}; diff --git a/src/cloudevent/partials/storage/storage-on-object-finalized.ts b/src/cloudevent/partials/storage/storage-on-object-finalized.ts deleted file mode 100644 index 3a01926..0000000 --- a/src/cloudevent/partials/storage/storage-on-object-finalized.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudEvent, CloudFunction, storage} from 'firebase-functions/v2'; -import {FILENAME, getEventFilters, getEventType} from '../helpers'; -import {getStorageObjectData} from './storage-data'; - -export const storageOnObjectFinalized: - MockCloudEventPartials = { - generatePartial( - cloudFunction: CloudFunction): DeepPartial> { - const bucket = getEventFilters(cloudFunction)?.bucket || 'bucket_name'; - const source = `//storage.googleapis.com/projects/_/buckets/${bucket}`; - const subject = `objects/${FILENAME}`; - - return { - source, - subject, - data: getStorageObjectData(bucket, FILENAME, 1), - - /* TODO(tystark): The following get returned by the server, I don't know what extension to expect*/ - // traceparent: '00-00000000000000000000000000000000-0000000000000000-00', - // bucket, - }; - }, - match(cloudFunction: CloudFunction): boolean { - return getEventType(cloudFunction) === 'google.cloud.storage.object.v1.finalized'; - }, -}; diff --git a/src/cloudevent/partials/storage/storage-on-object-metadata-updated.ts b/src/cloudevent/partials/storage/storage-on-object-metadata-updated.ts deleted file mode 100644 index c63e7f6..0000000 --- a/src/cloudevent/partials/storage/storage-on-object-metadata-updated.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {DeepPartial, MockCloudEventPartials} from '../../types'; -import {CloudEvent, CloudFunction, storage} from 'firebase-functions/v2'; -import {FILENAME, getEventFilters, getEventType} from '../helpers'; -import {getStorageObjectData} from './storage-data'; - -export const storageOnObjectMetadataUpdated: - MockCloudEventPartials = { - generatePartial( - cloudFunction: CloudFunction): DeepPartial> { - const bucket = getEventFilters(cloudFunction)?.bucket || 'bucket_name'; - const source = `//storage.googleapis.com/projects/_/buckets/${bucket}`; - const subject = `objects/__STORAGE_FILENAME__`; - - return { - source, - subject, - data: getStorageObjectData(bucket, FILENAME, 1), - }; - }, - match(cloudFunction: CloudFunction): boolean { - return getEventType(cloudFunction) === 'google.cloud.storage.object.v1.metadataUpdated'; - }, -}; diff --git a/src/cloudevent/types.ts b/src/cloudevent/types.ts index ae8e990..4ae593c 100644 --- a/src/cloudevent/types.ts +++ b/src/cloudevent/types.ts @@ -1,14 +1,16 @@ -import {CloudEvent, CloudFunction} from 'firebase-functions/v2'; +import { CloudEvent, CloudFunction } from 'firebase-functions/v2'; export type DeepPartial = { - [Key in keyof T]?: T[Key] extends object ? DeepPartial : T[Key] + [Key in keyof T]?: T[Key] extends object ? DeepPartial : T[Key]; }; -type MockCloudEventPartialFunction = - (cloudFunction: CloudFunction) => DeepPartial>; -type MockCloudEventMatchFunction = - (cloudFunction: CloudFunction) => boolean; +type MockCloudEventPartialFunction> = ( + cloudFunction: CloudFunction +) => DeepPartial; +type MockCloudEventMatchFunction> = ( + cloudFunction: CloudFunction +) => boolean; -export interface MockCloudEventPartials { +export interface MockCloudEventPartials> { generatePartial: MockCloudEventPartialFunction; match: MockCloudEventMatchFunction; } diff --git a/src/main.ts b/src/main.ts index c55616b..142f2ee 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,24 +20,16 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { - CloudFunction as CloudFunctionV1, -} from 'firebase-functions'; +import { CloudFunction as CloudFunctionV1 } from 'firebase-functions'; import { CloudFunction as CloudFunctionV2, + CloudEvent, } from 'firebase-functions/v2'; -import { - wrapV1, - WrappedFunction, - WrappedScheduledFunction, -} from './v1'; +import { wrapV1, WrappedFunction, WrappedScheduledFunction } from './v1'; -import { - wrapV2, - WrappedV2Function, -} from './v2'; +import { wrapV2, WrappedV2Function } from './v2'; // Re-exporting V1 (to reduce breakage) export { @@ -53,20 +45,20 @@ export { } from './v1'; // V2 Exports -export { - WrappedV2Function, -} from './v2'; - -type UnknownCloudFunction = CloudFunctionV1 | CloudFunctionV2; - -export function wrap(cloudFunction: CloudFunctionV1): WrappedScheduledFunction | WrappedFunction; -export function wrap(cloudFunction: CloudFunctionV2): WrappedV2Function; +export { WrappedV2Function } from './v2'; export function wrap( - cloudFunction: UnknownCloudFunction -): WrappedScheduledFunction | WrappedFunction | WrappedV2Function { - if (isV2CloudFunction(cloudFunction)) { - return wrapV2(cloudFunction as CloudFunctionV2); + cloudFunction: CloudFunctionV1 +): WrappedScheduledFunction | WrappedFunction; +export function wrap>( + cloudFunction: CloudFunctionV2 +): WrappedV2Function; + +export function wrap>( + cloudFunction: CloudFunctionV1 | CloudFunctionV2 +): WrappedScheduledFunction | WrappedFunction | WrappedV2Function { + if (isV2CloudFunction(cloudFunction)) { + return wrapV2(cloudFunction as CloudFunctionV2); } return wrapV1(cloudFunction as CloudFunctionV1); } @@ -80,6 +72,8 @@ export function wrap( *
  • V2 CloudFunction.run is always a unary function * @return True iff the CloudFunction is a V2 function. */ -function isV2CloudFunction(cloudFunction: UnknownCloudFunction) { +function isV2CloudFunction>( + cloudFunction: any +): cloudFunction is CloudFunctionV2 { return cloudFunction.length === 1 && cloudFunction?.run?.length === 1; } diff --git a/src/v1.ts b/src/v1.ts index 96b192f..5436ba9 100644 --- a/src/v1.ts +++ b/src/v1.ts @@ -20,7 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import {has, merge, random, get} from 'lodash'; +import { has, merge, random, get } from 'lodash'; import { CloudFunction, @@ -93,8 +93,8 @@ export type ContextOptions = EventContextOptions | CallableContextOptions; /** A function that can be called with test data and optional override values for the event context. * It will subsequently invoke the cloud function it wraps with the provided test data and a generated event context. */ -export type WrappedFunction = ( - data: any, +export type WrappedFunction = ( + data: T, options?: ContextOptions ) => any | Promise; @@ -108,7 +108,7 @@ export type WrappedScheduledFunction = ( /** Takes a cloud function to be tested, and returns a WrappedFunction which can be called in test code. */ export function wrapV1( cloudFunction: CloudFunction -): WrappedScheduledFunction | WrappedFunction { +): WrappedScheduledFunction | WrappedFunction { if (!has(cloudFunction, '__trigger')) { throw new Error( 'Wrap can only be called on functions written with the firebase-functions SDK.' @@ -150,7 +150,7 @@ export function wrapV1( const isCallableFunction = get(cloudFunction, '__trigger.labels.deployment-callable') === 'true'; - let wrapped: WrappedFunction = (data: T, options: ContextOptions) => { + let wrapped: WrappedFunction = (data: T, options: ContextOptions) => { // Although in Typescript we require `options` some of our JS samples do not pass it. options = options || {}; let context; @@ -264,7 +264,7 @@ function _makeDefaultContext( triggerParams = _extractFirestoreDocumentParams(eventResource, data); } } - const params = {...triggerParams, ...optionsParams}; + const params = { ...triggerParams, ...optionsParams }; const defaultContext: EventContext = { eventId: _makeEventId(), diff --git a/src/v2.ts b/src/v2.ts index 868fb2f..3140c3b 100644 --- a/src/v2.ts +++ b/src/v2.ts @@ -20,29 +20,25 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { - CloudFunction, - CloudEvent, -} from 'firebase-functions/v2'; +import { CloudFunction, CloudEvent } from 'firebase-functions/v2'; -import {generateCombinedCloudEvent} from './cloudevent/generate'; -import {DeepPartial} from './cloudevent/types'; +import { generateCombinedCloudEvent } from './cloudevent/generate'; +import { DeepPartial } from './cloudevent/types'; /** A function that can be called with test data and optional override values for {@link CloudEvent} * It will subsequently invoke the cloud function it wraps with the provided {@link CloudEvent} */ -export type WrappedV2Function = ( - cloudEventPartial?: DeepPartial +export type WrappedV2Function> = ( + cloudEventPartial?: DeepPartial ) => any | Promise; /** * Takes a v2 cloud function to be tested, and returns a {@link WrappedV2Function} * which can be called in test code. */ -export function wrapV2( +export function wrapV2>( cloudFunction: CloudFunction -): WrappedV2Function { - +): WrappedV2Function { if (cloudFunction?.__endpoint?.callableTrigger) { throw new Error( 'Wrap function is not available for callableTriggers functions.' @@ -59,8 +55,11 @@ export function wrapV2( throw new Error('This function can only wrap V2 CloudFunctions.'); } - return (cloudEventPartial?: DeepPartial) => { - const cloudEvent = generateCombinedCloudEvent(cloudFunction, cloudEventPartial); + return (cloudEventPartial?: DeepPartial) => { + const cloudEvent = generateCombinedCloudEvent( + cloudFunction, + cloudEventPartial + ); return cloudFunction.run(cloudEvent); }; }