enpilink 1.0.2

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 (477) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +289 -0
  3. package/bin/run.js +5 -0
  4. package/dist/cli/build-helpers.d.ts +8 -0
  5. package/dist/cli/build-helpers.js +105 -0
  6. package/dist/cli/build-helpers.js.map +1 -0
  7. package/dist/cli/build-helpers.test.d.ts +1 -0
  8. package/dist/cli/build-helpers.test.js +100 -0
  9. package/dist/cli/build-helpers.test.js.map +1 -0
  10. package/dist/cli/detect-port.d.ts +18 -0
  11. package/dist/cli/detect-port.js +50 -0
  12. package/dist/cli/detect-port.js.map +1 -0
  13. package/dist/cli/ensure-ssh-key.d.ts +17 -0
  14. package/dist/cli/ensure-ssh-key.js +45 -0
  15. package/dist/cli/ensure-ssh-key.js.map +1 -0
  16. package/dist/cli/ensure-ssh-key.test.d.ts +1 -0
  17. package/dist/cli/ensure-ssh-key.test.js +68 -0
  18. package/dist/cli/ensure-ssh-key.test.js.map +1 -0
  19. package/dist/cli/header.d.ts +4 -0
  20. package/dist/cli/header.js +6 -0
  21. package/dist/cli/header.js.map +1 -0
  22. package/dist/cli/resolve-views-dir.d.ts +1 -0
  23. package/dist/cli/resolve-views-dir.js +17 -0
  24. package/dist/cli/resolve-views-dir.js.map +1 -0
  25. package/dist/cli/run-command.d.ts +2 -0
  26. package/dist/cli/run-command.js +43 -0
  27. package/dist/cli/run-command.js.map +1 -0
  28. package/dist/cli/telemetry.d.ts +14 -0
  29. package/dist/cli/telemetry.js +24 -0
  30. package/dist/cli/telemetry.js.map +1 -0
  31. package/dist/cli/tunnel-control-server.d.ts +11 -0
  32. package/dist/cli/tunnel-control-server.js +35 -0
  33. package/dist/cli/tunnel-control-server.js.map +1 -0
  34. package/dist/cli/tunnel-control-server.test.d.ts +1 -0
  35. package/dist/cli/tunnel-control-server.test.js +39 -0
  36. package/dist/cli/tunnel-control-server.test.js.map +1 -0
  37. package/dist/cli/tunnel-handler.d.ts +3 -0
  38. package/dist/cli/tunnel-handler.js +48 -0
  39. package/dist/cli/tunnel-handler.js.map +1 -0
  40. package/dist/cli/tunnel-handler.test.d.ts +1 -0
  41. package/dist/cli/tunnel-handler.test.js +107 -0
  42. package/dist/cli/tunnel-handler.test.js.map +1 -0
  43. package/dist/cli/tunnel-providers/index.d.ts +5 -0
  44. package/dist/cli/tunnel-providers/index.js +5 -0
  45. package/dist/cli/tunnel-providers/index.js.map +1 -0
  46. package/dist/cli/tunnel-providers/srv-us.d.ts +18 -0
  47. package/dist/cli/tunnel-providers/srv-us.js +66 -0
  48. package/dist/cli/tunnel-providers/srv-us.js.map +1 -0
  49. package/dist/cli/tunnel-providers/srv-us.test.d.ts +1 -0
  50. package/dist/cli/tunnel-providers/srv-us.test.js +74 -0
  51. package/dist/cli/tunnel-providers/srv-us.test.js.map +1 -0
  52. package/dist/cli/tunnel-providers/types.d.ts +49 -0
  53. package/dist/cli/tunnel-providers/types.js +2 -0
  54. package/dist/cli/tunnel-providers/types.js.map +1 -0
  55. package/dist/cli/tunnel.d.ts +75 -0
  56. package/dist/cli/tunnel.js +254 -0
  57. package/dist/cli/tunnel.js.map +1 -0
  58. package/dist/cli/tunnel.test.d.ts +1 -0
  59. package/dist/cli/tunnel.test.js +255 -0
  60. package/dist/cli/tunnel.test.js.map +1 -0
  61. package/dist/cli/types.d.ts +5 -0
  62. package/dist/cli/types.js +2 -0
  63. package/dist/cli/types.js.map +1 -0
  64. package/dist/cli/use-execute-steps.d.ts +11 -0
  65. package/dist/cli/use-execute-steps.js +36 -0
  66. package/dist/cli/use-execute-steps.js.map +1 -0
  67. package/dist/cli/use-messages.d.ts +3 -0
  68. package/dist/cli/use-messages.js +11 -0
  69. package/dist/cli/use-messages.js.map +1 -0
  70. package/dist/cli/use-nodemon.d.ts +2 -0
  71. package/dist/cli/use-nodemon.js +73 -0
  72. package/dist/cli/use-nodemon.js.map +1 -0
  73. package/dist/cli/use-open-browser.d.ts +1 -0
  74. package/dist/cli/use-open-browser.js +44 -0
  75. package/dist/cli/use-open-browser.js.map +1 -0
  76. package/dist/cli/use-open-tunnel-browser.d.ts +6 -0
  77. package/dist/cli/use-open-tunnel-browser.js +19 -0
  78. package/dist/cli/use-open-tunnel-browser.js.map +1 -0
  79. package/dist/cli/use-tunnel.d.ts +17 -0
  80. package/dist/cli/use-tunnel.js +131 -0
  81. package/dist/cli/use-tunnel.js.map +1 -0
  82. package/dist/cli/use-typescript-check.d.ts +9 -0
  83. package/dist/cli/use-typescript-check.js +94 -0
  84. package/dist/cli/use-typescript-check.js.map +1 -0
  85. package/dist/commands/build.d.ts +8 -0
  86. package/dist/commands/build.js +97 -0
  87. package/dist/commands/build.js.map +1 -0
  88. package/dist/commands/create.d.ts +9 -0
  89. package/dist/commands/create.js +30 -0
  90. package/dist/commands/create.js.map +1 -0
  91. package/dist/commands/dev.d.ts +13 -0
  92. package/dist/commands/dev.js +112 -0
  93. package/dist/commands/dev.js.map +1 -0
  94. package/dist/commands/start.d.ts +10 -0
  95. package/dist/commands/start.js +76 -0
  96. package/dist/commands/start.js.map +1 -0
  97. package/dist/commands/telemetry/disable.d.ts +5 -0
  98. package/dist/commands/telemetry/disable.js +12 -0
  99. package/dist/commands/telemetry/disable.js.map +1 -0
  100. package/dist/commands/telemetry/enable.d.ts +5 -0
  101. package/dist/commands/telemetry/enable.js +12 -0
  102. package/dist/commands/telemetry/enable.js.map +1 -0
  103. package/dist/commands/telemetry/status.d.ts +5 -0
  104. package/dist/commands/telemetry/status.js +12 -0
  105. package/dist/commands/telemetry/status.js.map +1 -0
  106. package/dist/server/admin.d.ts +79 -0
  107. package/dist/server/admin.js +239 -0
  108. package/dist/server/admin.js.map +1 -0
  109. package/dist/server/admin.test.d.ts +1 -0
  110. package/dist/server/admin.test.js +226 -0
  111. package/dist/server/admin.test.js.map +1 -0
  112. package/dist/server/analytics.d.ts +60 -0
  113. package/dist/server/analytics.js +168 -0
  114. package/dist/server/analytics.js.map +1 -0
  115. package/dist/server/analytics.test.d.ts +1 -0
  116. package/dist/server/analytics.test.js +179 -0
  117. package/dist/server/analytics.test.js.map +1 -0
  118. package/dist/server/asset-base-url-transform-plugin.d.ts +11 -0
  119. package/dist/server/asset-base-url-transform-plugin.js +48 -0
  120. package/dist/server/asset-base-url-transform-plugin.js.map +1 -0
  121. package/dist/server/asset-base-url-transform-plugin.test.d.ts +1 -0
  122. package/dist/server/asset-base-url-transform-plugin.test.js +134 -0
  123. package/dist/server/asset-base-url-transform-plugin.test.js.map +1 -0
  124. package/dist/server/auth.d.ts +20 -0
  125. package/dist/server/auth.js +28 -0
  126. package/dist/server/auth.js.map +1 -0
  127. package/dist/server/build-manifest.test.d.ts +1 -0
  128. package/dist/server/build-manifest.test.js +27 -0
  129. package/dist/server/build-manifest.test.js.map +1 -0
  130. package/dist/server/config/config.test.d.ts +1 -0
  131. package/dist/server/config/config.test.js +214 -0
  132. package/dist/server/config/config.test.js.map +1 -0
  133. package/dist/server/config/index.d.ts +3 -0
  134. package/dist/server/config/index.js +4 -0
  135. package/dist/server/config/index.js.map +1 -0
  136. package/dist/server/config/resolve.d.ts +73 -0
  137. package/dist/server/config/resolve.js +167 -0
  138. package/dist/server/config/resolve.js.map +1 -0
  139. package/dist/server/config/router.d.ts +23 -0
  140. package/dist/server/config/router.js +119 -0
  141. package/dist/server/config/router.js.map +1 -0
  142. package/dist/server/config/schema.d.ts +78 -0
  143. package/dist/server/config/schema.js +158 -0
  144. package/dist/server/config/schema.js.map +1 -0
  145. package/dist/server/content-helpers.d.ts +67 -0
  146. package/dist/server/content-helpers.js +79 -0
  147. package/dist/server/content-helpers.js.map +1 -0
  148. package/dist/server/content-helpers.test.d.ts +1 -0
  149. package/dist/server/content-helpers.test.js +70 -0
  150. package/dist/server/content-helpers.test.js.map +1 -0
  151. package/dist/server/express.d.ts +11 -0
  152. package/dist/server/express.js +129 -0
  153. package/dist/server/express.js.map +1 -0
  154. package/dist/server/express.test.d.ts +1 -0
  155. package/dist/server/express.test.js +464 -0
  156. package/dist/server/express.test.js.map +1 -0
  157. package/dist/server/file-ref.d.ts +28 -0
  158. package/dist/server/file-ref.js +27 -0
  159. package/dist/server/file-ref.js.map +1 -0
  160. package/dist/server/index.d.ts +17 -0
  161. package/dist/server/index.js +14 -0
  162. package/dist/server/index.js.map +1 -0
  163. package/dist/server/inferUtilityTypes.d.ts +64 -0
  164. package/dist/server/inferUtilityTypes.js +2 -0
  165. package/dist/server/inferUtilityTypes.js.map +1 -0
  166. package/dist/server/log-sink.d.ts +16 -0
  167. package/dist/server/log-sink.js +66 -0
  168. package/dist/server/log-sink.js.map +1 -0
  169. package/dist/server/metric.d.ts +12 -0
  170. package/dist/server/metric.js +13 -0
  171. package/dist/server/metric.js.map +1 -0
  172. package/dist/server/middleware.d.ts +137 -0
  173. package/dist/server/middleware.js +93 -0
  174. package/dist/server/middleware.js.map +1 -0
  175. package/dist/server/middleware.test-d.d.ts +1 -0
  176. package/dist/server/middleware.test-d.js +75 -0
  177. package/dist/server/middleware.test-d.js.map +1 -0
  178. package/dist/server/middleware.test.d.ts +1 -0
  179. package/dist/server/middleware.test.js +493 -0
  180. package/dist/server/middleware.test.js.map +1 -0
  181. package/dist/server/mock-seed.d.ts +62 -0
  182. package/dist/server/mock-seed.js +251 -0
  183. package/dist/server/mock-seed.js.map +1 -0
  184. package/dist/server/mock-seed.test.d.ts +1 -0
  185. package/dist/server/mock-seed.test.js +122 -0
  186. package/dist/server/mock-seed.test.js.map +1 -0
  187. package/dist/server/observability.d.ts +149 -0
  188. package/dist/server/observability.js +340 -0
  189. package/dist/server/observability.js.map +1 -0
  190. package/dist/server/observability.test.d.ts +1 -0
  191. package/dist/server/observability.test.js +251 -0
  192. package/dist/server/observability.test.js.map +1 -0
  193. package/dist/server/otel.d.ts +45 -0
  194. package/dist/server/otel.js +117 -0
  195. package/dist/server/otel.js.map +1 -0
  196. package/dist/server/otel.test.d.ts +1 -0
  197. package/dist/server/otel.test.js +122 -0
  198. package/dist/server/otel.test.js.map +1 -0
  199. package/dist/server/server.d.ts +422 -0
  200. package/dist/server/server.js +684 -0
  201. package/dist/server/server.js.map +1 -0
  202. package/dist/server/storage/index.d.ts +23 -0
  203. package/dist/server/storage/index.js +46 -0
  204. package/dist/server/storage/index.js.map +1 -0
  205. package/dist/server/storage/memory.d.ts +30 -0
  206. package/dist/server/storage/memory.js +98 -0
  207. package/dist/server/storage/memory.js.map +1 -0
  208. package/dist/server/storage/memory.test.d.ts +1 -0
  209. package/dist/server/storage/memory.test.js +81 -0
  210. package/dist/server/storage/memory.test.js.map +1 -0
  211. package/dist/server/storage/postgres.d.ts +65 -0
  212. package/dist/server/storage/postgres.js +242 -0
  213. package/dist/server/storage/postgres.js.map +1 -0
  214. package/dist/server/storage/postgres.test.d.ts +1 -0
  215. package/dist/server/storage/postgres.test.js +182 -0
  216. package/dist/server/storage/postgres.test.js.map +1 -0
  217. package/dist/server/storage/sqlite.d.ts +33 -0
  218. package/dist/server/storage/sqlite.js +250 -0
  219. package/dist/server/storage/sqlite.js.map +1 -0
  220. package/dist/server/storage/sqlite.test.d.ts +1 -0
  221. package/dist/server/storage/sqlite.test.js +133 -0
  222. package/dist/server/storage/sqlite.test.js.map +1 -0
  223. package/dist/server/storage/types.d.ts +119 -0
  224. package/dist/server/storage/types.js +11 -0
  225. package/dist/server/storage/types.js.map +1 -0
  226. package/dist/server/templateHelper.d.ts +16 -0
  227. package/dist/server/templateHelper.js +11 -0
  228. package/dist/server/templateHelper.js.map +1 -0
  229. package/dist/server/templates.generated.d.ts +4 -0
  230. package/dist/server/templates.generated.js +47 -0
  231. package/dist/server/templates.generated.js.map +1 -0
  232. package/dist/server/tunnel-proxy-router.d.ts +7 -0
  233. package/dist/server/tunnel-proxy-router.js +110 -0
  234. package/dist/server/tunnel-proxy-router.js.map +1 -0
  235. package/dist/server/tunnel-proxy-router.test.d.ts +1 -0
  236. package/dist/server/tunnel-proxy-router.test.js +229 -0
  237. package/dist/server/tunnel-proxy-router.test.js.map +1 -0
  238. package/dist/server/viewsDevServer.d.ts +14 -0
  239. package/dist/server/viewsDevServer.js +45 -0
  240. package/dist/server/viewsDevServer.js.map +1 -0
  241. package/dist/test/utils.d.ts +127 -0
  242. package/dist/test/utils.js +247 -0
  243. package/dist/test/utils.js.map +1 -0
  244. package/dist/test/view.test.d.ts +1 -0
  245. package/dist/test/view.test.js +568 -0
  246. package/dist/test/view.test.js.map +1 -0
  247. package/dist/version.d.ts +1 -0
  248. package/dist/version.js +3 -0
  249. package/dist/version.js.map +1 -0
  250. package/dist/web/bridges/apps-sdk/adaptor.d.ts +54 -0
  251. package/dist/web/bridges/apps-sdk/adaptor.js +164 -0
  252. package/dist/web/bridges/apps-sdk/adaptor.js.map +1 -0
  253. package/dist/web/bridges/apps-sdk/bridge.d.ts +11 -0
  254. package/dist/web/bridges/apps-sdk/bridge.js +47 -0
  255. package/dist/web/bridges/apps-sdk/bridge.js.map +1 -0
  256. package/dist/web/bridges/apps-sdk/index.d.ts +5 -0
  257. package/dist/web/bridges/apps-sdk/index.js +5 -0
  258. package/dist/web/bridges/apps-sdk/index.js.map +1 -0
  259. package/dist/web/bridges/apps-sdk/types.d.ts +147 -0
  260. package/dist/web/bridges/apps-sdk/types.js +10 -0
  261. package/dist/web/bridges/apps-sdk/types.js.map +1 -0
  262. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.d.ts +13 -0
  263. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js +18 -0
  264. package/dist/web/bridges/apps-sdk/use-apps-sdk-context.js.map +1 -0
  265. package/dist/web/bridges/get-adaptor.d.ts +9 -0
  266. package/dist/web/bridges/get-adaptor.js +15 -0
  267. package/dist/web/bridges/get-adaptor.js.map +1 -0
  268. package/dist/web/bridges/index.d.ts +5 -0
  269. package/dist/web/bridges/index.js +6 -0
  270. package/dist/web/bridges/index.js.map +1 -0
  271. package/dist/web/bridges/mcp-app/adaptor.d.ts +81 -0
  272. package/dist/web/bridges/mcp-app/adaptor.js +346 -0
  273. package/dist/web/bridges/mcp-app/adaptor.js.map +1 -0
  274. package/dist/web/bridges/mcp-app/bridge.d.ts +28 -0
  275. package/dist/web/bridges/mcp-app/bridge.js +124 -0
  276. package/dist/web/bridges/mcp-app/bridge.js.map +1 -0
  277. package/dist/web/bridges/mcp-app/index.d.ts +4 -0
  278. package/dist/web/bridges/mcp-app/index.js +4 -0
  279. package/dist/web/bridges/mcp-app/index.js.map +1 -0
  280. package/dist/web/bridges/mcp-app/types.d.ts +8 -0
  281. package/dist/web/bridges/mcp-app/types.js +2 -0
  282. package/dist/web/bridges/mcp-app/types.js.map +1 -0
  283. package/dist/web/bridges/mcp-app/use-mcp-app-context.d.ts +19 -0
  284. package/dist/web/bridges/mcp-app/use-mcp-app-context.js +19 -0
  285. package/dist/web/bridges/mcp-app/use-mcp-app-context.js.map +1 -0
  286. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.d.ts +1 -0
  287. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js +26 -0
  288. package/dist/web/bridges/mcp-app/use-mcp-app-context.test.js.map +1 -0
  289. package/dist/web/bridges/mcp-app/view-tools.test.d.ts +1 -0
  290. package/dist/web/bridges/mcp-app/view-tools.test.js +144 -0
  291. package/dist/web/bridges/mcp-app/view-tools.test.js.map +1 -0
  292. package/dist/web/bridges/types.d.ts +243 -0
  293. package/dist/web/bridges/types.js +2 -0
  294. package/dist/web/bridges/types.js.map +1 -0
  295. package/dist/web/bridges/use-host-context.d.ts +7 -0
  296. package/dist/web/bridges/use-host-context.js +13 -0
  297. package/dist/web/bridges/use-host-context.js.map +1 -0
  298. package/dist/web/components/modal-provider.d.ts +4 -0
  299. package/dist/web/components/modal-provider.js +45 -0
  300. package/dist/web/components/modal-provider.js.map +1 -0
  301. package/dist/web/create-store.d.ts +29 -0
  302. package/dist/web/create-store.js +64 -0
  303. package/dist/web/create-store.js.map +1 -0
  304. package/dist/web/create-store.test.d.ts +1 -0
  305. package/dist/web/create-store.test.js +129 -0
  306. package/dist/web/create-store.test.js.map +1 -0
  307. package/dist/web/data-llm.d.ts +47 -0
  308. package/dist/web/data-llm.js +100 -0
  309. package/dist/web/data-llm.js.map +1 -0
  310. package/dist/web/data-llm.test.d.ts +1 -0
  311. package/dist/web/data-llm.test.js +142 -0
  312. package/dist/web/data-llm.test.js.map +1 -0
  313. package/dist/web/generate-helpers.d.ts +120 -0
  314. package/dist/web/generate-helpers.js +115 -0
  315. package/dist/web/generate-helpers.js.map +1 -0
  316. package/dist/web/generate-helpers.test-d.d.ts +1 -0
  317. package/dist/web/generate-helpers.test-d.js +211 -0
  318. package/dist/web/generate-helpers.test-d.js.map +1 -0
  319. package/dist/web/generate-helpers.test.d.ts +1 -0
  320. package/dist/web/generate-helpers.test.js +17 -0
  321. package/dist/web/generate-helpers.test.js.map +1 -0
  322. package/dist/web/helpers/state.d.ts +7 -0
  323. package/dist/web/helpers/state.js +45 -0
  324. package/dist/web/helpers/state.js.map +1 -0
  325. package/dist/web/helpers/state.test.d.ts +1 -0
  326. package/dist/web/helpers/state.test.js +53 -0
  327. package/dist/web/helpers/state.test.js.map +1 -0
  328. package/dist/web/hooks/index.d.ts +17 -0
  329. package/dist/web/hooks/index.js +18 -0
  330. package/dist/web/hooks/index.js.map +1 -0
  331. package/dist/web/hooks/test/utils.d.ts +20 -0
  332. package/dist/web/hooks/test/utils.js +75 -0
  333. package/dist/web/hooks/test/utils.js.map +1 -0
  334. package/dist/web/hooks/use-call-tool.d.ts +146 -0
  335. package/dist/web/hooks/use-call-tool.js +96 -0
  336. package/dist/web/hooks/use-call-tool.js.map +1 -0
  337. package/dist/web/hooks/use-call-tool.test-d.d.ts +1 -0
  338. package/dist/web/hooks/use-call-tool.test-d.js +104 -0
  339. package/dist/web/hooks/use-call-tool.test-d.js.map +1 -0
  340. package/dist/web/hooks/use-call-tool.test.d.ts +1 -0
  341. package/dist/web/hooks/use-call-tool.test.js +211 -0
  342. package/dist/web/hooks/use-call-tool.test.js.map +1 -0
  343. package/dist/web/hooks/use-display-mode.d.ts +24 -0
  344. package/dist/web/hooks/use-display-mode.js +29 -0
  345. package/dist/web/hooks/use-display-mode.js.map +1 -0
  346. package/dist/web/hooks/use-display-mode.test-d.d.ts +1 -0
  347. package/dist/web/hooks/use-display-mode.test-d.js +8 -0
  348. package/dist/web/hooks/use-display-mode.test-d.js.map +1 -0
  349. package/dist/web/hooks/use-display-mode.test.d.ts +1 -0
  350. package/dist/web/hooks/use-display-mode.test.js +41 -0
  351. package/dist/web/hooks/use-display-mode.test.js.map +1 -0
  352. package/dist/web/hooks/use-download.d.ts +5 -0
  353. package/dist/web/hooks/use-download.js +8 -0
  354. package/dist/web/hooks/use-download.js.map +1 -0
  355. package/dist/web/hooks/use-download.test.d.ts +1 -0
  356. package/dist/web/hooks/use-download.test.js +95 -0
  357. package/dist/web/hooks/use-download.test.js.map +1 -0
  358. package/dist/web/hooks/use-files.d.ts +39 -0
  359. package/dist/web/hooks/use-files.js +42 -0
  360. package/dist/web/hooks/use-files.js.map +1 -0
  361. package/dist/web/hooks/use-files.test.d.ts +1 -0
  362. package/dist/web/hooks/use-files.test.js +54 -0
  363. package/dist/web/hooks/use-files.test.js.map +1 -0
  364. package/dist/web/hooks/use-intent.d.ts +30 -0
  365. package/dist/web/hooks/use-intent.js +34 -0
  366. package/dist/web/hooks/use-intent.js.map +1 -0
  367. package/dist/web/hooks/use-intent.test.d.ts +1 -0
  368. package/dist/web/hooks/use-intent.test.js +85 -0
  369. package/dist/web/hooks/use-intent.test.js.map +1 -0
  370. package/dist/web/hooks/use-layout.d.ts +24 -0
  371. package/dist/web/hooks/use-layout.js +25 -0
  372. package/dist/web/hooks/use-layout.js.map +1 -0
  373. package/dist/web/hooks/use-layout.test.d.ts +1 -0
  374. package/dist/web/hooks/use-layout.test.js +96 -0
  375. package/dist/web/hooks/use-layout.test.js.map +1 -0
  376. package/dist/web/hooks/use-notify.d.ts +29 -0
  377. package/dist/web/hooks/use-notify.js +33 -0
  378. package/dist/web/hooks/use-notify.js.map +1 -0
  379. package/dist/web/hooks/use-notify.test.d.ts +1 -0
  380. package/dist/web/hooks/use-notify.test.js +105 -0
  381. package/dist/web/hooks/use-notify.test.js.map +1 -0
  382. package/dist/web/hooks/use-open-external.d.ts +20 -0
  383. package/dist/web/hooks/use-open-external.js +24 -0
  384. package/dist/web/hooks/use-open-external.js.map +1 -0
  385. package/dist/web/hooks/use-open-external.test.d.ts +1 -0
  386. package/dist/web/hooks/use-open-external.test.js +65 -0
  387. package/dist/web/hooks/use-open-external.test.js.map +1 -0
  388. package/dist/web/hooks/use-register-view-tool.d.ts +38 -0
  389. package/dist/web/hooks/use-register-view-tool.js +50 -0
  390. package/dist/web/hooks/use-register-view-tool.js.map +1 -0
  391. package/dist/web/hooks/use-request-close.d.ts +16 -0
  392. package/dist/web/hooks/use-request-close.js +21 -0
  393. package/dist/web/hooks/use-request-close.js.map +1 -0
  394. package/dist/web/hooks/use-request-close.test.d.ts +1 -0
  395. package/dist/web/hooks/use-request-close.test.js +52 -0
  396. package/dist/web/hooks/use-request-close.test.js.map +1 -0
  397. package/dist/web/hooks/use-request-modal.d.ts +24 -0
  398. package/dist/web/hooks/use-request-modal.js +31 -0
  399. package/dist/web/hooks/use-request-modal.js.map +1 -0
  400. package/dist/web/hooks/use-request-modal.test.d.ts +1 -0
  401. package/dist/web/hooks/use-request-modal.test.js +61 -0
  402. package/dist/web/hooks/use-request-modal.test.js.map +1 -0
  403. package/dist/web/hooks/use-request-size.d.ts +20 -0
  404. package/dist/web/hooks/use-request-size.js +24 -0
  405. package/dist/web/hooks/use-request-size.js.map +1 -0
  406. package/dist/web/hooks/use-request-size.test.d.ts +1 -0
  407. package/dist/web/hooks/use-request-size.test.js +65 -0
  408. package/dist/web/hooks/use-request-size.test.js.map +1 -0
  409. package/dist/web/hooks/use-send-follow-up-message.d.ts +19 -0
  410. package/dist/web/hooks/use-send-follow-up-message.js +25 -0
  411. package/dist/web/hooks/use-send-follow-up-message.js.map +1 -0
  412. package/dist/web/hooks/use-set-open-in-app-url.d.ts +18 -0
  413. package/dist/web/hooks/use-set-open-in-app-url.js +25 -0
  414. package/dist/web/hooks/use-set-open-in-app-url.js.map +1 -0
  415. package/dist/web/hooks/use-set-open-in-app-url.test.d.ts +1 -0
  416. package/dist/web/hooks/use-set-open-in-app-url.test.js +43 -0
  417. package/dist/web/hooks/use-set-open-in-app-url.test.js.map +1 -0
  418. package/dist/web/hooks/use-tool-info.d.ts +87 -0
  419. package/dist/web/hooks/use-tool-info.js +49 -0
  420. package/dist/web/hooks/use-tool-info.js.map +1 -0
  421. package/dist/web/hooks/use-tool-info.test-d.d.ts +1 -0
  422. package/dist/web/hooks/use-tool-info.test-d.js +91 -0
  423. package/dist/web/hooks/use-tool-info.test-d.js.map +1 -0
  424. package/dist/web/hooks/use-tool-info.test.d.ts +1 -0
  425. package/dist/web/hooks/use-tool-info.test.js +130 -0
  426. package/dist/web/hooks/use-tool-info.test.js.map +1 -0
  427. package/dist/web/hooks/use-user.d.ts +20 -0
  428. package/dist/web/hooks/use-user.js +37 -0
  429. package/dist/web/hooks/use-user.js.map +1 -0
  430. package/dist/web/hooks/use-user.test.d.ts +1 -0
  431. package/dist/web/hooks/use-user.test.js +122 -0
  432. package/dist/web/hooks/use-user.test.js.map +1 -0
  433. package/dist/web/hooks/use-view-state.d.ts +25 -0
  434. package/dist/web/hooks/use-view-state.js +32 -0
  435. package/dist/web/hooks/use-view-state.js.map +1 -0
  436. package/dist/web/hooks/use-view-state.test.d.ts +1 -0
  437. package/dist/web/hooks/use-view-state.test.js +177 -0
  438. package/dist/web/hooks/use-view-state.test.js.map +1 -0
  439. package/dist/web/index.d.ts +7 -0
  440. package/dist/web/index.js +8 -0
  441. package/dist/web/index.js.map +1 -0
  442. package/dist/web/mount-view.d.ts +20 -0
  443. package/dist/web/mount-view.js +46 -0
  444. package/dist/web/mount-view.js.map +1 -0
  445. package/dist/web/plugin/data-llm.test.d.ts +1 -0
  446. package/dist/web/plugin/data-llm.test.js +81 -0
  447. package/dist/web/plugin/data-llm.test.js.map +1 -0
  448. package/dist/web/plugin/plugin.d.ts +33 -0
  449. package/dist/web/plugin/plugin.js +189 -0
  450. package/dist/web/plugin/plugin.js.map +1 -0
  451. package/dist/web/plugin/scan-views.d.ts +16 -0
  452. package/dist/web/plugin/scan-views.js +88 -0
  453. package/dist/web/plugin/scan-views.js.map +1 -0
  454. package/dist/web/plugin/scan-views.test.d.ts +1 -0
  455. package/dist/web/plugin/scan-views.test.js +99 -0
  456. package/dist/web/plugin/scan-views.test.js.map +1 -0
  457. package/dist/web/plugin/transform-data-llm.d.ts +12 -0
  458. package/dist/web/plugin/transform-data-llm.js +96 -0
  459. package/dist/web/plugin/transform-data-llm.js.map +1 -0
  460. package/dist/web/plugin/transform-data-llm.test.d.ts +1 -0
  461. package/dist/web/plugin/transform-data-llm.test.js +81 -0
  462. package/dist/web/plugin/transform-data-llm.test.js.map +1 -0
  463. package/dist/web/plugin/validate-view.d.ts +1 -0
  464. package/dist/web/plugin/validate-view.js +9 -0
  465. package/dist/web/plugin/validate-view.js.map +1 -0
  466. package/dist/web/plugin/validate-view.test.d.ts +1 -0
  467. package/dist/web/plugin/validate-view.test.js +24 -0
  468. package/dist/web/plugin/validate-view.test.js.map +1 -0
  469. package/dist/web/proxy.d.ts +1 -0
  470. package/dist/web/proxy.js +52 -0
  471. package/dist/web/proxy.js.map +1 -0
  472. package/dist/web/types.d.ts +20 -0
  473. package/dist/web/types.js +2 -0
  474. package/dist/web/types.js.map +1 -0
  475. package/package.json +125 -0
  476. package/scripts/postinstall.mjs +45 -0
  477. package/tsconfig.base.json +36 -0
