@mastra/deployer 0.0.0-commonjs-20250227130920

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.
Files changed (86) hide show
  1. package/.turbo/turbo-build.log +41 -0
  2. package/CHANGELOG.md +897 -0
  3. package/LICENSE +44 -0
  4. package/README.md +159 -0
  5. package/dist/_tsup-dts-rollup.d.cts +360 -0
  6. package/dist/_tsup-dts-rollup.d.ts +360 -0
  7. package/dist/build/analyze.cjs +367 -0
  8. package/dist/build/analyze.d.cts +1 -0
  9. package/dist/build/analyze.d.ts +1 -0
  10. package/dist/build/analyze.js +2 -0
  11. package/dist/build/bundler.cjs +353 -0
  12. package/dist/build/bundler.d.cts +2 -0
  13. package/dist/build/bundler.d.ts +2 -0
  14. package/dist/build/bundler.js +2 -0
  15. package/dist/build/index.cjs +1146 -0
  16. package/dist/build/index.d.cts +10 -0
  17. package/dist/build/index.d.ts +10 -0
  18. package/dist/build/index.js +5 -0
  19. package/dist/bundler/index.cjs +999 -0
  20. package/dist/bundler/index.d.cts +1 -0
  21. package/dist/bundler/index.d.ts +1 -0
  22. package/dist/bundler/index.js +5 -0
  23. package/dist/chunk-3ONBKVC4.js +113 -0
  24. package/dist/chunk-AXS5WSIK.js +290 -0
  25. package/dist/chunk-DTSFVNIF.js +260 -0
  26. package/dist/chunk-JMH7HCD6.js +274 -0
  27. package/dist/chunk-SGK37ZWD.js +254 -0
  28. package/dist/chunk-YNXJO2XU.js +69 -0
  29. package/dist/index.cjs +1229 -0
  30. package/dist/index.d.cts +6 -0
  31. package/dist/index.d.ts +6 -0
  32. package/dist/index.js +131 -0
  33. package/dist/server/index.cjs +4930 -0
  34. package/dist/server/index.d.cts +2 -0
  35. package/dist/server/index.d.ts +2 -0
  36. package/dist/server/index.js +4923 -0
  37. package/dist/templates/instrumentation-template.js +86 -0
  38. package/eslint.config.js +6 -0
  39. package/global.d.ts +0 -0
  40. package/package.json +112 -0
  41. package/public/templates/instrumentation-template.js +86 -0
  42. package/src/build/analyze.ts +279 -0
  43. package/src/build/babel/fix-libsql.ts +41 -0
  44. package/src/build/babel/get-deployer.ts +54 -0
  45. package/src/build/babel/get-telemetry-config.ts +62 -0
  46. package/src/build/babel/remove-deployer.ts +43 -0
  47. package/src/build/bundle.ts +139 -0
  48. package/src/build/bundler.ts +135 -0
  49. package/src/build/deployer.ts +67 -0
  50. package/src/build/deps.ts +149 -0
  51. package/src/build/env.ts +76 -0
  52. package/src/build/fs.ts +66 -0
  53. package/src/build/index.ts +7 -0
  54. package/src/build/isNodeBuiltin.ts +7 -0
  55. package/src/build/plugins/fix-libsql.ts +69 -0
  56. package/src/build/plugins/hono-alias.ts +17 -0
  57. package/src/build/plugins/pino.ts +93 -0
  58. package/src/build/plugins/remove-deployer.ts +37 -0
  59. package/src/build/plugins/telemetry-fix.ts +54 -0
  60. package/src/build/telemetry.ts +76 -0
  61. package/src/build/utils.ts +12 -0
  62. package/src/build/watcher.ts +43 -0
  63. package/src/bundler/index.ts +144 -0
  64. package/src/deploy/base.ts +30 -0
  65. package/src/deploy/index.ts +2 -0
  66. package/src/deploy/log.ts +61 -0
  67. package/src/index.ts +3 -0
  68. package/src/server/handlers/agents.ts +209 -0
  69. package/src/server/handlers/client.ts +36 -0
  70. package/src/server/handlers/error.ts +29 -0
  71. package/src/server/handlers/logs.ts +53 -0
  72. package/src/server/handlers/memory.ts +196 -0
  73. package/src/server/handlers/prompt.ts +128 -0
  74. package/src/server/handlers/root.ts +6 -0
  75. package/src/server/handlers/telemetry.ts +48 -0
  76. package/src/server/handlers/tools.ts +114 -0
  77. package/src/server/handlers/utils.ts +15 -0
  78. package/src/server/handlers/vector.ts +149 -0
  79. package/src/server/handlers/workflows.ts +119 -0
  80. package/src/server/index.ts +1355 -0
  81. package/src/server/openapi.json +434 -0
  82. package/src/server/openapi.script.js +22 -0
  83. package/src/server/types.ts +4 -0
  84. package/src/server/welcome.ts +105 -0
  85. package/tsconfig.json +5 -0
  86. package/vitest.config.ts +8 -0
