@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,264 @@
1
+ import { beforeEach, describe, expect, it, vi, afterEach } from 'vitest';
2
+ import Fastify from 'fastify';
3
+ import type { IEntityRegistry, RegistrySnapshot } from '@kb-labs/core-registry';
4
+ import type { RestApiConfig } from '@kb-labs/rest-api-core';
5
+ import { registerCacheRoutes } from '../cache';
6
+
7
+ const BASE_CONFIG: RestApiConfig = {
8
+ port: 3000,
9
+ basePath: '/api/v1',
10
+ apiVersion: 'test',
11
+ cors: {
12
+ origins: [],
13
+ allowCredentials: true,
14
+ profile: 'dev',
15
+ },
16
+ plugins: [],
17
+ mockMode: false,
18
+ };
19
+
20
+ function createMockSnapshot(rev: number): RegistrySnapshot {
21
+ return {
22
+ schema: 'kb.registry/1',
23
+ rev,
24
+ version: '1.0.0',
25
+ generatedAt: new Date().toISOString(),
26
+ expiresAt: new Date(Date.now() + 60_000).toISOString(),
27
+ ttlMs: 60_000,
28
+ partial: false,
29
+ stale: false,
30
+ source: { platformVersion: 'test', cwd: process.cwd() },
31
+ corrupted: false,
32
+ plugins: [],
33
+ manifests: [],
34
+ ts: Date.now(),
35
+ };
36
+ }
37
+
38
+ describe('registerCacheRoutes', () => {
39
+ let app: ReturnType<typeof Fastify>;
40
+ let mockCliApi: IEntityRegistry;
41
+
42
+ beforeEach(async () => {
43
+ vi.clearAllMocks();
44
+ app = Fastify({ logger: false });
45
+
46
+ mockCliApi = {
47
+ snapshot: vi.fn(),
48
+ refresh: vi.fn(),
49
+ listPlugins: vi.fn(),
50
+ } as unknown as IEntityRegistry;
51
+
52
+ await registerCacheRoutes(app, BASE_CONFIG, mockCliApi);
53
+ });
54
+
55
+ afterEach(async () => {
56
+ await app.close();
57
+ });
58
+
59
+ describe('POST /api/v1/cache/invalidate', () => {
60
+ it('successfully invalidates cache and refreshes registry', async () => {
61
+ const beforeSnapshot = createMockSnapshot(1);
62
+ const afterSnapshot = createMockSnapshot(2);
63
+ const plugins = [
64
+ { id: '@kb-labs/plugin-1', version: '1.0.0', source: { kind: 'local' as const, path: '/plugins/plugin-1' } },
65
+ { id: '@kb-labs/plugin-2', version: '1.0.0', source: { kind: 'local' as const, path: '/plugins/plugin-2' } },
66
+ ];
67
+
68
+ vi.mocked(mockCliApi.snapshot)
69
+ .mockReturnValueOnce(beforeSnapshot)
70
+ .mockReturnValueOnce(afterSnapshot);
71
+ vi.mocked(mockCliApi.refresh).mockResolvedValue(undefined);
72
+ vi.mocked(mockCliApi.listPlugins).mockResolvedValue(plugins);
73
+
74
+ const response = await app.inject({
75
+ method: 'POST',
76
+ url: '/api/v1/cache/invalidate',
77
+ });
78
+
79
+ expect(response.statusCode).toBe(200);
80
+ const payload = response.json();
81
+
82
+ expect(payload.ok).toBe(true);
83
+ expect(payload.data.invalidated).toBe(true);
84
+ expect(payload.data.previousRev).toBe(1);
85
+ expect(payload.data.newRev).toBe(2);
86
+ expect(payload.data.pluginsDiscovered).toBe(2);
87
+ expect(payload.data.timestamp).toBeDefined();
88
+ expect(payload.meta.requestId).toBeDefined();
89
+ expect(payload.meta.durationMs).toBeGreaterThanOrEqual(0);
90
+ expect(payload.meta.apiVersion).toBe('1.0.0');
91
+
92
+ expect(mockCliApi.snapshot).toHaveBeenCalledTimes(2);
93
+ expect(mockCliApi.refresh).toHaveBeenCalledTimes(1);
94
+ expect(mockCliApi.listPlugins).toHaveBeenCalledTimes(1);
95
+ });
96
+
97
+ it('returns previous and new revision numbers', async () => {
98
+ const beforeSnapshot = createMockSnapshot(42);
99
+ const afterSnapshot = createMockSnapshot(43);
100
+
101
+ vi.mocked(mockCliApi.snapshot)
102
+ .mockReturnValueOnce(beforeSnapshot)
103
+ .mockReturnValueOnce(afterSnapshot);
104
+ vi.mocked(mockCliApi.refresh).mockResolvedValue(undefined);
105
+ vi.mocked(mockCliApi.listPlugins).mockResolvedValue([]);
106
+
107
+ const response = await app.inject({
108
+ method: 'POST',
109
+ url: '/api/v1/cache/invalidate',
110
+ });
111
+
112
+ expect(response.statusCode).toBe(200);
113
+ const payload = response.json();
114
+ expect(payload.data.previousRev).toBe(42);
115
+ expect(payload.data.newRev).toBe(43);
116
+ });
117
+
118
+ it('includes plugin registry count', async () => {
119
+ const snapshot = createMockSnapshot(1);
120
+ const plugins = Array.from({ length: 15 }, (_, i) => ({
121
+ id: `@kb-labs/plugin-${i}`,
122
+ version: '1.0.0',
123
+ source: { kind: 'local' as const, path: `/plugins/plugin-${i}` },
124
+ }));
125
+
126
+ vi.mocked(mockCliApi.snapshot).mockReturnValue(snapshot);
127
+ vi.mocked(mockCliApi.refresh).mockResolvedValue(undefined);
128
+ vi.mocked(mockCliApi.listPlugins).mockResolvedValue(plugins);
129
+
130
+ const response = await app.inject({
131
+ method: 'POST',
132
+ url: '/api/v1/cache/invalidate',
133
+ });
134
+
135
+ expect(response.statusCode).toBe(200);
136
+ const payload = response.json();
137
+ expect(payload.data.pluginsDiscovered).toBe(15);
138
+ });
139
+
140
+ it('handles cache refresh errors gracefully', async () => {
141
+ const beforeSnapshot = createMockSnapshot(1);
142
+ const error = new Error('Registry refresh failed');
143
+
144
+ vi.mocked(mockCliApi.snapshot).mockReturnValue(beforeSnapshot);
145
+ vi.mocked(mockCliApi.refresh).mockRejectedValue(error);
146
+
147
+ const response = await app.inject({
148
+ method: 'POST',
149
+ url: '/api/v1/cache/invalidate',
150
+ });
151
+
152
+ expect(response.statusCode).toBe(500);
153
+ const payload = response.json();
154
+
155
+ expect(payload.ok).toBe(false);
156
+ expect(payload.error.code).toBe('CACHE_INVALIDATION_FAILED');
157
+ expect(payload.error.message).toBe('Registry refresh failed');
158
+ expect(payload.meta.requestId).toBeDefined();
159
+ expect(payload.meta.durationMs).toBeGreaterThanOrEqual(0);
160
+
161
+ expect(mockCliApi.refresh).toHaveBeenCalledTimes(1);
162
+ expect(mockCliApi.listPlugins).not.toHaveBeenCalled();
163
+ });
164
+
165
+ it('handles non-Error exceptions', async () => {
166
+ const beforeSnapshot = createMockSnapshot(1);
167
+
168
+ vi.mocked(mockCliApi.snapshot).mockReturnValue(beforeSnapshot);
169
+ vi.mocked(mockCliApi.refresh).mockRejectedValue('String error');
170
+
171
+ const response = await app.inject({
172
+ method: 'POST',
173
+ url: '/api/v1/cache/invalidate',
174
+ });
175
+
176
+ expect(response.statusCode).toBe(500);
177
+ const payload = response.json();
178
+
179
+ expect(payload.ok).toBe(false);
180
+ expect(payload.error.code).toBe('CACHE_INVALIDATION_FAILED');
181
+ expect(payload.error.message).toBe('Cache invalidation failed');
182
+ });
183
+
184
+ it('handles snapshot() errors', async () => {
185
+ vi.mocked(mockCliApi.snapshot).mockImplementation(() => {
186
+ throw new Error('Registry snapshot unavailable');
187
+ });
188
+
189
+ const response = await app.inject({
190
+ method: 'POST',
191
+ url: '/api/v1/cache/invalidate',
192
+ });
193
+
194
+ expect(response.statusCode).toBe(500);
195
+ const payload = response.json();
196
+ expect(payload.ok).toBe(false);
197
+ expect(payload.error.message).toBe('Registry snapshot unavailable');
198
+ });
199
+
200
+ it('tracks request timing in metadata', async () => {
201
+ const snapshot = createMockSnapshot(1);
202
+
203
+ vi.mocked(mockCliApi.snapshot).mockReturnValue(snapshot);
204
+ vi.mocked(mockCliApi.refresh).mockImplementation(async () => {
205
+ await new Promise((resolve) => {
206
+ setTimeout(resolve, 10);
207
+ });
208
+ });
209
+ vi.mocked(mockCliApi.listPlugins).mockResolvedValue([]);
210
+
211
+ const response = await app.inject({
212
+ method: 'POST',
213
+ url: '/api/v1/cache/invalidate',
214
+ });
215
+
216
+ expect(response.statusCode).toBe(200);
217
+ const payload = response.json();
218
+ expect(payload.meta.durationMs).toBeGreaterThanOrEqual(10);
219
+ });
220
+
221
+ it('includes timestamp in ISO format', async () => {
222
+ const snapshot = createMockSnapshot(1);
223
+
224
+ vi.mocked(mockCliApi.snapshot).mockReturnValue(snapshot);
225
+ vi.mocked(mockCliApi.refresh).mockResolvedValue(undefined);
226
+ vi.mocked(mockCliApi.listPlugins).mockResolvedValue([]);
227
+
228
+ const before = new Date();
229
+ const response = await app.inject({
230
+ method: 'POST',
231
+ url: '/api/v1/cache/invalidate',
232
+ });
233
+ const after = new Date();
234
+
235
+ expect(response.statusCode).toBe(200);
236
+ const payload = response.json();
237
+ const timestamp = new Date(payload.data.timestamp);
238
+
239
+ expect(timestamp).toBeInstanceOf(Date);
240
+ expect(timestamp.getTime()).toBeGreaterThanOrEqual(before.getTime());
241
+ expect(timestamp.getTime()).toBeLessThanOrEqual(after.getTime());
242
+ });
243
+
244
+ it('handles empty plugin list after refresh', async () => {
245
+ const beforeSnapshot = createMockSnapshot(1);
246
+ const afterSnapshot = createMockSnapshot(2);
247
+
248
+ vi.mocked(mockCliApi.snapshot)
249
+ .mockReturnValueOnce(beforeSnapshot)
250
+ .mockReturnValueOnce(afterSnapshot);
251
+ vi.mocked(mockCliApi.refresh).mockResolvedValue(undefined);
252
+ vi.mocked(mockCliApi.listPlugins).mockResolvedValue([]);
253
+
254
+ const response = await app.inject({
255
+ method: 'POST',
256
+ url: '/api/v1/cache/invalidate',
257
+ });
258
+
259
+ expect(response.statusCode).toBe(200);
260
+ const payload = response.json();
261
+ expect(payload.data.pluginsDiscovered).toBe(0);
262
+ });
263
+ });
264
+ });
@@ -0,0 +1,434 @@
1
+ import { beforeEach, describe, expect, it, vi, afterEach } from 'vitest';
2
+ import Fastify from 'fastify';
3
+ import type { IEntityRegistry, RegistrySnapshot, SystemHealthSnapshot } from '@kb-labs/core-registry';
4
+ import type { RestApiConfig } from '@kb-labs/rest-api-core';
5
+ import type { EventHub, BroadcastEvent } from '../../events/hub';
6
+ import type { ReadinessState } from '../readiness';
7
+ import { registerEventRoutes } from '../events';
8
+
9
+ // Mock dependencies
10
+ vi.mock('../../middleware/metrics', () => ({
11
+ metricsCollector: {
12
+ getLastPluginMountSnapshot: vi.fn(() => ({
13
+ succeeded: 5,
14
+ failed: 1,
15
+ })),
16
+ },
17
+ }));
18
+
19
+ vi.mock('../../utils/sse-auth', () => ({
20
+ buildRegistrySseAuthHook: vi.fn(() => null),
21
+ }));
22
+
23
+ const BASE_CONFIG: RestApiConfig = {
24
+ port: 3000,
25
+ basePath: '/api/v1',
26
+ apiVersion: 'test',
27
+ cors: {
28
+ origins: [],
29
+ allowCredentials: true,
30
+ profile: 'dev',
31
+ },
32
+ plugins: [],
33
+ mockMode: false,
34
+ };
35
+
36
+ function createMockSnapshot(): RegistrySnapshot {
37
+ return {
38
+ schema: 'kb.registry/1',
39
+ rev: 42,
40
+ version: '1.0.0',
41
+ generatedAt: new Date().toISOString(),
42
+ expiresAt: new Date(Date.now() + 60_000).toISOString(),
43
+ ttlMs: 60_000,
44
+ partial: false,
45
+ stale: false,
46
+ source: { platformVersion: 'test', cwd: process.cwd() },
47
+ corrupted: false,
48
+ plugins: [],
49
+ manifests: [],
50
+ ts: Date.now(),
51
+ checksum: 'abc123',
52
+ checksumAlgorithm: 'sha256',
53
+ previousChecksum: 'def456',
54
+ };
55
+ }
56
+
57
+ function createMockHealthSnapshot(): SystemHealthSnapshot {
58
+ return {
59
+ schema: 'kb.health/1',
60
+ ts: new Date().toISOString(),
61
+ uptimeSec: 42,
62
+ version: {
63
+ kbLabs: '1.0.0',
64
+ rest: '1.0.0',
65
+ },
66
+ registry: {
67
+ total: 5,
68
+ withRest: 3,
69
+ withStudio: 2,
70
+ errors: 0,
71
+ generatedAt: new Date().toISOString(),
72
+ expiresAt: new Date(Date.now() + 60_000).toISOString(),
73
+ partial: false,
74
+ stale: false,
75
+ },
76
+ status: 'healthy',
77
+ components: [],
78
+ };
79
+ }
80
+
81
+ function createMockReadinessState(): ReadinessState {
82
+ return {
83
+ cliApiInitialized: true,
84
+ registryLoaded: true,
85
+ registryPartial: false,
86
+ registryStale: false,
87
+ pluginRoutesMounted: true,
88
+ pluginMountInProgress: false,
89
+ pluginRoutesCount: 5,
90
+ pluginRouteErrors: 0,
91
+ pluginRouteFailures: [],
92
+ lastPluginMountTs: new Date().toISOString(),
93
+ pluginRoutesLastDurationMs: 128,
94
+ redisEnabled: false,
95
+ redisConnected: false,
96
+ redisStates: {
97
+ publisher: null,
98
+ subscriber: null,
99
+ cache: null,
100
+ },
101
+ };
102
+ }
103
+
104
+ describe('registerEventRoutes', () => {
105
+ let app: ReturnType<typeof Fastify>;
106
+ let mockCliApi: IEntityRegistry;
107
+ let mockEventHub: EventHub;
108
+ let readiness: ReadinessState;
109
+ let subscribers: Array<(event: BroadcastEvent) => void> = [];
110
+
111
+ beforeEach(async () => {
112
+ vi.clearAllMocks();
113
+ subscribers = [];
114
+ app = Fastify({ logger: false });
115
+
116
+ mockCliApi = {
117
+ snapshot: vi.fn(() => createMockSnapshot()),
118
+ getSystemHealth: vi.fn(() => Promise.resolve(createMockHealthSnapshot())),
119
+ getRedisStatus: vi.fn(() => ({
120
+ enabled: false,
121
+ healthy: true,
122
+ roles: {
123
+ publisher: null,
124
+ subscriber: null,
125
+ cache: null,
126
+ },
127
+ })),
128
+ } as unknown as IEntityRegistry;
129
+
130
+ mockEventHub = {
131
+ subscribe: vi.fn((callback: (event: BroadcastEvent) => void) => {
132
+ subscribers.push(callback);
133
+ return () => {
134
+ const index = subscribers.indexOf(callback);
135
+ if (index > -1) {subscribers.splice(index, 1);}
136
+ };
137
+ }),
138
+ publish: vi.fn((event: BroadcastEvent) => {
139
+ subscribers.forEach((sub) => sub(event));
140
+ }),
141
+ } as any;
142
+
143
+ readiness = createMockReadinessState();
144
+
145
+ await registerEventRoutes(
146
+ app,
147
+ '/api/v1',
148
+ mockCliApi,
149
+ readiness,
150
+ mockEventHub,
151
+ BASE_CONFIG
152
+ );
153
+ });
154
+
155
+ afterEach(async () => {
156
+ await app.close();
157
+ });
158
+
159
+ describe('GET /api/v1/events/registry', () => {
160
+ it('returns SSE stream with correct headers', async () => {
161
+ const response = await app.inject({
162
+ method: 'GET',
163
+ url: '/api/v1/events/registry',
164
+ });
165
+
166
+ // SSE uses response hijacking, so status code is 0
167
+ // Check headers instead
168
+ expect(response.headers['content-type']).toBe('text/event-stream');
169
+ expect(response.headers['cache-control']).toBe('no-cache, no-transform');
170
+ expect(response.headers['connection']).toBe('keep-alive');
171
+ });
172
+
173
+ it('sends initial registry event', async () => {
174
+ const snapshot = createMockSnapshot();
175
+ vi.mocked(mockCliApi.snapshot).mockReturnValue(snapshot);
176
+
177
+ const response = await app.inject({
178
+ method: 'GET',
179
+ url: '/api/v1/events/registry',
180
+ });
181
+
182
+ const body = response.body;
183
+ expect(body).toContain('event: registry');
184
+ expect(body).toContain('"rev":42');
185
+ expect(body).toContain('"partial":false');
186
+ expect(body).toContain('"stale":false');
187
+ expect(body).toContain('"checksum":"abc123"');
188
+ expect(body).toContain('"checksumAlgorithm":"sha256"');
189
+ });
190
+
191
+ it('sends health event after registry event', async () => {
192
+ const health = createMockHealthSnapshot();
193
+ vi.mocked(mockCliApi.getSystemHealth).mockResolvedValue(health);
194
+
195
+ const response = await app.inject({
196
+ method: 'GET',
197
+ url: '/api/v1/events/registry',
198
+ });
199
+
200
+ // Wait for async health fetch
201
+ await new Promise((resolve) => {
202
+ setTimeout(resolve, 10);
203
+ });
204
+
205
+ const body = response.body;
206
+ expect(body).toContain('event: health');
207
+ expect(body).toContain('"status":"healthy"');
208
+ expect(body).toContain('"ready":true');
209
+ expect(body).toContain('"pluginRoutesMounted":true');
210
+ });
211
+
212
+ it('subscribes to event hub', async () => {
213
+ await app.inject({
214
+ method: 'GET',
215
+ url: '/api/v1/events/registry',
216
+ });
217
+
218
+ expect(mockEventHub.subscribe).toHaveBeenCalledTimes(1);
219
+ expect(mockEventHub.subscribe).toHaveBeenCalledWith(expect.any(Function));
220
+ });
221
+
222
+ it('includes Redis status in health event when Redis is enabled', async () => {
223
+ vi.mocked((mockCliApi as any).getRedisStatus).mockReturnValue({
224
+ enabled: true,
225
+ healthy: true,
226
+ roles: {
227
+ publisher: 'ready',
228
+ subscriber: 'ready',
229
+ cache: 'ready',
230
+ },
231
+ });
232
+
233
+ const response = await app.inject({
234
+ method: 'GET',
235
+ url: '/api/v1/events/registry',
236
+ });
237
+
238
+ await new Promise((resolve) => {
239
+ setTimeout(resolve, 10);
240
+ });
241
+
242
+ const body = response.body;
243
+ expect(body).toContain('"redisEnabled":true');
244
+ expect(body).toContain('"redisHealthy":true');
245
+ expect(body).toContain('"publisher":"ready"');
246
+ });
247
+
248
+ it('includes plugin mount statistics in health event', async () => {
249
+ const response = await app.inject({
250
+ method: 'GET',
251
+ url: '/api/v1/events/registry',
252
+ });
253
+
254
+ await new Promise((resolve) => {
255
+ setTimeout(resolve, 10);
256
+ });
257
+
258
+ const body = response.body;
259
+ expect(body).toContain('"pluginsMounted":5');
260
+ expect(body).toContain('"pluginsFailed":1');
261
+ expect(body).toContain('"pluginRoutesLastDurationMs":128');
262
+ });
263
+
264
+ it('includes readiness state in health event', async () => {
265
+ readiness.registryPartial = true;
266
+ readiness.pluginMountInProgress = true;
267
+
268
+ const response = await app.inject({
269
+ method: 'GET',
270
+ url: '/api/v1/events/registry',
271
+ });
272
+
273
+ await new Promise((resolve) => {
274
+ setTimeout(resolve, 10);
275
+ });
276
+
277
+ const body = response.body;
278
+ expect(body).toContain('"registryPartial":true');
279
+ expect(body).toContain('"pluginMountInProgress":true');
280
+ expect(body).toContain('"reason":"plugin_mount_in_progress"');
281
+ });
282
+
283
+ it('handles system health fetch errors gracefully', async () => {
284
+ vi.mocked(mockCliApi.getSystemHealth).mockRejectedValue(
285
+ new Error('Health fetch failed')
286
+ );
287
+
288
+ const response = await app.inject({
289
+ method: 'GET',
290
+ url: '/api/v1/events/registry',
291
+ });
292
+
293
+ await new Promise((resolve) => {
294
+ setTimeout(resolve, 10);
295
+ });
296
+
297
+ // Should still send registry event, just not health event
298
+ const body = response.body;
299
+ expect(body).toContain('event: registry');
300
+ // Should not crash
301
+ });
302
+
303
+ it('sets CORS headers for localhost:3000 origin', async () => {
304
+ const response = await app.inject({
305
+ method: 'GET',
306
+ url: '/api/v1/events/registry',
307
+ headers: {
308
+ origin: 'http://localhost:3000',
309
+ },
310
+ });
311
+
312
+ expect(response.headers['access-control-allow-origin']).toBe(
313
+ 'http://localhost:3000'
314
+ );
315
+ expect(response.headers['access-control-allow-credentials']).toBe('true');
316
+ });
317
+
318
+ it('sets CORS headers for localhost:5173 origin (Vite dev)', async () => {
319
+ const response = await app.inject({
320
+ method: 'GET',
321
+ url: '/api/v1/events/registry',
322
+ headers: {
323
+ origin: 'http://localhost:5173',
324
+ },
325
+ });
326
+
327
+ expect(response.headers['access-control-allow-origin']).toBe(
328
+ 'http://localhost:5173'
329
+ );
330
+ expect(response.headers['access-control-allow-credentials']).toBe('true');
331
+ });
332
+
333
+ it('does not set CORS headers for other origins', async () => {
334
+ const response = await app.inject({
335
+ method: 'GET',
336
+ url: '/api/v1/events/registry',
337
+ headers: {
338
+ origin: 'http://evil.com',
339
+ },
340
+ });
341
+
342
+ expect(response.headers['access-control-allow-origin']).toBeUndefined();
343
+ });
344
+
345
+ it('handles snapshot with missing checksum fields', async () => {
346
+ const snapshot = createMockSnapshot();
347
+ delete (snapshot as any).checksum;
348
+ delete (snapshot as any).checksumAlgorithm;
349
+ delete (snapshot as any).previousChecksum;
350
+
351
+ vi.mocked(mockCliApi.snapshot).mockReturnValue(snapshot);
352
+
353
+ const response = await app.inject({
354
+ method: 'GET',
355
+ url: '/api/v1/events/registry',
356
+ });
357
+
358
+ const body = response.body;
359
+ expect(body).toContain('event: registry');
360
+ expect(body).not.toContain('"checksum"');
361
+ expect(body).not.toContain('"checksumAlgorithm"');
362
+ });
363
+
364
+ it('handles snapshot with null expiration fields', async () => {
365
+ const snapshot = createMockSnapshot();
366
+ (snapshot as any).expiresAt = null;
367
+ (snapshot as any).ttlMs = null;
368
+
369
+ vi.mocked(mockCliApi.snapshot).mockReturnValue(snapshot);
370
+
371
+ const response = await app.inject({
372
+ method: 'GET',
373
+ url: '/api/v1/events/registry',
374
+ });
375
+
376
+ const body = response.body;
377
+ expect(body).toContain('"expiresAt":null');
378
+ expect(body).toContain('"ttlMs":null');
379
+ });
380
+
381
+ it('handles missing getRedisStatus method gracefully', async () => {
382
+ delete (mockCliApi as any).getRedisStatus;
383
+
384
+ const response = await app.inject({
385
+ method: 'GET',
386
+ url: '/api/v1/events/registry',
387
+ });
388
+
389
+ await new Promise((resolve) => {
390
+ setTimeout(resolve, 10);
391
+ });
392
+
393
+ const body = response.body;
394
+ expect(body).toContain('"redisEnabled":false');
395
+ expect(body).toContain('"redisHealthy":true');
396
+ });
397
+
398
+ it('handles missing plugin mount snapshot', async () => {
399
+ const { metricsCollector } = await import('../../middleware/metrics');
400
+ vi.mocked(metricsCollector.getLastPluginMountSnapshot).mockReturnValue(null);
401
+
402
+ const response = await app.inject({
403
+ method: 'GET',
404
+ url: '/api/v1/events/registry',
405
+ });
406
+
407
+ await new Promise((resolve) => {
408
+ setTimeout(resolve, 10);
409
+ });
410
+
411
+ const body = response.body;
412
+ expect(body).toContain('"pluginsMounted":0');
413
+ expect(body).toContain('"pluginsFailed":0');
414
+ });
415
+
416
+ it('handles null lastPluginMountTs', async () => {
417
+ readiness.lastPluginMountTs = null;
418
+ readiness.pluginRoutesLastDurationMs = null;
419
+
420
+ const response = await app.inject({
421
+ method: 'GET',
422
+ url: '/api/v1/events/registry',
423
+ });
424
+
425
+ await new Promise((resolve) => {
426
+ setTimeout(resolve, 10);
427
+ });
428
+
429
+ const body = response.body;
430
+ expect(body).toContain('"lastPluginMountTs":null');
431
+ expect(body).toContain('"pluginRoutesLastDurationMs":null');
432
+ });
433
+ });
434
+ });