@pikku/core 0.11.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/CHANGELOG.md +35 -1
  2. package/dist/errors/error-handler.js +3 -3
  3. package/dist/errors/errors.d.ts +1 -1
  4. package/dist/errors/errors.js +3 -3
  5. package/dist/function/function-runner.d.ts +8 -8
  6. package/dist/function/function-runner.js +88 -23
  7. package/dist/function/functions.types.d.ts +104 -33
  8. package/dist/function/functions.types.js +50 -7
  9. package/dist/handle-error.d.ts +1 -1
  10. package/dist/handle-error.js +1 -1
  11. package/dist/index.d.ts +6 -2
  12. package/dist/index.js +5 -2
  13. package/dist/middleware/auth-apikey.d.ts +1 -1
  14. package/dist/middleware/auth-apikey.js +3 -3
  15. package/dist/middleware/auth-bearer.d.ts +1 -1
  16. package/dist/middleware/auth-bearer.js +3 -3
  17. package/dist/middleware/auth-cookie.d.ts +1 -1
  18. package/dist/middleware/auth-cookie.js +5 -5
  19. package/dist/middleware/timeout.d.ts +1 -1
  20. package/dist/middleware/timeout.js +3 -2
  21. package/dist/middleware-runner.d.ts +6 -20
  22. package/dist/middleware-runner.js +19 -20
  23. package/dist/permissions.d.ts +6 -89
  24. package/dist/permissions.js +24 -81
  25. package/dist/pikku-state.d.ts +32 -104
  26. package/dist/pikku-state.js +140 -66
  27. package/dist/schema.d.ts +8 -6
  28. package/dist/schema.js +25 -13
  29. package/dist/services/user-session-service.d.ts +7 -3
  30. package/dist/services/user-session-service.js +8 -1
  31. package/dist/services/workflow-service.d.ts +38 -0
  32. package/dist/services/workflow-service.js +1 -0
  33. package/dist/types/core.types.d.ts +40 -41
  34. package/dist/types/core.types.js +4 -15
  35. package/dist/types/state.types.d.ts +135 -0
  36. package/dist/types/state.types.js +1 -0
  37. package/dist/utils.d.ts +9 -1
  38. package/dist/utils.js +48 -3
  39. package/dist/wirings/channel/channel-common.js +2 -3
  40. package/dist/wirings/channel/channel-handler.d.ts +3 -2
  41. package/dist/wirings/channel/channel-handler.js +7 -10
  42. package/dist/wirings/channel/channel-runner.d.ts +2 -2
  43. package/dist/wirings/channel/channel-runner.js +5 -5
  44. package/dist/wirings/channel/channel.types.d.ts +10 -5
  45. package/dist/wirings/channel/local/local-channel-runner.d.ts +1 -1
  46. package/dist/wirings/channel/local/local-channel-runner.js +19 -26
  47. package/dist/wirings/channel/log-channels.js +1 -1
  48. package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +1 -1
  49. package/dist/wirings/channel/serverless/serverless-channel-runner.js +43 -48
  50. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -2
  51. package/dist/wirings/cli/cli-runner.d.ts +5 -5
  52. package/dist/wirings/cli/cli-runner.js +20 -38
  53. package/dist/wirings/cli/cli.types.d.ts +16 -11
  54. package/dist/wirings/forge-node/forge-node.types.d.ts +120 -0
  55. package/dist/wirings/forge-node/forge-node.types.js +38 -0
  56. package/dist/wirings/forge-node/index.d.ts +1 -0
  57. package/dist/wirings/forge-node/index.js +1 -0
  58. package/dist/wirings/http/http-runner.d.ts +8 -8
  59. package/dist/wirings/http/http-runner.js +46 -51
  60. package/dist/wirings/http/http.types.d.ts +19 -11
  61. package/dist/wirings/http/log-http-routes.js +1 -1
  62. package/dist/wirings/http/routers/path-to-regex.js +2 -2
  63. package/dist/wirings/mcp/mcp-runner.d.ts +2 -2
  64. package/dist/wirings/mcp/mcp-runner.js +33 -40
  65. package/dist/wirings/mcp/mcp.types.d.ts +6 -0
  66. package/dist/wirings/queue/queue-runner.d.ts +3 -3
  67. package/dist/wirings/queue/queue-runner.js +13 -23
  68. package/dist/wirings/queue/queue.types.d.ts +4 -11
  69. package/dist/wirings/rpc/index.d.ts +1 -1
  70. package/dist/wirings/rpc/index.js +1 -1
  71. package/dist/wirings/rpc/rpc-runner.d.ts +17 -16
  72. package/dist/wirings/rpc/rpc-runner.js +98 -61
  73. package/dist/wirings/rpc/rpc-types.d.ts +7 -0
  74. package/dist/wirings/scheduler/log-schedulers.js +1 -1
  75. package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -3
  76. package/dist/wirings/scheduler/scheduler-runner.js +18 -29
  77. package/dist/wirings/scheduler/scheduler.types.d.ts +3 -8
  78. package/dist/wirings/trigger/index.d.ts +2 -0
  79. package/dist/wirings/trigger/index.js +2 -0
  80. package/dist/wirings/trigger/trigger-runner.d.ts +29 -0
  81. package/dist/wirings/trigger/trigger-runner.js +57 -0
  82. package/dist/wirings/trigger/trigger.types.d.ts +42 -0
  83. package/dist/wirings/trigger/trigger.types.js +1 -0
  84. package/dist/wirings/workflow/dsl/index.d.ts +5 -0
  85. package/dist/wirings/workflow/dsl/index.js +4 -0
  86. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +286 -0
  87. package/dist/wirings/workflow/dsl/workflow-dsl.types.js +5 -0
  88. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +5 -0
  89. package/dist/wirings/workflow/dsl/workflow-runner.js +22 -0
  90. package/dist/wirings/workflow/graph/graph-node.d.ts +122 -0
  91. package/dist/wirings/workflow/graph/graph-node.js +58 -0
  92. package/dist/wirings/workflow/graph/graph-runner.d.ts +35 -0
  93. package/dist/wirings/workflow/graph/graph-runner.js +452 -0
  94. package/dist/wirings/workflow/graph/index.d.ts +3 -0
  95. package/dist/wirings/workflow/graph/index.js +3 -0
  96. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +95 -0
  97. package/dist/wirings/workflow/graph/workflow-graph.types.js +15 -0
  98. package/dist/wirings/workflow/index.d.ts +7 -3
  99. package/dist/wirings/workflow/index.js +6 -3
  100. package/dist/wirings/workflow/pikku-workflow-service.d.ts +108 -10
  101. package/dist/wirings/workflow/pikku-workflow-service.js +274 -165
  102. package/dist/wirings/workflow/wire-workflow.d.ts +42 -0
  103. package/dist/wirings/workflow/wire-workflow.js +53 -0
  104. package/dist/wirings/workflow/workflow-utils.d.ts +23 -0
  105. package/dist/wirings/workflow/workflow-utils.js +66 -0
  106. package/dist/wirings/workflow/workflow.types.d.ts +135 -128
  107. package/package.json +11 -2
  108. package/src/errors/error-handler.ts +3 -3
  109. package/src/errors/errors.ts +3 -3
  110. package/src/factory-functions.test.ts +9 -36
  111. package/src/function/function-runner.test.ts +58 -69
  112. package/src/function/function-runner.ts +130 -37
  113. package/src/function/functions.types.ts +193 -54
  114. package/src/handle-error.ts +1 -1
  115. package/src/index.ts +10 -5
  116. package/src/middleware/auth-apikey.test.ts +360 -0
  117. package/src/middleware/auth-apikey.ts +3 -7
  118. package/src/middleware/auth-bearer.test.ts +447 -0
  119. package/src/middleware/auth-bearer.ts +27 -33
  120. package/src/middleware/auth-cookie.test.ts +525 -0
  121. package/src/middleware/auth-cookie.ts +6 -6
  122. package/src/middleware/timeout.ts +4 -2
  123. package/src/middleware-runner.test.ts +58 -127
  124. package/src/middleware-runner.ts +29 -25
  125. package/src/permissions.test.ts +68 -130
  126. package/src/permissions.ts +41 -100
  127. package/src/pikku-state.ts +156 -201
  128. package/src/schema.ts +42 -13
  129. package/src/services/user-session-service.ts +14 -4
  130. package/src/services/workflow-service.ts +74 -0
  131. package/src/types/core.types.ts +79 -58
  132. package/src/types/state.types.ts +195 -0
  133. package/src/utils.ts +59 -4
  134. package/src/wirings/channel/channel-common.ts +4 -7
  135. package/src/wirings/channel/channel-handler.ts +17 -23
  136. package/src/wirings/channel/channel-runner.ts +7 -7
  137. package/src/wirings/channel/channel.types.ts +14 -11
  138. package/src/wirings/channel/local/local-channel-runner.test.ts +8 -4
  139. package/src/wirings/channel/local/local-channel-runner.ts +23 -38
  140. package/src/wirings/channel/log-channels.ts +1 -1
  141. package/src/wirings/channel/serverless/serverless-channel-runner.ts +53 -79
  142. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -3
  143. package/src/wirings/cli/cli-runner.test.ts +26 -26
  144. package/src/wirings/cli/cli-runner.ts +34 -71
  145. package/src/wirings/cli/cli.types.ts +23 -16
  146. package/src/wirings/forge-node/forge-node.types.ts +135 -0
  147. package/src/wirings/forge-node/index.ts +1 -0
  148. package/src/wirings/http/http-runner.test.ts +10 -10
  149. package/src/wirings/http/http-runner.ts +56 -66
  150. package/src/wirings/http/http.types.ts +19 -14
  151. package/src/wirings/http/log-http-routes.ts +1 -1
  152. package/src/wirings/http/routers/path-to-regex.test.ts +30 -19
  153. package/src/wirings/http/routers/path-to-regex.ts +2 -2
  154. package/src/wirings/mcp/mcp-runner.ts +44 -69
  155. package/src/wirings/mcp/mcp.types.ts +6 -0
  156. package/src/wirings/queue/queue-runner.test.ts +641 -0
  157. package/src/wirings/queue/queue-runner.ts +16 -38
  158. package/src/wirings/queue/queue.types.ts +4 -11
  159. package/src/wirings/rpc/index.ts +1 -1
  160. package/src/wirings/rpc/rpc-runner.ts +129 -77
  161. package/src/wirings/rpc/rpc-types.ts +8 -0
  162. package/src/wirings/scheduler/log-schedulers.ts +1 -1
  163. package/src/wirings/scheduler/scheduler-runner.test.ts +627 -0
  164. package/src/wirings/scheduler/scheduler-runner.ts +29 -55
  165. package/src/wirings/scheduler/scheduler.types.ts +3 -9
  166. package/src/wirings/trigger/index.ts +2 -0
  167. package/src/wirings/trigger/trigger-runner.ts +96 -0
  168. package/src/wirings/trigger/trigger.types.ts +56 -0
  169. package/src/wirings/workflow/dsl/index.ts +30 -0
  170. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +312 -0
  171. package/src/wirings/workflow/dsl/workflow-runner.ts +27 -0
  172. package/src/wirings/workflow/graph/graph-node.ts +227 -0
  173. package/src/wirings/workflow/graph/graph-runner.ts +694 -0
  174. package/src/wirings/workflow/graph/index.ts +3 -0
  175. package/src/wirings/workflow/graph/workflow-graph.types.ts +126 -0
  176. package/src/wirings/workflow/index.ts +60 -12
  177. package/src/wirings/workflow/pikku-workflow-service.ts +401 -195
  178. package/src/wirings/workflow/wire-workflow.ts +94 -0
  179. package/src/wirings/workflow/workflow-utils.ts +120 -0
  180. package/src/wirings/workflow/workflow.types.ts +167 -188
  181. package/tsconfig.tsbuildinfo +1 -1
  182. package/dist/wirings/workflow/workflow-runner.d.ts +0 -35
  183. package/dist/wirings/workflow/workflow-runner.js +0 -68
  184. package/src/wirings/workflow/workflow-runner.ts +0 -85
