Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions integrations/dropbox/src/webhook-events/oauth/wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const _redirectToDropboxHandler: WizardHandler = async (props) => {
const _getOAuthRedirectUri = (ctx?: bp.Context) => oauthWizard.getWizardStepUrl('oauth-callback', ctx).toString()

const _oauthCallbackHandler: WizardHandler = async (props) => {
const { responses, query, client, ctx, logger } = props
const { responses, query, client, ctx, logger, setIntegrationIdentifier } = props

const oauthError = query.get('error')
const oauthErrorDescription = query.get('error_description')
Expand Down Expand Up @@ -100,7 +100,7 @@ const _oauthCallbackHandler: WizardHandler = async (props) => {
await oauthClient.processAuthorizationCode(authorizationCode, redirectUri)
logger.forBot().info('Successfully exchanged authorization code for refresh token')

await client.configureIntegration({ identifier: ctx.webhookId })
setIntegrationIdentifier(ctx.webhookId)

return responses.endWizard({
success: true,
Expand Down
3 changes: 2 additions & 1 deletion integrations/hubspot/src/webhook/handlers/oauth-wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ const _oauthCallbackStep: oauthWizard.WizardStepHandler<bp.HandlerProps> = async
logger,
query,
responses,
setIntegrationIdentifier,
}) => {
const error = query.get('error')
if (error) {
Expand All @@ -115,7 +116,7 @@ const _oauthCallbackStep: oauthWizard.WizardStepHandler<bp.HandlerProps> = async

const hsClient = new HubspotClient({ accessToken: credentials.accessToken, client, ctx, logger })
const hubId = await hsClient.getHubId()
await client.configureIntegration({ identifier: hubId })
setIntegrationIdentifier(hubId)

if (enableHitl) {
return responses.redirectToStep('hitl-inbox-id')
Expand Down
1 change: 1 addition & 0 deletions integrations/linear/src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export const handler: bp.IntegrationProps['handler'] = async (props) => {
userId: userId as string, // TODO: fix this
})
}
return
}

const _safeCheckWebhookSignature = ({
Expand Down
11 changes: 8 additions & 3 deletions integrations/linear/src/misc/linear.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RuntimeError, z } from '@botpress/sdk'
import { OAUTH_IDENTIFIER_HEADER, Response, RuntimeError, z } from '@botpress/sdk'
import { LinearClient } from '@linear/sdk'
import axios from 'axios'
import queryString from 'query-string'
Expand Down Expand Up @@ -269,7 +269,7 @@ export const registerWebhook = async ({
logger.forBot().info('Linear webhook registered successfully.')
}

export const handleOauth = async ({ req, ctx, client, logger }: bp.HandlerProps) => {
export const handleOauth = async ({ req, ctx, client, logger }: bp.HandlerProps): Promise<Response> => {
const linearOauthClient = new LinearOauthClient()

const query = queryString.parse(req.query)
Expand All @@ -290,7 +290,7 @@ export const handleOauth = async ({ req, ctx, client, logger }: bp.HandlerProps)

const linearClient = new LinearClient({ accessToken: credentials.accessToken })
const organization = await linearClient.organization
await client.configureIntegration({ identifier: organization.id, scheduleRegisterCall: 'monthly' })
await client.configureIntegration({ scheduleRegisterCall: 'monthly' })

const webhookUrl = `${process.env.BP_WEBHOOK_URL}/${ctx.webhookId}`
try {
Expand All @@ -299,4 +299,9 @@ export const handleOauth = async ({ req, ctx, client, logger }: bp.HandlerProps)
const errorMessage = thrown instanceof Error ? thrown.message : String(thrown)
logger.forBot().warn('Failed to register webhook:', errorMessage)
}

return {
status: 200,
headers: { [OAUTH_IDENTIFIER_HEADER]: organization.id },
}
}
13 changes: 9 additions & 4 deletions integrations/messenger/src/webhook/handlers/oauth/wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,14 @@ const _selectPageHandler: WizardHandler = async ({ responses, client, ctx, logge
})
}

const _setupHandler: WizardHandler = async ({ responses, client, ctx, logger, selectedChoice }) => {
const _setupHandler: WizardHandler = async ({
responses,
client,
ctx,
logger,
selectedChoice,
setIntegrationIdentifier,
}) => {
const { userToken } = await getMetaClientCredentials({ configType: 'oauth', client, ctx }).catch(() => ({
userToken: undefined,
}))
Expand Down Expand Up @@ -166,9 +173,7 @@ const _setupHandler: WizardHandler = async ({ responses, client, ctx, logger, se

logger.forBot().info(`Successfully subscribed to webhooks for OAuth page ${pageId}`)

await client.configureIntegration({
identifier: pageId,
})
setIntegrationIdentifier(pageId)

return responses.displayButtons({
pageTitle: 'Configuration Complete',
Expand Down
4 changes: 2 additions & 2 deletions integrations/sunco/src/wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ const _addToChannels: WizardHandler = async (props) => {
}

const _selectIdentifier: WizardHandler = async (props) => {
const { responses, client, ctx, selectedChoice } = props
const { responses, client, ctx, selectedChoice, setIntegrationIdentifier } = props

if (selectedChoice) {
await client.configureIntegration({ identifier: selectedChoice })
setIntegrationIdentifier(selectedChoice)
return responses.redirectToStep('end')
}

Expand Down
6 changes: 2 additions & 4 deletions integrations/whatsapp/src/webhook/handlers/oauth/wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ const _doStepVerifyNumber = async (
}

const _doStepWrapUp: WizardHandler = async (props) => {
const { responses, client, ctx, logger } = props
const { responses, client, ctx, logger, setIntegrationIdentifier } = props
const credentials = await _getCredentialsState(client, ctx)
const { accessToken, wabaId, defaultBotPhoneNumberId } = credentials
if (!accessToken) {
Expand All @@ -215,9 +215,7 @@ const _doStepWrapUp: WizardHandler = async (props) => {
throw new Error(PHONE_NUMBER_ID_UNAVAILABLE_ERROR)
}
const oauthClient = new MetaOauthClient(logger)
await client.configureIntegration({
identifier: wabaId,
})
setIntegrationIdentifier(wabaId)
await oauthClient.registerNumber(defaultBotPhoneNumberId, accessToken)
await oauthClient.subscribeToWebhooks(wabaId, accessToken)

Expand Down
4 changes: 2 additions & 2 deletions integrations/zendesk/src/oauth/wizard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ const _resetHandler: WizardHandler = async (props) => {
}

const _oauthCallbackHandler: WizardHandler = async (props) => {
const { responses, query, client, ctx } = props
const { responses, query, client, ctx, setIntegrationIdentifier } = props
const authorizationCode = query.get('code')
if (!authorizationCode) {
return responses.endWizard({
Expand All @@ -146,7 +146,7 @@ const _oauthCallbackHandler: WizardHandler = async (props) => {
const newCredentials = { ...credentials, accessToken }
await _patchCredentialsState(client, ctx, newCredentials)

await client.configureIntegration({ identifier: ctx.webhookId })
setIntegrationIdentifier(ctx.webhookId)

return responses.redirectToStep('end')
}
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@apidevtools/json-schema-ref-parser": "^11.7.0",
"@botpress/chat": "0.5.5",
"@botpress/client": "1.44.0",
"@botpress/sdk": "6.9.1",
"@botpress/sdk": "6.9.2",
"@bpinternal/const": "^0.1.0",
"@bpinternal/tunnel": "^0.1.1",
"@bpinternal/verel": "^0.2.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/templates/empty-bot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"private": true,
"dependencies": {
"@botpress/client": "1.44.0",
"@botpress/sdk": "6.9.1"
"@botpress/sdk": "6.9.2"
},
"devDependencies": {
"@types/node": "^22.16.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/templates/empty-integration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"private": true,
"dependencies": {
"@botpress/client": "1.44.0",
"@botpress/sdk": "6.9.1"
"@botpress/sdk": "6.9.2"
},
"devDependencies": {
"@types/node": "^22.16.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/templates/empty-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"private": true,
"dependencies": {
"@botpress/sdk": "6.9.1"
"@botpress/sdk": "6.9.2"
},
"devDependencies": {
"@types/node": "^22.16.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/templates/hello-world/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"private": true,
"dependencies": {
"@botpress/client": "1.44.0",
"@botpress/sdk": "6.9.1"
"@botpress/sdk": "6.9.2"
},
"devDependencies": {
"@types/node": "^22.16.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/templates/webhook-message/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"private": true,
"dependencies": {
"@botpress/client": "1.44.0",
"@botpress/sdk": "6.9.1",
"@botpress/sdk": "6.9.2",
"axios": "^1.6.8"
},
"devDependencies": {
Expand Down
8 changes: 8 additions & 0 deletions packages/common/src/oauth-wizard/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ export type WizardStepInputProps = {
inputValue?: string
formValues?: Record<string, string | number | boolean>
query: URLSearchParams
/**
* Records the integration identifier (e.g. an account or workspace id) by
* attaching the `x-bp-integration-identifier` response header to whatever
* Response this wizard step ultimately returns. The Botpress backend reads
* this header on the OAuth round-trip and treats it as proof that the
* integration owns the identifier, replacing any previous owner.
*/
setIntegrationIdentifier: (identifier: string) => void
responses: {
redirectToStep: (stepId: string) => Response
redirectToExternalUrl: (url: string) => Response
Expand Down
15 changes: 14 additions & 1 deletion packages/common/src/oauth-wizard/wizard-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,19 @@ export class OAuthWizard<THandlerProps extends types.HandlerProps> {
}
}

return await step.handler({
const extraHeaders: Record<string, string> = {}

const response = await step.handler({
...this._handlerProps,
query: searchParams,
selectedChoice: searchParams.get(consts.CHOICE_PARAM) ?? undefined,
selectedChoices:
searchParams.getAll(consts.CHOICE_PARAM).length > 0 ? searchParams.getAll(consts.CHOICE_PARAM) : undefined,
inputValue: searchParams.get(consts.INPUT_PARAM) ?? undefined,
formValues: Object.keys(formValues).length > 0 ? formValues : undefined,
setIntegrationIdentifier(identifier: string) {
extraHeaders[sdk.OAUTH_IDENTIFIER_HEADER] = identifier
},
responses: {
displayButtons: ({ buttons, pageTitle, htmlOrMarkdownPageContents }) =>
htmlDialogs.generateButtonDialog({
Expand Down Expand Up @@ -141,6 +146,14 @@ export class OAuthWizard<THandlerProps extends types.HandlerProps> {
),
},
})

return {
...response,
headers: {
...response.headers,
...extraHeaders,
},
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@botpress/sdk",
"version": "6.9.1",
"version": "6.9.2",
"description": "Botpress SDK",
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
Expand Down
2 changes: 2 additions & 0 deletions packages/sdk/src/public-consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export const WELL_KNOWN_ATTRIBUTES = {
HIDDEN_IN_STUDIO: { bpActionHiddenInStudio: 'true' },
AWAIT_RETURN: { bpActionAwaitReturn: 'true' },
} as const

export const OAUTH_IDENTIFIER_HEADER = 'x-bp-integration-identifier'
12 changes: 6 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading