@pikku/core 0.6.21 → 0.6.23
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 +12 -0
- package/dist/channel/channel-handler.d.ts +2 -2
- package/dist/channel/channel-handler.js +49 -26
- package/dist/channel/channel-runner.d.ts +3 -3
- package/dist/channel/channel-runner.js +5 -5
- package/dist/channel/channel.types.d.ts +12 -19
- package/dist/channel/local/local-channel-runner.d.ts +1 -1
- package/dist/channel/local/local-channel-runner.js +14 -8
- package/dist/channel/serverless/serverless-channel-runner.js +12 -7
- package/dist/handle-error.js +8 -6
- package/dist/http/http-route-runner.d.ts +75 -18
- package/dist/http/http-route-runner.js +148 -64
- package/dist/http/http-routes.types.d.ts +24 -9
- package/dist/http/incomingmessage-to-request-convertor.d.ts +1 -0
- package/dist/http/incomingmessage-to-request-convertor.js +1 -0
- package/dist/http/index.d.ts +4 -3
- package/dist/http/index.js +4 -3
- package/dist/http/{pikku-http-abstract-request.d.ts → pikku-fetch-http-request.d.ts} +14 -20
- package/dist/http/pikku-fetch-http-request.js +92 -0
- package/dist/http/pikku-fetch-http-response.d.ts +14 -0
- package/dist/http/pikku-fetch-http-response.js +59 -0
- package/dist/middleware/auth-apikey.js +4 -4
- package/dist/middleware/auth-bearer.js +4 -4
- package/dist/middleware/auth-cookie.js +16 -25
- package/dist/middleware-runner.d.ts +1 -1
- package/dist/pikku-request.d.ts +3 -3
- package/dist/pikku-request.js +5 -5
- package/dist/scheduler/scheduler-runner.d.ts +1 -1
- package/dist/services/user-session-service.d.ts +9 -14
- package/dist/services/user-session-service.js +22 -22
- package/dist/types/core.types.d.ts +1 -1
- package/dist/types/functions.types.d.ts +7 -2
- package/lcov.info +1529 -1412
- package/package.json +3 -4
- package/src/channel/channel-handler.ts +82 -29
- package/src/channel/channel-runner.ts +7 -7
- package/src/channel/channel.types.ts +19 -23
- package/src/channel/local/local-channel-runner.test.ts +68 -23
- package/src/channel/local/local-channel-runner.ts +23 -9
- package/src/channel/serverless/serverless-channel-runner.ts +15 -6
- package/src/handle-error.ts +8 -6
- package/src/http/http-route-runner.test.ts +13 -57
- package/src/http/http-route-runner.ts +173 -86
- package/src/http/http-routes.types.ts +26 -9
- package/src/http/incomingmessage-to-request-convertor.ts +0 -0
- package/src/http/index.ts +4 -5
- package/src/http/{pikku-http-abstract-request.ts → pikku-fetch-http-request.ts} +48 -39
- package/src/http/pikku-fetch-http-response.ts +70 -0
- package/src/middleware/auth-apikey.ts +4 -4
- package/src/middleware/auth-bearer.ts +4 -4
- package/src/middleware/auth-cookie.ts +20 -28
- package/src/middleware-runner.ts +1 -1
- package/src/pikku-request.ts +8 -4
- package/src/scheduler/scheduler-runner.ts +0 -2
- package/src/services/user-session-service.ts +26 -28
- package/src/types/core.types.ts +1 -1
- package/src/types/functions.types.ts +19 -4
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/http/pikku-http-abstract-request.js +0 -76
- package/dist/http/pikku-http-abstract-response.d.ts +0 -58
- package/dist/http/pikku-http-abstract-response.js +0 -54
- package/src/http/pikku-http-abstract-response.ts +0 -79
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { CoreServices } from '../types/core.types.js';
|
|
1
|
+
import { CoreServices, CoreUserSession } from '../types/core.types.js';
|
|
2
2
|
import { CoreAPIChannel, PikkuChannelHandler } from './channel.types.js';
|
|
3
|
-
export declare const processMessageHandlers: (services: CoreServices, channelConfig: CoreAPIChannel<any, any>, channelHandler: PikkuChannelHandler) => (rawData: any) => Promise<unknown>;
|
|
3
|
+
export declare const processMessageHandlers: (services: CoreServices, session: CoreUserSession | undefined, channelConfig: CoreAPIChannel<any, any>, channelHandler: PikkuChannelHandler) => (rawData: any) => Promise<unknown>;
|
|
@@ -1,45 +1,65 @@
|
|
|
1
1
|
import { verifyPermissions } from '../permissions.js';
|
|
2
2
|
import { pikkuState } from '../pikku-state.js';
|
|
3
|
-
const
|
|
3
|
+
const getRouteMeta = (channelName, routingProperty, routerValue) => {
|
|
4
4
|
const channelsMeta = pikkuState('channel', 'meta');
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// loadSchema(schemaNames, logger)
|
|
13
|
-
// validateJson(schemaNames, data)
|
|
14
|
-
}
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
5
|
+
const channelMeta = channelsMeta.find((channelMeta) => channelMeta.name === channelName);
|
|
6
|
+
if (!channelMeta) {
|
|
7
|
+
throw new Error(`Channel ${channelName} not found`);
|
|
8
|
+
}
|
|
9
|
+
if (!routingProperty) {
|
|
10
|
+
if (!channelMeta.message) {
|
|
11
|
+
throw new Error(`Channel ${channelName} has no default message route`);
|
|
17
12
|
}
|
|
13
|
+
return channelMeta.message;
|
|
14
|
+
}
|
|
15
|
+
if (!routerValue) {
|
|
16
|
+
throw new Error(`Channel ${channelName} requires a router value for ${routingProperty}`);
|
|
17
|
+
}
|
|
18
|
+
const route = channelMeta.messageRoutes[routingProperty]?.[routerValue];
|
|
19
|
+
if (!route) {
|
|
20
|
+
throw new Error(`Channel ${channelName} has no route for ${routingProperty}:${routerValue}`);
|
|
18
21
|
}
|
|
22
|
+
return route;
|
|
19
23
|
};
|
|
20
|
-
const
|
|
24
|
+
const validateSchema = (logger, data, channelRoute) => {
|
|
25
|
+
const schemaNames = channelRoute.inputs;
|
|
26
|
+
if (schemaNames) {
|
|
27
|
+
// TODO
|
|
28
|
+
// loadSchema(schemaNames, logger)
|
|
29
|
+
// validateJson(schemaNames, data)
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const validateAuth = (requiresSession, session, onMessage) => {
|
|
21
33
|
const auth = typeof onMessage === 'function'
|
|
22
34
|
? requiresSession
|
|
23
35
|
: onMessage.auth === undefined
|
|
24
36
|
? requiresSession
|
|
25
37
|
: onMessage.auth;
|
|
26
|
-
if (auth && !
|
|
38
|
+
if (auth && !session) {
|
|
27
39
|
return false;
|
|
28
40
|
}
|
|
29
41
|
return true;
|
|
30
42
|
};
|
|
31
|
-
const validatePermissions = async (services,
|
|
43
|
+
const validatePermissions = async (services, session, onMessage, data) => {
|
|
32
44
|
const permissions = typeof onMessage === 'function' ? {} : onMessage.permissions;
|
|
33
|
-
return await verifyPermissions(permissions, services, data,
|
|
45
|
+
return await verifyPermissions(permissions, services, data, session);
|
|
34
46
|
};
|
|
35
|
-
const runFunction = async (services, channelHandler, onMessage, data) => {
|
|
47
|
+
const runFunction = async (services, channelHandler, channelMessageMeta, session, onMessage, data) => {
|
|
36
48
|
const func = typeof onMessage === 'function' ? onMessage : onMessage.func;
|
|
37
|
-
|
|
49
|
+
if (channelMessageMeta.type?.toLowerCase().includes('function')) {
|
|
50
|
+
return await func({
|
|
51
|
+
...services,
|
|
52
|
+
channel: channelHandler.getChannel(),
|
|
53
|
+
}, data, session);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
return await func(services, channelHandler.getChannel(), data);
|
|
57
|
+
}
|
|
38
58
|
};
|
|
39
|
-
export const processMessageHandlers = (services, channelConfig, channelHandler) => {
|
|
59
|
+
export const processMessageHandlers = (services, session, channelConfig, channelHandler) => {
|
|
40
60
|
const logger = services.logger;
|
|
41
61
|
const requiresSession = channelConfig.auth !== false;
|
|
42
|
-
const processMessage = async (data, onMessage, routingProperty, routerValue) => {
|
|
62
|
+
const processMessage = async (data, onMessage, session, routingProperty, routerValue) => {
|
|
43
63
|
if (!validateAuth(requiresSession, channelHandler, onMessage)) {
|
|
44
64
|
const routeMessage = routingProperty
|
|
45
65
|
? `route '${routingProperty}:${routerValue}'`
|
|
@@ -49,12 +69,15 @@ export const processMessageHandlers = (services, channelConfig, channelHandler)
|
|
|
49
69
|
channelHandler.getChannel().send(`Unauthorized for ${routeMessage}`);
|
|
50
70
|
return;
|
|
51
71
|
}
|
|
52
|
-
|
|
72
|
+
const routeMeta = getRouteMeta(channelConfig.name, routingProperty, routerValue);
|
|
73
|
+
if (routeMeta) {
|
|
74
|
+
await validateSchema(services.logger, data, routeMeta);
|
|
75
|
+
}
|
|
53
76
|
const hasPermission = await validatePermissions(services, channelHandler, onMessage, data);
|
|
54
77
|
if (!hasPermission) {
|
|
55
78
|
logger.error(`Channel ${channelConfig.name} requires permissions for ${routingProperty || 'default message route'}`);
|
|
56
79
|
}
|
|
57
|
-
return await runFunction(services, channelHandler, onMessage, data);
|
|
80
|
+
return await runFunction(services, channelHandler, routeMeta, session, onMessage, data);
|
|
58
81
|
};
|
|
59
82
|
const onMessage = async (rawData) => {
|
|
60
83
|
let result;
|
|
@@ -68,14 +91,14 @@ export const processMessageHandlers = (services, channelConfig, channelHandler)
|
|
|
68
91
|
const routerValue = messageData[routingProperty];
|
|
69
92
|
if (routerValue && routes[routerValue]) {
|
|
70
93
|
processed = true;
|
|
71
|
-
result = await processMessage(messageData, routes[routerValue], routingProperty, routerValue);
|
|
94
|
+
result = await processMessage(messageData, routes[routerValue], session, routingProperty, routerValue);
|
|
72
95
|
break;
|
|
73
96
|
}
|
|
74
97
|
}
|
|
75
98
|
// Default handler if no routes matched but json data was parsed
|
|
76
99
|
if (!processed && channelConfig.onMessage) {
|
|
77
100
|
processed = true;
|
|
78
|
-
result = await processMessage(messageData, channelConfig.onMessage);
|
|
101
|
+
result = await processMessage(messageData, channelConfig.onMessage, session);
|
|
79
102
|
}
|
|
80
103
|
}
|
|
81
104
|
catch (error) {
|
|
@@ -85,7 +108,7 @@ export const processMessageHandlers = (services, channelConfig, channelHandler)
|
|
|
85
108
|
// Default handler if no routes matched and json data wasn't parsed
|
|
86
109
|
if (!processed && channelConfig.onMessage) {
|
|
87
110
|
processed = true;
|
|
88
|
-
result = await processMessage(rawData, channelConfig.onMessage);
|
|
111
|
+
result = await processMessage(rawData, channelConfig.onMessage, session);
|
|
89
112
|
}
|
|
90
113
|
if (!processed) {
|
|
91
114
|
logger.error(`No handler found for message in channel ${channelConfig.name} for ${rawData}`);
|
|
@@ -4,11 +4,11 @@ export declare const addChannel: <In, Channel extends string, ChannelFunction, C
|
|
|
4
4
|
export declare const getMatchingChannelConfig: (request: string) => {
|
|
5
5
|
matchedPath: import("path-to-regexp").MatchResult<Partial<Record<string, string | string[]>>>;
|
|
6
6
|
params: Partial<Record<string, string | string[]>>;
|
|
7
|
-
channelConfig: CoreAPIChannel<any, string, import("./channel.types.js").CoreChannelConnection<any, unknown, import("../index.js").CoreServices>, import("./channel.types.js").CoreChannelDisconnection<any, import("../index.js").CoreServices>, import("./channel.types.js").CoreChannelMessage<unknown, unknown, unknown, import("../index.js").CoreServices>, import("./channel.types.js").CoreChannelMessage<unknown, unknown, unknown, import("../index.js").CoreServices>, import("../index.js").CoreAPIPermission<any>>;
|
|
7
|
+
channelConfig: CoreAPIChannel<any, string, import("./channel.types.js").CoreChannelConnection<any, unknown, import("../index.js").CoreServices>, import("./channel.types.js").CoreChannelDisconnection<any, import("../index.js").CoreServices>, import("./channel.types.js").CoreChannelMessage<unknown, unknown, unknown, import("../index.js").CoreServices> | import("../index.js").CoreAPIFunction<unknown, unknown>, import("./channel.types.js").CoreChannelMessage<unknown, unknown, unknown, import("../index.js").CoreServices> | import("../index.js").CoreAPIFunction<unknown, unknown>, import("../index.js").CoreAPIPermission<any>>;
|
|
8
8
|
schemaName: string | null | undefined;
|
|
9
9
|
} | null;
|
|
10
|
-
export declare const openChannel: ({ route, singletonServices, coerceToArray,
|
|
11
|
-
userSessionService
|
|
10
|
+
export declare const openChannel: ({ route, singletonServices, coerceToArray, request, }: Pick<CoreAPIChannel<unknown, string>, "route"> & RunChannelParams<unknown> & {
|
|
11
|
+
userSessionService: UserSessionService<any>;
|
|
12
12
|
} & RunChannelOptions) => Promise<{
|
|
13
13
|
openingData: unknown;
|
|
14
14
|
channelConfig: CoreAPIChannel<unknown, any>;
|
|
@@ -27,7 +27,7 @@ export const getMatchingChannelConfig = (request) => {
|
|
|
27
27
|
}
|
|
28
28
|
return null;
|
|
29
29
|
};
|
|
30
|
-
export const openChannel = async ({ route, singletonServices, coerceToArray = false,
|
|
30
|
+
export const openChannel = async ({ route, singletonServices, coerceToArray = false, request, }) => {
|
|
31
31
|
const matchingChannel = getMatchingChannelConfig(route);
|
|
32
32
|
if (!matchingChannel) {
|
|
33
33
|
singletonServices.logger.info(`Channel not found: ${route}`);
|
|
@@ -35,15 +35,15 @@ export const openChannel = async ({ route, singletonServices, coerceToArray = fa
|
|
|
35
35
|
}
|
|
36
36
|
const { params, channelConfig, schemaName } = matchingChannel;
|
|
37
37
|
const requiresSession = channelConfig.auth !== false;
|
|
38
|
-
|
|
38
|
+
request?.setParams(params);
|
|
39
39
|
singletonServices.logger.info(`Matched channel: ${channelConfig.name} | route: ${channelConfig.route} | auth: ${requiresSession.toString()}`);
|
|
40
40
|
let openingData;
|
|
41
|
-
if (
|
|
42
|
-
openingData = await
|
|
41
|
+
if (request) {
|
|
42
|
+
openingData = await request.data();
|
|
43
43
|
if (coerceToArray && schemaName) {
|
|
44
44
|
coerceQueryStringToArray(schemaName, openingData);
|
|
45
45
|
}
|
|
46
|
-
validateSchema(singletonServices.logger, singletonServices.schemaService, schemaName, openingData);
|
|
46
|
+
await validateSchema(singletonServices.logger, singletonServices.schemaService, schemaName, openingData);
|
|
47
47
|
}
|
|
48
48
|
return { openingData, channelConfig };
|
|
49
49
|
};
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { PikkuError } from '../errors/error-handler.js';
|
|
2
|
-
import { HTTPFunctionMetaInputTypes,
|
|
3
|
-
import { PikkuHTTPAbstractRequest } from '../http/pikku-http-abstract-request.js';
|
|
4
|
-
import { PikkuHTTPAbstractResponse } from '../http/pikku-http-abstract-response.js';
|
|
2
|
+
import { HTTPFunctionMetaInputTypes, PikkuHTTPRequest, PikkuHTTPResponse } from '../http/http-routes.types.js';
|
|
5
3
|
import { APIDocs, CoreServices, CoreSingletonServices, CreateSessionServices, PikkuMiddleware } from '../types/core.types.js';
|
|
6
|
-
import { CoreAPIPermission } from '../types/functions.types.js';
|
|
7
|
-
import { PikkuRequest } from '../pikku-request.js';
|
|
8
|
-
import { PikkuResponse } from '../pikku-response.js';
|
|
4
|
+
import { CoreAPIFunction, CoreAPIPermission } from '../types/functions.types.js';
|
|
9
5
|
export type RunChannelOptions = Partial<{
|
|
10
6
|
skipUserSession: boolean;
|
|
11
7
|
respondWith404: boolean;
|
|
@@ -16,12 +12,15 @@ export type RunChannelOptions = Partial<{
|
|
|
16
12
|
export type RunChannelParams<ChannelData> = {
|
|
17
13
|
channelId: string;
|
|
18
14
|
singletonServices: CoreSingletonServices;
|
|
19
|
-
request?:
|
|
20
|
-
response?:
|
|
21
|
-
http?: PikkuHTTP;
|
|
15
|
+
request?: PikkuHTTPRequest<ChannelData>;
|
|
16
|
+
response?: PikkuHTTPResponse;
|
|
22
17
|
createSessionServices?: CreateSessionServices;
|
|
23
18
|
};
|
|
24
|
-
export interface
|
|
19
|
+
export interface ChannelMessageMeta {
|
|
20
|
+
inputs: string[] | null;
|
|
21
|
+
outputs: string[] | null;
|
|
22
|
+
docs?: APIDocs;
|
|
23
|
+
type: null | string;
|
|
25
24
|
}
|
|
26
25
|
export interface ChannelMeta {
|
|
27
26
|
name: string;
|
|
@@ -32,14 +31,8 @@ export interface ChannelMeta {
|
|
|
32
31
|
inputTypes?: HTTPFunctionMetaInputTypes;
|
|
33
32
|
connect: boolean;
|
|
34
33
|
disconnect: boolean;
|
|
35
|
-
message:
|
|
36
|
-
|
|
37
|
-
outputs: string[] | null;
|
|
38
|
-
} | null;
|
|
39
|
-
messageRoutes: Record<string, Record<string, {
|
|
40
|
-
inputs: string[] | null;
|
|
41
|
-
outputs: string[] | null;
|
|
42
|
-
}>>;
|
|
34
|
+
message: ChannelMessageMeta | null;
|
|
35
|
+
messageRoutes: Record<string, Record<string, ChannelMessageMeta>>;
|
|
43
36
|
docs?: APIDocs;
|
|
44
37
|
tags?: string[];
|
|
45
38
|
}
|
|
@@ -58,7 +51,7 @@ export type CoreAPIChannelMessage<ChannelFunctionMessage = CoreChannelMessage<un
|
|
|
58
51
|
func: ChannelFunctionMessage;
|
|
59
52
|
route: string;
|
|
60
53
|
};
|
|
61
|
-
export type CoreAPIChannel<ChannelData, Channel extends string, ChannelFunctionConnection = CoreChannelConnection<ChannelData>, ChannelFunctionDisconnection = CoreChannelDisconnection<ChannelData>, ChannelFunctionDefaultMessage = CoreChannelMessage<unknown, unknown, unknown>, ChannelFunctionMessageRoute = CoreChannelMessage<unknown, unknown, unknown>, APIPermission = CoreAPIPermission<ChannelData>> = {
|
|
54
|
+
export type CoreAPIChannel<ChannelData, Channel extends string, ChannelFunctionConnection = CoreChannelConnection<ChannelData>, ChannelFunctionDisconnection = CoreChannelDisconnection<ChannelData>, ChannelFunctionDefaultMessage = CoreChannelMessage<unknown, unknown, unknown> | CoreAPIFunction<unknown, unknown>, ChannelFunctionMessageRoute = CoreChannelMessage<unknown, unknown, unknown> | CoreAPIFunction<unknown, unknown>, APIPermission = CoreAPIPermission<ChannelData>> = {
|
|
62
55
|
name: string;
|
|
63
56
|
route: Channel;
|
|
64
57
|
onConnect?: ChannelFunctionConnection;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { CoreAPIChannel, RunChannelOptions, RunChannelParams } from '../channel.types.js';
|
|
2
2
|
import { PikkuLocalChannelHandler } from './local-channel-handler.js';
|
|
3
|
-
export declare const runLocalChannel: ({ singletonServices, channelId, request, response, route, createSessionServices, skipUserSession, respondWith404, coerceToArray, logWarningsForStatusCodes, bubbleErrors, }: Pick<CoreAPIChannel<unknown, any>, "route"
|
|
3
|
+
export declare const runLocalChannel: ({ singletonServices, channelId, request, response, route, createSessionServices, skipUserSession, respondWith404, coerceToArray, logWarningsForStatusCodes, bubbleErrors, }: Partial<Pick<CoreAPIChannel<unknown, any>, "route">> & RunChannelOptions & RunChannelParams<unknown>) => Promise<PikkuLocalChannelHandler | void>;
|
|
@@ -5,29 +5,35 @@ import { processMessageHandlers } from '../channel-handler.js';
|
|
|
5
5
|
import { PikkuLocalChannelHandler } from './local-channel-handler.js';
|
|
6
6
|
import { handleError } from '../../handle-error.js';
|
|
7
7
|
import { runMiddleware } from '../../middleware-runner.js';
|
|
8
|
-
import {
|
|
8
|
+
import { PikkuUserSessionService } from '../../services/user-session-service.js';
|
|
9
9
|
export const runLocalChannel = async ({ singletonServices, channelId, request, response, route, createSessionServices, skipUserSession = false, respondWith404 = true, coerceToArray = false, logWarningsForStatusCodes = [], bubbleErrors = false, }) => {
|
|
10
10
|
let sessionServices;
|
|
11
11
|
let channelHandler;
|
|
12
|
-
const userSessionService = new
|
|
13
|
-
|
|
12
|
+
const userSessionService = new PikkuUserSessionService();
|
|
13
|
+
let http;
|
|
14
|
+
if (request) {
|
|
15
|
+
http = createHTTPInteraction(request, response);
|
|
16
|
+
route = http?.request?.path();
|
|
17
|
+
}
|
|
14
18
|
const main = async () => {
|
|
15
19
|
try {
|
|
16
20
|
const { openingData, channelConfig } = await openChannel({
|
|
17
21
|
channelId,
|
|
18
22
|
createSessionServices,
|
|
19
23
|
respondWith404,
|
|
20
|
-
|
|
24
|
+
request,
|
|
25
|
+
response,
|
|
21
26
|
route,
|
|
22
27
|
singletonServices,
|
|
23
28
|
skipUserSession,
|
|
24
29
|
coerceToArray,
|
|
30
|
+
userSessionService,
|
|
25
31
|
});
|
|
26
32
|
channelHandler = new PikkuLocalChannelHandler(channelId, channelConfig.name, openingData);
|
|
27
33
|
const channel = channelHandler.getChannel();
|
|
28
|
-
const
|
|
34
|
+
const session = await userSessionService.get();
|
|
29
35
|
if (createSessionServices) {
|
|
30
|
-
sessionServices = await createSessionServices(singletonServices, { http },
|
|
36
|
+
sessionServices = await createSessionServices(singletonServices, { http }, session);
|
|
31
37
|
}
|
|
32
38
|
const allServices = {
|
|
33
39
|
...singletonServices,
|
|
@@ -43,7 +49,7 @@ export const runLocalChannel = async ({ singletonServices, channelId, request, r
|
|
|
43
49
|
await closeSessionServices(singletonServices.logger, sessionServices);
|
|
44
50
|
}
|
|
45
51
|
});
|
|
46
|
-
channelHandler.registerOnMessage(processMessageHandlers(allServices, channelConfig, channelHandler));
|
|
52
|
+
channelHandler.registerOnMessage(processMessageHandlers(allServices, session, channelConfig, channelHandler));
|
|
47
53
|
}
|
|
48
54
|
catch (e) {
|
|
49
55
|
handleError(e, http, channelId, singletonServices.logger, logWarningsForStatusCodes, respondWith404, bubbleErrors);
|
|
@@ -56,7 +62,7 @@ export const runLocalChannel = async ({ singletonServices, channelId, request, r
|
|
|
56
62
|
};
|
|
57
63
|
await runMiddleware({
|
|
58
64
|
...singletonServices,
|
|
59
|
-
|
|
65
|
+
userSessionService,
|
|
60
66
|
}, { http }, route.middleware || [], main);
|
|
61
67
|
return channelHandler;
|
|
62
68
|
};
|
|
@@ -3,9 +3,10 @@ import { processMessageHandlers } from '../channel-handler.js';
|
|
|
3
3
|
import { openChannel } from '../channel-runner.js';
|
|
4
4
|
import { createHTTPInteraction } from '../../http/http-route-runner.js';
|
|
5
5
|
import { handleError } from '../../handle-error.js';
|
|
6
|
-
import {
|
|
6
|
+
import { PikkuUserSessionService } from '../../services/user-session-service.js';
|
|
7
7
|
import { runMiddleware } from '../../middleware-runner.js';
|
|
8
8
|
import { pikkuState } from '../../pikku-state.js';
|
|
9
|
+
import { PikkuFetchHTTPRequest } from '../../http/pikku-fetch-http-request.js';
|
|
9
10
|
const getVariablesForChannel = ({ channelId, channelName, channelHandlerFactory, openingData, }) => {
|
|
10
11
|
const channels = pikkuState('channel', 'channels');
|
|
11
12
|
const channelConfig = channels.find((channelConfig) => channelConfig.name === channelName);
|
|
@@ -21,15 +22,19 @@ const getVariablesForChannel = ({ channelId, channelName, channelHandlerFactory,
|
|
|
21
22
|
};
|
|
22
23
|
export const runChannelConnect = async ({ singletonServices, channelId, channelObject, request, response, route, createSessionServices, channelStore, channelHandlerFactory, coerceToArray = false, logWarningsForStatusCodes = [], respondWith404 = true, bubbleErrors = false, }) => {
|
|
23
24
|
let sessionServices;
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
let http;
|
|
26
|
+
if (request instanceof Request) {
|
|
27
|
+
http = createHTTPInteraction(new PikkuFetchHTTPRequest(request), response);
|
|
28
|
+
}
|
|
29
|
+
const userSessionService = new PikkuUserSessionService(channelStore, channelId);
|
|
26
30
|
const { channelConfig, openingData } = await openChannel({
|
|
27
31
|
channelId,
|
|
28
32
|
createSessionServices,
|
|
29
|
-
|
|
33
|
+
request,
|
|
30
34
|
route,
|
|
31
35
|
singletonServices,
|
|
32
36
|
coerceToArray,
|
|
37
|
+
userSessionService,
|
|
33
38
|
});
|
|
34
39
|
const main = async () => {
|
|
35
40
|
try {
|
|
@@ -48,7 +53,7 @@ export const runChannelConnect = async ({ singletonServices, channelId, channelO
|
|
|
48
53
|
sessionServices = await createSessionServices(singletonServices, { http }, await userSessionService.get());
|
|
49
54
|
}
|
|
50
55
|
await channelConfig.onConnect?.({ ...singletonServices, ...sessionServices }, channel);
|
|
51
|
-
http?.response?.
|
|
56
|
+
http?.response?.status(101);
|
|
52
57
|
}
|
|
53
58
|
catch (e) {
|
|
54
59
|
handleError(e, http, channelId, singletonServices.logger, logWarningsForStatusCodes, respondWith404, bubbleErrors);
|
|
@@ -61,7 +66,7 @@ export const runChannelConnect = async ({ singletonServices, channelId, channelO
|
|
|
61
66
|
};
|
|
62
67
|
await runMiddleware({
|
|
63
68
|
...singletonServices,
|
|
64
|
-
|
|
69
|
+
userSessionService,
|
|
65
70
|
}, { http }, channelConfig.middleware || [], main);
|
|
66
71
|
};
|
|
67
72
|
export const runChannelDisconnect = async ({ singletonServices, ...params }) => {
|
|
@@ -94,7 +99,7 @@ export const runChannelMessage = async ({ singletonServices, ...params }, data)
|
|
|
94
99
|
}
|
|
95
100
|
let response;
|
|
96
101
|
try {
|
|
97
|
-
const onMessage = processMessageHandlers({ ...singletonServices, ...sessionServices }, channelConfig, channelHandler);
|
|
102
|
+
const onMessage = processMessageHandlers({ ...singletonServices, ...sessionServices }, session, channelConfig, channelHandler);
|
|
98
103
|
response = await onMessage(data);
|
|
99
104
|
}
|
|
100
105
|
finally {
|
package/dist/handle-error.js
CHANGED
|
@@ -20,8 +20,8 @@ export const handleError = (e, http, trackerId, logger, logWarningsForStatusCode
|
|
|
20
20
|
const errorResponse = getErrorResponse(e);
|
|
21
21
|
if (errorResponse != null) {
|
|
22
22
|
// Set status and response body
|
|
23
|
-
http?.response?.
|
|
24
|
-
http?.response?.
|
|
23
|
+
http?.response?.status(errorResponse.status);
|
|
24
|
+
http?.response?.json({
|
|
25
25
|
message: errorResponse.message,
|
|
26
26
|
payload: e.payload,
|
|
27
27
|
traceId: trackerId,
|
|
@@ -37,21 +37,23 @@ export const handleError = (e, http, trackerId, logger, logWarningsForStatusCode
|
|
|
37
37
|
else {
|
|
38
38
|
// Handle unexpected errors
|
|
39
39
|
logger.error(e);
|
|
40
|
-
http?.response?.
|
|
40
|
+
http?.response?.status(500);
|
|
41
41
|
if (trackerId) {
|
|
42
42
|
logger.warn(`Error id: ${trackerId}`);
|
|
43
|
-
http?.response?.
|
|
43
|
+
http?.response?.json({ errorId: trackerId });
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
// Handle 404 errors specifically
|
|
47
47
|
if (e instanceof NotFoundError) {
|
|
48
|
-
|
|
48
|
+
// TODO
|
|
49
|
+
// http?.response?.end()
|
|
49
50
|
}
|
|
50
51
|
// Either bubble up or end the response
|
|
51
52
|
if (bubbleError) {
|
|
52
53
|
throw e;
|
|
53
54
|
}
|
|
54
55
|
else {
|
|
55
|
-
|
|
56
|
+
// TODO
|
|
57
|
+
// http?.response?.end()
|
|
56
58
|
}
|
|
57
59
|
};
|
|
@@ -1,33 +1,90 @@
|
|
|
1
|
-
import { CoreHTTPFunctionRoute, RunRouteOptions, RunRouteParams, PikkuHTTP } from './http-routes.types.js';
|
|
1
|
+
import { CoreHTTPFunctionRoute, RunRouteOptions, RunRouteParams, PikkuHTTP, PikkuHTTPRequest, PikkuHTTPResponse } from './http-routes.types.js';
|
|
2
2
|
import { PikkuMiddleware } from '../types/core.types.js';
|
|
3
|
-
import {
|
|
4
|
-
import { PikkuResponse } from '../pikku-response.js';
|
|
3
|
+
import { PikkuFetchHTTPResponse } from './pikku-fetch-http-response.js';
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
5
|
+
* Registers middleware either globally or for a specific route.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* When a string route pattern is provided along with middleware, the middleware
|
|
8
|
+
* is applied only to that route. Otherwise, if an array is provided, it is treated
|
|
9
|
+
* as global middleware (applied to all routes).
|
|
10
|
+
*
|
|
11
|
+
* @template APIMiddleware The middleware type.
|
|
12
|
+
* @param {APIMiddleware[] | string} routeOrMiddleware - Either a global middleware array or a route pattern string.
|
|
13
|
+
* @param {APIMiddleware[]} [middleware] - The middleware array to apply when a route pattern is specified.
|
|
10
14
|
*/
|
|
11
15
|
export declare const addMiddleware: <APIMiddleware extends PikkuMiddleware>(routeOrMiddleware: APIMiddleware[] | string, middleware?: APIMiddleware[]) => void;
|
|
12
16
|
/**
|
|
13
|
-
*
|
|
17
|
+
* Adds a new route to the global HTTP route registry.
|
|
18
|
+
*
|
|
19
|
+
* The route configuration includes the HTTP method, route path, permissions,
|
|
20
|
+
* middleware, and the handler function that implements the route's logic.
|
|
14
21
|
*
|
|
15
|
-
* @
|
|
22
|
+
* @template In Expected input type.
|
|
23
|
+
* @template Out Expected output type.
|
|
24
|
+
* @template Route Route pattern as a string.
|
|
25
|
+
* @template APIFunction Type for the route handler function.
|
|
26
|
+
* @template APIFunctionSessionless Type for a sessionless handler.
|
|
27
|
+
* @template APIPermission Type representing required permissions.
|
|
28
|
+
* @template APIMiddleware Middleware type to be used with the route.
|
|
29
|
+
* @param {CoreHTTPFunctionRoute<In, Out, Route, APIFunction, APIFunctionSessionless, APIPermission, APIMiddleware>} route - The route configuration object.
|
|
16
30
|
*/
|
|
17
31
|
export declare const addRoute: <In, Out, Route extends string, APIFunction, APIFunctionSessionless, APIPermission, APIMiddleware>(route: CoreHTTPFunctionRoute<In, Out, Route, APIFunction, APIFunctionSessionless, APIPermission, APIMiddleware>) => void;
|
|
18
32
|
/**
|
|
19
|
-
*
|
|
33
|
+
* Combines the request and response objects into a single HTTP interaction object.
|
|
34
|
+
*
|
|
35
|
+
* This utility function creates an object that holds both the HTTP request and response,
|
|
36
|
+
* which simplifies passing these around through middleware and route execution.
|
|
37
|
+
*
|
|
38
|
+
* @param {PikkuHTTPRequest | undefined} request - The HTTP request object.
|
|
39
|
+
* @param {PikkuHTTPResponse | undefined} response - The HTTP response object.
|
|
40
|
+
* @returns {PikkuHTTP | undefined} The combined HTTP interaction object or undefined if none provided.
|
|
41
|
+
*/
|
|
42
|
+
export declare const createHTTPInteraction: (request: PikkuHTTPRequest | undefined, response: PikkuHTTPResponse | undefined) => PikkuHTTP | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Executes an HTTP route for a given Fetch API request.
|
|
20
45
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
46
|
+
* This function wraps the entire lifecycle of handling an HTTP request:
|
|
47
|
+
* - Matching the request to a registered route.
|
|
48
|
+
* - Validating input and session state.
|
|
49
|
+
* - Running middleware and the route handler.
|
|
50
|
+
* - Handling errors and forming the response.
|
|
51
|
+
*
|
|
52
|
+
* @template In Expected input data type.
|
|
53
|
+
* @template Out Expected output data type.
|
|
54
|
+
* @param {Request} request - The native Fetch API Request object.
|
|
55
|
+
* @param {RunRouteOptions & RunRouteParams} params - Additional options including services and session management.
|
|
56
|
+
* @returns {Promise<Response>} A promise that resolves to a Fetch API Response object.
|
|
57
|
+
*/
|
|
58
|
+
export declare const fetch: <In, Out>(request: Request, params: RunRouteOptions & RunRouteParams) => Promise<Response>;
|
|
59
|
+
/**
|
|
60
|
+
* Executes an HTTP route using a Pikku-specific request wrapper.
|
|
61
|
+
*
|
|
62
|
+
* This variant accepts either a native Request or a PikkuHTTPRequest object and returns
|
|
63
|
+
* a PikkuFetchHTTPResponse for further manipulation if needed.
|
|
64
|
+
*
|
|
65
|
+
* @template In Expected input data type.
|
|
66
|
+
* @template Out Expected output data type.
|
|
67
|
+
* @param {Request | PikkuHTTPRequest} request - The request object.
|
|
68
|
+
* @param {RunRouteOptions & RunRouteParams} params - Execution options including services and session configuration.
|
|
69
|
+
* @returns {Promise<PikkuFetchHTTPResponse>} A promise that resolves to a PikkuFetchHTTPResponse object.
|
|
24
70
|
*/
|
|
25
|
-
export declare const
|
|
71
|
+
export declare const pikkuFetch: <In, Out>(request: Request | PikkuHTTPRequest, params: RunRouteOptions & RunRouteParams) => Promise<PikkuFetchHTTPResponse>;
|
|
26
72
|
/**
|
|
27
|
-
*
|
|
73
|
+
* Core function to process an HTTP request through route matching, validation,
|
|
74
|
+
* middleware execution, error handling, and session service cleanup.
|
|
75
|
+
*
|
|
76
|
+
* This function does the following:
|
|
77
|
+
* - Wraps the incoming request and response into an HTTP interaction object.
|
|
78
|
+
* - Determines the correct route based on HTTP method and path.
|
|
79
|
+
* - Executes middleware and the route handler.
|
|
80
|
+
* - Catches and handles errors, optionally bubbling them if configured.
|
|
81
|
+
* - Cleans up any session services created during processing.
|
|
28
82
|
*
|
|
29
|
-
* @
|
|
30
|
-
* @
|
|
31
|
-
* @
|
|
83
|
+
* @template In Expected input data type.
|
|
84
|
+
* @template Out Expected output data type.
|
|
85
|
+
* @param {Request | PikkuHTTPRequest} request - The incoming HTTP request.
|
|
86
|
+
* @param {PikkuHTTPResponse} response - The response object to be populated.
|
|
87
|
+
* @param {RunRouteOptions & RunRouteParams} options - Options such as singleton services, session handling, and error configuration.
|
|
88
|
+
* @returns {Promise<Out | void>} The output from the route handler or void if an error occurred.
|
|
32
89
|
*/
|
|
33
|
-
export declare const
|
|
90
|
+
export declare const fetchData: <In, Out>(request: Request | PikkuHTTPRequest, response: PikkuHTTPResponse, { singletonServices, createSessionServices, skipUserSession, respondWith404, logWarningsForStatusCodes, coerceToArray, bubbleErrors, }: RunRouteOptions & RunRouteParams) => Promise<Out | void>;
|