@telepat/rilo 0.1.0

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 (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +209 -0
  3. package/index.js +1 -0
  4. package/models/black-forest-labs__flux-2-pro.json +78 -0
  5. package/models/black-forest-labs__flux-schnell.json +95 -0
  6. package/models/bytedance__seedream-4.json +71 -0
  7. package/models/deepseek-ai__deepseek-v3.json +61 -0
  8. package/models/google__nano-banana-pro.json +92 -0
  9. package/models/google__veo-3.1-fast.json +93 -0
  10. package/models/google__veo-3.1.json +93 -0
  11. package/models/jaaari__kokoro-82m.json +86 -0
  12. package/models/kwaivgi__kling-v3-video.json +101 -0
  13. package/models/minimax__speech-02-turbo.json +141 -0
  14. package/models/pixverse__pixverse-v5.6.json +113 -0
  15. package/models/prunaai__z-image-turbo.json +107 -0
  16. package/models/resemble-ai__chatterbox-turbo.json +102 -0
  17. package/models/wan-video__wan-2.2-i2v-fast.json +139 -0
  18. package/package.json +67 -0
  19. package/src/api/firebaseFunction.js +46 -0
  20. package/src/api/middleware/auth.js +70 -0
  21. package/src/api/openapi/generateOpenApi.js +21 -0
  22. package/src/api/openapi/spec.js +831 -0
  23. package/src/api/routes/jobs.js +45 -0
  24. package/src/api/routes/projectAssets.js +63 -0
  25. package/src/api/routes/projects.js +647 -0
  26. package/src/api/routes/webhooks.js +13 -0
  27. package/src/api/server.js +88 -0
  28. package/src/backends/firebaseClient.js +57 -0
  29. package/src/backends/outputBackend.js +186 -0
  30. package/src/backends/projectMetadataBackend.js +550 -0
  31. package/src/cli/commands/openHome.js +70 -0
  32. package/src/cli/commands/settingsFlow.js +196 -0
  33. package/src/cli/index.js +192 -0
  34. package/src/config/env.js +158 -0
  35. package/src/config/keystore.js +175 -0
  36. package/src/config/models.js +281 -0
  37. package/src/config/settingsSchema.js +214 -0
  38. package/src/media/ffmpeg.js +144 -0
  39. package/src/media/files.js +77 -0
  40. package/src/media/subtitles.js +444 -0
  41. package/src/observability/apiTrace.js +17 -0
  42. package/src/observability/logger.js +7 -0
  43. package/src/observability/metrics.js +10 -0
  44. package/src/pipeline/inputSanitizer.js +6 -0
  45. package/src/pipeline/orchestrator.js +1669 -0
  46. package/src/policy/contentGuardrails.js +30 -0
  47. package/src/providers/predictions.js +188 -0
  48. package/src/providers/replicateClient.js +12 -0
  49. package/src/steps/alignSubtitles.js +156 -0
  50. package/src/steps/burnInSubtitles.js +22 -0
  51. package/src/steps/composeFinalVideo.js +57 -0
  52. package/src/steps/generateKeyframes.js +70 -0
  53. package/src/steps/generateVideoSegments.js +95 -0
  54. package/src/steps/generateVoiceover.js +128 -0
  55. package/src/steps/imageToVideoAdapters.js +100 -0
  56. package/src/steps/script.js +177 -0
  57. package/src/steps/textToImageAdapters.js +87 -0
  58. package/src/store/assetStore.js +5 -0
  59. package/src/store/jobStore.js +102 -0
  60. package/src/store/projectAnalyticsStore.js +625 -0
  61. package/src/store/projectStore.js +684 -0
  62. package/src/store/settingsStore.js +155 -0
  63. package/src/store/staleAssetStore.js +63 -0
  64. package/src/types/job.js +28 -0
  65. package/src/types/media.js +28 -0
  66. package/src/worker/processor.js +24 -0
@@ -0,0 +1,831 @@
1
+ import {
2
+ DEFAULT_MODEL_SELECTIONS,
3
+ MODEL_SELECTION_KEYS,
4
+ getSupportedModelIdsForCategory
5
+ } from '../../config/models.js';
6
+
7
+ function jsonContent(schema) {
8
+ return {
9
+ 'application/json': {
10
+ schema
11
+ }
12
+ };
13
+ }
14
+
15
+ const modelSelectionProperties = Object.fromEntries(
16
+ MODEL_SELECTION_KEYS.map((category) => [
17
+ category,
18
+ {
19
+ type: 'string',
20
+ enum: getSupportedModelIdsForCategory(category),
21
+ default: DEFAULT_MODEL_SELECTIONS[category]
22
+ }
23
+ ])
24
+ );
25
+
26
+ const modelOptionsProperties = Object.fromEntries(
27
+ MODEL_SELECTION_KEYS.map((category) => [
28
+ category,
29
+ {
30
+ type: 'object',
31
+ description: 'Model-specific options validated against model metadata for selected model id.',
32
+ additionalProperties: true
33
+ }
34
+ ])
35
+ );
36
+
37
+ const schemas = {
38
+ ErrorResponse: {
39
+ type: 'object',
40
+ properties: {
41
+ error: { type: 'string' }
42
+ },
43
+ required: ['error'],
44
+ additionalProperties: true
45
+ },
46
+ HealthResponse: {
47
+ type: 'object',
48
+ properties: {
49
+ ok: { type: 'boolean' },
50
+ service: { type: 'string' }
51
+ },
52
+ required: ['ok', 'service'],
53
+ additionalProperties: true
54
+ },
55
+ JobCreateRequest: {
56
+ type: 'object',
57
+ properties: {
58
+ story: { type: 'string' },
59
+ project: { type: 'string' },
60
+ forceRestart: { type: 'boolean' }
61
+ },
62
+ required: ['story'],
63
+ additionalProperties: true
64
+ },
65
+ JobCreateAccepted: {
66
+ type: 'object',
67
+ properties: {
68
+ jobId: { type: 'string' },
69
+ status: { type: 'string' }
70
+ },
71
+ required: ['jobId', 'status'],
72
+ additionalProperties: true
73
+ },
74
+ ProjectsListResponse: {
75
+ type: 'object',
76
+ properties: {
77
+ projects: {
78
+ type: 'array',
79
+ items: { type: 'string' }
80
+ }
81
+ },
82
+ required: ['projects'],
83
+ additionalProperties: true
84
+ },
85
+ ProjectCreateRequest: {
86
+ type: 'object',
87
+ properties: {
88
+ project: { type: 'string' },
89
+ story: { type: 'string' },
90
+ config: { type: 'object', additionalProperties: true },
91
+ metadata: { type: 'object', additionalProperties: true }
92
+ },
93
+ required: ['project'],
94
+ additionalProperties: true
95
+ },
96
+ MetadataPatchRequest: {
97
+ type: 'object',
98
+ properties: {
99
+ metadata: { type: 'object', additionalProperties: true }
100
+ },
101
+ required: ['metadata'],
102
+ additionalProperties: true
103
+ },
104
+ ProjectConfigPatchRequest: {
105
+ type: 'object',
106
+ properties: {
107
+ config: {
108
+ type: 'object',
109
+ properties: {
110
+ aspectRatio: { type: 'string', enum: ['9:16', '16:9', '1:1'] },
111
+ targetDurationSec: { type: 'integer', minimum: 5, maximum: 600 },
112
+ finalDurationMode: { type: 'string', enum: ['match_audio', 'match_visual'] },
113
+ keyframeWidth: { type: 'integer', minimum: 64, maximum: 2048 },
114
+ keyframeHeight: { type: 'integer', minimum: 64, maximum: 2048 },
115
+ models: {
116
+ type: 'object',
117
+ properties: modelSelectionProperties,
118
+ additionalProperties: false
119
+ },
120
+ modelOptions: {
121
+ type: 'object',
122
+ properties: modelOptionsProperties,
123
+ additionalProperties: false
124
+ },
125
+ subtitleOptions: {
126
+ type: 'object',
127
+ properties: {
128
+ enabled: { type: 'boolean' },
129
+ templateId: {
130
+ type: 'string',
131
+ enum: ['custom', 'social_center_punch', 'social_center_clean', 'social_center_story']
132
+ },
133
+ position: { type: 'string', enum: ['top', 'center', 'bottom'] },
134
+ highlightMode: { type: 'string', enum: ['spoken_upcoming', 'current_only'] },
135
+ fontName: { type: 'string' },
136
+ fontSize: { type: 'integer', minimum: 16, maximum: 120 },
137
+ bold: { type: 'boolean' },
138
+ italic: { type: 'boolean' },
139
+ makeUppercase: { type: 'boolean' },
140
+ primaryColor: { type: 'string', pattern: '^#[0-9a-fA-F]{6}$' },
141
+ activeColor: { type: 'string', pattern: '^#[0-9a-fA-F]{6}$' },
142
+ outlineColor: { type: 'string', pattern: '^#[0-9a-fA-F]{6}$' },
143
+ backgroundEnabled: { type: 'boolean' },
144
+ backgroundColor: { type: 'string', pattern: '^#[0-9a-fA-F]{6}$' },
145
+ backgroundOpacity: { type: 'number', minimum: 0, maximum: 0.85 },
146
+ outline: { type: 'integer', minimum: 0, maximum: 12 },
147
+ shadow: { type: 'integer', minimum: 0, maximum: 12 },
148
+ marginV: { type: 'integer', minimum: 0, maximum: 400 },
149
+ maxWordsPerLine: { type: 'integer', minimum: 1, maximum: 20 },
150
+ maxLines: { type: 'integer', minimum: 1, maximum: 3 }
151
+ },
152
+ additionalProperties: false
153
+ }
154
+ },
155
+ required: ['aspectRatio', 'targetDurationSec', 'finalDurationMode'],
156
+ additionalProperties: false
157
+ }
158
+ },
159
+ required: ['config'],
160
+ additionalProperties: true
161
+ },
162
+ ProjectContentPatchRequest: {
163
+ type: 'object',
164
+ properties: {
165
+ story: { type: 'string' },
166
+ script: { type: 'string' },
167
+ shots: {
168
+ type: 'array',
169
+ items: { type: 'string' }
170
+ },
171
+ prompts: {
172
+ type: 'array',
173
+ items: { type: 'string' }
174
+ },
175
+ tone: { type: 'string' }
176
+ },
177
+ additionalProperties: true
178
+ },
179
+ ProjectRegenerateRequest: {
180
+ type: 'object',
181
+ properties: {
182
+ forceRestart: { type: 'boolean' },
183
+ targetType: {
184
+ type: 'string',
185
+ enum: ['script', 'voiceover', 'keyframe', 'segment', 'align', 'burnin']
186
+ },
187
+ index: {
188
+ type: 'integer',
189
+ minimum: 0
190
+ }
191
+ },
192
+ additionalProperties: true
193
+ },
194
+ GenericObjectResponse: {
195
+ type: 'object',
196
+ additionalProperties: true
197
+ }
198
+ };
199
+
200
+ export function buildOpenApiSpec({ baseUrl = 'http://localhost:3000' } = {}) {
201
+ return {
202
+ openapi: '3.1.0',
203
+ info: {
204
+ title: 'Rilo API',
205
+ version: '0.1.0',
206
+ description: 'API for Rilo jobs, projects metadata, and operational endpoints.'
207
+ },
208
+ servers: [{ url: baseUrl }],
209
+ security: [{ bearerAuth: [] }],
210
+ components: {
211
+ securitySchemes: {
212
+ bearerAuth: {
213
+ type: 'http',
214
+ scheme: 'bearer',
215
+ bearerFormat: 'Token'
216
+ }
217
+ },
218
+ schemas
219
+ },
220
+ paths: {
221
+ '/health': {
222
+ get: {
223
+ summary: 'Service health check',
224
+ security: [],
225
+ responses: {
226
+ 200: {
227
+ description: 'Service is healthy',
228
+ content: jsonContent({ $ref: '#/components/schemas/HealthResponse' })
229
+ }
230
+ }
231
+ }
232
+ },
233
+ '/openapi.json': {
234
+ get: {
235
+ summary: 'Get OpenAPI document',
236
+ security: [],
237
+ responses: {
238
+ 200: {
239
+ description: 'OpenAPI document',
240
+ content: jsonContent({ type: 'object', additionalProperties: true })
241
+ }
242
+ }
243
+ }
244
+ },
245
+ '/docs': {
246
+ get: {
247
+ summary: 'OpenAPI Swagger UI',
248
+ security: [],
249
+ responses: {
250
+ 200: {
251
+ description: 'Swagger UI HTML',
252
+ content: {
253
+ 'text/html': {
254
+ schema: { type: 'string' }
255
+ }
256
+ }
257
+ }
258
+ }
259
+ }
260
+ },
261
+ '/webhooks/replicate': {
262
+ post: {
263
+ summary: 'Replicate webhook callback (currently disabled)',
264
+ security: [],
265
+ requestBody: {
266
+ required: false,
267
+ content: jsonContent({ type: 'object', additionalProperties: true })
268
+ },
269
+ responses: {
270
+ 501: {
271
+ description: 'Webhook handling not implemented',
272
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
273
+ }
274
+ }
275
+ }
276
+ },
277
+ '/jobs': {
278
+ post: {
279
+ summary: 'Create a new generation job',
280
+ requestBody: {
281
+ required: true,
282
+ content: jsonContent({ $ref: '#/components/schemas/JobCreateRequest' })
283
+ },
284
+ responses: {
285
+ 202: {
286
+ description: 'Job accepted',
287
+ content: jsonContent({ $ref: '#/components/schemas/JobCreateAccepted' })
288
+ },
289
+ 400: {
290
+ description: 'Invalid request',
291
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
292
+ },
293
+ 401: {
294
+ description: 'Missing or invalid bearer token',
295
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
296
+ },
297
+ 409: {
298
+ description: 'Project has active job',
299
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
300
+ }
301
+ }
302
+ }
303
+ },
304
+ '/jobs/{jobId}': {
305
+ get: {
306
+ summary: 'Get job status',
307
+ parameters: [
308
+ {
309
+ name: 'jobId',
310
+ in: 'path',
311
+ required: true,
312
+ schema: { type: 'string' }
313
+ }
314
+ ],
315
+ responses: {
316
+ 200: {
317
+ description: 'Job details',
318
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
319
+ },
320
+ 401: {
321
+ description: 'Missing or invalid bearer token',
322
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
323
+ },
324
+ 404: {
325
+ description: 'Job not found',
326
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
327
+ }
328
+ }
329
+ }
330
+ },
331
+ '/projects': {
332
+ get: {
333
+ summary: 'List projects',
334
+ responses: {
335
+ 200: {
336
+ description: 'Projects list',
337
+ content: jsonContent({ $ref: '#/components/schemas/ProjectsListResponse' })
338
+ },
339
+ 401: {
340
+ description: 'Missing or invalid bearer token',
341
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
342
+ },
343
+ 500: {
344
+ description: 'Backend failure',
345
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
346
+ }
347
+ }
348
+ },
349
+ post: {
350
+ summary: 'Create or initialize project metadata',
351
+ requestBody: {
352
+ required: true,
353
+ content: jsonContent({ $ref: '#/components/schemas/ProjectCreateRequest' })
354
+ },
355
+ responses: {
356
+ 201: {
357
+ description: 'Project created',
358
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
359
+ },
360
+ 400: {
361
+ description: 'Validation error',
362
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
363
+ },
364
+ 401: {
365
+ description: 'Missing or invalid bearer token',
366
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
367
+ }
368
+ }
369
+ }
370
+ },
371
+ '/projects/{project}': {
372
+ get: {
373
+ summary: 'Get project details',
374
+ parameters: [
375
+ {
376
+ name: 'project',
377
+ in: 'path',
378
+ required: true,
379
+ schema: { type: 'string' }
380
+ }
381
+ ],
382
+ responses: {
383
+ 200: {
384
+ description: 'Project details',
385
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
386
+ },
387
+ 401: {
388
+ description: 'Missing or invalid bearer token',
389
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
390
+ },
391
+ 404: {
392
+ description: 'Project not found',
393
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
394
+ }
395
+ }
396
+ }
397
+ },
398
+ '/projects/{project}/assets/{assetPath}': {
399
+ get: {
400
+ summary: 'Read a local project asset file over HTTP',
401
+ description: 'For local backend only. Supports Authorization Bearer token or access_token query parameter for media tags.',
402
+ parameters: [
403
+ {
404
+ name: 'project',
405
+ in: 'path',
406
+ required: true,
407
+ schema: { type: 'string' }
408
+ },
409
+ {
410
+ name: 'assetPath',
411
+ in: 'path',
412
+ required: true,
413
+ schema: { type: 'string' },
414
+ description: 'Project-relative file path (nested paths supported).'
415
+ },
416
+ {
417
+ name: 'access_token',
418
+ in: 'query',
419
+ required: false,
420
+ schema: { type: 'string' },
421
+ description: 'Alternative to Authorization header for browser media tags.'
422
+ }
423
+ ],
424
+ responses: {
425
+ 200: {
426
+ description: 'Asset file content',
427
+ content: {
428
+ '*/*': {
429
+ schema: {
430
+ type: 'string',
431
+ format: 'binary'
432
+ }
433
+ }
434
+ }
435
+ },
436
+ 400: {
437
+ description: 'Validation error or non-local backend',
438
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
439
+ },
440
+ 401: {
441
+ description: 'Missing or invalid token',
442
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
443
+ },
444
+ 404: {
445
+ description: 'Asset not found',
446
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
447
+ }
448
+ }
449
+ }
450
+ },
451
+ '/projects/{project}/config': {
452
+ patch: {
453
+ summary: 'Update project config (aspect ratio, duration, keyframe dimensions)',
454
+ parameters: [
455
+ {
456
+ name: 'project',
457
+ in: 'path',
458
+ required: true,
459
+ schema: { type: 'string' }
460
+ }
461
+ ],
462
+ requestBody: {
463
+ required: true,
464
+ content: jsonContent({ $ref: '#/components/schemas/ProjectConfigPatchRequest' })
465
+ },
466
+ responses: {
467
+ 200: {
468
+ description: 'Config updated and synced',
469
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
470
+ },
471
+ 400: {
472
+ description: 'Validation error',
473
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
474
+ },
475
+ 401: {
476
+ description: 'Missing or invalid bearer token',
477
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
478
+ }
479
+ }
480
+ }
481
+ },
482
+ '/projects/{project}/metadata': {
483
+ patch: {
484
+ summary: 'Update project metadata',
485
+ parameters: [
486
+ {
487
+ name: 'project',
488
+ in: 'path',
489
+ required: true,
490
+ schema: { type: 'string' }
491
+ }
492
+ ],
493
+ requestBody: {
494
+ required: true,
495
+ content: jsonContent({ $ref: '#/components/schemas/MetadataPatchRequest' })
496
+ },
497
+ responses: {
498
+ 200: {
499
+ description: 'Metadata updated',
500
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
501
+ },
502
+ 400: {
503
+ description: 'Validation error',
504
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
505
+ },
506
+ 401: {
507
+ description: 'Missing or invalid bearer token',
508
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
509
+ }
510
+ }
511
+ }
512
+ },
513
+ '/projects/{project}/content': {
514
+ patch: {
515
+ summary: 'Update project story/script/shots/tone content',
516
+ parameters: [
517
+ {
518
+ name: 'project',
519
+ in: 'path',
520
+ required: true,
521
+ schema: { type: 'string' }
522
+ }
523
+ ],
524
+ requestBody: {
525
+ required: true,
526
+ content: jsonContent({ $ref: '#/components/schemas/ProjectContentPatchRequest' })
527
+ },
528
+ responses: {
529
+ 200: {
530
+ description: 'Project content updated and synced',
531
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
532
+ },
533
+ 400: {
534
+ description: 'Validation error',
535
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
536
+ },
537
+ 401: {
538
+ description: 'Missing or invalid bearer token',
539
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
540
+ }
541
+ }
542
+ }
543
+ },
544
+ '/projects/{project}/regenerate': {
545
+ post: {
546
+ summary: 'Regenerate project assets or a specific script/voiceover/keyframe/segment target',
547
+ parameters: [
548
+ {
549
+ name: 'project',
550
+ in: 'path',
551
+ required: true,
552
+ schema: { type: 'string' }
553
+ }
554
+ ],
555
+ requestBody: {
556
+ required: false,
557
+ content: jsonContent({ $ref: '#/components/schemas/ProjectRegenerateRequest' })
558
+ },
559
+ responses: {
560
+ 200: {
561
+ description: 'Targeted script/voiceover/keyframe/segment regenerated and downstream marked dirty',
562
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
563
+ },
564
+ 202: {
565
+ description: 'Regeneration job accepted',
566
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
567
+ },
568
+ 400: {
569
+ description: 'Validation error',
570
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
571
+ },
572
+ 401: {
573
+ description: 'Missing or invalid bearer token',
574
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
575
+ },
576
+ 409: {
577
+ description: 'Project has active job',
578
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
579
+ }
580
+ }
581
+ }
582
+ },
583
+ '/projects/{project}/logs': {
584
+ get: {
585
+ summary: 'Get model request logs',
586
+ parameters: [
587
+ {
588
+ name: 'project',
589
+ in: 'path',
590
+ required: true,
591
+ schema: { type: 'string' }
592
+ },
593
+ {
594
+ name: 'includeEntries',
595
+ in: 'query',
596
+ required: false,
597
+ schema: { type: 'boolean' }
598
+ },
599
+ {
600
+ name: 'limit',
601
+ in: 'query',
602
+ required: false,
603
+ schema: { type: 'integer', minimum: 1 }
604
+ }
605
+ ],
606
+ responses: {
607
+ 200: {
608
+ description: 'Logs response',
609
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
610
+ },
611
+ 400: {
612
+ description: 'Validation error',
613
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
614
+ },
615
+ 401: {
616
+ description: 'Missing or invalid bearer token',
617
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
618
+ }
619
+ }
620
+ }
621
+ },
622
+ '/projects/{project}/prompts': {
623
+ get: {
624
+ summary: 'Get extracted prompts from script/logs',
625
+ parameters: [
626
+ {
627
+ name: 'project',
628
+ in: 'path',
629
+ required: true,
630
+ schema: { type: 'string' }
631
+ },
632
+ {
633
+ name: 'limit',
634
+ in: 'query',
635
+ required: false,
636
+ schema: { type: 'integer', minimum: 1 }
637
+ }
638
+ ],
639
+ responses: {
640
+ 200: {
641
+ description: 'Prompt extraction response',
642
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
643
+ },
644
+ 400: {
645
+ description: 'Validation error',
646
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
647
+ },
648
+ 401: {
649
+ description: 'Missing or invalid bearer token',
650
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
651
+ }
652
+ }
653
+ }
654
+ },
655
+ '/projects/{project}/artifacts': {
656
+ get: {
657
+ summary: 'Get artifacts manifest',
658
+ parameters: [
659
+ {
660
+ name: 'project',
661
+ in: 'path',
662
+ required: true,
663
+ schema: { type: 'string' }
664
+ }
665
+ ],
666
+ responses: {
667
+ 200: {
668
+ description: 'Artifacts manifest',
669
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
670
+ },
671
+ 400: {
672
+ description: 'Validation error',
673
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
674
+ },
675
+ 401: {
676
+ description: 'Missing or invalid bearer token',
677
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
678
+ }
679
+ }
680
+ }
681
+ },
682
+ '/projects/{project}/sync': {
683
+ get: {
684
+ summary: 'Get backend sync state',
685
+ parameters: [
686
+ {
687
+ name: 'project',
688
+ in: 'path',
689
+ required: true,
690
+ schema: { type: 'string' }
691
+ }
692
+ ],
693
+ responses: {
694
+ 200: {
695
+ description: 'Sync status',
696
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
697
+ },
698
+ 400: {
699
+ description: 'Validation error',
700
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
701
+ },
702
+ 401: {
703
+ description: 'Missing or invalid bearer token',
704
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
705
+ }
706
+ }
707
+ }
708
+ },
709
+ '/projects/{project}/snapshots': {
710
+ get: {
711
+ summary: 'List project snapshots',
712
+ parameters: [
713
+ {
714
+ name: 'project',
715
+ in: 'path',
716
+ required: true,
717
+ schema: { type: 'string' }
718
+ }
719
+ ],
720
+ responses: {
721
+ 200: {
722
+ description: 'Snapshots list',
723
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
724
+ },
725
+ 400: {
726
+ description: 'Validation error',
727
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
728
+ },
729
+ 401: {
730
+ description: 'Missing or invalid bearer token',
731
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
732
+ }
733
+ }
734
+ }
735
+ },
736
+ '/projects/{project}/analytics': {
737
+ get: {
738
+ summary: 'Get project analytics summary',
739
+ parameters: [
740
+ {
741
+ name: 'project',
742
+ in: 'path',
743
+ required: true,
744
+ schema: { type: 'string' }
745
+ }
746
+ ],
747
+ responses: {
748
+ 200: {
749
+ description: 'Analytics summary',
750
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
751
+ },
752
+ 400: {
753
+ description: 'Validation error',
754
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
755
+ },
756
+ 401: {
757
+ description: 'Missing or invalid bearer token',
758
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
759
+ }
760
+ }
761
+ }
762
+ },
763
+ '/projects/{project}/analytics/runs': {
764
+ get: {
765
+ summary: 'List analytics runs',
766
+ parameters: [
767
+ {
768
+ name: 'project',
769
+ in: 'path',
770
+ required: true,
771
+ schema: { type: 'string' }
772
+ },
773
+ {
774
+ name: 'limit',
775
+ in: 'query',
776
+ required: false,
777
+ schema: { type: 'integer', minimum: 1 }
778
+ }
779
+ ],
780
+ responses: {
781
+ 200: {
782
+ description: 'Analytics runs',
783
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
784
+ },
785
+ 400: {
786
+ description: 'Validation error',
787
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
788
+ },
789
+ 401: {
790
+ description: 'Missing or invalid bearer token',
791
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
792
+ }
793
+ }
794
+ }
795
+ },
796
+ '/projects/{project}/analytics/runs/{runId}': {
797
+ get: {
798
+ summary: 'Get analytics run detail',
799
+ parameters: [
800
+ {
801
+ name: 'project',
802
+ in: 'path',
803
+ required: true,
804
+ schema: { type: 'string' }
805
+ },
806
+ {
807
+ name: 'runId',
808
+ in: 'path',
809
+ required: true,
810
+ schema: { type: 'string' }
811
+ }
812
+ ],
813
+ responses: {
814
+ 200: {
815
+ description: 'Analytics run detail',
816
+ content: jsonContent({ $ref: '#/components/schemas/GenericObjectResponse' })
817
+ },
818
+ 401: {
819
+ description: 'Missing or invalid bearer token',
820
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
821
+ },
822
+ 404: {
823
+ description: 'Run not found',
824
+ content: jsonContent({ $ref: '#/components/schemas/ErrorResponse' })
825
+ }
826
+ }
827
+ }
828
+ }
829
+ }
830
+ };
831
+ }