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,250 @@
1
+ /** Default on-disk database path. Overridable via `ENPILINK_DB_PATH`. */
2
+ export const DEFAULT_DB_PATH = "./enpilink.db";
3
+ /**
4
+ * Embedded-SQLite {@link StorageAdapter}, backed by `better-sqlite3`.
5
+ *
6
+ * `better-sqlite3` was chosen over `node:sqlite` (experimental, warns on every
7
+ * load) and `@libsql/client` (async, remote-oriented, heavier): it is mature,
8
+ * synchronous (simple adapter code), and ships prebuilt binaries for both
9
+ * macOS-arm64 and linux-x64, so `pnpm install` succeeds without node-gyp.
10
+ *
11
+ * Tables: `events`, `logs`, `config`, `config_audit`. Config values are stored
12
+ * as opaque JSON — no special-casing of keys. The DB path is gitignored.
13
+ */
14
+ export class SqliteStorageAdapter {
15
+ path;
16
+ db = null;
17
+ stmts = null;
18
+ constructor(opts) {
19
+ this.path = opts?.path ?? DEFAULT_DB_PATH;
20
+ }
21
+ async init() {
22
+ if (this.db) {
23
+ return;
24
+ }
25
+ // Dynamic import keeps the native module out of the load path until a
26
+ // sqlite adapter is actually instantiated (memory-only users pay nothing).
27
+ const mod = await import("better-sqlite3");
28
+ const Database = (mod.default ??
29
+ mod);
30
+ const db = new Database(this.path);
31
+ db.pragma("journal_mode = WAL");
32
+ db.exec(SCHEMA);
33
+ this.db = db;
34
+ this.stmts = {
35
+ insertEvent: db.prepare("INSERT INTO events (ts, type, tool, method, ms, ok, error, meta) VALUES (@ts, @type, @tool, @method, @ms, @ok, @error, @meta)"),
36
+ insertLog: db.prepare("INSERT INTO logs (ts, level, msg, data) VALUES (@ts, @level, @msg, @data)"),
37
+ getConfig: db.prepare("SELECT value FROM config WHERE key = ?"),
38
+ upsertConfig: db.prepare("INSERT INTO config (key, value) VALUES (@key, @value) ON CONFLICT(key) DO UPDATE SET value = @value"),
39
+ insertAudit: db.prepare("INSERT INTO config_audit (ts, key, old_value, new_value, actor) VALUES (@ts, @key, @old_value, @new_value, @actor)"),
40
+ allConfig: db.prepare("SELECT key, value FROM config"),
41
+ };
42
+ }
43
+ require() {
44
+ if (!this.db || !this.stmts) {
45
+ throw new Error("SqliteStorageAdapter: call init() before use");
46
+ }
47
+ return { db: this.db, stmts: this.stmts };
48
+ }
49
+ async recordEvent(e) {
50
+ const { stmts } = this.require();
51
+ stmts.insertEvent.run({
52
+ ts: e.ts,
53
+ type: e.type,
54
+ tool: e.tool ?? null,
55
+ method: e.method ?? null,
56
+ ms: e.ms ?? null,
57
+ ok: e.ok === undefined ? null : e.ok ? 1 : 0,
58
+ error: e.error ?? null,
59
+ meta: e.meta === undefined ? null : JSON.stringify(e.meta),
60
+ });
61
+ }
62
+ async queryEvents(f = {}) {
63
+ const { db } = this.require();
64
+ const where = [];
65
+ const params = {};
66
+ if (f.since !== undefined) {
67
+ where.push("ts >= @since");
68
+ params.since = f.since;
69
+ }
70
+ if (f.type !== undefined) {
71
+ where.push("type = @type");
72
+ params.type = f.type;
73
+ }
74
+ if (f.tool !== undefined) {
75
+ where.push("tool = @tool");
76
+ params.tool = f.tool;
77
+ }
78
+ const clause = where.length ? `WHERE ${where.join(" AND ")}` : "";
79
+ const limit = limitClause(f.limit, params);
80
+ const rows = db
81
+ .prepare(`SELECT ts, type, tool, method, ms, ok, error, meta FROM events ${clause} ORDER BY id DESC ${limit}`)
82
+ .all(params);
83
+ return rows.map(rowToEvent);
84
+ }
85
+ async appendLog(l) {
86
+ const { stmts } = this.require();
87
+ stmts.insertLog.run({
88
+ ts: l.ts,
89
+ level: l.level,
90
+ msg: l.msg,
91
+ data: l.data === undefined ? null : JSON.stringify(l.data),
92
+ });
93
+ }
94
+ async queryLogs(f = {}) {
95
+ const { db } = this.require();
96
+ const where = [];
97
+ const params = {};
98
+ if (f.since !== undefined) {
99
+ where.push("ts >= @since");
100
+ params.since = f.since;
101
+ }
102
+ if (f.level !== undefined) {
103
+ where.push("level = @level");
104
+ params.level = f.level;
105
+ }
106
+ const clause = where.length ? `WHERE ${where.join(" AND ")}` : "";
107
+ const limit = limitClause(f.limit, params);
108
+ const rows = db
109
+ .prepare(`SELECT ts, level, msg, data FROM logs ${clause} ORDER BY id DESC ${limit}`)
110
+ .all(params);
111
+ return rows.map(rowToLog);
112
+ }
113
+ async getConfig(key) {
114
+ const { stmts } = this.require();
115
+ const row = stmts.getConfig.get(key);
116
+ return row === undefined ? undefined : JSON.parse(row.value);
117
+ }
118
+ async setConfig(key, value, actor) {
119
+ const { db, stmts } = this.require();
120
+ const serialized = JSON.stringify(value);
121
+ // Atomically read-old → write-new → write-audit.
122
+ const tx = db.transaction(() => {
123
+ const existing = stmts.getConfig.get(key);
124
+ stmts.upsertConfig.run({ key, value: serialized });
125
+ stmts.insertAudit.run({
126
+ ts: Date.now(),
127
+ key,
128
+ old_value: existing === undefined ? null : existing.value,
129
+ new_value: serialized,
130
+ actor: actor ?? "system",
131
+ });
132
+ });
133
+ tx();
134
+ }
135
+ async allConfig() {
136
+ const { stmts } = this.require();
137
+ const rows = stmts.allConfig.all();
138
+ const out = {};
139
+ for (const r of rows) {
140
+ out[r.key] = JSON.parse(r.value);
141
+ }
142
+ return out;
143
+ }
144
+ async getConfigAudit() {
145
+ return this.getAuditLog();
146
+ }
147
+ async close() {
148
+ if (this.db) {
149
+ this.db.close();
150
+ this.db = null;
151
+ this.stmts = null;
152
+ }
153
+ }
154
+ /** Audit trail of config writes (most recent first). Synchronous helper. */
155
+ getAuditLog() {
156
+ const { db } = this.require();
157
+ const rows = db
158
+ .prepare("SELECT ts, key, old_value, new_value, actor FROM config_audit ORDER BY id DESC")
159
+ .all();
160
+ return rows.map((r) => ({
161
+ ts: r.ts,
162
+ key: r.key,
163
+ oldValue: r.old_value === null ? undefined : JSON.parse(r.old_value),
164
+ newValue: JSON.parse(r.new_value),
165
+ actor: r.actor,
166
+ }));
167
+ }
168
+ }
169
+ function limitClause(limit, params) {
170
+ if (limit === undefined || limit < 0) {
171
+ return "";
172
+ }
173
+ params.limit = limit;
174
+ return "LIMIT @limit";
175
+ }
176
+ function rowToEvent(r) {
177
+ const e = { ts: r.ts, type: r.type };
178
+ if (r.tool !== null) {
179
+ e.tool = r.tool;
180
+ }
181
+ if (r.method !== null) {
182
+ e.method = r.method;
183
+ }
184
+ if (r.ms !== null) {
185
+ e.ms = r.ms;
186
+ }
187
+ if (r.ok !== null) {
188
+ e.ok = r.ok === 1;
189
+ }
190
+ if (r.error !== null) {
191
+ e.error = r.error;
192
+ }
193
+ if (r.meta !== null) {
194
+ e.meta = JSON.parse(r.meta);
195
+ }
196
+ return e;
197
+ }
198
+ function rowToLog(r) {
199
+ const l = {
200
+ ts: r.ts,
201
+ level: r.level,
202
+ msg: r.msg,
203
+ };
204
+ if (r.data !== null) {
205
+ l.data = JSON.parse(r.data);
206
+ }
207
+ return l;
208
+ }
209
+ const SCHEMA = `
210
+ CREATE TABLE IF NOT EXISTS events (
211
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
212
+ ts INTEGER NOT NULL,
213
+ type TEXT NOT NULL,
214
+ tool TEXT,
215
+ method TEXT,
216
+ ms INTEGER,
217
+ ok INTEGER,
218
+ error TEXT,
219
+ meta TEXT
220
+ );
221
+ CREATE INDEX IF NOT EXISTS idx_events_ts ON events (ts);
222
+ CREATE INDEX IF NOT EXISTS idx_events_type ON events (type);
223
+ CREATE INDEX IF NOT EXISTS idx_events_tool ON events (tool);
224
+
225
+ CREATE TABLE IF NOT EXISTS logs (
226
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
227
+ ts INTEGER NOT NULL,
228
+ level TEXT NOT NULL,
229
+ msg TEXT NOT NULL,
230
+ data TEXT
231
+ );
232
+ CREATE INDEX IF NOT EXISTS idx_logs_ts ON logs (ts);
233
+ CREATE INDEX IF NOT EXISTS idx_logs_level ON logs (level);
234
+
235
+ CREATE TABLE IF NOT EXISTS config (
236
+ key TEXT PRIMARY KEY,
237
+ value TEXT NOT NULL
238
+ );
239
+
240
+ CREATE TABLE IF NOT EXISTS config_audit (
241
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
242
+ ts INTEGER NOT NULL,
243
+ key TEXT NOT NULL,
244
+ old_value TEXT,
245
+ new_value TEXT NOT NULL,
246
+ actor TEXT NOT NULL
247
+ );
248
+ CREATE INDEX IF NOT EXISTS idx_audit_key ON config_audit (key);
249
+ `;
250
+ //# sourceMappingURL=sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../../src/server/storage/sqlite.ts"],"names":[],"mappings":"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","sourcesContent":["import type DatabaseConstructor from \"better-sqlite3\";\nimport type { Database, Statement } from \"better-sqlite3\";\nimport type {\n AnalyticsEvent,\n ConfigAuditEntry,\n EventQuery,\n LogEntry,\n LogQuery,\n StorageAdapter,\n StorageAdapterOptions,\n} from \"./types.js\";\n\n/** Default on-disk database path. Overridable via `ENPILINK_DB_PATH`. */\nexport const DEFAULT_DB_PATH = \"./enpilink.db\";\n\n/**\n * Embedded-SQLite {@link StorageAdapter}, backed by `better-sqlite3`.\n *\n * `better-sqlite3` was chosen over `node:sqlite` (experimental, warns on every\n * load) and `@libsql/client` (async, remote-oriented, heavier): it is mature,\n * synchronous (simple adapter code), and ships prebuilt binaries for both\n * macOS-arm64 and linux-x64, so `pnpm install` succeeds without node-gyp.\n *\n * Tables: `events`, `logs`, `config`, `config_audit`. Config values are stored\n * as opaque JSON — no special-casing of keys. The DB path is gitignored.\n */\nexport class SqliteStorageAdapter implements StorageAdapter {\n private readonly path: string;\n private db: Database | null = null;\n private stmts: {\n insertEvent: Statement;\n insertLog: Statement;\n getConfig: Statement;\n upsertConfig: Statement;\n insertAudit: Statement;\n allConfig: Statement;\n } | null = null;\n\n constructor(opts?: StorageAdapterOptions) {\n this.path = opts?.path ?? DEFAULT_DB_PATH;\n }\n\n async init(): Promise<void> {\n if (this.db) {\n return;\n }\n // Dynamic import keeps the native module out of the load path until a\n // sqlite adapter is actually instantiated (memory-only users pay nothing).\n const mod = await import(\"better-sqlite3\");\n const Database = (mod.default ??\n mod) as unknown as typeof DatabaseConstructor;\n const db = new Database(this.path);\n db.pragma(\"journal_mode = WAL\");\n db.exec(SCHEMA);\n this.db = db;\n this.stmts = {\n insertEvent: db.prepare(\n \"INSERT INTO events (ts, type, tool, method, ms, ok, error, meta) VALUES (@ts, @type, @tool, @method, @ms, @ok, @error, @meta)\",\n ),\n insertLog: db.prepare(\n \"INSERT INTO logs (ts, level, msg, data) VALUES (@ts, @level, @msg, @data)\",\n ),\n getConfig: db.prepare(\"SELECT value FROM config WHERE key = ?\"),\n upsertConfig: db.prepare(\n \"INSERT INTO config (key, value) VALUES (@key, @value) ON CONFLICT(key) DO UPDATE SET value = @value\",\n ),\n insertAudit: db.prepare(\n \"INSERT INTO config_audit (ts, key, old_value, new_value, actor) VALUES (@ts, @key, @old_value, @new_value, @actor)\",\n ),\n allConfig: db.prepare(\"SELECT key, value FROM config\"),\n };\n }\n\n private require() {\n if (!this.db || !this.stmts) {\n throw new Error(\"SqliteStorageAdapter: call init() before use\");\n }\n return { db: this.db, stmts: this.stmts };\n }\n\n async recordEvent(e: AnalyticsEvent): Promise<void> {\n const { stmts } = this.require();\n stmts.insertEvent.run({\n ts: e.ts,\n type: e.type,\n tool: e.tool ?? null,\n method: e.method ?? null,\n ms: e.ms ?? null,\n ok: e.ok === undefined ? null : e.ok ? 1 : 0,\n error: e.error ?? null,\n meta: e.meta === undefined ? null : JSON.stringify(e.meta),\n });\n }\n\n async queryEvents(f: EventQuery = {}): Promise<AnalyticsEvent[]> {\n const { db } = this.require();\n const where: string[] = [];\n const params: Record<string, unknown> = {};\n if (f.since !== undefined) {\n where.push(\"ts >= @since\");\n params.since = f.since;\n }\n if (f.type !== undefined) {\n where.push(\"type = @type\");\n params.type = f.type;\n }\n if (f.tool !== undefined) {\n where.push(\"tool = @tool\");\n params.tool = f.tool;\n }\n const clause = where.length ? `WHERE ${where.join(\" AND \")}` : \"\";\n const limit = limitClause(f.limit, params);\n const rows = db\n .prepare(\n `SELECT ts, type, tool, method, ms, ok, error, meta FROM events ${clause} ORDER BY id DESC ${limit}`,\n )\n .all(params) as EventRow[];\n return rows.map(rowToEvent);\n }\n\n async appendLog(l: LogEntry): Promise<void> {\n const { stmts } = this.require();\n stmts.insertLog.run({\n ts: l.ts,\n level: l.level,\n msg: l.msg,\n data: l.data === undefined ? null : JSON.stringify(l.data),\n });\n }\n\n async queryLogs(f: LogQuery = {}): Promise<LogEntry[]> {\n const { db } = this.require();\n const where: string[] = [];\n const params: Record<string, unknown> = {};\n if (f.since !== undefined) {\n where.push(\"ts >= @since\");\n params.since = f.since;\n }\n if (f.level !== undefined) {\n where.push(\"level = @level\");\n params.level = f.level;\n }\n const clause = where.length ? `WHERE ${where.join(\" AND \")}` : \"\";\n const limit = limitClause(f.limit, params);\n const rows = db\n .prepare(\n `SELECT ts, level, msg, data FROM logs ${clause} ORDER BY id DESC ${limit}`,\n )\n .all(params) as LogRow[];\n return rows.map(rowToLog);\n }\n\n async getConfig(key: string): Promise<unknown> {\n const { stmts } = this.require();\n const row = stmts.getConfig.get(key) as { value: string } | undefined;\n return row === undefined ? undefined : JSON.parse(row.value);\n }\n\n async setConfig(key: string, value: unknown, actor?: string): Promise<void> {\n const { db, stmts } = this.require();\n const serialized = JSON.stringify(value);\n // Atomically read-old → write-new → write-audit.\n const tx = db.transaction(() => {\n const existing = stmts.getConfig.get(key) as\n | { value: string }\n | undefined;\n stmts.upsertConfig.run({ key, value: serialized });\n stmts.insertAudit.run({\n ts: Date.now(),\n key,\n old_value: existing === undefined ? null : existing.value,\n new_value: serialized,\n actor: actor ?? \"system\",\n });\n });\n tx();\n }\n\n async allConfig(): Promise<Record<string, unknown>> {\n const { stmts } = this.require();\n const rows = stmts.allConfig.all() as { key: string; value: string }[];\n const out: Record<string, unknown> = {};\n for (const r of rows) {\n out[r.key] = JSON.parse(r.value);\n }\n return out;\n }\n\n async getConfigAudit(): Promise<ConfigAuditEntry[]> {\n return this.getAuditLog();\n }\n\n async close(): Promise<void> {\n if (this.db) {\n this.db.close();\n this.db = null;\n this.stmts = null;\n }\n }\n\n /** Audit trail of config writes (most recent first). Synchronous helper. */\n getAuditLog(): ConfigAuditEntry[] {\n const { db } = this.require();\n const rows = db\n .prepare(\n \"SELECT ts, key, old_value, new_value, actor FROM config_audit ORDER BY id DESC\",\n )\n .all() as AuditRow[];\n return rows.map((r) => ({\n ts: r.ts,\n key: r.key,\n oldValue: r.old_value === null ? undefined : JSON.parse(r.old_value),\n newValue: JSON.parse(r.new_value),\n actor: r.actor,\n }));\n }\n}\n\nfunction limitClause(\n limit: number | undefined,\n params: Record<string, unknown>,\n): string {\n if (limit === undefined || limit < 0) {\n return \"\";\n }\n params.limit = limit;\n return \"LIMIT @limit\";\n}\n\ninterface EventRow {\n ts: number;\n type: string;\n tool: string | null;\n method: string | null;\n ms: number | null;\n ok: number | null;\n error: string | null;\n meta: string | null;\n}\n\ninterface LogRow {\n ts: number;\n level: string;\n msg: string;\n data: string | null;\n}\n\ninterface AuditRow {\n ts: number;\n key: string;\n old_value: string | null;\n new_value: string;\n actor: string;\n}\n\nfunction rowToEvent(r: EventRow): AnalyticsEvent {\n const e: AnalyticsEvent = { ts: r.ts, type: r.type };\n if (r.tool !== null) {\n e.tool = r.tool;\n }\n if (r.method !== null) {\n e.method = r.method;\n }\n if (r.ms !== null) {\n e.ms = r.ms;\n }\n if (r.ok !== null) {\n e.ok = r.ok === 1;\n }\n if (r.error !== null) {\n e.error = r.error;\n }\n if (r.meta !== null) {\n e.meta = JSON.parse(r.meta);\n }\n return e;\n}\n\nfunction rowToLog(r: LogRow): LogEntry {\n const l: LogEntry = {\n ts: r.ts,\n level: r.level as LogEntry[\"level\"],\n msg: r.msg,\n };\n if (r.data !== null) {\n l.data = JSON.parse(r.data);\n }\n return l;\n}\n\nconst SCHEMA = `\nCREATE TABLE IF NOT EXISTS events (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n ts INTEGER NOT NULL,\n type TEXT NOT NULL,\n tool TEXT,\n method TEXT,\n ms INTEGER,\n ok INTEGER,\n error TEXT,\n meta TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_events_ts ON events (ts);\nCREATE INDEX IF NOT EXISTS idx_events_type ON events (type);\nCREATE INDEX IF NOT EXISTS idx_events_tool ON events (tool);\n\nCREATE TABLE IF NOT EXISTS logs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n ts INTEGER NOT NULL,\n level TEXT NOT NULL,\n msg TEXT NOT NULL,\n data TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_logs_ts ON logs (ts);\nCREATE INDEX IF NOT EXISTS idx_logs_level ON logs (level);\n\nCREATE TABLE IF NOT EXISTS config (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS config_audit (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n ts INTEGER NOT NULL,\n key TEXT NOT NULL,\n old_value TEXT,\n new_value TEXT NOT NULL,\n actor TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_audit_key ON config_audit (key);\n`;\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,133 @@
1
+ import { mkdtempSync, rmSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
+ import { SqliteStorageAdapter } from "./sqlite.js";
6
+ describe("SqliteStorageAdapter", () => {
7
+ let dir;
8
+ let dbPath;
9
+ let store;
10
+ beforeEach(async () => {
11
+ dir = mkdtempSync(join(tmpdir(), "enpilink-sqlite-"));
12
+ dbPath = join(dir, "test.db");
13
+ store = new SqliteStorageAdapter({ path: dbPath });
14
+ await store.init();
15
+ });
16
+ afterEach(async () => {
17
+ await store.close();
18
+ rmSync(dir, { recursive: true, force: true });
19
+ });
20
+ describe("events", () => {
21
+ it("records and queries events with since/tool/type/limit filters", async () => {
22
+ await store.recordEvent({
23
+ ts: 1,
24
+ type: "tool_call",
25
+ tool: "a",
26
+ ms: 5,
27
+ ok: true,
28
+ });
29
+ await store.recordEvent({
30
+ ts: 5,
31
+ type: "tool_call",
32
+ tool: "a",
33
+ ms: 9,
34
+ ok: false,
35
+ error: "boom",
36
+ });
37
+ await store.recordEvent({ ts: 10, type: "ping", tool: "b" });
38
+ const all = await store.queryEvents({});
39
+ expect(all.map((e) => e.ts)).toEqual([10, 5, 1]);
40
+ expect(await store.queryEvents({ since: 5 })).toHaveLength(2);
41
+ expect(await store.queryEvents({ tool: "a" })).toHaveLength(2);
42
+ expect(await store.queryEvents({ type: "ping" })).toHaveLength(1);
43
+ expect(await store.queryEvents({ limit: 1 })).toHaveLength(1);
44
+ const errored = (await store.queryEvents({ since: 5, tool: "a" }))[0];
45
+ expect(errored).toMatchObject({ ok: false, error: "boom", ms: 9 });
46
+ });
47
+ it("round-trips the meta object", async () => {
48
+ await store.recordEvent({
49
+ ts: 1,
50
+ type: "tool_call",
51
+ meta: { user: "x", nested: { n: 1 } },
52
+ });
53
+ const [e] = await store.queryEvents({});
54
+ expect(e?.meta).toEqual({ user: "x", nested: { n: 1 } });
55
+ });
56
+ });
57
+ describe("logs", () => {
58
+ it("appends and queries logs with level/limit/since", async () => {
59
+ await store.appendLog({ ts: 1, level: "info", msg: "one" });
60
+ await store.appendLog({
61
+ ts: 2,
62
+ level: "error",
63
+ msg: "two",
64
+ data: { code: 42 },
65
+ });
66
+ await store.appendLog({ ts: 3, level: "info", msg: "three" });
67
+ const all = await store.queryLogs({});
68
+ expect(all.map((l) => l.msg)).toEqual(["three", "two", "one"]);
69
+ expect(await store.queryLogs({ level: "error" })).toHaveLength(1);
70
+ expect(await store.queryLogs({ since: 2 })).toHaveLength(2);
71
+ expect(await store.queryLogs({ limit: 1 })).toHaveLength(1);
72
+ expect((await store.queryLogs({ level: "error" }))[0]?.data).toEqual({
73
+ code: 42,
74
+ });
75
+ });
76
+ });
77
+ describe("config + audit", () => {
78
+ it("get/set/all round-trips opaque values", async () => {
79
+ expect(await store.getConfig("missing")).toBeUndefined();
80
+ await store.setConfig("analytics.enabled", true);
81
+ await store.setConfig("retention", { days: 7 });
82
+ expect(await store.getConfig("analytics.enabled")).toBe(true);
83
+ expect(await store.getConfig("retention")).toEqual({ days: 7 });
84
+ expect(await store.allConfig()).toEqual({
85
+ "analytics.enabled": true,
86
+ retention: { days: 7 },
87
+ });
88
+ });
89
+ it("writes a config_audit row on setConfig with old → new + actor", async () => {
90
+ await store.setConfig("k", "v1");
91
+ await store.setConfig("k", "v2", "alice");
92
+ const audit = store.getAuditLog();
93
+ expect(audit).toHaveLength(2);
94
+ // Most recent first.
95
+ expect(audit[0]).toMatchObject({
96
+ key: "k",
97
+ oldValue: "v1",
98
+ newValue: "v2",
99
+ actor: "alice",
100
+ });
101
+ expect(audit[1]).toMatchObject({
102
+ key: "k",
103
+ oldValue: undefined,
104
+ newValue: "v1",
105
+ actor: "system",
106
+ });
107
+ });
108
+ });
109
+ describe("persistence", () => {
110
+ it("retains data across close + reopen on the same path", async () => {
111
+ await store.recordEvent({ ts: 1, type: "tool_call", tool: "persisted" });
112
+ await store.appendLog({ ts: 1, level: "warning", msg: "stays" });
113
+ await store.setConfig("flag", { on: true }, "bob");
114
+ await store.close();
115
+ const reopened = new SqliteStorageAdapter({ path: dbPath });
116
+ await reopened.init();
117
+ try {
118
+ const events = await reopened.queryEvents({});
119
+ expect(events).toHaveLength(1);
120
+ expect(events[0]?.tool).toBe("persisted");
121
+ const logs = await reopened.queryLogs({});
122
+ expect(logs[0]?.msg).toBe("stays");
123
+ expect(await reopened.getConfig("flag")).toEqual({ on: true });
124
+ expect(reopened.getAuditLog()).toHaveLength(1);
125
+ expect(reopened.getAuditLog()[0]).toMatchObject({ actor: "bob" });
126
+ }
127
+ finally {
128
+ await reopened.close();
129
+ }
130
+ });
131
+ });
132
+ });
133
+ //# sourceMappingURL=sqlite.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite.test.js","sourceRoot":"","sources":["../../../src/server/storage/sqlite.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdtempSync, rmSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { afterEach, beforeEach, describe, expect, it } from \"vitest\";\nimport { SqliteStorageAdapter } from \"./sqlite.js\";\n\ndescribe(\"SqliteStorageAdapter\", () => {\n let dir: string;\n let dbPath: string;\n let store: SqliteStorageAdapter;\n\n beforeEach(async () => {\n dir = mkdtempSync(join(tmpdir(), \"enpilink-sqlite-\"));\n dbPath = join(dir, \"test.db\");\n store = new SqliteStorageAdapter({ path: dbPath });\n await store.init();\n });\n\n afterEach(async () => {\n await store.close();\n rmSync(dir, { recursive: true, force: true });\n });\n\n describe(\"events\", () => {\n it(\"records and queries events with since/tool/type/limit filters\", async () => {\n await store.recordEvent({\n ts: 1,\n type: \"tool_call\",\n tool: \"a\",\n ms: 5,\n ok: true,\n });\n await store.recordEvent({\n ts: 5,\n type: \"tool_call\",\n tool: \"a\",\n ms: 9,\n ok: false,\n error: \"boom\",\n });\n await store.recordEvent({ ts: 10, type: \"ping\", tool: \"b\" });\n\n const all = await store.queryEvents({});\n expect(all.map((e) => e.ts)).toEqual([10, 5, 1]);\n expect(await store.queryEvents({ since: 5 })).toHaveLength(2);\n expect(await store.queryEvents({ tool: \"a\" })).toHaveLength(2);\n expect(await store.queryEvents({ type: \"ping\" })).toHaveLength(1);\n expect(await store.queryEvents({ limit: 1 })).toHaveLength(1);\n\n const errored = (await store.queryEvents({ since: 5, tool: \"a\" }))[0];\n expect(errored).toMatchObject({ ok: false, error: \"boom\", ms: 9 });\n });\n\n it(\"round-trips the meta object\", async () => {\n await store.recordEvent({\n ts: 1,\n type: \"tool_call\",\n meta: { user: \"x\", nested: { n: 1 } },\n });\n const [e] = await store.queryEvents({});\n expect(e?.meta).toEqual({ user: \"x\", nested: { n: 1 } });\n });\n });\n\n describe(\"logs\", () => {\n it(\"appends and queries logs with level/limit/since\", async () => {\n await store.appendLog({ ts: 1, level: \"info\", msg: \"one\" });\n await store.appendLog({\n ts: 2,\n level: \"error\",\n msg: \"two\",\n data: { code: 42 },\n });\n await store.appendLog({ ts: 3, level: \"info\", msg: \"three\" });\n\n const all = await store.queryLogs({});\n expect(all.map((l) => l.msg)).toEqual([\"three\", \"two\", \"one\"]);\n expect(await store.queryLogs({ level: \"error\" })).toHaveLength(1);\n expect(await store.queryLogs({ since: 2 })).toHaveLength(2);\n expect(await store.queryLogs({ limit: 1 })).toHaveLength(1);\n expect((await store.queryLogs({ level: \"error\" }))[0]?.data).toEqual({\n code: 42,\n });\n });\n });\n\n describe(\"config + audit\", () => {\n it(\"get/set/all round-trips opaque values\", async () => {\n expect(await store.getConfig(\"missing\")).toBeUndefined();\n await store.setConfig(\"analytics.enabled\", true);\n await store.setConfig(\"retention\", { days: 7 });\n expect(await store.getConfig(\"analytics.enabled\")).toBe(true);\n expect(await store.getConfig(\"retention\")).toEqual({ days: 7 });\n expect(await store.allConfig()).toEqual({\n \"analytics.enabled\": true,\n retention: { days: 7 },\n });\n });\n\n it(\"writes a config_audit row on setConfig with old → new + actor\", async () => {\n await store.setConfig(\"k\", \"v1\");\n await store.setConfig(\"k\", \"v2\", \"alice\");\n const audit = store.getAuditLog();\n expect(audit).toHaveLength(2);\n // Most recent first.\n expect(audit[0]).toMatchObject({\n key: \"k\",\n oldValue: \"v1\",\n newValue: \"v2\",\n actor: \"alice\",\n });\n expect(audit[1]).toMatchObject({\n key: \"k\",\n oldValue: undefined,\n newValue: \"v1\",\n actor: \"system\",\n });\n });\n });\n\n describe(\"persistence\", () => {\n it(\"retains data across close + reopen on the same path\", async () => {\n await store.recordEvent({ ts: 1, type: \"tool_call\", tool: \"persisted\" });\n await store.appendLog({ ts: 1, level: \"warning\", msg: \"stays\" });\n await store.setConfig(\"flag\", { on: true }, \"bob\");\n await store.close();\n\n const reopened = new SqliteStorageAdapter({ path: dbPath });\n await reopened.init();\n try {\n const events = await reopened.queryEvents({});\n expect(events).toHaveLength(1);\n expect(events[0]?.tool).toBe(\"persisted\");\n\n const logs = await reopened.queryLogs({});\n expect(logs[0]?.msg).toBe(\"stays\");\n\n expect(await reopened.getConfig(\"flag\")).toEqual({ on: true });\n expect(reopened.getAuditLog()).toHaveLength(1);\n expect(reopened.getAuditLog()[0]).toMatchObject({ actor: \"bob\" });\n } finally {\n await reopened.close();\n }\n });\n });\n});\n"]}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Storage layer types for enpilink's admin / observability / config plane.
3
+ *
4
+ * The {@link StorageAdapter} is the single pluggable persistence surface used by
5
+ * analytics (events), log capture (logs), and the config/admin layer (config +
6
+ * audit). Built-in adapters: `memory` (dev default, zero deps) and `sqlite`
7
+ * (prod default, embedded). Custom adapters register via
8
+ * `registerStorageAdapter`.
9
+ */
10
+ /**
11
+ * A single analytics event. Emitted (in M2) by the analytics middleware for
12
+ * each MCP request — most commonly a `tool_call`. `type` is open-ended so other
13
+ * event kinds can be recorded without a schema change.
14
+ */
15
+ export interface AnalyticsEvent {
16
+ /** Unix epoch milliseconds when the event occurred. */
17
+ ts: number;
18
+ /** Event kind. `"tool_call"` is the built-in, but any string is allowed. */
19
+ type: "tool_call" | string;
20
+ /** Tool name (for `tools/call`), from `params.name`. */
21
+ tool?: string;
22
+ /** MCP method, e.g. `"tools/call"`. */
23
+ method?: string;
24
+ /** Duration of the call in milliseconds. */
25
+ ms?: number;
26
+ /** Whether the call succeeded (false when the result was an error). */
27
+ ok?: boolean;
28
+ /** Error message, when the call failed. */
29
+ error?: string;
30
+ /** Arbitrary extra structured data. */
31
+ meta?: Record<string, unknown>;
32
+ }
33
+ /** A captured server log line. */
34
+ export interface LogEntry {
35
+ /** Unix epoch milliseconds. */
36
+ ts: number;
37
+ /** Log severity. */
38
+ level: "debug" | "info" | "warning" | "error";
39
+ /** The log message. */
40
+ msg: string;
41
+ /** Optional structured payload. */
42
+ data?: unknown;
43
+ }
44
+ /** Filter for {@link StorageAdapter.queryEvents}. */
45
+ export interface EventQuery {
46
+ /** Only events with `ts >= since` (epoch ms). */
47
+ since?: number;
48
+ /** Only events whose `type` matches. */
49
+ type?: string;
50
+ /** Only events whose `tool` matches. */
51
+ tool?: string;
52
+ /** Maximum number of events returned (most recent first). */
53
+ limit?: number;
54
+ }
55
+ /** Filter for {@link StorageAdapter.queryLogs}. */
56
+ export interface LogQuery {
57
+ /** Only logs with `ts >= since` (epoch ms). */
58
+ since?: number;
59
+ /** Only logs whose `level` matches. */
60
+ level?: string;
61
+ /** Maximum number of logs returned (most recent first). */
62
+ limit?: number;
63
+ }
64
+ /**
65
+ * Pluggable persistence interface backing the observability + config plane.
66
+ *
67
+ * Implementations MUST:
68
+ * - treat config values as opaque (no special-casing of keys/secrets);
69
+ * - write a `config_audit` entry on every {@link setConfig} call;
70
+ * - return query results most-recent-first.
71
+ */
72
+ export interface StorageAdapter {
73
+ /** Open connections / create schema. Safe to call once before use. */
74
+ init(): Promise<void>;
75
+ /** Record an analytics event. Must never throw into the caller's hot path. */
76
+ recordEvent(e: AnalyticsEvent): Promise<void>;
77
+ /** Query events, most recent first. */
78
+ queryEvents(f: EventQuery): Promise<AnalyticsEvent[]>;
79
+ /** Append a captured log line. */
80
+ appendLog(l: LogEntry): Promise<void>;
81
+ /** Query logs, most recent first. */
82
+ queryLogs(f: LogQuery): Promise<LogEntry[]>;
83
+ /** Read a single config value (or `undefined` if unset). */
84
+ getConfig(key: string): Promise<unknown>;
85
+ /** Write a config value AND append a `config_audit` row (old → new). */
86
+ setConfig(key: string, value: unknown, actor?: string): Promise<void>;
87
+ /** Read all config as a plain object. */
88
+ allConfig(): Promise<Record<string, unknown>>;
89
+ /**
90
+ * Read the config-change audit trail, most recent first. Surfaces the
91
+ * `config_audit` rows that {@link setConfig} writes, for the admin UI's
92
+ * change history.
93
+ */
94
+ getConfigAudit(): Promise<ConfigAuditEntry[]>;
95
+ /** Release resources / close connections. */
96
+ close(): Promise<void>;
97
+ }
98
+ /** A single config-change audit record. */
99
+ export interface ConfigAuditEntry {
100
+ /** Unix epoch milliseconds. */
101
+ ts: number;
102
+ /** Config key that changed. */
103
+ key: string;
104
+ /** Previous value (JSON-serializable), or `undefined` if newly set. */
105
+ oldValue: unknown;
106
+ /** New value (JSON-serializable). */
107
+ newValue: unknown;
108
+ /** Who made the change (defaults to `"system"`). */
109
+ actor: string;
110
+ }
111
+ /** Options passed to a storage adapter factory. */
112
+ export interface StorageAdapterOptions {
113
+ /** Ring-buffer capacity (memory) — max events/logs retained. */
114
+ cap?: number;
115
+ /** Database path (sqlite). */
116
+ path?: string;
117
+ }
118
+ /** Factory signature for {@link registerStorageAdapter}. */
119
+ export type StorageAdapterFactory = (opts?: StorageAdapterOptions) => StorageAdapter;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Storage layer types for enpilink's admin / observability / config plane.
3
+ *
4
+ * The {@link StorageAdapter} is the single pluggable persistence surface used by
5
+ * analytics (events), log capture (logs), and the config/admin layer (config +
6
+ * audit). Built-in adapters: `memory` (dev default, zero deps) and `sqlite`
7
+ * (prod default, embedded). Custom adapters register via
8
+ * `registerStorageAdapter`.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/server/storage/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG","sourcesContent":["/**\n * Storage layer types for enpilink's admin / observability / config plane.\n *\n * The {@link StorageAdapter} is the single pluggable persistence surface used by\n * analytics (events), log capture (logs), and the config/admin layer (config +\n * audit). Built-in adapters: `memory` (dev default, zero deps) and `sqlite`\n * (prod default, embedded). Custom adapters register via\n * `registerStorageAdapter`.\n */\n\n/**\n * A single analytics event. Emitted (in M2) by the analytics middleware for\n * each MCP request — most commonly a `tool_call`. `type` is open-ended so other\n * event kinds can be recorded without a schema change.\n */\nexport interface AnalyticsEvent {\n /** Unix epoch milliseconds when the event occurred. */\n ts: number;\n /** Event kind. `\"tool_call\"` is the built-in, but any string is allowed. */\n type: \"tool_call\" | string;\n /** Tool name (for `tools/call`), from `params.name`. */\n tool?: string;\n /** MCP method, e.g. `\"tools/call\"`. */\n method?: string;\n /** Duration of the call in milliseconds. */\n ms?: number;\n /** Whether the call succeeded (false when the result was an error). */\n ok?: boolean;\n /** Error message, when the call failed. */\n error?: string;\n /** Arbitrary extra structured data. */\n meta?: Record<string, unknown>;\n}\n\n/** A captured server log line. */\nexport interface LogEntry {\n /** Unix epoch milliseconds. */\n ts: number;\n /** Log severity. */\n level: \"debug\" | \"info\" | \"warning\" | \"error\";\n /** The log message. */\n msg: string;\n /** Optional structured payload. */\n data?: unknown;\n}\n\n/** Filter for {@link StorageAdapter.queryEvents}. */\nexport interface EventQuery {\n /** Only events with `ts >= since` (epoch ms). */\n since?: number;\n /** Only events whose `type` matches. */\n type?: string;\n /** Only events whose `tool` matches. */\n tool?: string;\n /** Maximum number of events returned (most recent first). */\n limit?: number;\n}\n\n/** Filter for {@link StorageAdapter.queryLogs}. */\nexport interface LogQuery {\n /** Only logs with `ts >= since` (epoch ms). */\n since?: number;\n /** Only logs whose `level` matches. */\n level?: string;\n /** Maximum number of logs returned (most recent first). */\n limit?: number;\n}\n\n/**\n * Pluggable persistence interface backing the observability + config plane.\n *\n * Implementations MUST:\n * - treat config values as opaque (no special-casing of keys/secrets);\n * - write a `config_audit` entry on every {@link setConfig} call;\n * - return query results most-recent-first.\n */\nexport interface StorageAdapter {\n /** Open connections / create schema. Safe to call once before use. */\n init(): Promise<void>;\n /** Record an analytics event. Must never throw into the caller's hot path. */\n recordEvent(e: AnalyticsEvent): Promise<void>;\n /** Query events, most recent first. */\n queryEvents(f: EventQuery): Promise<AnalyticsEvent[]>;\n /** Append a captured log line. */\n appendLog(l: LogEntry): Promise<void>;\n /** Query logs, most recent first. */\n queryLogs(f: LogQuery): Promise<LogEntry[]>;\n /** Read a single config value (or `undefined` if unset). */\n getConfig(key: string): Promise<unknown>;\n /** Write a config value AND append a `config_audit` row (old → new). */\n setConfig(key: string, value: unknown, actor?: string): Promise<void>;\n /** Read all config as a plain object. */\n allConfig(): Promise<Record<string, unknown>>;\n /**\n * Read the config-change audit trail, most recent first. Surfaces the\n * `config_audit` rows that {@link setConfig} writes, for the admin UI's\n * change history.\n */\n getConfigAudit(): Promise<ConfigAuditEntry[]>;\n /** Release resources / close connections. */\n close(): Promise<void>;\n}\n\n/** A single config-change audit record. */\nexport interface ConfigAuditEntry {\n /** Unix epoch milliseconds. */\n ts: number;\n /** Config key that changed. */\n key: string;\n /** Previous value (JSON-serializable), or `undefined` if newly set. */\n oldValue: unknown;\n /** New value (JSON-serializable). */\n newValue: unknown;\n /** Who made the change (defaults to `\"system\"`). */\n actor: string;\n}\n\n/** Options passed to a storage adapter factory. */\nexport interface StorageAdapterOptions {\n /** Ring-buffer capacity (memory) — max events/logs retained. */\n cap?: number;\n /** Database path (sqlite). */\n path?: string;\n}\n\n/** Factory signature for {@link registerStorageAdapter}. */\nexport type StorageAdapterFactory = (\n opts?: StorageAdapterOptions,\n) => StorageAdapter;\n"]}
@@ -0,0 +1,16 @@
1
+ import type { ViewHostType } from "./server.js";
2
+ declare class TemplateHelper {
3
+ renderProduction(data: {
4
+ hostType: ViewHostType;
5
+ serverUrl: string;
6
+ viewFile: string;
7
+ styleFile: string;
8
+ }): string;
9
+ renderDevelopment(data: {
10
+ hostType: ViewHostType;
11
+ serverUrl: string;
12
+ viewName: string;
13
+ }): string;
14
+ }
15
+ export declare const templateHelper: TemplateHelper;
16
+ export {};
@@ -0,0 +1,11 @@
1
+ import { developmentTemplate, productionTemplate, } from "./templates.generated.js";
2
+ class TemplateHelper {
3
+ renderProduction(data) {
4
+ return productionTemplate(data);
5
+ }
6
+ renderDevelopment(data) {
7
+ return developmentTemplate(data);
8
+ }
9
+ }
10
+ export const templateHelper = new TemplateHelper();
11
+ //# sourceMappingURL=templateHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templateHelper.js","sourceRoot":"","sources":["../../src/server/templateHelper.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAElC,MAAM,cAAc;IAClB,gBAAgB,CAAC,IAKhB;QACC,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,iBAAiB,CAAC,IAIjB;QACC,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,cAAc,EAAE,CAAC","sourcesContent":["import type { ViewHostType } from \"./server.js\";\nimport {\n developmentTemplate,\n productionTemplate,\n} from \"./templates.generated.js\";\n\nclass TemplateHelper {\n renderProduction(data: {\n hostType: ViewHostType;\n serverUrl: string;\n viewFile: string;\n styleFile: string;\n }): string {\n return productionTemplate(data);\n }\n\n renderDevelopment(data: {\n hostType: ViewHostType;\n serverUrl: string;\n viewName: string;\n }): string {\n return developmentTemplate(data);\n }\n}\n\nexport const templateHelper = new TemplateHelper();\n"]}
@@ -0,0 +1,4 @@
1
+ /** @type {HandlebarsTemplateDelegate} */
2
+ export const developmentTemplate: HandlebarsTemplateDelegate;
3
+ /** @type {HandlebarsTemplateDelegate} */
4
+ export const productionTemplate: HandlebarsTemplateDelegate;