From e4cf79263b2e23d53c6c18cfa18bfc9b4d10ddeb Mon Sep 17 00:00:00 2001 From: Ben Beckford Date: Mon, 22 Jun 2026 00:01:04 -0700 Subject: [PATCH] feat: webhook workflow action --- packages/plugin-core/manifest.json | 28 +++++++++++++++++++ packages/plugin-core/src/index.d.ts | 2 ++ packages/plugin-core/src/index.ts | 22 +++++++++++++++ packages/plugin-sdk/src/host-functions.ts | 12 ++++++++ .../services/workflow-execution.service.ts | 15 ++++++++++ 5 files changed, 79 insertions(+) diff --git a/packages/plugin-core/manifest.json b/packages/plugin-core/manifest.json index 54642476b2..97e1add516 100644 --- a/packages/plugin-core/manifest.json +++ b/packages/plugin-core/manifest.json @@ -289,6 +289,34 @@ "required": ["albumIds"] } }, + { + "name": "assetDataWebhook", + "title": "Trigger Webhook", + "description": "POST asset data to any URL", + "types": ["AssetV1"], + "hostFunctions": true, + "schema": { + "type": "object", + "properties": { + "url": { + "type": "string", + "title": "URL", + "description": "Asset data will be POSTed to this URL as a JSON object" + }, + "headerName": { + "type": "string", + "title": "Header name", + "description": "The name of an additional header to include with the request (e.g. authentication)" + }, + "headerValue": { + "type": "string", + "title": "Header value", + "description": "The value of the additional header" + } + }, + "required": ["url"] + } + }, { "name": "noop1", "title": "DEV: Nested properties", diff --git a/packages/plugin-core/src/index.d.ts b/packages/plugin-core/src/index.d.ts index 107bcc7aa0..7a66e890f7 100644 --- a/packages/plugin-core/src/index.d.ts +++ b/packages/plugin-core/src/index.d.ts @@ -5,6 +5,7 @@ declare module 'extism:host' { createAlbum(ptr: PTR): I64; addAssetsToAlbum(ptr: PTR): I64; addAssetsToAlbums(ptr: PTR): I64; + httpRequest(ptr: PTR): I64; } } @@ -24,4 +25,5 @@ declare module 'main' { export function assetTimeline(): I32; export function assetTrash(): I32; export function assetAddToAlbums(): I32; + export function assetDataWebhook(): I32; } diff --git a/packages/plugin-core/src/index.ts b/packages/plugin-core/src/index.ts index fa956b8cec..006ddb915c 100644 --- a/packages/plugin-core/src/index.ts +++ b/packages/plugin-core/src/index.ts @@ -181,3 +181,25 @@ export const assetAddToAlbums = () => { return {}; }); }; + +export const assetDataWebhook = () => { + return wrapper( + ({ config, data, functions }) => { + let headers: Record = { + 'Content-Type': 'application/json', + }; + + if (config.headerName && config.headerValue) { + headers[config.headerName] = config.headerValue; + } + + functions.httpRequest(config.url, { + method: 'POST', + body: JSON.stringify(data.asset), + headers, + }); + + return {}; + }, + ); +}; diff --git a/packages/plugin-sdk/src/host-functions.ts b/packages/plugin-sdk/src/host-functions.ts index 281e27c83c..d0fd586cc8 100644 --- a/packages/plugin-sdk/src/host-functions.ts +++ b/packages/plugin-sdk/src/host-functions.ts @@ -13,6 +13,7 @@ declare module 'extism:host' { createAlbum(ptr: PTR): I64; addAssetsToAlbum(ptr: PTR): I64; addAssetsToAlbums(ptr: PTR): I64; + httpRequest(ptr: PTR): I64; } } @@ -33,6 +34,11 @@ type HostFunctionResult = type QueryParams any> = Parameters[0]; type AlbumSearchDto = QueryParams; +type HttpRequestOptions = { + method?: string; + headers?: Record; + body?: string; +}; export const hostFunctions = (authToken: string) => { const host = Host.getFunctions(); @@ -75,5 +81,11 @@ export const hostFunctions = (authToken: string) => { ), addAssetsToAlbums: ({ assetIds, albumIds }: AlbumsToAssets) => call('addAssetsToAlbums', authToken, [{ albumIds, assetIds }]), + httpRequest: (url: string, options?: HttpRequestOptions) => + call<[string, HttpRequestOptions | undefined], string>( + 'httpRequest', + authToken, + [url, options], + ), }; }; diff --git a/server/src/services/workflow-execution.service.ts b/server/src/services/workflow-execution.service.ts index 0a5f025fc1..3aef6893d7 100644 --- a/server/src/services/workflow-execution.service.ts +++ b/server/src/services/workflow-execution.service.ts @@ -74,12 +74,26 @@ export class WorkflowExecutionService extends BaseService { const addAssetsToAlbums = this.wrap<[dto: AlbumsAddAssetsDto]>((authDto, args) => albumService.addAssetsToAlbums(authDto, ...args), ); + const httpRequest = this.wrap< + [ + url: string, + options?: { + method?: string; + headers?: Record; + body?: string; + }, + ] + >(async (_, args) => { + const res = await fetch(...args); + return res.text(); + }); const functions = { searchAlbums, createAlbum, addAssetsToAlbum, addAssetsToAlbums, + httpRequest, }; const stubs: typeof functions = { @@ -87,6 +101,7 @@ export class WorkflowExecutionService extends BaseService { createAlbum: dummy, addAssetsToAlbum: dummy, addAssetsToAlbums: dummy, + httpRequest: dummy, }; const plugins = await this.pluginRepository.getForLoad();