@things-factory/integration-label-studio 10.0.0-beta.2 → 10.0.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -5,6 +5,7 @@ exports.registerWebhookHandler = registerWebhookHandler;
|
|
|
5
5
|
exports.unregisterWebhookHandler = unregisterWebhookHandler;
|
|
6
6
|
exports.clearWebhookHandlers = clearWebhookHandlers;
|
|
7
7
|
const tslib_1 = require("tslib");
|
|
8
|
+
require("koa-bodyparser");
|
|
8
9
|
const koa_router_1 = tslib_1.__importDefault(require("koa-router"));
|
|
9
10
|
const webhookRouter = new koa_router_1.default();
|
|
10
11
|
exports.webhookRouter = webhookRouter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../server/route/webhook.ts"],"names":[],"mappings":"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","sourcesContent":["import Koa from 'koa'\nimport Router from 'koa-router'\nimport { getRepository } from 'typeorm'\n\nconst webhookRouter = new Router()\n\n/**\n * Label Studio Webhook Event Types\n */\nexport enum WebhookAction {\n ANNOTATION_CREATED = 'ANNOTATION_CREATED',\n ANNOTATION_UPDATED = 'ANNOTATION_UPDATED',\n ANNOTATION_DELETED = 'ANNOTATION_DELETED',\n TASK_CREATED = 'TASK_CREATED',\n TASK_UPDATED = 'TASK_UPDATED',\n TASK_DELETED = 'TASK_DELETED',\n PROJECT_UPDATED = 'PROJECT_UPDATED'\n}\n\nexport interface WebhookPayload {\n action: WebhookAction\n project: {\n id: number\n title: string\n }\n task?: {\n id: number\n data: any\n annotations: any[]\n }\n annotation?: {\n id: number\n result: any[]\n completed_by: {\n id: number\n email: string\n }\n lead_time: number\n }\n}\n\n/**\n * Webhook handler function type\n * Applications can register custom handlers for any webhook action\n */\nexport type WebhookHandler = (payload: WebhookPayload, context: Koa.Context) => Promise<void>\n\n/**\n * Registry for custom webhook handlers\n * Multiple handlers can be registered per action\n */\nconst customHandlers: Map<WebhookAction, WebhookHandler[]> = new Map()\n\n/**\n * Register a custom webhook handler\n * Handlers are executed in registration order\n *\n * @param action - Webhook action to handle\n * @param handler - Handler function\n *\n * @example\n * registerWebhookHandler(WebhookAction.ANNOTATION_CREATED, async (payload, ctx) => {\n * console.log('Custom handler:', payload.annotation?.id)\n * // Store annotation in database\n * // Trigger ML training\n * // Send notifications\n * })\n */\nexport function registerWebhookHandler(action: WebhookAction, handler: WebhookHandler): void {\n if (!customHandlers.has(action)) {\n customHandlers.set(action, [])\n }\n customHandlers.get(action)!.push(handler)\n}\n\n/**\n * Unregister a webhook handler\n */\nexport function unregisterWebhookHandler(action: WebhookAction, handler: WebhookHandler): void {\n const handlers = customHandlers.get(action)\n if (handlers) {\n const index = handlers.indexOf(handler)\n if (index > -1) {\n handlers.splice(index, 1)\n }\n }\n}\n\n/**\n * Clear all custom handlers for an action\n */\nexport function clearWebhookHandlers(action?: WebhookAction): void {\n if (action) {\n customHandlers.delete(action)\n } else {\n customHandlers.clear()\n }\n}\n\n/**\n * Execute all registered handlers for an action\n */\nasync function executeCustomHandlers(action: WebhookAction, payload: WebhookPayload, ctx: Koa.Context): Promise<void> {\n const handlers = customHandlers.get(action)\n if (!handlers || handlers.length === 0) {\n return\n }\n\n // Execute all handlers in sequence\n for (const handler of handlers) {\n try {\n await handler(payload, ctx)\n } catch (error) {\n console.error(`[Webhook] Custom handler error for ${action}:`, error)\n // Continue executing other handlers even if one fails\n }\n }\n}\n\n/**\n * Handle annotation created event\n */\nasync function handleAnnotationCreated(payload: WebhookPayload) {\n console.log(`[Webhook] Annotation created:`, {\n projectId: payload.project.id,\n taskId: payload.task?.id,\n annotationId: payload.annotation?.id,\n completedBy: payload.annotation?.completed_by?.email\n })\n\n // TODO: Implement business logic\n // 1. Store annotation in Things-Factory database\n // 2. Trigger downstream processes (e.g., model training)\n // 3. Send notifications to stakeholders\n // 4. Update task status in external systems\n}\n\n/**\n * Handle annotation updated event\n */\nasync function handleAnnotationUpdated(payload: WebhookPayload) {\n console.log(`[Webhook] Annotation updated:`, {\n projectId: payload.project.id,\n annotationId: payload.annotation?.id\n })\n\n // TODO: Update annotation in database\n}\n\n/**\n * Handle annotation deleted event\n */\nasync function handleAnnotationDeleted(payload: WebhookPayload) {\n console.log(`[Webhook] Annotation deleted:`, {\n projectId: payload.project.id,\n annotationId: payload.annotation?.id\n })\n\n // TODO: Remove annotation from database\n}\n\n/**\n * Handle task created event\n */\nasync function handleTaskCreated(payload: WebhookPayload) {\n console.log(`[Webhook] Task created:`, {\n projectId: payload.project.id,\n taskId: payload.task?.id\n })\n\n // TODO: Store task reference\n}\n\n/**\n * Handle project updated event\n */\nasync function handleProjectUpdated(payload: WebhookPayload) {\n console.log(`[Webhook] Project updated:`, {\n projectId: payload.project.id,\n projectTitle: payload.project.title\n })\n\n // TODO: Update project metadata\n}\n\n/**\n * Main webhook endpoint\n * Label Studio will POST events here\n */\nwebhookRouter.post('/label-studio/webhook', async (ctx: Koa.Context) => {\n try {\n const payload = ctx.request.body as WebhookPayload\n\n console.log(`[Webhook] Received event: ${payload.action}`)\n\n // Execute default handlers first\n switch (payload.action) {\n case WebhookAction.ANNOTATION_CREATED:\n await handleAnnotationCreated(payload)\n break\n\n case WebhookAction.ANNOTATION_UPDATED:\n await handleAnnotationUpdated(payload)\n break\n\n case WebhookAction.ANNOTATION_DELETED:\n await handleAnnotationDeleted(payload)\n break\n\n case WebhookAction.TASK_CREATED:\n await handleTaskCreated(payload)\n break\n\n case WebhookAction.TASK_UPDATED:\n // Optional: handle task updates\n break\n\n case WebhookAction.TASK_DELETED:\n // Optional: handle task deletions\n break\n\n case WebhookAction.PROJECT_UPDATED:\n await handleProjectUpdated(payload)\n break\n\n default:\n console.warn(`[Webhook] Unknown action: ${payload.action}`)\n }\n\n // Execute custom handlers\n await executeCustomHandlers(payload.action, payload, ctx)\n\n ctx.status = 200\n ctx.body = { success: true }\n } catch (error) {\n console.error('[Webhook] Error processing webhook:', error)\n ctx.status = 500\n ctx.body = { error: error.message }\n }\n})\n\n/**\n * Webhook registration helper\n * Call this to register webhook with Label Studio\n */\nwebhookRouter.post('/label-studio/webhook/register', async (ctx: Koa.Context) => {\n try {\n const { projectId } = ctx.request.body as { projectId: number }\n\n // Get Things-Factory server URL\n const serverUrl = process.env.SERVER_URL || 'http://localhost:3000'\n const webhookUrl = `${serverUrl}/label-studio/webhook`\n\n // Register webhook using Label Studio API\n const { labelStudioApi } = await import('../utils/label-studio-api-client.js')\n\n const webhook = await labelStudioApi.createWebhook({\n project: projectId,\n url: webhookUrl,\n send_payload: true,\n send_for_all_actions: true,\n headers: {\n 'Content-Type': 'application/json'\n }\n })\n\n ctx.status = 200\n ctx.body = {\n success: true,\n webhook\n }\n } catch (error) {\n console.error('[Webhook] Error registering webhook:', error)\n ctx.status = 500\n ctx.body = { error: error.message }\n }\n})\n\n/**\n * Get webhooks for a project\n */\nwebhookRouter.get('/label-studio/webhook/:projectId', async (ctx: Koa.Context) => {\n try {\n const projectId = parseInt(ctx.params.projectId)\n\n const { labelStudioApi } = await import('../utils/label-studio-api-client.js')\n const webhooks = await labelStudioApi.getWebhooks(projectId)\n\n ctx.status = 200\n ctx.body = webhooks\n } catch (error) {\n console.error('[Webhook] Error fetching webhooks:', error)\n ctx.status = 500\n ctx.body = { error: error.message }\n }\n})\n\n// Register routes with Things-Factory\nprocess.on('bootstrap-module-domain-private-route', (_app: Koa, router: Router) => {\n router.use(webhookRouter.routes())\n router.use(webhookRouter.allowedMethods())\n})\n\nexport { webhookRouter }\n"]}
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../server/route/webhook.ts"],"names":[],"mappings":"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","sourcesContent":["import Koa from 'koa'\nimport 'koa-bodyparser'\nimport Router from 'koa-router'\nimport { getRepository } from 'typeorm'\n\nconst webhookRouter = new Router()\n\n/**\n * Label Studio Webhook Event Types\n */\nexport enum WebhookAction {\n ANNOTATION_CREATED = 'ANNOTATION_CREATED',\n ANNOTATION_UPDATED = 'ANNOTATION_UPDATED',\n ANNOTATION_DELETED = 'ANNOTATION_DELETED',\n TASK_CREATED = 'TASK_CREATED',\n TASK_UPDATED = 'TASK_UPDATED',\n TASK_DELETED = 'TASK_DELETED',\n PROJECT_UPDATED = 'PROJECT_UPDATED'\n}\n\nexport interface WebhookPayload {\n action: WebhookAction\n project: {\n id: number\n title: string\n }\n task?: {\n id: number\n data: any\n annotations: any[]\n }\n annotation?: {\n id: number\n result: any[]\n completed_by: {\n id: number\n email: string\n }\n lead_time: number\n }\n}\n\n/**\n * Webhook handler function type\n * Applications can register custom handlers for any webhook action\n */\nexport type WebhookHandler = (payload: WebhookPayload, context: Koa.Context) => Promise<void>\n\n/**\n * Registry for custom webhook handlers\n * Multiple handlers can be registered per action\n */\nconst customHandlers: Map<WebhookAction, WebhookHandler[]> = new Map()\n\n/**\n * Register a custom webhook handler\n * Handlers are executed in registration order\n *\n * @param action - Webhook action to handle\n * @param handler - Handler function\n *\n * @example\n * registerWebhookHandler(WebhookAction.ANNOTATION_CREATED, async (payload, ctx) => {\n * console.log('Custom handler:', payload.annotation?.id)\n * // Store annotation in database\n * // Trigger ML training\n * // Send notifications\n * })\n */\nexport function registerWebhookHandler(action: WebhookAction, handler: WebhookHandler): void {\n if (!customHandlers.has(action)) {\n customHandlers.set(action, [])\n }\n customHandlers.get(action)!.push(handler)\n}\n\n/**\n * Unregister a webhook handler\n */\nexport function unregisterWebhookHandler(action: WebhookAction, handler: WebhookHandler): void {\n const handlers = customHandlers.get(action)\n if (handlers) {\n const index = handlers.indexOf(handler)\n if (index > -1) {\n handlers.splice(index, 1)\n }\n }\n}\n\n/**\n * Clear all custom handlers for an action\n */\nexport function clearWebhookHandlers(action?: WebhookAction): void {\n if (action) {\n customHandlers.delete(action)\n } else {\n customHandlers.clear()\n }\n}\n\n/**\n * Execute all registered handlers for an action\n */\nasync function executeCustomHandlers(action: WebhookAction, payload: WebhookPayload, ctx: Koa.Context): Promise<void> {\n const handlers = customHandlers.get(action)\n if (!handlers || handlers.length === 0) {\n return\n }\n\n // Execute all handlers in sequence\n for (const handler of handlers) {\n try {\n await handler(payload, ctx)\n } catch (error) {\n console.error(`[Webhook] Custom handler error for ${action}:`, error)\n // Continue executing other handlers even if one fails\n }\n }\n}\n\n/**\n * Handle annotation created event\n */\nasync function handleAnnotationCreated(payload: WebhookPayload) {\n console.log(`[Webhook] Annotation created:`, {\n projectId: payload.project.id,\n taskId: payload.task?.id,\n annotationId: payload.annotation?.id,\n completedBy: payload.annotation?.completed_by?.email\n })\n\n // TODO: Implement business logic\n // 1. Store annotation in Things-Factory database\n // 2. Trigger downstream processes (e.g., model training)\n // 3. Send notifications to stakeholders\n // 4. Update task status in external systems\n}\n\n/**\n * Handle annotation updated event\n */\nasync function handleAnnotationUpdated(payload: WebhookPayload) {\n console.log(`[Webhook] Annotation updated:`, {\n projectId: payload.project.id,\n annotationId: payload.annotation?.id\n })\n\n // TODO: Update annotation in database\n}\n\n/**\n * Handle annotation deleted event\n */\nasync function handleAnnotationDeleted(payload: WebhookPayload) {\n console.log(`[Webhook] Annotation deleted:`, {\n projectId: payload.project.id,\n annotationId: payload.annotation?.id\n })\n\n // TODO: Remove annotation from database\n}\n\n/**\n * Handle task created event\n */\nasync function handleTaskCreated(payload: WebhookPayload) {\n console.log(`[Webhook] Task created:`, {\n projectId: payload.project.id,\n taskId: payload.task?.id\n })\n\n // TODO: Store task reference\n}\n\n/**\n * Handle project updated event\n */\nasync function handleProjectUpdated(payload: WebhookPayload) {\n console.log(`[Webhook] Project updated:`, {\n projectId: payload.project.id,\n projectTitle: payload.project.title\n })\n\n // TODO: Update project metadata\n}\n\n/**\n * Main webhook endpoint\n * Label Studio will POST events here\n */\nwebhookRouter.post('/label-studio/webhook', async (ctx: Koa.Context) => {\n try {\n const payload = ctx.request.body as WebhookPayload\n\n console.log(`[Webhook] Received event: ${payload.action}`)\n\n // Execute default handlers first\n switch (payload.action) {\n case WebhookAction.ANNOTATION_CREATED:\n await handleAnnotationCreated(payload)\n break\n\n case WebhookAction.ANNOTATION_UPDATED:\n await handleAnnotationUpdated(payload)\n break\n\n case WebhookAction.ANNOTATION_DELETED:\n await handleAnnotationDeleted(payload)\n break\n\n case WebhookAction.TASK_CREATED:\n await handleTaskCreated(payload)\n break\n\n case WebhookAction.TASK_UPDATED:\n // Optional: handle task updates\n break\n\n case WebhookAction.TASK_DELETED:\n // Optional: handle task deletions\n break\n\n case WebhookAction.PROJECT_UPDATED:\n await handleProjectUpdated(payload)\n break\n\n default:\n console.warn(`[Webhook] Unknown action: ${payload.action}`)\n }\n\n // Execute custom handlers\n await executeCustomHandlers(payload.action, payload, ctx)\n\n ctx.status = 200\n ctx.body = { success: true }\n } catch (error) {\n console.error('[Webhook] Error processing webhook:', error)\n ctx.status = 500\n ctx.body = { error: error.message }\n }\n})\n\n/**\n * Webhook registration helper\n * Call this to register webhook with Label Studio\n */\nwebhookRouter.post('/label-studio/webhook/register', async (ctx: Koa.Context) => {\n try {\n const { projectId } = ctx.request.body as { projectId: number }\n\n // Get Things-Factory server URL\n const serverUrl = process.env.SERVER_URL || 'http://localhost:3000'\n const webhookUrl = `${serverUrl}/label-studio/webhook`\n\n // Register webhook using Label Studio API\n const { labelStudioApi } = await import('../utils/label-studio-api-client.js')\n\n const webhook = await labelStudioApi.createWebhook({\n project: projectId,\n url: webhookUrl,\n send_payload: true,\n send_for_all_actions: true,\n headers: {\n 'Content-Type': 'application/json'\n }\n })\n\n ctx.status = 200\n ctx.body = {\n success: true,\n webhook\n }\n } catch (error) {\n console.error('[Webhook] Error registering webhook:', error)\n ctx.status = 500\n ctx.body = { error: error.message }\n }\n})\n\n/**\n * Get webhooks for a project\n */\nwebhookRouter.get('/label-studio/webhook/:projectId', async (ctx: Koa.Context) => {\n try {\n const projectId = parseInt(ctx.params.projectId)\n\n const { labelStudioApi } = await import('../utils/label-studio-api-client.js')\n const webhooks = await labelStudioApi.getWebhooks(projectId)\n\n ctx.status = 200\n ctx.body = webhooks\n } catch (error) {\n console.error('[Webhook] Error fetching webhooks:', error)\n ctx.status = 500\n ctx.body = { error: error.message }\n }\n})\n\n// Register routes with Things-Factory\nprocess.on('bootstrap-module-domain-private-route', (_app: Koa, router: Router) => {\n router.use(webhookRouter.routes())\n router.use(webhookRouter.allowedMethods())\n})\n\nexport { webhookRouter }\n"]}
|