I'm having trouble setting up a webhook endpoint API directly from RevenueCat's documentation.
My code is almost exactly like from the documentation so I don't know why this error is being triggered, and I'm not experienced enough with this kind of stuff to fix the issue. Here is the error I'm getting:
(parameter) res: functions.Response<any>
Argument of type '(req: Request, res: Response<any>) => Response<any> | Promise<void | Response<any>>' is not assignable to parameter of type '(req: Request, resp: Response<any>) => void | Promise<void>'.
Type 'Response<any> | Promise<void | Response<any>>' is not assignable to type 'void | Promise<void>'.
Type 'Response<any>' is not assignable to type 'void | Promise<void>'.
Type 'Response<any>' is missing the following properties from type 'Promise<void>': then, catch, finally, [Symbol.toStringTag]ts(2345)
Honestly, I'm not sure what its asking me to change. Any ideas? And here is my code:
import * as functions from 'firebase-functions'
import { PubSub } from '@google-cloud/pubsub'
const pubsubClient = new PubSub({projectId: '<PROJ_ID>'})
function isAuthorized(req: functions.https.Request) {
// Check authorization header
if (!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) {
return false
}
const authToken = req.headers.authorization.split('Bearer ')[1]
if (authToken !== '<MY_AUTH_TOKEN>') {
return false
}
return true
}
// Respond to incoming message
export const revenueCatApi = functions.https.onRequest((req, res) => { // *** ERROR DETECTED HERE
// Only allow POST request
if (req.method !== 'POST') {
return res.status(403).send('Forbidden')
}
// Make sure the auth key matches what we set in the Revenue Cat dashboard
if (!isAuthorized(req)) {
return res.status(401).send('Unauthorized')
}
const rc = req.body as RCEvent
var topic: RCTopic = ''
switch (rc.event.type) {
case 'INITIAL_PURCHASE':
topic = 'rc-initial-purchase'
break
case 'NON_RENEWING_PURCHASE':
topic = 'rc-non-renewing-purchase'
break
case 'RENEWAL':
topic = 'rc-renewal'
break
case 'PRODUCT_CHANGE':
topic = 'rc-product-change'
break
case 'CANCELLATION':
topic = 'rc-cancellation'
break
case 'BILLING_ISSUE':
topic = 'rc-billing-issue'
break
case 'SUBSCRIBER_ALIAS':
topic = 'rc-subscriber-alias'
break
default:
console.log('Unhandled event type: ', rc.event.type)
return res.sendStatus(200)
}
// Set the pub/sub data to the event body
const dataBuffer = Buffer.from(JSON.stringify(rc))
// Publishes a message
return pubsubClient.topic(topic)
.publish(dataBuffer)
.then(() => res.sendStatus(200))
.catch(err => {
console.error(err)
res.sendStatus(500)
return Promise.reject(err)
})
})
exports.handleInitialPurchase = functions.pubsub
.topic('rc-initial-purchase')
.onPublish(async (message, context) => {
...
})
/* Other pubsub functions below */
RCEvent:
interface RCEvent {
api_version: string
event: {
aliases: string[]
app_id: string
app_user_id: string
country_code: string
currency: string
entitlement_id: string
entitlement_ids: string[]
environment: string
event_timestamp_ms: number
expiration_at_ms: number
id: string
is_family_share: boolean
offer_code?: string
original_app_user_id: string
original_transaction_id: string
period_type: string
presented_offering_id: string
price: number
price_in_purchased_currency: number
product_id: string
purchased_at_ms: number
store: string
subscriber_attributes: any
takehome_percentage: number
transaction_id: string
type: string
}
}
The error message is telling you that TypeScript has determined that the signature of your function is this:
(req: Request, res: Response<any>) => Response<any> | Promise<void | Response<any>>
That means it takes a Request and Response as arguments, and can return either one of Response<any>
or Promise<void | Response<any>>
. That's not compatible with the requirement that it return only void
or Promise<void>
.
Your function possibly returns three things:
return res.status(403).send('Forbidden')
return res.status(401).send('Unauthorized')
return pubsubClient.topic(topic)
The first two things you are not really trying to return. You are just trying to send a response and end early. The third thing is a promise.
Don't return the result of res.status(403).send('Forbidden')
. Just return null if you want to terminate the function early without doing any further work.
res.status(403).send('Forbidden')
return null
Do this for both of the returns where you have no promise to wait on. This will make your function state that it only returns a promise or null, which is compatible with the TypeScript requirements for the function.