@@ -0,0 +1,1355 @@
1
+ import { readFile } from 'fs/promises';
2
+ import { join } from 'path';
3
+ import { pathToFileURL } from 'url';
4
+ import { serve } from '@hono/node-server';
5
+ import { serveStatic } from '@hono/node-server/serve-static';
6
+ import { swaggerUI } from '@hono/swagger-ui';
7
+ import type { Mastra } from '@mastra/core';
8
+ import { Hono } from 'hono';
9
+ import type { Context } from 'hono';
10
+
11
+ import { bodyLimit } from 'hono/body-limit';
12
+ import { cors } from 'hono/cors';
13
+ import { logger } from 'hono/logger';
14
+ import { describeRoute, openAPISpecs } from 'hono-openapi';
15
+
16
+ import {
17
+ generateHandler,
18
+ getAgentByIdHandler,
19
+ getAgentsHandler,
20
+ getEvalsByAgentIdHandler,
21
+ getLiveEvalsByAgentIdHandler,
22
+ setAgentInstructionsHandler,
23
+ streamGenerateHandler,
24
+ } from './handlers/agents.js';
25
+ import { handleClientsRefresh, handleTriggerClientsRefresh } from './handlers/client.js';
26
+ import { errorHandler } from './handlers/error.js';
27
+ import { getLogsByRunIdHandler, getLogsHandler, getLogTransports } from './handlers/logs.js';
28
+ import {
29
+ createThreadHandler,
30
+ deleteThreadHandler,
31
+ getMemoryStatusHandler,
32
+ getMessagesHandler,
33
+ getThreadByIdHandler,
34
+ getThreadsHandler,
35
+ saveMessagesHandler,
36
+ updateThreadHandler,
37
+ } from './handlers/memory.js';
38
+ import { generateSystemPromptHandler } from './handlers/prompt.js';
39
+ import { rootHandler } from './handlers/root.js';
40
+ import { getTelemetryHandler } from './handlers/telemetry.js';
41
+ import { executeAgentToolHandler, executeToolHandler, getToolByIdHandler, getToolsHandler } from './handlers/tools.js';
42
+ import {
43
+ upsertVectors,
44
+ createIndex,
45
+ queryVectors,
46
+ listIndexes,
47
+ describeIndex,
48
+ deleteIndex,
49
+ } from './handlers/vector.js';
50
+ import {
51
+ executeWorkflowHandler,
52
+ getWorkflowByIdHandler,
53
+ getWorkflowsHandler,
54
+ resumeWorkflowHandler,
55
+ watchWorkflowHandler,
56
+ } from './handlers/workflows.js';
57
+ import { html } from './welcome.js';
58
+
59
+ type Bindings = {};
60
+
61
+ type Variables = {
62
+ mastra: Mastra;
63
+ clients: Set<{ controller: ReadableStreamDefaultController }>;
64
+ tools: Record<string, any>;
65
+ playground: boolean;
66
+ };
67
+
68
+ export async function createHonoServer(
69
+ mastra: Mastra,
70
+ options: { playground?: boolean; swaggerUI?: boolean; apiReqLogs?: boolean } = {},
71
+ ) {
72
+ // Create typed Hono app
73
+ const app = new Hono<{ Bindings: Bindings; Variables: Variables }>();
74
+
75
+ // Initialize tools
76
+ const mastraToolsPaths = process.env.MASTRA_TOOLS_PATH;
77
+ const toolImports = mastraToolsPaths
78
+ ? await Promise.all(
79
+ mastraToolsPaths.split(',').map(async toolPath => {
80
+ return import(pathToFileURL(toolPath).href);
81
+ }),
82
+ )
83
+ : [];
84
+
85
+ const tools = toolImports.reduce((acc, toolModule) => {
86
+ Object.entries(toolModule).forEach(([key, tool]) => {
87
+ acc[key] = tool;
88
+ });
89
+ return acc;
90
+ }, {});
91
+
92
+ // Middleware
93
+ app.use(
94
+ '*',
95
+ cors({
96
+ origin: '*',
97
+ allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
98
+ allowHeaders: ['Content-Type', 'Authorization'],
99
+ exposeHeaders: ['Content-Length', 'X-Requested-With'],
100
+ credentials: false,
101
+ maxAge: 3600,
102
+ }),
103
+ );
104
+
105
+ if (options.apiReqLogs) {
106
+ app.use(logger());
107
+ }
108
+
109
+ app.onError(errorHandler);
110
+
111
+ // Add Mastra to context
112
+ app.use('*', async (c, next) => {
113
+ c.set('mastra', mastra);
114
+ c.set('tools', tools);
115
+ c.set('playground', options.playground === true);
116
+ await next();
117
+ });
118
+
119
+ const bodyLimitOptions = {
120
+ maxSize: 4.5 * 1024 * 1024, // 4.5 MB,
121
+ onError: (c: Context) => c.json({ error: 'Request body too large' }, 413),
122
+ };
123
+
124
+ // API routes
125
+ app.get(
126
+ '/api',
127
+ describeRoute({
128
+ description: 'Get API status',
129
+ tags: ['system'],
130
+ responses: {
131
+ 200: {
132
+ description: 'Success',
133
+ },
134
+ },
135
+ }),
136
+ rootHandler,
137
+ );
138
+
139
+ // Agent routes
140
+ app.get(
141
+ '/api/agents',
142
+ describeRoute({
143
+ description: 'Get all available agents',
144
+ tags: ['agents'],
145
+ responses: {
146
+ 200: {
147
+ description: 'List of all agents',
148
+ },
149
+ },
150
+ }),
151
+ getAgentsHandler,
152
+ );
153
+
154
+ app.get(
155
+ '/api/agents/:agentId',
156
+ describeRoute({
157
+ description: 'Get agent by ID',
158
+ tags: ['agents'],
159
+ parameters: [
160
+ {
161
+ name: 'agentId',
162
+ in: 'path',
163
+ required: true,
164
+ schema: { type: 'string' },
165
+ },
166
+ ],
167
+ responses: {
168
+ 200: {
169
+ description: 'Agent details',
170
+ },
171
+ 404: {
172
+ description: 'Agent not found',
173
+ },
174
+ },
175
+ }),
176
+ getAgentByIdHandler,
177
+ );
178
+
179
+ app.get(
180
+ '/api/agents/:agentId/evals/ci',
181
+ describeRoute({
182
+ description: 'Get CI evals by agent ID',
183
+ tags: ['agents'],
184
+ parameters: [
185
+ {
186
+ name: 'agentId',
187
+ in: 'path',
188
+ required: true,
189
+ schema: { type: 'string' },
190
+ },
191
+ ],
192
+ responses: {
193
+ 200: {
194
+ description: 'List of evals',
195
+ },
196
+ },
197
+ }),
198
+ getEvalsByAgentIdHandler,
199
+ );
200
+
201
+ app.get(
202
+ '/api/agents/:agentId/evals/live',
203
+ describeRoute({
204
+ description: 'Get live evals by agent ID',
205
+ tags: ['agents'],
206
+ parameters: [
207
+ {
208
+ name: 'agentId',
209
+ in: 'path',
210
+ required: true,
211
+ schema: { type: 'string' },
212
+ },
213
+ ],
214
+ responses: {
215
+ 200: {
216
+ description: 'List of evals',
217
+ },
218
+ },
219
+ }),
220
+ getLiveEvalsByAgentIdHandler,
221
+ );
222
+
223
+ app.post(
224
+ '/api/agents/:agentId/generate',
225
+ bodyLimit(bodyLimitOptions),
226
+ describeRoute({
227
+ description: 'Generate a response from an agent',
228
+ tags: ['agents'],
229
+ parameters: [
230
+ {
231
+ name: 'agentId',
232
+ in: 'path',
233
+ required: true,
234
+ schema: { type: 'string' },
235
+ },
236
+ ],
237
+ requestBody: {
238
+ required: true,
239
+ content: {
240
+ 'application/json': {
241
+ schema: {
242
+ type: 'object',
243
+ properties: {
244
+ messages: {
245
+ type: 'array',
246
+ items: { type: 'object' },
247
+ },
248
+ threadId: { type: 'string' },
249
+ resourceId: { type: 'string', description: 'The resource ID for the conversation' },
250
+ resourceid: {
251
+ type: 'string',
252
+ description: 'The resource ID for the conversation (deprecated, use resourceId instead)',
253
+ deprecated: true,
254
+ },
255
+ runId: { type: 'string' },
256
+ output: { type: 'object' },
257
+ },
258
+ required: ['messages'],
259
+ },
260
+ },
261
+ },
262
+ },
263
+ responses: {
264
+ 200: {
265
+ description: 'Generated response',
266
+ },
267
+ 404: {
268
+ description: 'Agent not found',
269
+ },
270
+ },
271
+ }),
272
+ generateHandler,
273
+ );
274
+
275
+ app.post(
276
+ '/api/agents/:agentId/stream',
277
+ bodyLimit(bodyLimitOptions),
278
+ describeRoute({
279
+ description: 'Stream a response from an agent',
280
+ tags: ['agents'],
281
+ parameters: [
282
+ {
283
+ name: 'agentId',
284
+ in: 'path',
285
+ required: true,
286
+ schema: { type: 'string' },
287
+ },
288
+ ],
289
+ requestBody: {
290
+ required: true,
291
+ content: {
292
+ 'application/json': {
293
+ schema: {
294
+ type: 'object',
295
+ properties: {
296
+ messages: {
297
+ type: 'array',
298
+ items: { type: 'object' },
299
+ },
300
+ threadId: { type: 'string' },
301
+ resourceId: { type: 'string', description: 'The resource ID for the conversation' },
302
+ resourceid: {
303
+ type: 'string',
304
+ description: 'The resource ID for the conversation (deprecated, use resourceId instead)',
305
+ deprecated: true,
306
+ },
307
+ runId: { type: 'string' },
308
+ output: { type: 'object' },
309
+ },
310
+ required: ['messages'],
311
+ },
312
+ },
313
+ },
314
+ },
315
+ responses: {
316
+ 200: {
317
+ description: 'Streamed response',
318
+ },
319
+ 404: {
320
+ description: 'Agent not found',
321
+ },
322
+ },
323
+ }),
324
+ streamGenerateHandler,
325
+ );
326
+
327
+ app.post(
328
+ '/api/agents/:agentId/instructions',
329
+ bodyLimit(bodyLimitOptions),
330
+ describeRoute({
331
+ description: "Update an agent's instructions",
332
+ tags: ['agents'],
333
+ parameters: [
334
+ {
335
+ name: 'agentId',
336
+ in: 'path',
337
+ required: true,
338
+ schema: { type: 'string' },
339
+ },
340
+ ],
341
+ requestBody: {
342
+ required: true,
343
+ content: {
344
+ 'application/json': {
345
+ schema: {
346
+ type: 'object',
347
+ properties: {
348
+ instructions: {
349
+ type: 'string',
350
+ description: 'New instructions for the agent',
351
+ },
352
+ },
353
+ required: ['instructions'],
354
+ },
355
+ },
356
+ },
357
+ },
358
+ responses: {
359
+ 200: {
360
+ description: 'Instructions updated successfully',
361
+ },
362
+ 403: {
363
+ description: 'Not allowed in non-playground environment',
364
+ },
365
+ 404: {
366
+ description: 'Agent not found',
367
+ },
368
+ },
369
+ }),
370
+ setAgentInstructionsHandler,
371
+ );
372
+
373
+ app.post(
374
+ '/api/agents/:agentId/instructions/enhance',
375
+ bodyLimit(bodyLimitOptions),
376
+ describeRoute({
377
+ description: 'Generate an improved system prompt from instructions',
378
+ tags: ['agents'],
379
+ parameters: [
380
+ {
381
+ name: 'agentId',
382
+ in: 'path',
383
+ required: true,
384
+ schema: { type: 'string' },
385
+ description: 'ID of the agent whose model will be used for prompt generation',
386
+ },
387
+ ],
388
+ requestBody: {
389
+ required: true,
390
+ content: {
391
+ 'application/json': {
392
+ schema: {
393
+ type: 'object',
394
+ properties: {
395
+ instructions: {
396
+ type: 'string',
397
+ description: 'Instructions to generate a system prompt from',
398
+ },
399
+ comment: {
400
+ type: 'string',
401
+ description: 'Optional comment for the enhanced prompt',
402
+ },
403
+ },
404
+ required: ['instructions'],
405
+ },
406
+ },
407
+ },
408
+ },
409
+ responses: {
410
+ 200: {
411
+ description: 'Generated system prompt and analysis',
412
+ content: {
413
+ 'application/json': {
414
+ schema: {
415
+ type: 'object',
416
+ properties: {
417
+ explanation: {
418
+ type: 'string',
419
+ description: 'Detailed analysis of the instructions',
420
+ },
421
+ new_prompt: {
422
+ type: 'string',
423
+ description: 'The enhanced system prompt',
424
+ },
425
+ },
426
+ },
427
+ },
428
+ },
429
+ },
430
+ 400: {
431
+ description: 'Missing or invalid request parameters',
432
+ },
433
+ 404: {
434
+ description: 'Agent not found',
435
+ },
436
+ 500: {
437
+ description: 'Internal server error or model response parsing error',
438
+ },
439
+ },
440
+ }),
441
+ generateSystemPromptHandler,
442
+ );
443
+
444
+ app.post(
445
+ '/api/agents/:agentId/tools/:toolId/execute',
446
+ bodyLimit(bodyLimitOptions),
447
+ describeRoute({
448
+ description: 'Execute a tool through an agent',
449
+ tags: ['agents'],
450
+ parameters: [
451
+ {
452
+ name: 'agentId',
453
+ in: 'path',
454
+ required: true,
455
+ schema: { type: 'string' },
456
+ },
457
+ {
458
+ name: 'toolId',
459
+ in: 'path',
460
+ required: true,
461
+ schema: { type: 'string' },
462
+ },
463
+ ],
464
+ requestBody: {
465
+ required: true,
466
+ content: {
467
+ 'application/json': {
468
+ schema: {
469
+ type: 'object',
470
+ properties: {
471
+ data: { type: 'object' },
472
+ },
473
+ required: ['data'],
474
+ },
475
+ },
476
+ },
477
+ },
478
+ responses: {
479
+ 200: {
480
+ description: 'Tool execution result',
481
+ },
482
+ 404: {
483
+ description: 'Tool or agent not found',
484
+ },
485
+ },
486
+ }),
487
+ executeAgentToolHandler,
488
+ );
489
+
490
+ // Memory routes
491
+ app.get(
492
+ '/api/memory/status',
493
+ describeRoute({
494
+ description: 'Get memory status',
495
+ tags: ['memory'],
496
+ parameters: [
497
+ {
498
+ name: 'agentId',
499
+ in: 'query',
500
+ required: true,
501
+ schema: { type: 'string' },
502
+ },
503
+ ],
504
+ responses: {
505
+ 200: {
506
+ description: 'Memory status',
507
+ },
508
+ },
509
+ }),
510
+ getMemoryStatusHandler,
511
+ );
512
+
513
+ app.get(
514
+ '/api/memory/threads',
515
+ describeRoute({
516
+ description: 'Get all threads',
517
+ tags: ['memory'],
518
+ parameters: [
519
+ {
520
+ name: 'resourceid',
521
+ in: 'query',
522
+ required: true,
523
+ schema: { type: 'string' },
524
+ },
525
+ {
526
+ name: 'agentId',
527
+ in: 'query',
528
+ required: true,
529
+ schema: { type: 'string' },
530
+ },
531
+ ],
532
+ responses: {
533
+ 200: {
534
+ description: 'List of all threads',
535
+ },
536
+ },
537
+ }),
538
+ getThreadsHandler,
539
+ );
540
+
541
+ app.get(
542
+ '/api/memory/threads/:threadId',
543
+ describeRoute({
544
+ description: 'Get thread by ID',
545
+ tags: ['memory'],
546
+ parameters: [
547
+ {
548
+ name: 'threadId',
549
+ in: 'path',
550
+ required: true,
551
+ schema: { type: 'string' },
552
+ },
553
+ {
554
+ name: 'agentId',
555
+ in: 'query',
556
+ required: true,
557
+ schema: { type: 'string' },
558
+ },
559
+ ],
560
+ responses: {
561
+ 200: {
562
+ description: 'Thread details',
563
+ },
564
+ 404: {
565
+ description: 'Thread not found',
566
+ },
567
+ },
568
+ }),
569
+ getThreadByIdHandler,
570
+ );
571
+
572
+ app.get(
573
+ '/api/memory/threads/:threadId/messages',
574
+ describeRoute({
575
+ description: 'Get messages for a thread',
576
+ tags: ['memory'],
577
+ parameters: [
578
+ {
579
+ name: 'threadId',
580
+ in: 'path',
581
+ required: true,
582
+ schema: { type: 'string' },
583
+ },
584
+ {
585
+ name: 'agentId',
586
+ in: 'query',
587
+ required: true,
588
+ schema: { type: 'string' },
589
+ },
590
+ ],
591
+ responses: {
592
+ 200: {
593
+ description: 'List of messages',
594
+ },
595
+ },
596
+ }),
597
+ getMessagesHandler,
598
+ );
599
+
600
+ app.post(
601
+ '/api/memory/threads',
602
+ bodyLimit(bodyLimitOptions),
603
+ describeRoute({
604
+ description: 'Create a new thread',
605
+ tags: ['memory'],
606
+ parameters: [
607
+ {
608
+ name: 'agentId',
609
+ in: 'query',
610
+ required: true,
611
+ schema: { type: 'string' },
612
+ },
613
+ ],
614
+ requestBody: {
615
+ required: true,
616
+ content: {
617
+ 'application/json': {
618
+ schema: {
619
+ type: 'object',
620
+ properties: {
621
+ title: { type: 'string' },
622
+ metadata: { type: 'object' },
623
+ resourceid: { type: 'string' },
624
+ threadId: { type: 'string' },
625
+ },
626
+ },
627
+ },
628
+ },
629
+ },
630
+ responses: {
631
+ 200: {
632
+ description: 'Created thread',
633
+ },
634
+ },
635
+ }),
636
+
637
+ createThreadHandler,
638
+ );
639
+
640
+ app.patch(
641
+ '/api/memory/threads/:threadId',
642
+ describeRoute({
643
+ description: 'Update a thread',
644
+ tags: ['memory'],
645
+ parameters: [
646
+ {
647
+ name: 'threadId',
648
+ in: 'path',
649
+ required: true,
650
+ schema: { type: 'string' },
651
+ },
652
+ {
653
+ name: 'agentId',
654
+ in: 'query',
655
+ required: true,
656
+ schema: { type: 'string' },
657
+ },
658
+ ],
659
+ requestBody: {
660
+ required: true,
661
+ content: {
662
+ 'application/json': {
663
+ schema: { type: 'object' },
664
+ },
665
+ },
666
+ },
667
+ responses: {
668
+ 200: {
669
+ description: 'Updated thread',
670
+ },
671
+ 404: {
672
+ description: 'Thread not found',
673
+ },
674
+ },
675
+ }),
676
+ updateThreadHandler,
677
+ );
678
+
679
+ app.delete(
680
+ '/api/memory/threads/:threadId',
681
+ describeRoute({
682
+ description: 'Delete a thread',
683
+ tags: ['memory'],
684
+ parameters: [
685
+ {
686
+ name: 'threadId',
687
+ in: 'path',
688
+ required: true,
689
+ schema: { type: 'string' },
690
+ },
691
+ {
692
+ name: 'agentId',
693
+ in: 'query',
694
+ required: true,
695
+ schema: { type: 'string' },
696
+ },
697
+ ],
698
+ responses: {
699
+ 200: {
700
+ description: 'Thread deleted',
701
+ },
702
+ 404: {
703
+ description: 'Thread not found',
704
+ },
705
+ },
706
+ }),
707
+ deleteThreadHandler,
708
+ );
709
+
710
+ app.post(
711
+ '/api/memory/save-messages',
712
+ bodyLimit(bodyLimitOptions),
713
+ describeRoute({
714
+ description: 'Save messages',
715
+ tags: ['memory'],
716
+ parameters: [
717
+ {
718
+ name: 'agentId',
719
+ in: 'query',
720
+ required: true,
721
+ schema: { type: 'string' },
722
+ },
723
+ ],
724
+ requestBody: {
725
+ required: true,
726
+ content: {
727
+ 'application/json': {
728
+ schema: {
729
+ type: 'object',
730
+ properties: {
731
+ messages: {
732
+ type: 'array',
733
+ items: { type: 'object' },
734
+ },
735
+ },
736
+ required: ['messages'],
737
+ },
738
+ },
739
+ },
740
+ },
741
+ responses: {
742
+ 200: {
743
+ description: 'Messages saved',
744
+ },
745
+ },
746
+ }),
747
+ saveMessagesHandler,
748
+ );
749
+
750
+ // Telemetry routes
751
+ app.get(
752
+ '/api/telemetry',
753
+ describeRoute({
754
+ description: 'Get all traces',
755
+ tags: ['telemetry'],
756
+ responses: {
757
+ 200: {
758
+ description: 'List of all traces (paged)',
759
+ },
760
+ },
761
+ }),
762
+ getTelemetryHandler,
763
+ );
764
+
765
+ // Workflow routes
766
+ app.get(
767
+ '/api/workflows',
768
+ describeRoute({
769
+ description: 'Get all workflows',
770
+ tags: ['workflows'],
771
+ responses: {
772
+ 200: {
773
+ description: 'List of all workflows',
774
+ },
775
+ },
776
+ }),
777
+ getWorkflowsHandler,
778
+ );
779
+
780
+ app.get(
781
+ '/api/workflows/:workflowId',
782
+ describeRoute({
783
+ description: 'Get workflow by ID',
784
+ tags: ['workflows'],
785
+ parameters: [
786
+ {
787
+ name: 'workflowId',
788
+ in: 'path',
789
+ required: true,
790
+ schema: { type: 'string' },
791
+ },
792
+ ],
793
+ responses: {
794
+ 200: {
795
+ description: 'Workflow details',
796
+ },
797
+ 404: {
798
+ description: 'Workflow not found',
799
+ },
800
+ },
801
+ }),
802
+ getWorkflowByIdHandler,
803
+ );
804
+
805
+ app.post(
806
+ '/api/workflows/:workflowId/execute',
807
+ bodyLimit(bodyLimitOptions),
808
+ describeRoute({
809
+ description: 'Execute/Start a workflow',
810
+ tags: ['workflows'],
811
+ parameters: [
812
+ {
813
+ name: 'workflowId',
814
+ in: 'path',
815
+ required: true,
816
+ schema: { type: 'string' },
817
+ },
818
+ ],
819
+ requestBody: {
820
+ required: true,
821
+ content: {
822
+ 'application/json': {
823
+ schema: {
824
+ type: 'object',
825
+ properties: {
826
+ input: { type: 'object' },
827
+ },
828
+ },
829
+ },
830
+ },
831
+ },
832
+ responses: {
833
+ 200: {
834
+ description: 'Workflow execution result',
835
+ },
836
+ 404: {
837
+ description: 'Workflow not found',
838
+ },
839
+ },
840
+ }),
841
+ executeWorkflowHandler,
842
+ );
843
+
844
+ app.post(
845
+ '/api/workflows/:workflowId/resume',
846
+ describeRoute({
847
+ description: 'Resume a suspended workflow step',
848
+ tags: ['workflows'],
849
+ parameters: [
850
+ {
851
+ name: 'workflowId',
852
+ in: 'path',
853
+ required: true,
854
+ schema: { type: 'string' },
855
+ },
856
+ ],
857
+ requestBody: {
858
+ required: true,
859
+ content: {
860
+ 'application/json': {
861
+ schema: {
862
+ type: 'object',
863
+ properties: {
864
+ stepId: { type: 'string' },
865
+ runId: { type: 'string' },
866
+ context: { type: 'object' },
867
+ },
868
+ },
869
+ },
870
+ },
871
+ },
872
+ }),
873
+ resumeWorkflowHandler,
874
+ );
875
+
876
+ app.get(
877
+ '/api/workflows/:workflowId/watch',
878
+ describeRoute({
879
+ description: 'Watch workflow transitions in real-time',
880
+ parameters: [
881
+ {
882
+ name: 'workflowId',
883
+ in: 'path',
884
+ required: true,
885
+ schema: { type: 'string' },
886
+ },
887
+ ],
888
+ tags: ['workflows'],
889
+ responses: {
890
+ 200: {
891
+ description: 'Workflow transitions in real-time',
892
+ },
893
+ },
894
+ }),
895
+ watchWorkflowHandler,
896
+ );
897
+
898
+ // Log routes
899
+ app.get(
900
+ '/api/logs',
901
+ describeRoute({
902
+ description: 'Get all logs',
903
+ tags: ['logs'],
904
+ parameters: [
905
+ {
906
+ name: 'transportId',
907
+ in: 'query',
908
+ required: true,
909
+ schema: { type: 'string' },
910
+ },
911
+ ],
912
+ responses: {
913
+ 200: {
914
+ description: 'List of all logs',
915
+ },
916
+ },
917
+ }),
918
+ getLogsHandler,
919
+ );
920
+
921
+ app.get(
922
+ '/api/logs/transports',
923
+ describeRoute({
924
+ description: 'List of all log transports',
925
+ tags: ['logs'],
926
+ responses: {
927
+ 200: {
928
+ description: 'List of all log transports',
929
+ },
930
+ },
931
+ }),
932
+ getLogTransports,
933
+ );
934
+
935
+ app.get(
936
+ '/api/logs/:runId',
937
+ describeRoute({
938
+ description: 'Get logs by run ID',
939
+ tags: ['logs'],
940
+ parameters: [
941
+ {
942
+ name: 'runId',
943
+ in: 'path',
944
+ required: true,
945
+ schema: { type: 'string' },
946
+ },
947
+ {
948
+ name: 'transportId',
949
+ in: 'query',
950
+ required: true,
951
+ schema: { type: 'string' },
952
+ },
953
+ ],
954
+ responses: {
955
+ 200: {
956
+ description: 'List of logs for run ID',
957
+ },
958
+ },
959
+ }),
960
+ getLogsByRunIdHandler,
961
+ );
962
+
963
+ // Tool routes
964
+ app.get(
965
+ '/api/tools',
966
+ describeRoute({
967
+ description: 'Get all tools',
968
+ tags: ['tools'],
969
+ responses: {
970
+ 200: {
971
+ description: 'List of all tools',
972
+ },
973
+ },
974
+ }),
975
+ getToolsHandler,
976
+ );
977
+
978
+ app.get(
979
+ '/api/tools/:toolId',
980
+ describeRoute({
981
+ description: 'Get tool by ID',
982
+ tags: ['tools'],
983
+ parameters: [
984
+ {
985
+ name: 'toolId',
986
+ in: 'path',
987
+ required: true,
988
+ schema: { type: 'string' },
989
+ },
990
+ ],
991
+ responses: {
992
+ 200: {
993
+ description: 'Tool details',
994
+ },
995
+ 404: {
996
+ description: 'Tool not found',
997
+ },
998
+ },
999
+ }),
1000
+ getToolByIdHandler,
1001
+ );
1002
+
1003
+ app.post(
1004
+ '/api/tools/:toolId/execute',
1005
+ bodyLimit(bodyLimitOptions),
1006
+ describeRoute({
1007
+ description: 'Execute a tool',
1008
+ tags: ['tools'],
1009
+ parameters: [
1010
+ {
1011
+ name: 'toolId',
1012
+ in: 'path',
1013
+ required: true,
1014
+ schema: { type: 'string' },
1015
+ },
1016
+ ],
1017
+ requestBody: {
1018
+ required: true,
1019
+ content: {
1020
+ 'application/json': {
1021
+ schema: {
1022
+ type: 'object',
1023
+ properties: {
1024
+ data: { type: 'object' },
1025
+ },
1026
+ required: ['data'],
1027
+ },
1028
+ },
1029
+ },
1030
+ },
1031
+ responses: {
1032
+ 200: {
1033
+ description: 'Tool execution result',
1034
+ },
1035
+ 404: {
1036
+ description: 'Tool not found',
1037
+ },
1038
+ },
1039
+ }),
1040
+ executeToolHandler(tools),
1041
+ );
1042
+
1043
+ // Vector routes
1044
+ app.post(
1045
+ '/api/vector/:vectorName/upsert',
1046
+ bodyLimit(bodyLimitOptions),
1047
+ describeRoute({
1048
+ description: 'Upsert vectors into an index',
1049
+ tags: ['vector'],
1050
+ parameters: [
1051
+ {
1052
+ name: 'vectorName',
1053
+ in: 'path',
1054
+ required: true,
1055
+ schema: { type: 'string' },
1056
+ },
1057
+ ],
1058
+ requestBody: {
1059
+ required: true,
1060
+ content: {
1061
+ 'application/json': {
1062
+ schema: {
1063
+ type: 'object',
1064
+ properties: {
1065
+ indexName: { type: 'string' },
1066
+ vectors: {
1067
+ type: 'array',
1068
+ items: {
1069
+ type: 'array',
1070
+ items: { type: 'number' },
1071
+ },
1072
+ },
1073
+ metadata: {
1074
+ type: 'array',
1075
+ items: { type: 'object' },
1076
+ },
1077
+ ids: {
1078
+ type: 'array',
1079
+ items: { type: 'string' },
1080
+ },
1081
+ },
1082
+ required: ['indexName', 'vectors'],
1083
+ },
1084
+ },
1085
+ },
1086
+ },
1087
+ responses: {
1088
+ 200: {
1089
+ description: 'Vectors upserted successfully',
1090
+ },
1091
+ },
1092
+ }),
1093
+ upsertVectors,
1094
+ );
1095
+
1096
+ app.post(
1097
+ '/api/vector/:vectorName/create-index',
1098
+ bodyLimit(bodyLimitOptions),
1099
+ describeRoute({
1100
+ description: 'Create a new vector index',
1101
+ tags: ['vector'],
1102
+ parameters: [
1103
+ {
1104
+ name: 'vectorName',
1105
+ in: 'path',
1106
+ required: true,
1107
+ schema: { type: 'string' },
1108
+ },
1109
+ ],
1110
+ requestBody: {
1111
+ required: true,
1112
+ content: {
1113
+ 'application/json': {
1114
+ schema: {
1115
+ type: 'object',
1116
+ properties: {
1117
+ indexName: { type: 'string' },
1118
+ dimension: { type: 'number' },
1119
+ metric: {
1120
+ type: 'string',
1121
+ enum: ['cosine', 'euclidean', 'dotproduct'],
1122
+ },
1123
+ },
1124
+ required: ['indexName', 'dimension'],
1125
+ },
1126
+ },
1127
+ },
1128
+ },
1129
+ responses: {
1130
+ 200: {
1131
+ description: 'Index created successfully',
1132
+ },
1133
+ },
1134
+ }),
1135
+ createIndex,
1136
+ );
1137
+
1138
+ app.post(
1139
+ '/api/vector/:vectorName/query',
1140
+ bodyLimit(bodyLimitOptions),
1141
+ describeRoute({
1142
+ description: 'Query vectors from an index',
1143
+ tags: ['vector'],
1144
+ parameters: [
1145
+ {
1146
+ name: 'vectorName',
1147
+ in: 'path',
1148
+ required: true,
1149
+ schema: { type: 'string' },
1150
+ },
1151
+ ],
1152
+ requestBody: {
1153
+ required: true,
1154
+ content: {
1155
+ 'application/json': {
1156
+ schema: {
1157
+ type: 'object',
1158
+ properties: {
1159
+ indexName: { type: 'string' },
1160
+ queryVector: {
1161
+ type: 'array',
1162
+ items: { type: 'number' },
1163
+ },
1164
+ topK: { type: 'number' },
1165
+ filter: { type: 'object' },
1166
+ includeVector: { type: 'boolean' },
1167
+ },
1168
+ required: ['indexName', 'queryVector'],
1169
+ },
1170
+ },
1171
+ },
1172
+ },
1173
+ responses: {
1174
+ 200: {
1175
+ description: 'Query results',
1176
+ },
1177
+ },
1178
+ }),
1179
+ queryVectors,
1180
+ );
1181
+
1182
+ app.get(
1183
+ '/api/vector/:vectorName/indexes',
1184
+ describeRoute({
1185
+ description: 'List all indexes for a vector store',
1186
+ tags: ['vector'],
1187
+ parameters: [
1188
+ {
1189
+ name: 'vectorName',
1190
+ in: 'path',
1191
+ required: true,
1192
+ schema: { type: 'string' },
1193
+ },
1194
+ ],
1195
+ responses: {
1196
+ 200: {
1197
+ description: 'List of indexes',
1198
+ },
1199
+ },
1200
+ }),
1201
+ listIndexes,
1202
+ );
1203
+
1204
+ app.get(
1205
+ '/api/vector/:vectorName/indexes/:indexName',
1206
+ describeRoute({
1207
+ description: 'Get details about a specific index',
1208
+ tags: ['vector'],
1209
+ parameters: [
1210
+ {
1211
+ name: 'vectorName',
1212
+ in: 'path',
1213
+ required: true,
1214
+ schema: { type: 'string' },
1215
+ },
1216
+ {
1217
+ name: 'indexName',
1218
+ in: 'path',
1219
+ required: true,
1220
+ schema: { type: 'string' },
1221
+ },
1222
+ ],
1223
+ responses: {
1224
+ 200: {
1225
+ description: 'Index details',
1226
+ },
1227
+ },
1228
+ }),
1229
+ describeIndex,
1230
+ );
1231
+
1232
+ app.delete(
1233
+ '/api/vector/:vectorName/indexes/:indexName',
1234
+ describeRoute({
1235
+ description: 'Delete a specific index',
1236
+ tags: ['vector'],
1237
+ parameters: [
1238
+ {
1239
+ name: 'vectorName',
1240
+ in: 'path',
1241
+ required: true,
1242
+ schema: { type: 'string' },
1243
+ },
1244
+ {
1245
+ name: 'indexName',
1246
+ in: 'path',
1247
+ required: true,
1248
+ schema: { type: 'string' },
1249
+ },
1250
+ ],
1251
+ responses: {
1252
+ 200: {
1253
+ description: 'Index deleted successfully',
1254
+ },
1255
+ },
1256
+ }),
1257
+ deleteIndex,
1258
+ );
1259
+
1260
+ app.get(
1261
+ '/openapi.json',
1262
+ openAPISpecs(app, {
1263
+ documentation: {
1264
+ info: { title: 'Mastra API', version: '1.0.0', description: 'Mastra API' },
1265
+ },
1266
+ }),
1267
+ );
1268
+
1269
+ app.get('/swagger-ui', swaggerUI({ url: '/openapi.json' }));
1270
+
1271
+ if (options?.swaggerUI) {
1272
+ app.get('/swagger-ui', swaggerUI({ url: '/openapi.json' }));
1273
+ }
1274
+
1275
+ if (options?.playground) {
1276
+ // SSE endpoint for refresh notifications
1277
+ app.get('/refresh-events', handleClientsRefresh);
1278
+
1279
+ // Trigger refresh for all clients
1280
+ app.post('/__refresh', handleTriggerClientsRefresh);
1281
+ // Playground routes - these should come after API routes
1282
+ // Serve assets with specific MIME types
1283
+ app.use('/assets/*', async (c, next) => {
1284
+ const path = c.req.path;
1285
+ if (path.endsWith('.js')) {
1286
+ c.header('Content-Type', 'application/javascript');
1287
+ } else if (path.endsWith('.css')) {
1288
+ c.header('Content-Type', 'text/css');
1289
+ }
1290
+ await next();
1291
+ });
1292
+
1293
+ // Serve static assets from playground directory
1294
+ app.use(
1295
+ '/assets/*',
1296
+ serveStatic({
1297
+ root: './playground/assets',
1298
+ }),
1299
+ );
1300
+
1301
+ // Serve extra static files from playground directory
1302
+ app.use(
1303
+ '*',
1304
+ serveStatic({
1305
+ root: './playground',
1306
+ }),
1307
+ );
1308
+ }
1309
+
1310
+ // Catch-all route to serve index.html for any non-API routes
1311
+ app.get('*', async (c, next) => {
1312
+ // Skip if it's an API route
1313
+ if (
1314
+ c.req.path.startsWith('/api/') ||
1315
+ c.req.path.startsWith('/swagger-ui') ||
1316
+ c.req.path.startsWith('/openapi.json')
1317
+ ) {
1318
+ return await next();
1319
+ }
1320
+
1321
+ if (options?.playground) {
1322
+ // For all other routes, serve index.html
1323
+ const indexHtml = await readFile(join(process.cwd(), './playground/index.html'), 'utf-8');
1324
+ return c.newResponse(indexHtml, 200, { 'Content-Type': 'text/html' });
1325
+ }
1326
+
1327
+ return c.newResponse(html, 200, { 'Content-Type': 'text/html' });
1328
+ });
1329
+
1330
+ return app;
1331
+ }
1332
+
1333
+ export async function createNodeServer(
1334
+ mastra: Mastra,
1335
+ options: { playground?: boolean; swaggerUI?: boolean; apiReqLogs?: boolean } = {},
1336
+ ) {
1337
+ const app = await createHonoServer(mastra, options);
1338
+ return serve(
1339
+ {
1340
+ fetch: app.fetch,
1341
+ port: Number(process.env.PORT) || 4111,
1342
+ },
1343
+ () => {
1344
+ const logger = mastra.getLogger();
1345
+ logger.info(`๐Ÿฆ„ Mastra API running on port ${process.env.PORT || 4111}/api`);
1346
+ logger.info(`๐Ÿ“š Open API documentation available at http://localhost:${process.env.PORT || 4111}/openapi.json`);
1347
+ if (options?.swaggerUI) {
1348
+ logger.info(`๐Ÿงช Swagger UI available at http://localhost:${process.env.PORT || 4111}/swagger-ui`);
1349
+ }
1350
+ if (options?.playground) {
1351
+ logger.info(`๐Ÿ‘จโ€๐Ÿ’ป Playground available at http://localhost:${process.env.PORT || 4111}/`);
1352
+ }
1353
+ },
1354
+ );
1355
+ }