@pikku/core 0.6.21 → 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.
- package/CHANGELOG.md +6 -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 +4 -4
- 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 +154 -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 +1543 -1420
- package/package.json +3 -4
- package/src/channel/channel-handler.ts +82 -29
- package/src/channel/channel-runner.ts +6 -6
- 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 +184 -92
- 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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.22",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -23,8 +23,6 @@
|
|
|
23
23
|
"./channel/local": "./dist/channel/local/index.js",
|
|
24
24
|
"./channel/serverless": "./dist/channel/serverless/index.js",
|
|
25
25
|
"./http": "./dist/http/index.js",
|
|
26
|
-
"./http/pikku-http-abstract-response": "./dist/http/pikku-http-abstract-response.js",
|
|
27
|
-
"./http/pikku-http-abstract-request": "./dist/http/pikku-http-abstract-request.js",
|
|
28
26
|
"./errors": "./dist/errors/index.js",
|
|
29
27
|
"./scheduler": "./dist/scheduler/index.js",
|
|
30
28
|
"./services": "./dist/services/index.js",
|
|
@@ -35,7 +33,8 @@
|
|
|
35
33
|
"@types/cookie": "^0.6.0",
|
|
36
34
|
"@types/uuid": "^10.0.0",
|
|
37
35
|
"cookie": "^1.0.1",
|
|
38
|
-
"path-to-regexp": "^8.2.0"
|
|
36
|
+
"path-to-regexp": "^8.2.0",
|
|
37
|
+
"picoquery": "^2.4.0"
|
|
39
38
|
},
|
|
40
39
|
"devDependencies": {
|
|
41
40
|
"@types/node": "^22.7.8",
|
|
@@ -4,38 +4,62 @@ import {
|
|
|
4
4
|
JSONValue,
|
|
5
5
|
CoreUserSession,
|
|
6
6
|
} from '../types/core.types.js'
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
ChannelMessageMeta,
|
|
9
|
+
CoreAPIChannel,
|
|
10
|
+
PikkuChannelHandler,
|
|
11
|
+
} from './channel.types.js'
|
|
8
12
|
import { verifyPermissions } from '../permissions.js'
|
|
9
13
|
import { pikkuState } from '../pikku-state.js'
|
|
10
14
|
|
|
11
|
-
const
|
|
12
|
-
logger: CoreSingletonServices['logger'],
|
|
13
|
-
data: JSONValue,
|
|
15
|
+
const getRouteMeta = (
|
|
14
16
|
channelName: string,
|
|
15
17
|
routingProperty?: string,
|
|
16
18
|
routerValue?: string
|
|
17
|
-
) => {
|
|
19
|
+
): ChannelMessageMeta => {
|
|
18
20
|
const channelsMeta = pikkuState('channel', 'meta')
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// validateJson(schemaNames, data)
|
|
29
|
-
}
|
|
30
|
-
return
|
|
31
|
-
}
|
|
21
|
+
const channelMeta = channelsMeta.find(
|
|
22
|
+
(channelMeta) => channelMeta.name === channelName
|
|
23
|
+
)
|
|
24
|
+
if (!channelMeta) {
|
|
25
|
+
throw new Error(`Channel ${channelName} not found`)
|
|
26
|
+
}
|
|
27
|
+
if (!routingProperty) {
|
|
28
|
+
if (!channelMeta.message) {
|
|
29
|
+
throw new Error(`Channel ${channelName} has no default message route`)
|
|
32
30
|
}
|
|
31
|
+
return channelMeta.message
|
|
32
|
+
}
|
|
33
|
+
if (!routerValue) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Channel ${channelName} requires a router value for ${routingProperty}`
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
const route = channelMeta.messageRoutes[routingProperty]?.[routerValue]
|
|
39
|
+
if (!route) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Channel ${channelName} has no route for ${routingProperty}:${routerValue}`
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
return route
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const validateSchema = (
|
|
48
|
+
logger: CoreSingletonServices['logger'],
|
|
49
|
+
data: JSONValue,
|
|
50
|
+
channelRoute: ChannelMessageMeta
|
|
51
|
+
) => {
|
|
52
|
+
const schemaNames = channelRoute.inputs
|
|
53
|
+
if (schemaNames) {
|
|
54
|
+
// TODO
|
|
55
|
+
// loadSchema(schemaNames, logger)
|
|
56
|
+
// validateJson(schemaNames, data)
|
|
33
57
|
}
|
|
34
58
|
}
|
|
35
59
|
|
|
36
60
|
const validateAuth = (
|
|
37
61
|
requiresSession: boolean,
|
|
38
|
-
|
|
62
|
+
session: CoreUserSession | undefined,
|
|
39
63
|
onMessage: any
|
|
40
64
|
) => {
|
|
41
65
|
const auth =
|
|
@@ -45,7 +69,7 @@ const validateAuth = (
|
|
|
45
69
|
? requiresSession
|
|
46
70
|
: onMessage.auth
|
|
47
71
|
|
|
48
|
-
if (auth && !
|
|
72
|
+
if (auth && !session) {
|
|
49
73
|
return false
|
|
50
74
|
}
|
|
51
75
|
return true
|
|
@@ -53,27 +77,41 @@ const validateAuth = (
|
|
|
53
77
|
|
|
54
78
|
const validatePermissions = async (
|
|
55
79
|
services: CoreServices,
|
|
56
|
-
|
|
80
|
+
session: CoreUserSession | undefined,
|
|
57
81
|
onMessage: any,
|
|
58
82
|
data: unknown
|
|
59
83
|
) => {
|
|
60
84
|
const permissions =
|
|
61
85
|
typeof onMessage === 'function' ? {} : onMessage.permissions
|
|
62
|
-
return await verifyPermissions(permissions, services, data,
|
|
86
|
+
return await verifyPermissions(permissions, services, data, session)
|
|
63
87
|
}
|
|
64
88
|
|
|
65
89
|
const runFunction = async (
|
|
66
90
|
services: CoreServices,
|
|
67
91
|
channelHandler: PikkuChannelHandler,
|
|
92
|
+
channelMessageMeta: ChannelMessageMeta,
|
|
93
|
+
session: CoreUserSession | undefined,
|
|
68
94
|
onMessage: any,
|
|
69
95
|
data: unknown
|
|
70
96
|
) => {
|
|
71
97
|
const func: any = typeof onMessage === 'function' ? onMessage : onMessage.func
|
|
72
|
-
|
|
98
|
+
if (channelMessageMeta.type?.toLowerCase().includes('function')) {
|
|
99
|
+
return await func(
|
|
100
|
+
{
|
|
101
|
+
...services,
|
|
102
|
+
channel: channelHandler.getChannel(),
|
|
103
|
+
},
|
|
104
|
+
data,
|
|
105
|
+
session
|
|
106
|
+
)
|
|
107
|
+
} else {
|
|
108
|
+
return await func(services, channelHandler.getChannel(), data)
|
|
109
|
+
}
|
|
73
110
|
}
|
|
74
111
|
|
|
75
112
|
export const processMessageHandlers = (
|
|
76
113
|
services: CoreServices,
|
|
114
|
+
session: CoreUserSession | undefined,
|
|
77
115
|
channelConfig: CoreAPIChannel<any, any>,
|
|
78
116
|
channelHandler: PikkuChannelHandler
|
|
79
117
|
) => {
|
|
@@ -83,6 +121,7 @@ export const processMessageHandlers = (
|
|
|
83
121
|
const processMessage = async (
|
|
84
122
|
data: JSONValue,
|
|
85
123
|
onMessage: any,
|
|
124
|
+
session: CoreUserSession | undefined,
|
|
86
125
|
routingProperty?: string,
|
|
87
126
|
routerValue?: string
|
|
88
127
|
): Promise<unknown> => {
|
|
@@ -98,14 +137,16 @@ export const processMessageHandlers = (
|
|
|
98
137
|
return
|
|
99
138
|
}
|
|
100
139
|
|
|
101
|
-
|
|
102
|
-
services.logger,
|
|
103
|
-
data,
|
|
140
|
+
const routeMeta = getRouteMeta(
|
|
104
141
|
channelConfig.name,
|
|
105
142
|
routingProperty,
|
|
106
143
|
routerValue
|
|
107
144
|
)
|
|
108
145
|
|
|
146
|
+
if (routeMeta) {
|
|
147
|
+
validateSchema(services.logger, data, routeMeta)
|
|
148
|
+
}
|
|
149
|
+
|
|
109
150
|
const hasPermission = await validatePermissions(
|
|
110
151
|
services,
|
|
111
152
|
channelHandler,
|
|
@@ -118,7 +159,14 @@ export const processMessageHandlers = (
|
|
|
118
159
|
)
|
|
119
160
|
}
|
|
120
161
|
|
|
121
|
-
return await runFunction(
|
|
162
|
+
return await runFunction(
|
|
163
|
+
services,
|
|
164
|
+
channelHandler,
|
|
165
|
+
routeMeta,
|
|
166
|
+
session,
|
|
167
|
+
onMessage,
|
|
168
|
+
data
|
|
169
|
+
)
|
|
122
170
|
}
|
|
123
171
|
|
|
124
172
|
const onMessage = async (rawData): Promise<unknown> => {
|
|
@@ -137,6 +185,7 @@ export const processMessageHandlers = (
|
|
|
137
185
|
result = await processMessage(
|
|
138
186
|
messageData,
|
|
139
187
|
routes[routerValue],
|
|
188
|
+
session,
|
|
140
189
|
routingProperty,
|
|
141
190
|
routerValue
|
|
142
191
|
)
|
|
@@ -147,7 +196,11 @@ export const processMessageHandlers = (
|
|
|
147
196
|
// Default handler if no routes matched but json data was parsed
|
|
148
197
|
if (!processed && channelConfig.onMessage) {
|
|
149
198
|
processed = true
|
|
150
|
-
result = await processMessage(
|
|
199
|
+
result = await processMessage(
|
|
200
|
+
messageData,
|
|
201
|
+
channelConfig.onMessage,
|
|
202
|
+
session
|
|
203
|
+
)
|
|
151
204
|
}
|
|
152
205
|
} catch (error) {
|
|
153
206
|
// Most likely a json error.. ignore
|
|
@@ -157,7 +210,7 @@ export const processMessageHandlers = (
|
|
|
157
210
|
// Default handler if no routes matched and json data wasn't parsed
|
|
158
211
|
if (!processed && channelConfig.onMessage) {
|
|
159
212
|
processed = true
|
|
160
|
-
result = await processMessage(rawData, channelConfig.onMessage)
|
|
213
|
+
result = await processMessage(rawData, channelConfig.onMessage, session)
|
|
161
214
|
}
|
|
162
215
|
|
|
163
216
|
if (!processed) {
|
|
@@ -57,10 +57,10 @@ export const openChannel = async ({
|
|
|
57
57
|
route,
|
|
58
58
|
singletonServices,
|
|
59
59
|
coerceToArray = false,
|
|
60
|
-
|
|
60
|
+
request,
|
|
61
61
|
}: Pick<CoreAPIChannel<unknown, string>, 'route'> &
|
|
62
|
-
|
|
63
|
-
userSessionService
|
|
62
|
+
RunChannelParams<unknown> & {
|
|
63
|
+
userSessionService: UserSessionService<any>
|
|
64
64
|
} & RunChannelOptions): Promise<{
|
|
65
65
|
openingData: unknown
|
|
66
66
|
channelConfig: CoreAPIChannel<unknown, any>
|
|
@@ -74,15 +74,15 @@ export const openChannel = async ({
|
|
|
74
74
|
const { params, channelConfig, schemaName } = matchingChannel
|
|
75
75
|
|
|
76
76
|
const requiresSession = channelConfig.auth !== false
|
|
77
|
-
|
|
77
|
+
request?.setParams(params)
|
|
78
78
|
|
|
79
79
|
singletonServices.logger.info(
|
|
80
80
|
`Matched channel: ${channelConfig.name} | route: ${channelConfig.route} | auth: ${requiresSession.toString()}`
|
|
81
81
|
)
|
|
82
82
|
|
|
83
83
|
let openingData: any | undefined
|
|
84
|
-
if (
|
|
85
|
-
openingData = await
|
|
84
|
+
if (request) {
|
|
85
|
+
openingData = await request.data()
|
|
86
86
|
if (coerceToArray && schemaName) {
|
|
87
87
|
coerceQueryStringToArray(schemaName, openingData)
|
|
88
88
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { PikkuError } from '../errors/error-handler.js'
|
|
2
2
|
import {
|
|
3
3
|
HTTPFunctionMetaInputTypes,
|
|
4
|
-
|
|
4
|
+
PikkuHTTPRequest,
|
|
5
|
+
PikkuHTTPResponse,
|
|
5
6
|
} from '../http/http-routes.types.js'
|
|
6
|
-
import { PikkuHTTPAbstractRequest } from '../http/pikku-http-abstract-request.js'
|
|
7
|
-
import { PikkuHTTPAbstractResponse } from '../http/pikku-http-abstract-response.js'
|
|
8
7
|
import {
|
|
9
8
|
APIDocs,
|
|
10
9
|
CoreServices,
|
|
@@ -12,9 +11,7 @@ import {
|
|
|
12
11
|
CreateSessionServices,
|
|
13
12
|
PikkuMiddleware,
|
|
14
13
|
} from '../types/core.types.js'
|
|
15
|
-
import { CoreAPIPermission } from '../types/functions.types.js'
|
|
16
|
-
import { PikkuRequest } from '../pikku-request.js'
|
|
17
|
-
import { PikkuResponse } from '../pikku-response.js'
|
|
14
|
+
import { CoreAPIFunction, CoreAPIPermission } from '../types/functions.types.js'
|
|
18
15
|
|
|
19
16
|
export type RunChannelOptions = Partial<{
|
|
20
17
|
skipUserSession: boolean
|
|
@@ -27,13 +24,17 @@ export type RunChannelOptions = Partial<{
|
|
|
27
24
|
export type RunChannelParams<ChannelData> = {
|
|
28
25
|
channelId: string
|
|
29
26
|
singletonServices: CoreSingletonServices
|
|
30
|
-
request?:
|
|
31
|
-
response?:
|
|
32
|
-
http?: PikkuHTTP
|
|
27
|
+
request?: PikkuHTTPRequest<ChannelData>
|
|
28
|
+
response?: PikkuHTTPResponse
|
|
33
29
|
createSessionServices?: CreateSessionServices
|
|
34
30
|
}
|
|
35
31
|
|
|
36
|
-
export interface
|
|
32
|
+
export interface ChannelMessageMeta {
|
|
33
|
+
inputs: string[] | null
|
|
34
|
+
outputs: string[] | null
|
|
35
|
+
docs?: APIDocs
|
|
36
|
+
type: null | string
|
|
37
|
+
}
|
|
37
38
|
|
|
38
39
|
export interface ChannelMeta {
|
|
39
40
|
name: string
|
|
@@ -44,17 +45,8 @@ export interface ChannelMeta {
|
|
|
44
45
|
inputTypes?: HTTPFunctionMetaInputTypes
|
|
45
46
|
connect: boolean
|
|
46
47
|
disconnect: boolean
|
|
47
|
-
message:
|
|
48
|
-
messageRoutes: Record<
|
|
49
|
-
string,
|
|
50
|
-
Record<
|
|
51
|
-
string,
|
|
52
|
-
{
|
|
53
|
-
inputs: string[] | null
|
|
54
|
-
outputs: string[] | null
|
|
55
|
-
}
|
|
56
|
-
>
|
|
57
|
-
>
|
|
48
|
+
message: ChannelMessageMeta | null
|
|
49
|
+
messageRoutes: Record<string, Record<string, ChannelMessageMeta>>
|
|
58
50
|
docs?: APIDocs
|
|
59
51
|
tags?: string[]
|
|
60
52
|
}
|
|
@@ -108,8 +100,12 @@ export type CoreAPIChannel<
|
|
|
108
100
|
Channel extends string,
|
|
109
101
|
ChannelFunctionConnection = CoreChannelConnection<ChannelData>,
|
|
110
102
|
ChannelFunctionDisconnection = CoreChannelDisconnection<ChannelData>,
|
|
111
|
-
ChannelFunctionDefaultMessage =
|
|
112
|
-
|
|
103
|
+
ChannelFunctionDefaultMessage =
|
|
104
|
+
| CoreChannelMessage<unknown, unknown, unknown>
|
|
105
|
+
| CoreAPIFunction<unknown, unknown>,
|
|
106
|
+
ChannelFunctionMessageRoute =
|
|
107
|
+
| CoreChannelMessage<unknown, unknown, unknown>
|
|
108
|
+
| CoreAPIFunction<unknown, unknown>,
|
|
113
109
|
APIPermission = CoreAPIPermission<ChannelData>,
|
|
114
110
|
> = {
|
|
115
111
|
name: string
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { test, beforeEach, afterEach } from 'node:test'
|
|
2
2
|
import * as assert from 'node:assert/strict'
|
|
3
|
-
import { JSONValue } from '../../types/core.types.js'
|
|
4
|
-
import { PikkuHTTPAbstractRequest } from '../../http/pikku-http-abstract-request.js'
|
|
5
|
-
import { PikkuHTTPAbstractResponse } from '../../http/pikku-http-abstract-response.js'
|
|
6
3
|
import { runLocalChannel } from './local-channel-runner.js'
|
|
7
4
|
import { resetPikkuState } from '../../pikku-state.js'
|
|
8
5
|
import { addChannel } from '../channel-runner.js'
|
|
6
|
+
import {
|
|
7
|
+
HTTPMethod,
|
|
8
|
+
PikkuHTTPRequest,
|
|
9
|
+
PikkuHTTPResponse,
|
|
10
|
+
PikkuQuery,
|
|
11
|
+
} from '../../http/http-routes.types.js'
|
|
12
|
+
import { SerializeOptions } from 'cookie'
|
|
9
13
|
|
|
10
14
|
/**
|
|
11
15
|
* Minimal stubs for dependencies that runChannel expects.
|
|
@@ -24,29 +28,69 @@ const mockSingletonServices = {
|
|
|
24
28
|
} as any
|
|
25
29
|
|
|
26
30
|
// Mock request and response objects
|
|
27
|
-
class
|
|
28
|
-
|
|
31
|
+
export class PikkuMockRequest implements PikkuHTTPRequest {
|
|
32
|
+
private _params: Record<string, string | string[] | undefined> = {}
|
|
33
|
+
|
|
34
|
+
constructor(
|
|
35
|
+
private _route: string,
|
|
36
|
+
private _method: HTTPMethod
|
|
37
|
+
) {}
|
|
38
|
+
|
|
39
|
+
method(): HTTPMethod {
|
|
40
|
+
return this._method
|
|
41
|
+
}
|
|
42
|
+
path(): string {
|
|
43
|
+
return this._route
|
|
44
|
+
}
|
|
45
|
+
json(): Promise<unknown> {
|
|
46
|
+
throw new Error('Method not implemented.')
|
|
47
|
+
}
|
|
48
|
+
arrayBuffer(): Promise<ArrayBuffer> {
|
|
29
49
|
throw new Error('Method not implemented.')
|
|
30
50
|
}
|
|
31
|
-
|
|
51
|
+
header(headerName: string): string | null {
|
|
52
|
+
throw new Error('Method not implemented.')
|
|
53
|
+
}
|
|
54
|
+
cookie(name?: string): string | null {
|
|
55
|
+
throw new Error('Method not implemented.')
|
|
56
|
+
}
|
|
57
|
+
params(): Partial<Record<string, string | string[]>> {
|
|
58
|
+
return this._params
|
|
59
|
+
}
|
|
60
|
+
setParams(params: Record<string, string | string[] | undefined>): void {
|
|
61
|
+
this._params = params
|
|
62
|
+
}
|
|
63
|
+
query(): PikkuQuery {
|
|
32
64
|
throw new Error('Method not implemented.')
|
|
33
65
|
}
|
|
34
|
-
public async
|
|
66
|
+
public async data() {
|
|
35
67
|
return { test: 'data' }
|
|
36
68
|
}
|
|
37
69
|
}
|
|
38
70
|
|
|
39
|
-
class
|
|
40
|
-
public
|
|
41
|
-
|
|
71
|
+
export class PikkuMockResponse implements PikkuHTTPResponse {
|
|
72
|
+
public _status: number | undefined
|
|
73
|
+
|
|
74
|
+
status(code: number): this {
|
|
75
|
+
this._status = code
|
|
76
|
+
return this
|
|
77
|
+
}
|
|
42
78
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
public setStatus(code) {
|
|
46
|
-
this.statusSet = code
|
|
79
|
+
cookie(name: string, value: string | null, options: SerializeOptions): this {
|
|
80
|
+
throw new Error('Method not implemented.')
|
|
47
81
|
}
|
|
48
|
-
|
|
49
|
-
|
|
82
|
+
header(name: string, value: string | string[]): this {
|
|
83
|
+
throw new Error('Method not implemented.')
|
|
84
|
+
}
|
|
85
|
+
arrayBuffer(data: XMLHttpRequestBodyInit): this {
|
|
86
|
+
throw new Error('Method not implemented.')
|
|
87
|
+
}
|
|
88
|
+
json(data: unknown): this {
|
|
89
|
+
// We don't need to implement this for our test
|
|
90
|
+
return this
|
|
91
|
+
}
|
|
92
|
+
redirect(location: string, status?: number): this {
|
|
93
|
+
throw new Error('Method not implemented.')
|
|
50
94
|
}
|
|
51
95
|
}
|
|
52
96
|
|
|
@@ -61,14 +105,13 @@ afterEach(() => {
|
|
|
61
105
|
})
|
|
62
106
|
|
|
63
107
|
test('runChannel should return undefined and 404 if no matching channel is found', async () => {
|
|
64
|
-
const mockResponse = new
|
|
108
|
+
const mockResponse = new PikkuMockResponse()
|
|
65
109
|
|
|
66
110
|
const result = await runLocalChannel({
|
|
67
111
|
singletonServices: mockSingletonServices,
|
|
68
112
|
channelId: 'test-channel-id',
|
|
69
|
-
request: new
|
|
113
|
+
request: new PikkuMockRequest('/non-existent-channel', 'get'),
|
|
70
114
|
response: mockResponse,
|
|
71
|
-
route: '/non-existent-channel',
|
|
72
115
|
createSessionServices: mockCreateSessionServices,
|
|
73
116
|
})
|
|
74
117
|
|
|
@@ -77,8 +120,8 @@ test('runChannel should return undefined and 404 if no matching channel is found
|
|
|
77
120
|
undefined,
|
|
78
121
|
'Should return undefined if no channel matches'
|
|
79
122
|
)
|
|
80
|
-
assert.equal(mockResponse.
|
|
81
|
-
assert.equal(mockResponse.
|
|
123
|
+
assert.equal(mockResponse._status, 404, 'Should set response status to 404')
|
|
124
|
+
// assert.equal(mockResponse._ended, true, 'Should end the response')
|
|
82
125
|
})
|
|
83
126
|
|
|
84
127
|
test('runChannel should return a channel handler if channel matches and no auth required', async () => {
|
|
@@ -100,12 +143,14 @@ test('runChannel should return a channel handler if channel matches and no auth
|
|
|
100
143
|
const result = await runLocalChannel({
|
|
101
144
|
singletonServices: singletonServicesWithPerm,
|
|
102
145
|
channelId: 'test-channel-id',
|
|
103
|
-
request: new
|
|
104
|
-
response: new
|
|
146
|
+
request: new PikkuMockRequest('/test-channel', 'get'),
|
|
147
|
+
response: new PikkuMockResponse(),
|
|
105
148
|
route: '/test-channel',
|
|
106
149
|
createSessionServices: mockCreateSessionServices,
|
|
107
150
|
})
|
|
108
151
|
|
|
152
|
+
console.log(result)
|
|
153
|
+
|
|
109
154
|
assert.ok(result, 'Should return a PikkuChannelHandler instance')
|
|
110
155
|
|
|
111
156
|
// Simulate opening the channel
|
|
@@ -11,7 +11,8 @@ import { PikkuLocalChannelHandler } from './local-channel-handler.js'
|
|
|
11
11
|
import { SessionServices } from '../../types/core.types.js'
|
|
12
12
|
import { handleError } from '../../handle-error.js'
|
|
13
13
|
import { runMiddleware } from '../../middleware-runner.js'
|
|
14
|
-
import {
|
|
14
|
+
import { PikkuUserSessionService } from '../../services/user-session-service.js'
|
|
15
|
+
import { PikkuHTTP } from '../../http/http-routes.types.js'
|
|
15
16
|
|
|
16
17
|
export const runLocalChannel = async ({
|
|
17
18
|
singletonServices,
|
|
@@ -25,14 +26,19 @@ export const runLocalChannel = async ({
|
|
|
25
26
|
coerceToArray = false,
|
|
26
27
|
logWarningsForStatusCodes = [],
|
|
27
28
|
bubbleErrors = false,
|
|
28
|
-
}: Pick<CoreAPIChannel<unknown, any>, 'route'
|
|
29
|
+
}: Partial<Pick<CoreAPIChannel<unknown, any>, 'route'>> &
|
|
29
30
|
RunChannelOptions &
|
|
30
31
|
RunChannelParams<unknown>): Promise<PikkuLocalChannelHandler | void> => {
|
|
31
32
|
let sessionServices: SessionServices<typeof singletonServices> | undefined
|
|
32
33
|
|
|
33
34
|
let channelHandler: PikkuLocalChannelHandler | undefined
|
|
34
|
-
const userSessionService = new
|
|
35
|
-
|
|
35
|
+
const userSessionService = new PikkuUserSessionService()
|
|
36
|
+
|
|
37
|
+
let http: PikkuHTTP | undefined
|
|
38
|
+
if (request) {
|
|
39
|
+
http = createHTTPInteraction(request, response)
|
|
40
|
+
route = http?.request?.path()
|
|
41
|
+
}
|
|
36
42
|
|
|
37
43
|
const main = async () => {
|
|
38
44
|
try {
|
|
@@ -40,11 +46,13 @@ export const runLocalChannel = async ({
|
|
|
40
46
|
channelId,
|
|
41
47
|
createSessionServices,
|
|
42
48
|
respondWith404,
|
|
43
|
-
|
|
49
|
+
request,
|
|
50
|
+
response,
|
|
44
51
|
route,
|
|
45
52
|
singletonServices,
|
|
46
53
|
skipUserSession,
|
|
47
54
|
coerceToArray,
|
|
55
|
+
userSessionService,
|
|
48
56
|
})
|
|
49
57
|
|
|
50
58
|
channelHandler = new PikkuLocalChannelHandler(
|
|
@@ -53,14 +61,15 @@ export const runLocalChannel = async ({
|
|
|
53
61
|
openingData
|
|
54
62
|
)
|
|
55
63
|
const channel = channelHandler.getChannel()
|
|
56
|
-
const
|
|
64
|
+
const session = await userSessionService.get()
|
|
57
65
|
if (createSessionServices) {
|
|
58
66
|
sessionServices = await createSessionServices(
|
|
59
67
|
singletonServices,
|
|
60
68
|
{ http },
|
|
61
|
-
|
|
69
|
+
session
|
|
62
70
|
)
|
|
63
71
|
}
|
|
72
|
+
|
|
64
73
|
const allServices = {
|
|
65
74
|
...singletonServices,
|
|
66
75
|
...sessionServices,
|
|
@@ -79,7 +88,12 @@ export const runLocalChannel = async ({
|
|
|
79
88
|
})
|
|
80
89
|
|
|
81
90
|
channelHandler.registerOnMessage(
|
|
82
|
-
processMessageHandlers(
|
|
91
|
+
processMessageHandlers(
|
|
92
|
+
allServices,
|
|
93
|
+
session,
|
|
94
|
+
channelConfig,
|
|
95
|
+
channelHandler
|
|
96
|
+
)
|
|
83
97
|
)
|
|
84
98
|
} catch (e: any) {
|
|
85
99
|
handleError(
|
|
@@ -101,7 +115,7 @@ export const runLocalChannel = async ({
|
|
|
101
115
|
await runMiddleware(
|
|
102
116
|
{
|
|
103
117
|
...singletonServices,
|
|
104
|
-
|
|
118
|
+
userSessionService,
|
|
105
119
|
},
|
|
106
120
|
{ http },
|
|
107
121
|
route.middleware || [],
|
|
@@ -11,9 +11,11 @@ import type {
|
|
|
11
11
|
import { createHTTPInteraction } from '../../http/http-route-runner.js'
|
|
12
12
|
import { ChannelStore } from '../channel-store.js'
|
|
13
13
|
import { handleError } from '../../handle-error.js'
|
|
14
|
-
import {
|
|
14
|
+
import { PikkuUserSessionService } from '../../services/user-session-service.js'
|
|
15
15
|
import { runMiddleware } from '../../middleware-runner.js'
|
|
16
16
|
import { pikkuState } from '../../pikku-state.js'
|
|
17
|
+
import { PikkuFetchHTTPRequest } from '../../http/pikku-fetch-http-request.js'
|
|
18
|
+
import { PikkuHTTP } from '../../http/http-routes.types.js'
|
|
17
19
|
|
|
18
20
|
export interface RunServerlessChannelParams<ChannelData>
|
|
19
21
|
extends RunChannelParams<ChannelData> {
|
|
@@ -70,8 +72,13 @@ export const runChannelConnect = async ({
|
|
|
70
72
|
RunChannelOptions &
|
|
71
73
|
RunServerlessChannelParams<unknown>) => {
|
|
72
74
|
let sessionServices: SessionServices | undefined
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
|
|
76
|
+
let http: PikkuHTTP | undefined
|
|
77
|
+
if (request instanceof Request) {
|
|
78
|
+
http = createHTTPInteraction(new PikkuFetchHTTPRequest(request), response)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const userSessionService = new PikkuUserSessionService(
|
|
75
82
|
channelStore,
|
|
76
83
|
channelId
|
|
77
84
|
)
|
|
@@ -79,10 +86,11 @@ export const runChannelConnect = async ({
|
|
|
79
86
|
const { channelConfig, openingData } = await openChannel({
|
|
80
87
|
channelId,
|
|
81
88
|
createSessionServices,
|
|
82
|
-
|
|
89
|
+
request,
|
|
83
90
|
route,
|
|
84
91
|
singletonServices,
|
|
85
92
|
coerceToArray,
|
|
93
|
+
userSessionService,
|
|
86
94
|
})
|
|
87
95
|
|
|
88
96
|
const main = async () => {
|
|
@@ -109,7 +117,7 @@ export const runChannelConnect = async ({
|
|
|
109
117
|
{ ...singletonServices, ...sessionServices },
|
|
110
118
|
channel
|
|
111
119
|
)
|
|
112
|
-
http?.response?.
|
|
120
|
+
http?.response?.status(101)
|
|
113
121
|
} catch (e: any) {
|
|
114
122
|
handleError(
|
|
115
123
|
e,
|
|
@@ -130,7 +138,7 @@ export const runChannelConnect = async ({
|
|
|
130
138
|
await runMiddleware(
|
|
131
139
|
{
|
|
132
140
|
...singletonServices,
|
|
133
|
-
|
|
141
|
+
userSessionService,
|
|
134
142
|
},
|
|
135
143
|
{ http },
|
|
136
144
|
channelConfig.middleware || [],
|
|
@@ -190,6 +198,7 @@ export const runChannelMessage = async (
|
|
|
190
198
|
try {
|
|
191
199
|
const onMessage = processMessageHandlers(
|
|
192
200
|
{ ...singletonServices, ...sessionServices },
|
|
201
|
+
session,
|
|
193
202
|
channelConfig,
|
|
194
203
|
channelHandler
|
|
195
204
|
)
|
package/src/handle-error.ts
CHANGED
|
@@ -32,8 +32,8 @@ export const handleError = (
|
|
|
32
32
|
const errorResponse = getErrorResponse(e)
|
|
33
33
|
if (errorResponse != null) {
|
|
34
34
|
// Set status and response body
|
|
35
|
-
http?.response?.
|
|
36
|
-
http?.response?.
|
|
35
|
+
http?.response?.status(errorResponse.status)
|
|
36
|
+
http?.response?.json({
|
|
37
37
|
message: errorResponse.message,
|
|
38
38
|
payload: (e as any).payload,
|
|
39
39
|
traceId: trackerId,
|
|
@@ -49,23 +49,25 @@ export const handleError = (
|
|
|
49
49
|
} else {
|
|
50
50
|
// Handle unexpected errors
|
|
51
51
|
logger.error(e)
|
|
52
|
-
http?.response?.
|
|
52
|
+
http?.response?.status(500)
|
|
53
53
|
|
|
54
54
|
if (trackerId) {
|
|
55
55
|
logger.warn(`Error id: ${trackerId}`)
|
|
56
|
-
http?.response?.
|
|
56
|
+
http?.response?.json({ errorId: trackerId })
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
// Handle 404 errors specifically
|
|
61
61
|
if (e instanceof NotFoundError) {
|
|
62
|
-
|
|
62
|
+
// TODO
|
|
63
|
+
// http?.response?.end()
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
// Either bubble up or end the response
|
|
66
67
|
if (bubbleError) {
|
|
67
68
|
throw e
|
|
68
69
|
} else {
|
|
69
|
-
|
|
70
|
+
// TODO
|
|
71
|
+
// http?.response?.end()
|
|
70
72
|
}
|
|
71
73
|
}
|