@pikku/core 0.12.3 → 0.12.4

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 (218) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/services/in-memory-workflow-service.d.ts +15 -2
  3. package/dist/services/in-memory-workflow-service.js +49 -0
  4. package/lcov.info +18891 -0
  5. package/package.json +1 -1
  6. package/src/crypto-utils.test.ts +0 -214
  7. package/src/crypto-utils.ts +0 -213
  8. package/src/errors/error-handler.ts +0 -62
  9. package/src/errors/error.test.ts +0 -195
  10. package/src/errors/errors.ts +0 -374
  11. package/src/errors/index.ts +0 -2
  12. package/src/factory-functions.test.ts +0 -109
  13. package/src/function/function-runner.test.ts +0 -536
  14. package/src/function/function-runner.ts +0 -365
  15. package/src/function/functions.types.ts +0 -304
  16. package/src/function/index.ts +0 -5
  17. package/src/handle-error.test.ts +0 -424
  18. package/src/handle-error.ts +0 -69
  19. package/src/index.ts +0 -118
  20. package/src/internal.ts +0 -6
  21. package/src/middleware/auth-apikey.test.ts +0 -363
  22. package/src/middleware/auth-apikey.ts +0 -47
  23. package/src/middleware/auth-bearer.test.ts +0 -450
  24. package/src/middleware/auth-bearer.ts +0 -72
  25. package/src/middleware/auth-cookie.test.ts +0 -528
  26. package/src/middleware/auth-cookie.ts +0 -80
  27. package/src/middleware/cors.test.ts +0 -424
  28. package/src/middleware/cors.ts +0 -104
  29. package/src/middleware/index.ts +0 -5
  30. package/src/middleware/remote-auth.test.ts +0 -488
  31. package/src/middleware/remote-auth.ts +0 -68
  32. package/src/middleware/timeout.ts +0 -15
  33. package/src/middleware-runner.test.ts +0 -418
  34. package/src/middleware-runner.ts +0 -234
  35. package/src/permissions.test.ts +0 -434
  36. package/src/permissions.ts +0 -319
  37. package/src/pikku-request.ts +0 -23
  38. package/src/pikku-response.ts +0 -5
  39. package/src/pikku-state.test.ts +0 -224
  40. package/src/pikku-state.ts +0 -216
  41. package/src/run-tests-script.test.ts +0 -49
  42. package/src/schema.test.ts +0 -249
  43. package/src/schema.ts +0 -151
  44. package/src/services/ai-agent-runner-service.ts +0 -41
  45. package/src/services/ai-run-state-service.ts +0 -20
  46. package/src/services/ai-storage-service.ts +0 -39
  47. package/src/services/content-service.ts +0 -76
  48. package/src/services/deployment-service.ts +0 -22
  49. package/src/services/gateway-service.ts +0 -20
  50. package/src/services/gopass-secrets.ts +0 -98
  51. package/src/services/in-memory-ai-run-state-service.ts +0 -73
  52. package/src/services/in-memory-trigger-service.ts +0 -64
  53. package/src/services/in-memory-workflow-service.test.ts +0 -351
  54. package/src/services/in-memory-workflow-service.ts +0 -438
  55. package/src/services/index.ts +0 -56
  56. package/src/services/jwt-service.ts +0 -30
  57. package/src/services/local-content.ts +0 -120
  58. package/src/services/local-gateway-service.ts +0 -62
  59. package/src/services/local-secrets.test.ts +0 -80
  60. package/src/services/local-secrets.ts +0 -94
  61. package/src/services/local-variables.test.ts +0 -61
  62. package/src/services/local-variables.ts +0 -39
  63. package/src/services/logger-console.test.ts +0 -118
  64. package/src/services/logger-console.ts +0 -98
  65. package/src/services/logger.ts +0 -57
  66. package/src/services/scheduler-service.ts +0 -86
  67. package/src/services/schema-service.ts +0 -33
  68. package/src/services/scoped-secret-service.test.ts +0 -74
  69. package/src/services/scoped-secret-service.ts +0 -41
  70. package/src/services/secret-service.ts +0 -38
  71. package/src/services/trigger-service.ts +0 -17
  72. package/src/services/typed-secret-service.test.ts +0 -93
  73. package/src/services/typed-secret-service.ts +0 -70
  74. package/src/services/typed-variables-service.test.ts +0 -73
  75. package/src/services/typed-variables-service.ts +0 -81
  76. package/src/services/user-session-service.test.ts +0 -113
  77. package/src/services/user-session-service.ts +0 -86
  78. package/src/services/variables-service.ts +0 -11
  79. package/src/services/workflow-service.ts +0 -95
  80. package/src/testing/index.ts +0 -2
  81. package/src/testing/service-tests.ts +0 -873
  82. package/src/time-utils.test.ts +0 -56
  83. package/src/time-utils.ts +0 -107
  84. package/src/types/core.types.ts +0 -478
  85. package/src/types/state.types.ts +0 -188
  86. package/src/utils/hash.test.ts +0 -68
  87. package/src/utils/hash.ts +0 -26
  88. package/src/utils.test.ts +0 -350
  89. package/src/utils.ts +0 -129
  90. package/src/version.test.ts +0 -80
  91. package/src/version.ts +0 -25
  92. package/src/wirings/ai-agent/agent-dynamic-workflow.ts +0 -469
  93. package/src/wirings/ai-agent/ai-agent-helpers.test.ts +0 -152
  94. package/src/wirings/ai-agent/ai-agent-helpers.ts +0 -76
  95. package/src/wirings/ai-agent/ai-agent-memory.ts +0 -310
  96. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +0 -115
  97. package/src/wirings/ai-agent/ai-agent-model-config.ts +0 -43
  98. package/src/wirings/ai-agent/ai-agent-prepare.ts +0 -636
  99. package/src/wirings/ai-agent/ai-agent-registry.test.ts +0 -37
  100. package/src/wirings/ai-agent/ai-agent-registry.ts +0 -82
  101. package/src/wirings/ai-agent/ai-agent-runner.test.ts +0 -319
  102. package/src/wirings/ai-agent/ai-agent-runner.ts +0 -773
  103. package/src/wirings/ai-agent/ai-agent-stream.test.ts +0 -859
  104. package/src/wirings/ai-agent/ai-agent-stream.ts +0 -1153
  105. package/src/wirings/ai-agent/ai-agent.types.ts +0 -382
  106. package/src/wirings/ai-agent/index.ts +0 -37
  107. package/src/wirings/channel/channel-common.ts +0 -90
  108. package/src/wirings/channel/channel-handler.ts +0 -250
  109. package/src/wirings/channel/channel-middleware-runner.ts +0 -120
  110. package/src/wirings/channel/channel-runner.ts +0 -166
  111. package/src/wirings/channel/channel-store.ts +0 -29
  112. package/src/wirings/channel/channel.types.ts +0 -172
  113. package/src/wirings/channel/define-channel-routes.ts +0 -25
  114. package/src/wirings/channel/eventhub-service.ts +0 -34
  115. package/src/wirings/channel/eventhub-store.ts +0 -13
  116. package/src/wirings/channel/index.ts +0 -24
  117. package/src/wirings/channel/local/index.ts +0 -3
  118. package/src/wirings/channel/local/local-channel-handler.ts +0 -81
  119. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -215
  120. package/src/wirings/channel/local/local-channel-runner.ts +0 -210
  121. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -95
  122. package/src/wirings/channel/local/local-eventhub-service.ts +0 -101
  123. package/src/wirings/channel/log-channels.ts +0 -20
  124. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +0 -54
  125. package/src/wirings/channel/pikku-abstract-channel-handler.ts +0 -45
  126. package/src/wirings/channel/serverless/index.ts +0 -5
  127. package/src/wirings/channel/serverless/serverless-channel-runner.ts +0 -289
  128. package/src/wirings/cli/channel/cli-channel-runner.ts +0 -136
  129. package/src/wirings/cli/channel/index.ts +0 -1
  130. package/src/wirings/cli/cli-runner.test.ts +0 -403
  131. package/src/wirings/cli/cli-runner.ts +0 -529
  132. package/src/wirings/cli/cli.types.ts +0 -358
  133. package/src/wirings/cli/command-parser.test.ts +0 -445
  134. package/src/wirings/cli/command-parser.ts +0 -504
  135. package/src/wirings/cli/define-cli-commands.ts +0 -24
  136. package/src/wirings/cli/index.ts +0 -19
  137. package/src/wirings/gateway/gateway-runner.test.ts +0 -474
  138. package/src/wirings/gateway/gateway-runner.ts +0 -411
  139. package/src/wirings/gateway/gateway.types.ts +0 -149
  140. package/src/wirings/gateway/index.ts +0 -13
  141. package/src/wirings/http/http-routes.test.ts +0 -322
  142. package/src/wirings/http/http-routes.ts +0 -197
  143. package/src/wirings/http/http-runner.test.ts +0 -144
  144. package/src/wirings/http/http-runner.ts +0 -588
  145. package/src/wirings/http/http.types.ts +0 -369
  146. package/src/wirings/http/index.ts +0 -28
  147. package/src/wirings/http/log-http-routes.ts +0 -22
  148. package/src/wirings/http/pikku-fetch-http-request.test.ts +0 -237
  149. package/src/wirings/http/pikku-fetch-http-request.ts +0 -170
  150. package/src/wirings/http/pikku-fetch-http-response.test.ts +0 -82
  151. package/src/wirings/http/pikku-fetch-http-response.ts +0 -147
  152. package/src/wirings/http/routers/http-router.ts +0 -13
  153. package/src/wirings/http/routers/path-to-regex.test.ts +0 -319
  154. package/src/wirings/http/routers/path-to-regex.ts +0 -126
  155. package/src/wirings/http/web-request.test.ts +0 -236
  156. package/src/wirings/http/web-request.ts +0 -104
  157. package/src/wirings/mcp/index.ts +0 -27
  158. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -389
  159. package/src/wirings/mcp/mcp-endpoint-registry.ts +0 -159
  160. package/src/wirings/mcp/mcp-runner.ts +0 -323
  161. package/src/wirings/mcp/mcp.types.ts +0 -216
  162. package/src/wirings/node/index.ts +0 -2
  163. package/src/wirings/node/node.types.ts +0 -23
  164. package/src/wirings/oauth2/index.ts +0 -3
  165. package/src/wirings/oauth2/oauth2-client.test.ts +0 -929
  166. package/src/wirings/oauth2/oauth2-client.ts +0 -335
  167. package/src/wirings/oauth2/oauth2.types.ts +0 -69
  168. package/src/wirings/oauth2/wire-oauth2-credential.ts +0 -23
  169. package/src/wirings/queue/index.ts +0 -31
  170. package/src/wirings/queue/queue-runner.test.ts +0 -710
  171. package/src/wirings/queue/queue-runner.ts +0 -192
  172. package/src/wirings/queue/queue.types.ts +0 -189
  173. package/src/wirings/queue/register-queue-helper.ts +0 -60
  174. package/src/wirings/queue/validate-worker-config.test.ts +0 -108
  175. package/src/wirings/queue/validate-worker-config.ts +0 -116
  176. package/src/wirings/rpc/index.ts +0 -4
  177. package/src/wirings/rpc/rpc-runner.ts +0 -460
  178. package/src/wirings/rpc/rpc-types.ts +0 -56
  179. package/src/wirings/rpc/wire-addon.ts +0 -21
  180. package/src/wirings/scheduler/index.ts +0 -11
  181. package/src/wirings/scheduler/log-schedulers.ts +0 -20
  182. package/src/wirings/scheduler/scheduler-runner.test.ts +0 -660
  183. package/src/wirings/scheduler/scheduler-runner.ts +0 -133
  184. package/src/wirings/scheduler/scheduler.types.ts +0 -53
  185. package/src/wirings/secret/index.ts +0 -9
  186. package/src/wirings/secret/secret.types.ts +0 -32
  187. package/src/wirings/secret/validate-secret-definitions.test.ts +0 -140
  188. package/src/wirings/secret/validate-secret-definitions.ts +0 -82
  189. package/src/wirings/trigger/index.ts +0 -10
  190. package/src/wirings/trigger/pikku-trigger-service.ts +0 -112
  191. package/src/wirings/trigger/trigger-runner.test.ts +0 -79
  192. package/src/wirings/trigger/trigger-runner.ts +0 -135
  193. package/src/wirings/trigger/trigger.types.ts +0 -178
  194. package/src/wirings/variable/index.ts +0 -8
  195. package/src/wirings/variable/validate-variable-definitions.test.ts +0 -91
  196. package/src/wirings/variable/validate-variable-definitions.ts +0 -69
  197. package/src/wirings/variable/variable.types.ts +0 -22
  198. package/src/wirings/workflow/dsl/index.ts +0 -31
  199. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +0 -320
  200. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -28
  201. package/src/wirings/workflow/graph/graph-node.ts +0 -222
  202. package/src/wirings/workflow/graph/graph-runner.test.ts +0 -487
  203. package/src/wirings/workflow/graph/graph-runner.ts +0 -816
  204. package/src/wirings/workflow/graph/graph-validation.test.ts +0 -170
  205. package/src/wirings/workflow/graph/graph-validation.ts +0 -237
  206. package/src/wirings/workflow/graph/index.ts +0 -19
  207. package/src/wirings/workflow/graph/template.test.ts +0 -49
  208. package/src/wirings/workflow/graph/template.ts +0 -42
  209. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -29
  210. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -104
  211. package/src/wirings/workflow/index.ts +0 -82
  212. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -200
  213. package/src/wirings/workflow/pikku-workflow-service.ts +0 -1176
  214. package/src/wirings/workflow/workflow-helpers.test.ts +0 -129
  215. package/src/wirings/workflow/workflow-helpers.ts +0 -79
  216. package/src/wirings/workflow/workflow.types.ts +0 -274
  217. package/tsconfig.json +0 -14
  218. package/tsconfig.tsbuildinfo +0 -1
