feat(webhook): add webhook application
This commit is contained in:
8
packages/backend/src/apps/webhook/assets/favicon.svg
Normal file
8
packages/backend/src/apps/webhook/assets/favicon.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 48 48" width="48px" height="48px"><g id="surface56721297">
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,12.156863%,32.156864%);fill-opacity:1;" d="M 35 37 C 32.800781 37 31 35.199219 31 33 C 31 30.800781 32.800781 29 35 29 C 37.199219 29 39 30.800781 39 33 C 39 35.199219 37.199219 37 35 37 Z M 35 37 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,12.156863%,32.156864%);fill-opacity:1;" d="M 35 43 C 32 43 29.101562 41.601562 27.199219 39.300781 L 30.300781 36.800781 C 31.398438 38.199219 33.199219 39.101562 35 39.101562 C 38.300781 39.101562 41 36.398438 41 33.101562 C 41 29.800781 38.300781 27.101562 35 27.101562 C 34 27.101562 33 27.398438 32.101562 27.800781 L 30.398438 28.800781 L 23.300781 16 L 26.800781 14.101562 L 32.101562 23.5 C 33.101562 23.199219 34.101562 23 35.101562 23 C 40.601562 23 45.101562 27.5 45.101562 33 C 45.101562 38.5 40.5 43 35 43 Z M 35 43 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,12.156863%,32.156864%);fill-opacity:1;" d="M 14 43 C 8.5 43 4 38.5 4 33 C 4 28.398438 7.101562 24.5 11.5 23.300781 L 12.5 27.199219 C 9.898438 27.898438 8 30.300781 8 33 C 8 36.300781 10.699219 39 14 39 C 17.300781 39 20 36.300781 20 33 L 20 31 L 35 31 L 35 35 L 23.800781 35 C 22.898438 39.601562 18.800781 43 14 43 Z M 14 43 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,34.901962%,96.862745%);fill-opacity:1;" d="M 14 37 C 11.800781 37 10 35.199219 10 33 C 10 30.800781 11.800781 29 14 29 C 16.199219 29 18 30.800781 18 33 C 18 35.199219 16.199219 37 14 37 Z M 14 37 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,12.156863%,32.156864%);fill-opacity:1;" d="M 25 19 C 22.800781 19 21 17.199219 21 15 C 21 12.800781 22.800781 11 25 11 C 27.199219 11 29 12.800781 29 15 C 29 17.199219 27.199219 19 25 19 Z M 25 19 "/>
|
||||
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,34.901962%,96.862745%);fill-opacity:1;" d="M 15.699219 34 L 12.300781 32 L 18.199219 22.300781 C 16.199219 20.398438 15 17.800781 15 15 C 15 9.5 19.5 5 25 5 C 30.5 5 35 9.5 35 15 C 35 15.898438 34.898438 16.699219 34.699219 17.5 L 30.800781 16.5 C 30.898438 16 31 15.5 31 15 C 31 11.699219 28.300781 9 25 9 C 21.699219 9 19 11.699219 19 15 C 19 17.101562 20.101562 19 21.898438 20.101562 L 23.601562 21.101562 Z M 15.699219 34 "/>
|
||||
</g></svg>
|
After Width: | Height: | Size: 2.3 KiB |
5
packages/backend/src/apps/webhook/auth/index.ts
Normal file
5
packages/backend/src/apps/webhook/auth/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import verifyWebhook from './verify-webhook';
|
||||
|
||||
export default {
|
||||
verifyWebhook,
|
||||
};
|
7
packages/backend/src/apps/webhook/auth/verify-webhook.ts
Normal file
7
packages/backend/src/apps/webhook/auth/verify-webhook.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { IGlobalVariable } from '@automatisch/types';
|
||||
|
||||
const verifyWebhook = async ($: IGlobalVariable) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
export default verifyWebhook;
|
0
packages/backend/src/apps/webhook/index.d.ts
vendored
Normal file
0
packages/backend/src/apps/webhook/index.d.ts
vendored
Normal file
16
packages/backend/src/apps/webhook/index.ts
Normal file
16
packages/backend/src/apps/webhook/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import defineApp from '../../helpers/define-app';
|
||||
import auth from './auth';
|
||||
import triggers from './triggers';
|
||||
|
||||
export default defineApp({
|
||||
name: 'Webhook',
|
||||
key: 'webhook',
|
||||
iconUrl: '{BASE_URL}/apps/webhook/assets/favicon.svg',
|
||||
authDocUrl: 'https://automatisch.io/docs/apps/webhook/connection',
|
||||
supportsConnections: false,
|
||||
baseUrl: '',
|
||||
apiBaseUrl: '',
|
||||
primaryColor: '0059F7',
|
||||
auth,
|
||||
triggers,
|
||||
});
|
@@ -0,0 +1,20 @@
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import defineTrigger from '../../../../helpers/define-trigger';
|
||||
|
||||
export default defineTrigger({
|
||||
name: 'Catch raw webhook',
|
||||
key: 'catchRawWebhook',
|
||||
type: 'webhook',
|
||||
description: 'Triggers when the webhook receives a request.',
|
||||
|
||||
async testRun($) {
|
||||
if (!isEmpty($.lastExecutionStep?.dataOut)) {
|
||||
$.pushTriggerItem({
|
||||
raw: $.lastExecutionStep.dataOut,
|
||||
meta: {
|
||||
internalId: '',
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
3
packages/backend/src/apps/webhook/triggers/index.ts
Normal file
3
packages/backend/src/apps/webhook/triggers/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import catchRawWebhook from './catch-raw-webhook';
|
||||
|
||||
export default [catchRawWebhook];
|
@@ -13,18 +13,19 @@ export default async (request: IRequest, response: Response) => {
|
||||
.findById(request.params.flowId)
|
||||
.throwIfNotFound();
|
||||
|
||||
if (!flow.active) {
|
||||
return response.send(404);
|
||||
}
|
||||
|
||||
const triggerStep = await flow.getTriggerStep();
|
||||
const triggerCommand = await triggerStep.getTriggerCommand();
|
||||
const app = await triggerStep.getApp();
|
||||
const isWebhookApp = app.key === 'webhook';
|
||||
|
||||
if (triggerCommand.type !== 'webhook') {
|
||||
return response.send(404);
|
||||
if (!flow.active && !isWebhookApp) {
|
||||
return response.sendStatus(404);
|
||||
}
|
||||
|
||||
if (triggerCommand.type !== 'webhook') {
|
||||
return response.sendStatus(404);
|
||||
}
|
||||
|
||||
const app = await triggerStep.getApp();
|
||||
|
||||
if (app.auth.verifyWebhook) {
|
||||
const $ = await globalVariable({
|
||||
@@ -42,8 +43,20 @@ export default async (request: IRequest, response: Response) => {
|
||||
}
|
||||
}
|
||||
|
||||
// in case trigger type is 'webhook'
|
||||
let payload = request.body;
|
||||
|
||||
// in case it's our built-in generic webhook trigger
|
||||
if (isWebhookApp) {
|
||||
payload = {
|
||||
headers: request.headers,
|
||||
body: request.body,
|
||||
query: request.query,
|
||||
}
|
||||
}
|
||||
|
||||
const triggerItem: ITriggerItem = {
|
||||
raw: request.body,
|
||||
raw: payload,
|
||||
meta: {
|
||||
internalId: await bcrypt.hash(request.rawBody, 1),
|
||||
},
|
||||
|
@@ -342,6 +342,7 @@ type Step {
|
||||
key: String
|
||||
appKey: String
|
||||
iconUrl: String
|
||||
webhookUrl: String
|
||||
type: StepEnumType
|
||||
parameters: JSONObject
|
||||
connection: Connection
|
||||
|
@@ -77,6 +77,7 @@ const globalVariable = async (
|
||||
id: execution?.id,
|
||||
testRun,
|
||||
},
|
||||
lastExecutionStep: (await step?.getLastExecutionStep())?.toJSON(),
|
||||
triggerOutput: {
|
||||
data: [],
|
||||
},
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { URL } from 'node:url';
|
||||
import { QueryContext, ModelOptions } from 'objection';
|
||||
import type { IJSONObject, IStep } from '@automatisch/types';
|
||||
import Base from './base';
|
||||
import App from './app';
|
||||
import Flow from './flow';
|
||||
import Connection from './connection';
|
||||
import ExecutionStep from './execution-step';
|
||||
import type { IJSONObject, IStep } from '@automatisch/types';
|
||||
import Telemetry from '../helpers/telemetry';
|
||||
import appConfig from '../config/app';
|
||||
|
||||
@@ -46,7 +47,7 @@ class Step extends Base {
|
||||
};
|
||||
|
||||
static get virtualAttributes() {
|
||||
return ['iconUrl'];
|
||||
return ['iconUrl', 'webhookUrl'];
|
||||
}
|
||||
|
||||
static relationMappings = () => ({
|
||||
@@ -82,6 +83,13 @@ class Step extends Base {
|
||||
return `${appConfig.baseUrl}/apps/${this.appKey}/assets/favicon.svg`;
|
||||
}
|
||||
|
||||
get webhookUrl() {
|
||||
if (this.appKey !== 'webhook') return null;
|
||||
|
||||
const url = new URL(`/webhooks/${this.flowId}`, appConfig.webhookUrl);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
async $afterInsert(queryContext: QueryContext) {
|
||||
await super.$afterInsert(queryContext);
|
||||
Telemetry.stepCreated(this);
|
||||
@@ -106,6 +114,14 @@ class Step extends Base {
|
||||
return await App.findOneByKey(this.appKey);
|
||||
}
|
||||
|
||||
async getLastExecutionStep() {
|
||||
const lastExecutionStep = await this.$relatedQuery('executionSteps')
|
||||
.orderBy('created_at', 'desc')
|
||||
.first();
|
||||
|
||||
return lastExecutionStep;
|
||||
}
|
||||
|
||||
async getNextStep() {
|
||||
const flow = await this.$relatedQuery('flow');
|
||||
|
||||
|
@@ -3,6 +3,8 @@ import webhookHandler from '../controllers/webhooks/handler';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get('/:flowId', webhookHandler);
|
||||
router.put('/:flowId', webhookHandler);
|
||||
router.post('/:flowId', webhookHandler);
|
||||
|
||||
export default router;
|
||||
|
15
packages/types/index.d.ts
vendored
15
packages/types/index.d.ts
vendored
@@ -54,6 +54,7 @@ export interface IStep {
|
||||
key?: string;
|
||||
appKey?: string;
|
||||
iconUrl: string;
|
||||
webhookUrl: string;
|
||||
type: 'action' | 'trigger';
|
||||
connectionId?: string;
|
||||
status: string;
|
||||
@@ -180,23 +181,16 @@ export interface IDynamicData {
|
||||
|
||||
export interface IAuth {
|
||||
generateAuthUrl?($: IGlobalVariable): Promise<void>;
|
||||
verifyCredentials($: IGlobalVariable): Promise<void>;
|
||||
isStillVerified($: IGlobalVariable): Promise<boolean>;
|
||||
verifyCredentials?($: IGlobalVariable): Promise<void>;
|
||||
isStillVerified?($: IGlobalVariable): Promise<boolean>;
|
||||
refreshToken?($: IGlobalVariable): Promise<void>;
|
||||
verifyWebhook?($: IGlobalVariable): Promise<boolean>;
|
||||
isRefreshTokenRequested?: boolean;
|
||||
fields: IField[];
|
||||
fields?: IField[];
|
||||
authenticationSteps?: IAuthenticationStep[];
|
||||
reconnectionSteps?: IAuthenticationStep[];
|
||||
}
|
||||
|
||||
export interface IService {
|
||||
authenticationClient?: IAuthentication;
|
||||
triggers?: any;
|
||||
actions?: any;
|
||||
data?: any;
|
||||
}
|
||||
|
||||
export interface ITriggerOutput {
|
||||
data: ITriggerItem[];
|
||||
error?: IJSONObject;
|
||||
@@ -300,6 +294,7 @@ export type IGlobalVariable = {
|
||||
id: string;
|
||||
testRun: boolean;
|
||||
};
|
||||
lastExecutionStep?: IExecutionStep;
|
||||
webhookUrl?: string;
|
||||
triggerOutput?: ITriggerOutput;
|
||||
actionOutput?: IActionOutput;
|
||||
|
Reference in New Issue
Block a user