@pikku/core 0.6.20 → 0.6.22

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 (62) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/channel/channel-handler.d.ts +2 -2
  3. package/dist/channel/channel-handler.js +49 -26
  4. package/dist/channel/channel-runner.d.ts +3 -3
  5. package/dist/channel/channel-runner.js +4 -4
  6. package/dist/channel/channel.types.d.ts +12 -19
  7. package/dist/channel/local/local-channel-runner.d.ts +1 -1
  8. package/dist/channel/local/local-channel-runner.js +14 -8
  9. package/dist/channel/serverless/serverless-channel-runner.js +12 -7
  10. package/dist/handle-error.js +8 -6
  11. package/dist/http/http-route-runner.d.ts +75 -18
  12. package/dist/http/http-route-runner.js +159 -64
  13. package/dist/http/http-routes.types.d.ts +24 -9
  14. package/dist/http/incomingmessage-to-request-convertor.d.ts +1 -0
  15. package/dist/http/incomingmessage-to-request-convertor.js +1 -0
  16. package/dist/http/index.d.ts +4 -3
  17. package/dist/http/index.js +4 -3
  18. package/dist/http/{pikku-http-abstract-request.d.ts → pikku-fetch-http-request.d.ts} +14 -20
  19. package/dist/http/pikku-fetch-http-request.js +92 -0
  20. package/dist/http/pikku-fetch-http-response.d.ts +14 -0
  21. package/dist/http/pikku-fetch-http-response.js +59 -0
  22. package/dist/middleware/auth-apikey.js +4 -4
  23. package/dist/middleware/auth-bearer.js +4 -4
  24. package/dist/middleware/auth-cookie.js +16 -25
  25. package/dist/middleware-runner.d.ts +1 -1
  26. package/dist/pikku-request.d.ts +3 -3
  27. package/dist/pikku-request.js +5 -5
  28. package/dist/scheduler/scheduler-runner.d.ts +1 -1
  29. package/dist/services/user-session-service.d.ts +9 -14
  30. package/dist/services/user-session-service.js +22 -22
  31. package/dist/types/core.types.d.ts +1 -1
  32. package/dist/types/functions.types.d.ts +7 -2
  33. package/lcov.info +1541 -1413
  34. package/package.json +3 -4
  35. package/src/channel/channel-handler.ts +82 -29
  36. package/src/channel/channel-runner.ts +6 -6
  37. package/src/channel/channel.types.ts +19 -23
  38. package/src/channel/local/local-channel-runner.test.ts +68 -23
  39. package/src/channel/local/local-channel-runner.ts +23 -9
  40. package/src/channel/serverless/serverless-channel-runner.ts +15 -6
  41. package/src/handle-error.ts +8 -6
  42. package/src/http/http-route-runner.test.ts +13 -57
  43. package/src/http/http-route-runner.ts +189 -92
  44. package/src/http/http-routes.types.ts +26 -9
  45. package/src/http/incomingmessage-to-request-convertor.ts +0 -0
  46. package/src/http/index.ts +4 -5
  47. package/src/http/{pikku-http-abstract-request.ts → pikku-fetch-http-request.ts} +48 -39
  48. package/src/http/pikku-fetch-http-response.ts +70 -0
  49. package/src/middleware/auth-apikey.ts +4 -4
  50. package/src/middleware/auth-bearer.ts +4 -4
  51. package/src/middleware/auth-cookie.ts +20 -28
  52. package/src/middleware-runner.ts +1 -1
  53. package/src/pikku-request.ts +8 -4
  54. package/src/scheduler/scheduler-runner.ts +0 -2
  55. package/src/services/user-session-service.ts +26 -28
  56. package/src/types/core.types.ts +1 -1
  57. package/src/types/functions.types.ts +19 -4
  58. package/tsconfig.tsbuildinfo +1 -1
  59. package/dist/http/pikku-http-abstract-request.js +0 -76
  60. package/dist/http/pikku-http-abstract-response.d.ts +0 -58
  61. package/dist/http/pikku-http-abstract-response.js +0 -54
  62. package/src/http/pikku-http-abstract-response.ts +0 -79
