@pikku/core 0.9.3 → 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.
- package/CHANGELOG.md +25 -0
- package/dist/function/function-runner.d.ts +2 -1
- package/dist/function/function-runner.js +22 -15
- package/dist/function/functions.types.d.ts +3 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/middleware-runner.d.ts +70 -0
- package/dist/middleware-runner.js +105 -2
- package/dist/permissions.d.ts +57 -1
- package/dist/permissions.js +122 -0
- package/dist/pikku-state.d.ts +3 -1
- package/dist/pikku-state.js +3 -1
- package/dist/types/core.types.d.ts +10 -5
- package/dist/wirings/channel/channel-handler.js +1 -0
- package/dist/wirings/channel/local/local-channel-runner.js +26 -15
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +5 -2
- package/dist/wirings/http/http-runner.js +20 -3
- package/dist/wirings/http/http.types.d.ts +5 -4
- package/dist/wirings/mcp/mcp-runner.js +27 -14
- package/dist/wirings/mcp/mcp.types.d.ts +7 -3
- package/dist/wirings/queue/index.d.ts +1 -1
- package/dist/wirings/queue/index.js +1 -1
- package/dist/wirings/queue/queue-runner.d.ts +15 -1
- package/dist/wirings/queue/queue-runner.js +71 -16
- package/dist/wirings/queue/queue.types.d.ts +19 -2
- package/dist/wirings/rpc/rpc-runner.d.ts +4 -2
- package/dist/wirings/scheduler/scheduler-runner.js +54 -24
- package/dist/wirings/scheduler/scheduler.types.d.ts +17 -2
- package/package.json +1 -1
- package/src/function/function-runner.test.ts +450 -0
- package/src/function/function-runner.ts +25 -26
- package/src/function/functions.types.ts +3 -1
- package/src/index.ts +10 -1
- package/src/middleware-runner.test.ts +329 -0
- package/src/middleware-runner.ts +131 -2
- package/src/permissions.test.ts +403 -42
- package/src/permissions.ts +182 -1
- package/src/pikku-state.ts +10 -2
- package/src/types/core.types.ts +10 -5
- package/src/wirings/channel/channel-handler.ts +1 -0
- package/src/wirings/channel/local/local-channel-runner.ts +33 -16
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +5 -2
- package/src/wirings/http/http-runner.ts +21 -3
- package/src/wirings/http/http.types.ts +5 -4
- package/src/wirings/mcp/mcp-runner.ts +37 -17
- package/src/wirings/mcp/mcp.types.ts +7 -0
- package/src/wirings/queue/index.ts +2 -0
- package/src/wirings/queue/queue-runner.ts +92 -19
- package/src/wirings/queue/queue.types.ts +20 -1
- package/src/wirings/scheduler/scheduler-runner.ts +80 -32
- package/src/wirings/scheduler/scheduler.types.ts +22 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
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
|
+
|
|
22
|
+
## 0.9.4
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- c18800d: feat: adding queue and scheduledTask to interactions
|
|
27
|
+
|
|
3
28
|
## 0.9.3
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
|
@@ -2,11 +2,12 @@ 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:
|
|
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;
|
|
9
9
|
permissions?: CorePermissionGroup;
|
|
10
10
|
middleware?: CorePikkuMiddleware[];
|
|
11
11
|
coerceDataFromSchema?: boolean;
|
|
12
|
+
tags?: string[];
|
|
12
13
|
}) => Promise<Out>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ForbiddenError } from '../errors/errors.js';
|
|
2
|
-
import { runMiddleware } from '../middleware-runner.js';
|
|
3
|
-
import {
|
|
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:
|
|
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,22 +38,29 @@ export const runPikkuFunc = async (funcName, { getAllServices, data, session, pe
|
|
|
38
38
|
coerceTopLevelDataFromSchema(inputSchemaName, data);
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
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) {
|
|
52
59
|
return (await runMiddleware(allServices, {
|
|
53
60
|
http: allServices.http,
|
|
54
61
|
mcp: allServices.mcp,
|
|
55
62
|
rpc: allServices.rpc,
|
|
56
|
-
},
|
|
63
|
+
}, allMiddleware, async () => await funcConfig.func(allServices, data, session)));
|
|
57
64
|
}
|
|
58
65
|
return (await funcConfig.func(allServices, data, session));
|
|
59
66
|
};
|
|
@@ -35,12 +35,13 @@ export type CorePikkuFunctionSessionless<In, Out, ChannelData extends unknown |
|
|
|
35
35
|
*/
|
|
36
36
|
export type CorePikkuPermission<In = any, Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession> = (services: Services, data: In, session?: Session) => Promise<boolean>;
|
|
37
37
|
export type CorePermissionGroup<PikkuPermission = CorePikkuPermission<any>> = Record<string, PikkuPermission | PikkuPermission[]> | undefined;
|
|
38
|
-
export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any, any, any, any, any> | CorePikkuFunctionSessionless<any, any, any, any, any>, PikkuPermission extends CorePikkuPermission<any, any, any> = CorePikkuPermission<any>> = {
|
|
38
|
+
export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any, any, any, any, any> | CorePikkuFunctionSessionless<any, any, any, any, any>, PikkuPermission extends CorePikkuPermission<any, any, any> = CorePikkuPermission<any>, PikkuMiddleware extends CorePikkuMiddleware<any> = CorePikkuMiddleware<any>> = {
|
|
39
39
|
name?: string;
|
|
40
40
|
expose?: boolean;
|
|
41
41
|
func: PikkuFunction;
|
|
42
42
|
auth?: boolean;
|
|
43
43
|
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
44
|
-
middleware?:
|
|
44
|
+
middleware?: PikkuMiddleware[];
|
|
45
|
+
tags?: string[];
|
|
45
46
|
docs?: PikkuDocs;
|
|
46
47
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -21,7 +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 } from './middleware-runner.js';
|
|
24
|
+
export { runMiddleware, addMiddleware, combineMiddleware, } from './middleware-runner.js';
|
|
25
|
+
export { addPermission, getPermissionsForTags, runPermissions, } from './permissions.js';
|
|
25
26
|
export { wireHTTP, addHTTPMiddleware } from './wirings/http/http-runner.js';
|
|
26
27
|
export { wireChannel } from './wirings/channel/channel-runner.js';
|
|
27
28
|
export { wireScheduler } from './wirings/scheduler/scheduler-runner.js';
|
package/dist/index.js
CHANGED
|
@@ -21,7 +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 } from './middleware-runner.js';
|
|
24
|
+
export { runMiddleware, addMiddleware, combineMiddleware, } from './middleware-runner.js';
|
|
25
|
+
export { addPermission, getPermissionsForTags, runPermissions, } from './permissions.js';
|
|
25
26
|
export { wireHTTP, addHTTPMiddleware } from './wirings/http/http-runner.js';
|
|
26
27
|
export { wireChannel } from './wirings/channel/channel-runner.js';
|
|
27
28
|
export { wireScheduler } from './wirings/scheduler/scheduler-runner.js';
|
|
@@ -20,3 +20,73 @@ import { CoreSingletonServices, PikkuInteraction, CorePikkuMiddleware } from './
|
|
|
20
20
|
export declare const runMiddleware: <Middleware extends CorePikkuMiddleware>(services: CoreSingletonServices & {
|
|
21
21
|
userSession?: UserSessionService<any>;
|
|
22
22
|
}, interaction: PikkuInteraction, middlewares: Middleware[], main?: () => Promise<unknown>) => Promise<unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* Adds global middleware for a specific tag.
|
|
25
|
+
*
|
|
26
|
+
* This function allows you to register middleware that will be applied to
|
|
27
|
+
* any wiring (HTTP, Channel, Queue, Scheduler, MCP) that includes the matching tag.
|
|
28
|
+
*
|
|
29
|
+
* @template PikkuMiddleware The middleware type.
|
|
30
|
+
* @param {string} tag - The tag that the middleware should apply to.
|
|
31
|
+
* @param {PikkuMiddleware[]} middleware - The middleware array to apply for the specified tag.
|
|
32
|
+
*
|
|
33
|
+
* @throws {Error} If middleware for the tag already exists.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* // Add admin middleware for admin endpoints
|
|
38
|
+
* addMiddleware('admin', [adminMiddleware])
|
|
39
|
+
*
|
|
40
|
+
* // Add authentication middleware for auth endpoints
|
|
41
|
+
* addMiddleware('auth', [authMiddleware])
|
|
42
|
+
*
|
|
43
|
+
* // Add logging middleware for all API endpoints
|
|
44
|
+
* addMiddleware('api', [loggingMiddleware])
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare const addMiddleware: <PikkuMiddleware extends CorePikkuMiddleware>(tag: string, middleware: PikkuMiddleware[]) => void;
|
|
48
|
+
/**
|
|
49
|
+
* Retrieves middleware for a given set of tags.
|
|
50
|
+
*
|
|
51
|
+
* This function looks up all middleware registered for any of the provided tags
|
|
52
|
+
* and returns them as a flattened array.
|
|
53
|
+
*
|
|
54
|
+
* @param {string[]} tags - Array of tags to look up middleware for.
|
|
55
|
+
* @returns {CorePikkuMiddleware[]} Array of middleware functions that apply to the given tags.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* // Get all middleware for tags 'api' and 'auth'
|
|
60
|
+
* const middleware = getMiddlewareForTags(['api', 'auth'])
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare const getMiddlewareForTags: (tags?: string[]) => CorePikkuMiddleware[];
|
|
64
|
+
/**
|
|
65
|
+
* Combines tag-based middleware with wiring-specific middleware and function-level middleware.
|
|
66
|
+
*
|
|
67
|
+
* This helper function gets middleware for tags and combines it with any
|
|
68
|
+
* wiring-specific middleware and function-level middleware, avoiding the need for manual spreading.
|
|
69
|
+
*
|
|
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.
|
|
75
|
+
* @returns {CorePikkuMiddleware[]} Combined array of tag-based and wiring-specific middleware.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const combined = combineMiddleware({
|
|
80
|
+
* wiringMiddleware: httpRoute.middleware,
|
|
81
|
+
* wiringTags: httpRoute.tags,
|
|
82
|
+
* funcMiddleware: funcConfig.middleware,
|
|
83
|
+
* funcTags: funcConfig.tags
|
|
84
|
+
* })
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export declare const combineMiddleware: ({ wiringMiddleware, wiringTags, funcMiddleware, funcTags, }?: {
|
|
88
|
+
wiringMiddleware?: CorePikkuMiddleware[];
|
|
89
|
+
wiringTags?: string[];
|
|
90
|
+
funcMiddleware?: CorePikkuMiddleware[];
|
|
91
|
+
funcTags?: string[];
|
|
92
|
+
}) => CorePikkuMiddleware[];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { pikkuState } from './pikku-state.js';
|
|
1
2
|
/**
|
|
2
3
|
* Runs a chain of middleware functions in sequence before executing the main function.
|
|
3
4
|
*
|
|
@@ -16,10 +17,12 @@
|
|
|
16
17
|
* );
|
|
17
18
|
*/
|
|
18
19
|
export const runMiddleware = async (services, interaction, middlewares, main) => {
|
|
20
|
+
// Deduplicate middleware using Set to avoid running the same middleware multiple times
|
|
21
|
+
const uniqueMiddleware = Array.from(new Set(middlewares));
|
|
19
22
|
let result;
|
|
20
23
|
const dispatch = async (index) => {
|
|
21
|
-
if (
|
|
22
|
-
return await
|
|
24
|
+
if (uniqueMiddleware && index < uniqueMiddleware.length) {
|
|
25
|
+
return await uniqueMiddleware[index](services, interaction, () => dispatch(index + 1));
|
|
23
26
|
}
|
|
24
27
|
else if (main) {
|
|
25
28
|
result = await main();
|
|
@@ -28,3 +31,103 @@ export const runMiddleware = async (services, interaction, middlewares, main) =>
|
|
|
28
31
|
await dispatch(0);
|
|
29
32
|
return result;
|
|
30
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* Adds global middleware for a specific tag.
|
|
36
|
+
*
|
|
37
|
+
* This function allows you to register middleware that will be applied to
|
|
38
|
+
* any wiring (HTTP, Channel, Queue, Scheduler, MCP) that includes the matching tag.
|
|
39
|
+
*
|
|
40
|
+
* @template PikkuMiddleware The middleware type.
|
|
41
|
+
* @param {string} tag - The tag that the middleware should apply to.
|
|
42
|
+
* @param {PikkuMiddleware[]} middleware - The middleware array to apply for the specified tag.
|
|
43
|
+
*
|
|
44
|
+
* @throws {Error} If middleware for the tag already exists.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* // Add admin middleware for admin endpoints
|
|
49
|
+
* addMiddleware('admin', [adminMiddleware])
|
|
50
|
+
*
|
|
51
|
+
* // Add authentication middleware for auth endpoints
|
|
52
|
+
* addMiddleware('auth', [authMiddleware])
|
|
53
|
+
*
|
|
54
|
+
* // Add logging middleware for all API endpoints
|
|
55
|
+
* addMiddleware('api', [loggingMiddleware])
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export const addMiddleware = (tag, middleware) => {
|
|
59
|
+
const middlewareStore = pikkuState('misc', 'middleware');
|
|
60
|
+
// Check if tag already exists
|
|
61
|
+
if (middlewareStore[tag]) {
|
|
62
|
+
throw new Error(`Middleware for tag '${tag}' already exists. Use a different tag or remove the existing middleware first.`);
|
|
63
|
+
}
|
|
64
|
+
middlewareStore[tag] = middleware;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Retrieves middleware for a given set of tags.
|
|
68
|
+
*
|
|
69
|
+
* This function looks up all middleware registered for any of the provided tags
|
|
70
|
+
* and returns them as a flattened array.
|
|
71
|
+
*
|
|
72
|
+
* @param {string[]} tags - Array of tags to look up middleware for.
|
|
73
|
+
* @returns {CorePikkuMiddleware[]} Array of middleware functions that apply to the given tags.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* // Get all middleware for tags 'api' and 'auth'
|
|
78
|
+
* const middleware = getMiddlewareForTags(['api', 'auth'])
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export const getMiddlewareForTags = (tags) => {
|
|
82
|
+
if (!tags || tags.length === 0) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
const middlewareStore = pikkuState('misc', 'middleware');
|
|
86
|
+
const applicableMiddleware = [];
|
|
87
|
+
// Collect middleware for all matching tags
|
|
88
|
+
for (const tag of tags) {
|
|
89
|
+
const tagMiddleware = middlewareStore[tag];
|
|
90
|
+
if (tagMiddleware) {
|
|
91
|
+
applicableMiddleware.push(...tagMiddleware);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return applicableMiddleware;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Combines tag-based middleware with wiring-specific middleware and function-level middleware.
|
|
98
|
+
*
|
|
99
|
+
* This helper function gets middleware for tags and combines it with any
|
|
100
|
+
* wiring-specific middleware and function-level middleware, avoiding the need for manual spreading.
|
|
101
|
+
*
|
|
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.
|
|
107
|
+
* @returns {CorePikkuMiddleware[]} Combined array of tag-based and wiring-specific middleware.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* const combined = combineMiddleware({
|
|
112
|
+
* wiringMiddleware: httpRoute.middleware,
|
|
113
|
+
* wiringTags: httpRoute.tags,
|
|
114
|
+
* funcMiddleware: funcConfig.middleware,
|
|
115
|
+
* funcTags: funcConfig.tags
|
|
116
|
+
* })
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
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
|
+
];
|
|
133
|
+
};
|
package/dist/permissions.d.ts
CHANGED
|
@@ -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.
|
|
@@ -8,3 +8,59 @@ import { CorePermissionGroup } from './function/functions.types.js';
|
|
|
8
8
|
* @returns A promise that resolves to void.
|
|
9
9
|
*/
|
|
10
10
|
export declare const verifyPermissions: (permissions: CorePermissionGroup, services: CoreServices, data: any, session?: CoreUserSession) => Promise<boolean>;
|
|
11
|
+
/**
|
|
12
|
+
* Adds global permissions for a specific tag.
|
|
13
|
+
*
|
|
14
|
+
* This function allows you to register permissions that will be applied to
|
|
15
|
+
* any wiring (HTTP, Channel, Queue, Scheduler, MCP) that includes the matching tag.
|
|
16
|
+
*
|
|
17
|
+
* @param {string} tag - The tag that the permissions should apply to.
|
|
18
|
+
* @param {any[]} permissions - The permissions array to apply for the specified tag.
|
|
19
|
+
*
|
|
20
|
+
* @throws {Error} If permissions for the tag already exist.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // Add admin permissions for admin endpoints
|
|
25
|
+
* addPermission('admin', [adminPermission])
|
|
26
|
+
*
|
|
27
|
+
* // Add authentication permissions for auth endpoints
|
|
28
|
+
* addPermission('auth', [authPermission])
|
|
29
|
+
*
|
|
30
|
+
* // Add read permissions for all API endpoints
|
|
31
|
+
* addPermission('api', [readPermission])
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare const addPermission: (tag: string, permissions: CorePermissionGroup | CorePikkuPermission[]) => void;
|
|
35
|
+
/**
|
|
36
|
+
* Retrieves permissions for a given set of tags.
|
|
37
|
+
*
|
|
38
|
+
* This function looks up all permissions registered for any of the provided tags
|
|
39
|
+
* and returns them as a flattened array.
|
|
40
|
+
*
|
|
41
|
+
* @param {string[]} tags - Array of tags to look up permissions for.
|
|
42
|
+
* @returns {any[]} Array of permission functions that apply to the given tags.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* // Get all permissions for tags 'api' and 'auth'
|
|
47
|
+
* const permissions = getPermissionsForTags(['api', 'auth'])
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
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>;
|
package/dist/permissions.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { pikkuState } from './pikku-state.js';
|
|
2
|
+
import { ForbiddenError } from './errors/errors.js';
|
|
1
3
|
/**
|
|
2
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.
|
|
3
5
|
* @param services - The core services required for permission validation.
|
|
@@ -30,3 +32,123 @@ export const verifyPermissions = async (permissions, services, data, session) =>
|
|
|
30
32
|
}
|
|
31
33
|
return false;
|
|
32
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Adds global permissions for a specific tag.
|
|
37
|
+
*
|
|
38
|
+
* This function allows you to register permissions that will be applied to
|
|
39
|
+
* any wiring (HTTP, Channel, Queue, Scheduler, MCP) that includes the matching tag.
|
|
40
|
+
*
|
|
41
|
+
* @param {string} tag - The tag that the permissions should apply to.
|
|
42
|
+
* @param {any[]} permissions - The permissions array to apply for the specified tag.
|
|
43
|
+
*
|
|
44
|
+
* @throws {Error} If permissions for the tag already exist.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* // Add admin permissions for admin endpoints
|
|
49
|
+
* addPermission('admin', [adminPermission])
|
|
50
|
+
*
|
|
51
|
+
* // Add authentication permissions for auth endpoints
|
|
52
|
+
* addPermission('auth', [authPermission])
|
|
53
|
+
*
|
|
54
|
+
* // Add read permissions for all API endpoints
|
|
55
|
+
* addPermission('api', [readPermission])
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export const addPermission = (tag, permissions) => {
|
|
59
|
+
const permissionsStore = pikkuState('misc', 'permissions');
|
|
60
|
+
// Check if tag already exists
|
|
61
|
+
if (permissionsStore[tag]) {
|
|
62
|
+
throw new Error(`Permissions for tag '${tag}' already exist. Use a different tag or remove the existing permissions first.`);
|
|
63
|
+
}
|
|
64
|
+
permissionsStore[tag] = permissions;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Retrieves permissions for a given set of tags.
|
|
68
|
+
*
|
|
69
|
+
* This function looks up all permissions registered for any of the provided tags
|
|
70
|
+
* and returns them as a flattened array.
|
|
71
|
+
*
|
|
72
|
+
* @param {string[]} tags - Array of tags to look up permissions for.
|
|
73
|
+
* @returns {any[]} Array of permission functions that apply to the given tags.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* // Get all permissions for tags 'api' and 'auth'
|
|
78
|
+
* const permissions = getPermissionsForTags(['api', 'auth'])
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export const getPermissionsForTags = (tags) => {
|
|
82
|
+
if (!tags || tags.length === 0) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
const permissionsStore = pikkuState('misc', 'permissions');
|
|
86
|
+
const applicablePermissions = [];
|
|
87
|
+
// Collect permissions for all matching tags
|
|
88
|
+
for (const tag of new Set(tags)) {
|
|
89
|
+
const tagPermissions = permissionsStore[tag];
|
|
90
|
+
if (tagPermissions) {
|
|
91
|
+
if (Array.isArray(tagPermissions)) {
|
|
92
|
+
applicablePermissions.push(...tagPermissions);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
applicablePermissions.push(tagPermissions);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return applicablePermissions;
|
|
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
|
+
};
|
package/dist/pikku-state.d.ts
CHANGED
|
@@ -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 {
|
|
@@ -49,6 +49,8 @@ interface PikkuState {
|
|
|
49
49
|
misc: {
|
|
50
50
|
errors: Map<PikkuError, ErrorDetails>;
|
|
51
51
|
schemas: Map<string, any>;
|
|
52
|
+
middleware: Record<string, CorePikkuMiddleware[]>;
|
|
53
|
+
permissions: Record<string, CorePermissionGroup | CorePikkuPermission[]>;
|
|
52
54
|
};
|
|
53
55
|
}
|
|
54
56
|
export declare const resetPikkuState: () => void;
|
package/dist/pikku-state.js
CHANGED
|
@@ -35,7 +35,9 @@ export const resetPikkuState = () => {
|
|
|
35
35
|
},
|
|
36
36
|
misc: {
|
|
37
37
|
errors: globalThis.pikkuState?.misc?.errors || new Map(),
|
|
38
|
-
schemas:
|
|
38
|
+
schemas: new Map(),
|
|
39
|
+
middleware: {},
|
|
40
|
+
permissions: {},
|
|
39
41
|
},
|
|
40
42
|
};
|
|
41
43
|
};
|
|
@@ -6,6 +6,8 @@ import { UserSessionService } from '../services/user-session-service.js';
|
|
|
6
6
|
import { PikkuChannel } from '../wirings/channel/channel.types.js';
|
|
7
7
|
import { PikkuRPC } from '../wirings/rpc/rpc-types.js';
|
|
8
8
|
import { PikkuMCP } from '../wirings/mcp/mcp.types.js';
|
|
9
|
+
import { PikkuScheduledTask } from '../wirings/scheduler/scheduler.types.js';
|
|
10
|
+
import { PikkuQueue } from '../wirings/queue/queue.types.js';
|
|
9
11
|
export declare enum PikkuWiringTypes {
|
|
10
12
|
http = "http",
|
|
11
13
|
scheduler = "scheduler",
|
|
@@ -90,11 +92,14 @@ export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
|
|
|
90
92
|
/**
|
|
91
93
|
* Represents different forms of interaction within Pikku and the outside world.
|
|
92
94
|
*/
|
|
93
|
-
export
|
|
94
|
-
http
|
|
95
|
-
mcp
|
|
96
|
-
rpc
|
|
97
|
-
|
|
95
|
+
export type PikkuInteraction<In = unknown, Out = unknown> = Partial<{
|
|
96
|
+
http: PikkuHTTP<In>;
|
|
97
|
+
mcp: PikkuMCP;
|
|
98
|
+
rpc: PikkuRPC;
|
|
99
|
+
channel: PikkuChannel<unknown, Out>;
|
|
100
|
+
scheduledTask: PikkuScheduledTask;
|
|
101
|
+
queue: PikkuQueue;
|
|
102
|
+
}>;
|
|
98
103
|
/**
|
|
99
104
|
* A function that can wrap an interaction and be called before or after
|
|
100
105
|
*/
|