@pikku/core 0.9.11 → 0.9.12-next.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 (99) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/function/function-runner.d.ts +13 -8
  3. package/dist/function/function-runner.js +49 -37
  4. package/dist/index.d.ts +3 -1
  5. package/dist/index.js +3 -1
  6. package/dist/middleware-runner.d.ts +61 -40
  7. package/dist/middleware-runner.js +118 -66
  8. package/dist/permissions.js +1 -0
  9. package/dist/pikku-state.d.ts +26 -1
  10. package/dist/pikku-state.js +10 -1
  11. package/dist/services/content-service.d.ts +2 -3
  12. package/dist/services/index.d.ts +0 -1
  13. package/dist/services/index.js +0 -1
  14. package/dist/services/local-content.d.ts +2 -4
  15. package/dist/types/core.types.d.ts +51 -2
  16. package/dist/types/core.types.js +21 -0
  17. package/dist/wirings/channel/channel-handler.d.ts +2 -2
  18. package/dist/wirings/channel/channel-handler.js +12 -9
  19. package/dist/wirings/channel/channel-runner.d.ts +0 -2
  20. package/dist/wirings/channel/channel-runner.js +2 -3
  21. package/dist/wirings/channel/channel.types.d.ts +5 -3
  22. package/dist/wirings/channel/local/local-channel-runner.js +12 -12
  23. package/dist/wirings/channel/serverless/serverless-channel-runner.js +7 -8
  24. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +12 -0
  25. package/dist/wirings/cli/channel/cli-channel-runner.js +80 -0
  26. package/dist/wirings/cli/channel/index.d.ts +1 -0
  27. package/dist/wirings/cli/channel/index.js +1 -0
  28. package/dist/wirings/cli/cli-runner.d.ts +32 -0
  29. package/dist/wirings/cli/cli-runner.js +328 -0
  30. package/dist/wirings/cli/cli.types.d.ts +177 -0
  31. package/dist/wirings/cli/cli.types.js +1 -0
  32. package/dist/wirings/cli/command-parser.d.ts +19 -0
  33. package/dist/wirings/cli/command-parser.js +373 -0
  34. package/dist/wirings/cli/index.d.ts +5 -0
  35. package/dist/wirings/cli/index.js +5 -0
  36. package/dist/wirings/http/http-runner.d.ts +29 -10
  37. package/dist/wirings/http/http-runner.js +103 -131
  38. package/dist/wirings/http/http.types.d.ts +10 -10
  39. package/dist/wirings/http/index.d.ts +1 -1
  40. package/dist/wirings/http/index.js +1 -1
  41. package/dist/wirings/http/pikku-fetch-http-response.js +3 -1
  42. package/dist/wirings/http/routers/http-router.d.ts +0 -2
  43. package/dist/wirings/http/routers/path-to-regex.d.ts +1 -1
  44. package/dist/wirings/http/routers/path-to-regex.js +5 -34
  45. package/dist/wirings/mcp/mcp-runner.d.ts +4 -5
  46. package/dist/wirings/mcp/mcp-runner.js +30 -34
  47. package/dist/wirings/mcp/mcp.types.d.ts +11 -8
  48. package/dist/wirings/queue/queue-runner.d.ts +2 -2
  49. package/dist/wirings/queue/queue-runner.js +25 -27
  50. package/dist/wirings/queue/queue.types.d.ts +6 -5
  51. package/dist/wirings/rpc/index.d.ts +1 -1
  52. package/dist/wirings/rpc/index.js +1 -1
  53. package/dist/wirings/rpc/rpc-runner.d.ts +6 -18
  54. package/dist/wirings/rpc/rpc-runner.js +13 -8
  55. package/dist/wirings/scheduler/scheduler-runner.d.ts +2 -2
  56. package/dist/wirings/scheduler/scheduler-runner.js +37 -35
  57. package/dist/wirings/scheduler/scheduler.types.d.ts +4 -3
  58. package/package.json +4 -3
  59. package/src/function/function-runner.test.ts +73 -23
  60. package/src/function/function-runner.ts +74 -55
  61. package/src/index.ts +8 -1
  62. package/src/middleware-runner.test.ts +24 -16
  63. package/src/middleware-runner.ts +136 -83
  64. package/src/permissions.ts +1 -0
  65. package/src/pikku-state.ts +47 -2
  66. package/src/services/content-service.ts +5 -4
  67. package/src/services/index.ts +0 -1
  68. package/src/services/local-content.ts +9 -4
  69. package/src/types/core.types.ts +74 -3
  70. package/src/wirings/channel/channel-handler.ts +9 -13
  71. package/src/wirings/channel/channel-runner.ts +2 -6
  72. package/src/wirings/channel/channel.types.ts +5 -1
  73. package/src/wirings/channel/local/local-channel-runner.ts +25 -15
  74. package/src/wirings/channel/serverless/serverless-channel-runner.ts +15 -17
  75. package/src/wirings/cli/channel/cli-channel-runner.ts +118 -0
  76. package/src/wirings/cli/channel/index.ts +1 -0
  77. package/src/wirings/cli/cli-runner.test.ts +382 -0
  78. package/src/wirings/cli/cli-runner.ts +503 -0
  79. package/src/wirings/cli/cli.types.ts +320 -0
  80. package/src/wirings/cli/command-parser.test.ts +440 -0
  81. package/src/wirings/cli/command-parser.ts +470 -0
  82. package/src/wirings/cli/index.ts +12 -0
  83. package/src/wirings/http/http-runner.test.ts +8 -7
  84. package/src/wirings/http/http-runner.ts +126 -159
  85. package/src/wirings/http/http.types.ts +56 -11
  86. package/src/wirings/http/index.ts +1 -1
  87. package/src/wirings/http/pikku-fetch-http-response.ts +3 -1
  88. package/src/wirings/http/routers/http-router.ts +0 -2
  89. package/src/wirings/http/routers/path-to-regex.test.ts +4 -5
  90. package/src/wirings/http/routers/path-to-regex.ts +6 -43
  91. package/src/wirings/mcp/mcp-runner.ts +56 -55
  92. package/src/wirings/mcp/mcp.types.ts +23 -8
  93. package/src/wirings/queue/queue-runner.ts +44 -47
  94. package/src/wirings/queue/queue.types.ts +10 -6
  95. package/src/wirings/rpc/index.ts +1 -1
  96. package/src/wirings/rpc/rpc-runner.ts +27 -9
  97. package/src/wirings/scheduler/scheduler-runner.ts +57 -56
  98. package/src/wirings/scheduler/scheduler.types.ts +9 -2
  99. 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,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,48 @@ 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
