@pikku/core 0.6.16 → 0.6.17

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 (92) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/channel/channel-handler.js +2 -2
  3. package/dist/channel/channel-runner.d.ts +2 -14
  4. package/dist/channel/channel-runner.js +5 -36
  5. package/dist/channel/channel-store.d.ts +9 -6
  6. package/dist/channel/index.d.ts +0 -1
  7. package/dist/channel/index.js +0 -1
  8. package/dist/channel/local/local-channel-runner.js +2 -2
  9. package/dist/channel/log-channels.js +2 -2
  10. package/dist/channel/serverless/serverless-channel-runner.js +8 -7
  11. package/dist/errors/error-handler.d.ts +1 -1
  12. package/dist/errors/error-handler.js +6 -14
  13. package/dist/errors/errors.d.ts +1 -1
  14. package/dist/errors/errors.js +2 -2
  15. package/dist/http/http-route-runner.d.ts +3 -23
  16. package/dist/http/http-route-runner.js +13 -82
  17. package/dist/http/index.d.ts +1 -1
  18. package/dist/http/index.js +1 -1
  19. package/dist/http/log-http-routes.js +2 -2
  20. package/dist/index.d.ts +1 -0
  21. package/dist/index.js +1 -0
  22. package/dist/middleware/auth-apikey.d.ts +15 -0
  23. package/dist/middleware/auth-apikey.js +36 -0
  24. package/dist/middleware/auth-bearer.d.ts +12 -0
  25. package/dist/middleware/auth-bearer.js +40 -0
  26. package/dist/middleware/auth-cookie.d.ts +16 -0
  27. package/dist/middleware/auth-cookie.js +43 -0
  28. package/dist/middleware/index.d.ts +3 -4
  29. package/dist/middleware/index.js +3 -4
  30. package/dist/middleware/timeout.d.ts +2 -0
  31. package/dist/middleware/timeout.js +10 -0
  32. package/dist/middleware-runner.d.ts +1 -1
  33. package/dist/pikku-state.d.ts +29 -0
  34. package/dist/pikku-state.js +30 -0
  35. package/dist/scheduler/index.d.ts +1 -1
  36. package/dist/scheduler/index.js +1 -1
  37. package/dist/scheduler/log-schedulers.js +2 -2
  38. package/dist/scheduler/scheduler-runner.d.ts +1 -11
  39. package/dist/scheduler/scheduler-runner.js +5 -33
  40. package/dist/schema.js +2 -2
  41. package/dist/services/jwt-service.d.ts +1 -10
  42. package/dist/services/user-session-service.d.ts +2 -2
  43. package/dist/services/user-session-service.js +6 -6
  44. package/dist/types/core.types.d.ts +3 -3
  45. package/lcov.info +814 -907
  46. package/package.json +2 -1
  47. package/src/channel/channel-handler.ts +2 -2
  48. package/src/channel/channel-runner.ts +4 -43
  49. package/src/channel/channel-store.ts +8 -11
  50. package/src/channel/index.ts +0 -1
  51. package/src/channel/local/local-channel-runner.test.ts +10 -20
  52. package/src/channel/local/local-channel-runner.ts +2 -2
  53. package/src/channel/log-channels.ts +2 -2
  54. package/src/channel/serverless/serverless-channel-runner.ts +10 -9
  55. package/src/errors/error-handler.ts +7 -18
  56. package/src/errors/errors.ts +2 -3
  57. package/src/handle-error.ts +0 -1
  58. package/src/http/http-route-runner.test.ts +3 -2
  59. package/src/http/http-route-runner.ts +18 -99
  60. package/src/http/index.ts +1 -6
  61. package/src/http/log-http-routes.ts +2 -2
  62. package/src/index.ts +1 -0
  63. package/src/middleware/auth-apikey.ts +65 -0
  64. package/src/middleware/auth-bearer.ts +65 -0
  65. package/src/middleware/auth-cookie.ts +76 -0
  66. package/src/middleware/index.ts +3 -4
  67. package/src/middleware/timeout.ts +13 -0
  68. package/src/middleware-runner.ts +1 -1
  69. package/src/pikku-state.ts +70 -0
  70. package/src/scheduler/index.ts +1 -7
  71. package/src/scheduler/log-schedulers.ts +2 -2
  72. package/src/scheduler/scheduler-runner.ts +6 -45
  73. package/src/schema.ts +2 -2
  74. package/src/services/jwt-service.ts +1 -12
  75. package/src/services/user-session-service.ts +8 -6
  76. package/src/types/core.types.ts +3 -6
  77. package/tsconfig.tsbuildinfo +1 -1
  78. package/dist/channel/eventhub-forwarder.d.ts +0 -17
  79. package/dist/channel/eventhub-forwarder.js +0 -1
  80. package/dist/middleware/auth-api-key.d.ts +0 -9
  81. package/dist/middleware/auth-api-key.js +0 -23
  82. package/dist/middleware/auth-cookie-middleware.d.ts +0 -11
  83. package/dist/middleware/auth-cookie-middleware.js +0 -36
  84. package/dist/middleware/auth-jwt-middleware.d.ts +0 -10
  85. package/dist/middleware/auth-jwt-middleware.js +0 -32
  86. package/dist/middleware/auth-query-middleware.d.ts +0 -10
  87. package/dist/middleware/auth-query-middleware.js +0 -21
  88. package/src/channel/eventhub-forwarder.ts +0 -25
  89. package/src/middleware/auth-api-key.ts +0 -32
  90. package/src/middleware/auth-cookie-middleware.ts +0 -54
  91. package/src/middleware/auth-jwt-middleware.ts +0 -47
  92. package/src/middleware/auth-query-middleware.ts +0 -33
