@pikku/core 0.9.4 → 0.9.5

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 (38) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/function/function-runner.d.ts +1 -1
  3. package/dist/function/function-runner.js +22 -25
  4. package/dist/index.d.ts +2 -2
  5. package/dist/index.js +2 -2
  6. package/dist/middleware-runner.d.ts +19 -11
  7. package/dist/middleware-runner.js +27 -13
  8. package/dist/permissions.d.ts +19 -3
  9. package/dist/permissions.js +61 -1
  10. package/dist/pikku-state.d.ts +2 -2
  11. package/dist/pikku-state.js +3 -3
  12. package/dist/types/core.types.d.ts +3 -4
  13. package/dist/wirings/channel/local/local-channel-runner.js +5 -2
  14. package/dist/wirings/channel/serverless/serverless-channel-runner.js +5 -2
  15. package/dist/wirings/http/http-runner.js +9 -2
  16. package/dist/wirings/http/http.types.d.ts +4 -4
  17. package/dist/wirings/mcp/mcp-runner.js +8 -3
  18. package/dist/wirings/queue/queue-runner.js +9 -2
  19. package/dist/wirings/rpc/rpc-runner.d.ts +1 -2
  20. package/dist/wirings/scheduler/scheduler-runner.js +8 -3
  21. package/package.json +1 -1
  22. package/src/function/function-runner.test.ts +450 -0
  23. package/src/function/function-runner.ts +23 -43
  24. package/src/index.ts +6 -2
  25. package/src/middleware-runner.test.ts +329 -0
  26. package/src/middleware-runner.ts +38 -17
  27. package/src/permissions.test.ts +403 -42
  28. package/src/permissions.ts +115 -5
  29. package/src/pikku-state.ts +9 -5
  30. package/src/types/core.types.ts +3 -4
  31. package/src/wirings/channel/local/local-channel-runner.ts +5 -5
  32. package/src/wirings/channel/serverless/serverless-channel-runner.ts +5 -5
  33. package/src/wirings/http/http-runner.ts +10 -2
  34. package/src/wirings/http/http.types.ts +4 -4
  35. package/src/wirings/mcp/mcp-runner.ts +8 -3
  36. package/src/wirings/queue/queue-runner.ts +12 -2
  37. package/src/wirings/scheduler/scheduler-runner.ts +10 -3
  38. package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  ## 0.9.0
2
2
 
3
+ ## 0.9.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 7e1f5b3: feat: implement ordered middleware and permission execution system
8
+
9
+ ## New Features
10
+
11
+ ### Ordered Execution System
12
+
13
+ Both middleware and permissions now execute in a specific hierarchical order:
14
+
15
+ 1. **Wiring Tags** - Tag-based middleware/permissions from wiring level (e.g., HTTP route tags)
16
+ 2. **Wiring Middleware/Permissions** - Direct wiring-level middleware/permissions
17
+ 3. **Function Middleware** - Function-level middleware
18
+ 4. **Function Tags** - Tag-based middleware/permissions from function level
19
+
20
+ - b443405: feat: adding middleware and functions by tags
21
+
3
22
  ## 0.9.4
4
23
 
5
24
  ### Patch Changes
@@ -2,7 +2,7 @@ import { CoreServices, CoreUserSession, CorePikkuMiddleware } from '../types/cor
2
2
  import { CorePermissionGroup, CorePikkuFunction, CorePikkuFunctionConfig, CorePikkuFunctionSessionless } from './functions.types.js';
3
3
  export declare const addFunction: (funcName: string, funcConfig: CorePikkuFunctionConfig<any, any> | CorePikkuFunctionSessionless<any, any> | CorePikkuFunction<any, any>) => void;
4
4
  export declare const runPikkuFuncDirectly: <In, Out>(funcName: string, allServices: CoreServices, data: In, session?: CoreUserSession) => Promise<Out>;
