@pikku/core 0.9.12-next.0 → 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 +8 -0
- package/dist/errors/errors.d.ts +2 -0
- package/dist/errors/errors.js +6 -0
- package/dist/function/function-runner.d.ts +5 -4
- package/dist/function/function-runner.js +10 -4
- package/dist/function/functions.types.d.ts +67 -1
- package/dist/function/functions.types.js +43 -1
- package/dist/index.d.ts +1 -7
- package/dist/index.js +1 -7
- 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 +0 -18
- package/dist/middleware-runner.js +0 -21
- package/dist/permissions.d.ts +82 -20
- package/dist/permissions.js +175 -62
- package/dist/pikku-state.d.ts +22 -2
- package/dist/pikku-state.js +7 -1
- package/dist/types/core.types.d.ts +58 -1
- package/dist/types/core.types.js +23 -1
- package/dist/utils.d.ts +1 -1
- package/dist/wirings/channel/channel-handler.js +6 -5
- package/dist/wirings/channel/channel-runner.d.ts +3 -1
- package/dist/wirings/channel/channel-runner.js +4 -21
- package/dist/wirings/channel/channel.types.d.ts +12 -13
- package/dist/wirings/cli/channel/cli-channel-runner.js +5 -2
- package/dist/wirings/cli/cli-runner.d.ts +10 -0
- package/dist/wirings/cli/cli-runner.js +44 -20
- package/dist/wirings/cli/cli.types.d.ts +54 -27
- package/dist/wirings/cli/command-parser.js +34 -4
- package/dist/wirings/cli/index.d.ts +1 -1
- package/dist/wirings/cli/index.js +1 -1
- package/dist/wirings/http/http-runner.d.ts +31 -1
- package/dist/wirings/http/http-runner.js +36 -1
- package/dist/wirings/http/http.types.d.ts +2 -1
- package/dist/wirings/http/index.d.ts +1 -1
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.js +2 -0
- package/dist/wirings/mcp/mcp.types.d.ts +35 -14
- package/dist/wirings/scheduler/scheduler-runner.js +1 -0
- package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
- package/package.json +6 -5
- package/src/errors/errors.ts +6 -0
- package/src/factory-functions.test.ts +60 -1
- package/src/function/function-runner.test.ts +8 -3
- package/src/function/function-runner.ts +18 -5
- package/src/function/functions.types.ts +85 -2
- package/src/index.ts +1 -21
- 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.ts +0 -25
- package/src/permissions.test.ts +26 -27
- package/src/permissions.ts +215 -104
- package/src/pikku-state.ts +35 -3
- package/src/types/core.types.ts +70 -3
- package/src/utils.ts +1 -1
- package/src/wirings/channel/channel-handler.ts +11 -10
- package/src/wirings/channel/channel-runner.ts +18 -27
- package/src/wirings/channel/channel.types.ts +24 -15
- package/src/wirings/cli/channel/cli-channel-runner.ts +8 -3
- package/src/wirings/cli/cli-runner.test.ts +80 -59
- package/src/wirings/cli/cli-runner.ts +57 -21
- package/src/wirings/cli/cli.types.ts +74 -44
- package/src/wirings/cli/command-parser.test.ts +91 -86
- package/src/wirings/cli/command-parser.ts +38 -4
- package/src/wirings/cli/index.ts +1 -0
- package/src/wirings/http/http-runner.ts +41 -1
- package/src/wirings/http/http.types.ts +3 -1
- package/src/wirings/http/index.ts +7 -1
- package/src/wirings/mcp/mcp-endpoint-registry.ts +1 -1
- package/src/wirings/mcp/mcp-runner.ts +2 -0
- package/src/wirings/mcp/mcp.types.ts +48 -12
- package/src/wirings/scheduler/scheduler-runner.ts +1 -0
- package/src/wirings/scheduler/scheduler.types.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
# @pikku/core
|
|
2
|
+
|
|
1
3
|
## 0.9.0
|
|
2
4
|
|
|
5
|
+
## 0.10.0
|
|
6
|
+
|
|
7
|
+
This release includes significant improvements across the framework including tree-shaking support, middleware/permission factories, enhanced CLI functionality, improved TypeScript type safety, and comprehensive test strategies.
|
|
8
|
+
|
|
9
|
+
For complete details, see https://pikku.dev/changelogs/0_10_0.md
|
|
10
|
+
|
|
3
11
|
## 0.9.12-next.0
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/dist/errors/errors.d.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* The server cannot or will not process the request due to client error (e.g., malformed request syntax).
|
|
3
3
|
*/
|
|
4
4
|
import { PikkuError } from './error-handler.js';
|
|
5
|
+
export declare class InvalidMiddlewareInteractionError extends PikkuError {
|
|
6
|
+
}
|
|
5
7
|
/**
|
|
6
8
|
* The server cannot or will not process the request due to client error (e.g., malformed request syntax).
|
|
7
9
|
* @group Error
|
package/dist/errors/errors.js
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
* The server cannot or will not process the request due to client error (e.g., malformed request syntax).
|
|
3
3
|
*/
|
|
4
4
|
import { addError, PikkuError } from './error-handler.js';
|
|
5
|
+
export class InvalidMiddlewareInteractionError extends PikkuError {
|
|
6
|
+
}
|
|
7
|
+
addError(InvalidMiddlewareInteractionError, {
|
|
8
|
+
status: 500,
|
|
9
|
+
message: 'The middleware interaction is invalid for the current wiring type.',
|
|
10
|
+
});
|
|
5
11
|
/**
|
|
6
12
|
* The server cannot or will not process the request due to client error (e.g., malformed request syntax).
|
|
7
13
|
* @group Error
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { CoreServices, CoreUserSession, CorePikkuMiddleware, PikkuWiringTypes, CoreSingletonServices, PikkuInteraction, MiddlewareMetadata } from '../types/core.types.js';
|
|
2
|
-
import { CorePermissionGroup, CorePikkuFunctionConfig } from './functions.types.js';
|
|
1
|
+
import { CoreServices, CoreUserSession, CorePikkuMiddleware, PikkuWiringTypes, CoreSingletonServices, PikkuInteraction, MiddlewareMetadata, PermissionMetadata } from '../types/core.types.js';
|
|
2
|
+
import { CorePermissionGroup, CorePikkuFunctionConfig, CorePikkuPermission } from './functions.types.js';
|
|
3
3
|
import { UserSessionService } from '../services/user-session-service.js';
|
|
4
4
|
export declare const addFunction: (funcName: string, funcConfig: CorePikkuFunctionConfig<any, any>) => void;
|
|
5
5
|
export declare const runPikkuFuncDirectly: <In, Out>(funcName: string, allServices: CoreServices, data: In, session?: CoreUserSession) => Promise<Out>;
|
|
6
|
-
export declare const runPikkuFunc: <In = any, Out = any>(wireType: PikkuWiringTypes, wireId: string, funcName: string, { getAllServices, singletonServices, data, userSession, auth: wiringAuth,
|
|
6
|
+
export declare const runPikkuFunc: <In = any, Out = any>(wireType: PikkuWiringTypes, wireId: string, funcName: string, { getAllServices, singletonServices, data, userSession, auth: wiringAuth, inheritedMiddleware, wireMiddleware, inheritedPermissions, wirePermissions, coerceDataFromSchema, tags, interaction, }: {
|
|
7
7
|
singletonServices: CoreSingletonServices;
|
|
8
8
|
getAllServices: (session?: CoreUserSession) => Promise<CoreServices> | CoreServices;
|
|
9
9
|
userSession?: UserSessionService<CoreUserSession>;
|
|
10
10
|
data: () => Promise<In> | In;
|
|
11
11
|
auth?: boolean;
|
|
12
|
-
permissions?: CorePermissionGroup;
|
|
13
12
|
inheritedMiddleware?: MiddlewareMetadata[];
|
|
14
13
|
wireMiddleware?: CorePikkuMiddleware[];
|
|
14
|
+
inheritedPermissions?: PermissionMetadata[];
|
|
15
|
+
wirePermissions?: CorePermissionGroup | CorePikkuPermission[];
|
|
15
16
|
coerceDataFromSchema?: boolean;
|
|
16
17
|
tags?: string[];
|
|
17
18
|
interaction: PikkuInteraction;
|
|
@@ -13,7 +13,7 @@ export const runPikkuFuncDirectly = async (funcName, allServices, data, session)
|
|
|
13
13
|
}
|
|
14
14
|
return (await funcConfig.func(allServices, data, session));
|
|
15
15
|
};
|
|
16
|
-
export const runPikkuFunc = async (wireType, wireId, funcName, { getAllServices, singletonServices, data, userSession, auth: wiringAuth,
|
|
16
|
+
export const runPikkuFunc = async (wireType, wireId, funcName, { getAllServices, singletonServices, data, userSession, auth: wiringAuth, inheritedMiddleware, wireMiddleware, inheritedPermissions, wirePermissions, coerceDataFromSchema, tags = [], interaction, }) => {
|
|
17
17
|
const funcConfig = pikkuState('function', 'functions').get(funcName);
|
|
18
18
|
if (!funcConfig) {
|
|
19
19
|
throw new Error(`Function not found: ${funcName}`);
|
|
@@ -22,6 +22,11 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { getAllServices,
|
|
|
22
22
|
if (!funcMeta) {
|
|
23
23
|
throw new Error(`Function meta not found: ${funcName}`);
|
|
24
24
|
}
|
|
25
|
+
// Convert tags to PermissionMetadata and merge with inheritedPermissions
|
|
26
|
+
const mergedInheritedPermissions = [
|
|
27
|
+
...(inheritedPermissions || []),
|
|
28
|
+
...(tags?.map((tag) => ({ type: 'tag', tag })) || []),
|
|
29
|
+
];
|
|
25
30
|
// Helper function to run permissions and execute the function
|
|
26
31
|
const executeFunction = async () => {
|
|
27
32
|
const session = userSession?.get();
|
|
@@ -50,10 +55,11 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { getAllServices,
|
|
|
50
55
|
}
|
|
51
56
|
}
|
|
52
57
|
const allServices = await getAllServices(session);
|
|
58
|
+
// Run permissions check with combined permissions: inheritedPermissions (including tags) → wirePermissions → funcPermissions
|
|
53
59
|
await runPermissions(wireType, wireId, {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
wireInheritedPermissions: mergedInheritedPermissions,
|
|
61
|
+
wirePermissions: wirePermissions,
|
|
62
|
+
funcInheritedPermissions: funcMeta.permissions,
|
|
57
63
|
funcPermissions: funcConfig.permissions,
|
|
58
64
|
allServices,
|
|
59
65
|
data: actualData,
|
|
@@ -5,6 +5,7 @@ import type { CoreServices, CoreSingletonServices, CoreUserSession, PikkuDocs, C
|
|
|
5
5
|
*
|
|
6
6
|
* @template In - The input type.
|
|
7
7
|
* @template Out - The output type.
|
|
8
|
+
* @template ChannelData - The channel data type.
|
|
8
9
|
* @template Services - The services type, defaults to `CoreServices`.
|
|
9
10
|
* @template Session - The session type, defaults to `CoreUserSession`.
|
|
10
11
|
*/
|
|
@@ -18,6 +19,7 @@ export type CorePikkuFunction<In, Out, ChannelData extends unknown | null = null
|
|
|
18
19
|
*
|
|
19
20
|
* @template In - The input type.
|
|
20
21
|
* @template Out - The output type.
|
|
22
|
+
* @template ChannelData - The channel data type.
|
|
21
23
|
* @template Services - The services type, defaults to `CoreServices`.
|
|
22
24
|
* @template Session - The session type, defaults to `CoreUserSession`.
|
|
23
25
|
*/
|
|
@@ -34,10 +36,74 @@ export type CorePikkuFunctionSessionless<In, Out, ChannelData extends unknown |
|
|
|
34
36
|
* @template Session - The session type, defaults to `CoreUserSession`.
|
|
35
37
|
*/
|
|
36
38
|
export type CorePikkuPermission<In = any, Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession> = (services: Services, data: In, session?: Session) => Promise<boolean>;
|
|
39
|
+
/**
|
|
40
|
+
* Configuration object for creating a permission with metadata
|
|
41
|
+
*
|
|
42
|
+
* @template In - The input type.
|
|
43
|
+
* @template Services - The services type, defaults to `CoreServices`.
|
|
44
|
+
* @template Session - The session type, defaults to `CoreUserSession`.
|
|
45
|
+
*/
|
|
46
|
+
export type CorePikkuPermissionConfig<In = any, Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession> = {
|
|
47
|
+
/** The permission function */
|
|
48
|
+
func: CorePikkuPermission<In, Services, Session>;
|
|
49
|
+
/** Optional human-readable name for the permission */
|
|
50
|
+
name?: string;
|
|
51
|
+
/** Optional description of what the permission checks */
|
|
52
|
+
description?: string;
|
|
53
|
+
};
|
|
37
54
|
/**
|
|
38
55
|
* Factory function for creating permissions with tree-shaking support
|
|
56
|
+
* Supports both direct function and configuration object syntax
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* // Direct function syntax
|
|
61
|
+
* export const adminPermission = pikkuPermission(
|
|
62
|
+
* async ({ logger }, data, session) => {
|
|
63
|
+
* return session?.role === 'admin'
|
|
64
|
+
* }
|
|
65
|
+
* )
|
|
66
|
+
*
|
|
67
|
+
* // Configuration object syntax with metadata
|
|
68
|
+
* export const adminPermission = pikkuPermission({
|
|
69
|
+
* name: 'Admin Permission',
|
|
70
|
+
* description: 'Checks if user has admin role',
|
|
71
|
+
* func: async ({ logger }, data, session) => {
|
|
72
|
+
* return session?.role === 'admin'
|
|
73
|
+
* }
|
|
74
|
+
* })
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare const pikkuPermission: <In = any, Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession>(permission: CorePikkuPermission<In, Services, Session> | CorePikkuPermissionConfig<In, Services, Session>) => CorePikkuPermission<In, Services, Session>;
|
|
78
|
+
/**
|
|
79
|
+
* A factory function that takes input and returns a permission
|
|
80
|
+
* Used when permissions need configuration/input parameters
|
|
81
|
+
*
|
|
82
|
+
* @template In - The input type for the factory.
|
|
83
|
+
* @template Services - The services type, defaults to `CoreServices`.
|
|
84
|
+
* @template Session - The session type, defaults to `CoreUserSession`.
|
|
85
|
+
*/
|
|
86
|
+
export type CorePikkuPermissionFactory<In = any, Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession> = (input: In) => CorePikkuPermission<any, Services, Session>;
|
|
87
|
+
/**
|
|
88
|
+
* Factory function for creating permission factories
|
|
89
|
+
* Use this when your permission needs configuration/input parameters
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* export const requireRole = pikkuPermissionFactory<{ role: string }>(({
|
|
94
|
+
* role
|
|
95
|
+
* }) => {
|
|
96
|
+
* return pikkuPermission(async ({ logger }, data, session) => {
|
|
97
|
+
* if (!session || session.role !== role) {
|
|
98
|
+
* logger.warn(`Permission denied: required role '${role}'`)
|
|
99
|
+
* return false
|
|
100
|
+
* }
|
|
101
|
+
* return true
|
|
102
|
+
* })
|
|
103
|
+
* })
|
|
104
|
+
* ```
|
|
39
105
|
*/
|
|
40
|
-
export declare const
|
|
106
|
+
export declare const pikkuPermissionFactory: <In = any>(factory: CorePikkuPermissionFactory<In>) => CorePikkuPermissionFactory<In>;
|
|
41
107
|
export type CorePermissionGroup<PikkuPermission = CorePikkuPermission<any>> = Record<string, PikkuPermission | PikkuPermission[]> | undefined;
|
|
42
108
|
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>> = {
|
|
43
109
|
name?: string;
|
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Factory function for creating permissions with tree-shaking support
|
|
3
|
+
* Supports both direct function and configuration object syntax
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* // Direct function syntax
|
|
8
|
+
* export const adminPermission = pikkuPermission(
|
|
9
|
+
* async ({ logger }, data, session) => {
|
|
10
|
+
* return session?.role === 'admin'
|
|
11
|
+
* }
|
|
12
|
+
* )
|
|
13
|
+
*
|
|
14
|
+
* // Configuration object syntax with metadata
|
|
15
|
+
* export const adminPermission = pikkuPermission({
|
|
16
|
+
* name: 'Admin Permission',
|
|
17
|
+
* description: 'Checks if user has admin role',
|
|
18
|
+
* func: async ({ logger }, data, session) => {
|
|
19
|
+
* return session?.role === 'admin'
|
|
20
|
+
* }
|
|
21
|
+
* })
|
|
22
|
+
* ```
|
|
3
23
|
*/
|
|
4
24
|
export const pikkuPermission = (permission) => {
|
|
5
|
-
return permission;
|
|
25
|
+
return typeof permission === 'function' ? permission : permission.func;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Factory function for creating permission factories
|
|
29
|
+
* Use this when your permission needs configuration/input parameters
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* export const requireRole = pikkuPermissionFactory<{ role: string }>(({
|
|
34
|
+
* role
|
|
35
|
+
* }) => {
|
|
36
|
+
* return pikkuPermission(async ({ logger }, data, session) => {
|
|
37
|
+
* if (!session || session.role !== role) {
|
|
38
|
+
* logger.warn(`Permission denied: required role '${role}'`)
|
|
39
|
+
* return false
|
|
40
|
+
* }
|
|
41
|
+
* return true
|
|
42
|
+
* })
|
|
43
|
+
* })
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export const pikkuPermissionFactory = (factory) => {
|
|
47
|
+
return factory;
|
|
6
48
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -22,11 +22,5 @@ export * from './middleware/index.js';
|
|
|
22
22
|
export * from './utils.js';
|
|
23
23
|
export * from './time-utils.js';
|
|
24
24
|
export { pikkuState } from './pikku-state.js';
|
|
25
|
-
export { runMiddleware,
|
|
25
|
+
export { runMiddleware, addMiddleware, getMiddlewareByName, } from './middleware-runner.js';
|
|
26
26
|
export { addPermission } from './permissions.js';
|
|
27
|
-
export { wireHTTP, addHTTPMiddleware } from './wirings/http/http-runner.js';
|
|
28
|
-
export { wireChannel } from './wirings/channel/channel-runner.js';
|
|
29
|
-
export { wireScheduler } from './wirings/scheduler/scheduler-runner.js';
|
|
30
|
-
export { wireQueueWorker } from './wirings/queue/queue-runner.js';
|
|
31
|
-
export { wireMCPResource, wireMCPTool, wireMCPPrompt, runMCPResource, runMCPTool, runMCPPrompt, getMCPTools, getMCPResources, getMCPPrompts, getMCPResourcesMeta, getMCPToolsMeta, getMCPPromptsMeta, } from './wirings/mcp/mcp-runner.js';
|
|
32
|
-
export { wireCLI, runCLICommand } from './wirings/cli/cli-runner.js';
|
package/dist/index.js
CHANGED
|
@@ -22,11 +22,5 @@ export * from './middleware/index.js';
|
|
|
22
22
|
export * from './utils.js';
|
|
23
23
|
export * from './time-utils.js';
|
|
24
24
|
export { pikkuState } from './pikku-state.js';
|
|
25
|
-
export { runMiddleware,
|
|
25
|
+
export { runMiddleware, addMiddleware, getMiddlewareByName, } from './middleware-runner.js';
|
|
26
26
|
export { addPermission } from './permissions.js';
|
|
27
|
-
export { wireHTTP, addHTTPMiddleware } from './wirings/http/http-runner.js';
|
|
28
|
-
export { wireChannel } from './wirings/channel/channel-runner.js';
|
|
29
|
-
export { wireScheduler } from './wirings/scheduler/scheduler-runner.js';
|
|
30
|
-
export { wireQueueWorker } from './wirings/queue/queue-runner.js';
|
|
31
|
-
export { wireMCPResource, wireMCPTool, wireMCPPrompt, runMCPResource, runMCPTool, runMCPPrompt, getMCPTools, getMCPResources, getMCPPrompts, getMCPResourcesMeta, getMCPToolsMeta, getMCPPromptsMeta, } from './wirings/mcp/mcp-runner.js';
|
|
32
|
-
export { wireCLI, runCLICommand } from './wirings/cli/cli-runner.js';
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import { CoreConfig, CoreSingletonServices, CoreUserSession, CorePikkuMiddleware } from '../types/core.types.js';
|
|
2
1
|
/**
|
|
3
|
-
* API key middleware that retrieves a session from the 'x-api-key' header using
|
|
2
|
+
* API key middleware that retrieves a session from the 'x-api-key' header using JWT decoding.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
4
|
+
* Extracts API key from either the 'x-api-key' header or 'apiKey' query parameter
|
|
5
|
+
* and decodes it using the JWT service.
|
|
6
|
+
*
|
|
7
|
+
* @param options.source - Where to look for the API key: 'header', 'query', or 'all'
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { authAPIKey } from '@pikku/core/middleware'
|
|
12
|
+
*
|
|
13
|
+
* addHTTPMiddleware([
|
|
14
|
+
* authAPIKey({ source: 'header' })
|
|
15
|
+
* ])
|
|
16
|
+
* ```
|
|
6
17
|
*/
|
|
7
|
-
export declare const authAPIKey: <
|
|
18
|
+
export declare const authAPIKey: import("../types/core.types.js").CorePikkuMiddlewareFactory<{
|
|
8
19
|
source: "header" | "query" | "all";
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
getSessionForAPIKey: (services: SingletonServices, apiKey: string) => Promise<any>;
|
|
14
|
-
jwt?: false;
|
|
15
|
-
})) => CorePikkuMiddleware;
|
|
20
|
+
}, import("../types/core.types.js").CoreSingletonServices<{
|
|
21
|
+
logLevel?: import("../index.js").LogLevel;
|
|
22
|
+
secrets?: {};
|
|
23
|
+
}>, import("../types/core.types.js").CoreUserSession>;
|
|
@@ -1,37 +1,37 @@
|
|
|
1
|
+
import { pikkuMiddleware, pikkuMiddlewareFactory } from '../types/core.types.js';
|
|
1
2
|
/**
|
|
2
|
-
* API key middleware that retrieves a session from the 'x-api-key' header using
|
|
3
|
+
* API key middleware that retrieves a session from the 'x-api-key' header using JWT decoding.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
+
* Extracts API key from either the 'x-api-key' header or 'apiKey' query parameter
|
|
6
|
+
* and decodes it using the JWT service.
|
|
7
|
+
*
|
|
8
|
+
* @param options.source - Where to look for the API key: 'header', 'query', or 'all'
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { authAPIKey } from '@pikku/core/middleware'
|
|
13
|
+
*
|
|
14
|
+
* addHTTPMiddleware([
|
|
15
|
+
* authAPIKey({ source: 'header' })
|
|
16
|
+
* ])
|
|
17
|
+
* ```
|
|
5
18
|
*/
|
|
6
|
-
export const authAPIKey = ({ source
|
|
7
|
-
|
|
8
|
-
const { userSession: userSessionService, jwt: jwtService } = services;
|
|
9
|
-
if (!http?.request || userSessionService.get()) {
|
|
10
|
-
return next();
|
|
11
|
-
}
|
|
12
|
-
let apiKey = null;
|
|
13
|
-
if (source === 'header' || source === 'all') {
|
|
14
|
-
apiKey = http.request.header('x-api-key');
|
|
15
|
-
}
|
|
16
|
-
if (!apiKey && (source === 'query' || source === 'all')) {
|
|
17
|
-
apiKey = http.request.query().apiKey;
|
|
18
|
-
}
|
|
19
|
-
if (apiKey) {
|
|
20
|
-
let userSession = null;
|
|
21
|
-
if (jwt) {
|
|
22
|
-
if (!jwtService) {
|
|
23
|
-
throw new Error('JWT service is required for JWT decoding.');
|
|
24
|
-
}
|
|
25
|
-
userSession = await jwtService.decode(apiKey);
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
userSession = await getSessionForAPIKey(services, apiKey);
|
|
29
|
-
}
|
|
30
|
-
if (userSession) {
|
|
31
|
-
userSessionService.setInitial(userSession);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
19
|
+
export const authAPIKey = pikkuMiddlewareFactory(({ source }) => pikkuMiddleware(async ({ userSession: userSessionService, jwt: jwtService }, { http }, next) => {
|
|
20
|
+
if (!http?.request || userSessionService.get()) {
|
|
34
21
|
return next();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
22
|
+
}
|
|
23
|
+
let apiKey = null;
|
|
24
|
+
if (source === 'header' || source === 'all') {
|
|
25
|
+
apiKey = http.request.header('x-api-key');
|
|
26
|
+
}
|
|
27
|
+
if (!apiKey && (source === 'query' || source === 'all')) {
|
|
28
|
+
apiKey = http.request.query().apiKey;
|
|
29
|
+
}
|
|
30
|
+
if (apiKey && jwtService) {
|
|
31
|
+
const userSession = await jwtService.decode(apiKey);
|
|
32
|
+
if (userSession) {
|
|
33
|
+
userSessionService.setInitial(userSession);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return next();
|
|
37
|
+
}));
|
|
@@ -1,12 +1,39 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CoreUserSession } from '../types/core.types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Bearer token middleware that extracts and validates tokens from the Authorization header.
|
|
4
|
+
*
|
|
5
|
+
* Supports two modes:
|
|
6
|
+
* - JWT decoding (default): Decodes bearer tokens using the JWT service
|
|
7
|
+
* - Static token: Provide a `token` object with a value and userSession for simple token validation
|
|
8
|
+
*
|
|
9
|
+
* @param options.token - Optional static token configuration { value: string, userSession: CoreUserSession }
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { authBearer } from '@pikku/core/middleware'
|
|
14
|
+
*
|
|
15
|
+
* // JWT mode (default)
|
|
16
|
+
* addHTTPMiddleware('*', [
|
|
17
|
+
* authBearer()
|
|
18
|
+
* ])
|
|
19
|
+
*
|
|
20
|
+
* // Static token mode
|
|
21
|
+
* addHTTPMiddleware('*', [
|
|
22
|
+
* authBearer({
|
|
23
|
+
* token: {
|
|
24
|
+
* value: process.env.API_TOKEN,
|
|
25
|
+
* userSession: { userId: 'system', role: 'admin' }
|
|
26
|
+
* }
|
|
27
|
+
* })
|
|
28
|
+
* ])
|
|
29
|
+
* ```
|
|
4
30
|
*/
|
|
5
|
-
export declare const authBearer: <
|
|
31
|
+
export declare const authBearer: import("../types/core.types.js").CorePikkuMiddlewareFactory<{
|
|
6
32
|
token?: {
|
|
7
33
|
value: string;
|
|
8
|
-
userSession:
|
|
34
|
+
userSession: CoreUserSession;
|
|
9
35
|
};
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
36
|
+
}, import("../types/core.types.js").CoreSingletonServices<{
|
|
37
|
+
logLevel?: import("../index.js").LogLevel;
|
|
38
|
+
secrets?: {};
|
|
39
|
+
}>, CoreUserSession>;
|
|
@@ -1,41 +1,58 @@
|
|
|
1
1
|
import { InvalidSessionError } from '../errors/errors.js';
|
|
2
|
+
import { pikkuMiddleware, pikkuMiddlewareFactory, } from '../types/core.types.js';
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
+
* Bearer token middleware that extracts and validates tokens from the Authorization header.
|
|
5
|
+
*
|
|
6
|
+
* Supports two modes:
|
|
7
|
+
* - JWT decoding (default): Decodes bearer tokens using the JWT service
|
|
8
|
+
* - Static token: Provide a `token` object with a value and userSession for simple token validation
|
|
9
|
+
*
|
|
10
|
+
* @param options.token - Optional static token configuration { value: string, userSession: CoreUserSession }
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { authBearer } from '@pikku/core/middleware'
|
|
15
|
+
*
|
|
16
|
+
* // JWT mode (default)
|
|
17
|
+
* addHTTPMiddleware('*', [
|
|
18
|
+
* authBearer()
|
|
19
|
+
* ])
|
|
20
|
+
*
|
|
21
|
+
* // Static token mode
|
|
22
|
+
* addHTTPMiddleware('*', [
|
|
23
|
+
* authBearer({
|
|
24
|
+
* token: {
|
|
25
|
+
* value: process.env.API_TOKEN,
|
|
26
|
+
* userSession: { userId: 'system', role: 'admin' }
|
|
27
|
+
* }
|
|
28
|
+
* })
|
|
29
|
+
* ])
|
|
30
|
+
* ```
|
|
4
31
|
*/
|
|
5
|
-
export const authBearer = ({ token, jwt
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
32
|
+
export const authBearer = pikkuMiddlewareFactory(({ token } = {}) => pikkuMiddleware(async ({ userSession: userSessionService, jwt: jwtService }, { http }, next) => {
|
|
33
|
+
// Skip if session already exists.
|
|
34
|
+
if (!http?.request || userSessionService.get()) {
|
|
35
|
+
return next();
|
|
36
|
+
}
|
|
37
|
+
const authHeader = http.request.header('authorization') ||
|
|
38
|
+
http.request.header('Authorization');
|
|
39
|
+
if (authHeader) {
|
|
40
|
+
const [scheme, bearerToken] = authHeader.split(' ');
|
|
41
|
+
if (scheme !== 'Bearer' || !bearerToken) {
|
|
42
|
+
throw new InvalidSessionError();
|
|
11
43
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
if (scheme !== 'Bearer' || !token || !bearerToken) {
|
|
17
|
-
throw new InvalidSessionError();
|
|
18
|
-
}
|
|
19
|
-
let userSession = null;
|
|
20
|
-
if (jwt) {
|
|
21
|
-
if (!jwtService) {
|
|
22
|
-
throw new Error('JWT service is required for JWT decoding.');
|
|
23
|
-
}
|
|
24
|
-
userSession = await jwtService.decode(bearerToken);
|
|
25
|
-
}
|
|
26
|
-
else if (token) {
|
|
27
|
-
if (bearerToken === token.value) {
|
|
28
|
-
userSession = token.userSession;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
else if (getSession) {
|
|
32
|
-
userSession = await getSession(services, token);
|
|
33
|
-
}
|
|
34
|
-
if (userSession) {
|
|
35
|
-
userSessionService.setInitial(userSession);
|
|
36
|
-
}
|
|
44
|
+
let userSession = null;
|
|
45
|
+
// If static token provided, validate against it
|
|
46
|
+
if (token && bearerToken === token.value) {
|
|
47
|
+
userSession = token.userSession;
|
|
37
48
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
49
|
+
// Otherwise, default to JWT decoding
|
|
50
|
+
else if (jwtService && !token) {
|
|
51
|
+
userSession = await jwtService.decode(bearerToken);
|
|
52
|
+
}
|
|
53
|
+
if (userSession) {
|
|
54
|
+
userSessionService.setInitial(userSession);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return next();
|
|
58
|
+
}));
|
|
@@ -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>;
|