@@ -0,0 +1,40 @@
1
+ import { InvalidSessionError } from '../errors/errors.js';
2
+ /**
3
+ * Extracts the Bearer token from the Authorization header
4
+ */
5
+ export const authBearer = ({ token, jwt, getSession, } = {}) => {
6
+ const middleware = async (services, { http }, next) => {
7
+ // Skip if session already exists.
8
+ if (!http?.request || services.userSession.get()) {
9
+ return next();
10
+ }
11
+ const authHeader = http.request.getHeader('authorization') ||
12
+ http.request.getHeader('Authorization');
13
+ if (authHeader) {
14
+ const [scheme, bearerToken] = authHeader.split(' ');
15
+ if (scheme !== 'Bearer' || !token || !bearerToken) {
16
+ throw new InvalidSessionError();
17
+ }
18
+ let userSession = null;
19
+ if (jwt) {
20
+ if (!services.jwt) {
21
+ throw new Error('JWT service is required for JWT decoding.');
22
+ }
23
+ userSession = await services.jwt.decode(bearerToken);
24
+ }
25
+ else if (token) {
26
+ if (bearerToken === token.value) {
27
+ userSession = token.userSession;
28
+ }
29
+ }
30
+ else if (getSession) {
31
+ userSession = await getSession(services, token);
32
+ }
33
+ if (userSession) {
34
+ await services.userSession.set(userSession);
35
+ }
36
+ }
37
+ return next();
38
+ };
39
+ return middleware;
40
+ };
@@ -0,0 +1,16 @@
1
+ import { CoreConfig, CoreSingletonServices, CoreUserSession, PikkuMiddleware } from '../types/core.types.js';
2
+ /**
3
+ * Cookie middleware that extracts a session from cookies.
4
+ *
5
+ * @param options.cookieNames - List of cookie names to check.
6
+ * @param options.getSessionForCookieValue - Function to retrieve a session using a cookie value.
7
+ */
8
+ export declare const authCookie: <SingletonServices extends CoreSingletonServices<CoreConfig>, UserSession extends CoreUserSession>({ cookieNames, getSessionForCookieValue, jwt, }: {
9
+ cookieNames: string[];
10
+ } & ({
11
+ getSessionForCookieValue: (services: SingletonServices, cookieValue: string, cookieName: string) => Promise<UserSession>;
12
+ jwt?: false;
13
+ } | {
14
+ getSessionForCookieValue?: undefined;
15
+ jwt: true;
16
+ })) => PikkuMiddleware;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Cookie middleware that extracts a session from cookies.
3
+ *
4
+ * @param options.cookieNames - List of cookie names to check.
5
+ * @param options.getSessionForCookieValue - Function to retrieve a session using a cookie value.
6
+ */
7
+ export const authCookie = ({ cookieNames, getSessionForCookieValue, jwt, }) => {
8
+ const middleware = async (services, { http }, next) => {
9
+ if (!http?.request || services.userSession.get()) {
10
+ return next();
11
+ }
12
+ const cookies = http.request.getCookies();
13
+ if (cookies) {
14
+ let cookieName;
15
+ for (const name of cookieNames) {
16
+ if (cookies[name]) {
17
+ cookieName = name;
18
+ break;
19
+ }
20
+ }
21
+ if (cookieName) {
22
+ let userSession = null;
23
+ const cookieValue = cookies[cookieName];
24
+ if (cookieValue) {
25
+ if (jwt) {
26
+ if (!services.jwt) {
27
+ throw new Error('JWT service is required for JWT decoding.');
28
+ }
29
+ userSession = await services.jwt.decode(cookieValue);
30
+ }
31
+ else if (getSessionForCookieValue) {
32
+ userSession = await getSessionForCookieValue(services, cookieValue, cookieName);
33
+ }
34
+ if (userSession) {
35
+ await services.userSession.set(userSession);
36
+ }
37
+ }
38
+ }
39
+ }
40
+ return next();
41
+ };
42
+ return middleware;
43
+ };
@@ -1,4 +1,3 @@
1
- export * from './auth-api-key.js';
2
- export * from './auth-cookie-middleware.js';
3
- export * from './auth-jwt-middleware.js';
4
- export * from './auth-query-middleware.js';
1
+ export * from './auth-apikey.js';
2
+ export * from './auth-cookie.js';
3
+ export * from './auth-bearer.js';
@@ -1,4 +1,3 @@
1
- export * from './auth-api-key.js';
2
- export * from './auth-cookie-middleware.js';
3
- export * from './auth-jwt-middleware.js';
4
- export * from './auth-query-middleware.js';
1
+ export * from './auth-apikey.js';
2
+ export * from './auth-cookie.js';
3
+ export * from './auth-bearer.js';
@@ -0,0 +1,2 @@
1
+ import { PikkuMiddleware } from '../types/core.types.js';
2
+ export declare const timeout: (timeout: number) => PikkuMiddleware;
@@ -0,0 +1,10 @@
1
+ import { RequestTimeoutError } from '../errors/errors.js';
2
+ export const timeout = (timeout) => {
3
+ const middleware = async (_services, _interaction, next) => {
4
+ setTimeout(() => {
5
+ throw new RequestTimeoutError();
6
+ }, timeout);
7
+ await next();
8
+ };
9
+ return middleware;
10
+ };
@@ -18,5 +18,5 @@ import { CoreSingletonServices, PikkuInteraction, PikkuMiddleware } from './type
18
18
  * );
