@pikku/core 0.9.11 → 0.10.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 (124) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/errors/errors.d.ts +2 -0
  3. package/dist/errors/errors.js +6 -0
  4. package/dist/function/function-runner.d.ts +15 -9
  5. package/dist/function/function-runner.js +55 -37
  6. package/dist/function/functions.types.d.ts +67 -1
  7. package/dist/function/functions.types.js +43 -1
  8. package/dist/index.d.ts +2 -6
  9. package/dist/index.js +2 -6
  10. package/dist/middleware/auth-apikey.d.ts +19 -11
  11. package/dist/middleware/auth-apikey.js +33 -33
  12. package/dist/middleware/auth-bearer.d.ts +34 -7
  13. package/dist/middleware/auth-bearer.js +53 -36
  14. package/dist/middleware/auth-cookie.d.ts +30 -12
  15. package/dist/middleware/auth-cookie.js +51 -43
  16. package/dist/middleware/timeout.d.ts +6 -2
  17. package/dist/middleware/timeout.js +7 -9
  18. package/dist/middleware-runner.d.ts +46 -43
  19. package/dist/middleware-runner.js +100 -69
  20. package/dist/permissions.d.ts +82 -20
  21. package/dist/permissions.js +176 -62
  22. package/dist/pikku-state.d.ts +46 -1
  23. package/dist/pikku-state.js +16 -1
  24. package/dist/services/content-service.d.ts +2 -3
  25. package/dist/services/index.d.ts +0 -1
  26. package/dist/services/index.js +0 -1
  27. package/dist/services/local-content.d.ts +2 -4
  28. package/dist/types/core.types.d.ts +110 -4
  29. package/dist/types/core.types.js +44 -1
  30. package/dist/utils.d.ts +1 -1
  31. package/dist/wirings/channel/channel-handler.d.ts +2 -2
  32. package/dist/wirings/channel/channel-handler.js +16 -12
  33. package/dist/wirings/channel/channel-runner.d.ts +2 -2
  34. package/dist/wirings/channel/channel-runner.js +6 -24
  35. package/dist/wirings/channel/channel.types.d.ts +15 -14
  36. package/dist/wirings/channel/local/local-channel-runner.js +12 -12
  37. package/dist/wirings/channel/serverless/serverless-channel-runner.js +7 -8
  38. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +12 -0
  39. package/dist/wirings/cli/channel/cli-channel-runner.js +83 -0
  40. package/dist/wirings/cli/channel/index.d.ts +1 -0
  41. package/dist/wirings/cli/channel/index.js +1 -0
  42. package/dist/wirings/cli/cli-runner.d.ts +42 -0
  43. package/dist/wirings/cli/cli-runner.js +352 -0
  44. package/dist/wirings/cli/cli.types.d.ts +204 -0
  45. package/dist/wirings/cli/cli.types.js +1 -0
  46. package/dist/wirings/cli/command-parser.d.ts +19 -0
  47. package/dist/wirings/cli/command-parser.js +403 -0
  48. package/dist/wirings/cli/index.d.ts +5 -0
  49. package/dist/wirings/cli/index.js +5 -0
  50. package/dist/wirings/http/http-runner.d.ts +59 -10
  51. package/dist/wirings/http/http-runner.js +138 -131
  52. package/dist/wirings/http/http.types.d.ts +11 -10
  53. package/dist/wirings/http/index.d.ts +1 -1
  54. package/dist/wirings/http/index.js +1 -1
  55. package/dist/wirings/http/pikku-fetch-http-response.js +3 -1
  56. package/dist/wirings/http/routers/http-router.d.ts +0 -2
  57. package/dist/wirings/http/routers/path-to-regex.d.ts +1 -1
  58. package/dist/wirings/http/routers/path-to-regex.js +5 -34
  59. package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
  60. package/dist/wirings/mcp/mcp-runner.d.ts +4 -5
  61. package/dist/wirings/mcp/mcp-runner.js +32 -34
  62. package/dist/wirings/mcp/mcp.types.d.ts +38 -14
  63. package/dist/wirings/queue/queue-runner.d.ts +2 -2
  64. package/dist/wirings/queue/queue-runner.js +25 -27
  65. package/dist/wirings/queue/queue.types.d.ts +6 -5
  66. package/dist/wirings/rpc/index.d.ts +1 -1
  67. package/dist/wirings/rpc/index.js +1 -1
  68. package/dist/wirings/rpc/rpc-runner.d.ts +6 -18
  69. package/dist/wirings/rpc/rpc-runner.js +13 -8
  70. package/dist/wirings/scheduler/scheduler-runner.d.ts +2 -2
  71. package/dist/wirings/scheduler/scheduler-runner.js +38 -35
  72. package/dist/wirings/scheduler/scheduler.types.d.ts +5 -4
  73. package/package.json +9 -7
  74. package/src/errors/errors.ts +6 -0
  75. package/src/factory-functions.test.ts +60 -1
  76. package/src/function/function-runner.test.ts +81 -26
  77. package/src/function/function-runner.ts +89 -57
  78. package/src/function/functions.types.ts +85 -2
  79. package/src/index.ts +6 -19
  80. package/src/middleware/auth-apikey.ts +42 -57
  81. package/src/middleware/auth-bearer.ts +66 -49
  82. package/src/middleware/auth-cookie.ts +63 -82
  83. package/src/middleware/timeout.ts +10 -14
  84. package/src/middleware-runner.test.ts +24 -16
  85. package/src/middleware-runner.ts +115 -87
  86. package/src/permissions.test.ts +26 -27
  87. package/src/permissions.ts +216 -104
  88. package/src/pikku-state.ts +79 -2
  89. package/src/services/content-service.ts +5 -4
  90. package/src/services/index.ts +0 -1
  91. package/src/services/local-content.ts +9 -4
  92. package/src/types/core.types.ts +143 -5
  93. package/src/utils.ts +1 -1
  94. package/src/wirings/channel/channel-handler.ts +18 -21
  95. package/src/wirings/channel/channel-runner.ts +19 -32
  96. package/src/wirings/channel/channel.types.ts +29 -16
  97. package/src/wirings/channel/local/local-channel-runner.ts +25 -15
  98. package/src/wirings/channel/serverless/serverless-channel-runner.ts +15 -17
  99. package/src/wirings/cli/channel/cli-channel-runner.ts +123 -0
  100. package/src/wirings/cli/channel/index.ts +1 -0
  101. package/src/wirings/cli/cli-runner.test.ts +403 -0
  102. package/src/wirings/cli/cli-runner.ts +539 -0
  103. package/src/wirings/cli/cli.types.ts +350 -0
  104. package/src/wirings/cli/command-parser.test.ts +445 -0
  105. package/src/wirings/cli/command-parser.ts +504 -0
  106. package/src/wirings/cli/index.ts +13 -0
  107. package/src/wirings/http/http-runner.test.ts +8 -7
  108. package/src/wirings/http/http-runner.ts +165 -158
  109. package/src/wirings/http/http.types.ts +58 -11
  110. package/src/wirings/http/index.ts +7 -1
  111. package/src/wirings/http/pikku-fetch-http-response.ts +3 -1
  112. package/src/wirings/http/routers/http-router.ts +0 -2
  113. package/src/wirings/http/routers/path-to-regex.test.ts +4 -5
  114. package/src/wirings/http/routers/path-to-regex.ts +6 -43
  115. package/src/wirings/mcp/mcp-endpoint-registry.ts +1 -1
  116. package/src/wirings/mcp/mcp-runner.ts +58 -55
  117. package/src/wirings/mcp/mcp.types.ts +65 -14
  118. package/src/wirings/queue/queue-runner.ts +44 -47
  119. package/src/wirings/queue/queue.types.ts +10 -6
  120. package/src/wirings/rpc/index.ts +1 -1
  121. package/src/wirings/rpc/rpc-runner.ts +27 -9
  122. package/src/wirings/scheduler/scheduler-runner.ts +58 -56
  123. package/src/wirings/scheduler/scheduler.types.ts +10 -3
  124. package/tsconfig.tsbuildinfo +1 -1
