opalserve 0.1.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/README.md +108 -115
  2. package/assets/logo.svg +51 -0
  3. package/dist/auth/api-keys.d.ts +7 -0
  4. package/dist/auth/api-keys.d.ts.map +1 -0
  5. package/dist/auth/api-keys.js +12 -0
  6. package/dist/auth/api-keys.js.map +1 -0
  7. package/dist/auth/index.d.ts +4 -0
  8. package/dist/auth/index.d.ts.map +1 -0
  9. package/dist/auth/index.js +4 -0
  10. package/dist/auth/index.js.map +1 -0
  11. package/dist/auth/middleware.d.ts +11 -0
  12. package/dist/auth/middleware.d.ts.map +1 -0
  13. package/dist/auth/middleware.js +46 -0
  14. package/dist/auth/middleware.js.map +1 -0
  15. package/dist/auth/passwords.d.ts +3 -0
  16. package/dist/auth/passwords.d.ts.map +1 -0
  17. package/dist/auth/passwords.js +33 -0
  18. package/dist/auth/passwords.js.map +1 -0
  19. package/dist/cli/commands/admin.d.ts +13 -0
  20. package/dist/cli/commands/admin.d.ts.map +1 -0
  21. package/dist/cli/commands/admin.js +261 -0
  22. package/dist/cli/commands/admin.js.map +1 -0
  23. package/dist/cli/commands/auth.d.ts +4 -0
  24. package/dist/cli/commands/auth.d.ts.map +1 -0
  25. package/dist/cli/commands/auth.js +77 -0
  26. package/dist/cli/commands/auth.js.map +1 -0
  27. package/dist/cli/commands/context.d.ts +5 -0
  28. package/dist/cli/commands/context.d.ts.map +1 -0
  29. package/dist/cli/commands/context.js +190 -0
  30. package/dist/cli/commands/context.js.map +1 -0
  31. package/dist/cli/commands/health.d.ts +4 -0
  32. package/dist/cli/commands/health.d.ts.map +1 -0
  33. package/dist/cli/commands/health.js +36 -0
  34. package/dist/cli/commands/health.js.map +1 -0
  35. package/dist/cli/commands/init.d.ts +2 -0
  36. package/dist/cli/commands/init.d.ts.map +1 -0
  37. package/dist/cli/commands/init.js +81 -0
  38. package/dist/cli/commands/init.js.map +1 -0
  39. package/dist/cli/commands/server.d.ts +10 -0
  40. package/dist/cli/commands/server.d.ts.map +1 -0
  41. package/dist/cli/commands/server.js +108 -0
  42. package/dist/cli/commands/server.js.map +1 -0
  43. package/dist/cli/commands/start.d.ts +6 -0
  44. package/dist/cli/commands/start.d.ts.map +1 -0
  45. package/dist/cli/commands/start.js +63 -0
  46. package/dist/cli/commands/start.js.map +1 -0
  47. package/dist/cli/commands/status.d.ts +2 -0
  48. package/dist/cli/commands/status.d.ts.map +1 -0
  49. package/dist/cli/commands/status.js +21 -0
  50. package/dist/cli/commands/status.js.map +1 -0
  51. package/dist/cli/commands/sync.d.ts +2 -0
  52. package/dist/cli/commands/sync.d.ts.map +1 -0
  53. package/dist/cli/commands/sync.js +58 -0
  54. package/dist/cli/commands/sync.js.map +1 -0
  55. package/dist/cli/commands/tools.d.ts +8 -0
  56. package/dist/cli/commands/tools.d.ts.map +1 -0
  57. package/dist/cli/commands/tools.js +28 -0
  58. package/dist/cli/commands/tools.js.map +1 -0
  59. package/dist/cli/index.d.ts +1 -1
  60. package/dist/cli/index.d.ts.map +1 -1
  61. package/dist/cli/index.js +156 -30
  62. package/dist/cli/index.js.map +1 -1
  63. package/dist/cli/ui/banner.d.ts +8 -0
  64. package/dist/cli/ui/banner.d.ts.map +1 -0
  65. package/dist/cli/ui/banner.js +54 -0
  66. package/dist/cli/ui/banner.js.map +1 -0
  67. package/dist/cli/ui/prompts.d.ts +11 -0
  68. package/dist/cli/ui/prompts.d.ts.map +1 -0
  69. package/dist/cli/ui/prompts.js +74 -0
  70. package/dist/cli/ui/prompts.js.map +1 -0
  71. package/dist/cli/ui/table.d.ts +5 -0
  72. package/dist/cli/ui/table.d.ts.map +1 -0
  73. package/dist/cli/ui/table.js +103 -0
  74. package/dist/cli/ui/table.js.map +1 -0
  75. package/dist/config/credentials.d.ts +10 -0
  76. package/dist/config/credentials.d.ts.map +1 -0
  77. package/dist/config/credentials.js +33 -0
  78. package/dist/config/credentials.js.map +1 -0
  79. package/dist/config/defaults.d.ts +5 -0
  80. package/dist/config/defaults.d.ts.map +1 -0
  81. package/dist/config/defaults.js +20 -0
  82. package/dist/config/defaults.js.map +1 -0
  83. package/dist/config/loader.d.ts +4 -0
  84. package/dist/config/loader.d.ts.map +1 -0
  85. package/dist/config/loader.js +57 -0
  86. package/dist/config/loader.js.map +1 -0
  87. package/dist/config/schema.d.ts +2 -0
  88. package/dist/config/schema.d.ts.map +1 -0
  89. package/dist/config/schema.js +2 -0
  90. package/dist/config/schema.js.map +1 -0
  91. package/dist/constants.d.ts +5 -0
  92. package/dist/constants.d.ts.map +1 -0
  93. package/dist/constants.js +5 -0
  94. package/dist/constants.js.map +1 -0
  95. package/dist/context/chunker.d.ts +2 -0
  96. package/dist/context/chunker.d.ts.map +1 -0
  97. package/dist/context/chunker.js +81 -0
  98. package/dist/context/chunker.js.map +1 -0
  99. package/dist/context/index.d.ts +26 -0
  100. package/dist/context/index.d.ts.map +1 -0
  101. package/dist/context/index.js +97 -0
  102. package/dist/context/index.js.map +1 -0
  103. package/dist/core/discovery.d.ts +17 -0
  104. package/dist/core/discovery.d.ts.map +1 -0
  105. package/dist/core/discovery.js +31 -0
  106. package/dist/core/discovery.js.map +1 -0
  107. package/dist/core/proxy.d.ts +14 -0
  108. package/dist/core/proxy.d.ts.map +1 -0
  109. package/dist/core/proxy.js +36 -0
  110. package/dist/core/proxy.js.map +1 -0
  111. package/dist/core/registry.d.ts +30 -31
  112. package/dist/core/registry.d.ts.map +1 -1
  113. package/dist/core/registry.js +92 -234
  114. package/dist/core/registry.js.map +1 -1
  115. package/dist/core/secrets.d.ts +4 -0
  116. package/dist/core/secrets.d.ts.map +1 -0
  117. package/dist/core/secrets.js +40 -0
  118. package/dist/core/secrets.js.map +1 -0
  119. package/dist/core/server-manager.d.ts +18 -0
  120. package/dist/core/server-manager.d.ts.map +1 -0
  121. package/dist/core/server-manager.js +120 -0
  122. package/dist/core/server-manager.js.map +1 -0
  123. package/dist/dashboard/assets/index-BNOtcUPs.js +257 -0
  124. package/dist/dashboard/assets/index-Duwp34GW.css +1 -0
  125. package/dist/dashboard/index.html +14 -0
  126. package/dist/index.d.ts +22 -12
  127. package/dist/index.d.ts.map +1 -1
  128. package/dist/index.js +31 -9
  129. package/dist/index.js.map +1 -1
  130. package/dist/integrations/github.d.ts +5 -0
  131. package/dist/integrations/github.d.ts.map +1 -0
  132. package/dist/integrations/github.js +63 -0
  133. package/dist/integrations/github.js.map +1 -0
  134. package/dist/integrations/slack.d.ts +21 -0
  135. package/dist/integrations/slack.d.ts.map +1 -0
  136. package/dist/integrations/slack.js +61 -0
  137. package/dist/integrations/slack.js.map +1 -0
  138. package/dist/monitoring/tracker.d.ts +31 -0
  139. package/dist/monitoring/tracker.d.ts.map +1 -0
  140. package/dist/monitoring/tracker.js +86 -0
  141. package/dist/monitoring/tracker.js.map +1 -0
  142. package/dist/server/app.d.ts +8 -0
  143. package/dist/server/app.d.ts.map +1 -0
  144. package/dist/server/app.js +81 -0
  145. package/dist/server/app.js.map +1 -0
  146. package/dist/server/mcp-gateway.d.ts +12 -0
  147. package/dist/server/mcp-gateway.d.ts.map +1 -0
  148. package/dist/server/mcp-gateway.js +91 -0
  149. package/dist/server/mcp-gateway.js.map +1 -0
  150. package/dist/server/routes/auth.d.ts +4 -0
  151. package/dist/server/routes/auth.d.ts.map +1 -0
  152. package/dist/server/routes/auth.js +117 -0
  153. package/dist/server/routes/auth.js.map +1 -0
  154. package/dist/server/routes/context.d.ts +4 -0
  155. package/dist/server/routes/context.d.ts.map +1 -0
  156. package/dist/server/routes/context.js +107 -0
  157. package/dist/server/routes/context.js.map +1 -0
  158. package/dist/server/routes/health.d.ts +4 -0
  159. package/dist/server/routes/health.d.ts.map +1 -0
  160. package/dist/server/routes/health.js +22 -0
  161. package/dist/server/routes/health.js.map +1 -0
  162. package/dist/server/routes/servers.d.ts +4 -0
  163. package/dist/server/routes/servers.d.ts.map +1 -0
  164. package/dist/server/routes/servers.js +47 -0
  165. package/dist/server/routes/servers.js.map +1 -0
  166. package/dist/server/routes/stats.d.ts +4 -0
  167. package/dist/server/routes/stats.d.ts.map +1 -0
  168. package/dist/server/routes/stats.js +97 -0
  169. package/dist/server/routes/stats.js.map +1 -0
  170. package/dist/server/routes/team-servers.d.ts +4 -0
  171. package/dist/server/routes/team-servers.d.ts.map +1 -0
  172. package/dist/server/routes/team-servers.js +108 -0
  173. package/dist/server/routes/team-servers.js.map +1 -0
  174. package/dist/server/routes/tools.d.ts +4 -0
  175. package/dist/server/routes/tools.d.ts.map +1 -0
  176. package/dist/server/routes/tools.js +44 -0
  177. package/dist/server/routes/tools.js.map +1 -0
  178. package/dist/server/routes/webhooks.d.ts +4 -0
  179. package/dist/server/routes/webhooks.d.ts.map +1 -0
  180. package/dist/server/routes/webhooks.js +77 -0
  181. package/dist/server/routes/webhooks.js.map +1 -0
  182. package/dist/storage/database.d.ts +48 -0
  183. package/dist/storage/database.d.ts.map +1 -0
  184. package/dist/storage/database.js +336 -0
  185. package/dist/storage/database.js.map +1 -0
  186. package/dist/storage/repositories/server-repo.d.ts +2 -0
  187. package/dist/storage/repositories/server-repo.d.ts.map +1 -0
  188. package/dist/storage/repositories/server-repo.js +3 -0
  189. package/dist/storage/repositories/server-repo.js.map +1 -0
  190. package/dist/storage/repositories/tool-repo.d.ts +2 -0
  191. package/dist/storage/repositories/tool-repo.d.ts.map +1 -0
  192. package/dist/storage/repositories/tool-repo.js +3 -0
  193. package/dist/storage/repositories/tool-repo.js.map +1 -0
  194. package/dist/types/index.d.ts +482 -587
  195. package/dist/types/index.d.ts.map +1 -1
  196. package/dist/types/index.js +52 -69
  197. package/dist/types/index.js.map +1 -1
  198. package/dist/utils/logger.d.ts +7 -0
  199. package/dist/utils/logger.d.ts.map +1 -0
  200. package/dist/utils/logger.js +23 -0
  201. package/dist/utils/logger.js.map +1 -0
  202. package/package.json +67 -56
  203. package/.env.example +0 -19
  204. package/config/servers.example.yaml +0 -67
  205. package/config/servers.yaml +0 -2
  206. package/dist/cli/discover.d.ts +0 -3
  207. package/dist/cli/discover.d.ts.map +0 -1
  208. package/dist/cli/discover.js +0 -160
  209. package/dist/cli/discover.js.map +0 -1
  210. package/dist/connectors/base.d.ts +0 -49
  211. package/dist/connectors/base.d.ts.map +0 -1
  212. package/dist/connectors/base.js +0 -45
  213. package/dist/connectors/base.js.map +0 -1
  214. package/dist/connectors/custom.d.ts +0 -19
  215. package/dist/connectors/custom.d.ts.map +0 -1
  216. package/dist/connectors/custom.js +0 -129
  217. package/dist/connectors/custom.js.map +0 -1
  218. package/dist/connectors/github.d.ts +0 -18
  219. package/dist/connectors/github.d.ts.map +0 -1
  220. package/dist/connectors/github.js +0 -188
  221. package/dist/connectors/github.js.map +0 -1
  222. package/dist/connectors/google-drive.d.ts +0 -18
  223. package/dist/connectors/google-drive.d.ts.map +0 -1
  224. package/dist/connectors/google-drive.js +0 -209
  225. package/dist/connectors/google-drive.js.map +0 -1
  226. package/dist/connectors/index.d.ts +0 -11
  227. package/dist/connectors/index.d.ts.map +0 -1
  228. package/dist/connectors/index.js +0 -76
  229. package/dist/connectors/index.js.map +0 -1
  230. package/dist/connectors/postgres.d.ts +0 -18
  231. package/dist/connectors/postgres.d.ts.map +0 -1
  232. package/dist/connectors/postgres.js +0 -140
  233. package/dist/connectors/postgres.js.map +0 -1
  234. package/dist/connectors/slack.d.ts +0 -18
  235. package/dist/connectors/slack.d.ts.map +0 -1
  236. package/dist/connectors/slack.js +0 -181
  237. package/dist/connectors/slack.js.map +0 -1
  238. package/dist/core/auth.d.ts +0 -26
  239. package/dist/core/auth.d.ts.map +0 -1
  240. package/dist/core/auth.js +0 -81
  241. package/dist/core/auth.js.map +0 -1
  242. package/dist/core/tokenizer.d.ts +0 -16
  243. package/dist/core/tokenizer.d.ts.map +0 -1
  244. package/dist/core/tokenizer.js +0 -29
  245. package/dist/core/tokenizer.js.map +0 -1
  246. package/dist/governance/audit.d.ts +0 -27
  247. package/dist/governance/audit.d.ts.map +0 -1
  248. package/dist/governance/audit.js +0 -149
  249. package/dist/governance/audit.js.map +0 -1
  250. package/dist/governance/index.d.ts +0 -5
  251. package/dist/governance/index.d.ts.map +0 -1
  252. package/dist/governance/index.js +0 -5
  253. package/dist/governance/index.js.map +0 -1
  254. package/dist/governance/policy.d.ts +0 -20
  255. package/dist/governance/policy.d.ts.map +0 -1
  256. package/dist/governance/policy.js +0 -162
  257. package/dist/governance/policy.js.map +0 -1
  258. package/dist/governance/rate-limiter.d.ts +0 -20
  259. package/dist/governance/rate-limiter.d.ts.map +0 -1
  260. package/dist/governance/rate-limiter.js +0 -73
  261. package/dist/governance/rate-limiter.js.map +0 -1
  262. package/dist/governance/types.d.ts +0 -246
  263. package/dist/governance/types.d.ts.map +0 -1
  264. package/dist/governance/types.js +0 -72
  265. package/dist/governance/types.js.map +0 -1
  266. package/dist/identity/access-control.d.ts +0 -15
  267. package/dist/identity/access-control.d.ts.map +0 -1
  268. package/dist/identity/access-control.js +0 -81
  269. package/dist/identity/access-control.js.map +0 -1
  270. package/dist/identity/index.d.ts +0 -4
  271. package/dist/identity/index.d.ts.map +0 -1
  272. package/dist/identity/index.js +0 -4
  273. package/dist/identity/index.js.map +0 -1
  274. package/dist/identity/manager.d.ts +0 -29
  275. package/dist/identity/manager.d.ts.map +0 -1
  276. package/dist/identity/manager.js +0 -167
  277. package/dist/identity/manager.js.map +0 -1
  278. package/dist/identity/types.d.ts +0 -237
  279. package/dist/identity/types.d.ts.map +0 -1
  280. package/dist/identity/types.js +0 -80
  281. package/dist/identity/types.js.map +0 -1
  282. package/dist/registry/server.d.ts +0 -14
  283. package/dist/registry/server.d.ts.map +0 -1
  284. package/dist/registry/server.js +0 -177
  285. package/dist/registry/server.js.map +0 -1
  286. package/dist/utils/config.d.ts +0 -29
  287. package/dist/utils/config.d.ts.map +0 -1
  288. package/dist/utils/config.js +0 -47
  289. package/dist/utils/config.js.map +0 -1
  290. package/dist/utils/index.d.ts +0 -7
  291. package/dist/utils/index.d.ts.map +0 -1
  292. package/dist/utils/index.js +0 -44
  293. package/dist/utils/index.js.map +0 -1
  294. package/dist/workflow/engine.d.ts +0 -18
  295. package/dist/workflow/engine.d.ts.map +0 -1
  296. package/dist/workflow/engine.js +0 -155
  297. package/dist/workflow/engine.js.map +0 -1
  298. package/dist/workflow/index.d.ts +0 -4
  299. package/dist/workflow/index.d.ts.map +0 -1
  300. package/dist/workflow/index.js +0 -4
  301. package/dist/workflow/index.js.map +0 -1
  302. package/dist/workflow/templates.d.ts +0 -4
  303. package/dist/workflow/templates.d.ts.map +0 -1
  304. package/dist/workflow/templates.js +0 -218
  305. package/dist/workflow/templates.js.map +0 -1
  306. package/dist/workflow/types.d.ts +0 -255
  307. package/dist/workflow/types.d.ts.map +0 -1
  308. package/dist/workflow/types.js +0 -48
  309. package/dist/workflow/types.js.map +0 -1
  310. package/eslint.config.js +0 -25
