@pikku/core 0.9.5 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/function/function-runner.d.ts +2 -2
  3. package/dist/function/function-runner.js +3 -3
  4. package/dist/function/functions.types.d.ts +4 -0
  5. package/dist/function/functions.types.js +6 -1
  6. package/dist/index.d.ts +3 -3
  7. package/dist/index.js +3 -3
  8. package/dist/middleware-runner.d.ts +5 -4
  9. package/dist/middleware-runner.js +20 -6
  10. package/dist/permissions.d.ts +3 -3
  11. package/dist/permissions.js +30 -8
  12. package/dist/pikku-state.d.ts +2 -4
  13. package/dist/pikku-state.js +3 -2
  14. package/dist/schema.js +8 -6
  15. package/dist/types/core.types.d.ts +4 -0
  16. package/dist/types/core.types.js +6 -0
  17. package/dist/utils.d.ts +1 -0
  18. package/dist/utils.js +17 -0
  19. package/dist/wirings/channel/channel-handler.js +2 -1
  20. package/dist/wirings/channel/channel-runner.d.ts +2 -0
  21. package/dist/wirings/channel/channel-runner.js +23 -25
  22. package/dist/wirings/channel/local/local-channel-runner.js +5 -3
  23. package/dist/wirings/channel/serverless/serverless-channel-runner.js +4 -2
  24. package/dist/wirings/http/http-runner.js +36 -53
  25. package/dist/wirings/http/http.types.d.ts +1 -1
  26. package/dist/wirings/http/pikku-fetch-http-request.js +3 -0
  27. package/dist/wirings/http/routers/http-router.d.ts +12 -0
  28. package/dist/wirings/http/routers/http-router.js +2 -0
  29. package/dist/wirings/http/routers/path-to-regex.d.ts +10 -0
  30. package/dist/wirings/http/routers/path-to-regex.js +118 -0
  31. package/dist/wirings/mcp/mcp-runner.d.ts +1 -1
  32. package/dist/wirings/mcp/mcp-runner.js +3 -2
  33. package/dist/wirings/queue/queue-runner.js +3 -2
  34. package/dist/wirings/rpc/rpc-runner.js +2 -1
  35. package/dist/wirings/scheduler/scheduler-runner.d.ts +1 -1
  36. package/dist/wirings/scheduler/scheduler-runner.js +3 -2
  37. package/package.json +1 -1
  38. package/src/factory-functions.test.ts +37 -0
  39. package/src/function/function-runner.test.ts +101 -52
  40. package/src/function/function-runner.ts +5 -2
  41. package/src/function/functions.types.ts +13 -0
  42. package/src/index.ts +3 -11
  43. package/src/middleware-runner.test.ts +71 -43
  44. package/src/middleware-runner.ts +43 -17
  45. package/src/permissions.test.ts +21 -17
  46. package/src/permissions.ts +68 -26
  47. package/src/pikku-state.ts +5 -3
  48. package/src/schema.ts +8 -6
  49. package/src/types/core.types.ts +12 -0
  50. package/src/utils.ts +19 -0
  51. package/src/wirings/channel/channel-handler.ts +17 -11
  52. package/src/wirings/channel/channel-runner.ts +31 -25
  53. package/src/wirings/channel/local/local-channel-runner.test.ts +4 -0
  54. package/src/wirings/channel/local/local-channel-runner.ts +5 -4
  55. package/src/wirings/channel/serverless/serverless-channel-runner.ts +13 -11
  56. package/src/wirings/http/http-runner.test.ts +18 -6
  57. package/src/wirings/http/http-runner.ts +55 -74
  58. package/src/wirings/http/http.types.ts +1 -1
  59. package/src/wirings/http/pikku-fetch-http-request.ts +3 -0
  60. package/src/wirings/http/routers/http-router.ts +15 -0
  61. package/src/wirings/http/routers/path-to-regex.test.ts +309 -0
  62. package/src/wirings/http/routers/path-to-regex.ts +162 -0
  63. package/src/wirings/mcp/mcp-runner.ts +18 -12
  64. package/src/wirings/queue/queue-runner.ts +15 -7
  65. package/src/wirings/rpc/rpc-runner.ts +21 -16
  66. package/src/wirings/scheduler/scheduler-runner.ts +18 -12
  67. package/tsconfig.tsbuildinfo +1 -1
  68. package/dist/pikku-function.d.ts +0 -1
  69. package/dist/pikku-function.js +0 -1
  70. package/src/pikku-function.ts +0 -1
@@ -1,4 +1,4 @@
1
- import { match } from 'path-to-regexp';
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
- if (typeof routeOrMiddleware === 'string' && middleware) {
26
- const route = routeOrMiddleware;
27
- // Remove existing entry for this route if it exists
28
- const existingIndex = middlewareStore.findIndex((item) => item.route === route);
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
- // Handle global middleware
36
- const existingIndex = middlewareStore.findIndex((item) => item.route === '*');
37
- if (existingIndex !== -1) {
38
- middlewareStore.splice(existingIndex, 1);
39
- }
40
- middlewareStore.push({
41
- route: '*',
42
- middleware: routeOrMiddleware,
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.find((meta) => meta.route === httpWiring.route && meta.method === httpWiring.method);
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 allRoutes = pikkuState('http', 'routes');
89
- const middleware = pikkuState('http', 'middleware');
90
- const routes = allRoutes.get(requestType.toLowerCase());
91
- if (!routes) {
92
- return undefined;
93
- }
94
- for (const route of routes.values()) {
95
- // Generate a matching function from the route pattern
96
- const matchFunc = match(`/${route.route}`.replace(/^\/\//, '/'), {
97
- decode: decodeURIComponent,
98
- });
99
- // Attempt to match the request path
100
- const matchedPath = matchFunc(requestPath.replace(/^\/\//, '/'));
101
- if (matchedPath) {
102
- // Aggregate global and route-specific middleware
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 = Array<HTTPWiringMeta>;
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;
@@ -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,2 @@
1
+ import { PathToRegexRouter } from './path-to-regex.js';
2
+ export const httpRouter = new 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 { CoreServices, CoreSingletonServices, CoreUserSession, CreateSessionServices } from '../../types/core.types.js';
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 { CoreServices, CoreSingletonServices, CoreUserSession, CreateSessionServices } from '../../types/core.types.js';
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/core",
3
- "version": "0.9.5",
3
+ "version": "0.9.6",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "module": "dist/index.js",
@@ -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
+ })