Skip to content

Commit 6f34f37

Browse files
committed
feat: add worker API endpoint
1 parent 334484d commit 6f34f37

File tree

4 files changed

+91
-1
lines changed

4 files changed

+91
-1
lines changed

src/client/routes/worker/$workerId/index.tsx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
1313
import { CodeEditor } from '@/components/CodeEditor';
1414
import { trpc } from '@/api/trpc';
1515
import { defaultErrorHandler } from '@/api/trpc';
16-
import { LuPlay, LuPencil, LuTrash, LuActivity } from 'react-icons/lu';
16+
import { LuPlay, LuPencil, LuTrash, LuActivity, LuGlobe } from 'react-icons/lu';
1717
import { useState } from 'react';
1818
import { AlertConfirm } from '@/components/AlertConfirm';
1919
import { Loading } from '@/components/Loading';
@@ -32,6 +32,8 @@ import {
3232
} from '@/components/ui/sheet';
3333
import { WorkerExecutionsTable } from '@/components/worker/WorkerExecutionsTable';
3434
import { WorkerExecutionDetail } from '@/components/worker/WorkerExecutionDetail';
35+
import { toast } from 'sonner';
36+
import { CodeBlock } from '@/components/CodeBlock';
3537

3638
export const Route = createFileRoute('/worker/$workerId/')({
3739
beforeLoad: routeAuthBeforeLoad,
@@ -217,6 +219,28 @@ function PageComponent() {
217219
</TabsList>
218220

219221
<TabsContent value="code" className="space-y-4">
222+
{/* API Calling Guide */}
223+
<Card className="border-blue-200 bg-blue-50/50 dark:border-blue-800 dark:bg-blue-950/50">
224+
<CardHeader>
225+
<CardTitle className="flex items-center space-x-2 text-blue-700 dark:text-blue-300">
226+
<LuGlobe className="h-5 w-5" />
227+
<span>{t('API Endpoint')}</span>
228+
</CardTitle>
229+
</CardHeader>
230+
<CardContent className="space-y-4">
231+
<div className="space-y-2">
232+
<p className="text-sm text-blue-600 dark:text-blue-400">
233+
{t(
234+
'You can call this worker function directly via HTTP API:'
235+
)}
236+
</p>
237+
<CodeBlock
238+
code={`${window.location.origin}/api/worker/${workspaceId}/${workerId}`}
239+
/>
240+
</div>
241+
</CardContent>
242+
</Card>
243+
220244
<Card>
221245
<CardHeader>
222246
<CardTitle>{t('Worker Code')}</CardTitle>

src/client/vite.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ export default defineConfig({
5555
'/api/push': {
5656
target: 'http://localhost:12345',
5757
},
58+
'/api/worker': {
59+
target: 'http://localhost:12345',
60+
},
5861
'^/monitor/.*/badge\\.svg(\\?.*)?$': {
5962
target: 'http://localhost:12345',
6063
},

src/server/app.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { prometheusApiVersion } from './middleware/prometheus/index.js';
2626
import { billingRouter } from './router/billing.js';
2727
import { aiGatewayRouter } from './router/aiGateway.js';
2828
import { pushRouter } from './router/push.js';
29+
import { workerRouter } from './router/worker.js';
2930

3031
const app = express();
3132

@@ -62,6 +63,7 @@ app.use('/api/application', applicationRouter);
6263
app.use('/api/ai', aiGatewayRouter);
6364
app.use('/api/billing', billingRouter);
6465
app.use('/api/push', pushRouter);
66+
app.use('/api/worker', workerRouter);
6567
app.use('/monitor', monitorRouter);
6668
app.use('/telemetry', telemetryRouter);
6769
app.use('/serverStatus', serverStatusRouter);

src/server/router/worker.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { Router } from 'express';
2+
import { param, validate } from '../middleware/validate.js';
3+
import { execWorker } from '../model/worker/index.js';
4+
import { prisma } from '../model/_client.js';
5+
import { logger } from '../utils/logger.js';
6+
7+
export const workerRouter = Router();
8+
9+
/**
10+
* Execute a worker by ID
11+
*/
12+
workerRouter.all(
13+
'/:workspaceId/:workerId',
14+
validate(param('workspaceId').isString(), param('workerId').isString()),
15+
async (req, res) => {
16+
try {
17+
const { workspaceId, workerId } = req.params;
18+
// const { requestPayload = {} } = req.body;
19+
20+
// Verify worker exists and belongs to workspace
21+
const worker = await prisma.functionWorker.findUnique({
22+
where: {
23+
id: workerId,
24+
workspaceId,
25+
},
26+
});
27+
28+
if (!worker) {
29+
return res.status(404).json({
30+
success: false,
31+
error: 'Worker not found or does not belong to this workspace',
32+
});
33+
}
34+
35+
if (!worker.active) {
36+
return res.status(400).json({
37+
success: false,
38+
error: 'Worker is not active',
39+
});
40+
}
41+
42+
// Execute the worker
43+
const execution = await execWorker(workerId);
44+
45+
const response = execution.responsePayload;
46+
47+
if (typeof response === 'object') {
48+
res.json(response);
49+
} else {
50+
res.send(response);
51+
}
52+
} catch (error) {
53+
logger.error('Worker execution error:', error);
54+
res.status(500).json({
55+
success: false,
56+
error: 'Internal server error during worker execution',
57+
message: error instanceof Error ? error.message : 'Unknown error',
58+
});
59+
}
60+
}
61+
);

0 commit comments

Comments
 (0)