@kb-labs/rest-api-app 1.3.0 → 1.4.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 (257) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +8151 -0
  3. package/dist/index.js.map +1 -0
  4. package/package.json +7 -4
  5. package/.kb/agents/sessions/session-1771531145393-ws3uh6q/turns.json +0 -42
  6. package/.kb/agents/sessions/session-1771548930486-ui6rtvm/turns.json +0 -33
  7. package/.kb/agents/sessions/session-1771549691485-nibqroq/turns.json +0 -133
  8. package/.kb/agents/sessions/session-1771550943182-dkwqdjc/turns.json +0 -130
  9. package/.kb/agents/sessions/session-1771551564182-cr4bwzn/turns.json +0 -349
  10. package/.kb/agents/sessions/session-1771552401370-g4ztwd1/turns.json +0 -206
  11. package/.kb/commit/current/plan.json +0 -248
  12. package/.kb/commit/current/status.json +0 -472
  13. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/health.d.ts +0 -10
  14. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/health.js +0 -215
  15. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/health.js.map +0 -1
  16. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/list.d.ts +0 -10
  17. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/list.js +0 -271
  18. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/list.js.map +0 -1
  19. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/logs.d.ts +0 -10
  20. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/logs.js +0 -230
  21. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/logs.js.map +0 -1
  22. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/metrics.d.ts +0 -10
  23. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/metrics.js +0 -228
  24. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/metrics.js.map +0 -1
  25. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/run.d.ts +0 -11
  26. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/run.js +0 -281
  27. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/run.js.map +0 -1
  28. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/status.d.ts +0 -10
  29. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/status.js +0 -266
  30. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/status.js.map +0 -1
  31. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/workflow-run.d.ts +0 -11
  32. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/workflow-run.js +0 -284
  33. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/workflow-run.js.map +0 -1
  34. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/flags-WLdpSZl4.d.ts +0 -77
  35. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/index.d.ts +0 -2
  36. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/index.js +0 -441
  37. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/index.js.map +0 -1
  38. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/manifest.d.ts +0 -196
  39. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/manifest.js +0 -441
  40. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/manifest.js.map +0 -1
  41. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/cron-list-handler.d.ts +0 -19
  42. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/cron-list-handler.js +0 -48
  43. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/cron-list-handler.js.map +0 -1
  44. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/index.d.ts +0 -6
  45. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/index.js +0 -170
  46. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/index.js.map +0 -1
  47. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-cancel-handler.d.ts +0 -12
  48. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-cancel-handler.js +0 -52
  49. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-cancel-handler.js.map +0 -1
  50. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-detail-handler.d.ts +0 -22
  51. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-detail-handler.js +0 -52
  52. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-detail-handler.js.map +0 -1
  53. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-logs-handler.d.ts +0 -13
  54. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-logs-handler.js +0 -52
  55. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-logs-handler.js.map +0 -1
  56. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-steps-handler.d.ts +0 -9
  57. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-steps-handler.js +0 -43
  58. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-steps-handler.js.map +0 -1
  59. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/jobs-list-handler.d.ts +0 -26
  60. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/jobs-list-handler.js +0 -63
  61. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/jobs-list-handler.js.map +0 -1
  62. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/pending-approvals-handler.d.ts +0 -9
  63. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/pending-approvals-handler.js +0 -46
  64. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/pending-approvals-handler.js.map +0 -1
  65. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/resolve-approval-handler.d.ts +0 -16
  66. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/resolve-approval-handler.js +0 -58
  67. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/resolve-approval-handler.js.map +0 -1
  68. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/run-detail-handler.d.ts +0 -9
  69. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/run-detail-handler.js +0 -46
  70. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/run-detail-handler.js.map +0 -1
  71. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/runs-list-handler.d.ts +0 -11
  72. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/runs-list-handler.js +0 -50
  73. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/runs-list-handler.js.map +0 -1
  74. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/stats-handler.d.ts +0 -7
  75. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/stats-handler.js +0 -39
  76. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/stats-handler.js.map +0 -1
  77. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-detail-handler.d.ts +0 -10
  78. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-detail-handler.js +0 -46
  79. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-detail-handler.js.map +0 -1
  80. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-cancel-handler.d.ts +0 -13
  81. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-cancel-handler.js +0 -47
  82. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-cancel-handler.js.map +0 -1
  83. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-handler.d.ts +0 -14
  84. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-handler.js +0 -53
  85. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-handler.js.map +0 -1
  86. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-runs-handler.d.ts +0 -13
  87. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-runs-handler.js +0 -54
  88. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-runs-handler.js.map +0 -1
  89. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflows-list-handler.d.ts +0 -12
  90. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflows-list-handler.js +0 -51
  91. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflows-list-handler.js.map +0 -1
  92. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/logs-channel.d.ts +0 -17
  93. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/logs-channel.js +0 -133
  94. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/logs-channel.js.map +0 -1
  95. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/progress-channel.d.ts +0 -11
  96. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/progress-channel.js +0 -46
  97. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/progress-channel.js.map +0 -1
  98. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/health.d.ts +0 -10
  99. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/health.js +0 -215
  100. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/health.js.map +0 -1
  101. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/list.d.ts +0 -10
  102. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/list.js +0 -271
  103. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/list.js.map +0 -1
  104. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/logs.d.ts +0 -10
  105. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/logs.js +0 -230
  106. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/logs.js.map +0 -1
  107. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/metrics.d.ts +0 -10
  108. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/metrics.js +0 -228
  109. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/metrics.js.map +0 -1
  110. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/run.d.ts +0 -11
  111. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/run.js +0 -281
  112. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/run.js.map +0 -1
  113. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/status.d.ts +0 -10
  114. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/status.js +0 -266
  115. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/status.js.map +0 -1
  116. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/workflow-run.d.ts +0 -11
  117. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/workflow-run.js +0 -284
  118. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/workflow-run.js.map +0 -1
  119. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/flags-WLdpSZl4.d.ts +0 -77
  120. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/index.d.ts +0 -2
  121. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/index.js +0 -441
  122. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/index.js.map +0 -1
  123. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/manifest.d.ts +0 -196
  124. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/manifest.js +0 -441
  125. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/manifest.js.map +0 -1
  126. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/cron-list-handler.d.ts +0 -19
  127. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/cron-list-handler.js +0 -48
  128. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/cron-list-handler.js.map +0 -1
  129. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/index.d.ts +0 -6
  130. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/index.js +0 -170
  131. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/index.js.map +0 -1
  132. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-cancel-handler.d.ts +0 -12
  133. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-cancel-handler.js +0 -52
  134. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-cancel-handler.js.map +0 -1
  135. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-detail-handler.d.ts +0 -22
  136. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-detail-handler.js +0 -52
  137. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-detail-handler.js.map +0 -1
  138. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-logs-handler.d.ts +0 -13
  139. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-logs-handler.js +0 -52
  140. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-logs-handler.js.map +0 -1
  141. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-steps-handler.d.ts +0 -9
  142. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-steps-handler.js +0 -43
  143. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-steps-handler.js.map +0 -1
  144. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/jobs-list-handler.d.ts +0 -26
  145. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/jobs-list-handler.js +0 -63
  146. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/jobs-list-handler.js.map +0 -1
  147. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/pending-approvals-handler.d.ts +0 -9
  148. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/pending-approvals-handler.js +0 -46
  149. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/pending-approvals-handler.js.map +0 -1
  150. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/resolve-approval-handler.d.ts +0 -16
  151. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/resolve-approval-handler.js +0 -58
  152. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/resolve-approval-handler.js.map +0 -1
  153. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/run-detail-handler.d.ts +0 -9
  154. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/run-detail-handler.js +0 -46
  155. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/run-detail-handler.js.map +0 -1
  156. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/runs-list-handler.d.ts +0 -11
  157. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/runs-list-handler.js +0 -50
  158. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/runs-list-handler.js.map +0 -1
  159. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/stats-handler.d.ts +0 -7
  160. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/stats-handler.js +0 -39
  161. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/stats-handler.js.map +0 -1
  162. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-detail-handler.d.ts +0 -10
  163. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-detail-handler.js +0 -46
  164. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-detail-handler.js.map +0 -1
  165. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-cancel-handler.d.ts +0 -13
  166. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-cancel-handler.js +0 -47
  167. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-cancel-handler.js.map +0 -1
  168. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-handler.d.ts +0 -14
  169. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-handler.js +0 -53
  170. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-handler.js.map +0 -1
  171. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-runs-handler.d.ts +0 -13
  172. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-runs-handler.js +0 -54
  173. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-runs-handler.js.map +0 -1
  174. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflows-list-handler.d.ts +0 -12
  175. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflows-list-handler.js +0 -51
  176. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflows-list-handler.js.map +0 -1
  177. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/logs-channel.d.ts +0 -17
  178. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/logs-channel.js +0 -133
  179. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/logs-channel.js.map +0 -1
  180. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/progress-channel.d.ts +0 -11
  181. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/progress-channel.js +0 -46
  182. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/progress-channel.js.map +0 -1
  183. package/eslint.config.js +0 -23
  184. package/src/.kb/agents/sessions/session-1773470583796-ximqnfk/kpi-baseline.json +0 -17
  185. package/src/.kb/memory/sessions/session-1773470583796-ximqnfk/fact-sheet.json +0 -1
  186. package/src/bootstrap.ts +0 -233
  187. package/src/diagnostics/header-debug.ts +0 -37
  188. package/src/events/hub.ts +0 -60
  189. package/src/events/index.ts +0 -1
  190. package/src/index.ts +0 -13
  191. package/src/manifest.ts +0 -21
  192. package/src/middleware/__tests__/cache.spec.ts +0 -184
  193. package/src/middleware/__tests__/envelope.spec.ts +0 -268
  194. package/src/middleware/__tests__/metrics.redis.spec.ts +0 -64
  195. package/src/middleware/__tests__/rate-limit.spec.ts +0 -283
  196. package/src/middleware/__tests__/request-id.spec.ts +0 -160
  197. package/src/middleware/cache.ts +0 -67
  198. package/src/middleware/envelope.ts +0 -136
  199. package/src/middleware/error-guard.ts +0 -69
  200. package/src/middleware/index.ts +0 -37
  201. package/src/middleware/metrics.ts +0 -810
  202. package/src/middleware/mock-mode.ts +0 -44
  203. package/src/middleware/prom-metrics.ts +0 -284
  204. package/src/middleware/rate-limit-routes.ts +0 -73
  205. package/src/middleware/rate-limit.ts +0 -72
  206. package/src/middleware/request-id.ts +0 -41
  207. package/src/middleware/request-timeout.ts +0 -69
  208. package/src/middleware/security-headers.ts +0 -24
  209. package/src/middleware/startup-guard.ts +0 -107
  210. package/src/observability/service-contract.ts +0 -192
  211. package/src/plugins/index.ts +0 -118
  212. package/src/routes/__tests__/adapters-date-helpers.spec.ts +0 -332
  213. package/src/routes/__tests__/adapters.spec.ts +0 -680
  214. package/src/routes/__tests__/cache.spec.ts +0 -264
  215. package/src/routes/__tests__/events.spec.ts +0 -434
  216. package/src/routes/__tests__/health.spec.ts +0 -414
  217. package/src/routes/__tests__/logs.spec.ts +0 -494
  218. package/src/routes/__tests__/observability.spec.ts +0 -392
  219. package/src/routes/__tests__/plugins.spec.ts +0 -931
  220. package/src/routes/__tests__/workflow-management.spec.ts +0 -698
  221. package/src/routes/__tests__/workflows.spec.ts +0 -204
  222. package/src/routes/adapter-call.ts +0 -220
  223. package/src/routes/adapters.ts +0 -1206
  224. package/src/routes/analytics.ts +0 -328
  225. package/src/routes/cache.ts +0 -104
  226. package/src/routes/debug-routes.ts +0 -95
  227. package/src/routes/events.ts +0 -115
  228. package/src/routes/health.ts +0 -348
  229. package/src/routes/hello.ts +0 -47
  230. package/src/routes/index.ts +0 -395
  231. package/src/routes/jobs.ts +0 -253
  232. package/src/routes/logs.ts +0 -718
  233. package/src/routes/metrics.ts +0 -120
  234. package/src/routes/observability.ts +0 -1388
  235. package/src/routes/openapi.ts +0 -101
  236. package/src/routes/platform.ts +0 -143
  237. package/src/routes/plugins.ts +0 -998
  238. package/src/routes/readiness.ts +0 -83
  239. package/src/routes/workflow-management.ts +0 -469
  240. package/src/routes/workflows.ts +0 -256
  241. package/src/server.ts +0 -203
  242. package/src/services/historical-metrics.ts +0 -496
  243. package/src/services/incident-analyzer.ts +0 -289
  244. package/src/services/incident-detector.ts +0 -691
  245. package/src/services/incident-schema.sql +0 -76
  246. package/src/services/incident-storage.ts +0 -593
  247. package/src/services/system-metrics-collector.ts +0 -244
  248. package/src/types/fastify.d.ts +0 -58
  249. package/src/utils/__tests__/sse-auth.spec.ts +0 -113
  250. package/src/utils/path-helpers.ts +0 -15
  251. package/src/utils/repo.ts +0 -42
  252. package/src/utils/schema.ts +0 -20
  253. package/src/utils/sse-auth.ts +0 -81
  254. package/test-sandbox.sh +0 -105
  255. package/tsconfig.build.json +0 -15
  256. package/tsconfig.json +0 -9
  257. package/tsup.config.ts +0 -18
