@kb-labs/rest-api-app 1.3.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 (255) hide show
  1. package/.kb/agents/sessions/session-1771531145393-ws3uh6q/turns.json +42 -0
  2. package/.kb/agents/sessions/session-1771548930486-ui6rtvm/turns.json +33 -0
  3. package/.kb/agents/sessions/session-1771549691485-nibqroq/turns.json +133 -0
  4. package/.kb/agents/sessions/session-1771550943182-dkwqdjc/turns.json +130 -0
  5. package/.kb/agents/sessions/session-1771551564182-cr4bwzn/turns.json +349 -0
  6. package/.kb/agents/sessions/session-1771552401370-g4ztwd1/turns.json +206 -0
  7. package/.kb/commit/current/plan.json +248 -0
  8. package/.kb/commit/current/status.json +472 -0
  9. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/health.d.ts +10 -0
  10. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/health.js +215 -0
  11. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/health.js.map +1 -0
  12. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/list.d.ts +10 -0
  13. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/list.js +271 -0
  14. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/list.js.map +1 -0
  15. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/logs.d.ts +10 -0
  16. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/logs.js +230 -0
  17. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/logs.js.map +1 -0
  18. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/metrics.d.ts +10 -0
  19. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/metrics.js +228 -0
  20. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/metrics.js.map +1 -0
  21. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/run.d.ts +11 -0
  22. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/run.js +281 -0
  23. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/run.js.map +1 -0
  24. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/status.d.ts +10 -0
  25. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/status.js +266 -0
  26. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/status.js.map +1 -0
  27. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/workflow-run.d.ts +11 -0
  28. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/workflow-run.js +284 -0
  29. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/workflow-run.js.map +1 -0
  30. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/flags-WLdpSZl4.d.ts +77 -0
  31. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/index.d.ts +2 -0
  32. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/index.js +441 -0
  33. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/index.js.map +1 -0
  34. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/manifest.d.ts +196 -0
  35. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/manifest.js +441 -0
  36. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/manifest.js.map +1 -0
  37. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/cron-list-handler.d.ts +19 -0
  38. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/cron-list-handler.js +48 -0
  39. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/cron-list-handler.js.map +1 -0
  40. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/index.d.ts +6 -0
  41. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/index.js +170 -0
  42. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/index.js.map +1 -0
  43. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-cancel-handler.d.ts +12 -0
  44. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-cancel-handler.js +52 -0
  45. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-cancel-handler.js.map +1 -0
  46. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-detail-handler.d.ts +22 -0
  47. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-detail-handler.js +52 -0
  48. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-detail-handler.js.map +1 -0
  49. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-logs-handler.d.ts +13 -0
  50. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-logs-handler.js +52 -0
  51. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-logs-handler.js.map +1 -0
  52. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-steps-handler.d.ts +9 -0
  53. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-steps-handler.js +43 -0
  54. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-steps-handler.js.map +1 -0
  55. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/jobs-list-handler.d.ts +26 -0
  56. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/jobs-list-handler.js +63 -0
  57. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/jobs-list-handler.js.map +1 -0
  58. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/pending-approvals-handler.d.ts +9 -0
  59. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/pending-approvals-handler.js +46 -0
  60. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/pending-approvals-handler.js.map +1 -0
  61. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/resolve-approval-handler.d.ts +16 -0
  62. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/resolve-approval-handler.js +58 -0
  63. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/resolve-approval-handler.js.map +1 -0
  64. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/run-detail-handler.d.ts +9 -0
  65. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/run-detail-handler.js +46 -0
  66. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/run-detail-handler.js.map +1 -0
  67. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/runs-list-handler.d.ts +11 -0
  68. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/runs-list-handler.js +50 -0
  69. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/runs-list-handler.js.map +1 -0
  70. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/stats-handler.d.ts +7 -0
  71. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/stats-handler.js +39 -0
  72. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/stats-handler.js.map +1 -0
  73. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-detail-handler.d.ts +10 -0
  74. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-detail-handler.js +46 -0
  75. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-detail-handler.js.map +1 -0
  76. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-cancel-handler.d.ts +13 -0
  77. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-cancel-handler.js +47 -0
  78. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-cancel-handler.js.map +1 -0
  79. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-handler.d.ts +14 -0
  80. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-handler.js +53 -0
  81. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-handler.js.map +1 -0
  82. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-runs-handler.d.ts +13 -0
  83. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-runs-handler.js +54 -0
  84. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-runs-handler.js.map +1 -0
  85. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflows-list-handler.d.ts +12 -0
  86. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflows-list-handler.js +51 -0
  87. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflows-list-handler.js.map +1 -0
  88. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/logs-channel.d.ts +17 -0
  89. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/logs-channel.js +133 -0
  90. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/logs-channel.js.map +1 -0
  91. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/progress-channel.d.ts +11 -0
  92. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/progress-channel.js +46 -0
  93. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/progress-channel.js.map +1 -0
  94. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/health.d.ts +10 -0
  95. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/health.js +215 -0
  96. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/health.js.map +1 -0
  97. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/list.d.ts +10 -0
  98. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/list.js +271 -0
  99. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/list.js.map +1 -0
  100. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/logs.d.ts +10 -0
  101. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/logs.js +230 -0
  102. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/logs.js.map +1 -0
  103. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/metrics.d.ts +10 -0
  104. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/metrics.js +228 -0
  105. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/metrics.js.map +1 -0
  106. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/run.d.ts +11 -0
  107. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/run.js +281 -0
  108. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/run.js.map +1 -0
  109. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/status.d.ts +10 -0
  110. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/status.js +266 -0
  111. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/status.js.map +1 -0
  112. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/workflow-run.d.ts +11 -0
  113. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/workflow-run.js +284 -0
  114. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/workflow-run.js.map +1 -0
  115. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/flags-WLdpSZl4.d.ts +77 -0
  116. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/index.d.ts +2 -0
  117. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/index.js +441 -0
  118. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/index.js.map +1 -0
  119. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/manifest.d.ts +196 -0
  120. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/manifest.js +441 -0
  121. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/manifest.js.map +1 -0
  122. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/cron-list-handler.d.ts +19 -0
  123. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/cron-list-handler.js +48 -0
  124. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/cron-list-handler.js.map +1 -0
  125. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/index.d.ts +6 -0
  126. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/index.js +170 -0
  127. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/index.js.map +1 -0
  128. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-cancel-handler.d.ts +12 -0
  129. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-cancel-handler.js +52 -0
  130. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-cancel-handler.js.map +1 -0
  131. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-detail-handler.d.ts +22 -0
  132. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-detail-handler.js +52 -0
  133. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-detail-handler.js.map +1 -0
  134. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-logs-handler.d.ts +13 -0
  135. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-logs-handler.js +52 -0
  136. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-logs-handler.js.map +1 -0
  137. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-steps-handler.d.ts +9 -0
  138. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-steps-handler.js +43 -0
  139. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-steps-handler.js.map +1 -0
  140. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/jobs-list-handler.d.ts +26 -0
  141. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/jobs-list-handler.js +63 -0
  142. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/jobs-list-handler.js.map +1 -0
  143. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/pending-approvals-handler.d.ts +9 -0
  144. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/pending-approvals-handler.js +46 -0
  145. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/pending-approvals-handler.js.map +1 -0
  146. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/resolve-approval-handler.d.ts +16 -0
  147. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/resolve-approval-handler.js +58 -0
  148. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/resolve-approval-handler.js.map +1 -0
  149. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/run-detail-handler.d.ts +9 -0
  150. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/run-detail-handler.js +46 -0
  151. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/run-detail-handler.js.map +1 -0
  152. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/runs-list-handler.d.ts +11 -0
  153. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/runs-list-handler.js +50 -0
  154. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/runs-list-handler.js.map +1 -0
  155. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/stats-handler.d.ts +7 -0
  156. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/stats-handler.js +39 -0
  157. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/stats-handler.js.map +1 -0
  158. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-detail-handler.d.ts +10 -0
  159. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-detail-handler.js +46 -0
  160. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-detail-handler.js.map +1 -0
  161. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-cancel-handler.d.ts +13 -0
  162. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-cancel-handler.js +47 -0
  163. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-cancel-handler.js.map +1 -0
  164. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-handler.d.ts +14 -0
  165. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-handler.js +53 -0
  166. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-handler.js.map +1 -0
  167. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-runs-handler.d.ts +13 -0
  168. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-runs-handler.js +54 -0
  169. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-runs-handler.js.map +1 -0
  170. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflows-list-handler.d.ts +12 -0
  171. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflows-list-handler.js +51 -0
  172. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflows-list-handler.js.map +1 -0
  173. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/logs-channel.d.ts +17 -0
  174. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/logs-channel.js +133 -0
  175. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/logs-channel.js.map +1 -0
  176. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/progress-channel.d.ts +11 -0
  177. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/progress-channel.js +46 -0
  178. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/progress-channel.js.map +1 -0
  179. package/README.md +54 -0
  180. package/eslint.config.js +23 -0
  181. package/package.json +72 -0
  182. package/src/.kb/agents/sessions/session-1773470583796-ximqnfk/kpi-baseline.json +17 -0
  183. package/src/.kb/memory/sessions/session-1773470583796-ximqnfk/fact-sheet.json +1 -0
  184. package/src/bootstrap.ts +233 -0
  185. package/src/diagnostics/header-debug.ts +37 -0
  186. package/src/events/hub.ts +60 -0
  187. package/src/events/index.ts +1 -0
  188. package/src/index.ts +13 -0
  189. package/src/manifest.ts +21 -0
  190. package/src/middleware/__tests__/cache.spec.ts +184 -0
  191. package/src/middleware/__tests__/envelope.spec.ts +268 -0
  192. package/src/middleware/__tests__/metrics.redis.spec.ts +64 -0
  193. package/src/middleware/__tests__/rate-limit.spec.ts +283 -0
  194. package/src/middleware/__tests__/request-id.spec.ts +160 -0
  195. package/src/middleware/cache.ts +67 -0
  196. package/src/middleware/envelope.ts +136 -0
  197. package/src/middleware/error-guard.ts +69 -0
  198. package/src/middleware/index.ts +37 -0
  199. package/src/middleware/metrics.ts +810 -0
  200. package/src/middleware/mock-mode.ts +44 -0
  201. package/src/middleware/prom-metrics.ts +284 -0
  202. package/src/middleware/rate-limit-routes.ts +73 -0
  203. package/src/middleware/rate-limit.ts +72 -0
  204. package/src/middleware/request-id.ts +41 -0
  205. package/src/middleware/request-timeout.ts +69 -0
  206. package/src/middleware/security-headers.ts +24 -0
  207. package/src/middleware/startup-guard.ts +107 -0
  208. package/src/observability/service-contract.ts +192 -0
  209. package/src/plugins/index.ts +118 -0
  210. package/src/routes/__tests__/adapters-date-helpers.spec.ts +332 -0
  211. package/src/routes/__tests__/adapters.spec.ts +680 -0
  212. package/src/routes/__tests__/cache.spec.ts +264 -0
  213. package/src/routes/__tests__/events.spec.ts +434 -0
  214. package/src/routes/__tests__/health.spec.ts +414 -0
  215. package/src/routes/__tests__/logs.spec.ts +494 -0
  216. package/src/routes/__tests__/observability.spec.ts +392 -0
  217. package/src/routes/__tests__/plugins.spec.ts +931 -0
  218. package/src/routes/__tests__/workflow-management.spec.ts +698 -0
  219. package/src/routes/__tests__/workflows.spec.ts +204 -0
  220. package/src/routes/adapter-call.ts +220 -0
  221. package/src/routes/adapters.ts +1206 -0
  222. package/src/routes/analytics.ts +328 -0
  223. package/src/routes/cache.ts +104 -0
  224. package/src/routes/debug-routes.ts +95 -0
  225. package/src/routes/events.ts +115 -0
  226. package/src/routes/health.ts +348 -0
  227. package/src/routes/hello.ts +47 -0
  228. package/src/routes/index.ts +395 -0
  229. package/src/routes/jobs.ts +253 -0
  230. package/src/routes/logs.ts +718 -0
  231. package/src/routes/metrics.ts +120 -0
  232. package/src/routes/observability.ts +1388 -0
  233. package/src/routes/openapi.ts +101 -0
  234. package/src/routes/platform.ts +143 -0
  235. package/src/routes/plugins.ts +998 -0
  236. package/src/routes/readiness.ts +83 -0
  237. package/src/routes/workflow-management.ts +469 -0
  238. package/src/routes/workflows.ts +256 -0
  239. package/src/server.ts +203 -0
  240. package/src/services/historical-metrics.ts +496 -0
  241. package/src/services/incident-analyzer.ts +289 -0
  242. package/src/services/incident-detector.ts +691 -0
  243. package/src/services/incident-schema.sql +76 -0
  244. package/src/services/incident-storage.ts +593 -0
  245. package/src/services/system-metrics-collector.ts +244 -0
  246. package/src/types/fastify.d.ts +58 -0
  247. package/src/utils/__tests__/sse-auth.spec.ts +113 -0
  248. package/src/utils/path-helpers.ts +15 -0
  249. package/src/utils/repo.ts +42 -0
  250. package/src/utils/schema.ts +20 -0
  251. package/src/utils/sse-auth.ts +81 -0
  252. package/test-sandbox.sh +105 -0
  253. package/tsconfig.build.json +15 -0
  254. package/tsconfig.json +9 -0
  255. package/tsup.config.ts +18 -0
