@pikku/core 0.10.1 → 0.11.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.
- package/CHANGELOG.md +47 -0
- package/dist/function/function-runner.js +2 -2
- package/dist/function/functions.types.d.ts +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/middleware/auth-apikey.d.ts +1 -0
- package/dist/middleware/auth-bearer.d.ts +1 -0
- package/dist/middleware/auth-cookie.d.ts +1 -0
- package/dist/middleware/timeout.d.ts +1 -0
- package/dist/middleware-runner.js +1 -0
- package/dist/permissions.js +1 -0
- package/dist/pikku-state.d.ts +7 -2
- package/dist/pikku-state.js +4 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/scheduler-service.d.ts +63 -0
- package/dist/services/scheduler-service.js +6 -0
- package/dist/time-utils.d.ts +14 -0
- package/dist/time-utils.js +62 -0
- package/dist/types/core.types.d.ts +24 -2
- package/dist/types/core.types.js +1 -0
- package/dist/wirings/channel/channel-common.d.ts +28 -0
- package/dist/wirings/channel/channel-common.js +42 -0
- package/dist/wirings/channel/channel-handler.js +37 -11
- package/dist/wirings/channel/channel-runner.js +9 -4
- package/dist/wirings/channel/channel.types.d.ts +8 -2
- package/dist/wirings/channel/local/local-channel-handler.js +3 -0
- package/dist/wirings/channel/local/local-channel-runner.js +47 -14
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +90 -41
- package/dist/wirings/cli/channel/cli-channel-runner.js +10 -1
- package/dist/wirings/cli/cli-runner.d.ts +1 -1
- package/dist/wirings/cli/cli-runner.js +1 -1
- package/dist/wirings/http/http-runner.js +0 -1
- package/dist/wirings/mcp/mcp-runner.js +3 -2
- package/dist/wirings/queue/queue-runner.js +6 -3
- package/dist/wirings/queue/queue.types.d.ts +1 -3
- 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 +15 -0
- package/dist/wirings/rpc/rpc-runner.js +38 -3
- package/dist/wirings/rpc/rpc-types.d.ts +1 -0
- package/dist/wirings/workflow/index.d.ts +6 -0
- package/dist/wirings/workflow/index.js +6 -0
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +152 -0
- package/dist/wirings/workflow/pikku-workflow-service.js +448 -0
- package/dist/wirings/workflow/workflow-runner.d.ts +35 -0
- package/dist/wirings/workflow/workflow-runner.js +68 -0
- package/dist/wirings/workflow/workflow.types.d.ts +247 -0
- package/dist/wirings/workflow/workflow.types.js +1 -0
- package/package.json +2 -3
- package/src/function/function-runner.ts +2 -2
- package/src/function/functions.types.ts +1 -0
- package/src/index.ts +2 -0
- package/src/middleware-runner.ts +1 -0
- package/src/permissions.ts +1 -0
- package/src/pikku-state.ts +14 -2
- package/src/services/index.ts +1 -0
- package/src/services/scheduler-service.ts +76 -0
- package/src/time-utils.ts +75 -0
- package/src/types/core.types.ts +30 -1
- package/src/wirings/channel/channel-common.ts +80 -0
- package/src/wirings/channel/channel-handler.ts +48 -18
- package/src/wirings/channel/channel-runner.ts +15 -4
- package/src/wirings/channel/channel.types.ts +12 -2
- package/src/wirings/channel/local/local-channel-handler.ts +3 -0
- package/src/wirings/channel/local/local-channel-runner.ts +48 -36
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +134 -66
- package/src/wirings/cli/channel/cli-channel-runner.ts +13 -1
- package/src/wirings/cli/cli-runner.ts +2 -2
- package/src/wirings/http/http-runner.ts +0 -2
- package/src/wirings/mcp/mcp-runner.ts +5 -2
- package/src/wirings/queue/queue-runner.ts +14 -6
- package/src/wirings/queue/queue.types.ts +1 -4
- package/src/wirings/rpc/index.ts +1 -1
- package/src/wirings/rpc/rpc-runner.ts +57 -4
- package/src/wirings/rpc/rpc-types.ts +1 -0
- package/src/wirings/workflow/index.ts +22 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +756 -0
- package/src/wirings/workflow/workflow-runner.ts +85 -0
- package/src/wirings/workflow/workflow.types.ts +332 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -42,8 +42,14 @@ export type ChannelsMeta = Record<string, ChannelMeta>;
|
|
|
42
42
|
export type CoreChannel<ChannelData, Channel extends string, ChannelConnect = CorePikkuFunctionConfig<CorePikkuFunction<void, unknown, ChannelData> | CorePikkuFunctionSessionless<void, unknown, ChannelData>, CorePikkuPermission<void>, CorePikkuMiddleware>, ChannelDisconnect = CorePikkuFunctionConfig<CorePikkuFunction<void, void, ChannelData> | CorePikkuFunctionSessionless<void, void, ChannelData>, CorePikkuPermission<void>, CorePikkuMiddleware>, ChannelFunctionMessage = CorePikkuFunctionConfig<CorePikkuFunction<unknown, unknown, ChannelData> | CorePikkuFunctionSessionless<unknown, unknown, ChannelData>, CorePikkuPermission<unknown>, CorePikkuMiddleware>, PikkuPermission = CorePikkuPermission<ChannelData>, PikkuMiddleware = CorePikkuMiddleware> = {
|
|
43
43
|
name: string;
|
|
44
44
|
route: Channel;
|
|
45
|
-
onConnect?: ChannelConnect
|
|
46
|
-
|
|
45
|
+
onConnect?: ChannelConnect | {
|
|
46
|
+
func?: ChannelConnect;
|
|
47
|
+
middleware?: PikkuMiddleware[];
|
|
48
|
+
};
|
|
49
|
+
onDisconnect?: ChannelDisconnect | {
|
|
50
|
+
func?: ChannelDisconnect;
|
|
51
|
+
middleware?: PikkuMiddleware[];
|
|
52
|
+
};
|
|
47
53
|
onMessage?: ChannelFunctionMessage;
|
|
48
54
|
onMessageWiring?: Record<string, Record<string, ChannelFunctionMessage | {
|
|
49
55
|
func: ChannelFunctionMessage;
|
|
@@ -3,12 +3,10 @@ import { createHTTPInteraction } from '../../http/http-runner.js';
|
|
|
3
3
|
import { closeSessionServices } from '../../../utils.js';
|
|
4
4
|
import { processMessageHandlers } from '../channel-handler.js';
|
|
5
5
|
import { PikkuLocalChannelHandler } from './local-channel-handler.js';
|
|
6
|
-
import { PikkuWiringTypes, } from '../../../types/core.types.js';
|
|
7
6
|
import { handleHTTPError } from '../../../handle-error.js';
|
|
8
|
-
import { combineMiddleware, runMiddleware } from '../../../middleware-runner.js';
|
|
9
7
|
import { PikkuUserSessionService } from '../../../services/user-session-service.js';
|
|
10
|
-
import { runPikkuFuncDirectly } from '../../../function/function-runner.js';
|
|
11
8
|
import { rpcService } from '../../rpc/rpc-runner.js';
|
|
9
|
+
import { runChannelLifecycleWithMiddleware } from '../channel-common.js';
|
|
12
10
|
export const runLocalChannel = async ({ singletonServices, channelId, request, response, route, createSessionServices, skipUserSession = false, respondWith404 = true, coerceDataFromSchema = true, logWarningsForStatusCodes = [], bubbleErrors = false, }) => {
|
|
13
11
|
let sessionServices;
|
|
14
12
|
let channelHandler;
|
|
@@ -49,23 +47,64 @@ export const runLocalChannel = async ({ singletonServices, channelId, request, r
|
|
|
49
47
|
const getAllServices = (channel, requiresAuth) => rpcService.injectRPCService({
|
|
50
48
|
...singletonServices,
|
|
51
49
|
...sessionServices,
|
|
50
|
+
channel,
|
|
52
51
|
userSession,
|
|
53
52
|
}, interaction, requiresAuth);
|
|
54
53
|
const interaction = { channel };
|
|
55
|
-
channelHandler.registerOnOpen(() => {
|
|
54
|
+
channelHandler.registerOnOpen(async () => {
|
|
56
55
|
if (channelConfig.onConnect && meta.connect) {
|
|
57
|
-
|
|
56
|
+
try {
|
|
57
|
+
const result = await runChannelLifecycleWithMiddleware({
|
|
58
|
+
channelConfig,
|
|
59
|
+
meta: meta.connect,
|
|
60
|
+
lifecycleConfig: channelConfig.onConnect,
|
|
61
|
+
lifecycleType: 'connect',
|
|
62
|
+
services: getAllServices(channel, false),
|
|
63
|
+
channel,
|
|
64
|
+
data: openingData,
|
|
65
|
+
});
|
|
66
|
+
if (result !== undefined) {
|
|
67
|
+
await channel.send(result);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
singletonServices.logger.error(`Error handling onConnect: ${e}`);
|
|
72
|
+
channel.send({ error: e.message || 'Unknown error' });
|
|
73
|
+
}
|
|
58
74
|
}
|
|
59
75
|
});
|
|
60
76
|
channelHandler.registerOnClose(async () => {
|
|
61
77
|
if (channelConfig.onDisconnect && meta.disconnect) {
|
|
62
|
-
|
|
78
|
+
try {
|
|
79
|
+
await runChannelLifecycleWithMiddleware({
|
|
80
|
+
channelConfig,
|
|
81
|
+
meta: meta.disconnect,
|
|
82
|
+
lifecycleConfig: channelConfig.onDisconnect,
|
|
83
|
+
lifecycleType: 'disconnect',
|
|
84
|
+
services: getAllServices(channel, false),
|
|
85
|
+
channel,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
singletonServices.logger.error(`Error handling onDisconnect: ${e}`);
|
|
90
|
+
channel.send({ error: e.message || 'Unknown error' });
|
|
91
|
+
}
|
|
63
92
|
}
|
|
64
93
|
if (sessionServices) {
|
|
65
94
|
await closeSessionServices(singletonServices.logger, sessionServices);
|
|
66
95
|
}
|
|
67
96
|
});
|
|
68
|
-
|
|
97
|
+
const onMessage = processMessageHandlers(getAllServices(channel), channelConfig, channelHandler);
|
|
98
|
+
channelHandler.registerOnMessage(async (data) => {
|
|
99
|
+
try {
|
|
100
|
+
const result = await onMessage(data);
|
|
101
|
+
await channel.send(result);
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
singletonServices.logger.error(`Error handling message: ${e.message}`);
|
|
105
|
+
channel.send({ error: e.message || 'Unknown error' });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
69
108
|
}
|
|
70
109
|
catch (e) {
|
|
71
110
|
handleHTTPError(e, http, channelId, singletonServices.logger, logWarningsForStatusCodes, respondWith404, bubbleErrors);
|
|
@@ -76,12 +115,6 @@ export const runLocalChannel = async ({ singletonServices, channelId, request, r
|
|
|
76
115
|
}
|
|
77
116
|
}
|
|
78
117
|
};
|
|
79
|
-
await
|
|
80
|
-
...singletonServices,
|
|
81
|
-
userSession,
|
|
82
|
-
}, { http }, combineMiddleware(PikkuWiringTypes.channel, channelConfig.name, {
|
|
83
|
-
wireInheritedMiddleware: meta.middleware,
|
|
84
|
-
wireMiddleware: channelConfig.middleware,
|
|
85
|
-
}), main);
|
|
118
|
+
await main();
|
|
86
119
|
return channelHandler;
|
|
87
120
|
};
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import { PikkuWiringTypes } from '../../../types/core.types.js';
|
|
2
1
|
import { closeSessionServices } from '../../../utils.js';
|
|
3
2
|
import { processMessageHandlers } from '../channel-handler.js';
|
|
4
3
|
import { openChannel } from '../channel-runner.js';
|
|
5
4
|
import { createHTTPInteraction } from '../../http/http-runner.js';
|
|
6
5
|
import { handleHTTPError } from '../../../handle-error.js';
|
|
7
6
|
import { PikkuUserSessionService } from '../../../services/user-session-service.js';
|
|
8
|
-
import { combineMiddleware, runMiddleware } from '../../../middleware-runner.js';
|
|
9
7
|
import { pikkuState } from '../../../pikku-state.js';
|
|
10
8
|
import { PikkuFetchHTTPRequest } from '../../http/pikku-fetch-http-request.js';
|
|
11
|
-
import {
|
|
9
|
+
import { runChannelLifecycleWithMiddleware } from '../channel-common.js';
|
|
10
|
+
import { rpcService } from '../../rpc/rpc-runner.js';
|
|
12
11
|
const getVariablesForChannel = ({ channelId, channelName, channelHandlerFactory, openingData, }) => {
|
|
13
12
|
const channels = pikkuState('channel', 'channels');
|
|
14
|
-
const channelConfig = channels
|
|
13
|
+
const channelConfig = channels.get(channelName);
|
|
15
14
|
const channelsMeta = pikkuState('channel', 'meta');
|
|
16
15
|
const meta = channelsMeta[channelName];
|
|
17
16
|
if (!channelConfig) {
|
|
@@ -44,57 +43,95 @@ export const runChannelConnect = async ({ singletonServices, channelId, channelO
|
|
|
44
43
|
coerceDataFromSchema,
|
|
45
44
|
userSession,
|
|
46
45
|
});
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
sessionServices = await createSessionServices(singletonServices, { http }, await userSession.get());
|
|
62
|
-
}
|
|
63
|
-
if (channelConfig.onConnect && meta.connect) {
|
|
64
|
-
await runPikkuFuncDirectly(meta.connect.pikkuFuncName, { ...singletonServices, ...sessionServices, channel }, openingData);
|
|
65
|
-
}
|
|
66
|
-
http?.response?.status(101);
|
|
46
|
+
try {
|
|
47
|
+
await channelStore.addChannel({
|
|
48
|
+
channelId,
|
|
49
|
+
channelName: channelConfig.name,
|
|
50
|
+
openingData,
|
|
51
|
+
channelObject,
|
|
52
|
+
});
|
|
53
|
+
const { channel } = getVariablesForChannel({
|
|
54
|
+
channelId,
|
|
55
|
+
channelHandlerFactory,
|
|
56
|
+
channelName: channelConfig.name,
|
|
57
|
+
});
|
|
58
|
+
if (createSessionServices) {
|
|
59
|
+
sessionServices = await createSessionServices(singletonServices, { http }, await userSession.get());
|
|
67
60
|
}
|
|
68
|
-
|
|
69
|
-
|
|
61
|
+
const interaction = { channel };
|
|
62
|
+
const getAllServices = (requiresAuth) => rpcService.injectRPCService({
|
|
63
|
+
...singletonServices,
|
|
64
|
+
...sessionServices,
|
|
65
|
+
channel,
|
|
66
|
+
userSession,
|
|
67
|
+
}, interaction, requiresAuth);
|
|
68
|
+
if (channelConfig.onConnect && meta.connect) {
|
|
69
|
+
await runChannelLifecycleWithMiddleware({
|
|
70
|
+
channelConfig,
|
|
71
|
+
meta: meta.connect,
|
|
72
|
+
lifecycleConfig: channelConfig.onConnect,
|
|
73
|
+
lifecycleType: 'connect',
|
|
74
|
+
services: getAllServices(false),
|
|
75
|
+
channel,
|
|
76
|
+
data: openingData,
|
|
77
|
+
});
|
|
70
78
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
http?.response?.status(101);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
handleHTTPError(e, http, channelId, singletonServices.logger, logWarningsForStatusCodes, respondWith404, bubbleErrors);
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
if (sessionServices) {
|
|
86
|
+
await closeSessionServices(singletonServices.logger, sessionServices);
|
|
75
87
|
}
|
|
76
|
-
}
|
|
77
|
-
await runMiddleware({
|
|
78
|
-
...singletonServices,
|
|
79
|
-
userSession,
|
|
80
|
-
}, { http }, combineMiddleware(PikkuWiringTypes.channel, channelConfig.name, {
|
|
81
|
-
wireInheritedMiddleware: meta.middleware,
|
|
82
|
-
wireMiddleware: channelConfig.middleware,
|
|
83
|
-
}), main);
|
|
88
|
+
}
|
|
84
89
|
};
|
|
85
90
|
export const runChannelDisconnect = async ({ singletonServices, ...params }) => {
|
|
86
91
|
let sessionServices;
|
|
87
|
-
|
|
92
|
+
// Try to get channel from store. In serverless environments (especially with
|
|
93
|
+
// serverless-offline or worker threads), disconnect can be called multiple times
|
|
94
|
+
// or after the channel has already been cleaned up. If channel doesn't exist,
|
|
95
|
+
// there's nothing to disconnect, so we can return early.
|
|
96
|
+
let channelData;
|
|
97
|
+
try {
|
|
98
|
+
channelData = await params.channelStore.getChannelAndSession(params.channelId);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
singletonServices.logger.info(`Channel ${params.channelId} not found during disconnect - already cleaned up`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const { openingData, channelName, session } = channelData;
|
|
88
105
|
const { channel, channelConfig, meta } = getVariablesForChannel({
|
|
89
106
|
...params,
|
|
90
107
|
openingData,
|
|
91
108
|
channelName,
|
|
92
109
|
});
|
|
110
|
+
const userSession = new PikkuUserSessionService(params.channelStore, params.channelId);
|
|
93
111
|
if (!sessionServices && params.createSessionServices) {
|
|
94
112
|
sessionServices = await params.createSessionServices(singletonServices, { channel }, session);
|
|
95
113
|
}
|
|
114
|
+
const interaction = { channel };
|
|
115
|
+
const getAllServices = (requiresAuth) => rpcService.injectRPCService({
|
|
116
|
+
...singletonServices,
|
|
117
|
+
...sessionServices,
|
|
118
|
+
channel,
|
|
119
|
+
userSession,
|
|
120
|
+
}, interaction, requiresAuth);
|
|
96
121
|
if (channelConfig.onDisconnect && meta.disconnect) {
|
|
97
|
-
|
|
122
|
+
try {
|
|
123
|
+
await runChannelLifecycleWithMiddleware({
|
|
124
|
+
channelConfig,
|
|
125
|
+
meta: meta.disconnect,
|
|
126
|
+
lifecycleConfig: channelConfig.onDisconnect,
|
|
127
|
+
lifecycleType: 'disconnect',
|
|
128
|
+
services: getAllServices(false),
|
|
129
|
+
channel,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
singletonServices.logger.error(`Error handling onDisconnect: ${e.message || e}`);
|
|
134
|
+
}
|
|
98
135
|
}
|
|
99
136
|
await params.channelStore.removeChannels([channel.channelId]);
|
|
100
137
|
if (sessionServices) {
|
|
@@ -109,14 +146,26 @@ export const runChannelMessage = async ({ singletonServices, ...params }, data)
|
|
|
109
146
|
openingData,
|
|
110
147
|
channelName,
|
|
111
148
|
});
|
|
149
|
+
const userSession = new PikkuUserSessionService(params.channelStore, params.channelId);
|
|
112
150
|
if (params.createSessionServices) {
|
|
113
151
|
sessionServices = await params.createSessionServices(singletonServices, { channel }, session);
|
|
114
152
|
}
|
|
153
|
+
const interaction = { channel };
|
|
154
|
+
const getAllServices = () => rpcService.injectRPCService({
|
|
155
|
+
...singletonServices,
|
|
156
|
+
...sessionServices,
|
|
157
|
+
channel,
|
|
158
|
+
userSession,
|
|
159
|
+
}, interaction);
|
|
115
160
|
let response;
|
|
116
161
|
try {
|
|
117
|
-
const onMessage = processMessageHandlers(
|
|
162
|
+
const onMessage = processMessageHandlers(getAllServices(), channelConfig, channelHandler);
|
|
118
163
|
response = await onMessage(data);
|
|
119
164
|
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
singletonServices.logger.error(`Error processing message: ${e.message || e}`);
|
|
167
|
+
return { error: e.message || 'Unknown error' };
|
|
168
|
+
}
|
|
120
169
|
finally {
|
|
121
170
|
if (sessionServices) {
|
|
122
171
|
await closeSessionServices(singletonServices.logger, sessionServices);
|
|
@@ -14,7 +14,7 @@ export async function executeCLIViaChannel({ programName, pikkuWS, args = proces
|
|
|
14
14
|
// Get CLI metadata from state
|
|
15
15
|
const allCLIMeta = pikkuState('cli', 'meta');
|
|
16
16
|
if (!allCLIMeta) {
|
|
17
|
-
throw new Error('[PKU342] CLI metadata not found. No CLI wirings were registered. See https://pikku.dev/errors/pku342 for more information.');
|
|
17
|
+
throw new Error('[PKU342] CLI metadata not found. No CLI wirings were registered. See https://pikku.dev/docs/pikku-cli/errors/pku342 for more information.');
|
|
18
18
|
}
|
|
19
19
|
const programMeta = allCLIMeta.programs[programName];
|
|
20
20
|
if (!programMeta) {
|
|
@@ -55,6 +55,15 @@ export async function executeCLIViaChannel({ programName, pikkuWS, args = proces
|
|
|
55
55
|
// Subscribe to responses for this command
|
|
56
56
|
const commandRoute = pikkuWS.getRoute('command');
|
|
57
57
|
const responseHandler = (response) => {
|
|
58
|
+
// Check if this is a control message
|
|
59
|
+
if (response?.action === 'cli-control' &&
|
|
60
|
+
response?.event === 'complete') {
|
|
61
|
+
// Server signals command is complete, close the connection client-side
|
|
62
|
+
commandRoute.unsubscribe(commandId, responseHandler);
|
|
63
|
+
pikkuWS.ws.close();
|
|
64
|
+
resolve(undefined);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
58
67
|
// Call renderer for any output
|
|
59
68
|
renderer(null, response, undefined);
|
|
60
69
|
};
|
|
@@ -38,5 +38,5 @@ export declare function executeCLI({ programName, args, createConfig, createSing
|
|
|
38
38
|
args?: string[];
|
|
39
39
|
createConfig: CreateConfig<any, any>;
|
|
40
40
|
createSingletonServices: CreateSingletonServices<any, any>;
|
|
41
|
-
createSessionServices?: CreateSessionServices<any, any>;
|
|
41
|
+
createSessionServices?: CreateSessionServices<any, any, any>;
|
|
42
42
|
}): Promise<void>;
|
|
@@ -286,7 +286,7 @@ export async function executeCLI({ programName, args, createConfig, createSingle
|
|
|
286
286
|
// Get CLI metadata from state
|
|
287
287
|
const allCLIMeta = pikkuState('cli', 'meta');
|
|
288
288
|
if (!allCLIMeta) {
|
|
289
|
-
throw new Error('[PKU342] CLI metadata not found. No CLI wirings were registered. See https://pikku.dev/errors/pku342 for more information.');
|
|
289
|
+
throw new Error('[PKU342] CLI metadata not found. No CLI wirings were registered. See https://pikku.dev/docs/pikku-cli/errors/pku342 for more information.');
|
|
290
290
|
}
|
|
291
291
|
const programMeta = allCLIMeta.programs[programName];
|
|
292
292
|
if (!programMeta) {
|
|
@@ -221,7 +221,6 @@ const executeRoute = async (services, matchedRoute, http, options) => {
|
|
|
221
221
|
}
|
|
222
222
|
const interaction = { http, channel };
|
|
223
223
|
const getAllServices = async (session) => {
|
|
224
|
-
let channel;
|
|
225
224
|
// Create session-specific services for handling the request
|
|
226
225
|
sessionServices = await createSessionServices({ ...singletonServices, userSession, channel }, { http }, session);
|
|
227
226
|
return rpcService.injectRPCService({
|
|
@@ -20,7 +20,7 @@ export const wireMCPResource = (mcpResource) => {
|
|
|
20
20
|
if (!mcpResourceMeta) {
|
|
21
21
|
throw new Error(`MCP resource metadata not found for '${mcpResource.uri}'`);
|
|
22
22
|
}
|
|
23
|
-
addFunction(mcpResourceMeta.pikkuFuncName, mcpResource);
|
|
23
|
+
addFunction(mcpResourceMeta.pikkuFuncName, mcpResource.func);
|
|
24
24
|
const resources = pikkuState('mcp', 'resources');
|
|
25
25
|
if (resources.has(mcpResource.uri)) {
|
|
26
26
|
throw new Error(`MCP resource already exists: ${mcpResource.uri}`);
|
|
@@ -85,7 +85,7 @@ export async function runMCPResource(request, params, uri) {
|
|
|
85
85
|
return await runMCPPikkuFunc({
|
|
86
86
|
...request,
|
|
87
87
|
params: { ...request.params, ...extractedParams },
|
|
88
|
-
}, 'resource', uri, endpoint, pikkuFuncName, { ...params, mcp: { uri } });
|
|
88
|
+
}, 'resource', uri, endpoint, pikkuFuncName, { ...params, mcp: { ...params.mcp, uri } });
|
|
89
89
|
}
|
|
90
90
|
export async function runMCPTool(request, params, name) {
|
|
91
91
|
const endpoint = pikkuState('mcp', 'tools').get(name);
|
|
@@ -120,6 +120,7 @@ async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncName, { single
|
|
|
120
120
|
return rpcService.injectRPCService({
|
|
121
121
|
...singletonServices,
|
|
122
122
|
...sessionServices,
|
|
123
|
+
mcp: mcpInteraction,
|
|
123
124
|
}, interaction);
|
|
124
125
|
};
|
|
125
126
|
// Get metadata for the MCP endpoint to access pre-resolved middleware
|
|
@@ -2,6 +2,7 @@ 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
4
|
import { PikkuWiringTypes, } from '../../types/core.types.js';
|
|
5
|
+
import { rpcService } from '../rpc/rpc-runner.js';
|
|
5
6
|
/**
|
|
6
7
|
* Error class for queue processor not found
|
|
7
8
|
*/
|
|
@@ -102,13 +103,15 @@ export async function runQueueJob({ singletonServices, createSessionServices, jo
|
|
|
102
103
|
};
|
|
103
104
|
try {
|
|
104
105
|
logger.info(`Processing job ${job.id} in queue ${job.queueName}`);
|
|
106
|
+
const interaction = { queue };
|
|
105
107
|
// Use provided singleton services
|
|
106
108
|
const getAllServices = async () => {
|
|
107
109
|
const sessionServices = await createSessionServices?.(singletonServices, { queue }, undefined);
|
|
108
|
-
|
|
110
|
+
const services = rpcService.injectRPCService({
|
|
109
111
|
...singletonServices,
|
|
110
112
|
...sessionServices,
|
|
111
|
-
};
|
|
113
|
+
}, interaction, false);
|
|
114
|
+
return services;
|
|
112
115
|
};
|
|
113
116
|
// Execute the pikku function with the job data
|
|
114
117
|
const result = await runPikkuFunc(PikkuWiringTypes.queue, job.queueName, processorMeta.pikkuFuncName, {
|
|
@@ -119,7 +122,7 @@ export async function runQueueJob({ singletonServices, createSessionServices, jo
|
|
|
119
122
|
inheritedMiddleware: processorMeta.middleware,
|
|
120
123
|
wireMiddleware: queueWorker.middleware,
|
|
121
124
|
tags: queueWorker.tags,
|
|
122
|
-
interaction
|
|
125
|
+
interaction,
|
|
123
126
|
});
|
|
124
127
|
logger.debug(`Successfully processed job ${job.id} in queue ${job.queueName}`);
|
|
125
128
|
return result;
|
|
@@ -126,13 +126,11 @@ export interface QueueWorkers {
|
|
|
126
126
|
configMappings: QueueConfigMapping;
|
|
127
127
|
/** Scan state and register all compatible processors */
|
|
128
128
|
registerQueues(): Promise<Record<string, ConfigValidationResult[]>>;
|
|
129
|
-
/** Close all queues and connections */
|
|
130
|
-
close(): Promise<void>;
|
|
131
129
|
}
|
|
132
130
|
/**
|
|
133
131
|
* Queue processor metadata
|
|
134
132
|
*/
|
|
135
|
-
export type
|
|
133
|
+
export type QueueWorkersMeta = Record<string, {
|
|
136
134
|
pikkuFuncName: string;
|
|
137
135
|
schemaName?: string;
|
|
138
136
|
queueName: string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { initialize, PikkuRPCService } from './rpc-runner.js';
|
|
1
|
+
export { initialize, PikkuRPCService, rpcService } from './rpc-runner.js';
|
|
2
2
|
export type { PikkuRPC, RPCMeta } from './rpc-types.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { initialize, PikkuRPCService } from './rpc-runner.js';
|
|
1
|
+
export { initialize, PikkuRPCService, rpcService } from './rpc-runner.js';
|
|
@@ -3,6 +3,21 @@ import { PikkuRPC } from './rpc-types.js';
|
|
|
3
3
|
type RPCServiceConfig = {
|
|
4
4
|
coerceDataFromSchema: boolean;
|
|
5
5
|
};
|
|
6
|
+
export declare class ContextAwareRPCService {
|
|
7
|
+
private services;
|
|
8
|
+
private interaction;
|
|
9
|
+
private options;
|
|
10
|
+
constructor(services: CoreServices, interaction: PikkuInteraction, options: {
|
|
11
|
+
coerceDataFromSchema?: boolean;
|
|
12
|
+
requiresAuth?: boolean;
|
|
13
|
+
});
|
|
14
|
+
rpcExposed(funcName: string, data: any): Promise<any>;
|
|
15
|
+
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>;
|
|
17
|
+
startWorkflow<In = any>(workflowName: string, input: In): Promise<{
|
|
18
|
+
runId: string;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
6
21
|
export declare class PikkuRPCService<Services extends CoreServices, TypedRPC = PikkuRPC> {
|
|
7
22
|
private config?;
|
|
8
23
|
initialize(config: RPCServiceConfig): void;
|
|
@@ -11,7 +11,7 @@ const getPikkuFunctionName = (rpcName) => {
|
|
|
11
11
|
return rpcMeta;
|
|
12
12
|
};
|
|
13
13
|
// Context-aware RPC client for use within services
|
|
14
|
-
class ContextAwareRPCService {
|
|
14
|
+
export class ContextAwareRPCService {
|
|
15
15
|
services;
|
|
16
16
|
interaction;
|
|
17
17
|
options;
|
|
@@ -32,8 +32,7 @@ class ContextAwareRPCService {
|
|
|
32
32
|
}
|
|
33
33
|
async rpc(funcName, data) {
|
|
34
34
|
const rpcDepth = this.services.rpc?.depth || 0;
|
|
35
|
-
|
|
36
|
-
return runPikkuFunc(PikkuWiringTypes.rpc, pikkuFuncName, pikkuFuncName, {
|
|
35
|
+
return runPikkuFunc(PikkuWiringTypes.rpc, funcName, getPikkuFunctionName(funcName), {
|
|
37
36
|
auth: this.options.requiresAuth,
|
|
38
37
|
singletonServices: this.services,
|
|
39
38
|
getAllServices: () => {
|
|
@@ -52,6 +51,40 @@ class ContextAwareRPCService {
|
|
|
52
51
|
interaction: this.interaction,
|
|
53
52
|
});
|
|
54
53
|
}
|
|
54
|
+
async rpcWithInteraction(funcName, data, interaction) {
|
|
55
|
+
const rpcDepth = this.services.rpc?.depth || 0;
|
|
56
|
+
const mergedInteraction = {
|
|
57
|
+
...this.interaction,
|
|
58
|
+
...interaction,
|
|
59
|
+
};
|
|
60
|
+
return runPikkuFunc(PikkuWiringTypes.rpc, funcName, getPikkuFunctionName(funcName), {
|
|
61
|
+
auth: this.options.requiresAuth,
|
|
62
|
+
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
|
+
data: () => data,
|
|
77
|
+
userSession: this.services.userSession,
|
|
78
|
+
coerceDataFromSchema: this.options.coerceDataFromSchema,
|
|
79
|
+
interaction: mergedInteraction,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
async startWorkflow(workflowName, input) {
|
|
83
|
+
if (!this.services.workflowService) {
|
|
84
|
+
throw new Error('WorkflowService service not available');
|
|
85
|
+
}
|
|
86
|
+
return this.services.workflowService.startWorkflow(workflowName, input, this);
|
|
87
|
+
}
|
|
55
88
|
}
|
|
56
89
|
// RPC Service class for the global interface
|
|
57
90
|
export class PikkuRPCService {
|
|
@@ -74,6 +107,8 @@ export class PikkuRPCService {
|
|
|
74
107
|
global: false,
|
|
75
108
|
invoke: serviceRPC.rpc.bind(serviceRPC),
|
|
76
109
|
invokeExposed: serviceRPC.rpc.bind(serviceRPC),
|
|
110
|
+
startWorkflow: serviceRPC.startWorkflow.bind(serviceRPC),
|
|
111
|
+
rpcWithInteraction: serviceRPC.rpcWithInteraction.bind(serviceRPC),
|
|
77
112
|
};
|
|
78
113
|
return serviceCopy;
|
|
79
114
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow module exports
|
|
3
|
+
*/
|
|
4
|
+
export type { CoreWorkflow, WorkflowStepOptions, WorkflowStepMeta, PikkuWorkflowInteraction, PikkuWorkflow, WorkflowsMeta, WorkflowRun, StepState, WorkflowStatus, StepStatus, } from './workflow.types.js';
|
|
5
|
+
export { PikkuWorkflowService } from './pikku-workflow-service.js';
|
|
6
|
+
export { wireWorkflow } from './workflow-runner.js';
|