@pikku/core 0.9.12-next.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/errors/errors.d.ts +2 -0
  3. package/dist/errors/errors.js +6 -0
  4. package/dist/function/function-runner.d.ts +5 -4
  5. package/dist/function/function-runner.js +10 -4
  6. package/dist/function/functions.types.d.ts +67 -1
  7. package/dist/function/functions.types.js +43 -1
  8. package/dist/index.d.ts +1 -7
  9. package/dist/index.js +1 -7
  10. package/dist/middleware/auth-apikey.d.ts +19 -11
  11. package/dist/middleware/auth-apikey.js +33 -33
  12. package/dist/middleware/auth-bearer.d.ts +34 -7
  13. package/dist/middleware/auth-bearer.js +53 -36
  14. package/dist/middleware/auth-cookie.d.ts +30 -12
  15. package/dist/middleware/auth-cookie.js +51 -43
  16. package/dist/middleware/timeout.d.ts +6 -2
  17. package/dist/middleware/timeout.js +7 -9
  18. package/dist/middleware-runner.d.ts +0 -18
  19. package/dist/middleware-runner.js +0 -21
  20. package/dist/permissions.d.ts +82 -20
  21. package/dist/permissions.js +175 -62
  22. package/dist/pikku-state.d.ts +22 -2
  23. package/dist/pikku-state.js +7 -1
  24. package/dist/types/core.types.d.ts +58 -1
  25. package/dist/types/core.types.js +23 -1
  26. package/dist/utils.d.ts +1 -1
  27. package/dist/wirings/channel/channel-handler.js +6 -5
  28. package/dist/wirings/channel/channel-runner.d.ts +3 -1
  29. package/dist/wirings/channel/channel-runner.js +4 -21
  30. package/dist/wirings/channel/channel.types.d.ts +12 -13
  31. package/dist/wirings/cli/channel/cli-channel-runner.js +5 -2
  32. package/dist/wirings/cli/cli-runner.d.ts +10 -0
  33. package/dist/wirings/cli/cli-runner.js +44 -20
  34. package/dist/wirings/cli/cli.types.d.ts +54 -27
  35. package/dist/wirings/cli/command-parser.js +34 -4
  36. package/dist/wirings/cli/index.d.ts +1 -1
  37. package/dist/wirings/cli/index.js +1 -1
  38. package/dist/wirings/http/http-runner.d.ts +31 -1
  39. package/dist/wirings/http/http-runner.js +36 -1
  40. package/dist/wirings/http/http.types.d.ts +2 -1
  41. package/dist/wirings/http/index.d.ts +1 -1
  42. package/dist/wirings/http/index.js +1 -1
  43. package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
  44. package/dist/wirings/mcp/mcp-runner.js +2 -0
  45. package/dist/wirings/mcp/mcp.types.d.ts +35 -14
  46. package/dist/wirings/queue/queue-runner.js +1 -0
  47. package/dist/wirings/scheduler/scheduler-runner.js +1 -0
  48. package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
  49. package/package.json +6 -5
  50. package/src/errors/errors.ts +6 -0
  51. package/src/factory-functions.test.ts +60 -1
  52. package/src/function/function-runner.test.ts +8 -3
  53. package/src/function/function-runner.ts +18 -5
  54. package/src/function/functions.types.ts +85 -2
  55. package/src/index.ts +1 -21
  56. package/src/middleware/auth-apikey.ts +42 -57
  57. package/src/middleware/auth-bearer.ts +66 -49
  58. package/src/middleware/auth-cookie.ts +63 -82
  59. package/src/middleware/timeout.ts +10 -14
  60. package/src/middleware-runner.ts +0 -25
  61. package/src/permissions.test.ts +26 -27
  62. package/src/permissions.ts +215 -104
  63. package/src/pikku-state.ts +35 -3
  64. package/src/types/core.types.ts +70 -3
  65. package/src/utils.ts +1 -1
  66. package/src/wirings/channel/channel-handler.ts +11 -10
  67. package/src/wirings/channel/channel-runner.ts +18 -27
  68. package/src/wirings/channel/channel.types.ts +24 -15
  69. package/src/wirings/cli/channel/cli-channel-runner.ts +8 -3
  70. package/src/wirings/cli/cli-runner.test.ts +80 -59
  71. package/src/wirings/cli/cli-runner.ts +57 -21
  72. package/src/wirings/cli/cli.types.ts +74 -44
  73. package/src/wirings/cli/command-parser.test.ts +91 -86
  74. package/src/wirings/cli/command-parser.ts +38 -4
  75. package/src/wirings/cli/index.ts +1 -0
  76. package/src/wirings/http/http-runner.ts +41 -1
  77. package/src/wirings/http/http.types.ts +3 -1
  78. package/src/wirings/http/index.ts +7 -1
  79. package/src/wirings/mcp/mcp-endpoint-registry.ts +1 -1
  80. package/src/wirings/mcp/mcp-runner.ts +2 -0
  81. package/src/wirings/mcp/mcp.types.ts +48 -12
  82. package/src/wirings/queue/queue-runner.ts +1 -0
  83. package/src/wirings/scheduler/scheduler-runner.ts +1 -0
  84. package/src/wirings/scheduler/scheduler.types.ts +2 -2
  85. package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