+ tags: mcp.tags,
280
+ interaction,
281
+ }
281
282
  )
282
283
 
283
284
  return {
@@ -1,5 +1,11 @@
1
- import { CorePikkuFunctionSessionless } from '../../function/functions.types.js'
2
- import { CorePikkuMiddleware } from '../../types/core.types.js'
1
+ import {
2
+ CorePikkuFunctionConfig,
3
+ CorePikkuFunctionSessionless,
4
+ } from '../../function/functions.types.js'
5
+ import {
6
+ CorePikkuMiddleware,
7
+ MiddlewareMetadata,
8
+ } from '../../types/core.types.js'
3
9
 
4
10
  export type PikkuMCP<Tools extends string = any> = {
5
11
  // elicitInput: <Input>(message: string) => Promise<{ action: string, content: Input }>
@@ -15,10 +21,11 @@ export type PikkuMCP<Tools extends string = any> = {
15
21
  */
16
22
  export type MCPResourceMeta = Record<
17
23
  string,
18
- Omit<CoreMCPResource, 'func'> & {
24
+ Omit<CoreMCPResource, 'func' | 'middleware'> & {
19
25
  pikkuFuncName: string
20
26
  inputSchema: string | null
21
27
  outputSchema: string | null
28
+ middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
22
29
  }
23
30
  >
24
31
 
@@ -27,10 +34,11 @@ export type MCPResourceMeta = Record<
27
34
  */
28
35
  export type MCPToolMeta = Record<
29
36
  string,
30
- Omit<CoreMCPTool, 'func'> & {
37
+ Omit<CoreMCPTool, 'func' | 'middleware'> & {
31
38
  pikkuFuncName: string
32
39
  inputSchema: string | null
33
40
  outputSchema: string | null
41
+ middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
34
42
  }
35
43
  >
36
44
 
@@ -39,7 +47,7 @@ export type MCPToolMeta = Record<
39
47
  */
40
48
  export type MCPPromptMeta = Record<
41
49
  string,
42
- Omit<CoreMCPPrompt, 'func'> & {
50
+ Omit<CoreMCPPrompt, 'func' | 'middleware'> & {
43
51
  pikkuFuncName: string
44
52
  inputSchema: string | null
45
53
  outputSchema: string | null
@@ -48,6 +56,7 @@ export type MCPPromptMeta = Record<
48
56
  description: string
49
57
  required: boolean
50
58
  }>
59
+ middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
51
60
  }
52
61
  >
53
62
 
@@ -55,7 +64,9 @@ export type MCPPromptMeta = Record<
55
64
  * Represents an MCP resource with specific properties.
56
65
  */
57
66
  export type CoreMCPResource<
58
- PikkuFunction = CorePikkuFunctionSessionless<any, any>,
67
+ PikkuFunction = CorePikkuFunctionConfig<
68
+ CorePikkuFunctionSessionless<any, any>
69
+ >,
59
70
  PikkuMiddleware = CorePikkuMiddleware<any>,
60
71
  > = {
61
72
  uri: string
@@ -73,7 +84,9 @@ export type CoreMCPResource<
73
84
  * Represents an MCP tool with specific properties.
74
85
  */
75
86
  export type CoreMCPTool<
76
- PikkuFunction = CorePikkuFunctionSessionless<any, any>,
87
+ PikkuFunction = CorePikkuFunctionConfig<
88
+ CorePikkuFunctionSessionless<any, any>
89
+ >,
77
90
  PikkuMiddleware = CorePikkuMiddleware<any>,
78
91
  > = {
79
92
  name: string
@@ -90,7 +103,9 @@ export type CoreMCPTool<
90
103
  * Represents an MCP prompt with specific properties.
91
104
  */
92
105
  export type CoreMCPPrompt<
93
- PikkuFunction = CorePikkuFunctionSessionless<any, MCPPromptResponse>,
106
+ PikkuFunction = CorePikkuFunctionConfig<
107
+ CorePikkuFunctionSessionless<any, MCPPromptResponse>
108
+ >,
94
109
  PikkuMiddleware = CorePikkuMiddleware<any>,
95
110
  > = {
96
111
  name: string
@@ -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'
@@ -1,7 +1,12 @@
1
- import { CoreServices, PikkuWiringTypes } from '../../types/core.types.js'
1
+ import {
2
+ CoreServices,
3
+ PikkuInteraction,
4
+ PikkuWiringTypes,
5
+ } from '../../types/core.types.js'
2
6
  import { runPikkuFunc } from '../../function/function-runner.js'
3
7
  import { pikkuState } from '../../pikku-state.js'
4
8
  import { ForbiddenError } from '../../errors/errors.js'
9
+ import { PikkuRPC } from './rpc-types.js'
5
10
 
6
11
  // Type for the RPC service configuration
7
12
  type RPCServiceConfig = {
@@ -21,8 +26,10 @@ const getPikkuFunctionName = (rpcName: string): string => {
21
26
  class ContextAwareRPCService {
22
27
  constructor(
23
28
  private services: CoreServices,
29
+ private interaction: PikkuInteraction,
24
30
  private options: {
25
31
  coerceDataFromSchema?: boolean
32
+ requiresAuth?: boolean
26
33
  }
27
34
  ) {}
28
35
 
@@ -41,7 +48,6 @@ class ContextAwareRPCService {
41
48
  funcName: string,
42
49
  data: In
43
50
  ): Promise<Out> {
44
- const session = await this.services.userSession?.get()
45
51
  const rpcDepth = this.services.rpc?.depth || 0
46
52
  const pikkuFuncName = getPikkuFunctionName(funcName)
47
53
  return runPikkuFunc<In, Out>(
@@ -49,6 +55,8 @@ class ContextAwareRPCService {
49
55
  pikkuFuncName,
50
56
  pikkuFuncName,
51
57
  {
58
+ auth: this.options.requiresAuth,
59
+ singletonServices: this.services,
52
60
  getAllServices: () => {
53
61
  this.services.rpc = this.services.rpc
54
62
  ? ({
@@ -59,16 +67,20 @@ class ContextAwareRPCService {
59
67
  : undefined
60
68
  return this.services
61
69
  },
62
- data,
63
- session,
70
+ data: () => data,
71
+ userSession: this.services.userSession,
64
72
  coerceDataFromSchema: this.options.coerceDataFromSchema,
73
+ interaction: this.interaction,
65
74
  }
66
75
  )
67
76
  }
68
77
  }
69
78
 
70
79
  // RPC Service class for the global interface
71
- export class PikkuRPCService {
80
+ export class PikkuRPCService<
81
+ Services extends CoreServices,
82
+ TypedRPC = PikkuRPC,
83
+ > {
72
84
  private config?: RPCServiceConfig
73
85
 
74
86
  // Initialize the RPC service with configuration
@@ -77,12 +89,18 @@ export class PikkuRPCService {
77
89
  }
78
90
 
79
91
  // Convenience function for initializing
80
- injectRPCService(coreServices: CoreServices, depth: number = 0) {
92
+ injectRPCService(
93
+ services: Services,
94
+ interaction: PikkuInteraction,
95
+ requiresAuth?: boolean | undefined,
96
+ depth: number = 0
97
+ ): Services & { rpc: TypedRPC } {
81
98
  const serviceCopy = {
82
- ...coreServices,
99
+ ...services,
83
100
  }
84
- const serviceRPC = new ContextAwareRPCService(serviceCopy, {
101
+ const serviceRPC = new ContextAwareRPCService(serviceCopy, interaction, {
85
102
  coerceDataFromSchema: this.config?.coerceDataFromSchema,
103
+ requiresAuth,
86
104
  })
87
105
  serviceCopy.rpc = {
88
106
  depth,
@@ -90,7 +108,7 @@ export class PikkuRPCService {
90
108
  invoke: serviceRPC.rpc.bind(serviceRPC),
91
109
  invokeExposed: serviceRPC.rpc.bind(serviceRPC),
92
110
  } as any
93
- return serviceCopy
111
+ return serviceCopy as Services & { rpc: TypedRPC }
94
112
  }
95
113
  }
96
114