@@ -0,0 +1,59 @@
1
+ export class PikkuFetchHTTPResponse {
2
+ #statusCode = 200;
3
+ #headers = new Headers();
4
+ #body = null;
5
+ status(code) {
6
+ this.#statusCode = code;
7
+ return this;
8
+ }
9
+ cookie(name, value, flags) {
10
+ // TODO
11
+ return this;
12
+ }
13
+ header(name, value) {
14
+ this.#headers.delete(name);
15
+ if (Array.isArray(value)) {
16
+ value.forEach((v) => this.#headers.append(name, v));
17
+ }
18
+ else {
19
+ this.#headers.set(name, value);
20
+ }
21
+ return this;
22
+ }
23
+ arrayBuffer(data) {
24
+ this.#body = data;
25
+ this.header('Content-Type', 'application/octet-stream');
26
+ return this;
27
+ }
28
+ json(data) {
29
+ this.#body = JSON.stringify(data);
30
+ this.header('Content-Type', 'application/json');
31
+ return this;
32
+ }
33
+ text(content) {
34
+ this.#body = content;
35
+ this.header('Content-Type', 'text/plain');
36
+ return this;
37
+ }
38
+ html(content) {
39
+ this.#body = content;
40
+ this.header('Content-Type', 'text/html');
41
+ return this;
42
+ }
43
+ body(body) {
44
+ this.#body = body;
45
+ return this;
46
+ }
47
+ redirect(location, status = 302) {
48
+ this.#statusCode = status;
49
+ this.header('Location', location);
50
+ return this;
51
+ }
52
+ toResponse(args) {
53
+ return new Response(this.#body, {
54
+ ...args,
55
+ status: this.#statusCode,
56
+ headers: this.#headers,
57
+ });
58
+ }
59
+ }
@@ -5,15 +5,15 @@
5
5
  */