19
19
  */
20
20
  export declare const runMiddleware: (services: CoreSingletonServices & {
21
- userSessionService: UserSessionService<any>;
21
+ userSession: UserSessionService<any>;
22
22
  }, interaction: PikkuInteraction, middlewares: PikkuMiddleware[], main?: () => Promise<void>) => Promise<void>;
@@ -0,0 +1,29 @@
1
+ import { ChannelsMeta, CoreAPIChannels } from './channel/channel.types.js';
2
+ import { CoreHTTPFunctionRoutes, HTTPRoutesMeta } from './http/http-routes.types.js';
3
+ import { PikkuMiddleware } from './types/core.types.js';
4
+ import { CoreScheduledTask, ScheduledTasksMeta } from './scheduler/scheduler.types.js';
5
+ import { ErrorDetails, PikkuError } from './errors/error-handler.js';
6
+ interface PikkuState {
7
+ http: {
8
+ middleware: Array<{
9
+ route: string;
10
+ middleware: PikkuMiddleware[];
11
+ }>;
12
+ routes: CoreHTTPFunctionRoutes;
13
+ meta: HTTPRoutesMeta;
14
+ };
15
+ channel: {
16
+ channels: CoreAPIChannels;
17
+ meta: ChannelsMeta;
18
+ };
19
+ scheduler: {
20
+ tasks: Map<string, CoreScheduledTask>;
21
+ meta: ScheduledTasksMeta;
22
+ };
23
+ errors: {
24
+ errors: Map<PikkuError, ErrorDetails>;
25
+ };
26
+ }
27
+ export declare const resetPikkuState: () => void;
28
+ export declare const pikkuState: <Type extends keyof PikkuState, Content extends keyof PikkuState[Type]>(type: Type, content: Content, value?: PikkuState[Type][Content]) => PikkuState[Type][Content];
29
+ export {};
@@ -0,0 +1,30 @@
1
+ export const resetPikkuState = () => {
2
+ globalThis.pikkuState = {
3
+ http: {
4
+ middleware: [],
5
+ routes: [],
6
+ meta: [],
7
+ },
8
+ channel: {
9
+ channels: [],
10
+ meta: [],
11
+ },
12
+ scheduler: {
13
+ tasks: new Map(),
14
+ meta: [],
15
+ },
16
+ errors: {
17
+ // We keep errors since they are registered globally
18
+ errors: globalThis.pikkuState?.errors?.errors || new Map(),
19
+ },
20
+ };
21
+ };
22
+ if (!globalThis.pikkuState) {
23
+ resetPikkuState();
24
+ }
25
+ export const pikkuState = (type, content, value) => {
26
+ if (value) {
27
+ globalThis.pikkuState[type][content] = value;
28
+ }
29
+ return globalThis.pikkuState[type][content];
30
+ };
@@ -1,3 +1,3 @@
1
1
  export * from './scheduler.types.js';