@@ -1,10 +1,9 @@
1
- import { PikkuWiringTypes, } from '../../types/core.types.js';
2
1
  import { getErrorResponse } from '../../errors/error-handler.js';
3
- import { closeSessionServices } from '../../utils.js';
2
+ import { closeWireServices } from '../../utils.js';
4
3
  import { pikkuState } from '../../pikku-state.js';
5
4
  import { addFunction, runPikkuFunc } from '../../function/function-runner.js';
6
- import { rpcService } from '../rpc/rpc-runner.js';
7
5
  import { BadRequestError, NotFoundError } from '../../errors/errors.js';
6
+ import { PikkuSessionService } from '../../services/user-session-service.js';
8
7
  export class MCPError extends Error {
9
8
  error;
10
9
  constructor(error) {
@@ -15,39 +14,39 @@ export class MCPError extends Error {
15
14
  }
16
15
  }
17
16
  export const wireMCPResource = (mcpResource) => {
18
- const resourcesMeta = pikkuState('mcp', 'resourcesMeta');
17
+ const resourcesMeta = pikkuState(null, 'mcp', 'resourcesMeta');
19
18
  const mcpResourceMeta = resourcesMeta[mcpResource.uri];
20
19
  if (!mcpResourceMeta) {
21
20
  throw new Error(`MCP resource metadata not found for '${mcpResource.uri}'`);
22
21
  }
23
22
  addFunction(mcpResourceMeta.pikkuFuncName, mcpResource.func);
24
- const resources = pikkuState('mcp', 'resources');
23
+ const resources = pikkuState(null, 'mcp', 'resources');
25
24
  if (resources.has(mcpResource.uri)) {
26
25
  throw new Error(`MCP resource already exists: ${mcpResource.uri}`);
27
26
  }
28
27
  resources.set(mcpResource.uri, mcpResource);
29
28
  };
30
29
  export const wireMCPTool = (mcpTool) => {
31
- const toolsMeta = pikkuState('mcp', 'toolsMeta');
30
+ const toolsMeta = pikkuState(null, 'mcp', 'toolsMeta');
32
31
  const mcpToolMeta = toolsMeta[mcpTool.name];
33
32
  if (!mcpToolMeta) {
34
33
  throw new Error(`MCP tool metadata not found for '${mcpTool.name}'`);
35
34
  }
36
35
  addFunction(mcpToolMeta.pikkuFuncName, mcpTool.func);
37
- const tools = pikkuState('mcp', 'tools');
36
+ const tools = pikkuState(null, 'mcp', 'tools');
38
37
  if (tools.has(mcpTool.name)) {
39
38
  throw new Error(`MCP tool already exists: ${mcpTool.name}`);
40
39
  }
41
40
  tools.set(mcpTool.name, mcpTool);
42
41
  };
43
42
  export const wireMCPPrompt = (mcpPrompt) => {
44
- const promptsMeta = pikkuState('mcp', 'promptsMeta');
43
+ const promptsMeta = pikkuState(null, 'mcp', 'promptsMeta');
45
44
  const mcpPromptMeta = promptsMeta[mcpPrompt.name];
46
45
  if (!mcpPromptMeta) {
47
46
  throw new Error(`MCP prompt metadata not found for '${mcpPrompt.name}'`);
48
47
  }
49
48
  addFunction(mcpPromptMeta.pikkuFuncName, mcpPrompt.func);
50
- const prompts = pikkuState('mcp', 'prompts');
49
+ const prompts = pikkuState(null, 'mcp', 'prompts');
51
50
  if (prompts.has(mcpPrompt.name)) {
52
51
  throw new Error(`MCP prompt already exists: ${mcpPrompt.name}`);
53
52
  }
@@ -57,8 +56,8 @@ export async function runMCPResource(request, params, uri) {
57
56
  let endpoint;
58
57
  let pikkuFuncName;
59
58
  let extractedParams = {};
60
- const metas = pikkuState('mcp', 'resourcesMeta');
61
- const endpoints = pikkuState('mcp', 'resources');
59
+ const metas = pikkuState(null, 'mcp', 'resourcesMeta');
60
+ const endpoints = pikkuState(null, 'mcp', 'resources');
62
61
  if (endpoints.has(uri)) {
63
62
  endpoint = endpoints.get(uri);
64
63
  pikkuFuncName = metas[uri]?.pikkuFuncName;
@@ -88,20 +87,20 @@ export async function runMCPResource(request, params, uri) {
88
87
  }, 'resource', uri, endpoint, pikkuFuncName, { ...params, mcp: { ...params.mcp, uri } });
89
88
  }
90
89
  export async function runMCPTool(request, params, name) {
91
- const endpoint = pikkuState('mcp', 'tools').get(name);
92
- const meta = pikkuState('mcp', 'toolsMeta')[name];
90
+ const endpoint = pikkuState(null, 'mcp', 'tools').get(name);
91
+ const meta = pikkuState(null, 'mcp', 'toolsMeta')[name];
93
92
  return await runMCPPikkuFunc(request, 'tool', name, endpoint, meta?.pikkuFuncName, params);
94
93
  }
95
94
  export async function runMCPPrompt(request, params, name) {
96
- const endpoint = pikkuState('mcp', 'prompts').get(name);
97
- const meta = pikkuState('mcp', 'promptsMeta')[name];
95
+ const endpoint = pikkuState(null, 'mcp', 'prompts').get(name);
96
+ const meta = pikkuState(null, 'mcp', 'promptsMeta')[name];
98
97
  return await runMCPPikkuFunc(request, 'prompt', name, endpoint, meta?.pikkuFuncName, params);
99
98
  }
100
99
  /**
101
100
  * JSON-RPC 2.0 compatible MCP endpoint runner
102
101
  */
103
- async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncName, { singletonServices, createSessionServices, mcp: mcpInteraction, }) {
104
- let sessionServices;
102
+ async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncName, { singletonServices, createWireServices, mcp: mcpWire }) {
103
+ let wireServices;
105
104
  try {
106
105
  // Validate JSON-RPC request structure
107
106
  if (request.jsonrpc !== '2.0') {
@@ -114,37 +113,31 @@ async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncName, { single
114
113
  throw new NotFoundError(`MCP '${type}' PikkuFunction Mapping not found for '${name}'`);
115
114
  }
116
115
  singletonServices.logger.debug(`Running MCP ${type}: ${name}`);
117
- const interaction = { mcp: mcpInteraction };
118
- const getAllServices = async () => {
119
- sessionServices = await createSessionServices?.(singletonServices, interaction, undefined);
120
- return rpcService.injectRPCService({
121
- ...singletonServices,
122
- ...sessionServices,
123
- mcp: mcpInteraction,
124
- }, interaction);
116
+ const wire = {
117
+ mcp: mcpWire,
118
+ session: new PikkuSessionService(),
125
119
  };
126
120
  // Get metadata for the MCP endpoint to access pre-resolved middleware
127
121
  let meta;
128
122
  if (type === 'resource') {
129
- meta = pikkuState('mcp', 'resourcesMeta')[name];
123
+ meta = pikkuState(null, 'mcp', 'resourcesMeta')[name];
130
124
  }
131
125
  else if (type === 'tool') {
132
- meta = pikkuState('mcp', 'toolsMeta')[name];
126
+ meta = pikkuState(null, 'mcp', 'toolsMeta')[name];
133
127
  }
134
128
  else if (type === 'prompt') {
135
- meta = pikkuState('mcp', 'promptsMeta')[name];
129
+ meta = pikkuState(null, 'mcp', 'promptsMeta')[name];
136
130
  }
137
- const result = await runPikkuFunc(PikkuWiringTypes.mcp, `${type}:${name}`, pikkuFuncName, {
131
+ const result = await runPikkuFunc('mcp', `${type}:${name}`, pikkuFuncName, {
138
132
  singletonServices,
139
- getAllServices,
140
- userSession: undefined, // TODO
133
+ createWireServices,
141
134
  data: () => request.params,
142
135
  inheritedMiddleware: meta?.middleware,
143
136
  wireMiddleware: mcp.middleware,
144
137
  inheritedPermissions: meta?.permissions,
145
138
  wirePermissions: mcp.permissions,
146
139
  tags: mcp.tags,
147
- interaction,
140
+ wire,
148
141
  });
149
142
  return {
150
143
  id: request.id,
@@ -174,26 +167,26 @@ async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncName, { single
174
167
  }
175
168
  }
176
169
  finally {
177
- if (sessionServices) {
178
- await closeSessionServices(singletonServices.logger, sessionServices);
170
+ if (wireServices) {
171
+ await closeWireServices(singletonServices.logger, wireServices);
179
172
  }
180
173
  }
181
174
  }
182
175
  export const getMCPTools = () => {
183
- return pikkuState('mcp', 'tools');
176
+ return pikkuState(null, 'mcp', 'tools');
184
177
  };
185
178
  export const getMCPResources = () => {
186
- return pikkuState('mcp', 'resources');
179
+ return pikkuState(null, 'mcp', 'resources');
187
180
  };
188
181
  export const getMCPResourcesMeta = () => {
189
- return pikkuState('mcp', 'resourcesMeta');
182
+ return pikkuState(null, 'mcp', 'resourcesMeta');
190
183
  };
191
184
  export const getMCPToolsMeta = () => {
192
- return pikkuState('mcp', 'toolsMeta');
185
+ return pikkuState(null, 'mcp', 'toolsMeta');
193
186
  };
194
187
  export const getMCPPrompts = () => {
195
- return pikkuState('mcp', 'prompts');
188
+ return pikkuState(null, 'mcp', 'prompts');
196
189
  };
197
190
  export const getMCPPromptsMeta = () => {
198
- return pikkuState('mcp', 'promptsMeta');
191
+ return pikkuState(null, 'mcp', 'promptsMeta');
199
192
  };
@@ -64,6 +64,8 @@ export type CoreMCPResource<PikkuFunctionConfig = CorePikkuFunctionConfig<CorePi
64
64
  uri: string;
65
65
  title: string;
66
66
  description: string;
67
+ summary?: string;
68
+ errors?: string[];
67
69
  mimeType?: string;
68
70
  size?: number;
69
71
  streaming?: boolean;
@@ -79,6 +81,8 @@ export type CoreMCPTool<PikkuFunctionConfig = CorePikkuFunctionConfig<CorePikkuF
79
81
  name: string;
80
82
  title?: string;
81
83
  description: string;
84
+ summary?: string;
85
+ errors?: string[];
82
86
  func: PikkuFunctionConfig;
83
87
  tags?: string[];
84
88
  streaming?: boolean;
@@ -91,6 +95,8 @@ export type CoreMCPTool<PikkuFunctionConfig = CorePikkuFunctionConfig<CorePikkuF
91
95
  export type CoreMCPPrompt<PikkuFunctionConfig = CorePikkuFunctionConfig<CorePikkuFunctionSessionless<any, MCPPromptResponse>>, PikkuPermission = CorePikkuPermission<any, any>, PikkuMiddleware = CorePikkuMiddleware<any>> = {
92
96
  name: string;
93
97
  description: string;
98
+ summary?: string;
99
+ errors?: string[];
94
100
  func: PikkuFunctionConfig;
95
101
  tags?: string[];
96
102
  middleware?: PikkuMiddleware[];
@@ -2,7 +2,7 @@ import type { CoreServices } from '../../types/core.types.js';
2
2
  import type { CoreQueueWorker, QueueJob } from './queue.types.js';
3
3
  import type { CorePikkuFunctionConfig, CorePikkuFunctionSessionless } from '../../function/functions.types.js';
4
4
  import { PikkuError } from '../../errors/error-handler.js';
5
- import { CreateSessionServices } from '../../types/core.types.js';
5
+ import { CreateWireServices } from '../../types/core.types.js';
6
6
  /**
7
7
  * Error class for when a queue job is explicitly failed
8
8
  */
@@ -30,9 +30,9 @@ export declare function removeQueueWorker(name: string): Promise<void>;
30
30
  /**
31
31
  * Process a single queue job - this function is called by queue consumers
32
32
  */
33
- export declare function runQueueJob({ singletonServices, createSessionServices, job, updateProgress, }: {
33
+ export declare function runQueueJob({ singletonServices, createWireServices, job, updateProgress, }: {
34
34
  singletonServices: CoreServices;
35
- createSessionServices?: CreateSessionServices;
35
+ createWireServices?: CreateWireServices;
36
36
  job: QueueJob;
37
37
  updateProgress?: (progress: number | string | object) => Promise<void>;
38
38
  }): Promise<void>;
@@ -1,8 +1,6 @@
1
1
  import { getErrorResponse, PikkuError } from '../../errors/error-handler.js';
2
2
  import { pikkuState } from '../../pikku-state.js';
3
3
  import { addFunction, runPikkuFunc } from '../../function/function-runner.js';
4
- import { PikkuWiringTypes, } from '../../types/core.types.js';
5
- import { rpcService } from '../rpc/rpc-runner.js';
6
4
  /**
7
5
  * Error class for queue processor not found
8
6
  */
@@ -34,7 +32,7 @@ export class QueueJobDiscardedError extends PikkuError {
34
32
  */
35
33
  export const wireQueueWorker = (queueWorker) => {
36
34
  // Get processor metadata
37
- const meta = pikkuState('queue', 'meta');
35
+ const meta = pikkuState(null, 'queue', 'meta');
38
36
  const processorMeta = meta[queueWorker.queueName];
39
37
  if (!processorMeta) {
40
38
  throw new Error(`Queue processor metadata not found for '${queueWorker.queueName}'. Make sure to run the CLI to generate metadata.`);
@@ -46,23 +44,22 @@ export const wireQueueWorker = (queueWorker) => {
46
44
  permissions: queueWorker.func.permissions,
47
45
  middleware: queueWorker.func.middleware,
48
46
  tags: queueWorker.func.tags,
49
- docs: queueWorker.func.docs,
50
47
  });
51
48
  // Store processor definition in state - runtime adapters will pick this up
52
- const registrations = pikkuState('queue', 'registrations');
49
+ const registrations = pikkuState(null, 'queue', 'registrations');
53
50
  registrations.set(queueWorker.queueName, queueWorker);
54
51
  };
55
52
  /**
56
53
  * Get all registered queue processors
57
54
  */
58
55
  export function getQueueWorkers() {
59
- return pikkuState('queue', 'registrations');
56
+ return pikkuState(null, 'queue', 'registrations');
60
57
  }
61
58
  /**
62
59
  * Stop and remove a queue processor
63
60
  */
64
61
  export async function removeQueueWorker(name) {
65
- const registrations = pikkuState('queue', 'registrations');
62
+ const registrations = pikkuState(null, 'queue', 'registrations');
66
63
  const registration = registrations.get(name);
67
64
  if (!registration) {
68
65
  throw new QueueWorkerNotFoundError(name);
@@ -72,20 +69,20 @@ export async function removeQueueWorker(name) {
72
69
  /**
73
70
  * Process a single queue job - this function is called by queue consumers
74
71
  */
75
- export async function runQueueJob({ singletonServices, createSessionServices, job, updateProgress, }) {
72
+ export async function runQueueJob({ singletonServices, createWireServices, job, updateProgress, }) {
76
73
  const logger = singletonServices.logger;
77
- const meta = pikkuState('queue', 'meta');
74
+ const meta = pikkuState(null, 'queue', 'meta');
78
75
  const processorMeta = meta[job.queueName];
79
76
  if (!processorMeta) {
80
77
  throw new Error(`Processor metadata not found for: ${job.queueName}`);
81
78
  }
82
79
  // Get the queue worker registration to access middleware
83
- const registrations = pikkuState('queue', 'registrations');
80
+ const registrations = pikkuState(null, 'queue', 'registrations');
84
81
  const queueWorker = registrations.get(job.queueName);
85
82
  if (!queueWorker) {
86
83
  throw new Error(`Queue worker registration not found for: ${job.queueName}`);
87
84
  }
88
- // Create the queue interaction object
85
+ // Create the queue wire object
89
86
  const queue = {
90
87
  queueName: job.queueName,
91
88
  jobId: job.id,
@@ -103,26 +100,19 @@ export async function runQueueJob({ singletonServices, createSessionServices, jo
103
100
  };
104
101
  try {
105
102
  logger.info(`Processing job ${job.id} in queue ${job.queueName}`);
106
- const interaction = { queue };
107
- // Use provided singleton services
108
- const getAllServices = async () => {
109
- const sessionServices = await createSessionServices?.(singletonServices, { queue }, undefined);
110
- const services = rpcService.injectRPCService({
111
- ...singletonServices,
112
- ...sessionServices,
113
- }, interaction, false);
114
- return services;
103
+ const wire = {
104
+ queue,
115
105
  };
116
106
  // Execute the pikku function with the job data
117
- const result = await runPikkuFunc(PikkuWiringTypes.queue, job.queueName, processorMeta.pikkuFuncName, {
107
+ const result = await runPikkuFunc('queue', job.queueName, processorMeta.pikkuFuncName, {
118
108
  singletonServices,
119
- getAllServices,
109
+ createWireServices,
120
110
  auth: false,
121
111
  data: () => job.data,
122
112
  inheritedMiddleware: processorMeta.middleware,
123
113
  wireMiddleware: queueWorker.middleware,
124
114
  tags: queueWorker.tags,
125
- interaction,
115
+ wire,
126
116
  });
127
117
  logger.debug(`Successfully processed job ${job.id} in queue ${job.queueName}`);
128
118
  return result;
@@ -1,4 +1,4 @@
1
- import { PikkuDocs, MiddlewareMetadata } from '../../types/core.types.js';
1
+ import { CommonWireMeta } from '../../types/core.types.js';
2
2
  import { CorePikkuFunctionConfig } from '../../function/functions.types.js';
3
3
  import { QueueConfigMapping } from './validate-worker-config.js';
4
4
  /**
@@ -130,15 +130,9 @@ export interface QueueWorkers {
130
130
  /**
131
131
  * Queue processor metadata
132
132
  */
133
- export type QueueWorkersMeta = Record<string, {
134
- pikkuFuncName: string;
135
- schemaName?: string;
133
+ export type QueueWorkersMeta = Record<string, CommonWireMeta & {
136
134
  queueName: string;
137
- session?: undefined;
138
- docs?: PikkuDocs;
139
- tags?: string[];
140
135
  config?: PikkuWorkerConfig;
141
- middleware?: MiddlewareMetadata[];
142
136
  }>;
143
137
  /**
144
138
  * Core queue processor definition
@@ -147,13 +141,12 @@ export type CoreQueueWorker<PikkuFunctionConfig extends CorePikkuFunctionConfig<
147
141
  queueName: string;
148
142
  func: PikkuFunctionConfig;
149
143
  config?: PikkuWorkerConfig;
150
- docs?: PikkuDocs;
151
- session?: undefined;
144
+ errors?: string[];
152
145
  tags?: string[];
153
146
  middleware?: PikkuFunctionConfig['middleware'];
154
147
  };
155
148
  /**
156
- * Represents a queue interaction object for middleware
149
+ * Represents a queue wire object for middleware
157
150
  * Provides information and actions for the current queue job execution
158
151
  */
159
152
  export interface PikkuQueue {
@@ -1,2 +1,2 @@
1
- export { initialize, PikkuRPCService, rpcService } from './rpc-runner.js';
1
+ export { PikkuRPCService, rpcService } from './rpc-runner.js';
2
2
  export type { PikkuRPC, RPCMeta } from './rpc-types.js';
@@ -1 +1 @@
1
- export { initialize, PikkuRPCService, rpcService } from './rpc-runner.js';
1
+ export { PikkuRPCService, rpcService } from './rpc-runner.js';
@@ -1,30 +1,31 @@
1
- import { CoreServices, PikkuInteraction } from '../../types/core.types.js';
1
+ import { CoreServices, PikkuWire } from '../../types/core.types.js';
2
2
  import { PikkuRPC } from './rpc-types.js';
3
- type RPCServiceConfig = {
4
- coerceDataFromSchema: boolean;
5
- };
6
3
  export declare class ContextAwareRPCService {
7
4
  private services;
8
- private interaction;
5
+ private wire;
9
6
  private options;
10
- constructor(services: CoreServices, interaction: PikkuInteraction, options: {
11
- coerceDataFromSchema?: boolean;
7
+ constructor(services: CoreServices, wire: PikkuWire, options: {
12
8
  requiresAuth?: boolean;
13
9
  });
14
10
  rpcExposed(funcName: string, data: any): Promise<any>;
15
11
  rpc<In = any, Out = any>(funcName: string, data: In): Promise<Out>;
16
- rpcWithInteraction<In = any, Out = any>(funcName: string, data: In, interaction: PikkuInteraction): Promise<Out>;
12
+ /**
13
+ * Invoke a function from an external package
14
+ * External packages register their functions in pikkuState under their package name.
15
+ * The function is executed using the parent services (shared singleton services).
16
+ * @private
17
+ */
18
+ private invokeExternalPackageFunction;
19
+ rpcWithWire<In = any, Out = any>(rpcName: string, data: In, wire: PikkuWire): Promise<Out>;
17
20
  startWorkflow<In = any>(workflowName: string, input: In): Promise<{
18
21
  runId: string;
19
22
  }>;
20
23
  }
21
24
  export declare class PikkuRPCService<Services extends CoreServices, TypedRPC = PikkuRPC> {
22
- private config?;
23
- initialize(config: RPCServiceConfig): void;
24
- injectRPCService(services: Services, interaction: PikkuInteraction, requiresAuth?: boolean | undefined, depth?: number): Services & {
25
- rpc: TypedRPC;
26
- };
25
+ getContextRPCService(services: Services, wire: PikkuWire, requiresAuth?: boolean | undefined, depth?: number): TypedRPC;
27
26
  }
28
- export declare const rpcService: PikkuRPCService<CoreServices, PikkuRPC>;
29
- export declare const initialize: (config: RPCServiceConfig) => void;
30
- export {};
27
+ export declare const rpcService: PikkuRPCService<import("../../types/core.types.js").CoreSingletonServices<{
28
+ logLevel?: import("../../index.js").LogLevel;
29
+ secrets?: {};
30
+ workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
31
+ }>, PikkuRPC>;
@@ -1,9 +1,29 @@
1
- import { PikkuWiringTypes, } from '../../types/core.types.js';
2
1
  import { runPikkuFunc } from '../../function/function-runner.js';
3
2
  import { pikkuState } from '../../pikku-state.js';
4
3
  import { ForbiddenError } from '../../errors/errors.js';
4
+ /**
5
+ * Resolve a namespaced function reference to package and function names
6
+ * Uses pikkuState to look up the namespace -> package mapping
7
+ */
8
+ const resolveNamespace = (namespacedFunction) => {
9
+ const colonIndex = namespacedFunction.indexOf(':');
10
+ if (colonIndex === -1) {
11
+ return null;
12
+ }
13
+ const namespace = namespacedFunction.substring(0, colonIndex);
14
+ const functionName = namespacedFunction.substring(colonIndex + 1);
15
+ const externalPackages = pikkuState(null, 'rpc', 'externalPackages');
16
+ const packageName = externalPackages.get(namespace);
17
+ if (!packageName) {
18
+ return null;
19
+ }
20
+ return {
21
+ package: packageName,
22
+ function: functionName,
23
+ };
24
+ };
5
25
  const getPikkuFunctionName = (rpcName) => {
6
- const rpc = pikkuState('rpc', 'meta');
26
+ const rpc = pikkuState(null, 'rpc', 'meta');
7
27
  const rpcMeta = rpc[rpcName];
8
28
  if (!rpcMeta) {
9
29
  throw new Error(`RPC function not found: ${rpcName}`);
@@ -13,15 +33,15 @@ const getPikkuFunctionName = (rpcName) => {
13
33
  // Context-aware RPC client for use within services
14
34
  export class ContextAwareRPCService {
15
35
  services;
16
- interaction;
36
+ wire;
17
37
  options;
18
- constructor(services, interaction, options) {
38
+ constructor(services, wire, options) {
19
39
  this.services = services;
20
- this.interaction = interaction;
40
+ this.wire = wire;
21
41
  this.options = options;
22
42
  }
23
43
  async rpcExposed(funcName, data) {
24
- const functionMeta = pikkuState('function', 'meta')[funcName];
44
+ const functionMeta = pikkuState(null, 'function', 'meta')[funcName];
25
45
  if (!functionMeta) {
26
46
  throw new Error(`Function not found: ${funcName}`);
27
47
  }
@@ -31,52 +51,83 @@ export class ContextAwareRPCService {
31
51
  return await this.rpc(funcName, data);
32
52
  }
33
53
  async rpc(funcName, data) {
34
- const rpcDepth = this.services.rpc?.depth || 0;
35
- return runPikkuFunc(PikkuWiringTypes.rpc, funcName, getPikkuFunctionName(funcName), {
54
+ const rpcDepth = this.wire.rpc?.depth || 0;
55
+ const updatedWire = {
56
+ ...this.wire,
57
+ rpc: this.wire.rpc
58
+ ? {
59
+ ...this.wire.rpc,
60
+ depth: rpcDepth + 1,
61
+ global: false,
62
+ }
63
+ : undefined,
64
+ };
65
+ // Check if it's a namespaced function call (e.g., 'stripe:createCharge')
66
+ if (funcName.includes(':')) {
67
+ return this.invokeExternalPackageFunction(funcName, data, updatedWire);
68
+ }
69
+ // Main package function
70
+ return runPikkuFunc('rpc', funcName, getPikkuFunctionName(funcName), {
36
71
  auth: this.options.requiresAuth,
72
+ // TODO: this is a hack since services have already been created
73
+ // but is valid since we don't want to keep creating new wire services
37
74
  singletonServices: this.services,
38
- getAllServices: () => {
39
- this.services.rpc = this.services.rpc
40
- ? {
41
- ...this.services.rpc,
42
- depth: rpcDepth + 1,
43
- global: false,
44
- }
45
- : undefined;
46
- return this.services;
47
- },
48
75
  data: () => data,
49
- userSession: this.services.userSession,
50
- coerceDataFromSchema: this.options.coerceDataFromSchema,
51
- interaction: this.interaction,
76
+ wire: updatedWire,
52
77
  });
53
78
  }
54
- async rpcWithInteraction(funcName, data, interaction) {
55
- const rpcDepth = this.services.rpc?.depth || 0;
56
- const mergedInteraction = {
57
- ...this.interaction,
58
- ...interaction,
79
+ /**
80
+ * Invoke a function from an external package
81
+ * External packages register their functions in pikkuState under their package name.
82
+ * The function is executed using the parent services (shared singleton services).
83
+ * @private
84
+ */
85
+ async invokeExternalPackageFunction(namespacedFunction, data, wire) {
86
+ // Resolve namespace to package name
87
+ const resolved = resolveNamespace(namespacedFunction);
88
+ if (!resolved) {
89
+ throw new Error(`Unknown namespace in function reference: ${namespacedFunction}. ` +
90
+ `Make sure the package is registered in externalPackages config.`);
91
+ }
92
+ // Get the function meta from the external package
93
+ // External packages use function meta, not RPC meta
94
+ const externalFunctionMeta = pikkuState(resolved.package, 'function', 'meta');
95
+ const funcMeta = externalFunctionMeta[resolved.function];
96
+ if (!funcMeta) {
97
+ throw new Error(`Function '${resolved.function}' not found in package '${resolved.package}'. ` +
98
+ `Available functions: ${Object.keys(externalFunctionMeta).join(', ') || '(none)'}`);
99
+ }
100
+ const funcName = funcMeta.pikkuFuncName || resolved.function;
101
+ // Execute the function using runPikkuFunc with the external package's state
102
+ // We use the parent services (this.services) since external packages share services
103
+ // Pass the function's tags so tag-based middleware/permissions are applied
104
+ return runPikkuFunc('rpc', namespacedFunction, funcName, {
105
+ auth: this.options.requiresAuth,
106
+ singletonServices: this.services,
107
+ data: () => data,
108
+ wire,
109
+ packageName: resolved.package,
110
+ tags: funcMeta.tags,
111
+ });
112
+ }
113
+ async rpcWithWire(rpcName, data, wire) {
114
+ const rpcDepth = this.wire.rpc?.depth || 0;
115
+ const mergedWire = {
116
+ ...this.wire,
117
+ ...wire,
118
+ rpc: this.wire.rpc
119
+ ? {
120
+ ...this.wire.rpc,
121
+ depth: rpcDepth + 1,
122
+ global: false,
123
+ }
124
+ : undefined,
59
125
  };
60
- return runPikkuFunc(PikkuWiringTypes.rpc, funcName, getPikkuFunctionName(funcName), {
126
+ return runPikkuFunc('rpc', rpcName, getPikkuFunctionName(rpcName), {
61
127
  auth: this.options.requiresAuth,
62
128
  singletonServices: this.services,
63
- getAllServices: () => {
64
- this.services.rpc = this.services.rpc
65
- ? {
66
- ...this.services.rpc,
67
- depth: rpcDepth + 1,
68
- global: false,
69
- }
70
- : undefined;
71
- return {
72
- ...this.services,
73
- ...mergedInteraction,
74
- };
75
- },
76
129
  data: () => data,
77
- userSession: this.services.userSession,
78
- coerceDataFromSchema: this.options.coerceDataFromSchema,
79
- interaction: mergedInteraction,
130
+ wire: mergedWire,
80
131
  });
81
132
  }
82
133
  async startWorkflow(workflowName, input) {
@@ -88,34 +139,20 @@ export class ContextAwareRPCService {
88
139
  }
89
140
  // RPC Service class for the global interface
90
141
  export class PikkuRPCService {
91
- config;
92
- // Initialize the RPC service with configuration
93
- initialize(config) {
94
- this.config = config;
95
- }
96
142
  // Convenience function for initializing
97
- injectRPCService(services, interaction, requiresAuth, depth = 0) {
98
- const serviceCopy = {
99
- ...services,
100
- };
101
- const serviceRPC = new ContextAwareRPCService(serviceCopy, interaction, {
102
- coerceDataFromSchema: this.config?.coerceDataFromSchema,
143
+ getContextRPCService(services, wire, requiresAuth, depth = 0) {
144
+ const serviceRPC = new ContextAwareRPCService(services, wire, {
103
145
  requiresAuth,
104
146
  });
105
- serviceCopy.rpc = {
147
+ return {
106
148
  depth,
107
149
  global: false,
108
150
  invoke: serviceRPC.rpc.bind(serviceRPC),
109
151
  invokeExposed: serviceRPC.rpc.bind(serviceRPC),
110
152
  startWorkflow: serviceRPC.startWorkflow.bind(serviceRPC),
111
- rpcWithInteraction: serviceRPC.rpcWithInteraction.bind(serviceRPC),
153
+ rpcWithWire: serviceRPC.rpcWithWire.bind(serviceRPC),
112
154
  };
113
- return serviceCopy;
114
155
  }
115
156
  }
116
157
  // Create a singleton instance
117
158
  export const rpcService = new PikkuRPCService();
118
- // Convenience function for initializing
119
- export const initialize = (config) => {
120
- rpcService.initialize(config);
121
- };
@@ -15,3 +15,10 @@ export interface RPCHandler<Input, Output> {
15
15
  input: Input;
16
16
  output: Output;
17
17
  }
18
+ /**
19
+ * Resolved function reference from namespace
20
+ */
21
+ export interface ResolvedFunction {
22
+ package: string;
23
+ function: string;
24
+ }
@@ -4,7 +4,7 @@ import { pikkuState } from '../../pikku-state.js';
4
4
  * @param logger - A logger for logging information.
5
5
  */
6
6
  export const logSchedulers = (logger) => {
7
- const scheduledTasks = pikkuState('scheduler', 'tasks');
7
+ const scheduledTasks = pikkuState(null, 'scheduler', 'tasks');
8
8
  if (scheduledTasks.size === 0) {
9
9
  logger.info('No scheduled tasks added');
10
10
  return;