@@ -0,0 +1,108 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { McpServerConfigSchema } from '../../types/index.js';
3
+ import { createAuthMiddleware } from '../../auth/middleware.js';
4
+ export function registerTeamServerRoutes(app, registry) {
5
+ const db = registry.getDatabase();
6
+ const requireAuth = createAuthMiddleware(db);
7
+ // --- List Team Servers ---
8
+ app.get('/api/v1/team/servers', { preHandler: requireAuth }, async (request, reply) => {
9
+ if (!request.user) {
10
+ return reply.status(401).send({ ok: false, error: 'Not authenticated' });
11
+ }
12
+ // Find user's team
13
+ const membership = db.get('SELECT team_id, role FROM team_members WHERE user_id = ?', [request.user.id]);
14
+ if (!membership) {
15
+ return reply.send({ ok: true, data: [] });
16
+ }
17
+ const servers = db.all('SELECT id, name, config_json, enabled, created_by, created_at, updated_at FROM team_servers WHERE team_id = ? ORDER BY name', [membership.team_id]);
18
+ const data = servers.map(s => ({
19
+ id: s.id,
20
+ name: s.name,
21
+ config: JSON.parse(s.config_json),
22
+ enabled: s.enabled === 1,
23
+ createdBy: s.created_by,
24
+ createdAt: s.created_at,
25
+ updatedAt: s.updated_at,
26
+ }));
27
+ return reply.send({ ok: true, data });
28
+ });
29
+ // --- Add Team Server (admin only) ---
30
+ app.post('/api/v1/team/servers', { preHandler: requireAuth }, async (request, reply) => {
31
+ if (!request.user) {
32
+ return reply.status(401).send({ ok: false, error: 'Not authenticated' });
33
+ }
34
+ const membership = db.get('SELECT team_id, role FROM team_members WHERE user_id = ?', [request.user.id]);
35
+ if (!membership || membership.role !== 'admin') {
36
+ return reply.status(403).send({ ok: false, error: 'Admin access required' });
37
+ }
38
+ const parsed = McpServerConfigSchema.safeParse(request.body);
39
+ if (!parsed.success) {
40
+ return reply.status(400).send({
41
+ ok: false,
42
+ error: 'Invalid server configuration',
43
+ details: parsed.error.flatten(),
44
+ });
45
+ }
46
+ const now = new Date().toISOString();
47
+ const id = randomUUID();
48
+ try {
49
+ db.run('INSERT INTO team_servers (id, team_id, name, config_json, created_by, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)', [id, membership.team_id, parsed.data.name, JSON.stringify(parsed.data), request.user.id, now, now]);
50
+ }
51
+ catch (error) {
52
+ const message = error instanceof Error ? error.message : String(error);
53
+ if (message.includes('UNIQUE')) {
54
+ return reply.status(409).send({ ok: false, error: `Server "${parsed.data.name}" already exists in this team` });
55
+ }
56
+ return reply.status(500).send({ ok: false, error: message });
57
+ }
58
+ return reply.status(201).send({
59
+ ok: true,
60
+ data: {
61
+ id,
62
+ name: parsed.data.name,
63
+ config: parsed.data,
64
+ enabled: true,
65
+ createdBy: request.user.id,
66
+ createdAt: now,
67
+ updatedAt: now,
68
+ },
69
+ });
70
+ });
71
+ // --- Remove Team Server (admin only) ---
72
+ app.delete('/api/v1/team/servers/:name', { preHandler: requireAuth }, async (request, reply) => {
73
+ if (!request.user) {
74
+ return reply.status(401).send({ ok: false, error: 'Not authenticated' });
75
+ }
76
+ const membership = db.get('SELECT team_id, role FROM team_members WHERE user_id = ?', [request.user.id]);
77
+ if (!membership || membership.role !== 'admin') {
78
+ return reply.status(403).send({ ok: false, error: 'Admin access required' });
79
+ }
80
+ const { name } = request.params;
81
+ const existing = db.get('SELECT id FROM team_servers WHERE team_id = ? AND name = ?', [membership.team_id, name]);
82
+ if (!existing) {
83
+ return reply.status(404).send({ ok: false, error: `Server "${name}" not found` });
84
+ }
85
+ db.run('DELETE FROM team_servers WHERE team_id = ? AND name = ?', [membership.team_id, name]);
86
+ return reply.send({ ok: true });
87
+ });
88
+ // --- Sync Team Servers ---
89
+ app.get('/api/v1/team/servers/sync', { preHandler: requireAuth }, async (request, reply) => {
90
+ if (!request.user) {
91
+ return reply.status(401).send({ ok: false, error: 'Not authenticated' });
92
+ }
93
+ const membership = db.get('SELECT team_id, role FROM team_members WHERE user_id = ?', [request.user.id]);
94
+ if (!membership) {
95
+ return reply.send({ ok: true, data: { servers: [], teamId: null } });
96
+ }
97
+ const servers = db.all('SELECT name, config_json, enabled FROM team_servers WHERE team_id = ? AND enabled = 1 ORDER BY name', [membership.team_id]);
98
+ const configs = servers.map(s => JSON.parse(s.config_json));
99
+ return reply.send({
100
+ ok: true,
101
+ data: {
102
+ teamId: membership.team_id,
103
+ servers: configs,
104
+ },
105
+ });
106
+ });
107
+ }
108
+ //# sourceMappingURL=team-servers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-servers.js","sourceRoot":"","sources":["../../../src/server/routes/team-servers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { OpalServeRegistry } from '../../core/registry.js';
3
+ export declare function registerToolRoutes(app: FastifyInstance, registry: OpalServeRegistry): void;
4
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/server/routes/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAkD1F"}
@@ -0,0 +1,44 @@
1
+ export function registerToolRoutes(app, registry) {
2
+ app.get('/api/v1/tools', async (request, reply) => {
3
+ const { server } = request.query;
4
+ const serverFilter = server ? server.split(',') : undefined;
5
+ const tools = registry.listTools(serverFilter);
6
+ return reply.send({ ok: true, data: tools });
7
+ });
8
+ app.get('/api/v1/tools/search', async (request, reply) => {
9
+ const { q, limit, server } = request.query;
10
+ if (!q) {
11
+ return reply.status(400).send({ ok: false, error: 'Query parameter "q" is required' });
12
+ }
13
+ const serverFilter = server ? server.split(',') : undefined;
14
+ const results = registry.searchTools(q, {
15
+ limit: limit ? parseInt(limit, 10) : undefined,
16
+ serverFilter,
17
+ });
18
+ return reply.send({ ok: true, data: results });
19
+ });
20
+ app.get('/api/v1/tools/:id', async (request, reply) => {
21
+ const { id } = request.params;
22
+ // Tool IDs contain colons, so decode the URL param
23
+ const toolId = decodeURIComponent(id);
24
+ const tool = registry.discovery.getById(toolId);
25
+ if (!tool) {
26
+ return reply.status(404).send({ ok: false, error: `Tool "${toolId}" not found` });
27
+ }
28
+ return reply.send({ ok: true, data: tool });
29
+ });
30
+ app.post('/api/v1/tools/:id/call', async (request, reply) => {
31
+ const { id } = request.params;
32
+ const toolId = decodeURIComponent(id);
33
+ const args = request.body || {};
34
+ try {
35
+ const result = await registry.callTool(toolId, args);
36
+ return reply.send({ ok: true, data: result });
37
+ }
38
+ catch (error) {
39
+ const message = error instanceof Error ? error.message : String(error);
40
+ return reply.status(500).send({ ok: false, error: message });
41
+ }
42
+ });
43
+ }
44
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/server/routes/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { OpalServeRegistry } from '../../core/registry.js';
3
+ export declare function registerWebhookRoutes(app: FastifyInstance, _registry: OpalServeRegistry): void;
4
+ //# sourceMappingURL=webhooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../../src/server/routes/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAKhE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,eAAe,EAAE,SAAS,EAAE,iBAAiB,GAAG,IAAI,CA6D9F"}
@@ -0,0 +1,77 @@
1
+ import { createLogger } from '../../utils/logger.js';
2
+ const log = createLogger('webhooks');
3
+ export function registerWebhookRoutes(app, _registry) {
4
+ // --- GitHub Webhook ---
5
+ app.post('/api/v1/webhooks/github', async (request, reply) => {
6
+ const event = request.headers['x-github-event'];
7
+ const delivery = request.headers['x-github-delivery'];
8
+ log.info({ event, delivery }, 'Received GitHub webhook');
9
+ try {
10
+ await handleGitHubWebhook(event ?? 'unknown', request.body);
11
+ return reply.send({ ok: true });
12
+ }
13
+ catch (error) {
14
+ const message = error instanceof Error ? error.message : String(error);
15
+ log.error({ error: message }, 'GitHub webhook error');
16
+ return reply.status(500).send({ ok: false, error: message });
17
+ }
18
+ });
19
+ // --- Slack Event Subscription ---
20
+ app.post('/api/v1/slack/events', async (request, reply) => {
21
+ const body = request.body;
22
+ // Slack URL verification challenge
23
+ if (body.type === 'url_verification') {
24
+ return reply.send({ challenge: body.challenge });
25
+ }
26
+ log.info({ type: body.type }, 'Received Slack event');
27
+ try {
28
+ await handleSlackEvent(body);
29
+ return reply.send({ ok: true });
30
+ }
31
+ catch (error) {
32
+ const message = error instanceof Error ? error.message : String(error);
33
+ log.error({ error: message }, 'Slack event error');
34
+ return reply.status(500).send({ ok: false, error: message });
35
+ }
36
+ });
37
+ // --- Slack Slash Command ---
38
+ app.post('/api/v1/slack/commands', async (request, reply) => {
39
+ const body = request.body;
40
+ const command = body.command;
41
+ const text = body.text;
42
+ const userId = body.user_id;
43
+ log.info({ command, text, userId }, 'Received Slack slash command');
44
+ try {
45
+ const response = await handleSlackCommand(command ?? '', text ?? '', userId ?? '');
46
+ return reply.send(response);
47
+ }
48
+ catch (error) {
49
+ const message = error instanceof Error ? error.message : String(error);
50
+ log.error({ error: message }, 'Slack command error');
51
+ return reply.send({
52
+ response_type: 'ephemeral',
53
+ text: `Error: ${message}`,
54
+ });
55
+ }
56
+ });
57
+ }
58
+ async function handleGitHubWebhook(event, payload) {
59
+ log.debug({ event, action: payload.action }, 'Processing GitHub webhook');
60
+ // Extensible: consumers can add handlers for specific events
61
+ // e.g., push, pull_request, issues, etc.
62
+ }
63
+ async function handleSlackEvent(payload) {
64
+ const event = payload.event;
65
+ log.debug({ eventType: event?.type }, 'Processing Slack event');
66
+ // Extensible: consumers can add handlers for specific event types
67
+ // e.g., message, app_mention, reaction_added, etc.
68
+ }
69
+ async function handleSlackCommand(command, text, _userId) {
70
+ log.debug({ command, text }, 'Processing Slack command');
71
+ // Default response for unhandled commands
72
+ return {
73
+ response_type: 'ephemeral',
74
+ text: `Received command: ${command} ${text}`,
75
+ };
76
+ }
77
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../../src/server/routes/webhooks.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;AAErC,MAAM,UAAU,qBAAqB,CAAC,GAAoB,EAAE,SAA4B;IAEtF,yBAAyB;IACzB,GAAG,CAAC,IAAI,CAAC,yBAAyB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC3D,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAuB,CAAC;QACtE,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAuB,CAAC;QAE5E,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,yBAAyB,CAAC,CAAC;QAEzD,IAAI,CAAC;YACH,MAAM,mBAAmB,CAAC,KAAK,IAAI,SAAS,EAAE,OAAO,CAAC,IAA+B,CAAC,CAAC;YACvF,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,sBAAsB,CAAC,CAAC;YACtD,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,mCAAmC;IACnC,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACxD,MAAM,IAAI,GAAG,OAAO,CAAC,IAA+B,CAAC;QAErD,mCAAmC;QACnC,IAAI,IAAI,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YACrC,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QACnD,CAAC;QAED,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,sBAAsB,CAAC,CAAC;QAEtD,IAAI,CAAC;YACH,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC7B,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,mBAAmB,CAAC,CAAC;YACnD,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,8BAA8B;IAC9B,GAAG,CAAC,IAAI,CAAC,wBAAwB,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC1D,MAAM,IAAI,GAAG,OAAO,CAAC,IAA+B,CAAC;QACrD,MAAM,OAAO,GAAG,IAAI,CAAC,OAA6B,CAAC;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,IAA0B,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,OAA6B,CAAC;QAElD,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,8BAA8B,CAAC,CAAC;QAEpE,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,OAAO,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;YACnF,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,qBAAqB,CAAC,CAAC;YACrD,OAAO,KAAK,CAAC,IAAI,CAAC;gBAChB,aAAa,EAAE,WAAW;gBAC1B,IAAI,EAAE,UAAU,OAAO,EAAE;aAC1B,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,mBAAmB,CAAC,KAAa,EAAE,OAAgC;IAChF,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,2BAA2B,CAAC,CAAC;IAC1E,6DAA6D;IAC7D,yCAAyC;AAC3C,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,OAAgC;IAC9D,MAAM,KAAK,GAAG,OAAO,CAAC,KAA4C,CAAC;IACnE,GAAG,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,wBAAwB,CAAC,CAAC;IAChE,kEAAkE;IAClE,mDAAmD;AACrD,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,OAAe,EAAE,IAAY,EAAE,OAAe;IAC9E,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,0BAA0B,CAAC,CAAC;IAEzD,0CAA0C;IAC1C,OAAO;QACL,aAAa,EAAE,WAAW;QAC1B,IAAI,EAAE,qBAAqB,OAAO,IAAI,IAAI,EAAE;KAC7C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,48 @@
1
+ import type { Database as SqlJsDatabase } from 'sql.js';
2
+ import type { McpServerConfig, ConnectedServer, ServerStatus, IndexedTool, ToolAnnotations } from '../types/index.js';
3
+ export declare class Database {
4
+ private db;
5
+ private filePath;
6
+ private constructor();
7
+ static open(filePath?: string): Promise<Database>;
8
+ static inMemory(): Promise<Database>;
9
+ save(): void;
10
+ close(): void;
11
+ run(sql: string, params?: unknown[]): void;
12
+ get<T = Record<string, unknown>>(sql: string, params?: unknown[]): T | null;
13
+ all<T = Record<string, unknown>>(sql: string, params?: unknown[]): T[];
14
+ upsertServer(config: McpServerConfig): void;
15
+ getServer(name: string): {
16
+ config: McpServerConfig;
17
+ server: ConnectedServer;
18
+ } | null;
19
+ getAllServers(): {
20
+ config: McpServerConfig;
21
+ server: ConnectedServer;
22
+ }[];
23
+ removeServer(name: string): boolean;
24
+ updateServerStatus(name: string, status: ServerStatus, error?: string | null): void;
25
+ updateServerInfo(name: string, info: {
26
+ name: string;
27
+ version: string;
28
+ }, toolCount: number): void;
29
+ upsertTools(serverName: string, tools: {
30
+ name: string;
31
+ description?: string;
32
+ inputSchema?: unknown;
33
+ annotations?: ToolAnnotations;
34
+ }[]): void;
35
+ getTool(id: string): IndexedTool | null;
36
+ getToolsByServer(serverName: string): IndexedTool[];
37
+ getAllTools(): IndexedTool[];
38
+ searchTools(query: string, limit?: number): {
39
+ tool: IndexedTool;
40
+ score: number;
41
+ }[];
42
+ removeToolsByServer(serverName: string): void;
43
+ toolCount(): number;
44
+ private toServerResult;
45
+ private toTool;
46
+ getRawDb(): SqlJsDatabase;
47
+ }
48
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,QAAQ,CAAC;AAKxD,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAkJtH,qBAAa,QAAQ;IACnB,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,QAAQ,CAAgB;IAEhC,OAAO;WAKM,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;WAsB1C,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IAQ1C,IAAI,IAAI,IAAI;IAOZ,KAAK,IAAI,IAAI;IAKb,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI;IAK1C,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,GAAG,IAAI;IAY3E,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE;IAatE,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI;IAS3C,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,eAAe,CAAC;QAAC,MAAM,EAAE,eAAe,CAAA;KAAE,GAAG,IAAI;IAMpF,aAAa,IAAI;QAAE,MAAM,EAAE,eAAe,CAAC;QAAC,MAAM,EAAE,eAAe,CAAA;KAAE,EAAE;IAKvE,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAMnC,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAKnF,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAOhG,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,eAAe,CAAA;KAAE,EAAE,GAAG,IAAI;IAY5I,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAKvC,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,EAAE;IAKnD,WAAW,IAAI,WAAW,EAAE;IAK5B,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE;IAuB9E,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAI7C,SAAS,IAAI,MAAM;IAOnB,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,MAAM;IAad,QAAQ,IAAI,aAAa;CAG1B"}
@@ -0,0 +1,336 @@
1
+ import initSqlJs from 'sql.js';
2
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { getDefaultDbPath } from '../config/defaults.js';
6
+ let SQL = null;
7
+ async function getSqlJs() {
8
+ if (!SQL) {
9
+ // Try to find the wasm file
10
+ let wasmBinary;
11
+ try {
12
+ const sqlJsPath = dirname(fileURLToPath(import.meta.resolve('sql.js')));
13
+ const wasmPath = join(sqlJsPath, 'dist', 'sql-wasm.wasm');
14
+ if (existsSync(wasmPath)) {
15
+ wasmBinary = readFileSync(wasmPath);
16
+ }
17
+ }
18
+ catch {
19
+ // Let sql.js find it on its own
20
+ }
21
+ SQL = await initSqlJs(wasmBinary ? { wasmBinary } : undefined);
22
+ }
23
+ return SQL;
24
+ }
25
+ const SCHEMA = `
26
+ CREATE TABLE IF NOT EXISTS servers (
27
+ name TEXT PRIMARY KEY,
28
+ config_json TEXT NOT NULL,
29
+ status TEXT NOT NULL DEFAULT 'disconnected',
30
+ server_info TEXT,
31
+ tool_count INTEGER DEFAULT 0,
32
+ last_seen TEXT,
33
+ error TEXT,
34
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
35
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
36
+ );
37
+
38
+ CREATE TABLE IF NOT EXISTS tools (
39
+ id TEXT PRIMARY KEY,
40
+ server_name TEXT NOT NULL,
41
+ name TEXT NOT NULL,
42
+ description TEXT DEFAULT '',
43
+ input_schema TEXT,
44
+ annotations TEXT,
45
+ discovered_at TEXT NOT NULL DEFAULT (datetime('now')),
46
+ last_verified TEXT NOT NULL DEFAULT (datetime('now'))
47
+ );
48
+
49
+ CREATE INDEX IF NOT EXISTS idx_tools_server ON tools(server_name);
50
+ CREATE INDEX IF NOT EXISTS idx_tools_name ON tools(name);
51
+
52
+ CREATE TABLE IF NOT EXISTS users (
53
+ id TEXT PRIMARY KEY,
54
+ email TEXT UNIQUE NOT NULL,
55
+ password_hash TEXT NOT NULL,
56
+ display_name TEXT,
57
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
58
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
59
+ );
60
+
61
+ CREATE TABLE IF NOT EXISTS teams (
62
+ id TEXT PRIMARY KEY,
63
+ name TEXT NOT NULL,
64
+ slug TEXT UNIQUE NOT NULL,
65
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
66
+ );
67
+
68
+ CREATE TABLE IF NOT EXISTS team_members (
69
+ team_id TEXT NOT NULL,
70
+ user_id TEXT NOT NULL,
71
+ role TEXT NOT NULL DEFAULT 'member',
72
+ joined_at TEXT NOT NULL DEFAULT (datetime('now')),
73
+ PRIMARY KEY (team_id, user_id)
74
+ );
75
+
76
+ CREATE TABLE IF NOT EXISTS api_keys (
77
+ id TEXT PRIMARY KEY,
78
+ user_id TEXT NOT NULL,
79
+ key_hash TEXT NOT NULL,
80
+ key_prefix TEXT NOT NULL,
81
+ name TEXT NOT NULL,
82
+ last_used_at TEXT,
83
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
84
+ expires_at TEXT
85
+ );
86
+
87
+ CREATE TABLE IF NOT EXISTS team_servers (
88
+ id TEXT PRIMARY KEY,
89
+ team_id TEXT NOT NULL,
90
+ name TEXT NOT NULL,
91
+ config_json TEXT NOT NULL,
92
+ credentials_encrypted TEXT,
93
+ enabled INTEGER DEFAULT 1,
94
+ created_by TEXT,
95
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
96
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
97
+ UNIQUE(team_id, name)
98
+ );
99
+
100
+ CREATE TABLE IF NOT EXISTS context_documents (
101
+ id TEXT PRIMARY KEY,
102
+ team_id TEXT,
103
+ title TEXT NOT NULL,
104
+ content TEXT NOT NULL,
105
+ content_type TEXT DEFAULT 'text/markdown',
106
+ source TEXT,
107
+ tags TEXT DEFAULT '[]',
108
+ uploaded_by TEXT,
109
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
110
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
111
+ );
112
+
113
+ CREATE TABLE IF NOT EXISTS usage_events (
114
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
115
+ team_id TEXT,
116
+ user_id TEXT,
117
+ event_type TEXT NOT NULL,
118
+ server_name TEXT,
119
+ tool_name TEXT,
120
+ latency_ms INTEGER,
121
+ success INTEGER,
122
+ error TEXT,
123
+ metadata TEXT,
124
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
125
+ );
126
+
127
+ CREATE INDEX IF NOT EXISTS idx_usage_user ON usage_events(user_id, created_at);
128
+ CREATE INDEX IF NOT EXISTS idx_usage_team ON usage_events(team_id, created_at);
129
+
130
+ CREATE TABLE IF NOT EXISTS rate_limits (
131
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
132
+ team_id TEXT NOT NULL,
133
+ user_id TEXT,
134
+ role TEXT,
135
+ limit_type TEXT NOT NULL,
136
+ max_value INTEGER NOT NULL
137
+ );
138
+
139
+ CREATE TABLE IF NOT EXISTS tool_permissions (
140
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
141
+ team_id TEXT NOT NULL,
142
+ role TEXT NOT NULL,
143
+ server_name TEXT NOT NULL,
144
+ tool_name TEXT,
145
+ permission TEXT NOT NULL DEFAULT 'allow'
146
+ );
147
+ `;
148
+ export class Database {
149
+ db;
150
+ filePath;
151
+ constructor(db, filePath) {
152
+ this.db = db;
153
+ this.filePath = filePath;
154
+ }
155
+ static async open(filePath) {
156
+ const resolved = filePath || getDefaultDbPath();
157
+ mkdirSync(dirname(resolved), { recursive: true });
158
+ const SqlJs = await getSqlJs();
159
+ let db;
160
+ if (existsSync(resolved)) {
161
+ const buffer = readFileSync(resolved);
162
+ db = new SqlJs.Database(buffer);
163
+ }
164
+ else {
165
+ db = new SqlJs.Database();
166
+ }
167
+ db.run('PRAGMA foreign_keys = ON');
168
+ db.run(SCHEMA);
169
+ const instance = new Database(db, resolved);
170
+ instance.save();
171
+ return instance;
172
+ }
173
+ static async inMemory() {
174
+ const SqlJs = await getSqlJs();
175
+ const db = new SqlJs.Database();
176
+ db.run('PRAGMA foreign_keys = ON');
177
+ db.run(SCHEMA);
178
+ return new Database(db, null);
179
+ }
180
+ save() {
181
+ if (this.filePath) {
182
+ const data = this.db.export();
183
+ writeFileSync(this.filePath, Buffer.from(data));
184
+ }
185
+ }
186
+ close() {
187
+ this.save();
188
+ this.db.close();
189
+ }
190
+ run(sql, params) {
191
+ this.db.run(sql, params);
192
+ this.save();
193
+ }
194
+ get(sql, params) {
195
+ const stmt = this.db.prepare(sql);
196
+ if (params)
197
+ stmt.bind(params);
198
+ if (stmt.step()) {
199
+ const row = stmt.getAsObject();
200
+ stmt.free();
201
+ return row;
202
+ }
203
+ stmt.free();
204
+ return null;
205
+ }
206
+ all(sql, params) {
207
+ const results = [];
208
+ const stmt = this.db.prepare(sql);
209
+ if (params)
210
+ stmt.bind(params);
211
+ while (stmt.step()) {
212
+ results.push(stmt.getAsObject());
213
+ }
214
+ stmt.free();
215
+ return results;
216
+ }
217
+ // --- Server Operations ---
218
+ upsertServer(config) {
219
+ const now = new Date().toISOString();
220
+ this.run(`
221
+ INSERT INTO servers (name, config_json, status, created_at, updated_at)
222
+ VALUES (?, ?, 'disconnected', ?, ?)
223
+ ON CONFLICT(name) DO UPDATE SET config_json = excluded.config_json, updated_at = ?
224
+ `, [config.name, JSON.stringify(config), now, now, now]);
225
+ }
226
+ getServer(name) {
227
+ const row = this.get('SELECT * FROM servers WHERE name = ?', [name]);
228
+ if (!row)
229
+ return null;
230
+ return this.toServerResult(row);
231
+ }
232
+ getAllServers() {
233
+ const rows = this.all('SELECT * FROM servers ORDER BY name');
234
+ return rows.map(r => this.toServerResult(r));
235
+ }
236
+ removeServer(name) {
237
+ this.run('DELETE FROM tools WHERE server_name = ?', [name]);
238
+ this.run('DELETE FROM servers WHERE name = ?', [name]);
239
+ return true;
240
+ }
241
+ updateServerStatus(name, status, error) {
242
+ this.run('UPDATE servers SET status = ?, error = ?, last_seen = datetime("now"), updated_at = datetime("now") WHERE name = ?', [status, error ?? null, name]);
243
+ }
244
+ updateServerInfo(name, info, toolCount) {
245
+ this.run('UPDATE servers SET server_info = ?, tool_count = ?, last_seen = datetime("now"), updated_at = datetime("now") WHERE name = ?', [JSON.stringify(info), toolCount, name]);
246
+ }
247
+ // --- Tool Operations ---
248
+ upsertTools(serverName, tools) {
249
+ this.run('DELETE FROM tools WHERE server_name = ?', [serverName]);
250
+ const now = new Date().toISOString();
251
+ for (const tool of tools) {
252
+ const id = `${serverName}:${tool.name}`;
253
+ this.run(`INSERT INTO tools (id, server_name, name, description, input_schema, annotations, discovered_at, last_verified)
254
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [id, serverName, tool.name, tool.description || '', tool.inputSchema ? JSON.stringify(tool.inputSchema) : null,
255
+ tool.annotations ? JSON.stringify(tool.annotations) : null, now, now]);
256
+ }
257
+ }
258
+ getTool(id) {
259
+ const row = this.get('SELECT * FROM tools WHERE id = ?', [id]);
260
+ return row ? this.toTool(row) : null;
261
+ }
262
+ getToolsByServer(serverName) {
263
+ return this.all('SELECT * FROM tools WHERE server_name = ? ORDER BY name', [serverName])
264
+ .map(r => this.toTool(r));
265
+ }
266
+ getAllTools() {
267
+ return this.all('SELECT * FROM tools ORDER BY server_name, name')
268
+ .map(r => this.toTool(r));
269
+ }
270
+ searchTools(query, limit = 20) {
271
+ if (!query.trim())
272
+ return [];
273
+ const terms = query.toLowerCase().split(/\s+/);
274
+ const tools = this.getAllTools();
275
+ return tools
276
+ .map(tool => {
277
+ let score = 0;
278
+ const nameL = tool.name.toLowerCase();
279
+ const descL = tool.description.toLowerCase();
280
+ for (const term of terms) {
281
+ if (nameL === term)
282
+ score += 10;
283
+ else if (nameL.includes(term))
284
+ score += 5;
285
+ if (descL.includes(term))
286
+ score += 3;
287
+ if (tool.serverName.toLowerCase().includes(term))
288
+ score += 1;
289
+ }
290
+ return { tool, score };
291
+ })
292
+ .filter(s => s.score > 0)
293
+ .sort((a, b) => b.score - a.score)
294
+ .slice(0, limit);
295
+ }
296
+ removeToolsByServer(serverName) {
297
+ this.run('DELETE FROM tools WHERE server_name = ?', [serverName]);
298
+ }
299
+ toolCount() {
300
+ const row = this.get('SELECT COUNT(*) as count FROM tools');
301
+ return row?.count ?? 0;
302
+ }
303
+ // --- Helpers ---
304
+ toServerResult(row) {
305
+ const config = JSON.parse(row.config_json);
306
+ const serverInfo = row.server_info ? JSON.parse(row.server_info) : null;
307
+ return {
308
+ config,
309
+ server: {
310
+ name: row.name,
311
+ status: row.status,
312
+ transport: config.transport.type,
313
+ toolCount: row.tool_count,
314
+ lastSeen: (row.last_seen || row.created_at),
315
+ error: row.error,
316
+ serverInfo,
317
+ },
318
+ };
319
+ }
320
+ toTool(row) {
321
+ return {
322
+ id: row.id,
323
+ serverName: row.server_name,
324
+ name: row.name,
325
+ description: (row.description || ''),
326
+ inputSchema: row.input_schema ? JSON.parse(row.input_schema) : undefined,
327
+ annotations: row.annotations ? JSON.parse(row.annotations) : undefined,
328
+ discoveredAt: row.discovered_at,
329
+ lastVerified: row.last_verified,
330
+ };
331
+ }
332
+ getRawDb() {
333
+ return this.db;
334
+ }
335
+ }
336
+ //# sourceMappingURL=database.js.map