5
- export declare const runPikkuFunc: <In = any, Out = any>(funcName: string, { getAllServices, data, session, permissions: transportPermissions, middleware: transportMiddleware, coerceDataFromSchema, tags, }: {
5
+ export declare const runPikkuFunc: <In = any, Out = any>(funcName: string, { getAllServices, data, session, permissions: wiringPermissions, middleware: wiringMiddleware, coerceDataFromSchema, tags, }: {
6
6
  getAllServices: () => Promise<CoreServices> | CoreServices;
7
7
  data: In;
8
8
  session?: CoreUserSession;
@@ -1,6 +1,6 @@
1
1
  import { ForbiddenError } from '../errors/errors.js';
2
- import { runMiddleware } from '../middleware-runner.js';
3
- import { verifyPermissions, getPermissionsForTags } from '../permissions.js';
2
+ import { runMiddleware, combineMiddleware } from '../middleware-runner.js';
3
+ import { runPermissions } from '../permissions.js';
4
4
  import { pikkuState } from '../pikku-state.js';
5
5
  import { coerceTopLevelDataFromSchema, validateSchema } from '../schema.js';
6
6
  export const addFunction = (funcName, funcConfig) => {
@@ -16,7 +16,7 @@ export const runPikkuFuncDirectly = async (funcName, allServices, data, session)
16
16
  }
17
17
  return (await funcConfig.func(allServices, data, session));
18
18
  };
19
- export const runPikkuFunc = async (funcName, { getAllServices, data, session, permissions: transportPermissions, middleware: transportMiddleware, coerceDataFromSchema, tags = [], }) => {
19
+ export const runPikkuFunc = async (funcName, { getAllServices, data, session, permissions: wiringPermissions, middleware: wiringMiddleware, coerceDataFromSchema, tags = [], }) => {
20
20
  const funcConfig = pikkuState('function', 'functions').get(funcName);
21
21
  if (!funcConfig) {
22
22
  throw new Error(`Function not found: ${funcName}`);
@@ -38,32 +38,29 @@ export const runPikkuFunc = async (funcName, { getAllServices, data, session, pe
38
38
  coerceTopLevelDataFromSchema(inputSchemaName, data);
39
39
  }
40
40
  }
41
- let permissioned = true;
42
- // Check tagged permissions first - ALL must pass
43
- const taggedPermissions = getPermissionsForTags([
44
- ...tags,
45
- ...(funcConfig.tags || []),
46
- ]);
47
- if (taggedPermissions.length > 0) {
48
- const taggedResults = await Promise.all(taggedPermissions.map((permission) => permission(allServices, data, session)));
49
- permissioned = taggedResults.every((result) => result);
50
- }
51
- // Only check function permissions if tagged permissions passed
52
- if (permissioned && funcConfig.permissions) {
53
- permissioned = await verifyPermissions(funcConfig.permissions, allServices, data, session);
54
- }
55
- if (!permissioned && transportPermissions) {
56
- permissioned = await verifyPermissions(transportPermissions, allServices, data, session);
57
- }
58
- if (permissioned === false) {
59
- throw new ForbiddenError('Permission denied');
60
- }
61
- if (transportMiddleware || funcConfig.middleware) {
41
+ // Run permission checks in the specified order
42
+ await runPermissions({
43
+ wiringTags: tags,
44
+ wiringPermissions,
45
+ funcTags: funcConfig.tags,
46
+ funcPermissions: funcConfig.permissions,
47
+ allServices,
48
+ data,
49
+ session,
50
+ });
51
+ // Combine all middleware: wiring tags wiring middleware → func middleware → func tags
52
+ const allMiddleware = combineMiddleware({
53
+ wiringTags: tags,
54
+ wiringMiddleware,
55
+ funcMiddleware: funcConfig.middleware,
56
+ funcTags: funcConfig.tags,
57
+ });
58
+ if (allMiddleware.length > 0) {
62
59
  return (await runMiddleware(allServices, {
63
60
  http: allServices.http,
64
61
  mcp: allServices.mcp,
65
62
  rpc: allServices.rpc,
66
- }, [...(transportMiddleware || []), ...(funcConfig.middleware || [])], async () => await funcConfig.func(allServices, data, session)));
63
+ }, allMiddleware, async () => await funcConfig.func(allServices, data, session)));
67
64
  }
68
65
  return (await funcConfig.func(allServices, data, session));
69
66
  };
package/dist/index.d.ts CHANGED
@@ -21,8 +21,8 @@ export * from './middleware/index.js';
21
21
  export * from './time-utils.js';
22
22
  export * from './utils.js';
23
23
  export { pikkuState } from './pikku-state.js';
24
- export { runMiddleware, addMiddleware, addMiddlewareForTags, } from './middleware-runner.js';
25
- export { addPermission, getPermissionsForTags } from './permissions.js';
24
+ export { runMiddleware, addMiddleware, combineMiddleware, } from './middleware-runner.js';
25
+ export { addPermission, getPermissionsForTags, runPermissions, } from './permissions.js';
26
26
  export { wireHTTP, addHTTPMiddleware } from './wirings/http/http-runner.js';
27
27
  export { wireChannel } from './wirings/channel/channel-runner.js';
28
28
  export { wireScheduler } from './wirings/scheduler/scheduler-runner.js';
package/dist/index.js CHANGED
@@ -21,8 +21,8 @@ export * from './middleware/index.js';
21
21
  export * from './time-utils.js';
22
22
  export * from './utils.js';
23
23
  export { pikkuState } from './pikku-state.js';
24
- export { runMiddleware, addMiddleware, addMiddlewareForTags, } from './middleware-runner.js';
25
- export { addPermission, getPermissionsForTags } from './permissions.js';
24
+ export { runMiddleware, addMiddleware, combineMiddleware, } from './middleware-runner.js';
25
+ export { addPermission, getPermissionsForTags, runPermissions, } from './permissions.js';
26
26
  export { wireHTTP, addHTTPMiddleware } from './wirings/http/http-runner.js';
27
27
  export { wireChannel } from './wirings/channel/channel-runner.js';
28
28
  export { wireScheduler } from './wirings/scheduler/scheduler-runner.js';
@@ -62,23 +62,31 @@ export declare const addMiddleware: <PikkuMiddleware extends CorePikkuMiddleware
62
62
  */
63
63
  export declare const getMiddlewareForTags: (tags?: string[]) => CorePikkuMiddleware[];
64
64
  /**
65
- * Combines tag-based middleware with wiring-specific middleware.
65
+ * Combines tag-based middleware with wiring-specific middleware and function-level middleware.
66
66
  *
67
67
  * This helper function gets middleware for tags and combines it with any
68
- * wiring-specific middleware, avoiding the need for manual spreading.
68
+ * wiring-specific middleware and function-level middleware, avoiding the need for manual spreading.
69
69
  *
70
- * @param {CorePikkuMiddleware[] | undefined} wiringMiddleware - Wiring-specific middleware.
71
- * @param {string[] | undefined} tags - Array of tags to look up middleware for.
70
+ * @param {object} options - Configuration object for combining middleware.
71
+ * @param {CorePikkuMiddleware[] | undefined} options.wiringMiddleware - Wiring-specific middleware.
72
+ * @param {string[] | undefined} options.wiringTags - Array of wiring-level tags to look up middleware for.
73
+ * @param {CorePikkuMiddleware[] | undefined} options.funcMiddleware - Function-level middleware.
74
+ * @param {string[] | undefined} options.funcTags - Array of function-level tags to look up middleware for.
72
75
  * @returns {CorePikkuMiddleware[]} Combined array of tag-based and wiring-specific middleware.
73
76
  *
74
77
  * @example
75
78
  * ```typescript
76
- * // Instead of:
77
- * const taggedMiddleware = getMiddlewareForTags(tags)
78
- * const combined = [...taggedMiddleware, ...(middleware || [])]
79
- *
80
- * // Use:
81
- * const combined = addMiddlewareForTags(middleware, tags)
79
+ * const combined = combineMiddleware({
80
+ * wiringMiddleware: httpRoute.middleware,
81
+ * wiringTags: httpRoute.tags,
82
+ * funcMiddleware: funcConfig.middleware,
83
+ * funcTags: funcConfig.tags
84
+ * })
82
85
  * ```
83
86
  */
84
- export declare const addMiddlewareForTags: (wiringMiddleware?: CorePikkuMiddleware[], tags?: string[]) => CorePikkuMiddleware[];
87
+ export declare const combineMiddleware: ({ wiringMiddleware, wiringTags, funcMiddleware, funcTags, }?: {
88
+ wiringMiddleware?: CorePikkuMiddleware[];
89
+ wiringTags?: string[];
90
+ funcMiddleware?: CorePikkuMiddleware[];
91
+ funcTags?: string[];
92
+ }) => CorePikkuMiddleware[];
@@ -94,26 +94,40 @@ export const getMiddlewareForTags = (tags) => {
94
94
  return applicableMiddleware;
95
95
  };
96
96
  /**
97
- * Combines tag-based middleware with wiring-specific middleware.
97
+ * Combines tag-based middleware with wiring-specific middleware and function-level middleware.
98
98
  *
99
99
  * This helper function gets middleware for tags and combines it with any
100
- * wiring-specific middleware, avoiding the need for manual spreading.
100
+ * wiring-specific middleware and function-level middleware, avoiding the need for manual spreading.
101
101
  *
102
- * @param {CorePikkuMiddleware[] | undefined} wiringMiddleware - Wiring-specific middleware.
103
- * @param {string[] | undefined} tags - Array of tags to look up middleware for.
102
+ * @param {object} options - Configuration object for combining middleware.
103
+ * @param {CorePikkuMiddleware[] | undefined} options.wiringMiddleware - Wiring-specific middleware.
104
+ * @param {string[] | undefined} options.wiringTags - Array of wiring-level tags to look up middleware for.
105
+ * @param {CorePikkuMiddleware[] | undefined} options.funcMiddleware - Function-level middleware.
106
+ * @param {string[] | undefined} options.funcTags - Array of function-level tags to look up middleware for.
104
107
  * @returns {CorePikkuMiddleware[]} Combined array of tag-based and wiring-specific middleware.
105
108
  *
106
109
  * @example
107
110
  * ```typescript
108
- * // Instead of:
109
- * const taggedMiddleware = getMiddlewareForTags(tags)
110
- * const combined = [...taggedMiddleware, ...(middleware || [])]
111
- *
112
- * // Use:
113
- * const combined = addMiddlewareForTags(middleware, tags)
111
+ * const combined = combineMiddleware({
112
+ * wiringMiddleware: httpRoute.middleware,
113
+ * wiringTags: httpRoute.tags,
114
+ * funcMiddleware: funcConfig.middleware,
115
+ * funcTags: funcConfig.tags
116
+ * })
114
117
  * ```
115
118
  */
116
- export const addMiddlewareForTags = (wiringMiddleware, tags) => {
117
- const taggedMiddleware = getMiddlewareForTags(tags);
118
- return [...taggedMiddleware, ...(wiringMiddleware || [])];
119
+ export const combineMiddleware = ({ wiringMiddleware, wiringTags, funcMiddleware, funcTags, } = {}) => {
120
+ // Run middleware in specific order:
121
+ // 1) wiringTags middleware
122
+ // 2) wiringMiddleware
123
+ // 3) funcMiddleware
124
+ // 4) funcTags middleware
125
+ const wiringTaggedMiddleware = getMiddlewareForTags(wiringTags);
126
+ const funcTaggedMiddleware = getMiddlewareForTags(funcTags);
127
+ return [
128
+ ...wiringTaggedMiddleware,
129
+ ...(wiringMiddleware || []),
130
+ ...(funcMiddleware || []),
131
+ ...funcTaggedMiddleware,
132
+ ];
119
133
  };
@@ -1,5 +1,5 @@
1
1
  import { CoreServices, CoreUserSession } from './types/core.types.js';
2
- import { CorePermissionGroup } from './function/functions.types.js';
2
+ import { CorePermissionGroup, CorePikkuPermission } from './function/functions.types.js';
3
3
  /**
4
4
  * This function validates permissions by iterating over permission groups and executing the corresponding permission functions. If all functions in at least one group return true, the permission is considered valid.
5
5
  * @param services - The core services required for permission validation.
@@ -31,7 +31,7 @@ export declare const verifyPermissions: (permissions: CorePermissionGroup, servi
31
31
  * addPermission('api', [readPermission])
32
32
  * ```
33
33
  */
34
- export declare const addPermission: (tag: string, permissions: any[]) => void;
34
+ export declare const addPermission: (tag: string, permissions: CorePermissionGroup | CorePikkuPermission[]) => void;
35
35
  /**
36
36
  * Retrieves permissions for a given set of tags.
37
37
  *
@@ -47,4 +47,20 @@ export declare const addPermission: (tag: string, permissions: any[]) => void;
47
47
  * const permissions = getPermissionsForTags(['api', 'auth'])
48
48
  * ```
49
49
  */
50
- export declare const getPermissionsForTags: (tags?: string[]) => any[];
50
+ export declare const getPermissionsForTags: (tags?: string[]) => Array<CorePermissionGroup | CorePikkuPermission>;
51
+ /**
52
+ * Runs permission checks in the specified order:
53
+ * 1) wiring tag permissions - at least one must pass if any exist
54
+ * 2) wiring permissions - must pass if defined
55
+ * 3) function tag permissions - at least one must pass if any exist
56
+ * 4) function permissions - must pass if defined
57
+ */
58
+ export declare const runPermissions: ({ wiringTags, wiringPermissions, funcTags, funcPermissions, allServices, data, session, }: {
59
+ wiringTags?: string[];
60
+ wiringPermissions?: CorePermissionGroup;
61
+ funcTags?: string[];
62
+ funcPermissions?: CorePermissionGroup;
63
+ allServices: CoreServices;
64
+ data: any;
65
+ session?: CoreUserSession;
66
+ }) => Promise<void>;
@@ -1,4 +1,5 @@
1
1
  import { pikkuState } from './pikku-state.js';
2
+ import { ForbiddenError } from './errors/errors.js';
2
3
  /**
3
4
  * This function validates permissions by iterating over permission groups and executing the corresponding permission functions. If all functions in at least one group return true, the permission is considered valid.
4
5
  * @param services - The core services required for permission validation.
@@ -87,8 +88,67 @@ export const getPermissionsForTags = (tags) => {
87
88
  for (const tag of new Set(tags)) {
88
89
  const tagPermissions = permissionsStore[tag];
89
90
  if (tagPermissions) {
90
- applicablePermissions.push(...tagPermissions);
91
+ if (Array.isArray(tagPermissions)) {
92
+ applicablePermissions.push(...tagPermissions);
93
+ }
94
+ else {
95
+ applicablePermissions.push(tagPermissions);
96
+ }
91
97
  }
92
98
  }
93
99
  return applicablePermissions;
94
100
  };
101
+ /**
102
+ * Runs permission checks in the specified order:
103
+ * 1) wiring tag permissions - at least one must pass if any exist
104
+ * 2) wiring permissions - must pass if defined
105
+ * 3) function tag permissions - at least one must pass if any exist
106
+ * 4) function permissions - must pass if defined
107
+ */
108
+ export const runPermissions = async ({ wiringTags, wiringPermissions, funcTags, funcPermissions, allServices, data, session, }) => {
109
+ let permissioned = true;
110
+ // 1. Wiring tag permissions - at least one must pass if any exist
111
+ const wiringTaggedPermissions = getPermissionsForTags(wiringTags || []);
112
+ if (wiringTaggedPermissions.length > 0) {
113
+ permissioned = false; // Start false, need at least one to pass
114
+ for (const permissions of wiringTaggedPermissions) {
115
+ const result = await verifyPermissions(typeof permissions === 'function' ? { permissions } : permissions, allServices, data, session);
116
+ if (result) {
117
+ permissioned = true;
118
+ break; // At least one passed, we're good at this level
119
+ }
120
+ }
121
+ if (!permissioned) {
122
+ throw new ForbiddenError('Permission denied - wiring tag permissions');
123
+ }
124
+ }
125
+ // 2. Wiring permissions - must pass if defined
126
+ if (wiringPermissions) {
127
+ permissioned = await verifyPermissions(wiringPermissions, allServices, data, session);
128
+ if (!permissioned) {
129
+ throw new ForbiddenError('Permission denied - wiring permissions');
130
+ }
131
+ }
132
+ // 3. Function tag permissions - at least one must pass if any exist
133
+ const funcTaggedPermissions = getPermissionsForTags(funcTags || []);
134
+ if (funcTaggedPermissions.length > 0) {
135
+ permissioned = false; // Start false, need at least one to pass
136
+ for (const permissions of funcTaggedPermissions) {
137
+ const result = await verifyPermissions(typeof permissions === 'function' ? { permissions } : permissions, allServices, data, session);
138
+ if (result) {
139
+ permissioned = true;
140
+ break; // At least one passed, we're good at this level
141
+ }
142
+ }
143
+ if (!permissioned) {
144
+ throw new ForbiddenError('Permission denied - function tag permissions');
145
+ }
146
+ }
147
+ // 4. Function permissions - must pass if defined
148
+ if (funcPermissions) {
149
+ permissioned = await verifyPermissions(funcPermissions, allServices, data, session);
150
+ if (!permissioned) {
151
+ throw new ForbiddenError('Permission denied - function permissions');
152
+ }
153
+ }
154
+ };
@@ -3,7 +3,7 @@ import { CoreHTTPFunctionWiring, HTTPMethod, HTTPWiringsMeta } from './wirings/h
3
3
  import { FunctionsMeta, CorePikkuMiddleware } from './types/core.types.js';
4
4
  import { CoreScheduledTask, ScheduledTasksMeta } from './wirings/scheduler/scheduler.types.js';
5
5
  import { ErrorDetails, PikkuError } from './errors/error-handler.js';
6
- import { CorePikkuFunctionConfig } from './function/functions.types.js';
6
+ import { CorePermissionGroup, CorePikkuFunctionConfig, CorePikkuPermission } from './function/functions.types.js';
7
7
  import { queueWorkersMeta, CoreQueueWorker } from './wirings/queue/queue.types.js';
8
8
  import { CoreMCPResource, CoreMCPTool, CoreMCPPrompt, MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from './wirings/mcp/mcp.types.js';
9
9
  interface PikkuState {
@@ -50,7 +50,7 @@ interface PikkuState {
50
50
  errors: Map<PikkuError, ErrorDetails>;
51
51
  schemas: Map<string, any>;
52
52
  middleware: Record<string, CorePikkuMiddleware[]>;
53
- permissions: Record<string, any[]>;
53
+ permissions: Record<string, CorePermissionGroup | CorePikkuPermission[]>;
54
54
  };
55
55
  }
56
56
  export declare const resetPikkuState: () => void;
@@ -35,9 +35,9 @@ export const resetPikkuState = () => {
35
35
  },
36
36
  misc: {
37
37
  errors: globalThis.pikkuState?.misc?.errors || new Map(),
38
- schemas: globalThis.pikkuState?.misc?.schema || new Map(),
39
- middleware: globalThis.pikkuState?.misc?.middleware || {},
40
- permissions: globalThis.pikkuState?.misc?.permissions || {},
38
+ schemas: new Map(),
39
+ middleware: {},
40
+ permissions: {},
41
41
  },
42
42
  };
43
43
  };
@@ -92,14 +92,13 @@ export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
92
92
  /**
93
93
  * Represents different forms of interaction within Pikku and the outside world.
94
94
  */
95
- export type PikkuInteraction = Partial<{
96
- http: PikkuHTTP;
95
+ export type PikkuInteraction<In = unknown, Out = unknown> = Partial<{
96
+ http: PikkuHTTP<In>;
97
97
  mcp: PikkuMCP;
98
98
  rpc: PikkuRPC;
99
- channel: PikkuChannel<unknown, unknown>;
99
+ channel: PikkuChannel<unknown, Out>;
100
100
  scheduledTask: PikkuScheduledTask;
101
101
  queue: PikkuQueue;
102
- s: any;
103
102
  }>;
104
103
  /**
105
104
  * A function that can wrap an interaction and be called before or after
@@ -4,7 +4,7 @@ import { closeSessionServices } from '../../../utils.js';
4
4
  import { processMessageHandlers } from '../channel-handler.js';
5
5
  import { PikkuLocalChannelHandler } from './local-channel-handler.js';
6
6
  import { handleHTTPError } from '../../../handle-error.js';
7
- import { addMiddlewareForTags, runMiddleware, } from '../../../middleware-runner.js';
7
+ import { combineMiddleware, runMiddleware } from '../../../middleware-runner.js';
8
8
  import { PikkuUserSessionService } from '../../../services/user-session-service.js';
9
9
  import { runPikkuFuncDirectly } from '../../../function/function-runner.js';
10
10
  import { rpcService } from '../../rpc/rpc-runner.js';
@@ -77,6 +77,9 @@ export const runLocalChannel = async ({ singletonServices, channelId, request, r
77
77
  await runMiddleware({
78
78
  ...singletonServices,
79
79
  userSession,
80
- }, { http }, addMiddlewareForTags(channelConfig.middleware, channelConfig.tags), main);
80
+ }, { http }, combineMiddleware({
81
+ wiringMiddleware: channelConfig.middleware,
82
+ wiringTags: channelConfig.tags,
83
+ }), main);
81
84
  return channelHandler;
82
85
  };
@@ -4,7 +4,7 @@ import { openChannel } from '../channel-runner.js';
4
4
  import { createHTTPInteraction } from '../../http/http-runner.js';
5
5
  import { handleHTTPError } from '../../../handle-error.js';
6
6
  import { PikkuUserSessionService } from '../../../services/user-session-service.js';
7
- import { addMiddlewareForTags, runMiddleware, } from '../../../middleware-runner.js';
7
+ import { combineMiddleware, runMiddleware } from '../../../middleware-runner.js';
8
8
  import { pikkuState } from '../../../pikku-state.js';
9
9
  import { PikkuFetchHTTPRequest } from '../../http/pikku-fetch-http-request.js';
10
10
  import { runPikkuFuncDirectly } from '../../../function/function-runner.js';
@@ -76,7 +76,10 @@ export const runChannelConnect = async ({ singletonServices, channelId, channelO
76
76
  await runMiddleware({
77
77
  ...singletonServices,
78
78
  userSession,
79
- }, { http }, addMiddlewareForTags(channelConfig.middleware, channelConfig.tags), main);
79
+ }, { http }, combineMiddleware({
80
+ wiringMiddleware: channelConfig.middleware,
81
+ wiringTags: channelConfig.tags,
82
+ }), main);
80
83
  };
81
84
  export const runChannelDisconnect = async ({ singletonServices, ...params }) => {
82
85
  let sessionServices;
@@ -2,7 +2,7 @@ import { match } from 'path-to-regexp';
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';
5
- import { addMiddlewareForTags, runMiddleware } from '../../middleware-runner.js';
5
+ import { combineMiddleware, runMiddleware } from '../../middleware-runner.js';
6
6
  import { handleHTTPError } from '../../handle-error.js';
7
7
  import { pikkuState } from '../../pikku-state.js';
8
8
  import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js';
@@ -250,8 +250,15 @@ const executeRouteWithMiddleware = async (services, matchedRoute, http, options)
250
250
  // TODO: Evaluate if the response stream should be explicitly ended.
251
251
  // http?.response?.end()
252
252
  };
253
+ // Get function config for middleware and tags
254
+ const funcConfig = pikkuState('function', 'functions').get(meta.pikkuFuncName);
253
255
  // Execute middleware, then run the main logic
254
- await runMiddleware({ ...singletonServices, userSession }, { http }, addMiddlewareForTags(middleware, route.tags), runMain);
256
+ await runMiddleware({ ...singletonServices, userSession }, { http }, combineMiddleware({
257
+ wiringMiddleware: middleware,
258
+ wiringTags: route.tags,
259
+ funcMiddleware: funcConfig?.middleware,
260
+ funcTags: funcConfig?.tags,
261
+ }), runMain);
255
262
  return sessionServices ? { result, sessionServices } : { result };
256
263
  };
257
264
  /**
@@ -46,8 +46,8 @@ export type CoreHTTPFunction = {
46
46
  /**
47
47
  * Represents a http interaction within Pikku, including a request and response.
48
48
  */
49
- export interface PikkuHTTP {
50
- request?: PikkuHTTPRequest;
49
+ export interface PikkuHTTP<In = unknown> {
50
+ request?: PikkuHTTPRequest<In>;
51
51
  response?: PikkuHTTPResponse;
52
52
  }
53
53
  /**
@@ -169,12 +169,12 @@ export interface PikkuHTTPRequest<In = unknown> {
169
169
  setParams(params: Record<string, string | string[] | undefined>): void;
170
170
  query(): PikkuQuery;
171
171
  }
172
- export interface PikkuHTTPResponse {
172
+ export interface PikkuHTTPResponse<Out = unknown> {
173
173
  status(code: number): this;
174
174
  cookie(name: string, value: string | null, options: SerializeOptions): this;
175
175
  header(name: string, value: string | string[]): this;
176
176
  arrayBuffer(data: ArrayBuffer | ArrayBufferView | Blob | string | FormData | URLSearchParams | ReadableStream): this;
177
- json(data: unknown): this;
177
+ json(data: Out): this;
178
178
  redirect(location: string, status?: number): this;
179
179
  close?: () => void;
180
180
  setMode?: (mode: 'stream') => void;
@@ -4,7 +4,7 @@ import { pikkuState } from '../../pikku-state.js';
4
4
  import { addFunction, runPikkuFunc } from '../../function/function-runner.js';
5
5
  import { rpcService } from '../rpc/rpc-runner.js';
6
6
  import { BadRequestError, NotFoundError } from '../../errors/errors.js';
7
- import { addMiddlewareForTags, runMiddleware } from '../../middleware-runner.js';
7
+ import { combineMiddleware, runMiddleware } from '../../middleware-runner.js';
8
8
  export class MCPError extends Error {
9
9
  error;
10
10
  constructor(error) {
@@ -139,8 +139,13 @@ async function runMCPPikkuFunc(request, type, name, mcp, pikkuFuncName, { sessio
139
139
  tags: mcp.tags,
140
140
  });
141
141
  };
142
- // Get middleware for tags and run middleware
143
- await runMiddleware(singletonServices, { mcp: interaction }, addMiddlewareForTags(mcp.middleware, mcp.tags), runMain);
142
+ const funcConfig = pikkuState('function', 'functions').get(pikkuFuncName);
143
+ await runMiddleware(singletonServices, { mcp: interaction }, combineMiddleware({
144
+ wiringMiddleware: mcp.middleware,
145
+ wiringTags: mcp.tags,
146
+ funcMiddleware: funcConfig?.middleware,
147
+ funcTags: funcConfig?.tags,
148
+ }), runMain);
144
149
  return {
145
150
  id: request.id,
146
151
  result,
@@ -1,7 +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 { addMiddlewareForTags, runMiddleware } from '../../middleware-runner.js';
4
+ import { combineMiddleware, runMiddleware } from '../../middleware-runner.js';
5
5
  /**
6
6
  * Error class for queue processor not found
7
7
  */
@@ -113,8 +113,15 @@ export async function runQueueJob({ singletonServices, createSessionServices, jo
113
113
  });
114
114
  logger.debug(`Successfully processed job ${job.id} in queue ${job.queueName}`);
115
115
  };
116
+ // Get function config for middleware and tags
117
+ const funcConfig = pikkuState('function', 'functions').get(processorMeta.pikkuFuncName);
116
118
  // Get middleware for tags and combine with queue-specific middleware
117
- await runMiddleware(singletonServices, { queue }, addMiddlewareForTags(queueWorker.middleware, queueWorker.tags), runMain);
119
+ await runMiddleware(singletonServices, { queue }, combineMiddleware({
120
+ wiringMiddleware: queueWorker.middleware,
121
+ wiringTags: queueWorker.tags,
122
+ funcMiddleware: funcConfig?.middleware,
123
+ funcTags: funcConfig?.tags,
124
+ }), runMain);
118
125
  return result;
119
126
  }
120
127
  catch (error) {
@@ -13,13 +13,12 @@ export declare class PikkuRPCService {
13
13
  };
14
14
  logger: import("../../index.js").Logger;
15
15
  variables: import("../../services/variables-service.js").VariablesService;
16
- http?: import("../http/http.types.js").PikkuHTTP | undefined;
16
+ http?: import("../http/http.types.js").PikkuHTTP<unknown> | undefined;
17
17
  mcp?: import("../mcp/mcp.types.js").PikkuMCP;
18
18
  rpc?: import("./rpc-types.js").PikkuRPC;
19
19
  channel?: import("../channel/channel.types.js").PikkuChannel<unknown, unknown>;
20
20
  scheduledTask?: import("../scheduler/scheduler.types.js").PikkuScheduledTask | undefined;
21
21
  queue?: import("../queue/queue.types.js").PikkuQueue | undefined;
22
- s?: any;
23
22
  userSession?: import("../../index.js").UserSessionService<import("../../types/core.types.js").CoreUserSession> | undefined;
24
23
  };
25
24
  }
@@ -3,7 +3,7 @@ import { closeSessionServices } from '../../utils.js';
3
3
  import { pikkuState } from '../../pikku-state.js';
4
4
  import { addFunction, runPikkuFunc } from '../../function/function-runner.js';
5
5
  import { rpcService } from '../rpc/rpc-runner.js';
6
- import { addMiddlewareForTags, runMiddleware } from '../../middleware-runner.js';
6
+ import { combineMiddleware, runMiddleware } from '../../middleware-runner.js';
7
7
  export const wireScheduler = (scheduledTask) => {
8
8
  const meta = pikkuState('scheduler', 'meta');
9
9
  const taskMeta = meta[scheduledTask.name];
@@ -70,8 +70,13 @@ export async function runScheduledTask({ name, session, singletonServices, creat
70
70
  tags: task.tags,
71
71
  });
72
72
  };
73
- // Get middleware for tags and run middleware
74
- await runMiddleware(singletonServices, { scheduledTask }, addMiddlewareForTags(task.middleware, task.tags), runMain);
73
+ const funcConfig = pikkuState('function', 'functions').get(meta.pikkuFuncName);
74
+ await runMiddleware(singletonServices, { scheduledTask }, combineMiddleware({
75
+ wiringMiddleware: task.middleware,
76
+ wiringTags: task.tags,
77
+ funcMiddleware: funcConfig?.middleware,
78
+ funcTags: funcConfig?.tags,
79
+ }), runMain);
75
80
  return result;
76
81
  }
77
82
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/core",
3
- "version": "0.9.4",
3
+ "version": "0.9.5",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "module": "dist/index.js",