@pikku/core 0.9.11 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/errors/errors.d.ts +2 -0
- package/dist/errors/errors.js +6 -0
- package/dist/function/function-runner.d.ts +15 -9
- package/dist/function/function-runner.js +55 -37
- package/dist/function/functions.types.d.ts +67 -1
- package/dist/function/functions.types.js +43 -1
- package/dist/index.d.ts +2 -6
- package/dist/index.js +2 -6
- package/dist/middleware/auth-apikey.d.ts +19 -11
- package/dist/middleware/auth-apikey.js +33 -33
- package/dist/middleware/auth-bearer.d.ts +34 -7
- package/dist/middleware/auth-bearer.js +53 -36
- package/dist/middleware/auth-cookie.d.ts +30 -12
- package/dist/middleware/auth-cookie.js +51 -43
- package/dist/middleware/timeout.d.ts +6 -2
- package/dist/middleware/timeout.js +7 -9
- package/dist/middleware-runner.d.ts +46 -43
- package/dist/middleware-runner.js +100 -69
- package/dist/permissions.d.ts +82 -20
- package/dist/permissions.js +176 -62
- package/dist/pikku-state.d.ts +46 -1
- package/dist/pikku-state.js +16 -1
- package/dist/services/content-service.d.ts +2 -3
- package/dist/services/index.d.ts +0 -1
- package/dist/services/index.js +0 -1
- package/dist/services/local-content.d.ts +2 -4
- package/dist/types/core.types.d.ts +110 -4
- package/dist/types/core.types.js +44 -1
- package/dist/utils.d.ts +1 -1
- package/dist/wirings/channel/channel-handler.d.ts +2 -2
- package/dist/wirings/channel/channel-handler.js +16 -12
- package/dist/wirings/channel/channel-runner.d.ts +2 -2
- package/dist/wirings/channel/channel-runner.js +6 -24
- package/dist/wirings/channel/channel.types.d.ts +15 -14
- package/dist/wirings/channel/local/local-channel-runner.js +12 -12
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +7 -8
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +12 -0
- package/dist/wirings/cli/channel/cli-channel-runner.js +83 -0
- package/dist/wirings/cli/channel/index.d.ts +1 -0
- package/dist/wirings/cli/channel/index.js +1 -0
- package/dist/wirings/cli/cli-runner.d.ts +42 -0
- package/dist/wirings/cli/cli-runner.js +352 -0
- package/dist/wirings/cli/cli.types.d.ts +204 -0
- package/dist/wirings/cli/cli.types.js +1 -0
- package/dist/wirings/cli/command-parser.d.ts +19 -0
- package/dist/wirings/cli/command-parser.js +403 -0
- package/dist/wirings/cli/index.d.ts +5 -0
- package/dist/wirings/cli/index.js +5 -0
- package/dist/wirings/http/http-runner.d.ts +59 -10
- package/dist/wirings/http/http-runner.js +138 -131
- package/dist/wirings/http/http.types.d.ts +11 -10
- package/dist/wirings/http/index.d.ts +1 -1
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/http/pikku-fetch-http-response.js +3 -1
- package/dist/wirings/http/routers/http-router.d.ts +0 -2
- package/dist/wirings/http/routers/path-to-regex.d.ts +1 -1
- package/dist/wirings/http/routers/path-to-regex.js +5 -34
- package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.d.ts +4 -5
- package/dist/wirings/mcp/mcp-runner.js +32 -34
- package/dist/wirings/mcp/mcp.types.d.ts +38 -14
- package/dist/wirings/queue/queue-runner.d.ts +2 -2
- package/dist/wirings/queue/queue-runner.js +25 -27
- package/dist/wirings/queue/queue.types.d.ts +6 -5
- package/dist/wirings/rpc/index.d.ts +1 -1
- package/dist/wirings/rpc/index.js +1 -1
- package/dist/wirings/rpc/rpc-runner.d.ts +6 -18
- package/dist/wirings/rpc/rpc-runner.js +13 -8
- package/dist/wirings/scheduler/scheduler-runner.d.ts +2 -2
- package/dist/wirings/scheduler/scheduler-runner.js +38 -35
- package/dist/wirings/scheduler/scheduler.types.d.ts +5 -4
- package/package.json +9 -7
- package/src/errors/errors.ts +6 -0
- package/src/factory-functions.test.ts +60 -1
- package/src/function/function-runner.test.ts +81 -26
- package/src/function/function-runner.ts +89 -57
- package/src/function/functions.types.ts +85 -2
- package/src/index.ts +6 -19
- package/src/middleware/auth-apikey.ts +42 -57
- package/src/middleware/auth-bearer.ts +66 -49
- package/src/middleware/auth-cookie.ts +63 -82
- package/src/middleware/timeout.ts +10 -14
- package/src/middleware-runner.test.ts +24 -16
- package/src/middleware-runner.ts +115 -87
- package/src/permissions.test.ts +26 -27
- package/src/permissions.ts +216 -104
- package/src/pikku-state.ts +79 -2
- package/src/services/content-service.ts +5 -4
- package/src/services/index.ts +0 -1
- package/src/services/local-content.ts +9 -4
- package/src/types/core.types.ts +143 -5
- package/src/utils.ts +1 -1
- package/src/wirings/channel/channel-handler.ts +18 -21
- package/src/wirings/channel/channel-runner.ts +19 -32
- package/src/wirings/channel/channel.types.ts +29 -16
- package/src/wirings/channel/local/local-channel-runner.ts +25 -15
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +15 -17
- package/src/wirings/cli/channel/cli-channel-runner.ts +123 -0
- package/src/wirings/cli/channel/index.ts +1 -0
- package/src/wirings/cli/cli-runner.test.ts +403 -0
- package/src/wirings/cli/cli-runner.ts +539 -0
- package/src/wirings/cli/cli.types.ts +350 -0
- package/src/wirings/cli/command-parser.test.ts +445 -0
- package/src/wirings/cli/command-parser.ts +504 -0
- package/src/wirings/cli/index.ts +13 -0
- package/src/wirings/http/http-runner.test.ts +8 -7
- package/src/wirings/http/http-runner.ts +165 -158
- package/src/wirings/http/http.types.ts +58 -11
- package/src/wirings/http/index.ts +7 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +3 -1
- package/src/wirings/http/routers/http-router.ts +0 -2
- package/src/wirings/http/routers/path-to-regex.test.ts +4 -5
- package/src/wirings/http/routers/path-to-regex.ts +6 -43
- package/src/wirings/mcp/mcp-endpoint-registry.ts +1 -1
- package/src/wirings/mcp/mcp-runner.ts +58 -55
- package/src/wirings/mcp/mcp.types.ts +65 -14
- package/src/wirings/queue/queue-runner.ts +44 -47
- package/src/wirings/queue/queue.types.ts +10 -6
- package/src/wirings/rpc/index.ts +1 -1
- package/src/wirings/rpc/rpc-runner.ts +27 -9
- package/src/wirings/scheduler/scheduler-runner.ts +58 -56
- package/src/wirings/scheduler/scheduler.types.ts +10 -3
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,20 +1,38 @@
|
|
|
1
1
|
import { SerializeOptions } from 'cookie';
|
|
2
|
-
import { CoreConfig, CoreSingletonServices, CoreUserSession, CorePikkuMiddleware } from '../types/core.types.js';
|
|
3
2
|
import { RelativeTimeInput } from '../time-utils.js';
|
|
4
3
|
/**
|
|
5
|
-
* Cookie middleware that
|
|
4
|
+
* Cookie-based session middleware that uses JWT for encoding/decoding session data.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* Reads session from a cookie on incoming requests and automatically updates the cookie
|
|
7
|
+
* when the session changes (e.g., after login).
|
|
8
|
+
*
|
|
9
|
+
* @param options.name - Cookie name
|
|
10
|
+
* @param options.expiresIn - Cookie expiration time (e.g., { value: 30, unit: 'day' })
|
|
11
|
+
* @param options.options - Cookie serialization options (httpOnly, secure, sameSite, etc.)
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { authCookie } from '@pikku/core/middleware'
|
|
16
|
+
*
|
|
17
|
+
* addHTTPMiddleware([
|
|
18
|
+
* authCookie({
|
|
19
|
+
* name: 'session',
|
|
20
|
+
* expiresIn: { value: 30, unit: 'day' },
|
|
21
|
+
* options: {
|
|
22
|
+
* httpOnly: true,
|
|
23
|
+
* secure: true,
|
|
24
|
+
* sameSite: 'strict',
|
|
25
|
+
* path: '/'
|
|
26
|
+
* }
|
|
27
|
+
* })
|
|
28
|
+
* ])
|
|
29
|
+
* ```
|
|
9
30
|
*/
|
|
10
|
-
export declare const authCookie: <
|
|
31
|
+
export declare const authCookie: import("../types/core.types.js").CorePikkuMiddlewareFactory<{
|
|
11
32
|
name: string;
|
|
12
33
|
options: SerializeOptions;
|
|
13
34
|
expiresIn: RelativeTimeInput;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
getSessionForCookieValue?: undefined;
|
|
19
|
-
jwt: true;
|
|
20
|
-
})) => CorePikkuMiddleware;
|
|
35
|
+
}, import("../types/core.types.js").CoreSingletonServices<{
|
|
36
|
+
logLevel?: import("../index.js").LogLevel;
|
|
37
|
+
secrets?: {};
|
|
38
|
+
}>, import("../types/core.types.js").CoreUserSession>;
|
|
@@ -1,52 +1,60 @@
|
|
|
1
|
+
import { pikkuMiddleware, pikkuMiddlewareFactory } from '../types/core.types.js';
|
|
1
2
|
import { getRelativeTimeOffsetFromNow, } from '../time-utils.js';
|
|
2
3
|
/**
|
|
3
|
-
* Cookie middleware that
|
|
4
|
+
* Cookie-based session middleware that uses JWT for encoding/decoding session data.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
6
|
+
* Reads session from a cookie on incoming requests and automatically updates the cookie
|
|
7
|
+
* when the session changes (e.g., after login).
|
|
8
|
+
*
|
|
9
|
+
* @param options.name - Cookie name
|
|
10
|
+
* @param options.expiresIn - Cookie expiration time (e.g., { value: 30, unit: 'day' })
|
|
11
|
+
* @param options.options - Cookie serialization options (httpOnly, secure, sameSite, etc.)
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { authCookie } from '@pikku/core/middleware'
|
|
16
|
+
*
|
|
17
|
+
* addHTTPMiddleware([
|
|
18
|
+
* authCookie({
|
|
19
|
+
* name: 'session',
|
|
20
|
+
* expiresIn: { value: 30, unit: 'day' },
|
|
21
|
+
* options: {
|
|
22
|
+
* httpOnly: true,
|
|
23
|
+
* secure: true,
|
|
24
|
+
* sameSite: 'strict',
|
|
25
|
+
* path: '/'
|
|
26
|
+
* }
|
|
27
|
+
* })
|
|
28
|
+
* ])
|
|
29
|
+
* ```
|
|
7
30
|
*/
|
|
8
|
-
export const authCookie = ({ name,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
if (cookieValue) {
|
|
17
|
-
if (jwt) {
|
|
18
|
-
if (!jwtService) {
|
|
19
|
-
throw new Error('JWT service is required for JWT decoding.');
|
|
20
|
-
}
|
|
21
|
-
userSession = await jwtService.decode(cookieValue);
|
|
22
|
-
}
|
|
23
|
-
else if (getSessionForCookieValue) {
|
|
24
|
-
userSession = await getSessionForCookieValue(services, cookieValue, name);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
31
|
+
export const authCookie = pikkuMiddlewareFactory(({ name, options, expiresIn }) => pikkuMiddleware(async ({ userSession: userSessionService, jwt: jwtService, logger }, { http }, next) => {
|
|
32
|
+
if (!http?.request || userSessionService.get()) {
|
|
33
|
+
return next();
|
|
34
|
+
}
|
|
35
|
+
// Try to decode session from cookie
|
|
36
|
+
const cookieValue = http.request.cookie(name);
|
|
37
|
+
if (cookieValue && jwtService) {
|
|
38
|
+
const userSession = await jwtService.decode(cookieValue);
|
|
27
39
|
if (userSession) {
|
|
28
40
|
userSessionService.setInitial(userSession);
|
|
29
41
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
}
|
|
43
|
+
await next();
|
|
44
|
+
// Set the cookie in the response if the session has changed
|
|
45
|
+
if (!http?.response) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (userSessionService.sessionChanged) {
|
|
49
|
+
const session = userSessionService.get();
|
|
50
|
+
if (jwtService) {
|
|
51
|
+
http.response.cookie(name, await jwtService.encode(expiresIn, session), {
|
|
52
|
+
...options,
|
|
53
|
+
expires: getRelativeTimeOffsetFromNow(expiresIn),
|
|
54
|
+
});
|
|
34
55
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (jwt) {
|
|
38
|
-
if (!jwtService) {
|
|
39
|
-
throw new Error('JWT service is required for JWT encoding.');
|
|
40
|
-
}
|
|
41
|
-
http.response.cookie(name, await jwtService.encode(expiresIn, session), {
|
|
42
|
-
...options,
|
|
43
|
-
expires: getRelativeTimeOffsetFromNow(expiresIn),
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
logger.warn('No JWT service available, unable to set cookie');
|
|
48
|
-
}
|
|
56
|
+
else {
|
|
57
|
+
logger.warn('No JWT service available, unable to set cookie');
|
|
49
58
|
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
};
|
|
59
|
+
}
|
|
60
|
+
}));
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export declare const timeout: () => import("../types/core.types.js").CorePikkuMiddlewareFactory<{
|
|
2
|
+
timeout: number;
|
|
3
|
+
}, import("../types/core.types.js").CoreSingletonServices<{
|
|
4
|
+
logLevel?: import("../index.js").LogLevel;
|
|
5
|
+
secrets?: {};
|
|
6
|
+
}>, import("../types/core.types.js").CoreUserSession>;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { RequestTimeoutError } from '../errors/errors.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return middleware;
|
|
10
|
-
};
|
|
2
|
+
import { pikkuMiddleware, pikkuMiddlewareFactory } from '../types/core.types.js';
|
|
3
|
+
export const timeout = () => pikkuMiddlewareFactory(({ timeout }) => pikkuMiddleware(async (_services, _interaction, next) => {
|
|
4
|
+
setTimeout(() => {
|
|
5
|
+
throw new RequestTimeoutError();
|
|
6
|
+
}, timeout);
|
|
7
|
+
await next();
|
|
8
|
+
}));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { UserSessionService } from './services/user-session-service.js';
|
|
2
|
-
import { CoreSingletonServices, PikkuInteraction, CorePikkuMiddleware, PikkuWiringTypes } from './types/core.types.js';
|
|
2
|
+
import { CoreSingletonServices, PikkuInteraction, CorePikkuMiddleware, CorePikkuMiddlewareGroup, PikkuWiringTypes, MiddlewareMetadata } from './types/core.types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Runs a chain of middleware functions in sequence before executing the main function.
|
|
5
5
|
*
|
|
@@ -21,73 +21,76 @@ export declare const runMiddleware: <Middleware extends CorePikkuMiddleware>(ser
|
|
|
21
21
|
userSession?: UserSessionService<any>;
|
|
22
22
|
}, interaction: PikkuInteraction, middlewares: readonly Middleware[], main?: () => Promise<unknown>) => Promise<unknown>;
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
24
|
+
* Registers global middleware for a specific tag.
|
|
25
25
|
*
|
|
26
|
-
* This function
|
|
27
|
-
* any wiring (HTTP, Channel, Queue, Scheduler, MCP) that includes the matching tag.
|
|
26
|
+
* This function registers middleware at runtime that will be applied to
|
|
27
|
+
* any wiring (HTTP, Channel, Queue, Scheduler, MCP, CLI) that includes the matching tag.
|
|
28
|
+
*
|
|
29
|
+
* For tree-shaking benefits, wrap in a factory function:
|
|
30
|
+
* `export const x = () => addMiddleware('tag', [...])`
|
|
31
|
+
*
|
|
32
|
+
* Accepts an array that can contain:
|
|
33
|
+
* - Direct middleware functions (CorePikkuMiddleware)
|
|
34
|
+
* - Factory middleware functions (CorePikkuMiddlewareFactory)
|
|
28
35
|
*
|
|
29
36
|
* @template PikkuMiddleware The middleware type.
|
|
30
37
|
* @param {string} tag - The tag that the middleware should apply to.
|
|
31
|
-
* @param {
|
|
38
|
+
* @param {CorePikkuMiddlewareGroup} middleware - Array of middleware for this tag.
|
|
32
39
|
*
|
|
33
|
-
* @
|
|
40
|
+
* @returns {CorePikkuMiddlewareGroup} The middleware array (for chaining/wrapping).
|
|
34
41
|
*
|
|
35
42
|
* @example
|
|
36
43
|
* ```typescript
|
|
37
|
-
* //
|
|
38
|
-
* addMiddleware('admin', [
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
44
|
+
* // Recommended: tree-shakeable
|
|
45
|
+
* export const adminMiddleware = () => addMiddleware('admin', [
|
|
46
|
+
* authMiddleware,
|
|
47
|
+
* loggingMiddleware({ level: 'info' })
|
|
48
|
+
* ])
|
|
42
49
|
*
|
|
43
|
-
* //
|
|
44
|
-
* addMiddleware('api', [
|
|
50
|
+
* // Also works: no tree-shaking
|
|
51
|
+
* export const apiMiddleware = addMiddleware('api', [
|
|
52
|
+
* rateLimitMiddleware
|
|
53
|
+
* ])
|
|
45
54
|
* ```
|
|
46
55
|
*/
|
|
47
|
-
export declare const addMiddleware: <PikkuMiddleware extends CorePikkuMiddleware>(tag: string, middleware:
|
|
56
|
+
export declare const addMiddleware: <PikkuMiddleware extends CorePikkuMiddleware>(tag: string, middleware: CorePikkuMiddlewareGroup) => CorePikkuMiddlewareGroup;
|
|
48
57
|
/**
|
|
49
|
-
* Retrieves
|
|
58
|
+
* Retrieves a registered middleware function by its name.
|
|
50
59
|
*
|
|
51
|
-
* This function looks up
|
|
52
|
-
*
|
|
60
|
+
* This function looks up middleware that was registered with registerMiddleware.
|
|
61
|
+
* It's used internally by the framework to resolve middleware references in metadata.
|
|
53
62
|
*
|
|
54
|
-
* @param {string
|
|
55
|
-
* @returns {CorePikkuMiddleware
|
|
63
|
+
* @param {string} name - The unique name (pikkuFuncName) of the middleware function.
|
|
64
|
+
* @returns {CorePikkuMiddleware | undefined} The middleware function, or undefined if not found.
|
|
56
65
|
*
|
|
57
|
-
* @
|
|
58
|
-
* ```typescript
|
|
59
|
-
* // Get all middleware for tags 'api' and 'auth'
|
|
60
|
-
* const middleware = getMiddlewareForTags(['api', 'auth'])
|
|
61
|
-
* ```
|
|
66
|
+
* @internal
|
|
62
67
|
*/
|
|
63
|
-
export declare const
|
|
68
|
+
export declare const getMiddlewareByName: (name: string) => CorePikkuMiddleware | undefined;
|
|
64
69
|
/**
|
|
65
|
-
* Combines
|
|
70
|
+
* Combines wiring-specific middleware with function-level middleware.
|
|
66
71
|
*
|
|
67
|
-
* This
|
|
68
|
-
*
|
|
72
|
+
* This function resolves middleware metadata into actual middleware functions and combines them.
|
|
73
|
+
* It filters out wire middleware without tags from inheritedMiddleware to avoid duplication
|
|
74
|
+
* (those are passed separately as wireMiddleware).
|
|
69
75
|
*
|
|
70
76
|
* @param {object} options - Configuration object for combining middleware.
|
|
71
|
-
* @param {
|
|
72
|
-
* @param {
|
|
73
|
-
* @param {
|
|
74
|
-
* @
|
|
75
|
-
* @returns {CorePikkuMiddleware[]} Combined array of tag-based and wiring-specific middleware.
|
|
77
|
+
* @param {MiddlewareMetadata[] | undefined} options.inheritedMiddleware - Metadata from wiring (HTTP + tags + wire with tags).
|
|
78
|
+
* @param {CorePikkuMiddleware[] | undefined} options.wireMiddleware - Inline wire middleware.
|
|
79
|
+
* @param {MiddlewareMetadata[] | undefined} options.funcMiddleware - Function middleware metadata.
|
|
80
|
+
* @returns {CorePikkuMiddleware[]} Combined array of resolved middleware.
|
|
76
81
|
*
|
|
77
82
|
* @example
|
|
78
83
|
* ```typescript
|
|
79
|
-
* const combined = combineMiddleware({
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* funcMiddleware:
|
|
83
|
-
* funcTags: funcConfig.tags
|
|
84
|
+
* const combined = combineMiddleware(wireType, wireId, {
|
|
85
|
+
* inheritedMiddleware: meta.middleware,
|
|
86
|
+
* wireMiddleware: [inlineMiddleware],
|
|
87
|
+
* funcMiddleware: funcMeta.middleware
|
|
84
88
|
* })
|
|
85
89
|
* ```
|
|
86
90
|
*/
|
|
87
|
-
export declare const combineMiddleware: (wireType: PikkuWiringTypes, uid: string, {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
export declare const combineMiddleware: (wireType: PikkuWiringTypes, uid: string, { wireInheritedMiddleware, wireMiddleware, funcInheritedMiddleware, funcMiddleware, }?: {
|
|
92
|
+
wireInheritedMiddleware?: MiddlewareMetadata[];
|
|
93
|
+
wireMiddleware?: CorePikkuMiddleware[];
|
|
94
|
+
funcInheritedMiddleware?: MiddlewareMetadata[];
|
|
91
95
|
funcMiddleware?: CorePikkuMiddleware[];
|
|
92
|
-
funcTags?: string[];
|
|
93
96
|
}) => readonly CorePikkuMiddleware[];
|
|
@@ -33,66 +33,58 @@ export const runMiddleware = async (services, interaction, middlewares, main) =>
|
|
|
33
33
|
return result;
|
|
34
34
|
};
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* Registers global middleware for a specific tag.
|
|
37
37
|
*
|
|
38
|
-
* This function
|
|
39
|
-
* any wiring (HTTP, Channel, Queue, Scheduler, MCP) that includes the matching tag.
|
|
38
|
+
* This function registers middleware at runtime that will be applied to
|
|
39
|
+
* any wiring (HTTP, Channel, Queue, Scheduler, MCP, CLI) that includes the matching tag.
|
|
40
|
+
*
|
|
41
|
+
* For tree-shaking benefits, wrap in a factory function:
|
|
42
|
+
* `export const x = () => addMiddleware('tag', [...])`
|
|
43
|
+
*
|
|
44
|
+
* Accepts an array that can contain:
|
|
45
|
+
* - Direct middleware functions (CorePikkuMiddleware)
|
|
46
|
+
* - Factory middleware functions (CorePikkuMiddlewareFactory)
|
|
40
47
|
*
|
|
41
48
|
* @template PikkuMiddleware The middleware type.
|
|
42
49
|
* @param {string} tag - The tag that the middleware should apply to.
|
|
43
|
-
* @param {
|
|
50
|
+
* @param {CorePikkuMiddlewareGroup} middleware - Array of middleware for this tag.
|
|
44
51
|
*
|
|
45
|
-
* @
|
|
52
|
+
* @returns {CorePikkuMiddlewareGroup} The middleware array (for chaining/wrapping).
|
|
46
53
|
*
|
|
47
54
|
* @example
|
|
48
55
|
* ```typescript
|
|
49
|
-
* //
|
|
50
|
-
* addMiddleware('admin', [
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
56
|
+
* // Recommended: tree-shakeable
|
|
57
|
+
* export const adminMiddleware = () => addMiddleware('admin', [
|
|
58
|
+
* authMiddleware,
|
|
59
|
+
* loggingMiddleware({ level: 'info' })
|
|
60
|
+
* ])
|
|
54
61
|
*
|
|
55
|
-
* //
|
|
56
|
-
* addMiddleware('api', [
|
|
62
|
+
* // Also works: no tree-shaking
|
|
63
|
+
* export const apiMiddleware = addMiddleware('api', [
|
|
64
|
+
* rateLimitMiddleware
|
|
65
|
+
* ])
|
|
57
66
|
* ```
|
|
58
67
|
*/
|
|
59
68
|
export const addMiddleware = (tag, middleware) => {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
throw new Error(`Middleware for tag '${tag}' already exists. Use a different tag or remove the existing middleware first.`);
|
|
64
|
-
}
|
|
65
|
-
middlewareStore[tag] = middleware;
|
|
69
|
+
const tagGroups = pikkuState('middleware', 'tagGroup');
|
|
70
|
+
tagGroups[tag] = middleware;
|
|
71
|
+
return middleware;
|
|
66
72
|
};
|
|
67
73
|
/**
|
|
68
|
-
* Retrieves
|
|
74
|
+
* Retrieves a registered middleware function by its name.
|
|
69
75
|
*
|
|
70
|
-
* This function looks up
|
|
71
|
-
*
|
|
76
|
+
* This function looks up middleware that was registered with registerMiddleware.
|
|
77
|
+
* It's used internally by the framework to resolve middleware references in metadata.
|
|
72
78
|
*
|
|
73
|
-
* @param {string
|
|
74
|
-
* @returns {CorePikkuMiddleware
|
|
79
|
+
* @param {string} name - The unique name (pikkuFuncName) of the middleware function.
|
|
80
|
+
* @returns {CorePikkuMiddleware | undefined} The middleware function, or undefined if not found.
|
|
75
81
|
*
|
|
76
|
-
* @
|
|
77
|
-
* ```typescript
|
|
78
|
-
* // Get all middleware for tags 'api' and 'auth'
|
|
79
|
-
* const middleware = getMiddlewareForTags(['api', 'auth'])
|
|
80
|
-
* ```
|
|
82
|
+
* @internal
|
|
81
83
|
*/
|
|
82
|
-
export const
|
|
83
|
-
if (!tags || tags.length === 0) {
|
|
84
|
-
return [];
|
|
85
|
-
}
|
|
84
|
+
export const getMiddlewareByName = (name) => {
|
|
86
85
|
const middlewareStore = pikkuState('misc', 'middleware');
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
for (const tag of tags) {
|
|
90
|
-
const tagMiddleware = middlewareStore[tag];
|
|
91
|
-
if (tagMiddleware) {
|
|
92
|
-
applicableMiddleware.push(...tagMiddleware);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return applicableMiddleware;
|
|
86
|
+
const middleware = middlewareStore[name];
|
|
87
|
+
return middleware?.[0];
|
|
96
88
|
};
|
|
97
89
|
const middlewareCache = {
|
|
98
90
|
[PikkuWiringTypes.http]: {},
|
|
@@ -101,47 +93,86 @@ const middlewareCache = {
|
|
|
101
93
|
[PikkuWiringTypes.queue]: {},
|
|
102
94
|
[PikkuWiringTypes.scheduler]: {},
|
|
103
95
|
[PikkuWiringTypes.mcp]: {},
|
|
96
|
+
[PikkuWiringTypes.cli]: {},
|
|
104
97
|
};
|
|
105
98
|
/**
|
|
106
|
-
* Combines
|
|
99
|
+
* Combines wiring-specific middleware with function-level middleware.
|
|
107
100
|
*
|
|
108
|
-
* This
|
|
109
|
-
*
|
|
101
|
+
* This function resolves middleware metadata into actual middleware functions and combines them.
|
|
102
|
+
* It filters out wire middleware without tags from inheritedMiddleware to avoid duplication
|
|
103
|
+
* (those are passed separately as wireMiddleware).
|
|
110
104
|
*
|
|
111
105
|
* @param {object} options - Configuration object for combining middleware.
|
|
112
|
-
* @param {
|
|
113
|
-
* @param {
|
|
114
|
-
* @param {
|
|
115
|
-
* @
|
|
116
|
-
* @returns {CorePikkuMiddleware[]} Combined array of tag-based and wiring-specific middleware.
|
|
106
|
+
* @param {MiddlewareMetadata[] | undefined} options.inheritedMiddleware - Metadata from wiring (HTTP + tags + wire with tags).
|
|
107
|
+
* @param {CorePikkuMiddleware[] | undefined} options.wireMiddleware - Inline wire middleware.
|
|
108
|
+
* @param {MiddlewareMetadata[] | undefined} options.funcMiddleware - Function middleware metadata.
|
|
109
|
+
* @returns {CorePikkuMiddleware[]} Combined array of resolved middleware.
|
|
117
110
|
*
|
|
118
111
|
* @example
|
|
119
112
|
* ```typescript
|
|
120
|
-
* const combined = combineMiddleware({
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* funcMiddleware:
|
|
124
|
-
* funcTags: funcConfig.tags
|
|
113
|
+
* const combined = combineMiddleware(wireType, wireId, {
|
|
114
|
+
* inheritedMiddleware: meta.middleware,
|
|
115
|
+
* wireMiddleware: [inlineMiddleware],
|
|
116
|
+
* funcMiddleware: funcMeta.middleware
|
|
125
117
|
* })
|
|
126
118
|
* ```
|
|
127
119
|
*/
|
|
128
|
-
export const combineMiddleware = (wireType, uid, {
|
|
120
|
+
export const combineMiddleware = (wireType, uid, { wireInheritedMiddleware, wireMiddleware, funcInheritedMiddleware, funcMiddleware, } = {}) => {
|
|
129
121
|
if (middlewareCache[wireType][uid]) {
|
|
130
122
|
return middlewareCache[wireType][uid];
|
|
131
123
|
}
|
|
132
|
-
|
|
133
|
-
// 1
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
124
|
+
const resolved = [];
|
|
125
|
+
// 1. Resolve wire inherited middleware (HTTP + tag groups + individual wire middleware)
|
|
126
|
+
if (wireInheritedMiddleware) {
|
|
127
|
+
for (const meta of wireInheritedMiddleware) {
|
|
128
|
+
if (meta.type === 'http') {
|
|
129
|
+
// Look up HTTP middleware group from pikkuState
|
|
130
|
+
const group = pikkuState('middleware', 'httpGroup')[meta.route];
|
|
131
|
+
if (group) {
|
|
132
|
+
// At runtime, all factories should be resolved to middleware
|
|
133
|
+
resolved.push(...group);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else if (meta.type === 'tag') {
|
|
137
|
+
// Look up tag middleware group from pikkuState
|
|
138
|
+
const group = pikkuState('middleware', 'tagGroup')[meta.tag];
|
|
139
|
+
if (group) {
|
|
140
|
+
// At runtime, all factories should be resolved to middleware
|
|
141
|
+
resolved.push(...group);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else if (meta.type === 'wire') {
|
|
145
|
+
// Individual wire middleware (exported, not inline)
|
|
146
|
+
const middleware = getMiddlewareByName(meta.name);
|
|
147
|
+
if (middleware) {
|
|
148
|
+
resolved.push(middleware);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// 2. Add inline wire middleware
|
|
154
|
+
if (wireMiddleware) {
|
|
155
|
+
resolved.push(...wireMiddleware);
|
|
156
|
+
}
|
|
157
|
+
// 3. Resolve function inherited middleware (only tags, wire middleware already handled)
|
|
158
|
+
if (funcInheritedMiddleware) {
|
|
159
|
+
for (const meta of funcInheritedMiddleware) {
|
|
160
|
+
if (meta.type === 'tag') {
|
|
161
|
+
// Look up tag middleware group from pikkuState
|
|
162
|
+
const group = pikkuState('middleware', 'tagGroup')[meta.tag];
|
|
163
|
+
if (group) {
|
|
164
|
+
// At runtime, all factories should be resolved to middleware
|
|
165
|
+
resolved.push(...group);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Note: wire middleware is already handled in wireInheritedMiddleware
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// 4. Add inline function middleware
|
|
172
|
+
if (funcMiddleware) {
|
|
173
|
+
resolved.push(...funcMiddleware);
|
|
174
|
+
}
|
|
175
|
+
// Deduplicate and freeze
|
|
176
|
+
middlewareCache[wireType][uid] = freezeDedupe(resolved);
|
|
146
177
|
return middlewareCache[wireType][uid];
|
|
147
178
|
};
|