@@ -0,0 +1,62 @@
1
+ import type { AnalyticsEvent, LogEntry, StorageAdapter } from "./storage/types.js";
2
+ /**
3
+ * Mock demo seed (MD). Populates a {@link StorageAdapter} with a realistic,
4
+ * clearly-labelled spread of demo analytics so the observability Dashboard
5
+ * renders full and good-looking immediately — for demos and screenshots, with
6
+ * NO real traffic.
7
+ *
8
+ * Determinism is a hard requirement: given the same `seed` + the same base
9
+ * timestamp (`now`), {@link generateMockEvents} / {@link generateMockLogs}
10
+ * produce byte-identical output every run. There is NO `Math.random()` and NO
11
+ * `Date.now()` drift — the only randomness comes from the seeded
12
+ * {@link mulberry32} PRNG, and every timestamp is derived from the injected
13
+ * base. This keeps screenshots reproducible across runs and machines.
14
+ *
15
+ * This is opt-in only (wired to `enpilink dev --mock` / `ENPILINK_MOCK`); it is
16
+ * never invoked on a normal dev/prod run.
17
+ */
18
+ /**
19
+ * `mulberry32` — a tiny, fast, well-distributed 32-bit PRNG. Pure function of
20
+ * its seed: same seed → same sequence. Returns a generator producing floats in
21
+ * `[0, 1)`. Used for ALL "randomness" in the mock seed so output is fully
22
+ * deterministic.
23
+ */
24
+ export declare function mulberry32(seed: number): () => number;
25
+ /** Default seed for the demo dataset (arbitrary fixed constant). */
26
+ export declare const MOCK_SEED = 1592594996;
27
+ /** Options for {@link generateMockEvents} / {@link seedMockData}. */
28
+ export interface MockSeedOptions {
29
+ /**
30
+ * The base "now" timestamp (epoch ms). All events are placed BEFORE this so
31
+ * the dashboard's default trailing window shows them. Injected (never
32
+ * `Date.now()`) so output is deterministic.
33
+ */
34
+ now: number;
35
+ /** PRNG seed. Defaults to {@link MOCK_SEED}. */
36
+ seed?: number;
37
+ /** Number of `tool_call` events to generate. Defaults to 600. */
38
+ count?: number;
39
+ /** Time span the events are spread over, in ms. Defaults to ~10 days. */
40
+ spanMs?: number;
41
+ }
42
+ /**
43
+ * Build a deterministic, weighted, time-ordered list of demo `tool_call`
44
+ * events spanning `[now - spanMs, now]`. Latencies follow a per-tool
45
+ * distribution (with an occasional heavy tail), and errors are injected at each
46
+ * tool's configured rate. Pure function of `(now, seed, count, spanMs)`.
47
+ */
48
+ export declare function generateMockEvents(opts: MockSeedOptions): AnalyticsEvent[];
49
+ /**
50
+ * Build a deterministic list of demo log lines spread across the same window.
51
+ * Pure function of `(now, seed)`.
52
+ */
53
+ export declare function generateMockLogs(opts: MockSeedOptions): LogEntry[];
54
+ /**
55
+ * Seed `storage` with the deterministic demo dataset. Records all generated
56
+ * events + logs. Errors are swallowed per-write (a demo seed must never break
57
+ * server startup). Idempotency is NOT guaranteed — call once at startup.
58
+ */
59
+ export declare function seedMockData(storage: StorageAdapter, opts: MockSeedOptions): Promise<{
60
+ events: number;
61
+ logs: number;
62
+ }>;
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Mock demo seed (MD). Populates a {@link StorageAdapter} with a realistic,
3
+ * clearly-labelled spread of demo analytics so the observability Dashboard
4
+ * renders full and good-looking immediately — for demos and screenshots, with
5
+ * NO real traffic.
6
+ *
7
+ * Determinism is a hard requirement: given the same `seed` + the same base
8
+ * timestamp (`now`), {@link generateMockEvents} / {@link generateMockLogs}
9
+ * produce byte-identical output every run. There is NO `Math.random()` and NO
10
+ * `Date.now()` drift — the only randomness comes from the seeded
11
+ * {@link mulberry32} PRNG, and every timestamp is derived from the injected
12
+ * base. This keeps screenshots reproducible across runs and machines.
13
+ *
14
+ * This is opt-in only (wired to `enpilink dev --mock` / `ENPILINK_MOCK`); it is
15
+ * never invoked on a normal dev/prod run.
16
+ */
17
+ /**
18
+ * `mulberry32` — a tiny, fast, well-distributed 32-bit PRNG. Pure function of
19
+ * its seed: same seed → same sequence. Returns a generator producing floats in
20
+ * `[0, 1)`. Used for ALL "randomness" in the mock seed so output is fully
21
+ * deterministic.
22
+ */
23
+ export function mulberry32(seed) {
24
+ let a = seed >>> 0;
25
+ return () => {
26
+ a |= 0;
27
+ a = (a + 0x6d2b79f5) | 0;
28
+ let t = Math.imul(a ^ (a >>> 15), 1 | a);
29
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
30
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
31
+ };
32
+ }
33
+ /** Default seed for the demo dataset (arbitrary fixed constant). */
34
+ export const MOCK_SEED = 0x5eed1234;
35
+ /**
36
+ * A curated, realistic spread of demo tools — varied names, latencies (fast
37
+ * lookups → slow LLM/search calls), and a sensible error rate per tool. Fixed
38
+ * data, no randomness, so the shape of the dashboard is stable.
39
+ */
40
+ const MOCK_TOOLS = [
41
+ {
42
+ tool: "search_documents",
43
+ method: "tools/call",
44
+ baseMs: 180,
45
+ errorRate: 0.04,
46
+ weight: 9,
47
+ },
48
+ {
49
+ tool: "get_weather",
50
+ method: "tools/call",
51
+ baseMs: 90,
52
+ errorRate: 0.02,
53
+ weight: 7,
54
+ },
55
+ {
56
+ tool: "create_invoice",
57
+ method: "tools/call",
58
+ baseMs: 320,
59
+ errorRate: 0.08,
60
+ weight: 5,
61
+ },
62
+ {
63
+ tool: "send_email",
64
+ method: "tools/call",
65
+ baseMs: 240,
66
+ errorRate: 0.11,
67
+ weight: 4,
68
+ },
69
+ {
70
+ tool: "summarize_text",
71
+ method: "tools/call",
72
+ baseMs: 1100,
73
+ errorRate: 0.06,
74
+ weight: 6,
75
+ },
76
+ {
77
+ tool: "list_customers",
78
+ method: "tools/call",
79
+ baseMs: 60,
80
+ errorRate: 0.01,
81
+ weight: 8,
82
+ },
83
+ {
84
+ tool: "run_report",
85
+ method: "tools/call",
86
+ baseMs: 1700,
87
+ errorRate: 0.13,
88
+ weight: 3,
89
+ },
90
+ {
91
+ tool: "translate",
92
+ method: "tools/call",
93
+ baseMs: 420,
94
+ errorRate: 0.05,
95
+ weight: 5,
96
+ },
97
+ {
98
+ tool: undefined,
99
+ method: "tools/list",
100
+ baseMs: 8,
101
+ errorRate: 0.0,
102
+ weight: 6,
103
+ },
104
+ {
105
+ tool: undefined,
106
+ method: "initialize",
107
+ baseMs: 4,
108
+ errorRate: 0.0,
109
+ weight: 4,
110
+ },
111
+ ];
112
+ /** Demo log messages, paired with a level, for the live-log feed. */
113
+ const MOCK_LOGS = [
114
+ { level: "info", msg: "MCP server ready — accepting tool calls" },
115
+ { level: "info", msg: "search_documents: indexed 1,284 documents" },
116
+ { level: "debug", msg: "cache hit for get_weather(region=eu-west)" },
117
+ { level: "info", msg: "create_invoice: invoice #INV-4821 generated" },
118
+ {
119
+ level: "warning",
120
+ msg: "send_email: rate limit approaching (87% of quota)",
121
+ },
122
+ { level: "info", msg: "summarize_text: 4,096 tokens → 312 tokens" },
123
+ {
124
+ level: "error",
125
+ msg: "run_report: upstream timeout after 5000ms, retrying",
126
+ },
127
+ { level: "info", msg: "translate: en → ja (confidence 0.97)" },
128
+ { level: "debug", msg: "list_customers: page 3 of 12 served from replica" },
129
+ {
130
+ level: "warning",
131
+ msg: "create_invoice: tax rate fallback used for region=unknown",
132
+ },
133
+ { level: "error", msg: "send_email: SMTP 421 service not available" },
134
+ {
135
+ level: "info",
136
+ msg: "health check ok — storage=memory, analytics=on (demo)",
137
+ },
138
+ ];
139
+ const DEFAULT_COUNT = 600;
140
+ // Spread the demo events across ~10 days so the dashboard's default 7-day range
141
+ // (M9) looks full rather than sparse. Still deterministic (same seed+base →
142
+ // identical output) — only the time window widened, the count is unchanged.
143
+ const DEFAULT_SPAN_MS = 10 * 24 * 60 * 60 * 1000; // ~10 days
144
+ /**
145
+ * Build a deterministic, weighted, time-ordered list of demo `tool_call`
146
+ * events spanning `[now - spanMs, now]`. Latencies follow a per-tool
147
+ * distribution (with an occasional heavy tail), and errors are injected at each
148
+ * tool's configured rate. Pure function of `(now, seed, count, spanMs)`.
149
+ */
150
+ export function generateMockEvents(opts) {
151
+ const now = opts.now;
152
+ const seed = opts.seed ?? MOCK_SEED;
153
+ const count = opts.count ?? DEFAULT_COUNT;
154
+ const spanMs = opts.spanMs ?? DEFAULT_SPAN_MS;
155
+ const rand = mulberry32(seed);
156
+ // Weighted pick table for tools.
157
+ const totalWeight = MOCK_TOOLS.reduce((sum, t) => sum + t.weight, 0);
158
+ const events = [];
159
+ for (let i = 0; i < count; i++) {
160
+ // Pick a tool by weight.
161
+ let pick = rand() * totalWeight;
162
+ let chosen = MOCK_TOOLS[0];
163
+ for (const t of MOCK_TOOLS) {
164
+ pick -= t.weight;
165
+ if (pick <= 0) {
166
+ chosen = t;
167
+ break;
168
+ }
169
+ }
170
+ // Spread events across the window with a slight rising trend toward `now`
171
+ // (more recent activity), so the volume chart looks alive.
172
+ const trend = (i / count) ** 0.85;
173
+ const jitter = (rand() - 0.5) * (spanMs / count) * 8;
174
+ const ts = Math.round(now - spanMs + trend * spanMs + jitter);
175
+ const clampedTs = Math.min(now - 250, Math.max(now - spanMs, ts));
176
+ // Latency: baseline ± lognormal-ish spread, with a rare heavy tail.
177
+ const noise = 0.55 + rand() * 0.95; // 0.55x .. 1.5x
178
+ const tail = rand() < 0.05 ? 2.4 + rand() * 2.2 : 1; // ~5% slow tail
179
+ const ms = Math.max(1, Math.round(chosen.baseMs * noise * tail));
180
+ const ok = rand() >= chosen.errorRate;
181
+ events.push({
182
+ ts: clampedTs,
183
+ type: "tool_call",
184
+ tool: chosen.tool,
185
+ method: chosen.method,
186
+ ms,
187
+ ok,
188
+ error: ok ? undefined : "demo error: simulated upstream failure",
189
+ meta: { demo: true },
190
+ });
191
+ }
192
+ // Storage adapters return most-recent-first; keep the seeded array
193
+ // oldest-first for readability (recordEvent order doesn't matter).
194
+ events.sort((a, b) => a.ts - b.ts);
195
+ return events;
196
+ }
197
+ /**
198
+ * Build a deterministic list of demo log lines spread across the same window.
199
+ * Pure function of `(now, seed)`.
200
+ */
201
+ export function generateMockLogs(opts) {
202
+ const now = opts.now;
203
+ const seed = opts.seed ?? MOCK_SEED;
204
+ const spanMs = opts.spanMs ?? DEFAULT_SPAN_MS;
205
+ // Offset the seed so log jitter is independent of event jitter but still
206
+ // fully deterministic.
207
+ const rand = mulberry32((seed ^ 0x9e3779b9) >>> 0);
208
+ const logs = [];
209
+ const n = MOCK_LOGS.length;
210
+ for (let i = 0; i < n; i++) {
211
+ const entry = MOCK_LOGS[i];
212
+ const frac = (i + 1) / (n + 1);
213
+ const jitter = (rand() - 0.5) * (spanMs / n);
214
+ const ts = Math.round(now - spanMs + frac * spanMs + jitter);
215
+ logs.push({
216
+ ts: Math.min(now - 100, Math.max(now - spanMs, ts)),
217
+ level: entry.level,
218
+ msg: entry.msg,
219
+ data: { demo: true },
220
+ });
221
+ }
222
+ logs.sort((a, b) => a.ts - b.ts);
223
+ return logs;
224
+ }
225
+ /**
226
+ * Seed `storage` with the deterministic demo dataset. Records all generated
227
+ * events + logs. Errors are swallowed per-write (a demo seed must never break
228
+ * server startup). Idempotency is NOT guaranteed — call once at startup.
229
+ */
230
+ export async function seedMockData(storage, opts) {
231
+ const events = generateMockEvents(opts);
232
+ const logs = generateMockLogs(opts);
233
+ for (const e of events) {
234
+ try {
235
+ await storage.recordEvent(e);
236
+ }
237
+ catch {
238
+ // Demo seeding must never break startup.
239
+ }
240
+ }
241
+ for (const l of logs) {
242
+ try {
243
+ await storage.appendLog(l);
244
+ }
245
+ catch {
246
+ // Demo seeding must never break startup.
247
+ }
248
+ }
249
+ return { events: events.length, logs: logs.length };
250
+ }
251
+ //# sourceMappingURL=mock-seed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-seed.js","sourceRoot":"","sources":["../../src/server/mock-seed.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AnalyticsEvent,\n LogEntry,\n StorageAdapter,\n} from \"./storage/types.js\";\n\n/**\n * Mock demo seed (MD). Populates a {@link StorageAdapter} with a realistic,\n * clearly-labelled spread of demo analytics so the observability Dashboard\n * renders full and good-looking immediately — for demos and screenshots, with\n * NO real traffic.\n *\n * Determinism is a hard requirement: given the same `seed` + the same base\n * timestamp (`now`), {@link generateMockEvents} / {@link generateMockLogs}\n * produce byte-identical output every run. There is NO `Math.random()` and NO\n * `Date.now()` drift — the only randomness comes from the seeded\n * {@link mulberry32} PRNG, and every timestamp is derived from the injected\n * base. This keeps screenshots reproducible across runs and machines.\n *\n * This is opt-in only (wired to `enpilink dev --mock` / `ENPILINK_MOCK`); it is\n * never invoked on a normal dev/prod run.\n */\n\n/**\n * `mulberry32` — a tiny, fast, well-distributed 32-bit PRNG. Pure function of\n * its seed: same seed → same sequence. Returns a generator producing floats in\n * `[0, 1)`. Used for ALL \"randomness\" in the mock seed so output is fully\n * deterministic.\n */\nexport function mulberry32(seed: number): () => number {\n let a = seed >>> 0;\n return () => {\n a |= 0;\n a = (a + 0x6d2b79f5) | 0;\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n/** Default seed for the demo dataset (arbitrary fixed constant). */\nexport const MOCK_SEED = 0x5eed1234;\n\n/** A demo tool: name, MCP method, baseline latency, and a relative error rate. */\ninterface MockTool {\n tool: string;\n method: string;\n /** Baseline latency in ms (the distribution is built around this). */\n baseMs: number;\n /** Fraction of calls that error, in `[0, 1]`. */\n errorRate: number;\n /** Relative call-volume weight (higher → more calls). */\n weight: number;\n}\n\n/**\n * A curated, realistic spread of demo tools — varied names, latencies (fast\n * lookups → slow LLM/search calls), and a sensible error rate per tool. Fixed\n * data, no randomness, so the shape of the dashboard is stable.\n */\nconst MOCK_TOOLS: MockTool[] = [\n {\n tool: \"search_documents\",\n method: \"tools/call\",\n baseMs: 180,\n errorRate: 0.04,\n weight: 9,\n },\n {\n tool: \"get_weather\",\n method: \"tools/call\",\n baseMs: 90,\n errorRate: 0.02,\n weight: 7,\n },\n {\n tool: \"create_invoice\",\n method: \"tools/call\",\n baseMs: 320,\n errorRate: 0.08,\n weight: 5,\n },\n {\n tool: \"send_email\",\n method: \"tools/call\",\n baseMs: 240,\n errorRate: 0.11,\n weight: 4,\n },\n {\n tool: \"summarize_text\",\n method: \"tools/call\",\n baseMs: 1100,\n errorRate: 0.06,\n weight: 6,\n },\n {\n tool: \"list_customers\",\n method: \"tools/call\",\n baseMs: 60,\n errorRate: 0.01,\n weight: 8,\n },\n {\n tool: \"run_report\",\n method: \"tools/call\",\n baseMs: 1700,\n errorRate: 0.13,\n weight: 3,\n },\n {\n tool: \"translate\",\n method: \"tools/call\",\n baseMs: 420,\n errorRate: 0.05,\n weight: 5,\n },\n {\n tool: undefined as unknown as string,\n method: \"tools/list\",\n baseMs: 8,\n errorRate: 0.0,\n weight: 6,\n },\n {\n tool: undefined as unknown as string,\n method: \"initialize\",\n baseMs: 4,\n errorRate: 0.0,\n weight: 4,\n },\n];\n\n/** Demo log messages, paired with a level, for the live-log feed. */\nconst MOCK_LOGS: Array<{ level: LogEntry[\"level\"]; msg: string }> = [\n { level: \"info\", msg: \"MCP server ready — accepting tool calls\" },\n { level: \"info\", msg: \"search_documents: indexed 1,284 documents\" },\n { level: \"debug\", msg: \"cache hit for get_weather(region=eu-west)\" },\n { level: \"info\", msg: \"create_invoice: invoice #INV-4821 generated\" },\n {\n level: \"warning\",\n msg: \"send_email: rate limit approaching (87% of quota)\",\n },\n { level: \"info\", msg: \"summarize_text: 4,096 tokens → 312 tokens\" },\n {\n level: \"error\",\n msg: \"run_report: upstream timeout after 5000ms, retrying\",\n },\n { level: \"info\", msg: \"translate: en → ja (confidence 0.97)\" },\n { level: \"debug\", msg: \"list_customers: page 3 of 12 served from replica\" },\n {\n level: \"warning\",\n msg: \"create_invoice: tax rate fallback used for region=unknown\",\n },\n { level: \"error\", msg: \"send_email: SMTP 421 service not available\" },\n {\n level: \"info\",\n msg: \"health check ok — storage=memory, analytics=on (demo)\",\n },\n];\n\n/** Options for {@link generateMockEvents} / {@link seedMockData}. */\nexport interface MockSeedOptions {\n /**\n * The base \"now\" timestamp (epoch ms). All events are placed BEFORE this so\n * the dashboard's default trailing window shows them. Injected (never\n * `Date.now()`) so output is deterministic.\n */\n now: number;\n /** PRNG seed. Defaults to {@link MOCK_SEED}. */\n seed?: number;\n /** Number of `tool_call` events to generate. Defaults to 600. */\n count?: number;\n /** Time span the events are spread over, in ms. Defaults to ~10 days. */\n spanMs?: number;\n}\n\nconst DEFAULT_COUNT = 600;\n// Spread the demo events across ~10 days so the dashboard's default 7-day range\n// (M9) looks full rather than sparse. Still deterministic (same seed+base →\n// identical output) — only the time window widened, the count is unchanged.\nconst DEFAULT_SPAN_MS = 10 * 24 * 60 * 60 * 1000; // ~10 days\n\n/**\n * Build a deterministic, weighted, time-ordered list of demo `tool_call`\n * events spanning `[now - spanMs, now]`. Latencies follow a per-tool\n * distribution (with an occasional heavy tail), and errors are injected at each\n * tool's configured rate. Pure function of `(now, seed, count, spanMs)`.\n */\nexport function generateMockEvents(opts: MockSeedOptions): AnalyticsEvent[] {\n const now = opts.now;\n const seed = opts.seed ?? MOCK_SEED;\n const count = opts.count ?? DEFAULT_COUNT;\n const spanMs = opts.spanMs ?? DEFAULT_SPAN_MS;\n const rand = mulberry32(seed);\n\n // Weighted pick table for tools.\n const totalWeight = MOCK_TOOLS.reduce((sum, t) => sum + t.weight, 0);\n\n const events: AnalyticsEvent[] = [];\n for (let i = 0; i < count; i++) {\n // Pick a tool by weight.\n let pick = rand() * totalWeight;\n let chosen = MOCK_TOOLS[0] as MockTool;\n for (const t of MOCK_TOOLS) {\n pick -= t.weight;\n if (pick <= 0) {\n chosen = t;\n break;\n }\n }\n\n // Spread events across the window with a slight rising trend toward `now`\n // (more recent activity), so the volume chart looks alive.\n const trend = (i / count) ** 0.85;\n const jitter = (rand() - 0.5) * (spanMs / count) * 8;\n const ts = Math.round(now - spanMs + trend * spanMs + jitter);\n const clampedTs = Math.min(now - 250, Math.max(now - spanMs, ts));\n\n // Latency: baseline ± lognormal-ish spread, with a rare heavy tail.\n const noise = 0.55 + rand() * 0.95; // 0.55x .. 1.5x\n const tail = rand() < 0.05 ? 2.4 + rand() * 2.2 : 1; // ~5% slow tail\n const ms = Math.max(1, Math.round(chosen.baseMs * noise * tail));\n\n const ok = rand() >= chosen.errorRate;\n\n events.push({\n ts: clampedTs,\n type: \"tool_call\",\n tool: chosen.tool,\n method: chosen.method,\n ms,\n ok,\n error: ok ? undefined : \"demo error: simulated upstream failure\",\n meta: { demo: true },\n });\n }\n\n // Storage adapters return most-recent-first; keep the seeded array\n // oldest-first for readability (recordEvent order doesn't matter).\n events.sort((a, b) => a.ts - b.ts);\n return events;\n}\n\n/**\n * Build a deterministic list of demo log lines spread across the same window.\n * Pure function of `(now, seed)`.\n */\nexport function generateMockLogs(opts: MockSeedOptions): LogEntry[] {\n const now = opts.now;\n const seed = opts.seed ?? MOCK_SEED;\n const spanMs = opts.spanMs ?? DEFAULT_SPAN_MS;\n // Offset the seed so log jitter is independent of event jitter but still\n // fully deterministic.\n const rand = mulberry32((seed ^ 0x9e3779b9) >>> 0);\n\n const logs: LogEntry[] = [];\n const n = MOCK_LOGS.length;\n for (let i = 0; i < n; i++) {\n const entry = MOCK_LOGS[i] as { level: LogEntry[\"level\"]; msg: string };\n const frac = (i + 1) / (n + 1);\n const jitter = (rand() - 0.5) * (spanMs / n);\n const ts = Math.round(now - spanMs + frac * spanMs + jitter);\n logs.push({\n ts: Math.min(now - 100, Math.max(now - spanMs, ts)),\n level: entry.level,\n msg: entry.msg,\n data: { demo: true },\n });\n }\n logs.sort((a, b) => a.ts - b.ts);\n return logs;\n}\n\n/**\n * Seed `storage` with the deterministic demo dataset. Records all generated\n * events + logs. Errors are swallowed per-write (a demo seed must never break\n * server startup). Idempotency is NOT guaranteed — call once at startup.\n */\nexport async function seedMockData(\n storage: StorageAdapter,\n opts: MockSeedOptions,\n): Promise<{ events: number; logs: number }> {\n const events = generateMockEvents(opts);\n const logs = generateMockLogs(opts);\n\n for (const e of events) {\n try {\n await storage.recordEvent(e);\n } catch {\n // Demo seeding must never break startup.\n }\n }\n for (const l of logs) {\n try {\n await storage.appendLog(l);\n } catch {\n // Demo seeding must never break startup.\n }\n }\n return { events: events.length, logs: logs.length };\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,122 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { generateMockEvents, generateMockLogs, MOCK_SEED, mulberry32, seedMockData, } from "./mock-seed.js";
3
+ import { MemoryStorageAdapter } from "./storage/memory.js";
4
+ const BASE = 1_700_000_000_000; // fixed base timestamp
5
+ describe("mulberry32", () => {
6
+ it("is a pure function of its seed (same seed → same sequence)", () => {
7
+ const a = mulberry32(123);
8
+ const b = mulberry32(123);
9
+ const seqA = [a(), a(), a(), a(), a()];
10
+ const seqB = [b(), b(), b(), b(), b()];
11
+ expect(seqA).toEqual(seqB);
12
+ });
13
+ it("produces floats in [0, 1)", () => {
14
+ const r = mulberry32(MOCK_SEED);
15
+ for (let i = 0; i < 1000; i++) {
16
+ const v = r();
17
+ expect(v).toBeGreaterThanOrEqual(0);
18
+ expect(v).toBeLessThan(1);
19
+ }
20
+ });
21
+ it("differs for different seeds", () => {
22
+ expect(mulberry32(1)()).not.toEqual(mulberry32(2)());
23
+ });
24
+ });
25
+ describe("generateMockEvents (determinism)", () => {
26
+ it("same seed + base → byte-identical events", () => {
27
+ const a = generateMockEvents({ now: BASE });
28
+ const b = generateMockEvents({ now: BASE });
29
+ expect(JSON.stringify(a)).toEqual(JSON.stringify(b));
30
+ });
31
+ it("a different base shifts every timestamp by the same delta", () => {
32
+ const a = generateMockEvents({ now: BASE });
33
+ const b = generateMockEvents({ now: BASE + 10_000 });
34
+ expect(a).toHaveLength(b.length);
35
+ // Non-ts fields are identical (PRNG sequence unchanged); ts shifts by +10s.
36
+ for (let i = 0; i < a.length; i++) {
37
+ const ea = a[i];
38
+ const eb = b[i];
39
+ expect(eb?.ts).toBe((ea?.ts ?? 0) + 10_000);
40
+ expect(eb?.tool).toBe(ea?.tool);
41
+ expect(eb?.ms).toBe(ea?.ms);
42
+ expect(eb?.ok).toBe(ea?.ok);
43
+ }
44
+ });
45
+ it("a different seed produces a different dataset", () => {
46
+ const a = generateMockEvents({ now: BASE, seed: 1 });
47
+ const b = generateMockEvents({ now: BASE, seed: 2 });
48
+ expect(JSON.stringify(a)).not.toEqual(JSON.stringify(b));
49
+ });
50
+ it("honors count, keeps events within the window, oldest-first", () => {
51
+ const span = 6 * 60 * 60 * 1000;
52
+ const events = generateMockEvents({ now: BASE, count: 120, spanMs: span });
53
+ expect(events).toHaveLength(120);
54
+ for (let i = 1; i < events.length; i++) {
55
+ expect((events[i]?.ts ?? 0) >= (events[i - 1]?.ts ?? 0)).toBe(true);
56
+ }
57
+ for (const e of events) {
58
+ expect(e.ts).toBeGreaterThanOrEqual(BASE - span);
59
+ expect(e.ts).toBeLessThanOrEqual(BASE);
60
+ expect(e.ms).toBeGreaterThanOrEqual(1);
61
+ expect(e.type).toBe("tool_call");
62
+ }
63
+ });
64
+ it("spreads the default dataset across ~7–14 days (M9: fills the 7d default)", () => {
65
+ // The default window widened from 6h to ~10 days so the dashboard's
66
+ // default Last-7-days range looks full. Verify deterministically (fixed
67
+ // base) without hardcoding the exact span.
68
+ const events = generateMockEvents({ now: BASE });
69
+ expect(events).toHaveLength(600);
70
+ const oldest = events[0]?.ts ?? 0;
71
+ const newest = events.at(-1)?.ts ?? 0;
72
+ const spanDays = (newest - oldest) / (24 * 60 * 60 * 1000);
73
+ expect(spanDays).toBeGreaterThanOrEqual(7);
74
+ expect(spanDays).toBeLessThanOrEqual(14);
75
+ // All within [now-14d, now]; comfortably more than a day's worth before now.
76
+ for (const e of events) {
77
+ expect(e.ts).toBeLessThanOrEqual(BASE);
78
+ expect(e.ts).toBeGreaterThanOrEqual(BASE - 14 * 24 * 60 * 60 * 1000);
79
+ }
80
+ // A healthy chunk of events falls inside the default 7-day window.
81
+ const sevenDaysAgo = BASE - 7 * 24 * 60 * 60 * 1000;
82
+ const inLast7d = events.filter((e) => e.ts >= sevenDaysAgo).length;
83
+ expect(inLast7d).toBeGreaterThan(200);
84
+ });
85
+ it("default window is deterministic (same base → identical wide spread)", () => {
86
+ expect(JSON.stringify(generateMockEvents({ now: BASE }))).toEqual(JSON.stringify(generateMockEvents({ now: BASE })));
87
+ });
88
+ it("produces a sensible (non-zero, non-total) error spread", () => {
89
+ const events = generateMockEvents({ now: BASE, count: 600 });
90
+ const errors = events.filter((e) => e.ok === false).length;
91
+ expect(errors).toBeGreaterThan(0);
92
+ expect(errors).toBeLessThan(events.length);
93
+ });
94
+ });
95
+ describe("generateMockLogs (determinism)", () => {
96
+ it("same seed + base → identical logs", () => {
97
+ expect(JSON.stringify(generateMockLogs({ now: BASE }))).toEqual(JSON.stringify(generateMockLogs({ now: BASE })));
98
+ });
99
+ it("includes multiple severity levels", () => {
100
+ const levels = new Set(generateMockLogs({ now: BASE }).map((l) => l.level));
101
+ expect(levels.has("info")).toBe(true);
102
+ expect(levels.has("error")).toBe(true);
103
+ });
104
+ });
105
+ describe("seedMockData", () => {
106
+ it("writes the generated events + logs into storage deterministically", async () => {
107
+ const s1 = new MemoryStorageAdapter();
108
+ await s1.init();
109
+ const r1 = await seedMockData(s1, { now: BASE, count: 50 });
110
+ expect(r1.events).toBe(50);
111
+ const s2 = new MemoryStorageAdapter();
112
+ await s2.init();
113
+ await seedMockData(s2, { now: BASE, count: 50 });
114
+ const e1 = await s1.queryEvents({ since: 0, limit: 5000 });
115
+ const e2 = await s2.queryEvents({ since: 0, limit: 5000 });
116
+ expect(JSON.stringify(e1)).toEqual(JSON.stringify(e2));
117
+ expect(e1.length).toBe(50);
118
+ const l1 = await s1.queryLogs({ since: 0, limit: 5000 });
119
+ expect(l1.length).toBeGreaterThan(0);
120
+ });
121
+ });
122
+ //# sourceMappingURL=mock-seed.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock-seed.test.js","sourceRoot":"","sources":["../../src/server/mock-seed.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,YAAY,GACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,MAAM,IAAI,GAAG,iBAAiB,CAAC,CAAC,uBAAuB;AAEvD,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC1B,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC1B,MAAM,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;QAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YACd,MAAM,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YACpC,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,GAAG,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,CAAC,GAAG,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,GAAG,MAAM,EAAE,CAAC,CAAC;QACrD,MAAM,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACjC,4EAA4E;QAC5E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAChB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAChB,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;YAC5C,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YAChC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC5B,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,CAAC,GAAG,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,CAAC,GAAG,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAChC,MAAM,MAAM,GAAG,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3E,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtE,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,sBAAsB,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;YACjD,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;YACvC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YACvC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACnC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,oEAAoE;QACpE,wEAAwE;QACxE,2CAA2C;QAC3C,MAAM,MAAM,GAAG,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC3D,MAAM,CAAC,QAAQ,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,QAAQ,CAAC,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;QACzC,6EAA6E;QAC7E,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;YACvC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,sBAAsB,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QACvE,CAAC;QACD,mEAAmE;QACnE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QACpD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,YAAY,CAAC,CAAC,MAAM,CAAC;QACnE,MAAM,CAAC,QAAQ,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAC/D,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAClD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,MAAM,GAAG,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,MAAM,CAAC;QAC3D,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAC7D,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAChD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5E,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,EAAE,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACtC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,EAAE,GAAG,MAAM,YAAY,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5D,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAE3B,MAAM,EAAE,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACtC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,YAAY,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAEjD,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAE3B,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport {\n generateMockEvents,\n generateMockLogs,\n MOCK_SEED,\n mulberry32,\n seedMockData,\n} from \"./mock-seed.js\";\nimport { MemoryStorageAdapter } from \"./storage/memory.js\";\n\nconst BASE = 1_700_000_000_000; // fixed base timestamp\n\ndescribe(\"mulberry32\", () => {\n it(\"is a pure function of its seed (same seed → same sequence)\", () => {\n const a = mulberry32(123);\n const b = mulberry32(123);\n const seqA = [a(), a(), a(), a(), a()];\n const seqB = [b(), b(), b(), b(), b()];\n expect(seqA).toEqual(seqB);\n });\n\n it(\"produces floats in [0, 1)\", () => {\n const r = mulberry32(MOCK_SEED);\n for (let i = 0; i < 1000; i++) {\n const v = r();\n expect(v).toBeGreaterThanOrEqual(0);\n expect(v).toBeLessThan(1);\n }\n });\n\n it(\"differs for different seeds\", () => {\n expect(mulberry32(1)()).not.toEqual(mulberry32(2)());\n });\n});\n\ndescribe(\"generateMockEvents (determinism)\", () => {\n it(\"same seed + base → byte-identical events\", () => {\n const a = generateMockEvents({ now: BASE });\n const b = generateMockEvents({ now: BASE });\n expect(JSON.stringify(a)).toEqual(JSON.stringify(b));\n });\n\n it(\"a different base shifts every timestamp by the same delta\", () => {\n const a = generateMockEvents({ now: BASE });\n const b = generateMockEvents({ now: BASE + 10_000 });\n expect(a).toHaveLength(b.length);\n // Non-ts fields are identical (PRNG sequence unchanged); ts shifts by +10s.\n for (let i = 0; i < a.length; i++) {\n const ea = a[i];\n const eb = b[i];\n expect(eb?.ts).toBe((ea?.ts ?? 0) + 10_000);\n expect(eb?.tool).toBe(ea?.tool);\n expect(eb?.ms).toBe(ea?.ms);\n expect(eb?.ok).toBe(ea?.ok);\n }\n });\n\n it(\"a different seed produces a different dataset\", () => {\n const a = generateMockEvents({ now: BASE, seed: 1 });\n const b = generateMockEvents({ now: BASE, seed: 2 });\n expect(JSON.stringify(a)).not.toEqual(JSON.stringify(b));\n });\n\n it(\"honors count, keeps events within the window, oldest-first\", () => {\n const span = 6 * 60 * 60 * 1000;\n const events = generateMockEvents({ now: BASE, count: 120, spanMs: span });\n expect(events).toHaveLength(120);\n for (let i = 1; i < events.length; i++) {\n expect((events[i]?.ts ?? 0) >= (events[i - 1]?.ts ?? 0)).toBe(true);\n }\n for (const e of events) {\n expect(e.ts).toBeGreaterThanOrEqual(BASE - span);\n expect(e.ts).toBeLessThanOrEqual(BASE);\n expect(e.ms).toBeGreaterThanOrEqual(1);\n expect(e.type).toBe(\"tool_call\");\n }\n });\n\n it(\"spreads the default dataset across ~7–14 days (M9: fills the 7d default)\", () => {\n // The default window widened from 6h to ~10 days so the dashboard's\n // default Last-7-days range looks full. Verify deterministically (fixed\n // base) without hardcoding the exact span.\n const events = generateMockEvents({ now: BASE });\n expect(events).toHaveLength(600);\n const oldest = events[0]?.ts ?? 0;\n const newest = events.at(-1)?.ts ?? 0;\n const spanDays = (newest - oldest) / (24 * 60 * 60 * 1000);\n expect(spanDays).toBeGreaterThanOrEqual(7);\n expect(spanDays).toBeLessThanOrEqual(14);\n // All within [now-14d, now]; comfortably more than a day's worth before now.\n for (const e of events) {\n expect(e.ts).toBeLessThanOrEqual(BASE);\n expect(e.ts).toBeGreaterThanOrEqual(BASE - 14 * 24 * 60 * 60 * 1000);\n }\n // A healthy chunk of events falls inside the default 7-day window.\n const sevenDaysAgo = BASE - 7 * 24 * 60 * 60 * 1000;\n const inLast7d = events.filter((e) => e.ts >= sevenDaysAgo).length;\n expect(inLast7d).toBeGreaterThan(200);\n });\n\n it(\"default window is deterministic (same base → identical wide spread)\", () => {\n expect(JSON.stringify(generateMockEvents({ now: BASE }))).toEqual(\n JSON.stringify(generateMockEvents({ now: BASE })),\n );\n });\n\n it(\"produces a sensible (non-zero, non-total) error spread\", () => {\n const events = generateMockEvents({ now: BASE, count: 600 });\n const errors = events.filter((e) => e.ok === false).length;\n expect(errors).toBeGreaterThan(0);\n expect(errors).toBeLessThan(events.length);\n });\n});\n\ndescribe(\"generateMockLogs (determinism)\", () => {\n it(\"same seed + base → identical logs\", () => {\n expect(JSON.stringify(generateMockLogs({ now: BASE }))).toEqual(\n JSON.stringify(generateMockLogs({ now: BASE })),\n );\n });\n\n it(\"includes multiple severity levels\", () => {\n const levels = new Set(generateMockLogs({ now: BASE }).map((l) => l.level));\n expect(levels.has(\"info\")).toBe(true);\n expect(levels.has(\"error\")).toBe(true);\n });\n});\n\ndescribe(\"seedMockData\", () => {\n it(\"writes the generated events + logs into storage deterministically\", async () => {\n const s1 = new MemoryStorageAdapter();\n await s1.init();\n const r1 = await seedMockData(s1, { now: BASE, count: 50 });\n expect(r1.events).toBe(50);\n\n const s2 = new MemoryStorageAdapter();\n await s2.init();\n await seedMockData(s2, { now: BASE, count: 50 });\n\n const e1 = await s1.queryEvents({ since: 0, limit: 5000 });\n const e2 = await s2.queryEvents({ since: 0, limit: 5000 });\n expect(JSON.stringify(e1)).toEqual(JSON.stringify(e2));\n expect(e1.length).toBe(50);\n\n const l1 = await s1.queryLogs({ since: 0, limit: 5000 });\n expect(l1.length).toBeGreaterThan(0);\n });\n});\n"]}
@@ -0,0 +1,149 @@
1
+ import { type Router } from "express";
2
+ import type { AnalyticsEvent, StorageAdapter } from "./storage/types.js";
3
+ /**
4
+ * Observability read API (M3). Pure core — reads the SAME active
5
+ * {@link StorageAdapter} the analytics middleware + log sink write to, via
6
+ * {@link getActiveStorage}. It does NOT depend on `@enpilink/console`.
7
+ *
8
+ * Mounted dev-only (under the `NODE_ENV !== "production"` block in
9
+ * `express.ts`) at `/__enpilink/observability/`. The `/__enpilink/` prefix
10
+ * avoids colliding with user-defined routes; the dev-only mount keeps prod
11
+ * surface unchanged (prod admin is M5).
12
+ *
13
+ * Graceful when analytics is OFF: storage is read PER-REQUEST (it may be `null`
14
+ * when disabled or before the server applies middleware). When there is no
15
+ * active storage every route returns a 200 with `{ enabled: false }` / an empty
16
+ * payload — NEVER a 500. The storage may also change between requests, so we
17
+ * never cache it.
18
+ */
19
+ /** A single point on the calls-over-time series. */
20
+ export interface TimeBucket {
21
+ /** Bucket start, epoch ms (aligned to `bucketMs`). */
22
+ ts: number;
23
+ /** Total calls in the bucket. */
24
+ count: number;
25
+ /** Errored calls in the bucket. */
26
+ errors: number;
27
+ }
28
+ /** Per-tool (or per-method) aggregate row. */
29
+ export interface ToolStat {
30
+ /** Tool name, or the method name when there is no tool (non-`tools/call`). */
31
+ name: string;
32
+ /** Total calls. */
33
+ count: number;
34
+ /** Errored calls. */
35
+ errors: number;
36
+ /** Error rate in `[0, 1]`. */
37
+ errorRate: number;
38
+ /** Median latency (ms). */
39
+ p50: number;
40
+ /** 95th-percentile latency (ms). */
41
+ p95: number;
42
+ /** 99th-percentile latency (ms). */
43
+ p99: number;
44
+ /** Average latency (ms) over events with timing. */
45
+ avg: number;
46
+ }
47
+ /** Per-MCP-method aggregate row (e.g. `tools/call`, `tools/list`). */
48
+ export interface MethodStat {
49
+ /** MCP method name, or `"unknown"`. */
50
+ method: string;
51
+ /** Total calls. */
52
+ count: number;
53
+ /** Errored calls. */
54
+ errors: number;
55
+ }
56
+ /** A single bar of the latency histogram. */
57
+ export interface LatencyBucket {
58
+ /** Inclusive lower bound of the bucket (ms). */
59
+ from: number;
60
+ /** Exclusive upper bound of the bucket (ms), or `null` for the open top bin. */
61
+ to: number | null;
62
+ /** Number of events whose latency fell in this bucket. */
63
+ count: number;
64
+ }
65
+ /** The aggregate returned by `GET /summary` when analytics is enabled. */
66
+ export interface ObservabilitySummary {
67
+ enabled: true;
68
+ /** Window the summary was computed over (epoch ms). */
69
+ since: number;
70
+ /** Total events considered. */
71
+ total: number;
72
+ /** Errored events. */
73
+ errors: number;
74
+ /** Error rate in `[0, 1]`. */
75
+ errorRate: number;
76
+ /** Median latency across all events (ms). */
77
+ p50: number;
78
+ /** 95th-percentile latency across all events (ms). */
79
+ p95: number;
80
+ /** 99th-percentile latency across all events (ms). */
81
+ p99: number;
82
+ /** Average latency across all timed events (ms). */
83
+ avg: number;
84
+ /** Throughput: calls per minute over the window `[since, latest event]`. */
85
+ throughputPerMin: number;
86
+ /** Bucket width used for {@link callsOverTime} (ms). */
87
+ bucketMs: number;
88
+ /** Calls-over-time series, oldest bucket first. */
89
+ callsOverTime: TimeBucket[];
90
+ /** Top tools/methods by call count (descending). */
91
+ topTools: ToolStat[];
92
+ /** Slowest tools/methods by p95 latency (descending). Only timed tools. */
93
+ slowestTools: ToolStat[];
94
+ /** Calls grouped by MCP method (descending by count). */
95
+ byMethod: MethodStat[];
96
+ /** Latency distribution histogram (fixed buckets). */
97
+ latencyHistogram: LatencyBucket[];
98
+ }
99
+ /** The disabled/no-storage shape — a valid 200 payload, never a 500. */
100
+ export interface ObservabilityDisabled {
101
+ enabled: false;
102
+ total: 0;
103
+ errors: 0;
104
+ errorRate: 0;
105
+ p50: 0;
106
+ p95: 0;
107
+ p99: 0;
108
+ avg: 0;
109
+ throughputPerMin: 0;
110
+ bucketMs: number;
111
+ callsOverTime: [];
112
+ topTools: [];
113
+ slowestTools: [];
114
+ byMethod: [];
115
+ latencyHistogram: [];
116
+ }
117
+ /**
118
+ * Percentile of a numeric sample using nearest-rank (lower) interpolation.
119
+ * Returns `0` for an empty sample. `p` is in `[0, 1]`. Tolerates `ms === 0`
120
+ * (a zero-latency call is a real data point, not a missing one).
121
+ */
122
+ export declare function percentile(sorted: number[], p: number): number;
123
+ /** Options for {@link summarize}. */
124
+ export interface SummarizeOptions {
125
+ /** Lower bound used in the response (epoch ms). */
126
+ since: number;
127
+ /** Bucket width for the calls-over-time series (ms). Defaults to 60_000. */
128
+ bucketMs?: number;
129
+ /** Max tools in `topTools`. Defaults to 10. */
130
+ topLimit?: number;
131
+ }
132
+ /**
133
+ * Aggregate raw events into a {@link ObservabilitySummary}. Pure + deterministic
134
+ * (no clock, no I/O) so it is unit-testable with injected events. The storage
135
+ * adapter intentionally does NOT aggregate — all rollups happen here.
136
+ *
137
+ * - Latency percentiles only consider events with a numeric `ms` (including
138
+ * `ms === 0`); events without timing are excluded from p50/p95 but still
139
+ * counted toward totals + error rate.
140
+ * - `ok === false` (or a present `error`) counts as an error.
141
+ * - Tools group by `tool`, falling back to `method`, then `"unknown"`.
142
+ */
143
+ export declare function summarize(events: AnalyticsEvent[], opts: SummarizeOptions): ObservabilitySummary;
144
+ /**
145
+ * Build the observability read API router. All routes read storage
146
+ * per-request via {@link getActiveStorage} (overridable for tests) so the
147
+ * disabled / not-yet-installed path returns a 200 empty payload, never a 500.
148
+ */
149
+ export declare function createObservabilityRouter(getStorage?: () => StorageAdapter | null): Router;