@@ -0,0 +1,60 @@
1
+ import { EventEmitter } from 'node:events';
2
+
3
+ export type RegistryBroadcast = {
4
+ type: 'registry';
5
+ rev: number;
6
+ generatedAt?: string;
7
+ partial?: boolean;
8
+ stale?: boolean;
9
+ expiresAt?: string | null;
10
+ ttlMs?: number | null;
11
+ checksum?: string;
12
+ checksumAlgorithm?: 'sha256';
13
+ previousChecksum?: string | null;
14
+ };
15
+
16
+ export type HealthBroadcast = {
17
+ type: 'health';
18
+ status: 'healthy' | 'degraded';
19
+ ts: string;
20
+ ready: boolean;
21
+ reason?: string;
22
+ registryPartial?: boolean;
23
+ registryStale?: boolean;
24
+ registryLoaded?: boolean;
25
+ pluginMountInProgress?: boolean;
26
+ pluginRoutesMounted?: boolean;
27
+ pluginsMounted?: number;
28
+ pluginsFailed?: number;
29
+ lastPluginMountTs?: string | null;
30
+ pluginRoutesLastDurationMs?: number | null;
31
+ redisEnabled?: boolean;
32
+ redisHealthy?: boolean;
33
+ redisStates?: {
34
+ publisher: string | null;
35
+ subscriber: string | null;
36
+ cache: string | null;
37
+ };
38
+ };
39
+
40
+ export type BroadcastEvent = RegistryBroadcast | HealthBroadcast;
41
+
42
+ export class EventHub {
43
+ private emitter: EventEmitter;
44
+
45
+ constructor() {
46
+ this.emitter = new EventEmitter();
47
+ this.emitter.setMaxListeners(0);
48
+ }
49
+
50
+ publish(event: BroadcastEvent): void {
51
+ this.emitter.emit('broadcast', event);
52
+ }
53
+
54
+ subscribe(handler: (event: BroadcastEvent) => void): () => void {
55
+ this.emitter.on('broadcast', handler);
56
+ return () => {
57
+ this.emitter.off('broadcast', handler);
58
+ };
59
+ }
60
+ }
@@ -0,0 +1 @@
1
+ export { EventHub, type BroadcastEvent, type RegistryBroadcast, type HealthBroadcast } from './hub';
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @module @kb-labs/rest-api-app
3
+ * REST API application entry point
4
+ */
5
+
6
+ import { bootstrap } from './bootstrap';
7
+
8
+ // process.cwd() = workspace root when launched via `node ./platform/kb-labs-rest-api/.../dist/index.js`
9
+ bootstrap(process.cwd()).catch((error) => {
10
+ console.error('Failed to start server:', error);
11
+ process.exit(1);
12
+ });
13
+
@@ -0,0 +1,21 @@
1
+ import type { ServiceManifest } from '@kb-labs/plugin-contracts';
2
+
3
+ export const manifest: ServiceManifest = {
4
+ schema: 'kb.service/1',
5
+ id: 'rest',
6
+ name: 'REST API',
7
+ version: '1.2.0',
8
+ description: 'Platform REST API daemon — routes, plugin execution, OpenAPI',
9
+ runtime: {
10
+ entry: 'dist/index.js',
11
+ port: 5050,
12
+ healthCheck: '/api/v1/health',
13
+ },
14
+ dependsOn: ['qdrant'],
15
+ env: {
16
+ PORT: { description: 'HTTP port', default: '5050' },
17
+ NODE_ENV: { description: 'Environment mode', default: 'development' },
18
+ },
19
+ };
20
+
21
+ export default manifest;
@@ -0,0 +1,184 @@
1
+ /**
2
+ * @module @kb-labs/rest-api-app/middleware/__tests__/cache
3
+ *
4
+ * Tests for cache middleware (ETag/Last-Modified support).
5
+ */
6
+
7
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
+ import Fastify from 'fastify';
9
+
10
+ import { generateETag, registerCacheMiddleware } from '../cache';
11
+
12
+ describe('generateETag', () => {
13
+ it('should generate consistent ETag for same string content', () => {
14
+ const content = 'Hello, World!';
15
+ const etag1 = generateETag(content);
16
+ const etag2 = generateETag(content);
17
+
18
+ expect(etag1).toBe(etag2);
19
+ expect(etag1).toMatch(/^"[a-f0-9]{16}"$/);
20
+ });
21
+
22
+ it('should generate different ETags for different content', () => {
23
+ const etag1 = generateETag('Hello');
24
+ const etag2 = generateETag('World');
25
+
26
+ expect(etag1).not.toBe(etag2);
27
+ });
28
+
29
+ it('should handle object content by stringifying', () => {
30
+ const obj = { foo: 'bar', num: 42 };
31
+ const etag = generateETag(obj);
32
+
33
+ expect(etag).toMatch(/^"[a-f0-9]{16}"$/);
34
+
35
+ // Same object should produce same ETag
36
+ const etag2 = generateETag({ foo: 'bar', num: 42 });
37
+ expect(etag).toBe(etag2);
38
+ });
39
+
40
+ it('should handle Buffer content', () => {
41
+ const buffer = Buffer.from('Hello, Buffer!');
42
+ const etag = generateETag(buffer);
43
+
44
+ expect(etag).toMatch(/^"[a-f0-9]{16}"$/);
45
+ });
46
+
47
+ it('should handle empty string', () => {
48
+ const etag = generateETag('');
49
+ expect(etag).toMatch(/^"[a-f0-9]{16}"$/);
50
+ });
51
+
52
+ it('should handle empty object', () => {
53
+ const etag = generateETag({});
54
+ expect(etag).toMatch(/^"[a-f0-9]{16}"$/);
55
+ });
56
+ });
57
+
58
+ describe('registerCacheMiddleware', () => {
59
+ let app: ReturnType<typeof Fastify>;
60
+
61
+ beforeEach(async () => {
62
+ app = Fastify({ logger: false });
63
+ registerCacheMiddleware(app);
64
+
65
+ // Add test route
66
+ app.get('/test', async () => {
67
+ return { message: 'Hello, World!' };
68
+ });
69
+
70
+ app.post('/test', async () => {
71
+ return { created: true };
72
+ });
73
+
74
+ await app.ready();
75
+ });
76
+
77
+ describe('ETag handling', () => {
78
+ it('should add ETag header to GET responses when If-None-Match is provided', async () => {
79
+ const response = await app.inject({
80
+ method: 'GET',
81
+ url: '/test',
82
+ headers: { 'if-none-match': '"invalid-etag"' },
83
+ });
84
+
85
+ expect(response.statusCode).toBe(200);
86
+ expect(response.headers.etag).toMatch(/^"[a-f0-9]{16}"$/);
87
+ });
88
+
89
+ it('should return 304 when ETag matches', async () => {
90
+ // First request to get the ETag
91
+ const firstResponse = await app.inject({
92
+ method: 'GET',
93
+ url: '/test',
94
+ headers: { 'if-none-match': '"dummy"' },
95
+ });
96
+
97
+ const etag = firstResponse.headers.etag as string;
98
+ expect(etag).toBeDefined();
99
+
100
+ // Second request with matching ETag
101
+ const secondResponse = await app.inject({
102
+ method: 'GET',
103
+ url: '/test',
104
+ headers: { 'if-none-match': etag },
105
+ });
106
+
107
+ expect(secondResponse.statusCode).toBe(304);
108
+ // Note: Fastify inject may still include body in response object,
109
+ // but HTTP clients won't receive body content for 304 responses
110
+ });
111
+
112
+ it('should return 304 when weak ETag matches', async () => {
113
+ // First request to get the ETag
114
+ const firstResponse = await app.inject({
115
+ method: 'GET',
116
+ url: '/test',
117
+ headers: { 'if-none-match': '"dummy"' },
118
+ });
119
+
120
+ const etag = firstResponse.headers.etag as string;
121
+
122
+ // Second request with weak ETag
123
+ const secondResponse = await app.inject({
124
+ method: 'GET',
125
+ url: '/test',
126
+ headers: { 'if-none-match': `W/${etag}` },
127
+ });
128
+
129
+ expect(secondResponse.statusCode).toBe(304);
130
+ });
131
+
132
+ it('should not add ETag to POST requests', async () => {
133
+ const response = await app.inject({
134
+ method: 'POST',
135
+ url: '/test',
136
+ headers: { 'if-none-match': '"some-etag"' },
137
+ });
138
+
139
+ expect(response.statusCode).toBe(200);
140
+ expect(response.headers.etag).toBeUndefined();
141
+ });
142
+ });
143
+
144
+ describe('Last-Modified handling', () => {
145
+ it('should add Last-Modified header when If-Modified-Since is provided', async () => {
146
+ const response = await app.inject({
147
+ method: 'GET',
148
+ url: '/test',
149
+ headers: { 'if-modified-since': 'Wed, 01 Jan 2020 00:00:00 GMT' },
150
+ });
151
+
152
+ expect(response.headers['last-modified']).toBeDefined();
153
+ });
154
+ });
155
+
156
+ describe('streaming responses', () => {
157
+ it('should skip cache for SSE responses', async () => {
158
+ const sseApp = Fastify({ logger: false });
159
+ registerCacheMiddleware(sseApp as any);
160
+
161
+ sseApp.get('/events', async (request, reply) => {
162
+ reply.header('content-type', 'text/event-stream');
163
+ return 'data: test\n\n';
164
+ });
165
+
166
+ await sseApp.ready();
167
+
168
+ const response = await sseApp.inject({
169
+ method: 'GET',
170
+ url: '/events',
171
+ headers: { 'if-none-match': '"some-etag"' },
172
+ });
173
+
174
+ expect(response.statusCode).toBe(200);
175
+ expect(response.headers.etag).toBeUndefined();
176
+
177
+ await sseApp.close();
178
+ });
179
+ });
180
+
181
+ afterEach(async () => {
182
+ await app.close();
183
+ });
184
+ });
@@ -0,0 +1,268 @@
1
+ /**
2
+ * @module @kb-labs/rest-api-app/middleware/__tests__/envelope
3
+ *
4
+ * Tests for response envelope middleware.
5
+ */
6
+
7
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
8
+ import Fastify from 'fastify';
9
+ import type { FastifyRequest, FastifyReply } from 'fastify';
10
+ import type { RestApiConfig } from '@kb-labs/rest-api-core';
11
+ import { registerEnvelopeMiddleware } from '../envelope';
12
+
13
+ const TEST_CONFIG: RestApiConfig = {
14
+ port: 3000,
15
+ basePath: '/api/v1',
16
+ apiVersion: '1.0.0',
17
+ cors: {
18
+ origins: [],
19
+ allowCredentials: true,
20
+ profile: 'dev',
21
+ },
22
+ plugins: [],
23
+ mockMode: false,
24
+ };
25
+
26
+ describe('registerEnvelopeMiddleware', () => {
27
+ let app: ReturnType<typeof Fastify>;
28
+
29
+ beforeEach(async () => {
30
+ app = Fastify({ logger: false });
31
+ registerEnvelopeMiddleware(app, TEST_CONFIG);
32
+ });
33
+
34
+ afterEach(async () => {
35
+ await app.close();
36
+ });
37
+
38
+ describe('successful responses', () => {
39
+ it('should wrap JSON response in envelope', async () => {
40
+ app.get('/test', async () => {
41
+ return { message: 'Hello' };
42
+ });
43
+
44
+ await app.ready();
45
+
46
+ const response = await app.inject({
47
+ method: 'GET',
48
+ url: '/test',
49
+ });
50
+
51
+ expect(response.statusCode).toBe(200);
52
+
53
+ const body = response.json();
54
+ expect(body.ok).toBe(true);
55
+ expect(body.data).toEqual({ message: 'Hello' });
56
+ expect(body.meta).toBeDefined();
57
+ expect(body.meta.apiVersion).toBe('1.0.0');
58
+ expect(body.meta.requestId).toBeDefined();
59
+ expect(typeof body.meta.durationMs).toBe('number');
60
+ });
61
+
62
+ it('should add x-schema-version header', async () => {
63
+ app.get('/test', async () => ({ value: 42 }));
64
+
65
+ await app.ready();
66
+
67
+ const response = await app.inject({
68
+ method: 'GET',
69
+ url: '/test',
70
+ });
71
+
72
+ expect(response.headers['x-schema-version']).toBe('1.0.0');
73
+ });
74
+
75
+ it('should handle empty object response', async () => {
76
+ app.get('/empty', async () => ({}));
77
+
78
+ await app.ready();
79
+
80
+ const response = await app.inject({
81
+ method: 'GET',
82
+ url: '/empty',
83
+ });
84
+
85
+ const body = response.json();
86
+ expect(body.ok).toBe(true);
87
+ expect(body.data).toEqual({});
88
+ });
89
+
90
+ it('should handle null response', async () => {
91
+ app.get('/null', async () => null);
92
+
93
+ await app.ready();
94
+
95
+ const response = await app.inject({
96
+ method: 'GET',
97
+ url: '/null',
98
+ });
99
+
100
+ const body = response.json();
101
+ expect(body.ok).toBe(true);
102
+ expect(body.data).toBeNull();
103
+ });
104
+
105
+ it('should handle array response', async () => {
106
+ app.get('/array', async () => [1, 2, 3]);
107
+
108
+ await app.ready();
109
+
110
+ const response = await app.inject({
111
+ method: 'GET',
112
+ url: '/array',
113
+ });
114
+
115
+ const body = response.json();
116
+ expect(body.ok).toBe(true);
117
+ expect(body.data).toEqual([1, 2, 3]);
118
+ });
119
+
120
+ it('should not double-wrap already enveloped responses', async () => {
121
+ app.get('/enveloped', async () => ({
122
+ ok: true,
123
+ data: { already: 'wrapped' },
124
+ meta: { custom: 'meta' },
125
+ }));
126
+
127
+ await app.ready();
128
+
129
+ const response = await app.inject({
130
+ method: 'GET',
131
+ url: '/enveloped',
132
+ });
133
+
134
+ const body = response.json();
135
+ expect(body.ok).toBe(true);
136
+ expect(body.data).toEqual({ already: 'wrapped' });
137
+ expect(body.meta).toEqual({ custom: 'meta' });
138
+ // Should not have nested 'ok' in data
139
+ expect(body.data.ok).toBeUndefined();
140
+ });
141
+ });
142
+
143
+ describe('error responses', () => {
144
+ it('should wrap errors in error envelope', async () => {
145
+ app.get('/error', async () => {
146
+ const error = new Error('Something went wrong') as any;
147
+ error.statusCode = 400;
148
+ error.code = 'E_BAD_REQUEST';
149
+ throw error;
150
+ });
151
+
152
+ await app.ready();
153
+
154
+ const response = await app.inject({
155
+ method: 'GET',
156
+ url: '/error',
157
+ });
158
+
159
+ expect(response.statusCode).toBe(400);
160
+
161
+ const body = response.json();
162
+ expect(body.ok).toBe(false);
163
+ expect(body.error).toBeDefined();
164
+ expect(body.error.code).toBe('E_BAD_REQUEST');
165
+ expect(body.error.message).toBe('Something went wrong');
166
+ expect(body.meta).toBeDefined();
167
+ expect(body.meta.apiVersion).toBe('1.0.0');
168
+ });
169
+
170
+ it('should default to E_INTERNAL for unknown errors', async () => {
171
+ app.get('/internal-error', async () => {
172
+ throw new Error('Unexpected error');
173
+ });
174
+
175
+ await app.ready();
176
+
177
+ const response = await app.inject({
178
+ method: 'GET',
179
+ url: '/internal-error',
180
+ });
181
+
182
+ expect(response.statusCode).toBe(500);
183
+
184
+ const body = response.json();
185
+ expect(body.ok).toBe(false);
186
+ expect(body.error.code).toBe('E_INTERNAL');
187
+ });
188
+
189
+ it('should include error details when provided', async () => {
190
+ app.get('/detailed-error', async () => {
191
+ const error = new Error('Validation failed') as any;
192
+ error.statusCode = 422;
193
+ error.code = 'E_VALIDATION';
194
+ error.details = { field: 'email', reason: 'invalid format' };
195
+ throw error;
196
+ });
197
+
198
+ await app.ready();
199
+
200
+ const response = await app.inject({
201
+ method: 'GET',
202
+ url: '/detailed-error',
203
+ });
204
+
205
+ const body = response.json();
206
+ expect(body.error.details).toEqual({ field: 'email', reason: 'invalid format' });
207
+ });
208
+
209
+ it('should include traceId when provided', async () => {
210
+ app.get('/traced-error', async () => {
211
+ const error = new Error('Traceable error') as any;
212
+ error.statusCode = 500;
213
+ error.traceId = 'trace-123-abc';
214
+ throw error;
215
+ });
216
+
217
+ await app.ready();
218
+
219
+ const response = await app.inject({
220
+ method: 'GET',
221
+ url: '/traced-error',
222
+ });
223
+
224
+ const body = response.json();
225
+ expect(body.error.traceId).toBe('trace-123-abc');
226
+ });
227
+ });
228
+
229
+ describe('streaming responses', () => {
230
+ it('should skip envelope for SSE responses', async () => {
231
+ app.get('/events', async (request: FastifyRequest, reply: FastifyReply) => {
232
+ reply.header('content-type', 'text/event-stream');
233
+ return 'data: test\n\n';
234
+ });
235
+
236
+ await app.ready();
237
+
238
+ const response = await app.inject({
239
+ method: 'GET',
240
+ url: '/events',
241
+ });
242
+
243
+ // Should return raw SSE data, not wrapped
244
+ expect(response.body).toBe('data: test\n\n');
245
+ expect(response.headers['x-schema-version']).toBe('1.0.0');
246
+ });
247
+ });
248
+
249
+ describe('non-JSON responses', () => {
250
+ it('should pass through non-JSON string responses', async () => {
251
+ app.get('/text', async (request: FastifyRequest, reply: FastifyReply) => {
252
+ reply.header('content-type', 'text/plain');
253
+ return 'Plain text response';
254
+ });
255
+
256
+ await app.ready();
257
+
258
+ const response = await app.inject({
259
+ method: 'GET',
260
+ url: '/text',
261
+ });
262
+
263
+ // Plain text should be wrapped if it can be parsed
264
+ // but since 'Plain text response' is not valid JSON, it passes through
265
+ expect(response.body).toBe('Plain text response');
266
+ });
267
+ });
268
+ });
@@ -0,0 +1,64 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { metricsCollector } from '../metrics'
3
+
4
+ type RedisStatus = {
5
+ enabled: boolean;
6
+ healthy: boolean;
7
+ roles: { publisher?: string | null; subscriber?: string | null; cache?: string | null };
8
+ };
9
+
10
+ function redisStatus(overrides: Partial<RedisStatus> = {}): RedisStatus {
11
+ const baseRoles: RedisStatus['roles'] = {
12
+ publisher: 'ready',
13
+ subscriber: 'subscribed',
14
+ cache: null,
15
+ }
16
+
17
+ const roles: RedisStatus['roles'] = {
18
+ publisher: overrides.roles?.publisher ?? baseRoles.publisher,
19
+ subscriber: overrides.roles?.subscriber ?? baseRoles.subscriber,
20
+ cache: overrides.roles?.cache ?? baseRoles.cache,
21
+ }
22
+
23
+ return {
24
+ enabled: overrides.enabled ?? true,
25
+ healthy: overrides.healthy ?? true,
26
+ roles,
27
+ }
28
+ }
29
+
30
+ describe('metricsCollector.recordRedisStatus', () => {
31
+ it('tracks redis health transitions and role states', () => {
32
+ metricsCollector.reset()
33
+
34
+ const initial = redisStatus()
35
+ const degraded = redisStatus({
36
+ healthy: false,
37
+ roles: { publisher: 'reconnecting', subscriber: 'reconnecting', cache: 'stale' },
38
+ })
39
+
40
+ metricsCollector.recordRedisStatus(initial)
41
+ metricsCollector.recordRedisStatus(degraded)
42
+
43
+ const snapshot = metricsCollector.getMetrics().redis
44
+
45
+ expect(snapshot.updates).toBe(2)
46
+ expect(snapshot.healthyTransitions).toBe(0)
47
+ expect(snapshot.unhealthyTransitions).toBe(1)
48
+ expect(snapshot.lastStatus).toMatchObject({
49
+ enabled: true,
50
+ healthy: false,
51
+ roles: {
52
+ publisher: 'reconnecting',
53
+ subscriber: 'reconnecting',
54
+ cache: 'stale',
55
+ },
56
+ })
57
+
58
+ const publisherStates = snapshot.roleStates.find((entry) => entry.role === 'publisher')
59
+ expect(publisherStates?.states.find((state) => state.state === 'ready')?.count).toBe(1)
60
+ expect(publisherStates?.states.find((state) => state.state === 'reconnecting')?.count).toBe(1)
61
+ })
62
+ })
63
+
64
+