@pikku/core 0.11.1 → 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.
- package/CHANGELOG.md +24 -0
- package/dist/errors/error-handler.js +3 -3
- package/dist/function/function-runner.d.ts +4 -3
- package/dist/function/function-runner.js +60 -14
- package/dist/function/functions.types.d.ts +84 -5
- package/dist/function/functions.types.js +41 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +5 -2
- package/dist/middleware/auth-apikey.d.ts +1 -1
- package/dist/middleware/auth-bearer.d.ts +1 -1
- package/dist/middleware/auth-cookie.d.ts +1 -1
- package/dist/middleware/timeout.d.ts +1 -1
- package/dist/middleware-runner.d.ts +3 -14
- package/dist/middleware-runner.js +8 -8
- package/dist/permissions.d.ts +3 -86
- package/dist/permissions.js +11 -67
- package/dist/pikku-state.d.ts +32 -104
- package/dist/pikku-state.js +140 -66
- package/dist/schema.d.ts +8 -6
- package/dist/schema.js +25 -13
- package/dist/services/workflow-service.d.ts +38 -0
- package/dist/services/workflow-service.js +1 -0
- package/dist/types/core.types.d.ts +12 -4
- package/dist/types/core.types.js +1 -1
- package/dist/types/state.types.d.ts +135 -0
- package/dist/types/state.types.js +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.js +45 -0
- package/dist/wirings/channel/channel-handler.js +1 -1
- package/dist/wirings/channel/channel-runner.js +5 -5
- package/dist/wirings/channel/log-channels.js +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -2
- package/dist/wirings/cli/channel/cli-channel-runner.js +3 -2
- package/dist/wirings/cli/cli-runner.js +10 -10
- package/dist/wirings/cli/cli.types.d.ts +1 -0
- package/dist/wirings/forge-node/forge-node.types.d.ts +120 -0
- package/dist/wirings/forge-node/forge-node.types.js +38 -0
- package/dist/wirings/forge-node/index.d.ts +1 -0
- package/dist/wirings/forge-node/index.js +1 -0
- package/dist/wirings/http/http-runner.d.ts +2 -2
- package/dist/wirings/http/http-runner.js +21 -12
- package/dist/wirings/http/http.types.d.ts +14 -1
- package/dist/wirings/http/log-http-routes.js +1 -1
- package/dist/wirings/http/routers/path-to-regex.js +2 -2
- package/dist/wirings/mcp/mcp-runner.js +21 -21
- package/dist/wirings/queue/queue-runner.js +6 -6
- package/dist/wirings/rpc/index.d.ts +1 -1
- package/dist/wirings/rpc/index.js +1 -1
- package/dist/wirings/rpc/rpc-runner.d.ts +7 -8
- package/dist/wirings/rpc/rpc-runner.js +62 -14
- package/dist/wirings/rpc/rpc-types.d.ts +7 -0
- package/dist/wirings/scheduler/log-schedulers.js +1 -1
- package/dist/wirings/scheduler/scheduler-runner.js +5 -5
- package/dist/wirings/trigger/index.d.ts +2 -0
- package/dist/wirings/trigger/index.js +2 -0
- package/dist/wirings/trigger/trigger-runner.d.ts +29 -0
- package/dist/wirings/trigger/trigger-runner.js +57 -0
- package/dist/wirings/trigger/trigger.types.d.ts +42 -0
- package/dist/wirings/trigger/trigger.types.js +1 -0
- package/dist/wirings/workflow/dsl/index.d.ts +5 -0
- package/dist/wirings/workflow/dsl/index.js +4 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +286 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.js +5 -0
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +5 -0
- package/dist/wirings/workflow/dsl/workflow-runner.js +22 -0
- package/dist/wirings/workflow/graph/graph-node.d.ts +122 -0
- package/dist/wirings/workflow/graph/graph-node.js +58 -0
- package/dist/wirings/workflow/graph/graph-runner.d.ts +35 -0
- package/dist/wirings/workflow/graph/graph-runner.js +452 -0
- package/dist/wirings/workflow/graph/index.d.ts +3 -0
- package/dist/wirings/workflow/graph/index.js +3 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +95 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.js +15 -0
- package/dist/wirings/workflow/index.d.ts +7 -12
- package/dist/wirings/workflow/index.js +6 -11
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +96 -6
- package/dist/wirings/workflow/pikku-workflow-service.js +230 -103
- package/dist/wirings/workflow/wire-workflow.d.ts +42 -0
- package/dist/wirings/workflow/wire-workflow.js +53 -0
- package/dist/wirings/workflow/workflow-utils.d.ts +23 -0
- package/dist/wirings/workflow/workflow-utils.js +66 -0
- package/dist/wirings/workflow/workflow.types.d.ts +133 -211
- package/package.json +10 -1
- package/src/errors/error-handler.ts +3 -3
- package/src/function/function-runner.test.ts +1 -1
- package/src/function/function-runner.ts +86 -16
- package/src/function/functions.types.ts +126 -4
- package/src/index.ts +10 -5
- package/src/middleware-runner.ts +16 -9
- package/src/permissions.test.ts +28 -86
- package/src/permissions.ts +21 -80
- package/src/pikku-state.ts +156 -201
- package/src/schema.ts +42 -13
- package/src/services/workflow-service.ts +74 -0
- package/src/types/core.types.ts +12 -3
- package/src/types/state.types.ts +195 -0
- package/src/utils.ts +55 -0
- package/src/wirings/channel/channel-handler.ts +1 -1
- package/src/wirings/channel/channel-runner.ts +5 -5
- package/src/wirings/channel/local/local-channel-runner.test.ts +3 -1
- package/src/wirings/channel/log-channels.ts +1 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -2
- package/src/wirings/cli/channel/cli-channel-runner.ts +4 -3
- package/src/wirings/cli/cli-runner.test.ts +19 -19
- package/src/wirings/cli/cli-runner.ts +10 -9
- package/src/wirings/cli/cli.types.ts +1 -0
- package/src/wirings/forge-node/forge-node.types.ts +135 -0
- package/src/wirings/forge-node/index.ts +1 -0
- package/src/wirings/http/http-runner.test.ts +2 -2
- package/src/wirings/http/http-runner.ts +30 -13
- package/src/wirings/http/http.types.ts +14 -0
- package/src/wirings/http/log-http-routes.ts +1 -1
- package/src/wirings/http/routers/path-to-regex.test.ts +30 -19
- package/src/wirings/http/routers/path-to-regex.ts +2 -2
- package/src/wirings/mcp/mcp-runner.ts +21 -21
- package/src/wirings/queue/queue-runner.test.ts +19 -19
- package/src/wirings/queue/queue-runner.ts +6 -6
- package/src/wirings/rpc/index.ts +1 -1
- package/src/wirings/rpc/rpc-runner.ts +88 -22
- package/src/wirings/rpc/rpc-types.ts +8 -0
- package/src/wirings/scheduler/log-schedulers.ts +1 -1
- package/src/wirings/scheduler/scheduler-runner.test.ts +27 -27
- package/src/wirings/scheduler/scheduler-runner.ts +5 -5
- package/src/wirings/trigger/index.ts +2 -0
- package/src/wirings/trigger/trigger-runner.ts +96 -0
- package/src/wirings/trigger/trigger.types.ts +56 -0
- package/src/wirings/workflow/dsl/index.ts +30 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +312 -0
- package/src/wirings/workflow/dsl/workflow-runner.ts +27 -0
- package/src/wirings/workflow/graph/graph-node.ts +227 -0
- package/src/wirings/workflow/graph/graph-runner.ts +694 -0
- package/src/wirings/workflow/graph/index.ts +3 -0
- package/src/wirings/workflow/graph/workflow-graph.types.ts +126 -0
- package/src/wirings/workflow/index.ts +53 -26
- package/src/wirings/workflow/pikku-workflow-service.ts +333 -117
- package/src/wirings/workflow/wire-workflow.ts +94 -0
- package/src/wirings/workflow/workflow-utils.ts +120 -0
- package/src/wirings/workflow/workflow.types.ts +166 -277
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/wirings/workflow/workflow-runner.d.ts +0 -34
- package/dist/wirings/workflow/workflow-runner.js +0 -65
- package/src/function/function-runner.ts.bak +0 -188
- package/src/wirings/workflow/workflow-runner.ts +0 -72
|
@@ -7,6 +7,7 @@ import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js';
|
|
|
7
7
|
import { PikkuFetchHTTPRequest } from './pikku-fetch-http-request.js';
|
|
8
8
|
import { addFunction, runPikkuFunc } from '../../function/function-runner.js';
|
|
9
9
|
import { httpRouter } from './routers/http-router.js';
|
|
10
|
+
import { startWorkflowByHttpWire } from '../workflow/workflow-utils.js';
|
|
10
11
|
/**
|
|
11
12
|
* Registers HTTP middleware for a specific route pattern.
|
|
12
13
|
*
|
|
@@ -36,8 +37,8 @@ import { httpRouter } from './routers/http-router.js';
|
|
|
36
37
|
* ])
|
|
37
38
|
* ```
|
|
38
39
|
*/
|
|
39
|
-
export const addHTTPMiddleware = (pattern, middleware) => {
|
|
40
|
-
const httpGroups = pikkuState('middleware', 'httpGroup');
|
|
40
|
+
export const addHTTPMiddleware = (pattern, middleware, packageName = null) => {
|
|
41
|
+
const httpGroups = pikkuState(packageName, 'middleware', 'httpGroup');
|
|
41
42
|
httpGroups[pattern] = middleware;
|
|
42
43
|
return middleware;
|
|
43
44
|
};
|
|
@@ -70,8 +71,8 @@ export const addHTTPMiddleware = (pattern, middleware) => {
|
|
|
70
71
|
* ])
|
|
71
72
|
* ```
|
|
72
73
|
*/
|
|
73
|
-
export const addHTTPPermission = (pattern, permissions) => {
|
|
74
|
-
const httpGroups = pikkuState('permissions', 'httpGroup');
|
|
74
|
+
export const addHTTPPermission = (pattern, permissions, packageName = null) => {
|
|
75
|
+
const httpGroups = pikkuState(packageName, 'permissions', 'httpGroup');
|
|
75
76
|
httpGroups[pattern] = permissions;
|
|
76
77
|
return permissions;
|
|
77
78
|
};
|
|
@@ -91,17 +92,19 @@ export const addHTTPPermission = (pattern, permissions) => {
|
|
|
91
92
|
* @param {CoreHTTPFunctionWiring<In, Out, Route, PikkuFunction, PikkuFunctionSessionless, PikkuPermission, PikkuMiddleware>} httpWiring - The HTTP wiring configuration object.
|
|
92
93
|
*/
|
|
93
94
|
export const wireHTTP = (httpWiring) => {
|
|
94
|
-
const httpMeta = pikkuState('http', 'meta');
|
|
95
|
+
const httpMeta = pikkuState(null, 'http', 'meta');
|
|
95
96
|
const routeMeta = httpMeta[httpWiring.method][httpWiring.route];
|
|
96
97
|
if (!routeMeta) {
|
|
97
98
|
throw new Error('Route metadata not found');
|
|
98
99
|
}
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
if (httpWiring.func) {
|
|
101
|
+
addFunction(routeMeta.pikkuFuncName, httpWiring.func);
|
|
102
|
+
}
|
|
103
|
+
const routes = pikkuState(null, 'http', 'routes');
|
|
101
104
|
if (!routes.has(httpWiring.method)) {
|
|
102
105
|
routes.set(httpWiring.method, new Map());
|
|
103
106
|
}
|
|
104
|
-
pikkuState('http', 'routes')
|
|
107
|
+
pikkuState(null, 'http', 'routes')
|
|
105
108
|
.get(httpWiring.method)
|
|
106
109
|
?.set(httpWiring.route, httpWiring);
|
|
107
110
|
};
|
|
@@ -119,10 +122,10 @@ export const wireHTTP = (httpWiring) => {
|
|
|
119
122
|
const getMatchingRoute = (requestType, requestPath) => {
|
|
120
123
|
const matchedPath = httpRouter.match(requestType.toLowerCase(), requestPath);
|
|
121
124
|
if (matchedPath) {
|
|
122
|
-
const route = pikkuState('http', 'routes')
|
|
125
|
+
const route = pikkuState(null, 'http', 'routes')
|
|
123
126
|
.get(requestType.toLowerCase())
|
|
124
127
|
.get(matchedPath.route);
|
|
125
|
-
const meta = pikkuState('http', 'meta')[requestType.toLowerCase()][route.route];
|
|
128
|
+
const meta = pikkuState(null, 'http', 'meta')[requestType.toLowerCase()][route.route];
|
|
126
129
|
return {
|
|
127
130
|
matchedPath,
|
|
128
131
|
params: matchedPath.params,
|
|
@@ -179,11 +182,11 @@ const executeRoute = async (services, matchedRoute, http, options) => {
|
|
|
179
182
|
const userSession = new PikkuSessionService();
|
|
180
183
|
const { params, route, meta } = matchedRoute;
|
|
181
184
|
const { singletonServices, createWireServices, skipUserSession, requestId } = services;
|
|
185
|
+
// Attach URL parameters to the request object
|
|
186
|
+
http?.request?.setParams(params);
|
|
182
187
|
const requiresSession = route.auth !== false;
|
|
183
188
|
let wireServices;
|
|
184
189
|
let result;
|
|
185
|
-
// Attach URL parameters to the request object
|
|
186
|
-
http?.request?.setParams(params);
|
|
187
190
|
singletonServices.logger.info(`Matched route: ${route.route} | method: ${route.method.toUpperCase()} | auth: ${requiresSession.toString()}`);
|
|
188
191
|
// Ensure session is available when required
|
|
189
192
|
if (skipUserSession && requiresSession) {
|
|
@@ -218,6 +221,12 @@ const executeRoute = async (services, matchedRoute, http, options) => {
|
|
|
218
221
|
};
|
|
219
222
|
}
|
|
220
223
|
const wire = { http, channel, session: userSession };
|
|
224
|
+
if (matchedRoute.meta.workflow === true) {
|
|
225
|
+
await startWorkflowByHttpWire(singletonServices, createWireServices, matchedRoute, wire);
|
|
226
|
+
return wireServices
|
|
227
|
+
? { wireServices, result: http.response }
|
|
228
|
+
: { result: http.response };
|
|
229
|
+
}
|
|
221
230
|
result = await runPikkuFunc('http', `${meta.method}:${meta.route}`, meta.pikkuFuncName, {
|
|
222
231
|
singletonServices,
|
|
223
232
|
createWireServices,
|
|
@@ -123,7 +123,19 @@ export type CoreHTTPFunctionWiring<In, Out, R extends string, PikkuFunction exte
|
|
|
123
123
|
tags?: string[];
|
|
124
124
|
middleware?: PikkuMiddleware[];
|
|
125
125
|
sse?: undefined;
|
|
126
|
-
})
|
|
126
|
+
}) | {
|
|
127
|
+
/** Route triggers a workflow matched by route/method from workflow wires.http */
|
|
128
|
+
route: R;
|
|
129
|
+
method: HTTPMethod;
|
|
130
|
+
workflow: true;
|
|
131
|
+
func?: undefined;
|
|
132
|
+
permissions?: undefined;
|
|
133
|
+
auth?: undefined;
|
|
134
|
+
tags?: undefined;
|
|
135
|
+
middleware?: undefined;
|
|
136
|
+
returnsJSON?: undefined;
|
|
137
|
+
sse?: boolean;
|
|
138
|
+
};
|
|
127
139
|
/**
|
|
128
140
|
* Represents the input types for HTTP wiring metadata, including parameters, query, and body types.
|
|
129
141
|
*/
|
|
@@ -142,6 +154,7 @@ export type HTTPWiringMeta = CommonWireMeta & {
|
|
|
142
154
|
query?: string[];
|
|
143
155
|
inputTypes?: HTTPFunctionMetaInputTypes;
|
|
144
156
|
sse?: true;
|
|
157
|
+
workflow?: true;
|
|
145
158
|
};
|
|
146
159
|
export type HTTPWiringsMeta = Record<HTTPMethod, Record<string, HTTPWiringMeta>>;
|
|
147
160
|
export type HTTPFunctionsMeta = Array<{
|
|
@@ -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 logRoutes = (logger) => {
|
|
7
|
-
const routesByType = pikkuState('http', 'routes');
|
|
7
|
+
const routesByType = pikkuState(null, 'http', 'routes');
|
|
8
8
|
if (routesByType.size === 0) {
|
|
9
9
|
logger.info('No routes added');
|
|
10
10
|
return;
|
|
@@ -10,8 +10,8 @@ export class PathToRegexRouter {
|
|
|
10
10
|
this.isInitialized = false;
|
|
11
11
|
}
|
|
12
12
|
initialize() {
|
|
13
|
-
const routes = pikkuState('http', 'routes');
|
|
14
|
-
const channelRoutes = pikkuState('channel', 'channels');
|
|
13
|
+
const routes = pikkuState(null, 'http', 'routes');
|
|
14
|
+
const channelRoutes = pikkuState(null, 'channel', 'channels');
|
|
15
15
|
// Helper function to compile routes for a given method
|
|
16
16
|
const compileRoutesForMethod = (method, routeEntries) => {
|
|
17
17
|
const methodCompiledRoutes = this.compiledRoutes.get(method) || new Map();
|
|
@@ -14,39 +14,39 @@ export class MCPError extends Error {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
export const wireMCPResource = (mcpResource) => {
|
|
17
|
-
const resourcesMeta = pikkuState('mcp', 'resourcesMeta');
|
|
17
|
+
const resourcesMeta = pikkuState(null, 'mcp', 'resourcesMeta');
|
|
18
18
|
const mcpResourceMeta = resourcesMeta[mcpResource.uri];
|
|
19
19
|
if (!mcpResourceMeta) {
|
|
20
20
|
throw new Error(`MCP resource metadata not found for '${mcpResource.uri}'`);
|
|
21
21
|
}
|
|
22
22
|
addFunction(mcpResourceMeta.pikkuFuncName, mcpResource.func);
|
|
23
|
-
const resources = pikkuState('mcp', 'resources');
|
|
23
|
+
const resources = pikkuState(null, 'mcp', 'resources');
|
|
24
24
|
if (resources.has(mcpResource.uri)) {
|
|
25
25
|
throw new Error(`MCP resource already exists: ${mcpResource.uri}`);
|
|
26
26
|
}
|
|
27
27
|
resources.set(mcpResource.uri, mcpResource);
|
|
28
28
|
};
|
|
29
29
|
export const wireMCPTool = (mcpTool) => {
|
|
30
|
-
const toolsMeta = pikkuState('mcp', 'toolsMeta');
|
|
30
|
+
const toolsMeta = pikkuState(null, 'mcp', 'toolsMeta');
|
|
31
31
|
const mcpToolMeta = toolsMeta[mcpTool.name];
|
|
32
32
|
if (!mcpToolMeta) {
|
|
33
33
|
throw new Error(`MCP tool metadata not found for '${mcpTool.name}'`);
|
|
34
34
|
}
|
|
35
35
|
addFunction(mcpToolMeta.pikkuFuncName, mcpTool.func);
|
|
36
|
-
const tools = pikkuState('mcp', 'tools');
|
|
36
|
+
const tools = pikkuState(null, 'mcp', 'tools');
|
|
37
37
|
if (tools.has(mcpTool.name)) {
|
|
38
38
|
throw new Error(`MCP tool already exists: ${mcpTool.name}`);
|
|
39
39
|
}
|
|
40
40
|
tools.set(mcpTool.name, mcpTool);
|
|
41
41
|
};
|
|
42
42
|
export const wireMCPPrompt = (mcpPrompt) => {
|
|
43
|
-
const promptsMeta = pikkuState('mcp', 'promptsMeta');
|
|
43
|
+
const promptsMeta = pikkuState(null, 'mcp', 'promptsMeta');
|
|
44
44
|
const mcpPromptMeta = promptsMeta[mcpPrompt.name];
|
|
45
45
|
if (!mcpPromptMeta) {
|
|
46
46
|
throw new Error(`MCP prompt metadata not found for '${mcpPrompt.name}'`);
|
|
47
47
|
}
|
|
48
48
|
addFunction(mcpPromptMeta.pikkuFuncName, mcpPrompt.func);
|
|
49
|
-
const prompts = pikkuState('mcp', 'prompts');
|
|
49
|
+
const prompts = pikkuState(null, 'mcp', 'prompts');
|
|
50
50
|
if (prompts.has(mcpPrompt.name)) {
|
|
51
51
|
throw new Error(`MCP prompt already exists: ${mcpPrompt.name}`);
|
|
52
52
|
}
|
|
@@ -56,8 +56,8 @@ export async function runMCPResource(request, params, uri) {
|
|
|
56
56
|
let endpoint;
|
|
57
57
|
let pikkuFuncName;
|
|
58
58
|
let extractedParams = {};
|
|
59
|
-
const metas = pikkuState('mcp', 'resourcesMeta');
|
|
60
|
-
const endpoints = pikkuState('mcp', 'resources');
|
|
59
|
+
const metas = pikkuState(null, 'mcp', 'resourcesMeta');
|
|
60
|
+
const endpoints = pikkuState(null, 'mcp', 'resources');
|
|
61
61
|
if (endpoints.has(uri)) {
|
|
62
62
|
endpoint = endpoints.get(uri);
|
|
63
63
|
pikkuFuncName = metas[uri]?.pikkuFuncName;
|
|
@@ -87,13 +87,13 @@ export async function runMCPResource(request, params, uri) {
|
|
|
87
87
|
}, 'resource', uri, endpoint, pikkuFuncName, { ...params, mcp: { ...params.mcp, uri } });
|
|
88
88
|
}
|
|
89
89
|
export async function runMCPTool(request, params, name) {
|
|
90
|
-
const endpoint = pikkuState('mcp', 'tools').get(name);
|
|
91
|
-
const meta = pikkuState('mcp', 'toolsMeta')[name];
|
|
90
|
+
const endpoint = pikkuState(null, 'mcp', 'tools').get(name);
|
|
91
|
+
const meta = pikkuState(null, 'mcp', 'toolsMeta')[name];
|
|
92
92
|
return await runMCPPikkuFunc(request, 'tool', name, endpoint, meta?.pikkuFuncName, params);
|
|
93
93
|
}
|
|
94
94
|
export async function runMCPPrompt(request, params, name) {
|
|
95
|
-
const endpoint = pikkuState('mcp', 'prompts').get(name);
|
|
96
|
-
const meta = pikkuState('mcp', 'promptsMeta')[name];
|
|
95
|
+
const endpoint = pikkuState(null, 'mcp', 'prompts').get(name);
|
|
96
|
+
const meta = pikkuState(null, 'mcp', 'promptsMeta')[name];
|
|
97
97
|
return await runMCPPikkuFunc(request, 'prompt', name, endpoint, meta?.pikkuFuncName, params);
|
|
98
98
|
}
|
|
99
99
|
/**
|
|
@@ -120,13 +120,13 @@ async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncName, { single
|
|
|
120
120
|
// Get metadata for the MCP endpoint to access pre-resolved middleware
|
|
121
121
|
let meta;
|
|
122
122
|
if (type === 'resource') {
|
|
123
|
-
meta = pikkuState('mcp', 'resourcesMeta')[name];
|
|
123
|
+
meta = pikkuState(null, 'mcp', 'resourcesMeta')[name];
|
|
124
124
|
}
|
|
125
125
|
else if (type === 'tool') {
|
|
126
|
-
meta = pikkuState('mcp', 'toolsMeta')[name];
|
|
126
|
+
meta = pikkuState(null, 'mcp', 'toolsMeta')[name];
|
|
127
127
|
}
|
|
128
128
|
else if (type === 'prompt') {
|
|
129
|
-
meta = pikkuState('mcp', 'promptsMeta')[name];
|
|
129
|
+
meta = pikkuState(null, 'mcp', 'promptsMeta')[name];
|
|
130
130
|
}
|
|
131
131
|
const result = await runPikkuFunc('mcp', `${type}:${name}`, pikkuFuncName, {
|
|
132
132
|
singletonServices,
|
|
@@ -173,20 +173,20 @@ async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncName, { single
|
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
175
|
export const getMCPTools = () => {
|
|
176
|
-
return pikkuState('mcp', 'tools');
|
|
176
|
+
return pikkuState(null, 'mcp', 'tools');
|
|
177
177
|
};
|
|
178
178
|
export const getMCPResources = () => {
|
|
179
|
-
return pikkuState('mcp', 'resources');
|
|
179
|
+
return pikkuState(null, 'mcp', 'resources');
|
|
180
180
|
};
|
|
181
181
|
export const getMCPResourcesMeta = () => {
|
|
182
|
-
return pikkuState('mcp', 'resourcesMeta');
|
|
182
|
+
return pikkuState(null, 'mcp', 'resourcesMeta');
|
|
183
183
|
};
|
|
184
184
|
export const getMCPToolsMeta = () => {
|
|
185
|
-
return pikkuState('mcp', 'toolsMeta');
|
|
185
|
+
return pikkuState(null, 'mcp', 'toolsMeta');
|
|
186
186
|
};
|
|
187
187
|
export const getMCPPrompts = () => {
|
|
188
|
-
return pikkuState('mcp', 'prompts');
|
|
188
|
+
return pikkuState(null, 'mcp', 'prompts');
|
|
189
189
|
};
|
|
190
190
|
export const getMCPPromptsMeta = () => {
|
|
191
|
-
return pikkuState('mcp', 'promptsMeta');
|
|
191
|
+
return pikkuState(null, 'mcp', 'promptsMeta');
|
|
192
192
|
};
|
|
@@ -32,7 +32,7 @@ export class QueueJobDiscardedError extends PikkuError {
|
|
|
32
32
|
*/
|
|
33
33
|
export const wireQueueWorker = (queueWorker) => {
|
|
34
34
|
// Get processor metadata
|
|
35
|
-
const meta = pikkuState('queue', 'meta');
|
|
35
|
+
const meta = pikkuState(null, 'queue', 'meta');
|
|
36
36
|
const processorMeta = meta[queueWorker.queueName];
|
|
37
37
|
if (!processorMeta) {
|
|
38
38
|
throw new Error(`Queue processor metadata not found for '${queueWorker.queueName}'. Make sure to run the CLI to generate metadata.`);
|
|
@@ -46,20 +46,20 @@ export const wireQueueWorker = (queueWorker) => {
|
|
|
46
46
|
tags: queueWorker.func.tags,
|
|
47
47
|
});
|
|
48
48
|
// Store processor definition in state - runtime adapters will pick this up
|
|
49
|
-
const registrations = pikkuState('queue', 'registrations');
|
|
49
|
+
const registrations = pikkuState(null, 'queue', 'registrations');
|
|
50
50
|
registrations.set(queueWorker.queueName, queueWorker);
|
|
51
51
|
};
|
|
52
52
|
/**
|
|
53
53
|
* Get all registered queue processors
|
|
54
54
|
*/
|
|
55
55
|
export function getQueueWorkers() {
|
|
56
|
-
return pikkuState('queue', 'registrations');
|
|
56
|
+
return pikkuState(null, 'queue', 'registrations');
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
59
|
* Stop and remove a queue processor
|
|
60
60
|
*/
|
|
61
61
|
export async function removeQueueWorker(name) {
|
|
62
|
-
const registrations = pikkuState('queue', 'registrations');
|
|
62
|
+
const registrations = pikkuState(null, 'queue', 'registrations');
|
|
63
63
|
const registration = registrations.get(name);
|
|
64
64
|
if (!registration) {
|
|
65
65
|
throw new QueueWorkerNotFoundError(name);
|
|
@@ -71,13 +71,13 @@ export async function removeQueueWorker(name) {
|
|
|
71
71
|
*/
|
|
72
72
|
export async function runQueueJob({ singletonServices, createWireServices, job, updateProgress, }) {
|
|
73
73
|
const logger = singletonServices.logger;
|
|
74
|
-
const meta = pikkuState('queue', 'meta');
|
|
74
|
+
const meta = pikkuState(null, 'queue', 'meta');
|
|
75
75
|
const processorMeta = meta[job.queueName];
|
|
76
76
|
if (!processorMeta) {
|
|
77
77
|
throw new Error(`Processor metadata not found for: ${job.queueName}`);
|
|
78
78
|
}
|
|
79
79
|
// Get the queue worker registration to access middleware
|
|
80
|
-
const registrations = pikkuState('queue', 'registrations');
|
|
80
|
+
const registrations = pikkuState(null, 'queue', 'registrations');
|
|
81
81
|
const queueWorker = registrations.get(job.queueName);
|
|
82
82
|
if (!queueWorker) {
|
|
83
83
|
throw new Error(`Queue worker registration not found for: ${job.queueName}`);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { PikkuRPCService, rpcService } from './rpc-runner.js';
|
|
2
2
|
export type { PikkuRPC, RPCMeta } from './rpc-types.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { PikkuRPCService, rpcService } from './rpc-runner.js';
|
|
@@ -1,26 +1,27 @@
|
|
|
1
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
5
|
private wire;
|
|
9
6
|
private options;
|
|
10
7
|
constructor(services: CoreServices, wire: PikkuWire, options: {
|
|
11
|
-
coerceDataFromSchema?: boolean;
|
|
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>;
|
|
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;
|
|
16
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
25
|
getContextRPCService(services: Services, wire: PikkuWire, requiresAuth?: boolean | undefined, depth?: number): TypedRPC;
|
|
25
26
|
}
|
|
26
27
|
export declare const rpcService: PikkuRPCService<import("../../types/core.types.js").CoreSingletonServices<{
|
|
@@ -28,5 +29,3 @@ export declare const rpcService: PikkuRPCService<import("../../types/core.types.
|
|
|
28
29
|
secrets?: {};
|
|
29
30
|
workflow?: import("../workflow/workflow.types.js").WorkflowServiceConfig;
|
|
30
31
|
}>, PikkuRPC>;
|
|
31
|
-
export declare const initialize: (config: RPCServiceConfig) => void;
|
|
32
|
-
export {};
|
|
@@ -1,8 +1,29 @@
|
|
|
1
1
|
import { runPikkuFunc } from '../../function/function-runner.js';
|
|
2
2
|
import { pikkuState } from '../../pikku-state.js';
|
|
3
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
|
+
};
|
|
4
25
|
const getPikkuFunctionName = (rpcName) => {
|
|
5
|
-
const rpc = pikkuState('rpc', 'meta');
|
|
26
|
+
const rpc = pikkuState(null, 'rpc', 'meta');
|
|
6
27
|
const rpcMeta = rpc[rpcName];
|
|
7
28
|
if (!rpcMeta) {
|
|
8
29
|
throw new Error(`RPC function not found: ${rpcName}`);
|
|
@@ -20,7 +41,7 @@ export class ContextAwareRPCService {
|
|
|
20
41
|
this.options = options;
|
|
21
42
|
}
|
|
22
43
|
async rpcExposed(funcName, data) {
|
|
23
|
-
const functionMeta = pikkuState('function', 'meta')[funcName];
|
|
44
|
+
const functionMeta = pikkuState(null, 'function', 'meta')[funcName];
|
|
24
45
|
if (!functionMeta) {
|
|
25
46
|
throw new Error(`Function not found: ${funcName}`);
|
|
26
47
|
}
|
|
@@ -41,16 +62,54 @@ export class ContextAwareRPCService {
|
|
|
41
62
|
}
|
|
42
63
|
: undefined,
|
|
43
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
|
|
44
70
|
return runPikkuFunc('rpc', funcName, getPikkuFunctionName(funcName), {
|
|
45
71
|
auth: this.options.requiresAuth,
|
|
46
72
|
// TODO: this is a hack since services have already been created
|
|
47
73
|
// but is valid since we don't want to keep creating new wire services
|
|
48
74
|
singletonServices: this.services,
|
|
49
75
|
data: () => data,
|
|
50
|
-
coerceDataFromSchema: this.options.coerceDataFromSchema,
|
|
51
76
|
wire: updatedWire,
|
|
52
77
|
});
|
|
53
78
|
}
|
|
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
|
+
}
|
|
54
113
|
async rpcWithWire(rpcName, data, wire) {
|
|
55
114
|
const rpcDepth = this.wire.rpc?.depth || 0;
|
|
56
115
|
const mergedWire = {
|
|
@@ -68,7 +127,6 @@ export class ContextAwareRPCService {
|
|
|
68
127
|
auth: this.options.requiresAuth,
|
|
69
128
|
singletonServices: this.services,
|
|
70
129
|
data: () => data,
|
|
71
|
-
coerceDataFromSchema: this.options.coerceDataFromSchema,
|
|
72
130
|
wire: mergedWire,
|
|
73
131
|
});
|
|
74
132
|
}
|
|
@@ -81,15 +139,9 @@ export class ContextAwareRPCService {
|
|
|
81
139
|
}
|
|
82
140
|
// RPC Service class for the global interface
|
|
83
141
|
export class PikkuRPCService {
|
|
84
|
-
config;
|
|
85
|
-
// Initialize the RPC service with configuration
|
|
86
|
-
initialize(config) {
|
|
87
|
-
this.config = config;
|
|
88
|
-
}
|
|
89
142
|
// Convenience function for initializing
|
|
90
143
|
getContextRPCService(services, wire, requiresAuth, depth = 0) {
|
|
91
144
|
const serviceRPC = new ContextAwareRPCService(services, wire, {
|
|
92
|
-
coerceDataFromSchema: this.config?.coerceDataFromSchema,
|
|
93
145
|
requiresAuth,
|
|
94
146
|
});
|
|
95
147
|
return {
|
|
@@ -104,7 +156,3 @@ export class PikkuRPCService {
|
|
|
104
156
|
}
|
|
105
157
|
// Create a singleton instance
|
|
106
158
|
export const rpcService = new PikkuRPCService();
|
|
107
|
-
// Convenience function for initializing
|
|
108
|
-
export const initialize = (config) => {
|
|
109
|
-
rpcService.initialize(config);
|
|
110
|
-
};
|
|
@@ -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;
|
|
@@ -4,7 +4,7 @@ import { pikkuState } from '../../pikku-state.js';
|
|
|
4
4
|
import { addFunction, runPikkuFunc } from '../../function/function-runner.js';
|
|
5
5
|
import { PikkuSessionService } from '../../services/user-session-service.js';
|
|
6
6
|
export const wireScheduler = (scheduledTask) => {
|
|
7
|
-
const meta = pikkuState('scheduler', 'meta');
|
|
7
|
+
const meta = pikkuState(null, 'scheduler', 'meta');
|
|
8
8
|
const taskMeta = meta[scheduledTask.name];
|
|
9
9
|
if (!taskMeta) {
|
|
10
10
|
throw new Error('Task metadata not found');
|
|
@@ -16,7 +16,7 @@ export const wireScheduler = (scheduledTask) => {
|
|
|
16
16
|
middleware: scheduledTask.func.middleware,
|
|
17
17
|
tags: scheduledTask.func.tags,
|
|
18
18
|
});
|
|
19
|
-
const tasks = pikkuState('scheduler', 'tasks');
|
|
19
|
+
const tasks = pikkuState(null, 'scheduler', 'tasks');
|
|
20
20
|
if (tasks.has(scheduledTask.name)) {
|
|
21
21
|
throw new Error(`Scheduled task already exists: ${scheduledTask.name}`);
|
|
22
22
|
}
|
|
@@ -35,8 +35,8 @@ class ScheduledTaskSkippedError extends PikkuError {
|
|
|
35
35
|
}
|
|
36
36
|
export async function runScheduledTask({ name, session, singletonServices, createWireServices, }) {
|
|
37
37
|
let wireServices;
|
|
38
|
-
const task = pikkuState('scheduler', 'tasks').get(name);
|
|
39
|
-
const meta = pikkuState('scheduler', 'meta')[name];
|
|
38
|
+
const task = pikkuState(null, 'scheduler', 'tasks').get(name);
|
|
39
|
+
const meta = pikkuState(null, 'scheduler', 'meta')[name];
|
|
40
40
|
const userSession = new PikkuSessionService();
|
|
41
41
|
if (session) {
|
|
42
42
|
userSession.set(session);
|
|
@@ -86,5 +86,5 @@ export async function runScheduledTask({ name, session, singletonServices, creat
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
export const getScheduledTasks = () => {
|
|
89
|
-
return pikkuState('scheduler', 'tasks');
|
|
89
|
+
return pikkuState(null, 'scheduler', 'tasks');
|
|
90
90
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { CoreSingletonServices } from '../../types/core.types.js';
|
|
2
|
+
import type { CoreTrigger, TriggerInstance } from './trigger.types.js';
|
|
3
|
+
import type { CorePikkuTriggerFunctionConfig } from '../../function/functions.types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Registers a trigger with the Pikku framework.
|
|
6
|
+
* The trigger will be available for setup via setupTrigger.
|
|
7
|
+
*/
|
|
8
|
+
export declare const wireTrigger: <TConfig = unknown, TOutput = unknown, TriggerFunctionConfig extends CorePikkuTriggerFunctionConfig<TConfig, TOutput> = CorePikkuTriggerFunctionConfig<TConfig, TOutput>>(trigger: CoreTrigger<TConfig, TOutput, TriggerFunctionConfig>) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Parameters for setting up a trigger
|
|
11
|
+
*/
|
|
12
|
+
export type SetupTriggerParams<TOutput = unknown> = {
|
|
13
|
+
name: string;
|
|
14
|
+
singletonServices: CoreSingletonServices;
|
|
15
|
+
onTrigger: (data: TOutput) => void | Promise<void>;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Sets up a registered trigger and starts listening for events.
|
|
19
|
+
* Returns a TriggerInstance with a teardown function.
|
|
20
|
+
*/
|
|
21
|
+
export declare function setupTrigger<TOutput = unknown>({ name, singletonServices, onTrigger, }: SetupTriggerParams<TOutput>): Promise<TriggerInstance>;
|
|
22
|
+
/**
|
|
23
|
+
* Gets all registered triggers
|
|
24
|
+
*/
|
|
25
|
+
export declare const getRegisteredTriggers: () => Map<string, CoreTrigger<unknown, unknown, CorePikkuTriggerFunctionConfig<unknown, unknown>>>;
|
|
26
|
+
/**
|
|
27
|
+
* Gets trigger metadata
|
|
28
|
+
*/
|
|
29
|
+
export declare const getTriggerMeta: () => import("./trigger.types.js").TriggerMeta;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { pikkuState } from '../../pikku-state.js';
|
|
2
|
+
/**
|
|
3
|
+
* Registers a trigger with the Pikku framework.
|
|
4
|
+
* The trigger will be available for setup via setupTrigger.
|
|
5
|
+
*/
|
|
6
|
+
export const wireTrigger = (trigger) => {
|
|
7
|
+
const meta = pikkuState(null, 'trigger', 'meta');
|
|
8
|
+
const triggerMeta = meta[trigger.name];
|
|
9
|
+
if (!triggerMeta) {
|
|
10
|
+
throw new Error(`Trigger metadata not found: ${trigger.name}`);
|
|
11
|
+
}
|
|
12
|
+
const triggers = pikkuState(null, 'trigger', 'triggers');
|
|
13
|
+
if (triggers.has(trigger.name)) {
|
|
14
|
+
throw new Error(`Trigger already exists: ${trigger.name}`);
|
|
15
|
+
}
|
|
16
|
+
triggers.set(trigger.name, trigger);
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Sets up a registered trigger and starts listening for events.
|
|
20
|
+
* Returns a TriggerInstance with a teardown function.
|
|
21
|
+
*/
|
|
22
|
+
export async function setupTrigger({ name, singletonServices, onTrigger, }) {
|
|
23
|
+
const trigger = pikkuState(null, 'trigger', 'triggers').get(name);
|
|
24
|
+
const meta = pikkuState(null, 'trigger', 'meta')[name];
|
|
25
|
+
if (!trigger) {
|
|
26
|
+
throw new Error(`Trigger not found: ${name}`);
|
|
27
|
+
}
|
|
28
|
+
if (!meta) {
|
|
29
|
+
throw new Error(`Trigger metadata not found: ${name}`);
|
|
30
|
+
}
|
|
31
|
+
const wire = {
|
|
32
|
+
trigger: {
|
|
33
|
+
trigger: (data) => {
|
|
34
|
+
singletonServices.logger.info(`Trigger fired: ${name}`);
|
|
35
|
+
onTrigger(data);
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
singletonServices.logger.info(`Setting up trigger: ${name}`);
|
|
40
|
+
const teardown = await trigger.func.func(singletonServices, trigger.config, wire);
|
|
41
|
+
return {
|
|
42
|
+
name,
|
|
43
|
+
teardown,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Gets all registered triggers
|
|
48
|
+
*/
|
|
49
|
+
export const getRegisteredTriggers = () => {
|
|
50
|
+
return pikkuState(null, 'trigger', 'triggers');
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Gets trigger metadata
|
|
54
|
+
*/
|
|
55
|
+
export const getTriggerMeta = () => {
|
|
56
|
+
return pikkuState(null, 'trigger', 'meta');
|
|
57
|
+
};
|