@pikku/core 0.9.5 → 0.9.7
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 +15 -0
- package/dist/function/function-runner.d.ts +2 -2
- package/dist/function/function-runner.js +3 -3
- package/dist/function/functions.types.d.ts +4 -0
- package/dist/function/functions.types.js +6 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/middleware-runner.d.ts +5 -4
- package/dist/middleware-runner.js +20 -6
- package/dist/permissions.d.ts +3 -3
- package/dist/permissions.js +30 -8
- package/dist/pikku-state.d.ts +2 -4
- package/dist/pikku-state.js +3 -2
- package/dist/schema.js +8 -6
- package/dist/services/local-content.js +1 -0
- package/dist/types/core.types.d.ts +4 -0
- package/dist/types/core.types.js +6 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +17 -0
- package/dist/wirings/channel/channel-handler.js +2 -1
- package/dist/wirings/channel/channel-runner.d.ts +2 -0
- package/dist/wirings/channel/channel-runner.js +23 -25
- package/dist/wirings/channel/local/local-channel-runner.js +5 -3
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +4 -2
- package/dist/wirings/http/http-runner.js +36 -53
- package/dist/wirings/http/http.types.d.ts +1 -1
- package/dist/wirings/http/pikku-fetch-http-request.js +4 -1
- package/dist/wirings/http/routers/http-router.d.ts +12 -0
- package/dist/wirings/http/routers/http-router.js +2 -0
- package/dist/wirings/http/routers/path-to-regex.d.ts +10 -0
- package/dist/wirings/http/routers/path-to-regex.js +118 -0
- package/dist/wirings/mcp/mcp-runner.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.js +3 -2
- package/dist/wirings/queue/queue-runner.js +3 -2
- package/dist/wirings/rpc/rpc-runner.js +2 -1
- package/dist/wirings/scheduler/scheduler-runner.d.ts +1 -1
- package/dist/wirings/scheduler/scheduler-runner.js +3 -2
- package/package.json +1 -1
- package/run-tests.sh +1 -1
- package/src/factory-functions.test.ts +37 -0
- package/src/function/function-runner.test.ts +101 -52
- package/src/function/function-runner.ts +5 -2
- package/src/function/functions.types.ts +13 -0
- package/src/index.ts +3 -11
- package/src/middleware-runner.test.ts +71 -43
- package/src/middleware-runner.ts +43 -17
- package/src/permissions.test.ts +21 -17
- package/src/permissions.ts +68 -26
- package/src/pikku-state.ts +5 -3
- package/src/schema.ts +8 -6
- package/src/services/local-content.ts +1 -0
- package/src/types/core.types.ts +12 -0
- package/src/utils.ts +19 -0
- package/src/wirings/channel/channel-handler.ts +17 -11
- package/src/wirings/channel/channel-runner.ts +31 -25
- package/src/wirings/channel/local/local-channel-runner.test.ts +4 -0
- package/src/wirings/channel/local/local-channel-runner.ts +5 -4
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +13 -11
- package/src/wirings/http/http-runner.test.ts +18 -6
- package/src/wirings/http/http-runner.ts +55 -74
- package/src/wirings/http/http.types.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-request.ts +4 -1
- package/src/wirings/http/routers/http-router.ts +15 -0
- package/src/wirings/http/routers/path-to-regex.test.ts +309 -0
- package/src/wirings/http/routers/path-to-regex.ts +162 -0
- package/src/wirings/mcp/mcp-runner.ts +18 -12
- package/src/wirings/queue/queue-runner.ts +15 -7
- package/src/wirings/rpc/rpc-runner.ts +21 -16
- package/src/wirings/scheduler/scheduler-runner.ts +18 -12
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/pikku-function.d.ts +0 -1
- package/dist/pikku-function.js +0 -1
- package/src/pikku-function.ts +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PikkuWiringTypes, } from '../../types/core.types.js';
|
|
2
2
|
import { MissingSessionError, NotFoundError } from '../../errors/errors.js';
|
|
3
3
|
import { closeSessionServices, createWeakUID, isSerializable, } from '../../utils.js';
|
|
4
4
|
import { PikkuUserSessionService, } from '../../services/user-session-service.js';
|
|
@@ -9,6 +9,7 @@ import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js';
|
|
|
9
9
|
import { PikkuFetchHTTPRequest } from './pikku-fetch-http-request.js';
|
|
10
10
|
import { addFunction, runPikkuFunc } from '../../function/function-runner.js';
|
|
11
11
|
import { rpcService } from '../rpc/rpc-runner.js';
|
|
12
|
+
import { httpRouter } from './routers/http-router.js';
|
|
12
13
|
/**
|
|
13
14
|
* Registers middleware either globally or for a specific route.
|
|
14
15
|
*
|
|
@@ -22,25 +23,20 @@ import { rpcService } from '../rpc/rpc-runner.js';
|
|
|
22
23
|
*/
|
|
23
24
|
export const addHTTPMiddleware = (routeOrMiddleware, middleware) => {
|
|
24
25
|
const middlewareStore = pikkuState('http', 'middleware');
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (existingIndex !== -1) {
|
|
30
|
-
middlewareStore.splice(existingIndex, 1);
|
|
31
|
-
}
|
|
32
|
-
middlewareStore.push({ route, middleware });
|
|
26
|
+
let route = '*';
|
|
27
|
+
if (typeof routeOrMiddleware === 'string') {
|
|
28
|
+
route = routeOrMiddleware;
|
|
29
|
+
middleware = middleware;
|
|
33
30
|
}
|
|
34
31
|
else {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
});
|
|
32
|
+
middleware = routeOrMiddleware;
|
|
33
|
+
}
|
|
34
|
+
const currentMiddleware = middlewareStore.get(route);
|
|
35
|
+
if (currentMiddleware) {
|
|
36
|
+
middlewareStore.set(route, [...currentMiddleware, ...middleware]);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
middlewareStore.set(route, middleware);
|
|
44
40
|
}
|
|
45
41
|
};
|
|
46
42
|
/**
|
|
@@ -60,7 +56,7 @@ export const addHTTPMiddleware = (routeOrMiddleware, middleware) => {
|
|
|
60
56
|
*/
|
|
61
57
|
export const wireHTTP = (httpWiring) => {
|
|
62
58
|
const httpMeta = pikkuState('http', 'meta');
|
|
63
|
-
const routeMeta = httpMeta
|
|
59
|
+
const routeMeta = httpMeta[httpWiring.method][httpWiring.route];
|
|
64
60
|
if (!routeMeta) {
|
|
65
61
|
throw new Error('Route metadata not found');
|
|
66
62
|
}
|
|
@@ -85,37 +81,22 @@ export const wireHTTP = (httpWiring) => {
|
|
|
85
81
|
* @returns {Object | undefined} An object with matched route details or undefined if no match.
|
|
86
82
|
*/
|
|
87
83
|
const getMatchingRoute = (requestType, requestPath) => {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const globalMiddleware = middleware
|
|
104
|
-
.filter((m) => m.route === '*' || new RegExp(m.route).test(route.route))
|
|
105
|
-
.map((m) => m.middleware)
|
|
106
|
-
.flat();
|
|
107
|
-
const meta = pikkuState('http', 'meta').find((meta) => meta.route === route.route && meta.method === route.method);
|
|
108
|
-
return {
|
|
109
|
-
matchedPath,
|
|
110
|
-
params: matchedPath.params,
|
|
111
|
-
route,
|
|
112
|
-
permissions: route.permissions,
|
|
113
|
-
middleware: [...globalMiddleware, ...(route.middleware || [])],
|
|
114
|
-
meta: meta,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
84
|
+
const matchedPath = httpRouter.match(requestType.toLowerCase(), requestPath);
|
|
85
|
+
if (matchedPath) {
|
|
86
|
+
const route = pikkuState('http', 'routes')
|
|
87
|
+
.get(requestType.toLowerCase())
|
|
88
|
+
.get(matchedPath.route);
|
|
89
|
+
const meta = pikkuState('http', 'meta')[requestType.toLowerCase()][route.route];
|
|
90
|
+
return {
|
|
91
|
+
matchedPath,
|
|
92
|
+
params: matchedPath.params,
|
|
93
|
+
route,
|
|
94
|
+
permissions: route.permissions,
|
|
95
|
+
httpMiddleware: matchedPath.middleware,
|
|
96
|
+
middleware: route.middleware,
|
|
97
|
+
meta: meta,
|
|
98
|
+
};
|
|
117
99
|
}
|
|
118
|
-
return undefined;
|
|
119
100
|
};
|
|
120
101
|
/**
|
|
121
102
|
* Combines the request and response objects into a single HTTP interaction object.
|
|
@@ -170,7 +151,7 @@ export const createHTTPInteraction = (request, response) => {
|
|
|
170
151
|
* @throws Throws errors like MissingSessionError or ForbiddenError on validation failures.
|
|
171
152
|
*/
|
|
172
153
|
const executeRouteWithMiddleware = async (services, matchedRoute, http, options) => {
|
|
173
|
-
const { matchedPath, params, route, middleware, meta } = matchedRoute;
|
|
154
|
+
const { matchedPath, params, route, httpMiddleware, middleware, meta } = matchedRoute;
|
|
174
155
|
const { singletonServices, userSession, createSessionServices, skipUserSession, requestId, } = services;
|
|
175
156
|
const requiresSession = route.auth !== false;
|
|
176
157
|
let sessionServices;
|
|
@@ -231,7 +212,7 @@ const executeRouteWithMiddleware = async (services, matchedRoute, http, options)
|
|
|
231
212
|
channel,
|
|
232
213
|
});
|
|
233
214
|
};
|
|
234
|
-
result = await runPikkuFunc(meta.pikkuFuncName, {
|
|
215
|
+
result = await runPikkuFunc(PikkuWiringTypes.http, `${meta.method}:${meta.route}`, meta.pikkuFuncName, {
|
|
235
216
|
getAllServices,
|
|
236
217
|
session,
|
|
237
218
|
data,
|
|
@@ -253,7 +234,8 @@ const executeRouteWithMiddleware = async (services, matchedRoute, http, options)
|
|
|
253
234
|
// Get function config for middleware and tags
|
|
254
235
|
const funcConfig = pikkuState('function', 'functions').get(meta.pikkuFuncName);
|
|
255
236
|
// Execute middleware, then run the main logic
|
|
256
|
-
await runMiddleware({ ...singletonServices, userSession }, { http }, combineMiddleware({
|
|
237
|
+
await runMiddleware({ ...singletonServices, userSession }, { http }, combineMiddleware(PikkuWiringTypes.http, `${meta.method}:${meta.route}`, {
|
|
238
|
+
httpMiddleware,
|
|
257
239
|
wiringMiddleware: middleware,
|
|
258
240
|
wiringTags: route.tags,
|
|
259
241
|
funcMiddleware: funcConfig?.middleware,
|
|
@@ -350,7 +332,8 @@ export const fetchData = async (request, response, { singletonServices, createSe
|
|
|
350
332
|
}, ignoreMiddleware
|
|
351
333
|
? {
|
|
352
334
|
...matchedRoute,
|
|
353
|
-
middleware:
|
|
335
|
+
middleware: undefined,
|
|
336
|
+
httpMiddleware: undefined,
|
|
354
337
|
}
|
|
355
338
|
: matchedRoute, http, { coerceDataFromSchema }));
|
|
356
339
|
return result;
|
|
@@ -147,7 +147,7 @@ export type HTTPWiringMeta = {
|
|
|
147
147
|
tags?: string[];
|
|
148
148
|
sse?: true;
|
|
149
149
|
};
|
|
150
|
-
export type HTTPWiringsMeta =
|
|
150
|
+
export type HTTPWiringsMeta = Record<HTTPMethod, Record<string, HTTPWiringMeta>>;
|
|
151
151
|
export type HTTPFunctionsMeta = Array<{
|
|
152
152
|
name: string;
|
|
153
153
|
inputs: string[] | null;
|
|
@@ -48,6 +48,9 @@ export class PikkuFetchHTTPRequest {
|
|
|
48
48
|
* @returns An object containing the cookies.
|
|
49
49
|
*/
|
|
50
50
|
cookie(cookieName) {
|
|
51
|
+
if (this.#cookies?.[cookieName]) {
|
|
52
|
+
return this.#cookies[cookieName];
|
|
53
|
+
}
|
|
51
54
|
const cookieHeader = this.header('cookie');
|
|
52
55
|
this.#cookies = cookieHeader ? parseCookie(cookieHeader) : {};
|
|
53
56
|
return this.#cookies[cookieName] || null;
|
|
@@ -92,7 +95,7 @@ export class PikkuFetchHTTPRequest {
|
|
|
92
95
|
return merged;
|
|
93
96
|
}
|
|
94
97
|
async body() {
|
|
95
|
-
const noBodyMethods = ['get', 'head', 'options'];
|
|
98
|
+
const noBodyMethods = ['get', 'head', 'options', 'delete'];
|
|
96
99
|
if (noBodyMethods.includes(this.method())) {
|
|
97
100
|
return {};
|
|
98
101
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CorePikkuMiddleware } from '../../../types/core.types.js';
|
|
2
|
+
import { HTTPMethod } from '../http.types.js';
|
|
3
|
+
import { PathToRegexRouter } from './path-to-regex.js';
|
|
4
|
+
export type MatchResult = {
|
|
5
|
+
route: string;
|
|
6
|
+
params: Record<string, any>;
|
|
7
|
+
middleware?: CorePikkuMiddleware[];
|
|
8
|
+
} | null;
|
|
9
|
+
export interface Router {
|
|
10
|
+
match(method: HTTPMethod, path: string): MatchResult;
|
|
11
|
+
}
|
|
12
|
+
export declare const httpRouter: PathToRegexRouter;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { MatchResult, Router } from './http-router.js';
|
|
2
|
+
import { HTTPMethod } from '../http.types.js';
|
|
3
|
+
export declare class PathToRegexRouter implements Router {
|
|
4
|
+
private compiledRoutes;
|
|
5
|
+
private staticRoutes;
|
|
6
|
+
private precompiledMiddleware;
|
|
7
|
+
private isInitialized;
|
|
8
|
+
initialize(): void;
|
|
9
|
+
match(method: HTTPMethod, path: string): MatchResult;
|
|
10
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { match } from 'path-to-regexp';
|
|
2
|
+
import { pikkuState } from '../../../pikku-state.js';
|
|
3
|
+
export class PathToRegexRouter {
|
|
4
|
+
compiledRoutes = new Map();
|
|
5
|
+
staticRoutes = new Map();
|
|
6
|
+
precompiledMiddleware = new Map();
|
|
7
|
+
isInitialized = false;
|
|
8
|
+
initialize() {
|
|
9
|
+
const routes = pikkuState('http', 'routes');
|
|
10
|
+
const channelRoutes = pikkuState('channel', 'channels');
|
|
11
|
+
const middlewareMap = pikkuState('http', 'middleware');
|
|
12
|
+
// Precompile middleware lookups
|
|
13
|
+
for (const [middlewareRoute, middlewareArray] of middlewareMap.entries()) {
|
|
14
|
+
this.precompiledMiddleware.set(middlewareRoute, middlewareArray);
|
|
15
|
+
}
|
|
16
|
+
// Helper function to compile routes for a given method
|
|
17
|
+
const compileRoutesForMethod = (method, routeEntries) => {
|
|
18
|
+
const methodCompiledRoutes = this.compiledRoutes.get(method) || new Map();
|
|
19
|
+
const methodStaticRoutes = this.staticRoutes.get(method) || new Map();
|
|
20
|
+
for (const [routePath] of routeEntries) {
|
|
21
|
+
// Normalize route path - ensure it starts with /
|
|
22
|
+
const normalizedRoutePath = routePath.startsWith('/')
|
|
23
|
+
? routePath
|
|
24
|
+
: `/${routePath}`;
|
|
25
|
+
// Check if route is static (no parameters or wildcards)
|
|
26
|
+
const isStaticRoute = !/\*|:/.test(normalizedRoutePath);
|
|
27
|
+
// Precompute middleware for this route
|
|
28
|
+
const routeMiddleware = [];
|
|
29
|
+
// Add global middleware (*)
|
|
30
|
+
const globalMiddleware = this.precompiledMiddleware.get('*');
|
|
31
|
+
if (globalMiddleware) {
|
|
32
|
+
routeMiddleware.push(...globalMiddleware);
|
|
33
|
+
}
|
|
34
|
+
// Add route-specific middleware
|
|
35
|
+
for (const [middlewareRoute, middlewareArray,] of this.precompiledMiddleware.entries()) {
|
|
36
|
+
if (middlewareRoute !== '*') {
|
|
37
|
+
// Use regex test for pattern matching
|
|
38
|
+
try {
|
|
39
|
+
if (new RegExp(middlewareRoute).test(normalizedRoutePath)) {
|
|
40
|
+
routeMiddleware.push(...middlewareArray);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// If regex is invalid, do exact match
|
|
45
|
+
if (middlewareRoute === normalizedRoutePath) {
|
|
46
|
+
routeMiddleware.push(...middlewareArray);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (isStaticRoute) {
|
|
52
|
+
// Store static routes for O(1) lookup
|
|
53
|
+
methodStaticRoutes.set(normalizedRoutePath, {
|
|
54
|
+
route: routePath, // Keep the original route path for lookup in pikkuState
|
|
55
|
+
middleware: routeMiddleware,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Compile dynamic routes with path-to-regexp
|
|
60
|
+
const matcher = match(normalizedRoutePath, {
|
|
61
|
+
decode: decodeURIComponent,
|
|
62
|
+
});
|
|
63
|
+
methodCompiledRoutes.set(normalizedRoutePath, {
|
|
64
|
+
matcher,
|
|
65
|
+
route: routePath, // Keep the original route path for lookup in pikkuState
|
|
66
|
+
middleware: routeMiddleware,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
this.compiledRoutes.set(method, methodCompiledRoutes);
|
|
71
|
+
this.staticRoutes.set(method, methodStaticRoutes);
|
|
72
|
+
};
|
|
73
|
+
// Precompile all HTTP route matchers
|
|
74
|
+
for (const [method, routeMap] of routes.entries()) {
|
|
75
|
+
compileRoutesForMethod(method, routeMap.entries());
|
|
76
|
+
}
|
|
77
|
+
// Precompile all channel route matchers (treating them as GET routes for WebSocket upgrades)
|
|
78
|
+
const channelRoutesArray = Array.from(channelRoutes.entries()).map(([, channel]) => [channel.route, channel]);
|
|
79
|
+
compileRoutesForMethod('get', channelRoutesArray);
|
|
80
|
+
this.isInitialized = true;
|
|
81
|
+
}
|
|
82
|
+
match(method, path) {
|
|
83
|
+
if (!this.isInitialized) {
|
|
84
|
+
this.initialize();
|
|
85
|
+
}
|
|
86
|
+
// Normalize path - ensure it starts with /
|
|
87
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
88
|
+
// First, try static routes for O(1) lookup
|
|
89
|
+
const methodStaticRoutes = this.staticRoutes.get(method);
|
|
90
|
+
if (methodStaticRoutes) {
|
|
91
|
+
const staticRoute = methodStaticRoutes.get(normalizedPath);
|
|
92
|
+
if (staticRoute) {
|
|
93
|
+
return {
|
|
94
|
+
route: staticRoute.route,
|
|
95
|
+
params: {},
|
|
96
|
+
middleware: staticRoute.middleware,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// If no static route matched, try dynamic routes
|
|
101
|
+
const methodRoutes = this.compiledRoutes.get(method);
|
|
102
|
+
if (!methodRoutes) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
// Try each compiled route for this method
|
|
106
|
+
for (const [, compiledRoute] of methodRoutes.entries()) {
|
|
107
|
+
const result = compiledRoute.matcher(normalizedPath);
|
|
108
|
+
if (result) {
|
|
109
|
+
return {
|
|
110
|
+
route: compiledRoute.route,
|
|
111
|
+
params: result.params,
|
|
112
|
+
middleware: compiledRoute.middleware,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CoreServices, type CoreSingletonServices, type CoreUserSession, type CreateSessionServices } from '../../types/core.types.js';
|
|
2
2
|
import type { CoreMCPResource, CoreMCPTool, CoreMCPPrompt, JsonRpcRequest, JsonRpcResponse, JsonRpcErrorResponse, PikkuMCP } from './mcp.types.js';
|
|
3
3
|
import type { CorePikkuFunctionSessionless } from '../../function/functions.types.js';
|
|
4
4
|
export declare class MCPError extends Error {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PikkuWiringTypes, } from '../../types/core.types.js';
|
|
1
2
|
import { getErrorResponse } from '../../errors/error-handler.js';
|
|
2
3
|
import { closeSessionServices } from '../../utils.js';
|
|
3
4
|
import { pikkuState } from '../../pikku-state.js';
|
|
@@ -132,7 +133,7 @@ async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncName, { sessio
|
|
|
132
133
|
mcp: interaction,
|
|
133
134
|
});
|
|
134
135
|
};
|
|
135
|
-
result = await runPikkuFunc(pikkuFuncName, {
|
|
136
|
+
result = await runPikkuFunc(PikkuWiringTypes.mcp, `${type}:${name}`, pikkuFuncName, {
|
|
136
137
|
getAllServices,
|
|
137
138
|
session,
|
|
138
139
|
data: request.params,
|
|
@@ -140,7 +141,7 @@ async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncName, { sessio
|
|
|
140
141
|
});
|
|
141
142
|
};
|
|
142
143
|
const funcConfig = pikkuState('function', 'functions').get(pikkuFuncName);
|
|
143
|
-
await runMiddleware(singletonServices, { mcp: interaction }, combineMiddleware({
|
|
144
|
+
await runMiddleware(singletonServices, { mcp: interaction }, combineMiddleware(PikkuWiringTypes.mcp, `${type}:${name}`, {
|
|
144
145
|
wiringMiddleware: mcp.middleware,
|
|
145
146
|
wiringTags: mcp.tags,
|
|
146
147
|
funcMiddleware: funcConfig?.middleware,
|
|
@@ -1,6 +1,7 @@
|
|
|
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';
|
|
4
5
|
import { combineMiddleware, runMiddleware } from '../../middleware-runner.js';
|
|
5
6
|
/**
|
|
6
7
|
* Error class for queue processor not found
|
|
@@ -106,7 +107,7 @@ export async function runQueueJob({ singletonServices, createSessionServices, jo
|
|
|
106
107
|
: {}),
|
|
107
108
|
});
|
|
108
109
|
// Execute the pikku function with the job data
|
|
109
|
-
result = await runPikkuFunc(processorMeta.pikkuFuncName, {
|
|
110
|
+
result = await runPikkuFunc(PikkuWiringTypes.queue, job.queueName, processorMeta.pikkuFuncName, {
|
|
110
111
|
getAllServices,
|
|
111
112
|
data: job.data,
|
|
112
113
|
tags: queueWorker.tags,
|
|
@@ -116,7 +117,7 @@ export async function runQueueJob({ singletonServices, createSessionServices, jo
|
|
|
116
117
|
// Get function config for middleware and tags
|
|
117
118
|
const funcConfig = pikkuState('function', 'functions').get(processorMeta.pikkuFuncName);
|
|
118
119
|
// Get middleware for tags and combine with queue-specific middleware
|
|
119
|
-
await runMiddleware(singletonServices, { queue }, combineMiddleware({
|
|
120
|
+
await runMiddleware(singletonServices, { queue }, combineMiddleware(PikkuWiringTypes.queue, `${job.queueName}:${job.id}`, {
|
|
120
121
|
wiringMiddleware: queueWorker.middleware,
|
|
121
122
|
wiringTags: queueWorker.tags,
|
|
122
123
|
funcMiddleware: funcConfig?.middleware,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PikkuWiringTypes } from '../../types/core.types.js';
|
|
1
2
|
import { runPikkuFunc } from '../../function/function-runner.js';
|
|
2
3
|
import { pikkuState } from '../../pikku-state.js';
|
|
3
4
|
import { ForbiddenError } from '../../errors/errors.js';
|
|
@@ -31,7 +32,7 @@ class ContextAwareRPCService {
|
|
|
31
32
|
const session = await this.services.userSession?.get();
|
|
32
33
|
const rpcDepth = this.services.rpc?.depth || 0;
|
|
33
34
|
const pikkuFuncName = getPikkuFunctionName(funcName);
|
|
34
|
-
return runPikkuFunc(pikkuFuncName, {
|
|
35
|
+
return runPikkuFunc(PikkuWiringTypes.rpc, pikkuFuncName, pikkuFuncName, {
|
|
35
36
|
getAllServices: () => {
|
|
36
37
|
this.services.rpc = this.services.rpc
|
|
37
38
|
? {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CoreServices, type CoreSingletonServices, type CoreUserSession, type CreateSessionServices } from '../../types/core.types.js';
|
|
2
2
|
import type { CoreScheduledTask } from './scheduler.types.js';
|
|
3
3
|
import type { CorePikkuFunctionSessionless } from '../../function/functions.types.js';
|
|
4
4
|
export type RunScheduledTasksParams = {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PikkuWiringTypes, } from '../../types/core.types.js';
|
|
1
2
|
import { getErrorResponse, PikkuError } from '../../errors/error-handler.js';
|
|
2
3
|
import { closeSessionServices } from '../../utils.js';
|
|
3
4
|
import { pikkuState } from '../../pikku-state.js';
|
|
@@ -63,7 +64,7 @@ export async function runScheduledTask({ name, session, singletonServices, creat
|
|
|
63
64
|
}
|
|
64
65
|
return singletonServices;
|
|
65
66
|
};
|
|
66
|
-
result = await runPikkuFunc(meta.pikkuFuncName, {
|
|
67
|
+
result = await runPikkuFunc(PikkuWiringTypes.scheduler, meta.name, meta.pikkuFuncName, {
|
|
67
68
|
getAllServices,
|
|
68
69
|
session,
|
|
69
70
|
data: undefined,
|
|
@@ -71,7 +72,7 @@ export async function runScheduledTask({ name, session, singletonServices, creat
|
|
|
71
72
|
});
|
|
72
73
|
};
|
|
73
74
|
const funcConfig = pikkuState('function', 'functions').get(meta.pikkuFuncName);
|
|
74
|
-
await runMiddleware(singletonServices, { scheduledTask }, combineMiddleware({
|
|
75
|
+
await runMiddleware(singletonServices, { scheduledTask }, combineMiddleware(PikkuWiringTypes.scheduler, meta.name, {
|
|
75
76
|
wiringMiddleware: task.middleware,
|
|
76
77
|
wiringTags: task.tags,
|
|
77
78
|
funcMiddleware: funcConfig?.middleware,
|
package/package.json
CHANGED
package/run-tests.sh
CHANGED
|
@@ -46,7 +46,7 @@ if [ "$watch_mode" = true ]; then
|
|
|
46
46
|
fi
|
|
47
47
|
|
|
48
48
|
if [ "$coverage_mode" = true ]; then
|
|
49
|
-
node_cmd="$node_cmd --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info"
|
|
49
|
+
node_cmd="$node_cmd --test-coverage-include=\"src/**/*.{ts,js}\" --test-coverage-exclude=\"**/dist/**\" --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info"
|
|
50
50
|
fi
|
|
51
51
|
|
|
52
52
|
# Execute the node command with the expanded list of files
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { pikkuPermission, pikkuMiddleware } from './index.js'
|
|
4
|
+
|
|
5
|
+
test('pikkuPermission factory function', async () => {
|
|
6
|
+
const permission = pikkuPermission(async ({ logger }, data, session) => {
|
|
7
|
+
return true
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
assert.strictEqual(typeof permission, 'function')
|
|
11
|
+
assert.strictEqual(permission.length, 3) // services, data, session
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
test('pikkuMiddleware factory function', async () => {
|
|
15
|
+
const middleware = pikkuMiddleware(async ({ logger }, interactions, next) => {
|
|
16
|
+
await next()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
assert.strictEqual(typeof middleware, 'function')
|
|
20
|
+
assert.strictEqual(middleware.length, 3) // services, interactions, next
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('pikkuPermission returns the same function', async () => {
|
|
24
|
+
const originalFn = async ({ logger }, data, session) => true
|
|
25
|
+
const wrappedFn = pikkuPermission(originalFn)
|
|
26
|
+
|
|
27
|
+
assert.strictEqual(wrappedFn, originalFn)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('pikkuMiddleware returns the same function', async () => {
|
|
31
|
+
const originalFn = async ({ logger }, interactions, next) => {
|
|
32
|
+
await next()
|
|
33
|
+
}
|
|
34
|
+
const wrappedFn = pikkuMiddleware(originalFn)
|
|
35
|
+
|
|
36
|
+
assert.strictEqual(wrappedFn, originalFn)
|
|
37
|
+
})
|