@pikku/core 0.6.12 → 0.6.14
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 +13 -0
- package/dist/channel/channel-handler.d.ts +2 -2
- package/dist/channel/channel-handler.js +4 -4
- package/dist/channel/channel-runner.d.ts +5 -4
- package/dist/channel/channel-runner.js +8 -14
- package/dist/channel/channel.types.d.ts +11 -18
- package/dist/channel/local/local-channel-handler.d.ts +1 -3
- package/dist/channel/local/local-channel-handler.js +0 -3
- package/dist/channel/local/local-channel-runner.js +49 -33
- package/dist/channel/pikku-abstract-channel-handler.d.ts +4 -7
- package/dist/channel/pikku-abstract-channel-handler.js +1 -5
- package/dist/channel/serverless/serverless-channel-runner.js +45 -38
- package/dist/handle-error.d.ts +14 -0
- package/dist/handle-error.js +53 -0
- package/dist/http/http-route-runner.d.ts +34 -11
- package/dist/http/http-route-runner.js +177 -106
- package/dist/http/http-routes.types.d.ts +15 -9
- package/dist/http/index.d.ts +0 -1
- package/dist/http/index.js +0 -1
- package/dist/http/pikku-http-abstract-request.d.ts +4 -1
- package/dist/http/pikku-http-abstract-request.js +7 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/middleware/auth-api-key.d.ts +9 -0
- package/dist/middleware/auth-api-key.js +23 -0
- package/dist/middleware/auth-cookie-middleware.d.ts +11 -0
- package/dist/middleware/auth-cookie-middleware.js +36 -0
- package/dist/middleware/auth-jwt-middleware.d.ts +10 -0
- package/dist/middleware/auth-jwt-middleware.js +32 -0
- package/dist/middleware/auth-query-middleware.d.ts +10 -0
- package/dist/middleware/auth-query-middleware.js +21 -0
- package/dist/middleware/index.d.ts +4 -0
- package/dist/middleware/index.js +4 -0
- package/dist/middleware-runner.d.ts +22 -0
- package/dist/middleware-runner.js +28 -0
- package/dist/scheduler/scheduler.types.d.ts +2 -0
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +3 -6
- package/dist/services/user-session-service.d.ts +20 -3
- package/dist/services/user-session-service.js +35 -1
- package/dist/types/core.types.d.ts +11 -15
- package/dist/types/functions.types.d.ts +4 -4
- package/lcov.info +1572 -1729
- package/package.json +1 -2
- package/src/channel/channel-handler.ts +6 -11
- package/src/channel/channel-runner.ts +13 -32
- package/src/channel/channel.types.ts +13 -39
- package/src/channel/local/local-channel-handler.ts +1 -7
- package/src/channel/local/local-channel-runner.test.ts +2 -5
- package/src/channel/local/local-channel-runner.ts +72 -54
- package/src/channel/pikku-abstract-channel-handler.test.ts +3 -28
- package/src/channel/pikku-abstract-channel-handler.ts +3 -9
- package/src/channel/serverless/serverless-channel-runner.ts +68 -56
- package/src/handle-error.ts +67 -0
- package/src/http/http-route-runner.test.ts +12 -45
- package/src/http/http-route-runner.ts +256 -182
- package/src/http/http-routes.types.ts +15 -10
- package/src/http/index.ts +0 -2
- package/src/http/pikku-http-abstract-request.ts +8 -1
- package/src/index.ts +2 -0
- package/src/middleware/auth-api-key.ts +32 -0
- package/src/middleware/auth-cookie-middleware.ts +54 -0
- package/src/middleware/auth-jwt-middleware.ts +47 -0
- package/src/middleware/auth-query-middleware.ts +33 -0
- package/src/middleware/index.ts +4 -0
- package/src/middleware-runner.ts +43 -0
- package/src/scheduler/scheduler.types.ts +2 -0
- package/src/schema.ts +4 -8
- package/src/services/user-session-service.ts +45 -3
- package/src/types/core.types.ts +19 -18
- package/src/types/functions.types.ts +11 -7
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/http/http-session-service.d.ts +0 -15
- package/dist/http/http-session-service.js +0 -1
- package/dist/http/pikku-http-session-service.d.ts +0 -45
- package/dist/http/pikku-http-session-service.js +0 -92
- package/src/http/http-session-service.ts +0 -19
- package/src/http/pikku-http-session-service.test.ts +0 -106
- package/src/http/pikku-http-session-service.ts +0 -135
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.14",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
"./channel/local": "./dist/channel/local/index.js",
|
|
23
23
|
"./channel/serverless": "./dist/channel/serverless/index.js",
|
|
24
24
|
"./http": "./dist/http/index.js",
|
|
25
|
-
"./http/pikku-http-session-service": "./dist/http/pikku-http-session-service.js",
|
|
26
25
|
"./http/pikku-http-abstract-response": "./dist/http/pikku-http-abstract-response.js",
|
|
27
26
|
"./http/pikku-http-abstract-request": "./dist/http/pikku-http-abstract-request.js",
|
|
28
27
|
"./errors": "./dist/errors/index.js",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CoreSingletonServices,
|
|
3
3
|
CoreServices,
|
|
4
|
-
CoreUserSession,
|
|
5
4
|
JSONValue,
|
|
5
|
+
CoreUserSession,
|
|
6
6
|
} from '../types/core.types.js'
|
|
7
7
|
import { CoreAPIChannel, PikkuChannelHandler } from './channel.types.js'
|
|
8
8
|
import { verifyPermissions } from '../permissions.js'
|
|
@@ -35,7 +35,7 @@ const validateSchema = (
|
|
|
35
35
|
|
|
36
36
|
const validateAuth = (
|
|
37
37
|
requiresSession: boolean,
|
|
38
|
-
|
|
38
|
+
userSession: CoreUserSession | undefined,
|
|
39
39
|
onMessage: any
|
|
40
40
|
) => {
|
|
41
41
|
const auth =
|
|
@@ -45,7 +45,7 @@ const validateAuth = (
|
|
|
45
45
|
? requiresSession
|
|
46
46
|
: onMessage.auth
|
|
47
47
|
|
|
48
|
-
if (auth && !
|
|
48
|
+
if (auth && !userSession) {
|
|
49
49
|
return false
|
|
50
50
|
}
|
|
51
51
|
return true
|
|
@@ -53,18 +53,13 @@ const validateAuth = (
|
|
|
53
53
|
|
|
54
54
|
const validatePermissions = async (
|
|
55
55
|
services: CoreServices,
|
|
56
|
-
|
|
56
|
+
userSession: CoreUserSession | undefined,
|
|
57
57
|
onMessage: any,
|
|
58
58
|
data: unknown
|
|
59
59
|
) => {
|
|
60
60
|
const permissions =
|
|
61
61
|
typeof onMessage === 'function' ? {} : onMessage.permissions
|
|
62
|
-
return await verifyPermissions(
|
|
63
|
-
permissions,
|
|
64
|
-
services,
|
|
65
|
-
data,
|
|
66
|
-
channelHandler.getChannel().userSession
|
|
67
|
-
)
|
|
62
|
+
return await verifyPermissions(permissions, services, data, userSession)
|
|
68
63
|
}
|
|
69
64
|
|
|
70
65
|
const runFunction = async (
|
|
@@ -80,7 +75,7 @@ const runFunction = async (
|
|
|
80
75
|
export const processMessageHandlers = (
|
|
81
76
|
services: CoreServices,
|
|
82
77
|
channelConfig: CoreAPIChannel<any, any>,
|
|
83
|
-
channelHandler: PikkuChannelHandler
|
|
78
|
+
channelHandler: PikkuChannelHandler
|
|
84
79
|
) => {
|
|
85
80
|
const logger = services.logger
|
|
86
81
|
const requiresSession = channelConfig.auth !== false
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { NotFoundError } from '../errors/errors.js'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { CoreUserSession } from '../types/core.types.js'
|
|
2
|
+
import { coerceQueryStringToArray, validateSchema } from '../schema.js'
|
|
3
|
+
import { UserSessionService } from '../services/user-session-service.js'
|
|
5
4
|
import {
|
|
6
5
|
CoreAPIChannel,
|
|
7
6
|
ChannelsMeta,
|
|
@@ -95,13 +94,13 @@ export const getMatchingChannelConfig = (request: string) => {
|
|
|
95
94
|
export const openChannel = async ({
|
|
96
95
|
route,
|
|
97
96
|
singletonServices,
|
|
98
|
-
skipUserSession = false,
|
|
99
97
|
coerceToArray = false,
|
|
100
98
|
http,
|
|
99
|
+
userSessionService,
|
|
101
100
|
}: Pick<CoreAPIChannel<unknown, string>, 'route'> &
|
|
102
|
-
Omit<RunChannelParams<unknown>, 'response' | 'request'> &
|
|
103
|
-
|
|
104
|
-
|
|
101
|
+
Omit<RunChannelParams<unknown>, 'response' | 'request'> & {
|
|
102
|
+
userSessionService?: UserSessionService<any>
|
|
103
|
+
} & RunChannelOptions): Promise<{
|
|
105
104
|
openingData: unknown
|
|
106
105
|
channelConfig: CoreAPIChannel<unknown, any>
|
|
107
106
|
}> => {
|
|
@@ -111,7 +110,7 @@ export const openChannel = async ({
|
|
|
111
110
|
throw new NotFoundError(`Channel not found: ${route}`)
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
const {
|
|
113
|
+
const { params, channelConfig, schemaName } = matchingChannel
|
|
115
114
|
|
|
116
115
|
const requiresSession = channelConfig.auth !== false
|
|
117
116
|
http?.request?.setParams(params)
|
|
@@ -120,37 +119,19 @@ export const openChannel = async ({
|
|
|
120
119
|
`Matched channel: ${channelConfig.name} | route: ${channelConfig.route} | auth: ${requiresSession.toString()}`
|
|
121
120
|
)
|
|
122
121
|
|
|
123
|
-
const userSession = await loadUserSession(
|
|
124
|
-
skipUserSession,
|
|
125
|
-
// We may require a session, but we don't actually need it
|
|
126
|
-
// on connect since channels can authenticate later given
|
|
127
|
-
// how websocket sessions work (cookie or queryParam based)
|
|
128
|
-
false,
|
|
129
|
-
http,
|
|
130
|
-
matchedPath,
|
|
131
|
-
channelConfig,
|
|
132
|
-
singletonServices.logger,
|
|
133
|
-
singletonServices.httpSessionService
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
if (singletonServices.enforceChannelAccess) {
|
|
137
|
-
await singletonServices.enforceChannelAccess(
|
|
138
|
-
matchingChannel.channelConfig,
|
|
139
|
-
userSession
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
122
|
let openingData: any | undefined
|
|
144
123
|
if (http?.request) {
|
|
145
124
|
openingData = await http.request.getData()
|
|
146
|
-
|
|
125
|
+
if (coerceToArray && schemaName) {
|
|
126
|
+
coerceQueryStringToArray(schemaName, openingData)
|
|
127
|
+
}
|
|
128
|
+
validateSchema(
|
|
147
129
|
singletonServices.logger,
|
|
148
130
|
singletonServices.schemaService,
|
|
149
131
|
schemaName,
|
|
150
|
-
openingData
|
|
151
|
-
coerceToArray
|
|
132
|
+
openingData
|
|
152
133
|
)
|
|
153
134
|
}
|
|
154
135
|
|
|
155
|
-
return {
|
|
136
|
+
return { openingData, channelConfig }
|
|
156
137
|
}
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
APIDocs,
|
|
10
10
|
CoreServices,
|
|
11
11
|
CoreSingletonServices,
|
|
12
|
-
CoreUserSession,
|
|
13
12
|
CreateSessionServices,
|
|
13
|
+
PikkuMiddleware,
|
|
14
14
|
} from '../types/core.types.js'
|
|
15
15
|
import { CoreAPIPermission } from '../types/functions.types.js'
|
|
16
16
|
import { PikkuRequest } from '../pikku-request.js'
|
|
@@ -56,6 +56,7 @@ export interface ChannelMeta {
|
|
|
56
56
|
>
|
|
57
57
|
>
|
|
58
58
|
docs?: APIDocs
|
|
59
|
+
tags?: string[]
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
export type ChannelsMeta = ChannelMeta[]
|
|
@@ -64,19 +65,17 @@ export type CoreChannelConnection<
|
|
|
64
65
|
ChannelData,
|
|
65
66
|
Out = unknown,
|
|
66
67
|
Services extends CoreServices = CoreServices,
|
|
67
|
-
Session extends CoreUserSession = CoreUserSession,
|
|
68
68
|
> = (
|
|
69
69
|
services: Services,
|
|
70
|
-
channel: PikkuChannel<
|
|
70
|
+
channel: PikkuChannel<ChannelData, Out>
|
|
71
71
|
) => Promise<void>
|
|
72
72
|
|
|
73
73
|
export type CoreChannelDisconnection<
|
|
74
74
|
ChannelData,
|
|
75
75
|
Services extends CoreServices = CoreServices,
|
|
76
|
-
Session extends CoreUserSession = CoreUserSession,
|
|
77
76
|
> = (
|
|
78
77
|
services: Services,
|
|
79
|
-
channel: PikkuChannel<
|
|
78
|
+
channel: PikkuChannel<ChannelData, never>
|
|
80
79
|
) => Promise<void>
|
|
81
80
|
|
|
82
81
|
/**
|
|
@@ -91,10 +90,9 @@ export type CoreChannelMessage<
|
|
|
91
90
|
Out,
|
|
92
91
|
ChannelData,
|
|
93
92
|
Services extends CoreServices = CoreServices,
|
|
94
|
-
Session extends CoreUserSession = CoreUserSession,
|
|
95
93
|
> = (
|
|
96
94
|
services: Services,
|
|
97
|
-
channel: PikkuChannel<
|
|
95
|
+
channel: PikkuChannel<ChannelData, Out>,
|
|
98
96
|
data: In
|
|
99
97
|
) => Promise<void | Out>
|
|
100
98
|
|
|
@@ -137,6 +135,7 @@ export type CoreAPIChannel<
|
|
|
137
135
|
}
|
|
138
136
|
>
|
|
139
137
|
>
|
|
138
|
+
middleware?: PikkuMiddleware[]
|
|
140
139
|
permissions?: Record<string, APIPermission[] | APIPermission>
|
|
141
140
|
auth?: boolean
|
|
142
141
|
docs?: Partial<{
|
|
@@ -145,18 +144,14 @@ export type CoreAPIChannel<
|
|
|
145
144
|
errors: Array<typeof PikkuError>
|
|
146
145
|
tags: string[]
|
|
147
146
|
}>
|
|
147
|
+
tags?: string[]
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
export type CoreAPIChannels = CoreAPIChannel<any, string>[]
|
|
151
151
|
|
|
152
|
-
export interface PikkuChannel<
|
|
152
|
+
export interface PikkuChannel<OpeningData, Out> {
|
|
153
153
|
// The channel identifier
|
|
154
154
|
channelId: string
|
|
155
|
-
// The user session, if available
|
|
156
|
-
userSession?: UserSession
|
|
157
|
-
// Update the user session, useful if you deal with auth on the
|
|
158
|
-
// stream side
|
|
159
|
-
setUserSession: (userSession: UserSession) => Promise<void> | void
|
|
160
155
|
// The data the channel was created with. This could be query parameters
|
|
161
156
|
// or parameters in the url.
|
|
162
157
|
openingData: OpeningData
|
|
@@ -168,34 +163,13 @@ export interface PikkuChannel<UserSession, OpeningData, Out> {
|
|
|
168
163
|
state: 'initial' | 'open' | 'closed'
|
|
169
164
|
}
|
|
170
165
|
|
|
171
|
-
export interface PikkuChannelHandler<
|
|
172
|
-
UserSession extends CoreUserSession = CoreUserSession,
|
|
173
|
-
OpeningData = unknown,
|
|
174
|
-
Out = unknown,
|
|
175
|
-
> {
|
|
176
|
-
setUserSession(session: UserSession): Promise<void> | void
|
|
166
|
+
export interface PikkuChannelHandler<OpeningData = unknown, Out = unknown> {
|
|
177
167
|
send(message: Out, isBinary?: boolean): Promise<void> | void
|
|
178
|
-
getChannel(): PikkuChannel<
|
|
168
|
+
getChannel(): PikkuChannel<OpeningData, Out>
|
|
179
169
|
}
|
|
180
170
|
|
|
181
|
-
export type PikkuChannelHandlerFactory<
|
|
182
|
-
OpeningData = unknown,
|
|
183
|
-
UserSession extends CoreUserSession = CoreUserSession,
|
|
184
|
-
Out = unknown,
|
|
185
|
-
> = (
|
|
171
|
+
export type PikkuChannelHandlerFactory<OpeningData = unknown, Out = unknown> = (
|
|
186
172
|
channelId: string,
|
|
187
173
|
channelName: string,
|
|
188
|
-
openingData: OpeningData
|
|
189
|
-
|
|
190
|
-
) => PikkuChannelHandler<UserSession, OpeningData, Out>
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Enfore access to a channel.
|
|
194
|
-
* @param route - The channel to verify access for.
|
|
195
|
-
* @param session - The user session.
|
|
196
|
-
* @returns A promise that resolves if access is granted.
|
|
197
|
-
*/
|
|
198
|
-
export type enforceChannelAccess = (
|
|
199
|
-
channel: CoreAPIChannel<unknown, any>,
|
|
200
|
-
session?: CoreUserSession
|
|
201
|
-
) => Promise<void> | void
|
|
174
|
+
openingData: OpeningData
|
|
175
|
+
) => PikkuChannelHandler<OpeningData, Out>
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { CoreUserSession } from '../../types/core.types.js'
|
|
2
1
|
import { PikkuAbstractChannelHandler } from '../pikku-abstract-channel-handler.js'
|
|
3
2
|
|
|
4
3
|
export class PikkuLocalChannelHandler<
|
|
5
|
-
UserSession extends CoreUserSession = CoreUserSession,
|
|
6
4
|
OpeningData = unknown,
|
|
7
5
|
Out = unknown,
|
|
8
|
-
> extends PikkuAbstractChannelHandler<
|
|
6
|
+
> extends PikkuAbstractChannelHandler<OpeningData, Out> {
|
|
9
7
|
private onMessageCallback?: (message: unknown) => void
|
|
10
8
|
private openCallBack?: () => void
|
|
11
9
|
private closeCallback?: () => void
|
|
@@ -49,8 +47,4 @@ export class PikkuLocalChannelHandler<
|
|
|
49
47
|
}
|
|
50
48
|
return this.sendCallback?.(message, isBinary)
|
|
51
49
|
}
|
|
52
|
-
|
|
53
|
-
public setUserSession(userSession: UserSession): void {
|
|
54
|
-
this.getChannel().userSession = userSession
|
|
55
|
-
}
|
|
56
50
|
}
|
|
@@ -19,9 +19,6 @@ const mockLogger = {
|
|
|
19
19
|
|
|
20
20
|
const mockSingletonServices = {
|
|
21
21
|
logger: mockLogger,
|
|
22
|
-
// Provide a mock channelPermissionService only when needed
|
|
23
|
-
// e.g., channelPermissionService: { verifyChannelAccess: async () => {} },
|
|
24
|
-
httpSessionService: {},
|
|
25
22
|
} as any
|
|
26
23
|
|
|
27
24
|
// Mock request and response objects
|
|
@@ -79,7 +76,7 @@ test('runChannel should return undefined and 404 if no matching channel is found
|
|
|
79
76
|
const result = await runLocalChannel({
|
|
80
77
|
singletonServices: mockSingletonServices,
|
|
81
78
|
channelId: 'test-channel-id',
|
|
82
|
-
request: new MockRequest(),
|
|
79
|
+
request: new MockRequest('/non-existent-channel', 'get'),
|
|
83
80
|
response: mockResponse,
|
|
84
81
|
route: '/non-existent-channel',
|
|
85
82
|
createSessionServices: mockCreateSessionServices,
|
|
@@ -113,7 +110,7 @@ test('runChannel should return a channel handler if channel matches and no auth
|
|
|
113
110
|
const result = await runLocalChannel({
|
|
114
111
|
singletonServices: singletonServicesWithPerm,
|
|
115
112
|
channelId: 'test-channel-id',
|
|
116
|
-
request: new MockRequest(),
|
|
113
|
+
request: new MockRequest('/test-channel', 'get'),
|
|
117
114
|
response: new MockResponse(),
|
|
118
115
|
route: '/test-channel',
|
|
119
116
|
createSessionServices: mockCreateSessionServices,
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { openChannel } from '../channel-runner.js'
|
|
2
|
-
import {
|
|
3
|
-
createHTTPInteraction,
|
|
4
|
-
handleError,
|
|
5
|
-
} from '../../http/http-route-runner.js'
|
|
2
|
+
import { createHTTPInteraction } from '../../http/http-route-runner.js'
|
|
6
3
|
import { closeSessionServices } from '../../utils.js'
|
|
7
4
|
import { processMessageHandlers } from '../channel-handler.js'
|
|
8
5
|
import {
|
|
@@ -12,6 +9,9 @@ import {
|
|
|
12
9
|
} from '../channel.types.js'
|
|
13
10
|
import { PikkuLocalChannelHandler } from './local-channel-handler.js'
|
|
14
11
|
import { SessionServices } from '../../types/core.types.js'
|
|
12
|
+
import { handleError } from '../../handle-error.js'
|
|
13
|
+
import { runMiddleware } from '../../middleware-runner.js'
|
|
14
|
+
import { LocalUserSessionService } from '../../services/user-session-service.js'
|
|
15
15
|
|
|
16
16
|
export const runLocalChannel = async ({
|
|
17
17
|
singletonServices,
|
|
@@ -30,65 +30,83 @@ export const runLocalChannel = async ({
|
|
|
30
30
|
RunChannelParams<unknown>): Promise<PikkuLocalChannelHandler | void> => {
|
|
31
31
|
let sessionServices: SessionServices<typeof singletonServices> | undefined
|
|
32
32
|
|
|
33
|
+
let channelHandler: PikkuLocalChannelHandler | undefined
|
|
34
|
+
const userSessionService = new LocalUserSessionService()
|
|
33
35
|
const http = createHTTPInteraction(request, response)
|
|
34
|
-
try {
|
|
35
|
-
const { userSession, openingData, channelConfig } = await openChannel({
|
|
36
|
-
channelId,
|
|
37
|
-
createSessionServices,
|
|
38
|
-
respondWith404,
|
|
39
|
-
http,
|
|
40
|
-
route,
|
|
41
|
-
singletonServices,
|
|
42
|
-
skipUserSession,
|
|
43
|
-
coerceToArray,
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
const channelHandler = new PikkuLocalChannelHandler(
|
|
47
|
-
channelId,
|
|
48
|
-
channelConfig.name,
|
|
49
|
-
userSession,
|
|
50
|
-
openingData
|
|
51
|
-
)
|
|
52
|
-
const channel = channelHandler.getChannel()
|
|
53
36
|
|
|
54
|
-
|
|
55
|
-
|
|
37
|
+
const main = async () => {
|
|
38
|
+
try {
|
|
39
|
+
const { openingData, channelConfig } = await openChannel({
|
|
40
|
+
channelId,
|
|
41
|
+
createSessionServices,
|
|
42
|
+
respondWith404,
|
|
43
|
+
http,
|
|
44
|
+
route,
|
|
56
45
|
singletonServices,
|
|
57
|
-
|
|
58
|
-
|
|
46
|
+
skipUserSession,
|
|
47
|
+
coerceToArray,
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
channelHandler = new PikkuLocalChannelHandler(
|
|
51
|
+
channelId,
|
|
52
|
+
channelConfig.name,
|
|
53
|
+
openingData
|
|
59
54
|
)
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
const channel = channelHandler.getChannel()
|
|
56
|
+
const userSession = await userSessionService.get()
|
|
57
|
+
if (createSessionServices) {
|
|
58
|
+
sessionServices = await createSessionServices(
|
|
59
|
+
singletonServices,
|
|
60
|
+
{ http },
|
|
61
|
+
userSession
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
const allServices = {
|
|
65
|
+
...singletonServices,
|
|
66
|
+
...sessionServices,
|
|
67
|
+
userSessionService,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
channelHandler.registerOnOpen(() => {
|
|
71
|
+
channelConfig.onConnect?.(allServices, channel)
|
|
72
|
+
})
|
|
62
73
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
74
|
+
channelHandler.registerOnClose(async () => {
|
|
75
|
+
channelConfig.onDisconnect?.(allServices, channel)
|
|
76
|
+
if (sessionServices) {
|
|
77
|
+
await closeSessionServices(singletonServices.logger, sessionServices)
|
|
78
|
+
}
|
|
79
|
+
})
|
|
66
80
|
|
|
67
|
-
|
|
68
|
-
|
|
81
|
+
channelHandler.registerOnMessage(
|
|
82
|
+
processMessageHandlers(allServices, channelConfig, channelHandler)
|
|
83
|
+
)
|
|
84
|
+
} catch (e: any) {
|
|
85
|
+
handleError(
|
|
86
|
+
e,
|
|
87
|
+
http,
|
|
88
|
+
channelId,
|
|
89
|
+
singletonServices.logger,
|
|
90
|
+
logWarningsForStatusCodes,
|
|
91
|
+
respondWith404,
|
|
92
|
+
bubbleErrors
|
|
93
|
+
)
|
|
94
|
+
} finally {
|
|
69
95
|
if (sessionServices) {
|
|
70
96
|
await closeSessionServices(singletonServices.logger, sessionServices)
|
|
71
97
|
}
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
channelHandler.registerOnMessage(
|
|
75
|
-
processMessageHandlers(allServices, channelConfig, channelHandler)
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
return channelHandler
|
|
79
|
-
} catch (e: any) {
|
|
80
|
-
handleError(
|
|
81
|
-
e,
|
|
82
|
-
http,
|
|
83
|
-
channelId,
|
|
84
|
-
singletonServices.logger,
|
|
85
|
-
logWarningsForStatusCodes,
|
|
86
|
-
respondWith404,
|
|
87
|
-
bubbleErrors
|
|
88
|
-
)
|
|
89
|
-
} finally {
|
|
90
|
-
if (sessionServices) {
|
|
91
|
-
await closeSessionServices(singletonServices.logger, sessionServices)
|
|
92
98
|
}
|
|
93
99
|
}
|
|
100
|
+
|
|
101
|
+
await runMiddleware(
|
|
102
|
+
{
|
|
103
|
+
...singletonServices,
|
|
104
|
+
userSessionService,
|
|
105
|
+
},
|
|
106
|
+
{ http },
|
|
107
|
+
route.middleware || [],
|
|
108
|
+
main
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
return channelHandler!
|
|
94
112
|
}
|
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
import { test, beforeEach } from 'node:test'
|
|
2
2
|
import * as assert from 'node:assert/strict'
|
|
3
|
-
import { CoreUserSession } from '../types/core.types.js'
|
|
4
3
|
import { PikkuAbstractChannelHandler } from './pikku-abstract-channel-handler.js'
|
|
5
4
|
|
|
6
5
|
// A concrete implementation of the abstract class for testing
|
|
7
6
|
class TestChannelHandler extends PikkuAbstractChannelHandler<
|
|
8
|
-
CoreUserSession,
|
|
9
7
|
{ param: string },
|
|
10
8
|
{ msg: string }
|
|
11
9
|
> {
|
|
12
|
-
public async setUserSession(session: CoreUserSession): Promise<void> {
|
|
13
|
-
this.userSession = session
|
|
14
|
-
}
|
|
15
|
-
|
|
16
10
|
public async send(message: { msg: string }, isBinary = false): Promise<void> {
|
|
17
11
|
// Mock send implementation
|
|
18
12
|
}
|
|
@@ -21,12 +15,9 @@ class TestChannelHandler extends PikkuAbstractChannelHandler<
|
|
|
21
15
|
let handler: TestChannelHandler
|
|
22
16
|
|
|
23
17
|
beforeEach(() => {
|
|
24
|
-
handler = new TestChannelHandler(
|
|
25
|
-
'
|
|
26
|
-
|
|
27
|
-
undefined,
|
|
28
|
-
{ param: 'testParam' }
|
|
29
|
-
)
|
|
18
|
+
handler = new TestChannelHandler('test-channel-id', 'channel-name', {
|
|
19
|
+
param: 'testParam',
|
|
20
|
+
})
|
|
30
21
|
})
|
|
31
22
|
|
|
32
23
|
test('getChannel should return a channel with initial state', () => {
|
|
@@ -38,22 +29,6 @@ test('getChannel should return a channel with initial state', () => {
|
|
|
38
29
|
{ param: 'testParam' },
|
|
39
30
|
'Opening data should be accessible'
|
|
40
31
|
)
|
|
41
|
-
assert.equal(
|
|
42
|
-
channel.userSession,
|
|
43
|
-
undefined,
|
|
44
|
-
'Session should initially be undefined'
|
|
45
|
-
)
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
test('setUserSession should update the channel session', async () => {
|
|
49
|
-
const session = { userId: 'user123' } as CoreUserSession
|
|
50
|
-
await handler.setUserSession(session)
|
|
51
|
-
const channel = handler.getChannel()
|
|
52
|
-
assert.deepEqual(
|
|
53
|
-
channel.userSession,
|
|
54
|
-
session,
|
|
55
|
-
'Session should be updated correctly'
|
|
56
|
-
)
|
|
57
32
|
})
|
|
58
33
|
|
|
59
34
|
test('open should change channel state to open', () => {
|
|
@@ -1,31 +1,25 @@
|
|
|
1
|
-
import { CoreUserSession } from '../types/core.types.js'
|
|
2
1
|
import { PikkuChannel, PikkuChannelHandler } from './channel.types.js'
|
|
3
2
|
|
|
4
3
|
export abstract class PikkuAbstractChannelHandler<
|
|
5
|
-
UserSession extends CoreUserSession = CoreUserSession,
|
|
6
4
|
OpeningData = unknown,
|
|
7
5
|
Out = unknown,
|
|
8
|
-
> implements PikkuChannelHandler<
|
|
6
|
+
> implements PikkuChannelHandler<OpeningData, Out>
|
|
9
7
|
{
|
|
10
|
-
protected channel?: PikkuChannel<
|
|
8
|
+
protected channel?: PikkuChannel<OpeningData, Out>
|
|
11
9
|
|
|
12
10
|
constructor(
|
|
13
11
|
public channelId: string,
|
|
14
12
|
public channelName: string,
|
|
15
|
-
protected userSession: UserSession | undefined,
|
|
16
13
|
protected openingData: OpeningData
|
|
17
14
|
) {}
|
|
18
15
|
|
|
19
|
-
public abstract setUserSession(userSession: UserSession): Promise<void> | void
|
|
20
16
|
public abstract send(message: Out, isBinary?: boolean): Promise<void> | void
|
|
21
17
|
|
|
22
|
-
public getChannel(): PikkuChannel<
|
|
18
|
+
public getChannel(): PikkuChannel<OpeningData, Out> {
|
|
23
19
|
if (!this.channel) {
|
|
24
20
|
this.channel = {
|
|
25
21
|
channelId: this.channelId,
|
|
26
|
-
userSession: this.userSession,
|
|
27
22
|
openingData: this.openingData,
|
|
28
|
-
setUserSession: this.setUserSession.bind(this),
|
|
29
23
|
send: this.send.bind(this),
|
|
30
24
|
close: this.close.bind(this),
|
|
31
25
|
state: 'initial',
|