diff --git a/spec/v2/providers/alerts/appDistribution.spec.ts b/spec/v2/providers/alerts/appDistribution.spec.ts index 5fb112daa..9b699bc62 100644 --- a/spec/v2/providers/alerts/appDistribution.spec.ts +++ b/spec/v2/providers/alerts/appDistribution.spec.ts @@ -97,6 +97,89 @@ describe('appDistribution', () => { }); }); + describe('onInAppfeedbackPublished', () => { + it('should create a function with alertType & appId', () => { + const func = appDistribution.onInAppFeedbackPublished(APPID, myHandler); + + expect(func.__endpoint).to.deep.equal({ + platform: 'gcfv2', + labels: {}, + eventTrigger: { + eventType: alerts.eventType, + eventFilters: { + ...APP_EVENT_FILTER, + alerttype: appDistribution.inAppFeedbackAlert, + }, + retry: false, + }, + }); + }); + + it('should create a function with opts', () => { + const func = appDistribution.onInAppFeedbackPublished( + { ...FULL_OPTIONS }, + myHandler + ); + + expect(func.__endpoint).to.deep.equal({ + ...FULL_ENDPOINT, + eventTrigger: { + eventType: alerts.eventType, + eventFilters: { + alerttype: appDistribution.inAppFeedbackAlert, + }, + retry: false, + }, + }); + }); + + it('should create a function with appid in opts', () => { + const func = appDistribution.onInAppFeedbackPublished( + { ...FULL_OPTIONS, appId: APPID }, + myHandler + ); + + expect(func.__endpoint).to.deep.equal({ + ...FULL_ENDPOINT, + eventTrigger: { + eventType: alerts.eventType, + eventFilters: { + ...APP_EVENT_FILTER, + alerttype: appDistribution.inAppFeedbackAlert, + }, + retry: false, + }, + }); + }); + + it('should create a function without opts or appId', () => { + const func = appDistribution.onInAppFeedbackPublished(myHandler); + + expect(func.__endpoint).to.deep.equal({ + platform: 'gcfv2', + labels: {}, + eventTrigger: { + eventType: alerts.eventType, + eventFilters: { + alerttype: appDistribution.inAppFeedbackAlert, + }, + retry: false, + }, + }); + }); + + it('should create a function with a run method', () => { + const func = appDistribution.onInAppFeedbackPublished( + APPID, + (event) => event + ); + + const res = func.run('input' as any); + + expect(res).to.equal('input'); + }); + }); + describe('getOptsAndApp', () => { it('should parse a string', () => { const [opts, appId] = appDistribution.getOptsAndApp(APPID); diff --git a/src/v2/providers/alerts/alerts.ts b/src/v2/providers/alerts/alerts.ts index 4cb0ac2de..556b2b77b 100644 --- a/src/v2/providers/alerts/alerts.ts +++ b/src/v2/providers/alerts/alerts.ts @@ -68,6 +68,7 @@ export type AlertType = | 'billing.planUpdate' | 'billing.automatedPlanUpdate' | 'appDistribution.newTesterIosDevice' + | 'appDistribution.inAppFeedback' | string; /** diff --git a/src/v2/providers/alerts/appDistribution.ts b/src/v2/providers/alerts/appDistribution.ts index c3f058cff..ffac2d43d 100644 --- a/src/v2/providers/alerts/appDistribution.ts +++ b/src/v2/providers/alerts/appDistribution.ts @@ -45,6 +45,36 @@ export interface NewTesterDevicePayload { testerDeviceIdentifier: string; } +/** + * The internal payload object for receiving in-app feedback from a tester. + * Payload is wrapped inside a `FirebaseAlertData` object. + */ +export interface InAppFeedbackPayload { + ['@type']: 'type.googleapis.com/google.events.firebase.firebasealerts.v1.AppDistroInAppFeedbackPayload'; + /** Resource name. Format: `projects/{project_number}/apps/{app_id}/releases/{release_id}/feedbackReports/{feedback_id}` */ + feedbackReport: string; + /** Name of the tester */ + testerName?: string; + /** Email of the tester */ + testerEmail: string; + /** + * Display version of the release. For an Android release, the display version + * is the `versionName`. For an iOS release, the display version is the + * `CFBundleShortVersionString`. + */ + displayVersion: string; + /** + * Build version of the release. For an Android release, the build version + * is the `versionCode`. For an iOS release, the build version is the + * `CFBundleVersion`. + */ + buildVersion: string; + /** Text entered by the tester */ + text: string; + /** URIs to download screenshot(s) */ + screenshotUris?: string[]; +} + /** * A custom CloudEvent for Firebase Alerts (with custom extension attributes). * @typeParam T - the data type for app distribution alerts that is wrapped in a `FirebaseAlertData` object. @@ -59,6 +89,8 @@ export interface AppDistributionEvent /** @internal */ export const newTesterIosDeviceAlert = 'appDistribution.newTesterIosDevice'; +/** @internal */ +export const inAppFeedbackAlert = 'appDistribution.inAppFeedback'; /** * Configuration for app distribution functions. @@ -234,6 +266,79 @@ export function onNewTesterIosDevicePublished( return func; } +/** + * Declares a function that can handle receiving new in-app feedback from a tester. + * @param handler - Event handler which is run every time new feedback is received. + * @returns A function that you can export and deploy. + */ +export function onInAppFeedbackPublished( + handler: ( + event: AppDistributionEvent + ) => any | Promise +): CloudFunction>; + +/** + * Declares a function that can handle receiving new in-app feedback from a tester. + * @param appId - A specific application the handler will trigger on. + * @param handler - Event handler which is run every time new feedback is received. + * @returns A function that you can export and deploy. + */ +export function onInAppFeedbackPublished( + appId: string, + handler: ( + event: AppDistributionEvent + ) => any | Promise +): CloudFunction>; + +/** + * Declares a function that can handle receiving new in-app feedback from a tester. + * @param opts - Options that can be set on the function. + * @param handler - Event handler which is run every time new feedback is received. + * @returns A function that you can export and deploy. + */ +export function onInAppFeedbackPublished( + opts: AppDistributionOptions, + handler: ( + event: AppDistributionEvent + ) => any | Promise +): CloudFunction>; + +/** + * Declares a function that can handle receiving new in-app feedback from a tester. + * @param appIdOrOptsOrHandler - A specific application, options, or an event-handling function. + * @param handler - Event handler which is run every time new feedback is received. + * @returns A function that you can export and deploy. + */ +export function onInAppFeedbackPublished( + appIdOrOptsOrHandler: + | string + | AppDistributionOptions + | (( + event: AppDistributionEvent + ) => any | Promise), + handler?: ( + event: AppDistributionEvent + ) => any | Promise +): CloudFunction> { + if (typeof appIdOrOptsOrHandler === 'function') { + handler = appIdOrOptsOrHandler as ( + event: AppDistributionEvent + ) => any | Promise; + appIdOrOptsOrHandler = {}; + } + + const [opts, appId] = getOptsAndApp(appIdOrOptsOrHandler); + + const func = (raw: CloudEvent) => { + return handler(raw as AppDistributionEvent); + }; + + func.run = handler; + func.__endpoint = getEndpointAnnotation(opts, inAppFeedbackAlert, appId); + + return func; +} + /** * Helper function to parse the function opts and appId. * @internal