@@ -1,1206 +0,0 @@
1
- /**
2
- * @module @kb-labs/rest-api-app/routes/adapters
3
- * Platform adapter analytics endpoints
4
- */
5
-
6
- import type { FastifyInstance } from 'fastify';
7
- import type { RestApiConfig } from '@kb-labs/rest-api-core';
8
- import { normalizeBasePath, resolvePaths } from '../utils/path-helpers';
9
- import { platform } from '@kb-labs/core-runtime';
10
-
11
- /**
12
- * LLM usage statistics response
13
- */
14
- interface LLMUsageStats {
15
- totalRequests: number;
16
- totalTokens: number;
17
- totalCost: number;
18
- costPer1KTokens: number; // Enhanced: Cost efficiency metric
19
- // Cache savings
20
- totalCacheReadTokens: number;
21
- totalBillableTokens: number;
22
- totalCacheSavingsUsd: number;
23
- byModel: Record<
24
- string,
25
- {
26
- requests: number;
27
- promptTokens: number;
28
- completionTokens: number;
29
- totalTokens: number;
30
- cost: number;
31
- costPer1KTokens: number; // Enhanced: Cost per 1K tokens for this model
32
- tokensPerRequest: number; // Enhanced: Average tokens per request
33
- errorRate: number; // Enhanced: Error rate percentage (0-100)
34
- avgDurationMs: number;
35
- // Enhanced: Latency percentiles
36
- p50DurationMs: number;
37
- p95DurationMs: number;
38
- p99DurationMs: number;
39
- // Cache savings per model
40
- cacheReadTokens: number;
41
- billableTokens: number;
42
- cacheSavingsUsd: number;
43
- }
44
- >;
45
- errors: number;
46
- // Enhanced: Error breakdown by type
47
- errorBreakdown: {
48
- timeout: number;
49
- rateLimit: number;
50
- invalidRequest: number;
51
- serverError: number;
52
- other: number;
53
- };
54
- timeRange: {
55
- from: string;
56
- to: string;
57
- };
58
- }
59
-
60
- /**
61
- * Helper to get event data, supporting both kb.v1 (payload) and legacy (properties) formats
62
- */
63
- function getEventData(event: any): Record<string, unknown> {
64
- // kb.v1 format uses 'payload'
65
- if (event.schema === 'kb.v1' && event.payload) {
66
- return event.payload as Record<string, unknown>;
67
- }
68
- // Legacy format uses 'properties'
69
- return (event.properties as Record<string, unknown>) || {};
70
- }
71
-
72
- /**
73
- * Extract date range from query parameters
74
- */
75
- function extractDateRange(query: any): { from?: string; to?: string } {
76
- // Handle null/undefined query
77
- if (!query) {
78
- return { from: undefined, to: undefined };
79
- }
80
-
81
- const from = query.from as string | undefined;
82
- const to = query.to as string | undefined;
83
-
84
- // Validate ISO 8601 format
85
- if (from && !isValidISODate(from)) {
86
- throw new Error('Invalid "from" date format. Expected ISO 8601 datetime (e.g., 2026-01-01T00:00:00Z)');
87
- }
88
- if (to && !isValidISODate(to)) {
89
- throw new Error('Invalid "to" date format. Expected ISO 8601 datetime (e.g., 2026-01-31T23:59:59Z)');
90
- }
91
-
92
- return { from, to };
93
- }
94
-
95
- /**
96
- * Extract model filter from query parameters
97
- * Supports both single model (?models=gpt-4) and multiple (?models=gpt-4,claude-sonnet)
98
- */
99
- function extractModelFilter(query: any): string[] | undefined {
100
- if (!query || !query.models) {
101
- return undefined;
102
- }
103
-
104
- const modelsParam = query.models as string;
105
-
106
- // Split by comma and trim whitespace
107
- const models = modelsParam
108
- .split(',')
109
- .map((m) => m.trim())
110
- .filter((m) => m.length > 0);
111
-
112
- return models.length > 0 ? models : undefined;
113
- }
114
-
115
- /**
116
- * Extract StatsQuery fields (groupBy, breakdownBy, metrics) from query parameters.
117
- * These are optional — adapters silently ignore fields they don't support.
118
- */
119
- function extractStatsOptions(query: any): {
120
- groupBy?: 'hour' | 'day' | 'week' | 'month';
121
- breakdownBy?: string;
122
- metrics?: string[];
123
- } {
124
- if (!query) {return {};}
125
-
126
- const groupBy = query.groupBy as string | undefined;
127
- const validGroupBy = ['hour', 'day', 'week', 'month'];
128
- const resolvedGroupBy =
129
- groupBy && validGroupBy.includes(groupBy)
130
- ? (groupBy as 'hour' | 'day' | 'week' | 'month')
131
- : undefined;
132
-
133
- const breakdownBy = query.breakdownBy as string | undefined;
134
-
135
- const metricsParam = query.metrics as string | undefined;
136
- const metrics = metricsParam
137
- ? metricsParam
138
- .split(',')
139
- .map((m) => m.trim())
140
- .filter((m) => m.length > 0)
141
- : undefined;
142
-
143
- return {
144
- groupBy: resolvedGroupBy,
145
- breakdownBy: breakdownBy || undefined,
146
- metrics: metrics && metrics.length > 0 ? metrics : undefined,
147
- };
148
- }
149
-
150
- /**
151
- * Fetch all events for a given query in batches to avoid memory issues.
152
- *
153
- * Backend handles pagination internally:
154
- * - PAGE_SIZE: 10,000 events per request
155
- * - MAX_EVENTS: 100,000 total events to process
156
- *
157
- * Frontend just sends date range, backend fetches all events in that range.
158
- *
159
- * @param analytics - Analytics adapter
160
- * @param query - Event query (type, from, to)
161
- * @param fastify - Fastify instance for logging
162
- * @returns All events (up to MAX_EVENTS)
163
- */
164
- async function fetchAllEventsBatched(
165
- analytics: any,
166
- query: { type: string | string[]; from?: string; to?: string },
167
- fastify: FastifyInstance
168
- ): Promise<any[]> {
169
- const PAGE_SIZE = 10000;
170
- const MAX_EVENTS = 100000;
171
-
172
- const allEvents: any[] = [];
173
- let offset = 0;
174
- let hasMore = true;
175
-
176
- while (hasMore && allEvents.length < MAX_EVENTS) {
177
- const response = await analytics.getEvents({
178
- ...query,
179
- limit: PAGE_SIZE,
180
- offset,
181
- });
182
-
183
- allEvents.push(...response.events);
184
- hasMore = response.hasMore;
185
- offset += PAGE_SIZE;
186
-
187
- // Stop if we've fetched all events or page not full
188
- if (!hasMore || response.events.length < PAGE_SIZE) {
189
- break;
190
- }
191
- }
192
-
193
- // Warn if we hit the safety limit
194
- if (allEvents.length >= MAX_EVENTS) {
195
- fastify.log.warn({ query }, `Hit max events limit (${MAX_EVENTS}) for query. Some events excluded from stats.`);
196
- }
197
-
198
- return allEvents;
199
- }
200
-
201
- /**
202
- * Basic ISO 8601 validation
203
- */
204
- function isValidISODate(dateString: string): boolean {
205
- // Check if it's a string
206
- if (typeof dateString !== 'string' || dateString.length === 0) {
207
- return false;
208
- }
209
-
210
- const date = new Date(dateString);
211
- return !isNaN(date.getTime());
212
- }
213
-
214
- /**
215
- * Register platform adapter analytics routes
216
- */
217
- export async function registerAdaptersRoutes(
218
- fastify: FastifyInstance,
219
- config: RestApiConfig
220
- ): Promise<void> {
221
- const basePath = normalizeBasePath(config.basePath);
222
-
223
- // GET /api/v1/adapters/llm/usage
224
- // Returns aggregated LLM usage statistics
225
- const llmUsagePaths = resolvePaths(basePath, '/adapters/llm/usage');
226
- for (const path of llmUsagePaths) {
227
- fastify.get(path, async (request, reply) => {
228
- const analytics = platform.analytics;
229
-
230
- // Check if analytics supports reading
231
- if (!analytics.getEvents) {
232
- return reply.code(501).send({
233
- ok: false,
234
- error: {
235
- code: 'ANALYTICS_NOT_IMPLEMENTED',
236
- message: 'Analytics adapter does not support reading events',
237
- },
238
- });
239
- }
240
-
241
- try {
242
- // Extract and validate date range
243
- const dateRange = extractDateRange(request.query);
244
-
245
- // Fetch ALL LLM completion events in batches (backend handles pagination)
246
- const completedEvents = await fetchAllEventsBatched(
247
- analytics,
248
- {
249
- type: ['llm.completion.completed', 'llm.chatWithTools.completed'],
250
- from: dateRange.from,
251
- to: dateRange.to,
252
- },
253
- fastify
254
- );
255
-
256
- // Fetch ALL error events in batches
257
- const errorEvents = await fetchAllEventsBatched(
258
- analytics,
259
- {
260
- type: ['llm.completion.error', 'llm.chatWithTools.error'],
261
- from: dateRange.from,
262
- to: dateRange.to,
263
- },
264
- fastify
265
- );
266
-
267
- // Aggregate statistics
268
- const stats: LLMUsageStats = {
269
- totalRequests: 0,
270
- totalTokens: 0,
271
- totalCost: 0,
272
- costPer1KTokens: 0,
273
- totalCacheReadTokens: 0,
274
- totalBillableTokens: 0,
275
- totalCacheSavingsUsd: 0,
276
- byModel: {},
277
- errors: errorEvents.length,
278
- errorBreakdown: {
279
- timeout: 0,
280
- rateLimit: 0,
281
- invalidRequest: 0,
282
- serverError: 0,
283
- other: 0,
284
- },
285
- timeRange: {
286
- from: '',
287
- to: '',
288
- },
289
- };
290
-
291
- // Collect durations per model for percentile calculation
292
- const durationsByModel: Record<string, number[]> = {};
293
-
294
- // Track errors per model
295
- const errorsByModel: Record<string, number> = {};
296
-
297
- // Process completed events
298
- for (const event of completedEvents) {
299
- const props = getEventData(event);
300
-
301
- const model = (props.model || 'unknown') as string;
302
- const promptTokens = Number(props.promptTokens || 0);
303
- const completionTokens = Number(props.completionTokens || 0);
304
- const totalTokens = Number(props.totalTokens || promptTokens + completionTokens);
305
- const estimatedCost = Number(props.estimatedCost || 0);
306
- const durationMs = Number(props.durationMs || 0);
307
- const cacheReadTokens = Number(props.cacheReadTokens || 0);
308
- const billableTokens = Number(props.billableTotalTokens || totalTokens);
309
- const cacheSavingsUsd = Number(props.estimatedCacheSavingsUsd || 0);
310
-
311
- stats.totalRequests++;
312
- stats.totalTokens += totalTokens;
313
- stats.totalCost += estimatedCost;
314
- stats.totalCacheReadTokens += cacheReadTokens;
315
- stats.totalBillableTokens += billableTokens;
316
- stats.totalCacheSavingsUsd += cacheSavingsUsd;
317
-
318
- if (!stats.byModel[model]) {
319
- stats.byModel[model] = {
320
- requests: 0,
321
- promptTokens: 0,
322
- completionTokens: 0,
323
- totalTokens: 0,
324
- cost: 0,
325
- costPer1KTokens: 0,
326
- tokensPerRequest: 0,
327
- errorRate: 0,
328
- avgDurationMs: 0,
329
- p50DurationMs: 0,
330
- p95DurationMs: 0,
331
- p99DurationMs: 0,
332
- cacheReadTokens: 0,
333
- billableTokens: 0,
334
- cacheSavingsUsd: 0,
335
- };
336
- durationsByModel[model] = [];
337
- }
338
-
339
- const modelStats = stats.byModel[model]!;
340
- modelStats.requests++;
341
- modelStats.promptTokens += promptTokens;
342
- modelStats.completionTokens += completionTokens;
343
- modelStats.totalTokens += totalTokens;
344
- modelStats.cost += estimatedCost;
345
- modelStats.cacheReadTokens += cacheReadTokens;
346
- modelStats.billableTokens += billableTokens;
347
- modelStats.cacheSavingsUsd += cacheSavingsUsd;
348
- modelStats.avgDurationMs =
349
- (modelStats.avgDurationMs * (modelStats.requests - 1) + durationMs) / modelStats.requests;
350
-
351
- // Collect duration for percentile calculation
352
- durationsByModel[model]!.push(durationMs);
353
- }
354
-
355
- // Process error events for breakdown
356
- for (const event of errorEvents) {
357
- const props = getEventData(event);
358
- const errorType = String(props.errorType || props.errorCode || '').toLowerCase();
359
- const errorMessage = String(props.error || props.message || '').toLowerCase();
360
- const model = (props.model || 'unknown') as string;
361
-
362
- // Track errors per model
363
- errorsByModel[model] = (errorsByModel[model] || 0) + 1;
364
-
365
- // Categorize error by type
366
- if (errorType.includes('timeout') || errorMessage.includes('timeout') || errorMessage.includes('timed out')) {
367
- stats.errorBreakdown.timeout++;
368
- } else if (errorType.includes('rate') || errorType.includes('quota') || errorMessage.includes('rate limit') || errorMessage.includes('quota exceeded')) {
369
- stats.errorBreakdown.rateLimit++;
370
- } else if (errorType.includes('invalid') || errorType.includes('validation') || errorMessage.includes('invalid request') || errorMessage.includes('bad request')) {
371
- stats.errorBreakdown.invalidRequest++;
372
- } else if (errorType.includes('server') || errorType.includes('5xx') || errorMessage.includes('internal error') || errorMessage.includes('server error')) {
373
- stats.errorBreakdown.serverError++;
374
- } else {
375
- stats.errorBreakdown.other++;
376
- }
377
- }
378
-
379
- // Calculate percentiles and cost per 1K tokens for each model
380
- for (const [model, durations] of Object.entries(durationsByModel)) {
381
- const modelStats = stats.byModel[model]!;
382
-
383
- // Calculate percentiles
384
- if (durations.length > 0) {
385
- const sorted = durations.slice().sort((a, b) => a - b);
386
- const p50Index = Math.floor(sorted.length * 0.5);
387
- const p95Index = Math.floor(sorted.length * 0.95);
388
- const p99Index = Math.floor(sorted.length * 0.99);
389
-
390
- modelStats.p50DurationMs = sorted[p50Index] ?? 0;
391
- modelStats.p95DurationMs = sorted[p95Index] ?? 0;
392
- modelStats.p99DurationMs = sorted[p99Index] ?? 0;
393
- }
394
-
395
- // Calculate cost per 1K tokens
396
- if (modelStats.totalTokens > 0) {
397
- modelStats.costPer1KTokens = (modelStats.cost / modelStats.totalTokens) * 1000;
398
- }
399
-
400
- // Calculate tokens per request
401
- if (modelStats.requests > 0) {
402
- modelStats.tokensPerRequest = modelStats.totalTokens / modelStats.requests;
403
- }
404
-
405
- // Calculate error rate percentage
406
- const modelErrors = errorsByModel[model] || 0;
407
- const totalModelRequests = modelStats.requests + modelErrors;
408
- if (totalModelRequests > 0) {
409
- modelStats.errorRate = (modelErrors / totalModelRequests) * 100;
410
- }
411
- }
412
-
413
- // Calculate overall cost per 1K tokens
414
- if (stats.totalTokens > 0) {
415
- stats.costPer1KTokens = (stats.totalCost / stats.totalTokens) * 1000;
416
- }
417
-
418
- // Calculate time range
419
- const allTimestamps = completedEvents.map((e) => e.ts);
420
- if (allTimestamps.length > 0) {
421
- stats.timeRange.from = allTimestamps[allTimestamps.length - 1]!; // oldest
422
- stats.timeRange.to = allTimestamps[0]!; // newest
423
- }
424
-
425
- return {
426
- ok: true,
427
- data: stats,
428
- meta: {
429
- source: 'analytics-adapter',
430
- totalEvents: completedEvents.length,
431
- },
432
- };
433
- } catch (error) {
434
- // Handle validation errors
435
- if (error instanceof Error && error.message.includes('Invalid')) {
436
- return reply.code(400).send({
437
- ok: false,
438
- error: {
439
- code: 'INVALID_DATE_RANGE',
440
- message: error.message,
441
- },
442
- });
443
- }
444
-
445
- platform.logger.error('Failed to fetch LLM usage stats', error instanceof Error ? error : new Error(String(error)));
446
-
447
- return reply.code(500).send({
448
- ok: false,
449
- error: {
450
- code: 'LLM_USAGE_STATS_ERROR',
451
- message: error instanceof Error ? error.message : 'Failed to fetch LLM usage statistics',
452
- },
453
- });
454
- }
455
- });
456
- }
457
-
458
- // GET /api/v1/adapters/llm/daily-stats
459
- // Returns time-bucketed aggregated LLM statistics for time-series visualization
460
- // Query params: from, to, groupBy (hour|day|week|month), breakdownBy (dot-path), metrics (csv), models (csv, legacy filter)
461
- const llmDailyStatsPaths = resolvePaths(basePath, '/adapters/llm/daily-stats');
462
- for (const path of llmDailyStatsPaths) {
463
- fastify.get(path, async (request, reply) => {
464
- const analytics = platform.analytics;
465
-
466
- if (!analytics.getDailyStats) {
467
- return reply.code(501).send({
468
- ok: false,
469
- error: {
470
- code: 'DAILY_STATS_NOT_IMPLEMENTED',
471
- message: 'Analytics adapter does not support daily statistics',
472
- },
473
- });
474
- }
475
-
476
- try {
477
- const dateRange = extractDateRange(request.query);
478
- const statsOptions = extractStatsOptions(request.query);
479
- const modelFilter = extractModelFilter(request.query);
480
-
481
- const dailyStats = await analytics.getDailyStats({
482
- type: ['llm.completion.completed', 'llm.chatWithTools.completed'],
483
- from: dateRange.from,
484
- to: dateRange.to,
485
- limit: 50000,
486
- // Legacy ?models= filter maps to source filter via getEvents inside the adapter.
487
- // When breakdownBy is provided explicitly it takes precedence.
488
- // Models filter is handled post-aggregation below for backward compat.
489
- ...statsOptions,
490
- });
491
-
492
- // Legacy model filter: post-filter rows by breakdown value when models param is used
493
- // without an explicit breakdownBy (backward compatibility with existing Studio pages)
494
- const result =
495
- modelFilter && modelFilter.length > 0 && !statsOptions.breakdownBy
496
- ? dailyStats.filter((s) => !s.breakdown || modelFilter.includes(s.breakdown))
497
- : dailyStats;
498
-
499
- return reply.send({ ok: true, data: result });
500
- } catch (error) {
501
- if (error instanceof Error && error.message.includes('Invalid')) {
502
- return reply.code(400).send({
503
- ok: false,
504
- error: { code: 'INVALID_DATE_RANGE', message: error.message },
505
- });
506
- }
507
- return reply.code(500).send({
508
- ok: false,
509
- error: {
510
- code: 'DAILY_STATS_ERROR',
511
- message: error instanceof Error ? error.message : 'Failed to fetch daily statistics',
512
- },
513
- });
514
- }
515
- });
516
- }
517
-
518
- // GET /api/v1/adapters/embeddings/daily-stats
519
- // Returns time-bucketed aggregated Embeddings statistics for time-series visualization
520
- // Query params: from, to, groupBy (hour|day|week|month), breakdownBy (dot-path), metrics (csv)
521
- const embeddingsDailyStatsPaths = resolvePaths(basePath, '/adapters/embeddings/daily-stats');
522
- for (const path of embeddingsDailyStatsPaths) {
523
- fastify.get(path, async (request, reply) => {
524
- const analytics = platform.analytics;
525
-
526
- if (!analytics.getDailyStats) {
527
- return reply.code(501).send({
528
- ok: false,
529
- error: {
530
- code: 'DAILY_STATS_NOT_IMPLEMENTED',
531
- message: 'Analytics adapter does not support daily statistics',
532
- },
533
- });
534
- }
535
-
536
- try {
537
- const dateRange = extractDateRange(request.query);
538
- const statsOptions = extractStatsOptions(request.query);
539
-
540
- const dailyStats = await analytics.getDailyStats({
541
- type: ['embeddings.embed.completed', 'embeddings.embedBatch.completed'],
542
- from: dateRange.from,
543
- to: dateRange.to,
544
- limit: 50000,
545
- ...statsOptions,
546
- });
547
-
548
- return reply.send({ ok: true, data: dailyStats });
549
- } catch (error) {
550
- if (error instanceof Error && error.message.includes('Invalid')) {
551
- return reply.code(400).send({
552
- ok: false,
553
- error: { code: 'INVALID_DATE_RANGE', message: error.message },
554
- });
555
- }
556
- return reply.code(500).send({
557
- ok: false,
558
- error: {
559
- code: 'DAILY_STATS_ERROR',
560
- message: error instanceof Error ? error.message : 'Failed to fetch daily statistics',
561
- },
562
- });
563
- }
564
- });
565
- }
566
-
567
- // GET /api/v1/adapters/embeddings/usage
568
- // Returns aggregated Embeddings usage statistics
569
- const embeddingsUsagePaths = resolvePaths(basePath, '/adapters/embeddings/usage');
570
- for (const path of embeddingsUsagePaths) {
571
- fastify.get(path, async (request, reply) => {
572
- const analytics = platform.analytics;
573
-
574
- if (!analytics.getEvents) {
575
- return reply.code(501).send({
576
- ok: false,
577
- error: {
578
- code: 'ANALYTICS_NOT_IMPLEMENTED',
579
- message: 'Analytics adapter does not support reading events',
580
- },
581
- });
582
- }
583
-
584
- try {
585
- // Extract and validate date range
586
- const dateRange = extractDateRange(request.query);
587
-
588
- const completedEvents = await fetchAllEventsBatched(
589
- analytics,
590
- {
591
- type: ['embeddings.embed.completed', 'embeddings.embedBatch.completed'],
592
- from: dateRange.from,
593
- to: dateRange.to,
594
- },
595
- fastify
596
- );
597
-
598
- const errorEvents = await fetchAllEventsBatched(
599
- analytics,
600
- {
601
- type: ['embeddings.embed.error', 'embeddings.embedBatch.error'],
602
- from: dateRange.from,
603
- to: dateRange.to,
604
- },
605
- fastify
606
- );
607
-
608
- const stats = {
609
- totalRequests: completedEvents.length,
610
- totalTextLength: 0,
611
- totalCost: 0,
612
- costPer1KChars: 0, // Enhanced: Cost efficiency metric
613
- errors: errorEvents.length,
614
- // Enhanced: Error breakdown by type
615
- errorBreakdown: {
616
- timeout: 0,
617
- rateLimit: 0,
618
- invalidRequest: 0,
619
- serverError: 0,
620
- other: 0,
621
- },
622
- avgDurationMs: 0,
623
- // Enhanced: Latency percentiles
624
- p50DurationMs: 0,
625
- p95DurationMs: 0,
626
- p99DurationMs: 0,
627
- batchRequests: 0,
628
- singleRequests: 0,
629
- avgBatchSize: 0,
630
- };
631
-
632
- let totalDuration = 0;
633
- let totalBatchSize = 0;
634
- const durations: number[] = [];
635
-
636
- for (const event of completedEvents) {
637
- const props = getEventData(event);
638
-
639
- const textLength = Number(props.textLength || props.totalTextLength || 0);
640
- const cost = Number(props.estimatedCost || 0);
641
- const duration = Number(props.durationMs || 0);
642
- const batchSize = Number(props.batchSize || 1);
643
-
644
- stats.totalTextLength += textLength;
645
- stats.totalCost += cost;
646
- totalDuration += duration;
647
- durations.push(duration);
648
-
649
- if (batchSize > 1) {
650
- stats.batchRequests++;
651
- totalBatchSize += batchSize;
652
- } else {
653
- stats.singleRequests++;
654
- }
655
- }
656
-
657
- stats.avgDurationMs = stats.totalRequests > 0 ? totalDuration / stats.totalRequests : 0;
658
- stats.avgBatchSize = stats.batchRequests > 0 ? totalBatchSize / stats.batchRequests : 0;
659
-
660
- // Calculate percentiles
661
- if (durations.length > 0) {
662
- const sorted = durations.slice().sort((a, b) => a - b);
663
- const p50Index = Math.floor(sorted.length * 0.5);
664
- const p95Index = Math.floor(sorted.length * 0.95);
665
- const p99Index = Math.floor(sorted.length * 0.99);
666
-
667
- stats.p50DurationMs = sorted[p50Index] ?? 0;
668
- stats.p95DurationMs = sorted[p95Index] ?? 0;
669
- stats.p99DurationMs = sorted[p99Index] ?? 0;
670
- }
671
-
672
- // Calculate cost per 1K characters
673
- if (stats.totalTextLength > 0) {
674
- stats.costPer1KChars = (stats.totalCost / stats.totalTextLength) * 1000;
675
- }
676
-
677
- // Process error events for breakdown
678
- for (const event of errorEvents) {
679
- const props = getEventData(event);
680
- const errorType = String(props.errorType || props.errorCode || '').toLowerCase();
681
- const errorMessage = String(props.error || props.message || '').toLowerCase();
682
-
683
- // Categorize error by type
684
- if (errorType.includes('timeout') || errorMessage.includes('timeout') || errorMessage.includes('timed out')) {
685
- stats.errorBreakdown.timeout++;
686
- } else if (errorType.includes('rate') || errorType.includes('quota') || errorMessage.includes('rate limit') || errorMessage.includes('quota exceeded')) {
687
- stats.errorBreakdown.rateLimit++;
688
- } else if (errorType.includes('invalid') || errorType.includes('validation') || errorMessage.includes('invalid request') || errorMessage.includes('bad request')) {
689
- stats.errorBreakdown.invalidRequest++;
690
- } else if (errorType.includes('server') || errorType.includes('5xx') || errorMessage.includes('internal error') || errorMessage.includes('server error')) {
691
- stats.errorBreakdown.serverError++;
692
- } else {
693
- stats.errorBreakdown.other++;
694
- }
695
- }
696
-
697
- return { ok: true, data: stats, meta: { source: 'analytics-adapter' } };
698
- } catch (error) {
699
- // Handle validation errors
700
- if (error instanceof Error && error.message.includes('Invalid')) {
701
- return reply.code(400).send({
702
- ok: false,
703
- error: {
704
- code: 'INVALID_DATE_RANGE',
705
- message: error.message,
706
- },
707
- });
708
- }
709
-
710
- platform.logger.error('Failed to fetch Embeddings usage stats', error instanceof Error ? error : new Error(String(error)));
711
- return reply.code(500).send({
712
- ok: false,
713
- error: {
714
- code: 'EMBEDDINGS_USAGE_STATS_ERROR',
715
- message: error instanceof Error ? error.message : 'Failed to fetch embeddings statistics',
716
- },
717
- });
718
- }
719
- });
720
- }
721
-
722
- // GET /api/v1/adapters/vectorstore/daily-stats
723
- // Returns time-bucketed aggregated VectorStore statistics for time-series visualization
724
- // Query params: from, to, groupBy (hour|day|week|month), breakdownBy (dot-path), metrics (csv)
725
- const vectorstoreDailyStatsPaths = resolvePaths(basePath, '/adapters/vectorstore/daily-stats');
726
- for (const path of vectorstoreDailyStatsPaths) {
727
- fastify.get(path, async (request, reply) => {
728
- const analytics = platform.analytics;
729
-
730
- if (!analytics.getDailyStats) {
731
- return reply.code(501).send({
732
- ok: false,
733
- error: {
734
- code: 'DAILY_STATS_NOT_IMPLEMENTED',
735
- message: 'Analytics adapter does not support daily statistics',
736
- },
737
- });
738
- }
739
-
740
- try {
741
- const dateRange = extractDateRange(request.query);
742
- const statsOptions = extractStatsOptions(request.query);
743
-
744
- const dailyStats = await analytics.getDailyStats({
745
- type: ['vectorstore.search.completed', 'vectorstore.upsert.completed', 'vectorstore.delete.completed'],
746
- from: dateRange.from,
747
- to: dateRange.to,
748
- limit: 50000,
749
- ...statsOptions,
750
- });
751
-
752
- return reply.send({ ok: true, data: dailyStats });
753
- } catch (error) {
754
- if (error instanceof Error && error.message.includes('Invalid')) {
755
- return reply.code(400).send({
756
- ok: false,
757
- error: { code: 'INVALID_DATE_RANGE', message: error.message },
758
- });
759
- }
760
- return reply.code(500).send({
761
- ok: false,
762
- error: {
763
- code: 'DAILY_STATS_ERROR',
764
- message: error instanceof Error ? error.message : 'Failed to fetch daily statistics',
765
- },
766
- });
767
- }
768
- });
769
- }
770
-
771
- // GET /api/v1/adapters/vectorstore/usage
772
- // Returns aggregated VectorStore usage statistics
773
- const vectorstoreUsagePaths = resolvePaths(basePath, '/adapters/vectorstore/usage');
774
- for (const path of vectorstoreUsagePaths) {
775
- fastify.get(path, async (request, reply) => {
776
- const analytics = platform.analytics;
777
-
778
- if (!analytics.getEvents) {
779
- return reply.code(501).send({
780
- ok: false,
781
- error: {
782
- code: 'ANALYTICS_NOT_IMPLEMENTED',
783
- message: 'Analytics adapter does not support reading events',
784
- },
785
- });
786
- }
787
-
788
- try {
789
- // Extract and validate date range
790
- const dateRange = extractDateRange(request.query);
791
-
792
- const searchEvents = await fetchAllEventsBatched(
793
- analytics,
794
- {
795
- type: 'vectorstore.search.completed',
796
- from: dateRange.from,
797
- to: dateRange.to,
798
- },
799
- fastify
800
- );
801
-
802
- const upsertEvents = await fetchAllEventsBatched(
803
- analytics,
804
- {
805
- type: 'vectorstore.upsert.completed',
806
- from: dateRange.from,
807
- to: dateRange.to,
808
- },
809
- fastify
810
- );
811
-
812
- const deleteEvents = await fetchAllEventsBatched(
813
- analytics,
814
- {
815
- type: 'vectorstore.delete.completed',
816
- from: dateRange.from,
817
- to: dateRange.to,
818
- },
819
- fastify
820
- );
821
-
822
- const stats = {
823
- searchQueries: searchEvents.length,
824
- upsertOperations: upsertEvents.length,
825
- deleteOperations: deleteEvents.length,
826
- avgSearchDuration: 0,
827
- // Enhanced: Search latency percentiles
828
- p50SearchDuration: 0,
829
- p95SearchDuration: 0,
830
- p99SearchDuration: 0,
831
- avgSearchScore: 0,
832
- avgResultsCount: 0,
833
- totalVectorsUpserted: 0,
834
- totalVectorsDeleted: 0,
835
- };
836
-
837
- let totalSearchDuration = 0;
838
- let totalSearchScore = 0;
839
- let totalResultsCount = 0;
840
- const searchDurations: number[] = [];
841
-
842
- for (const event of searchEvents) {
843
- const props = getEventData(event);
844
-
845
- const duration = Number(props.durationMs || 0);
846
- const avgScore = Number(props.avgScore || 0);
847
- const resultsCount = Number(props.resultsCount || 0);
848
-
849
- totalSearchDuration += duration;
850
- totalSearchScore += avgScore;
851
- totalResultsCount += resultsCount;
852
- searchDurations.push(duration);
853
- }
854
-
855
- stats.avgSearchDuration = stats.searchQueries > 0 ? totalSearchDuration / stats.searchQueries : 0;
856
- stats.avgSearchScore = stats.searchQueries > 0 ? totalSearchScore / stats.searchQueries : 0;
857
- stats.avgResultsCount = stats.searchQueries > 0 ? totalResultsCount / stats.searchQueries : 0;
858
-
859
- // Calculate search latency percentiles
860
- if (searchDurations.length > 0) {
861
- const sorted = searchDurations.slice().sort((a, b) => a - b);
862
- const p50Index = Math.floor(sorted.length * 0.5);
863
- const p95Index = Math.floor(sorted.length * 0.95);
864
- const p99Index = Math.floor(sorted.length * 0.99);
865
-
866
- stats.p50SearchDuration = sorted[p50Index] ?? 0;
867
- stats.p95SearchDuration = sorted[p95Index] ?? 0;
868
- stats.p99SearchDuration = sorted[p99Index] ?? 0;
869
- }
870
-
871
- for (const event of upsertEvents) {
872
- const props = getEventData(event);
873
- stats.totalVectorsUpserted += Number(props.vectorCount || 0);
874
- }
875
-
876
- for (const event of deleteEvents) {
877
- const props = getEventData(event);
878
- stats.totalVectorsDeleted += Number(props.idsCount || 0);
879
- }
880
-
881
- return { ok: true, data: stats, meta: { source: 'analytics-adapter' } };
882
- } catch (error) {
883
- // Handle validation errors
884
- if (error instanceof Error && error.message.includes('Invalid')) {
885
- return reply.code(400).send({
886
- ok: false,
887
- error: {
888
- code: 'INVALID_DATE_RANGE',
889
- message: error.message,
890
- },
891
- });
892
- }
893
-
894
- platform.logger.error('Failed to fetch VectorStore usage stats', error instanceof Error ? error : new Error(String(error)));
895
- return reply.code(500).send({
896
- ok: false,
897
- error: {
898
- code: 'VECTORSTORE_USAGE_STATS_ERROR',
899
- message: error instanceof Error ? error.message : 'Failed to fetch vectorstore statistics',
900
- },
901
- });
902
- }
903
- });
904
- }
905
-
906
- // GET /api/v1/adapters/cache/daily-stats
907
- // Returns time-bucketed aggregated Cache statistics for time-series visualization
908
- // Query params: from, to, groupBy (hour|day|week|month), breakdownBy (dot-path), metrics (csv)
909
- const cacheDailyStatsPaths = resolvePaths(basePath, '/adapters/cache/daily-stats');
910
- for (const path of cacheDailyStatsPaths) {
911
- fastify.get(path, async (request, reply) => {
912
- const analytics = platform.analytics;
913
-
914
- if (!analytics.getDailyStats) {
915
- return reply.code(501).send({
916
- ok: false,
917
- error: {
918
- code: 'DAILY_STATS_NOT_IMPLEMENTED',
919
- message: 'Analytics adapter does not support daily statistics',
920
- },
921
- });
922
- }
923
-
924
- try {
925
- const dateRange = extractDateRange(request.query);
926
- const statsOptions = extractStatsOptions(request.query);
927
-
928
- const dailyStats = await analytics.getDailyStats({
929
- type: ['cache.get.hit', 'cache.get.miss', 'cache.set.completed'],
930
- from: dateRange.from,
931
- to: dateRange.to,
932
- limit: 50000,
933
- ...statsOptions,
934
- });
935
-
936
- return reply.send({ ok: true, data: dailyStats });
937
- } catch (error) {
938
- if (error instanceof Error && error.message.includes('Invalid')) {
939
- return reply.code(400).send({
940
- ok: false,
941
- error: { code: 'INVALID_DATE_RANGE', message: error.message },
942
- });
943
- }
944
- return reply.code(500).send({
945
- ok: false,
946
- error: {
947
- code: 'DAILY_STATS_ERROR',
948
- message: error instanceof Error ? error.message : 'Failed to fetch daily statistics',
949
- },
950
- });
951
- }
952
- });
953
- }
954
-
955
- // GET /api/v1/adapters/cache/usage
956
- // Returns aggregated Cache usage statistics
957
- const cacheUsagePaths = resolvePaths(basePath, '/adapters/cache/usage');
958
- for (const path of cacheUsagePaths) {
959
- fastify.get(path, async (request, reply) => {
960
- const analytics = platform.analytics;
961
-
962
- if (!analytics.getEvents) {
963
- return reply.code(501).send({
964
- ok: false,
965
- error: {
966
- code: 'ANALYTICS_NOT_IMPLEMENTED',
967
- message: 'Analytics adapter does not support reading events',
968
- },
969
- });
970
- }
971
-
972
- try {
973
- // Extract and validate date range
974
- const dateRange = extractDateRange(request.query);
975
-
976
- const hitEvents = await fetchAllEventsBatched(
977
- analytics,
978
- {
979
- type: 'cache.get.hit',
980
- from: dateRange.from,
981
- to: dateRange.to,
982
- },
983
- fastify
984
- );
985
- const missEvents = await fetchAllEventsBatched(
986
- analytics,
987
- {
988
- type: 'cache.get.miss',
989
- from: dateRange.from,
990
- to: dateRange.to,
991
- },
992
- fastify
993
- );
994
- const setEvents = await fetchAllEventsBatched(
995
- analytics,
996
- {
997
- type: 'cache.set.completed',
998
- from: dateRange.from,
999
- to: dateRange.to,
1000
- },
1001
- fastify
1002
- );
1003
-
1004
- const totalGets = hitEvents.length + missEvents.length;
1005
- const hitRate = totalGets > 0 ? (hitEvents.length / totalGets) * 100 : 0;
1006
-
1007
- const stats = {
1008
- totalGets,
1009
- hits: hitEvents.length,
1010
- misses: missEvents.length,
1011
- hitRate,
1012
- sets: setEvents.length,
1013
- avgGetDuration: 0,
1014
- avgSetDuration: 0,
1015
- };
1016
-
1017
- let totalGetDuration = 0;
1018
- for (const event of [...hitEvents, ...missEvents]) {
1019
- const props = getEventData(event);
1020
- totalGetDuration += Number(props.durationMs || 0);
1021
- }
1022
- stats.avgGetDuration = totalGets > 0 ? totalGetDuration / totalGets : 0;
1023
-
1024
- let totalSetDuration = 0;
1025
- for (const event of setEvents) {
1026
- const props = getEventData(event);
1027
- totalSetDuration += Number(props.durationMs || 0);
1028
- }
1029
- stats.avgSetDuration = stats.sets > 0 ? totalSetDuration / stats.sets : 0;
1030
-
1031
- return { ok: true, data: stats, meta: { source: 'analytics-adapter' } };
1032
- } catch (error) {
1033
- // Handle validation errors
1034
- if (error instanceof Error && error.message.includes('Invalid')) {
1035
- return reply.code(400).send({
1036
- ok: false,
1037
- error: {
1038
- code: 'INVALID_DATE_RANGE',
1039
- message: error.message,
1040
- },
1041
- });
1042
- }
1043
-
1044
- platform.logger.error('Failed to fetch Cache usage stats', error instanceof Error ? error : new Error(String(error)));
1045
- return reply.code(500).send({
1046
- ok: false,
1047
- error: {
1048
- code: 'CACHE_USAGE_STATS_ERROR',
1049
- message: error instanceof Error ? error.message : 'Failed to fetch cache statistics',
1050
- },
1051
- });
1052
- }
1053
- });
1054
- }
1055
-
1056
- // GET /api/v1/adapters/storage/daily-stats
1057
- // Returns time-bucketed aggregated Storage statistics for time-series visualization
1058
- // Query params: from, to, groupBy (hour|day|week|month), breakdownBy (dot-path), metrics (csv)
1059
- const storageDailyStatsPaths = resolvePaths(basePath, '/adapters/storage/daily-stats');
1060
- for (const path of storageDailyStatsPaths) {
1061
- fastify.get(path, async (request, reply) => {
1062
- const analytics = platform.analytics;
1063
-
1064
- if (!analytics.getDailyStats) {
1065
- return reply.code(501).send({
1066
- ok: false,
1067
- error: {
1068
- code: 'DAILY_STATS_NOT_IMPLEMENTED',
1069
- message: 'Analytics adapter does not support daily statistics',
1070
- },
1071
- });
1072
- }
1073
-
1074
- try {
1075
- const dateRange = extractDateRange(request.query);
1076
- const statsOptions = extractStatsOptions(request.query);
1077
-
1078
- const dailyStats = await analytics.getDailyStats({
1079
- type: ['storage.read.completed', 'storage.write.completed', 'storage.delete.completed'],
1080
- from: dateRange.from,
1081
- to: dateRange.to,
1082
- limit: 50000,
1083
- ...statsOptions,
1084
- });
1085
-
1086
- return reply.send({ ok: true, data: dailyStats });
1087
- } catch (error) {
1088
- if (error instanceof Error && error.message.includes('Invalid')) {
1089
- return reply.code(400).send({
1090
- ok: false,
1091
- error: { code: 'INVALID_DATE_RANGE', message: error.message },
1092
- });
1093
- }
1094
- return reply.code(500).send({
1095
- ok: false,
1096
- error: {
1097
- code: 'DAILY_STATS_ERROR',
1098
- message: error instanceof Error ? error.message : 'Failed to fetch daily statistics',
1099
- },
1100
- });
1101
- }
1102
- });
1103
- }
1104
-
1105
- // GET /api/v1/adapters/storage/usage
1106
- // Returns aggregated Storage usage statistics
1107
- const storageUsagePaths = resolvePaths(basePath, '/adapters/storage/usage');
1108
- for (const path of storageUsagePaths) {
1109
- fastify.get(path, async (request, reply) => {
1110
- const analytics = platform.analytics;
1111
-
1112
- if (!analytics.getEvents) {
1113
- return reply.code(501).send({
1114
- ok: false,
1115
- error: {
1116
- code: 'ANALYTICS_NOT_IMPLEMENTED',
1117
- message: 'Analytics adapter does not support reading events',
1118
- },
1119
- });
1120
- }
1121
-
1122
- try {
1123
- // Extract and validate date range
1124
- const dateRange = extractDateRange(request.query);
1125
-
1126
- const readEvents = await fetchAllEventsBatched(
1127
- analytics,
1128
- {
1129
- type: 'storage.read.completed',
1130
- from: dateRange.from,
1131
- to: dateRange.to,
1132
- },
1133
- fastify
1134
- );
1135
- const writeEvents = await fetchAllEventsBatched(
1136
- analytics,
1137
- {
1138
- type: 'storage.write.completed',
1139
- from: dateRange.from,
1140
- to: dateRange.to,
1141
- },
1142
- fastify
1143
- );
1144
- const deleteEvents = await fetchAllEventsBatched(
1145
- analytics,
1146
- {
1147
- type: 'storage.delete.completed',
1148
- from: dateRange.from,
1149
- to: dateRange.to,
1150
- },
1151
- fastify
1152
- );
1153
-
1154
- const stats = {
1155
- readOperations: readEvents.length,
1156
- writeOperations: writeEvents.length,
1157
- deleteOperations: deleteEvents.length,
1158
- totalBytesRead: 0,
1159
- totalBytesWritten: 0,
1160
- avgReadDuration: 0,
1161
- avgWriteDuration: 0,
1162
- };
1163
-
1164
- let totalReadDuration = 0;
1165
- for (const event of readEvents) {
1166
- const props = getEventData(event);
1167
- stats.totalBytesRead += Number(props.bytesRead || 0);
1168
- totalReadDuration += Number(props.durationMs || 0);
1169
- }
1170
- stats.avgReadDuration = stats.readOperations > 0 ? totalReadDuration / stats.readOperations : 0;
1171
-
1172
- let totalWriteDuration = 0;
1173
- for (const event of writeEvents) {
1174
- const props = getEventData(event);
1175
- stats.totalBytesWritten += Number(props.bytesWritten || 0);
1176
- totalWriteDuration += Number(props.durationMs || 0);
1177
- }
1178
- stats.avgWriteDuration = stats.writeOperations > 0 ? totalWriteDuration / stats.writeOperations : 0;
1179
-
1180
- return { ok: true, data: stats, meta: { source: 'analytics-adapter' } };
1181
- } catch (error) {
1182
- // Handle validation errors
1183
- if (error instanceof Error && error.message.includes('Invalid')) {
1184
- return reply.code(400).send({
1185
- ok: false,
1186
- error: {
1187
- code: 'INVALID_DATE_RANGE',
1188
- message: error.message,
1189
- },
1190
- });
1191
- }
1192
-
1193
- platform.logger.error('Failed to fetch Storage usage stats', error instanceof Error ? error : new Error(String(error)));
1194
- return reply.code(500).send({
1195
- ok: false,
1196
- error: {
1197
- code: 'STORAGE_USAGE_STATS_ERROR',
1198
- message: error instanceof Error ? error.message : 'Failed to fetch storage statistics',
1199
- },
1200
- });
1201
- }
1202
- });
1203
- }
1204
-
1205
- fastify.log.info('Platform adapter routes registered');
1206
- }