@@ -2,35 +2,31 @@ import { match, MatchFunction } from 'path-to-regexp'
2
2
  import { MatchResult, Router } from './http-router.js'
3
3
  import { HTTPMethod } from '../http.types.js'
4
4
  import { pikkuState } from '../../../pikku-state.js'
5
- import { CorePikkuMiddleware } from '../../../types/core.types.js'
6
5
 
7
6
  interface CompiledRoute {
8
7
  matcher: MatchFunction<Partial<Record<string, string | string[]>>>
9
8
  route: string
10
- middleware: CorePikkuMiddleware[]
11
9
  }
12
10
 
13
11
  interface StaticRoute {
14
12
  route: string
15
- middleware: CorePikkuMiddleware[]
16
13
  }
17
14
 
18
15
  export class PathToRegexRouter implements Router {
19
16
  private compiledRoutes: Map<HTTPMethod, Map<string, CompiledRoute>> =
20
17
  new Map()
21
18
  private staticRoutes: Map<HTTPMethod, Map<string, StaticRoute>> = new Map()
22
- private precompiledMiddleware: Map<string, CorePikkuMiddleware[]> = new Map()
23
19
  private isInitialized = false
24
20
 
21
+ public reset() {
22
+ this.compiledRoutes = new Map()
23
+ this.staticRoutes = new Map()
24
+ this.isInitialized = false
25
+ }
26
+
25
27
  public initialize() {
26
28
  const routes = pikkuState('http', 'routes')
27
29
  const channelRoutes = pikkuState('channel', 'channels')
28
- const middlewareMap = pikkuState('http', 'middleware')
29
-
30
- // Precompile middleware lookups
31
- for (const [middlewareRoute, middlewareArray] of middlewareMap.entries()) {
32
- this.precompiledMiddleware.set(middlewareRoute, middlewareArray)
33
- }
34
30
 
35
31
  // Helper function to compile routes for a given method
36
32
  const compileRoutesForMethod = (
@@ -51,40 +47,10 @@ export class PathToRegexRouter implements Router {
51
47
  // Check if route is static (no parameters or wildcards)
52
48
  const isStaticRoute = !/\*|:/.test(normalizedRoutePath)
53
49
 
54
- // Precompute middleware for this route
55
- const routeMiddleware: CorePikkuMiddleware[] = []
56
-
57
- // Add global middleware (*)
58
- const globalMiddleware = this.precompiledMiddleware.get('*')
59
- if (globalMiddleware) {
60
- routeMiddleware.push(...globalMiddleware)
61
- }
62
-
63
- // Add route-specific middleware
64
- for (const [
65
- middlewareRoute,
66
- middlewareArray,
67
- ] of this.precompiledMiddleware.entries()) {
68
- if (middlewareRoute !== '*') {
69
- // Use regex test for pattern matching
70
- try {
71
- if (new RegExp(middlewareRoute).test(normalizedRoutePath)) {
72
- routeMiddleware.push(...middlewareArray)
73
- }
74
- } catch {
75
- // If regex is invalid, do exact match
76
- if (middlewareRoute === normalizedRoutePath) {
77
- routeMiddleware.push(...middlewareArray)
78
- }
79
- }
80
- }
81
- }
82
-
83
50
  if (isStaticRoute) {
84
51
  // Store static routes for O(1) lookup
85
52
  methodStaticRoutes.set(normalizedRoutePath, {
86
53
  route: routePath, // Keep the original route path for lookup in pikkuState
87
- middleware: routeMiddleware,
88
54
  })
89
55
  } else {
90
56
  // Compile dynamic routes with path-to-regexp
@@ -95,7 +61,6 @@ export class PathToRegexRouter implements Router {
95
61
  methodCompiledRoutes.set(normalizedRoutePath, {
96
62
  matcher,
97
63
  route: routePath, // Keep the original route path for lookup in pikkuState
98
- middleware: routeMiddleware,
99
64
  })
100
65
  }
101
66
  }
@@ -134,7 +99,6 @@ export class PathToRegexRouter implements Router {
134
99
  return {
135
100
  route: staticRoute.route,
136
101
  params: {},
137
- middleware: staticRoute.middleware,
138
102
  }
139
103
  }
140
104
  }
@@ -152,7 +116,6 @@ export class PathToRegexRouter implements Router {
152
116
  return {
153
117
  route: compiledRoute.route,
154
118
  params: result.params,
155
- middleware: compiledRoute.middleware,
156
119
  }
157
120
  }
158
121
  }
@@ -1,4 +1,4 @@
1
- import { MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from '@pikku/core'
1
+ import { MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from '@pikku/core/mcp'
2
2
 
3
3
  export interface MCPToolEndpoint {
4
4
  name: string
@@ -1,4 +1,5 @@
1
1
  import {
2
+ PikkuInteraction,
2
3
  PikkuWiringTypes,
3
4
  type CoreServices,
4
5
  type CoreSingletonServices,
@@ -14,14 +15,16 @@ import type {
14
15
  JsonRpcErrorResponse,
15
16
  PikkuMCP,
16
17
  } from './mcp.types.js'
17
- import type { CorePikkuFunctionSessionless } from '../../function/functions.types.js'
18
+ import type {
19
+ CorePikkuFunctionConfig,
20
+ CorePikkuFunctionSessionless,
21
+ } from '../../function/functions.types.js'
18
22
  import { getErrorResponse } from '../../errors/error-handler.js'
19
23
  import { closeSessionServices } from '../../utils.js'
20
24
  import { pikkuState } from '../../pikku-state.js'
21
25
  import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
22
26
  import { rpcService } from '../rpc/rpc-runner.js'
23
27
  import { BadRequestError, NotFoundError } from '../../errors/errors.js'
24
- import { combineMiddleware, runMiddleware } from '../../middleware-runner.js'
25
28
 
26
29
  export class MCPError extends Error {
27
30
  constructor(public readonly error: JsonRpcErrorResponse) {
@@ -32,7 +35,6 @@ export class MCPError extends Error {
32
35
  }
33
36
 
34
37
  export type RunMCPEndpointParams<Tools extends string = any> = {
35
- session?: CoreUserSession
36
38
  singletonServices: CoreSingletonServices
37
39
  mcp?: PikkuMCP<Tools>
38
40
  createSessionServices?: CreateSessionServices<
@@ -49,16 +51,18 @@ export type JsonRpcError = {
49
51
  }
50
52
 
51
53
  export const wireMCPResource = <
52
- PikkuFunction extends CorePikkuFunctionSessionless<any, any>,
54
+ PikkuFunctionConfig extends CorePikkuFunctionConfig<
55
+ CorePikkuFunctionSessionless<any, any>
56
+ > = CorePikkuFunctionConfig<CorePikkuFunctionSessionless<any, any>>,
53
57
  >(
54
- mcpResource: CoreMCPResource<PikkuFunction>
58
+ mcpResource: CoreMCPResource<PikkuFunctionConfig>
55
59
  ) => {
56
60
  const resourcesMeta = pikkuState('mcp', 'resourcesMeta')
57
61
  const mcpResourceMeta = resourcesMeta[mcpResource.uri]
58
62
  if (!mcpResourceMeta) {
59
63
  throw new Error(`MCP resource metadata not found for '${mcpResource.uri}'`)
60
64
  }
61
- addFunction(mcpResourceMeta.pikkuFuncName, mcpResource.func)
65
+ addFunction(mcpResourceMeta.pikkuFuncName, mcpResource)
62
66
  const resources = pikkuState('mcp', 'resources')
63
67
  if (resources.has(mcpResource.uri)) {
64
68
  throw new Error(`MCP resource already exists: ${mcpResource.uri}`)
@@ -67,9 +71,11 @@ export const wireMCPResource = <
67
71
  }
68
72
 
69
73
  export const wireMCPTool = <
70
- PikkuFunction extends CorePikkuFunctionSessionless<any, any>,
74
+ PikkuFunctionConfig extends CorePikkuFunctionConfig<
75
+ CorePikkuFunctionSessionless<any, any>
76
+ > = CorePikkuFunctionConfig<CorePikkuFunctionSessionless<any, any>>,
71
77
  >(
72
- mcpTool: CoreMCPTool<PikkuFunction>
78
+ mcpTool: CoreMCPTool<PikkuFunctionConfig>
73
79
  ) => {
74
80
  const toolsMeta = pikkuState('mcp', 'toolsMeta')
75
81
  const mcpToolMeta = toolsMeta[mcpTool.name]
@@ -85,9 +91,11 @@ export const wireMCPTool = <
85
91
  }
86
92
 
87
93
  export const wireMCPPrompt = <
88
- PikkuFunction extends CorePikkuFunctionSessionless<any, any>,
94
+ PikkuFunctionConfig extends CorePikkuFunctionConfig<
95
+ CorePikkuFunctionSessionless<any, any>
96
+ > = CorePikkuFunctionConfig<CorePikkuFunctionSessionless<any, any>>,
89
97
  >(
90
- mcpPrompt: CoreMCPPrompt<PikkuFunction>
98
+ mcpPrompt: CoreMCPPrompt<PikkuFunctionConfig>
91
99
  ) => {
92
100
  const promptsMeta = pikkuState('mcp', 'promptsMeta')
93
101
  const mcpPromptMeta = promptsMeta[mcpPrompt.name]
@@ -200,10 +208,9 @@ async function runMCPPikkuFunc(
200
208
  mcp: CoreMCPResource | CoreMCPTool | CoreMCPPrompt | undefined,
201
209
  pikkuFuncName: string | undefined,
202
210
  {
203
- session,
204
211
  singletonServices,
205
212
  createSessionServices,
206
- mcp: interaction,
213
+ mcp: mcpInteraction,
207
214
  }: RunMCPEndpointParams
208
215
  ): Promise<JsonRpcResponse> {
209
216
  let sessionServices: any
@@ -230,54 +237,50 @@ async function runMCPPikkuFunc(
230
237
 
231
238
  singletonServices.logger.debug(`Running MCP ${type}: ${name}`)
232
239
 
233
- let result: any
234
-
235
- // Main MCP execution logic wrapped for middleware handling
236
- const runMain = async () => {
237
- const getAllServices = async () => {
238
- if (createSessionServices) {
239
- const services = await createSessionServices(
240
- singletonServices,
241
- { mcp: interaction },
242
- session
243
- )
244
- sessionServices = services
245
- return rpcService.injectRPCService({
246
- ...singletonServices,
247
- ...services,
248
- mcp: interaction,
249
- })
250
- }
251
- return rpcService.injectRPCService({
252
- ...singletonServices,
253
- mcp: interaction,
254
- })
255
- }
240
+ const interaction: PikkuInteraction = { mcp: mcpInteraction }
241
+
242
+ const getAllServices = async () => {
243
+ sessionServices = await createSessionServices?.(
244
+ singletonServices,
245
+ interaction,
246
+ undefined
247
+ )
256
248
 
257
- result = await runPikkuFunc(
258
- PikkuWiringTypes.mcp,
259
- `${type}:${name}`,
260
- pikkuFuncName,
249
+ return rpcService.injectRPCService(
261
250
  {
262
- getAllServices,
263
- session,
264
- data: request.params,
265
- tags: mcp.tags,
266
- }
251
+ ...singletonServices,
252
+ ...sessionServices,
253
+ },
254
+ interaction
267
255
  )
268
256
  }
269
257
 
270
- const funcConfig = pikkuState('function', 'functions').get(pikkuFuncName!)
271
- await runMiddleware(
272
- singletonServices,
273
- { mcp: interaction },
274
- combineMiddleware(PikkuWiringTypes.mcp, `${type}:${name}`, {
275
- wiringMiddleware: mcp.middleware,
276
- wiringTags: mcp.tags,
277
- funcMiddleware: funcConfig?.middleware,
278
- funcTags: funcConfig?.tags,
279
- }),
280
- runMain
258
+ // Get metadata for the MCP endpoint to access pre-resolved middleware
259
+ let meta: any
260
+ if (type === 'resource') {
261
+ meta = pikkuState('mcp', 'resourcesMeta')[name]
262
+ } else if (type === 'tool') {
263
+ meta = pikkuState('mcp', 'toolsMeta')[name]
264
+ } else if (type === 'prompt') {
265
+ meta = pikkuState('mcp', 'promptsMeta')[name]
266
+ }
267
+
268
+ const result = await runPikkuFunc(
269
+ PikkuWiringTypes.mcp,
270
+ `${type}:${name}`,
271
+ pikkuFuncName,
272
+ {
273
+ singletonServices,
274
+ getAllServices,
275
+ userSession: undefined, // TODO
276
+ data: () => request.params,
277
+ inheritedMiddleware: meta?.middleware,
278
+ wireMiddleware: mcp.middleware,
279
+ inheritedPermissions: meta?.permissions,
280
+ wirePermissions: mcp.permissions,
281
+ tags: mcp.tags,
282
+ interaction,
283
+ }
281
284
  )
282
285
 
283
286
  return {
@@ -1,5 +1,39 @@
1
- import { CorePikkuFunctionSessionless } from '../../function/functions.types.js'
2
- import { CorePikkuMiddleware } from '../../types/core.types.js'
1
+ import {
2
+ CorePermissionGroup,
3
+ CorePikkuFunctionConfig,
4
+ CorePikkuFunctionSessionless,
5
+ CorePikkuPermission,
6
+ } from '../../function/functions.types.js'
7
+ import {
8
+ CorePikkuMiddleware,
9
+ MiddlewareMetadata,
10
+ PermissionMetadata,
11
+ } from '../../types/core.types.js'
12
+
13
+ /**
14
+ * Extract URI parameters from MCP resource URI template.
15
+ * E.g., "user/{userId}/post/{postId}" => "userId" | "postId"
16
+ */
17
+ type ExtractMCPURIParams<S extends string> =
18
+ S extends `${string}{${infer Param}}/${infer Rest}`
19
+ ? Param | ExtractMCPURIParams<Rest>
20
+ : S extends `${string}{${infer Param}}`
21
+ ? Param
22
+ : never
23
+
24
+ /**
25
+ * Type-level assertion that MCP resource URI parameters are present in the input type.
26
+ * This ensures compile-time safety for URI parameter validation.
27
+ */
28
+ export type AssertMCPResourceURIParams<In, URI extends string> =
29
+ ExtractMCPURIParams<URI> extends keyof In
30
+ ? unknown
31
+ : [
32
+ 'Error: MCP Resource URI parameters',
33
+ ExtractMCPURIParams<URI>,
34
+ 'not in input type',
35
+ keyof In,
36
+ ]
3
37
 
4
38
  export type PikkuMCP<Tools extends string = any> = {
5
39
  // elicitInput: <Input>(message: string) => Promise<{ action: string, content: Input }>
@@ -15,10 +49,12 @@ export type PikkuMCP<Tools extends string = any> = {
15
49
  */
16
50
  export type MCPResourceMeta = Record<
17
51
  string,
18
- Omit<CoreMCPResource, 'func'> & {
52
+ Omit<CoreMCPResource, 'func' | 'middleware' | 'permissions'> & {
19
53
  pikkuFuncName: string
20
54
  inputSchema: string | null
21
55
  outputSchema: string | null
56
+ middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
57
+ permissions?: PermissionMetadata[] // Pre-resolved permission chain (tag + explicit)
22
58
  }
23
59
  >
24
60
 
@@ -27,10 +63,12 @@ export type MCPResourceMeta = Record<
27
63
  */
28
64
  export type MCPToolMeta = Record<
29
65
  string,
30
- Omit<CoreMCPTool, 'func'> & {
66
+ Omit<CoreMCPTool, 'func' | 'middleware' | 'permissions'> & {
31
67
  pikkuFuncName: string
32
68
  inputSchema: string | null
33
69
  outputSchema: string | null
70
+ middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
71
+ permissions?: PermissionMetadata[] // Pre-resolved permission chain (tag + explicit)
34
72
  }
35
73
  >
36
74
 
@@ -39,7 +77,7 @@ export type MCPToolMeta = Record<
39
77
  */
40
78
  export type MCPPromptMeta = Record<
41
79
  string,
42
- Omit<CoreMCPPrompt, 'func'> & {
80
+ Omit<CoreMCPPrompt, 'func' | 'middleware' | 'permissions'> & {
43
81
  pikkuFuncName: string
44
82
  inputSchema: string | null
45
83
  outputSchema: string | null
@@ -48,6 +86,8 @@ export type MCPPromptMeta = Record<
48
86
  description: string
49
87
  required: boolean
50
88
  }>
89
+ middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
90
+ permissions?: PermissionMetadata[] // Pre-resolved permission chain (tag + explicit)
51
91
  }
52
92
  >
53
93
 
@@ -55,49 +95,60 @@ export type MCPPromptMeta = Record<
55
95
  * Represents an MCP resource with specific properties.
56
96
  */
57
97
  export type CoreMCPResource<
58
- PikkuFunction = CorePikkuFunctionSessionless<any, any>,
98
+ PikkuFunctionConfig = CorePikkuFunctionConfig<
99
+ CorePikkuFunctionSessionless<any, any>
100
+ >,
101
+ PikkuPermission = CorePikkuPermission<any, any>,
59
102
  PikkuMiddleware = CorePikkuMiddleware<any>,
60
103
  > = {
61
104
  uri: string
62
105
  title: string
63
- description?: string
106
+ description: string
64
107
  mimeType?: string
65
108
  size?: number
66
109
  streaming?: boolean
67
- func: PikkuFunction
110
+ func: PikkuFunctionConfig
68
111
  tags?: string[]
69
112
  middleware?: PikkuMiddleware[]
113
+ permissions?: CorePermissionGroup<PikkuPermission>
70
114
  }
71
115
 
72
116
  /**
73
117
  * Represents an MCP tool with specific properties.
74
118
  */
75
119
  export type CoreMCPTool<
76
- PikkuFunction = CorePikkuFunctionSessionless<any, any>,
120
+ PikkuFunctionConfig = CorePikkuFunctionConfig<
121
+ CorePikkuFunctionSessionless<any, any>
122
+ >,
123
+ PikkuPermission = CorePikkuPermission<any, any>,
77
124
  PikkuMiddleware = CorePikkuMiddleware<any>,
78
125
  > = {
79
126
  name: string
80
127
  title?: string
81
128
  description: string
82
- annotations?: Record<string, any>
83
- func: PikkuFunction
129
+ func: PikkuFunctionConfig
84
130
  tags?: string[]
85
131
  streaming?: boolean
86
132
  middleware?: PikkuMiddleware[]
133
+ permissions?: CorePermissionGroup<PikkuPermission>
87
134
  }
88
135
 
89
136
  /**
90
137
  * Represents an MCP prompt with specific properties.
91
138
  */
92
139
  export type CoreMCPPrompt<
93
- PikkuFunction = CorePikkuFunctionSessionless<any, MCPPromptResponse>,
140
+ PikkuFunctionConfig = CorePikkuFunctionConfig<
141
+ CorePikkuFunctionSessionless<any, MCPPromptResponse>
142
+ >,
143
+ PikkuPermission = CorePikkuPermission<any, any>,
94
144
  PikkuMiddleware = CorePikkuMiddleware<any>,
95
145
  > = {
96
146
  name: string
97
- description?: string
98
- func: PikkuFunction
147
+ description: string
148
+ func: PikkuFunctionConfig
99
149
  tags?: string[]
100
150
  middleware?: PikkuMiddleware[]
151
+ permissions?: CorePermissionGroup<PikkuPermission>
101
152
  }
102
153
 
103
154
  export type JsonRpcRequest = {
@@ -1,6 +1,9 @@
1
1
  import type { CoreServices } from '../../types/core.types.js'
2
2
  import type { CoreQueueWorker, QueueJob, PikkuQueue } from './queue.types.js'
3
- import type { CorePikkuFunctionSessionless } from '../../function/functions.types.js'
3
+ import type {
4
+ CorePikkuFunctionConfig,
5
+ CorePikkuFunctionSessionless,
6
+ } from '../../function/functions.types.js'
4
7
  import { getErrorResponse, PikkuError } from '../../errors/error-handler.js'
5
8
  import { pikkuState } from '../../pikku-state.js'
6
9
  import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
@@ -8,7 +11,6 @@ import {
8
11
  CreateSessionServices,
9
12
  PikkuWiringTypes,
10
13
  } from '../../types/core.types.js'
11
- import { combineMiddleware, runMiddleware } from '../../middleware-runner.js'
12
14
 
13
15
  /**
14
16
  * Error class for queue processor not found
@@ -44,12 +46,13 @@ export class QueueJobDiscardedError extends PikkuError {
44
46
  export const wireQueueWorker = <
45
47
  InputData = any,
46
48
  OutputData = any,
47
- PikkuFunction extends CorePikkuFunctionSessionless<
48
- InputData,
49
- OutputData
50
- > = CorePikkuFunctionSessionless<InputData, OutputData>,
49
+ PikkuFunctionConfig extends CorePikkuFunctionConfig<
50
+ CorePikkuFunctionSessionless<InputData, OutputData>
51
+ > = CorePikkuFunctionConfig<
52
+ CorePikkuFunctionSessionless<InputData, OutputData>
53
+ >,
51
54
  >(
52
- queueWorker: CoreQueueWorker<PikkuFunction>
55
+ queueWorker: CoreQueueWorker<PikkuFunctionConfig>
53
56
  ) => {
54
57
  // Get processor metadata
55
58
  const meta = pikkuState('queue', 'meta')
@@ -61,7 +64,14 @@ export const wireQueueWorker = <
61
64
  }
62
65
 
63
66
  // Register the function with pikku
64
- addFunction(processorMeta.pikkuFuncName, queueWorker.func)
67
+ addFunction(processorMeta.pikkuFuncName, {
68
+ func: queueWorker.func.func,
69
+ auth: queueWorker.func.auth,
70
+ permissions: queueWorker.func.permissions,
71
+ middleware: queueWorker.func.middleware as any,
72
+ tags: queueWorker.func.tags,
73
+ docs: queueWorker.func.docs as any,
74
+ })
65
75
 
66
76
  // Store processor definition in state - runtime adapters will pick this up
67
77
  const registrations = pikkuState('queue', 'registrations')
@@ -139,51 +149,38 @@ export async function runQueueJob({
139
149
  try {
140
150
  logger.info(`Processing job ${job.id} in queue ${job.queueName}`)
141
151
 
142
- let result: any
143
-
144
- // Main job execution logic wrapped for middleware handling
145
- const runMain = async () => {
146
- // Use provided singleton services
147
- const getAllServices = () => ({
148
- ...singletonServices,
149
- ...(createSessionServices
150
- ? createSessionServices(singletonServices, { queue }, undefined)
151
- : {}),
152
- })
153
-
154
- // Execute the pikku function with the job data
155
- result = await runPikkuFunc(
156
- PikkuWiringTypes.queue,
157
- job.queueName,
158
- processorMeta.pikkuFuncName,
159
- {
160
- getAllServices,
161
- data: job.data,
162
- tags: queueWorker.tags,
163
- }
152
+ // Use provided singleton services
153
+ const getAllServices = async () => {
154
+ const sessionServices = await createSessionServices?.(
155
+ singletonServices,
156
+ { queue },
157
+ undefined
164
158
  )
165
159
 
166
- logger.debug(
167
- `Successfully processed job ${job.id} in queue ${job.queueName}`
168
- )
160
+ return {
161
+ ...singletonServices,
162
+ ...sessionServices,
163
+ }
169
164
  }
170
165
 
171
- // Get function config for middleware and tags
172
- const funcConfig = pikkuState('function', 'functions').get(
173
- processorMeta.pikkuFuncName
166
+ // Execute the pikku function with the job data
167
+ const result = await runPikkuFunc(
168
+ PikkuWiringTypes.queue,
169
+ job.queueName,
170
+ processorMeta.pikkuFuncName,
171
+ {
172
+ singletonServices,
173
+ getAllServices,
174
+ data: () => job.data,
175
+ inheritedMiddleware: processorMeta.middleware,
176
+ wireMiddleware: queueWorker.middleware,
177
+ tags: queueWorker.tags,
178
+ interaction: { queue },
179
+ }
174
180
  )
175
181
 
176
- // Get middleware for tags and combine with queue-specific middleware
177
- await runMiddleware(
178
- singletonServices,
179
- { queue },
180
- combineMiddleware(PikkuWiringTypes.queue, `${job.queueName}:${job.id}`, {
181
- wiringMiddleware: queueWorker.middleware,
182
- wiringTags: queueWorker.tags,
183
- funcMiddleware: funcConfig?.middleware,
184
- funcTags: funcConfig?.tags,
185
- }),
186
- runMain
182
+ logger.debug(
183
+ `Successfully processed job ${job.id} in queue ${job.queueName}`
187
184
  )
188
185
 
189
186
  return result
@@ -1,5 +1,5 @@
1
- import { PikkuDocs, CorePikkuMiddleware } from '../../types/core.types.js'
2
- import { CorePikkuFunctionSessionless } from '../../function/functions.types.js'
1
+ import { PikkuDocs, MiddlewareMetadata } from '../../types/core.types.js'
2
+ import { CorePikkuFunctionConfig } from '../../function/functions.types.js'
3
3
  import { QueueConfigMapping } from './validate-worker-config.js'
4
4
 
5
5
  /**
@@ -158,6 +158,7 @@ export type queueWorkersMeta = Record<
158
158
  docs?: PikkuDocs
159
159
  tags?: string[]
160
160
  config?: PikkuWorkerConfig
161
+ middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
161
162
  }
162
163
  >
163
164
 
@@ -165,16 +166,19 @@ export type queueWorkersMeta = Record<
165
166
  * Core queue processor definition
166
167
  */
167
168
  export type CoreQueueWorker<
168
- PikkuFunction = CorePikkuFunctionSessionless<any, any>,
169
- PikkuMiddleware = CorePikkuMiddleware<any>,
169
+ PikkuFunctionConfig extends CorePikkuFunctionConfig<
170
+ any,
171
+ any,
172
+ any
173
+ > = CorePikkuFunctionConfig<any, any, any>,
170
174
  > = {
171
175
  queueName: string
172
- func: PikkuFunction
176
+ func: PikkuFunctionConfig
173
177
  config?: PikkuWorkerConfig
174
178
  docs?: PikkuDocs
175
179
  session?: undefined
176
180
  tags?: string[]
177
- middleware?: PikkuMiddleware[]
181
+ middleware?: PikkuFunctionConfig['middleware']
178
182
  }
179
183
 
180
184
  /**
@@ -1,2 +1,2 @@
1
- export { initialize } from './rpc-runner.js'
1
+ export { initialize, PikkuRPCService } from './rpc-runner.js'
2
2
  export type { PikkuRPC, RPCMeta } from './rpc-types.js'