6
6
  export const authAPIKey = ({ source, getSessionForAPIKey, jwt, }) => {
7
7
  const middleware = async (services, { http }, next) => {
8
- if (!http?.request || services.userSession.get()) {
8
+ if (!http?.request || services.userSessionService.get()) {
9
9
  return next();
10
10
  }
11
11
  let apiKey = null;
12
12
  if (source === 'header' || source === 'all') {
13
- apiKey = http.request.getHeader('x-api-key');
13
+ apiKey = http.request.header('x-api-key');
14
14
  }
15
15
  if (!apiKey && (source === 'query' || source === 'all')) {
16
- apiKey = http.request.getQuery().apiKey;
16
+ apiKey = http.request.query().apiKey;
17
17
  }
18
18
  if (apiKey) {
19
19
  let userSession = null;
@@ -27,7 +27,7 @@ export const authAPIKey = ({ source, getSessionForAPIKey, jwt, }) => {
27
27
  userSession = await getSessionForAPIKey(services, apiKey);
28
28
  }
29
29
  if (userSession) {
30
- await services.userSession.set(userSession);
30
+ services.userSessionService.setInitial(userSession);
31
31
  }
32
32
  }
33
33
  return next();
@@ -5,11 +5,11 @@ import { InvalidSessionError } from '../errors/errors.js';
5
5
  export const authBearer = ({ token, jwt, getSession, } = {}) => {
6
6
  const middleware = async (services, { http }, next) => {
7
7
  // Skip if session already exists.
8
- if (!http?.request || services.userSession.get()) {
8
+ if (!http?.request || services.userSessionService.get()) {
9
9
  return next();
10
10
  }
11
- const authHeader = http.request.getHeader('authorization') ||
12
- http.request.getHeader('Authorization');
11
+ const authHeader = http.request.header('authorization') ||
12
+ http.request.header('Authorization');
13
13
  if (authHeader) {
14
14
  const [scheme, bearerToken] = authHeader.split(' ');
15
15
  if (scheme !== 'Bearer' || !token || !bearerToken) {
@@ -31,7 +31,7 @@ export const authBearer = ({ token, jwt, getSession, } = {}) => {
31
31
  userSession = await getSession(services, token);
32
32
  }
33
33
  if (userSession) {
34
- await services.userSession.set(userSession);
34
+ services.userSessionService.setInitial(userSession);
35
35
  }
36
36
  }
37
37
  return next();
@@ -6,37 +6,28 @@
6
6
  */
7
7
  export const authCookie = ({ cookieNames, getSessionForCookieValue, jwt, }) => {
8
8
  const middleware = async (services, { http }, next) => {
9
- if (!http?.request || services.userSession.get()) {
9
+ if (!http?.request || services.userSessionService.get()) {
10
10
  return next();
11
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);
12
+ let userSession = null;
13
+ for (const cookieName of cookieNames) {
14
+ const cookieValue = http.request.cookie(cookieName);
15
+ if (cookieValue) {
16
+ if (jwt) {
17
+ if (!services.jwt) {
18
+ throw new Error('JWT service is required for JWT decoding.');
36
19
  }
20
+ userSession = await services.jwt.decode(cookieValue);
21
+ }
22
+ else if (getSessionForCookieValue) {
23
+ userSession = await getSessionForCookieValue(services, cookieValue, cookieName);
37
24
  }
25
+ break;
38
26
  }
39
27
  }
28
+ if (userSession) {
29
+ services.userSessionService.setInitial(userSession);
30
+ }
40
31
  return next();
41
32
  };
42
33
  return middleware;
@@ -18,5 +18,5 @@ import { CoreSingletonServices, PikkuInteraction, PikkuMiddleware } from './type
18
18
  * );
19
19
  */
20
20
  export declare const runMiddleware: (services: CoreSingletonServices & {
21
- userSession: UserSessionService<any>;
21
+ userSessionService: UserSessionService<any>;
22
22
  }, interaction: PikkuInteraction, middlewares: PikkuMiddleware[], main?: () => Promise<void>) => Promise<void>;
@@ -4,11 +4,11 @@
4
4
  * @group RequestResponse
5
5
  */
6
6
  export declare abstract class PikkuRequest<In = any> {
7
- private data?;
8
- constructor(data?: In | undefined);
7
+ #private;
8
+ constructor(data: In);
9
9
  /**
10
10
  * Retrieves the data
11
11
  * @returns A promise that resolves to an object containing the combined data.
12
12
  */
13
- getData(): Promise<In>;
13
+ data(): Promise<In>;
14
14
  }
@@ -4,18 +4,18 @@
4
4
  * @group RequestResponse
5
5
  */
6
6
  export class PikkuRequest {
7
- data;
7
+ #data;
8
8
  constructor(data) {
9
- this.data = data;
9
+ this.#data = data;
10
10
  }
11
11
  /**
12
12
  * Retrieves the data
13
13
  * @returns A promise that resolves to an object containing the combined data.
14
14
  */
15
- async getData() {
16
- if (!this.data) {
15
+ async data() {
16
+ if (!this.#data) {
17
17
  throw new Error('Data not found');
18
18
  }
19
- return this.data;
19
+ return this.#data;
20
20
  }
21
21
  }
@@ -8,4 +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 function runScheduledTask<SingletonServices extends CoreSingletonServices = CoreSingletonServices, UserSession extends CoreUserSession = CoreUserSession, Services extends CoreServices<SingletonServices> = CoreServices<SingletonServices>>({ name, session, singletonServices, createSessionServices, }: RunScheduledTasksParams): Promise<void>;
11
+ export declare function runScheduledTask<SingletonServices extends CoreSingletonServices = CoreSingletonServices, UserSession extends CoreUserSession = CoreUserSession>({ name, session, singletonServices, createSessionServices, }: RunScheduledTasksParams): Promise<void>;
@@ -1,23 +1,18 @@
1
1
  import { ChannelStore } from '../channel/channel-store.js';
2
2
  import { CoreUserSession } from '../types/core.types.js';
3
3
  export interface UserSessionService<UserSession extends CoreUserSession> {
4
+ setInitial(session: UserSession): void;
4
5
  set(session: UserSession): Promise<void> | void;
5
6
  clear(): Promise<void> | void;
6
7
  get(): Promise<UserSession | undefined> | UserSession | undefined;
7
8
  }
8
- export declare class LocalUserSessionService<UserSession extends CoreUserSession> implements UserSessionService<UserSession> {
9
+ export declare class PikkuUserSessionService<UserSession extends CoreUserSession> implements UserSessionService<UserSession> {
10
+ private channelStore?;
11
+ private channelId?;
9
12
  private session;
10
- constructor(session?: UserSession | undefined);
11
- set(session: UserSession): void;
12
- clear(): void;
13
- get(): UserSession | undefined;
14
- }
15
- export declare class RemoteUserSessionService<UserSession extends CoreUserSession> implements UserSessionService<UserSession> {
16
- private channelStore;
17
- private channelId;
18
- session: UserSession | undefined;
19
- constructor(channelStore: ChannelStore<unknown, unknown, UserSession>, channelId: string, session?: UserSession | undefined);
20
- set(session: UserSession): void | Promise<void>;
21
- clear(): void | Promise<void>;
22
- get(): Promise<UserSession | undefined>;
13
+ constructor(channelStore?: ChannelStore<unknown, unknown, UserSession> | undefined, channelId?: string | undefined);
14
+ setInitial(session: UserSession): void;
15
+ set(session: UserSession): void | Promise<void> | undefined;
16
+ clear(): void | Promise<void> | undefined;
17
+ get(): Promise<UserSession> | UserSession | undefined;
23
18
  }
@@ -1,35 +1,35 @@
1
- export class LocalUserSessionService {
2
- session;
3
- constructor(session = undefined) {
4
- this.session = session;
5
- }
6
- set(session) {
7
- this.session = session;
8
- }
9
- clear() {
10
- this.session = undefined;
11
- }
12
- get() {
13
- return this.session;
14
- }
15
- }
16
- export class RemoteUserSessionService {
1
+ export class PikkuUserSessionService {
17
2
  channelStore;
18
3
  channelId;
19
4
  session;
20
- constructor(channelStore, channelId, session = undefined) {
5
+ constructor(channelStore, channelId) {
21
6
  this.channelStore = channelStore;
22
7
  this.channelId = channelId;
8
+ if (channelStore && !channelId) {
9
+ throw new Error('Channel ID is required when using channel store');
10
+ }
11
+ }
12
+ setInitial(session) {
23
13
  this.session = session;
24
14
  }
25
15
  set(session) {
26
- return this.channelStore.setUserSession(this.channelId, session);
16
+ this.session = session;
17
+ return this.channelStore?.setUserSession(this.channelId, session);
27
18
  }
28
19
  clear() {
29
- return this.channelStore.setUserSession(this.channelId, null);
20
+ this.session = undefined;
21
+ return this.channelStore?.setUserSession(this.channelId, null);
30
22
  }
31
- async get() {
32
- const { session } = await this.channelStore.getChannelAndSession(this.channelId);
33
- return session;
23
+ get() {
24
+ if (this.channelStore) {
25
+ const channel = this.channelStore.getChannelAndSession(this.channelId);
26
+ if (channel instanceof Promise) {
27
+ return channel.then(({ session }) => session);
28
+ }
29
+ else {
30
+ return channel.session;
31
+ }
32
+ }
33
+ return this.session;
34
34
  }
35
35
  }
@@ -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
- userSession: UserSessionService<UserSession>;
77
+ userSessionService: 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.
@@ -1,3 +1,4 @@
1
+ import { PikkuChannel } from '../channel/channel.types.js';
1
2
  import type { CoreServices, CoreSingletonServices, CoreUserSession } from './core.types.js';
2
3
  /**
3
4
  * Represents a core API function that performs an operation using core services and a user session.
@@ -7,7 +8,9 @@ import type { CoreServices, CoreSingletonServices, CoreUserSession } from './cor
7
8
  * @template Services - The services type, defaults to `CoreServices`.
8
9
  * @template Session - The session type, defaults to `CoreUserSession`.
9
10
  */
10
- export type CoreAPIFunction<In, Out, Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession> = (services: Services, data: In, session: Session) => Promise<Out>;
11
+ export type CoreAPIFunction<In, Out, Services extends CoreSingletonServices = CoreServices & {
12
+ channel?: PikkuChannel<unknown, Out>;
13
+ }, Session extends CoreUserSession = CoreUserSession, Channel extends boolean = false> = (services: Services, data: In, session: Session) => Channel extends true ? Promise<Out> | Promise<void> : Promise<Out>;
11
14
  /**
12
15
  * Represents a core API function that can be used without a session.
13
16
  *
@@ -16,7 +19,9 @@ export type CoreAPIFunction<In, Out, Services extends CoreSingletonServices = Co
16
19
  * @template Services - The services type, defaults to `CoreServices`.
17
20
  * @template Session - The session type, defaults to `CoreUserSession`.
18
21
  */
19
- export type CoreAPIFunctionSessionless<In, Out, Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession> = (services: Services, data: In, session?: Session) => Promise<Out>;
22
+ export type CoreAPIFunctionSessionless<In, Out, Services extends CoreSingletonServices = CoreServices & {
23
+ channel?: PikkuChannel<unknown, Out>;
24
+ }, Session extends CoreUserSession = CoreUserSession, Channel extends boolean = false> = (services: Services, data: In, session: Session) => Channel extends true ? Promise<Out> | Promise<void> : Promise<Out>;
20
25
  /**
21
26
  * Represents a function that checks permissions for a given API operation.
22
27
  *