@@ -1,104 +0,0 @@
1
- import type { PikkuHTTPRequest } from './http.types.js'
2
- import type { PikkuHTTPResponse } from './http.types.js'
3
-
4
- /**
5
- * Converts a PikkuHTTPRequest into a Web API Request.
6
- * Useful for bridging Pikku routes to libraries that expect standard Web Request objects.
7
- */
8
- export function toWebRequest(req: PikkuHTTPRequest, baseUrl?: string): Request {
9
- const url = new URL(
10
- req.path(),
11
- baseUrl ?? `http://${req.header('host') ?? 'localhost'}`
12
- )
13
-
14
- const query = req.query()
15
- for (const [key, value] of Object.entries(query)) {
16
- if (value != null) {
17
- url.searchParams.set(key, String(value))
18
- }
19
- }
20
-
21
- const headers = new Headers(req.headers())
22
-
23
- const method = req.method().toUpperCase()
24
- const hasBody = !['GET', 'HEAD', 'OPTIONS'].includes(method)
25
-
26
- if (!hasBody) {
27
- return new Request(url, { method, headers })
28
- }
29
-
30
- return new Request(url, {
31
- method,
32
- headers,
33
- body: new ReadableStream({
34
- async start(controller) {
35
- try {
36
- const buffer = await req.arrayBuffer()
37
- if (buffer.byteLength > 0) {
38
- controller.enqueue(new Uint8Array(buffer))
39
- } else {
40
- // arrayBuffer may be empty if body was pre-parsed (e.g., Express middleware)
41
- const contentType = (
42
- headers.get('content-type') || ''
43
- ).toLowerCase()
44
- const parsed = await req.json()
45
- if (
46
- parsed &&
47
- typeof parsed === 'object' &&
48
- Object.keys(parsed as any).length > 0
49
- ) {
50
- let reconstructed: string
51
- if (contentType.includes('application/x-www-form-urlencoded')) {
52
- reconstructed = new URLSearchParams(
53
- parsed as Record<string, string>
54
- ).toString()
55
- } else {
56
- reconstructed = JSON.stringify(parsed)
57
- }
58
- controller.enqueue(new TextEncoder().encode(reconstructed))
59
- }
60
- }
61
- } catch {
62
- // Empty body
63
- }
64
- controller.close()
65
- },
66
- }),
67
- // @ts-ignore - duplex is needed for streaming body in Node.js
68
- duplex: 'half',
69
- })
70
- }
71
-
72
- const SKIP_RESPONSE_HEADERS = new Set(['content-length', 'transfer-encoding'])
73
-
74
- /**
75
- * Applies a Web API Response to a PikkuHTTPResponse.
76
- * Copies status, headers (including Set-Cookie), redirects, and body.
77
- */
78
- export async function applyWebResponse(
79
- res: PikkuHTTPResponse,
80
- webResponse: Response
81
- ): Promise<void> {
82
- res.status(webResponse.status)
83
-
84
- webResponse.headers.forEach((value, name) => {
85
- const lower = name.toLowerCase()
86
- if (SKIP_RESPONSE_HEADERS.has(lower)) {
87
- return
88
- }
89
- if (lower === 'location') {
90
- res.redirect(value, webResponse.status)
91
- } else {
92
- res.header(name, value)
93
- }
94
- })
95
-
96
- const body = await webResponse.text()
97
- if (body) {
98
- if (res.send) {
99
- res.send(body)
100
- } else {
101
- res.arrayBuffer(body)
102
- }
103
- }
104
- }
@@ -1,27 +0,0 @@
1
- export { MCPEndpointRegistry } from './mcp-endpoint-registry.js'
2
- export {
3
- MCPError,
4
- wireMCPResource,
5
- wireMCPPrompt,
6
- runMCPResource,
7
- runMCPTool,
8
- runMCPPrompt,
9
- } from './mcp-runner.js'
10
- export {
11
- getMCPResourcesMeta,
12
- getMCPToolsMeta,
13
- getMCPPromptsMeta,
14
- } from './mcp-runner.js'
15
- export type {
16
- AssertMCPResourceURIParams,
17
- CoreMCPPrompt,
18
- CoreMCPResource,
19
- CoreMCPTool,
20
- MCPPromptResponse,
21
- MCPResourceMeta,
22
- MCPResourceResponse,
23
- MCPToolMeta,
24
- MCPToolResponse,
25
- MCPPromptMeta,
26
- PikkuMCP,
27
- } from './mcp.types.js'
@@ -1,389 +0,0 @@
1
- import { test, describe, beforeEach } from 'node:test'
2
- import * as assert from 'assert'
3
- import { MCPEndpointRegistry } from './mcp-endpoint-registry.js'
4
-
5
- describe('MCPEndpointRegistry', () => {
6
- let registry: MCPEndpointRegistry
7
-
8
- beforeEach(() => {
9
- registry = new MCPEndpointRegistry()
10
- })
11
-
12
- describe('constructor', () => {
13
- test('should initialize with empty maps', () => {
14
- assert.deepStrictEqual(registry.getTools(), [])
15
- assert.deepStrictEqual(registry.getResources(), [])
16
- assert.deepStrictEqual(registry.getPrompts(), [])
17
- })
18
- })
19
-
20
- describe('loadFromMCPJson', () => {
21
- test('should load tools from MCP JSON', async () => {
22
- const mockData = {
23
- tools: [
24
- {
25
- name: 'test-tool',
26
- title: 'Test Tool',
27
- description: 'A test tool',
28
- parameters: { type: 'object' },
29
- returns: { type: 'string' },
30
- enabled: true,
31
- },
32
- ],
33
- }
34
-
35
- await registry.loadFromMCPJson(mockData)
36
-
37
- const tools = registry.getTools()
38
- assert.strictEqual(tools.length, 1)
39
- assert.strictEqual(tools[0].name, 'test-tool')
40
- assert.strictEqual(tools[0].title, 'Test Tool')
41
- assert.strictEqual(tools[0].description, 'A test tool')
42
- assert.deepStrictEqual(tools[0].inputSchema, { type: 'object' })
43
- assert.deepStrictEqual(tools[0].outputSchema, { type: 'string' })
44
- assert.strictEqual(tools[0].enabled, true)
45
- })
46
-
47
- test('should load resources from MCP JSON', async () => {
48
- const mockData = {
49
- resources: [
50
- {
51
- name: 'test-resource',
52
- uri: 'file://test.txt',
53
- description: 'A test resource',
54
- parameters: { type: 'object' },
55
- enabled: false,
56
- },
57
- ],
58
- }
59
-
60
- await registry.loadFromMCPJson(mockData)
61
-
62
- const resources = registry.getResources()
63
- assert.strictEqual(resources.length, 1)
64
- assert.strictEqual(resources[0].title, 'test-resource')
65
- assert.strictEqual(resources[0].uri, 'file://test.txt')
66
- assert.strictEqual(resources[0].description, 'A test resource')
67
- assert.deepStrictEqual(resources[0].inputSchema, { type: 'object' })
68
- assert.strictEqual(resources[0].enabled, false)
69
- })
70
-
71
- test('should load prompts from MCP JSON', async () => {
72
- const mockData = {
73
- prompts: [
74
- {
75
- name: 'test-prompt',
76
- description: 'A test prompt',
77
- arguments: { type: 'object' },
78
- },
79
- ],
80
- }
81
-
82
- await registry.loadFromMCPJson(mockData)
83
-
84
- const prompts = registry.getPrompts()
85
- assert.strictEqual(prompts.length, 1)
86
- assert.strictEqual(prompts[0].name, 'test-prompt')
87
- assert.strictEqual(prompts[0].description, 'A test prompt')
88
- assert.deepStrictEqual(prompts[0].inputSchema, { type: 'object' })
89
- assert.strictEqual(prompts[0].enabled, true)
90
- })
91
-
92
- test('should handle tools with default enabled state', async () => {
93
- const mockData = {
94
- tools: [
95
- {
96
- name: 'default-tool',
97
- title: 'Default Tool',
98
- description: 'Tool with default enabled state',
99
- },
100
- ],
101
- }
102
-
103
- await registry.loadFromMCPJson(mockData)
104
-
105
- const tools = registry.getTools()
106
- assert.strictEqual(tools.length, 1)
107
- assert.strictEqual(tools[0].enabled, true)
108
- })
109
-
110
- test('should handle empty arrays', async () => {
111
- const mockData = {
112
- tools: [],
113
- resources: [],
114
- prompts: [],
115
- }
116
-
117
- await registry.loadFromMCPJson(mockData)
118
-
119
- assert.deepStrictEqual(registry.getTools(), [])
120
- assert.deepStrictEqual(registry.getResources(), [])
121
- assert.deepStrictEqual(registry.getPrompts(), [])
122
- })
123
-
124
- test('should handle missing arrays', async () => {
125
- const mockData = {}
126
-
127
- await registry.loadFromMCPJson(mockData)
128
-
129
- assert.deepStrictEqual(registry.getTools(), [])
130
- assert.deepStrictEqual(registry.getResources(), [])
131
- assert.deepStrictEqual(registry.getPrompts(), [])
132
- })
133
-
134
- test('should handle empty object gracefully', async () => {
135
- // Test with empty object
136
- await registry.loadFromMCPJson({})
137
- assert.deepStrictEqual(registry.getTools(), [])
138
- assert.deepStrictEqual(registry.getResources(), [])
139
- assert.deepStrictEqual(registry.getPrompts(), [])
140
- })
141
- })
142
-
143
- describe('meta setters and getters', () => {
144
- test('should set and check resource meta', () => {
145
- const meta = {
146
- 'test-resource': {
147
- uri: 'file://test.txt',
148
- title: 'Test Resource',
149
- description: 'Test description',
150
- pikkuFuncId: 'testResource',
151
- inputSchema: null,
152
- outputSchema: null,
153
- mimeType: 'text/plain',
154
- },
155
- }
156
- registry.setResourcesMeta(meta)
157
- assert.strictEqual(registry.hasResource('test-resource'), true)
158
- assert.strictEqual(registry.hasResource('nonexistent'), false)
159
- })
160
-
161
- test('should set and check tool meta', () => {
162
- const meta = {
163
- 'test-tool': {
164
- name: 'test-tool',
165
- title: 'Test Tool',
166
- description: 'Test description',
167
- pikkuFuncId: 'testTool',
168
- inputSchema: null,
169
- outputSchema: null,
170
- },
171
- }
172
- registry.setToolsMeta(meta)
173
- assert.strictEqual(registry.hasTool('test-tool'), true)
174
- assert.strictEqual(registry.hasTool('nonexistent'), false)
175
- })
176
-
177
- test('should set and check prompt meta', () => {
178
- const meta = {
179
- 'test-prompt': {
180
- name: 'test-prompt',
181
- description: 'Test Prompt',
182
- pikkuFuncId: 'testPrompt',
183
- inputSchema: null,
184
- outputSchema: null,
185
- arguments: [],
186
- },
187
- }
188
- registry.setPromptsMeta(meta)
189
- assert.strictEqual(registry.hasPrompt('test-prompt'), true)
190
- assert.strictEqual(registry.hasPrompt('nonexistent'), false)
191
- })
192
- })
193
-
194
- describe('individual item getters', () => {
195
- beforeEach(async () => {
196
- const mockData = {
197
- tools: [
198
- {
199
- name: 'tool1',
200
- title: 'Tool 1',
201
- description: 'First tool',
202
- enabled: true,
203
- },
204
- ],
205
- resources: [
206
- {
207
- name: 'resource1',
208
- uri: 'file://resource1.txt',
209
- description: 'First resource',
210
- enabled: true,
211
- },
212
- ],
213
- prompts: [
214
- {
215
- name: 'prompt1',
216
- description: 'First prompt',
217
- enabled: true,
218
- },
219
- ],
220
- }
221
-
222
- await registry.loadFromMCPJson(mockData)
223
- })
224
-
225
- test('should get tool by name', () => {
226
- const tool = registry.getTool('tool1')
227
- assert.strictEqual(tool?.name, 'tool1')
228
- assert.strictEqual(tool?.title, 'Tool 1')
229
- assert.strictEqual(registry.getTool('nonexistent'), undefined)
230
- })
231
-
232
- test('should get resource by name', () => {
233
- const resource = registry.getResource('resource1')
234
- assert.strictEqual(resource?.title, 'resource1')
235
- assert.strictEqual(resource?.uri, 'file://resource1.txt')
236
- assert.strictEqual(registry.getResource('nonexistent'), undefined)
237
- })
238
-
239
- test('should get prompt by name', () => {
240
- const prompt = registry.getPrompt('prompt1')
241
- assert.strictEqual(prompt?.name, 'prompt1')
242
- assert.strictEqual(prompt?.description, 'First prompt')
243
- assert.strictEqual(registry.getPrompt('nonexistent'), undefined)
244
- })
245
- })
246
-
247
- describe('getTools filters enabled tools', () => {
248
- test('should only return enabled tools', async () => {
249
- const mockData = {
250
- tools: [
251
- {
252
- name: 'enabled-tool',
253
- title: 'Enabled Tool',
254
- description: 'This tool is enabled',
255
- enabled: true,
256
- },
257
- {
258
- name: 'disabled-tool',
259
- title: 'Disabled Tool',
260
- description: 'This tool is disabled',
261
- enabled: false,
262
- },
263
- ],
264
- }
265
-
266
- await registry.loadFromMCPJson(mockData)
267
-
268
- const tools = registry.getTools()
269
- assert.strictEqual(tools.length, 1)
270
- assert.strictEqual(tools[0].name, 'enabled-tool')
271
- })
272
- })
273
-
274
- describe('enable/disable methods', () => {
275
- beforeEach(async () => {
276
- const mockData = {
277
- tools: [
278
- {
279
- name: 'tool1',
280
- title: 'Tool 1',
281
- description: 'First tool',
282
- enabled: true,
283
- },
284
- {
285
- name: 'tool2',
286
- title: 'Tool 2',
287
- description: 'Second tool',
288
- enabled: false,
289
- },
290
- ],
291
- resources: [
292
- {
293
- name: 'resource1',
294
- uri: 'file://resource1.txt',
295
- description: 'First resource',
296
- enabled: true,
297
- },
298
- ],
299
- prompts: [
300
- {
301
- name: 'prompt1',
302
- description: 'First prompt',
303
- enabled: true,
304
- },
305
- ],
306
- }
307
-
308
- await registry.loadFromMCPJson(mockData)
309
- })
310
-
311
- test('should enable/disable tools and return change status', () => {
312
- let changed = registry.enableTools({ tool1: false, tool2: true })
313
- assert.strictEqual(changed, true)
314
-
315
- const tool1 = registry.getTool('tool1')
316
- const tool2 = registry.getTool('tool2')
317
- assert.strictEqual(tool1?.enabled, false)
318
- assert.strictEqual(tool2?.enabled, true)
319
-
320
- changed = registry.enableTools({ tool1: false, tool2: true })
321
- assert.strictEqual(changed, false)
322
- })
323
-
324
- test('should handle nonexistent tools', () => {
325
- const changed = registry.enableTools({ nonexistent: true })
326
- assert.strictEqual(changed, false)
327
- })
328
-
329
- test('should enable/disable prompts and return change status', () => {
330
- let changed = registry.enablePrompts({ prompt1: false })
331
- assert.strictEqual(changed, true)
332
-
333
- const prompt1 = registry.getPrompt('prompt1')
334
- assert.strictEqual(prompt1?.enabled, false)
335
-
336
- changed = registry.enablePrompts({ prompt1: false })
337
- assert.strictEqual(changed, false)
338
- })
339
-
340
- test('should handle nonexistent prompts', () => {
341
- const changed = registry.enablePrompts({ nonexistent: true })
342
- assert.strictEqual(changed, false)
343
- })
344
-
345
- test('should enable/disable resources', () => {
346
- const changed = registry.enableResources({ resource1: false })
347
- assert.strictEqual(changed, true)
348
-
349
- const resource1 = registry.getResource('resource1')
350
- assert.strictEqual(resource1?.enabled, false)
351
- })
352
- })
353
-
354
- describe('edge cases', () => {
355
- test('should handle null/undefined values in MCP JSON', async () => {
356
- const mockData = {
357
- tools: [
358
- {
359
- name: 'incomplete-tool',
360
- title: null,
361
- description: undefined,
362
- },
363
- ],
364
- }
365
-
366
- await registry.loadFromMCPJson(mockData)
367
-
368
- const tools = registry.getTools()
369
- assert.strictEqual(tools.length, 1)
370
- assert.strictEqual(tools[0].name, 'incomplete-tool')
371
- assert.strictEqual(tools[0].title, null)
372
- assert.strictEqual(tools[0].description, undefined)
373
- })
374
-
375
- test('should handle non-array values for tools/resources/prompts', async () => {
376
- const mockData = {
377
- tools: 'not an array',
378
- resources: null,
379
- prompts: undefined,
380
- }
381
-
382
- await registry.loadFromMCPJson(mockData)
383
-
384
- assert.deepStrictEqual(registry.getTools(), [])
385
- assert.deepStrictEqual(registry.getResources(), [])
386
- assert.deepStrictEqual(registry.getPrompts(), [])
387
- })
388
- })
389
- })
@@ -1,159 +0,0 @@
1
- import type {
2
- MCPResourceMeta,
3
- MCPToolMeta,
4
- MCPPromptMeta,
5
- } from '@pikku/core/mcp'
6
-
7
- export interface MCPToolEndpoint {
8
- name: string
9
- title: string
10
- description: string
11
- inputSchema?: any
12
- outputSchema?: any
13
- enabled: boolean
14
- }
15
-
16
- export interface MCPResourceEndpoint {
17
- uri: string
18
- title: string
19
- description: string
20
- inputSchema?: any
21
- mimeType?: string
22
- enabled: boolean
23
- }
24
-
25
- export interface MCPPromptEndpoint {
26
- name: string
27
- description: string
28
- inputSchema?: any
29
- enabled: boolean
30
- }
31
-
32
- export class MCPEndpointRegistry {
33
- private tools: Map<string, MCPToolEndpoint> = new Map()
34
- private resources: Map<string, MCPResourceEndpoint> = new Map()
35
- private prompts: Map<string, MCPPromptEndpoint> = new Map()
36
- private resourcesMeta: MCPResourceMeta = {}
37
- private toolsMeta: MCPToolMeta = {}
38
- private promptsMeta: MCPPromptMeta = {}
39
-
40
- async loadFromMCPJson(mcpData: any): Promise<void> {
41
- if (mcpData.tools && Array.isArray(mcpData.tools)) {
42
- for (const tool of mcpData.tools) {
43
- this.tools.set(tool.name, {
44
- name: tool.name,
45
- title: tool.title,
46
- description: tool.description,
47
- inputSchema: tool.parameters ?? { type: 'object' },
48
- outputSchema: tool.returns,
49
- enabled: tool.enabled !== undefined ? tool.enabled : true,
50
- })
51
- }
52
- }
53
- if (mcpData.resources && Array.isArray(mcpData.resources)) {
54
- for (const resource of mcpData.resources) {
55
- this.resources.set(resource.name, {
56
- title: resource.name,
57
- uri: resource.uri,
58
- description: resource.description,
59
- inputSchema: resource.parameters,
60
- enabled: resource.enabled !== undefined ? resource.enabled : true,
61
- })
62
- }
63
- }
64
- if (mcpData.prompts && Array.isArray(mcpData.prompts)) {
65
- for (const prompt of mcpData.prompts) {
66
- this.prompts.set(prompt.name, {
67
- name: prompt.name,
68
- description: prompt.description,
69
- inputSchema: prompt.arguments,
70
- enabled: prompt.enabled !== undefined ? prompt.enabled : true,
71
- })
72
- }
73
- }
74
- }
75
-
76
- setResourcesMeta(meta: MCPResourceMeta): void {
77
- this.resourcesMeta = meta
78
- }
79
-
80
- setToolsMeta(meta: MCPToolMeta): void {
81
- this.toolsMeta = meta
82
- }
83
-
84
- setPromptsMeta(meta: MCPPromptMeta): void {
85
- this.promptsMeta = meta
86
- }
87
-
88
- getTools(): MCPToolEndpoint[] {
89
- return Array.from(this.tools.values()).filter((tool) => tool.enabled)
90
- }
91
-
92
- getResources(): MCPResourceEndpoint[] {
93
- return Array.from(this.resources.values())
94
- }
95
-
96
- getPrompts(): MCPPromptEndpoint[] {
97
- return Array.from(this.prompts.values())
98
- }
99
-
100
- getTool(name: string): MCPToolEndpoint | undefined {
101
- return this.tools.get(name)
102
- }
103
-
104
- getResource(name: string): MCPResourceEndpoint | undefined {
105
- return this.resources.get(name)
106
- }
107
-
108
- getPrompt(name: string): MCPPromptEndpoint | undefined {
109
- return this.prompts.get(name)
110
- }
111
-
112
- hasResource(name: string): boolean {
113
- return name in this.resourcesMeta
114
- }
115
-
116
- hasTool(name: string): boolean {
117
- return name in this.toolsMeta
118
- }
119
-
120
- hasPrompt(name: string): boolean {
121
- return name in this.promptsMeta
122
- }
123
-
124
- enableTools(tools: Record<any, boolean>): boolean {
125
- let changed = false
126
- for (const [name, enabled] of Object.entries(tools)) {
127
- const tool = this.tools.get(name)
128
- if (tool && tool.enabled !== enabled) {
129
- tool.enabled = enabled
130
- changed = true
131
- }
132
- }
133
- return changed
134
- }
135
-
136
- enablePrompts(prompts: Record<any, boolean>): boolean {
137
- let changed = false
138
- for (const [name, enabled] of Object.entries(prompts)) {
139
- const prompt = this.prompts.get(name)
140
- if (prompt && prompt.enabled !== enabled) {
141
- prompt.enabled = enabled
142
- changed = true
143
- }
144
- }
145
- return changed
146
- }
147
-
148
- enableResources(resources: Record<any, boolean>): boolean {
149
- let changed = false
150
- for (const [name, enabled] of Object.entries(resources)) {
151
- const resource = this.resources.get(name)
152
- if (resource && resource.enabled !== enabled) {
153
- resource.enabled = enabled
154
- changed = true
155
- }
156
- }
157
- return changed
158
- }
159
- }