2
- export { runScheduledTask, getScheduledTasks, addScheduledTask, clearScheduledTasks, setScheduledTasksMeta, } from './scheduler-runner.js';
2
+ export { runScheduledTask, addScheduledTask } from './scheduler-runner.js';
3
3
  export * from './log-schedulers.js';
@@ -1,3 +1,3 @@
1
1
  export * from './scheduler.types.js';
2
- export { runScheduledTask, getScheduledTasks, addScheduledTask, clearScheduledTasks, setScheduledTasksMeta, } from './scheduler-runner.js';
2
+ export { runScheduledTask, addScheduledTask } from './scheduler-runner.js';
3
3
  export * from './log-schedulers.js';
@@ -1,10 +1,10 @@
1
- import { getScheduledTasks } from './scheduler-runner.js';
1
+ import { pikkuState } from '../pikku-state.js';
2
2
  /**
3
3
  * Logs all the loaded scheduled tasks.
4
4
  * @param logger - A logger for logging information.
5
5
  */
6
6
  export const logSchedulers = (logger) => {
7
- const { scheduledTasks } = getScheduledTasks();
7
+ const scheduledTasks = pikkuState('scheduler', 'tasks');
8
8
  if (scheduledTasks.size === 0) {
9
9
  logger.info('No scheduled tasks added');
10
10
  return;
@@ -1,5 +1,5 @@
1
1
  import type { CoreServices, CoreSingletonServices, CoreUserSession, CreateSessionServices } from '../types/core.types.js';
2
- import type { CoreScheduledTask, ScheduledTasksMeta } from './scheduler.types.js';
2
+ import type { CoreScheduledTask } from './scheduler.types.js';
3
3
  import type { CoreAPIFunctionSessionless } from '../types/functions.types.js';
4
4
  export type RunScheduledTasksParams = {
5
5
  name: string;
@@ -8,14 +8,4 @@ export type RunScheduledTasksParams = {
8
8
  createSessionServices?: CreateSessionServices<CoreSingletonServices, CoreServices<CoreSingletonServices>, CoreUserSession>;
9
9
  };
10
10
  export declare const addScheduledTask: <APIFunction extends CoreAPIFunctionSessionless<void, void>>(scheduledTask: CoreScheduledTask<APIFunction>) => void;
11
- export declare const clearScheduledTasks: () => void;
12
- export declare const setScheduledTasksMeta: (_scheduledTasksMeta: ScheduledTasksMeta) => void;
13
- /**
14
- * Returns all the cron jobs
15
- * @internal
16
- */
17
- export declare const getScheduledTasks: () => {
18
- scheduledTasks: Map<string, CoreScheduledTask>;
19
- scheduledTasksMeta: any;
20
- };
21
11
  export declare function runScheduledTask<SingletonServices extends CoreSingletonServices = CoreSingletonServices, UserSession extends CoreUserSession = CoreUserSession, Services extends CoreServices<SingletonServices> = CoreServices<SingletonServices>>({ name, session, singletonServices, createSessionServices, }: RunScheduledTasksParams): Promise<void>;
@@ -1,41 +1,13 @@
1
1
  import crypto from 'crypto';
2
2
  import { getErrorResponse } from '../errors/error-handler.js';
3
3
  import { closeSessionServices } from '../utils.js';
4
- if (!global.pikku?.scheduledTasks) {
5
- global.pikku = global.pikku || {};
6
- global.pikku.scheduledTasks = new Map();
7
- global.pikku.scheduledTasksMeta = [];
8
- }
9
- const scheduledTasks = () => {
10
- return global.pikku.scheduledTasks;
11
- };
12
- const scheduledTasksMeta = (data) => {
13
- if (data) {
14
- global.pikku.scheduledTasksMeta = data;
15
- }
16
- return global.pikku.scheduledTasksMeta;
17
- };
4
+ import { pikkuState } from '../pikku-state.js';
18
5
  export const addScheduledTask = (scheduledTask) => {
19
- if (scheduledTasks().has(scheduledTask.name)) {
6
+ const tasks = pikkuState('scheduler', 'tasks');
7
+ if (tasks.has(scheduledTask.name)) {
20
8
  throw new Error(`Scheduled task already exists: ${scheduledTask.name}`);
21
9
  }
22
- scheduledTasks().set(scheduledTask.name, scheduledTask);
23
- };
24
- export const clearScheduledTasks = () => {
25
- scheduledTasks().clear();
26
- };
27
- export const setScheduledTasksMeta = (_scheduledTasksMeta) => {
28
- scheduledTasksMeta(_scheduledTasksMeta);
29
- };
30
- /**
31
- * Returns all the cron jobs
32
- * @internal
33
- */
34
- export const getScheduledTasks = () => {
35
- return {
36
- scheduledTasks: scheduledTasks(),
37
- scheduledTasksMeta: scheduledTasksMeta(),
38
- };
10
+ tasks.set(scheduledTask.name, scheduledTask);
39
11
  };
40
12
  class ScheduledTaskNotFoundError extends Error {
41
13
  constructor(title) {
@@ -46,7 +18,7 @@ export async function runScheduledTask({ name, session, singletonServices, creat
46
18
  let sessionServices;
47
19
  const trackerId = crypto.randomUUID().toString();
48
20
  try {
49
- const task = scheduledTasks().get(name);
21
+ const task = pikkuState('scheduler', 'tasks').get(name);
50
22
  if (!task) {
51
23
  throw new ScheduledTaskNotFoundError(`Scheduled task not found: ${name}`);
52
24
  }
package/dist/schema.js CHANGED
@@ -1,5 +1,5 @@
1
- import { getRoutes } from './http/http-route-runner.js';
2
1
  import { UnprocessableContentError } from './errors/errors.js';
2
+ import { pikkuState } from './pikku-state.js';
3
3
  /**
4
4
  * Retrieves the global schemas map.
5
5
  * @returns A map of schemas.
@@ -45,7 +45,7 @@ export const compileAllSchemas = (logger, schemaService) => {
45
45
  validateAllSchemasLoaded(logger, schemaService);
46
46
  };
47
47
  const validateAllSchemasLoaded = (logger, schemaService) => {
48
- const { routesMeta } = getRoutes();
48
+ const routesMeta = pikkuState('http', 'meta');
49
49
  const validators = schemaService.getSchemaNames();
50
50
  const missingSchemas = [];
51
51
  for (const route of routesMeta) {
@@ -1,9 +1,7 @@
1
- import { CoreUserSession } from '../types/core.types.js';
2
1
  /**
3
2
  * Interface for handling JSON Web Tokens (JWT).
4
- * @template UserSession - The type of the user session.
5
3
  */
6
- export interface JWTService<UserSession = CoreUserSession> {
4
+ export interface JWTService {
7
5
  /**
8
6
  * Encodes a payload into a JWT.
9
7
  * @param expiresIn - The expiration time of the token.
@@ -19,11 +17,4 @@ export interface JWTService<UserSession = CoreUserSession> {
19
17
  * @returns A promise that resolves to the decoded payload.
20
18
  */
21
19
  decode: <T>(hash: string, invalidHashError?: Error, debug?: boolean) => Promise<T>;
22
- /**
23
- * Decodes a user session from a JWT.
24
- * @param jwtToken - The JWT representing the user session.
25
- * @param debug - An optional flag for debugging.
26
- * @returns A promise that resolves to the decoded user session.
27
- */
28
- decodeSession: (jwtToken: string, debug?: any) => Promise<UserSession>;
29
20
  }
@@ -17,7 +17,7 @@ export declare class RemoteUserSessionService<UserSession extends CoreUserSessio
17
17
  private channelId;
18
18
  session: UserSession | undefined;
19
19
  constructor(channelStore: ChannelStore<unknown, unknown, UserSession>, channelId: string, session?: UserSession | undefined);
20
- set(session: UserSession): Promise<void>;
21
- clear(): Promise<void>;
20
+ set(session: UserSession): void | Promise<void>;
21
+ clear(): void | Promise<void>;
22
22
  get(): Promise<UserSession | undefined>;
23
23
  }
@@ -22,14 +22,14 @@ export class RemoteUserSessionService {
22
22
  this.channelId = channelId;
23
23
  this.session = session;
24
24
  }
25
- async set(session) {
26
- await this.channelStore.setUserSession(this.channelId, session);
25
+ set(session) {
26
+ return this.channelStore.setUserSession(this.channelId, session);
27
27
  }
28
- async clear() {
29
- await this.channelStore.setUserSession(this.channelId, undefined);
28
+ clear() {
29
+ return this.channelStore.setUserSession(this.channelId, null);
30
30
  }
31
31
  async get() {
32
- const channel = await this.channelStore.getChannel(this.channelId);
33
- return channel.userSession;
32
+ const { session } = await this.channelStore.getChannelAndSession(this.channelId);
33
+ return session;
34
34
  }
35
35
  }
@@ -48,9 +48,9 @@ export interface CoreUserSession {
48
48
  /**
49
49
  * Interface for core singleton services provided by Pikku.
50
50
  */
51
- export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig, UserSession extends CoreUserSession = CoreUserSession> {
51
+ export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
52
52
  /** JWT Service */
53
- jwt?: JWTService<UserSession>;
53
+ jwt?: JWTService;
54
54
  /** The schema library used to validate data */
55
55
  schemaService?: SchemaService;
56
56
  /** The core configuration for the application. */
@@ -74,7 +74,7 @@ export interface PikkuInteraction {
74
74
  * A function that can wrap an interaction and be called before or after
75
75
  */
76
76
  export type PikkuMiddleware<SingletonServices extends CoreSingletonServices = CoreSingletonServices, UserSession extends CoreUserSession = CoreUserSession> = (services: SingletonServices & {
77
- userSessionService: UserSessionService<UserSession>;
77
+ userSession: UserSessionService<UserSession>;
78
78
  }, interactions: PikkuInteraction, next: () => Promise<void>) => Promise<void>;
79
79
  /**
80
80
  * Represents the core services used by Pikku, including singleton services and the request/response interaction.