+ # @pikku/core
2
+
3
+ ## 0.10.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 778267e: fix: fixing inspector ensuring pikkuConfig is set
8
+
1
9
  ## 0.9.0
2
10
 
11
+ ## 0.10.0
12
+
13
+ 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.
14
+
15
+ For complete details, see https://pikku.dev/changelogs/0_10_0.md
16
+
3
17
  ## 0.9.12-next.0
4
18
 
5
19
  ### Patch Changes
@@ -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
@@ -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, permissions: wiringPermissions, inheritedMiddleware, wireMiddleware, coerceDataFromSchema, tags, interaction, }: {
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, permissions: wiringPermissions, inheritedMiddleware, wireMiddleware, coerceDataFromSchema, tags = [], interaction, }) => {
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
- wiringTags: tags,
55
- wiringPermissions,
56
- funcTags: funcConfig.tags,
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 pikkuPermission: <In = any, Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession>(permission: CorePikkuPermission<In, Services, Session>) => CorePikkuPermission<In, Services, Session>;
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, registerMiddleware, getMiddlewareByName, addMiddleware, } from './middleware-runner.js';
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, registerMiddleware, getMiddlewareByName, addMiddleware, } from './middleware-runner.js';
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 a provided callback.
2
+ * API key middleware that retrieves a session from the 'x-api-key' header using JWT decoding.
4
3
  *
5
- * @param options.getSessionForAPIKey - A function that returns a session when provided an API key.
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: <SingletonServices extends CoreSingletonServices<CoreConfig>, UserSession extends CoreUserSession>({ source, getSessionForAPIKey, jwt, }: {
18
+ export declare const authAPIKey: import("../types/core.types.js").CorePikkuMiddlewareFactory<{
8
19
  source: "header" | "query" | "all";
9
- } & ({
10
- getSessionForAPIKey?: undefined;
11
- jwt?: true;
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 a provided callback.
3
+ * API key middleware that retrieves a session from the 'x-api-key' header using JWT decoding.
3
4
  *
4
- * @param options.getSessionForAPIKey - A function that returns a session when provided an API key.
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, getSessionForAPIKey, jwt, }) => {
7
- const middleware = async (services, { http }, next) => {
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
- return middleware;
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 { CoreConfig, CoreSingletonServices, CoreUserSession, CorePikkuMiddleware } from '../types/core.types.js';
1
+ import { CoreUserSession } from '../types/core.types.js';
2
2
  /**
3
- * Extracts the Bearer token from the Authorization header
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: <SingletonServices extends CoreSingletonServices<CoreConfig>, UserSession extends CoreUserSession>({ token, jwt, getSession, }?: {
31
+ export declare const authBearer: import("../types/core.types.js").CorePikkuMiddlewareFactory<{
6
32
  token?: {
7
33
  value: string;
8
- userSession: UserSession;
34
+ userSession: CoreUserSession;
9
35
  };
10
- jwt?: boolean;
11
- getSession?: (services: SingletonServices, token: string) => Promise<UserSession> | UserSession;
12
- }) => CorePikkuMiddleware;
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
- * Extracts the Bearer token from the Authorization header
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, getSession, } = {}) => {
6
- const middleware = async (services, { http }, next) => {
7
- const { userSession: userSessionService, jwt: jwtService } = services;
8
- // Skip if session already exists.
9
- if (!http?.request || userSessionService.get()) {
10
- return next();
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
- const authHeader = http.request.header('authorization') ||
13
- http.request.header('Authorization');
14
- if (authHeader) {
15
- const [scheme, bearerToken] = authHeader.split(' ');
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
- return next();
39
- };
40
- return middleware;
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 extracts a session from cookies.
4
+ * Cookie-based session middleware that uses JWT for encoding/decoding session data.
6
5
  *
7
- * @param options.name - List of cookie names to check.
8
- * @param options.getSessionForCookieValue - Function to retrieve a session using a cookie value.
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: <SingletonServices extends CoreSingletonServices<CoreConfig>, UserSession extends CoreUserSession>({ name, getSessionForCookieValue, jwt, options, expiresIn, }: {
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
- getSessionForCookieValue: (services: SingletonServices, cookieValue: string, cookieName: string) => Promise<UserSession>;
16
- jwt?: false;
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>;