@pikku/core 0.6.16 → 0.6.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/channel/channel-handler.js +2 -2
- package/dist/channel/channel-runner.d.ts +2 -14
- package/dist/channel/channel-runner.js +5 -36
- package/dist/channel/channel-store.d.ts +9 -6
- package/dist/channel/index.d.ts +0 -1
- package/dist/channel/index.js +0 -1
- package/dist/channel/local/local-channel-runner.js +2 -2
- package/dist/channel/log-channels.js +2 -2
- package/dist/channel/serverless/serverless-channel-runner.js +8 -7
- package/dist/errors/error-handler.d.ts +1 -1
- package/dist/errors/error-handler.js +6 -14
- package/dist/errors/errors.d.ts +1 -1
- package/dist/errors/errors.js +2 -2
- package/dist/http/http-route-runner.d.ts +3 -23
- package/dist/http/http-route-runner.js +13 -82
- package/dist/http/index.d.ts +1 -1
- package/dist/http/index.js +1 -1
- package/dist/http/log-http-routes.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/middleware/auth-apikey.d.ts +15 -0
- package/dist/middleware/auth-apikey.js +36 -0
- package/dist/middleware/auth-bearer.d.ts +12 -0
- package/dist/middleware/auth-bearer.js +40 -0
- package/dist/middleware/auth-cookie.d.ts +16 -0
- package/dist/middleware/auth-cookie.js +43 -0
- package/dist/middleware/index.d.ts +3 -4
- package/dist/middleware/index.js +3 -4
- package/dist/middleware/timeout.d.ts +2 -0
- package/dist/middleware/timeout.js +10 -0
- package/dist/middleware-runner.d.ts +1 -1
- package/dist/pikku-state.d.ts +29 -0
- package/dist/pikku-state.js +30 -0
- package/dist/scheduler/index.d.ts +1 -1
- package/dist/scheduler/index.js +1 -1
- package/dist/scheduler/log-schedulers.js +2 -2
- package/dist/scheduler/scheduler-runner.d.ts +1 -11
- package/dist/scheduler/scheduler-runner.js +5 -33
- package/dist/schema.js +2 -2
- package/dist/services/jwt-service.d.ts +1 -10
- package/dist/services/user-session-service.d.ts +2 -2
- package/dist/services/user-session-service.js +6 -6
- package/dist/types/core.types.d.ts +3 -3
- package/lcov.info +814 -907
- package/package.json +2 -1
- package/src/channel/channel-handler.ts +2 -2
- package/src/channel/channel-runner.ts +4 -43
- package/src/channel/channel-store.ts +8 -11
- package/src/channel/index.ts +0 -1
- package/src/channel/local/local-channel-runner.test.ts +10 -20
- package/src/channel/local/local-channel-runner.ts +2 -2
- package/src/channel/log-channels.ts +2 -2
- package/src/channel/serverless/serverless-channel-runner.ts +10 -9
- package/src/errors/error-handler.ts +7 -18
- package/src/errors/errors.ts +2 -3
- package/src/handle-error.ts +0 -1
- package/src/http/http-route-runner.test.ts +3 -2
- package/src/http/http-route-runner.ts +18 -99
- package/src/http/index.ts +1 -6
- package/src/http/log-http-routes.ts +2 -2
- package/src/index.ts +1 -0
- package/src/middleware/auth-apikey.ts +65 -0
- package/src/middleware/auth-bearer.ts +65 -0
- package/src/middleware/auth-cookie.ts +76 -0
- package/src/middleware/index.ts +3 -4
- package/src/middleware/timeout.ts +13 -0
- package/src/middleware-runner.ts +1 -1
- package/src/pikku-state.ts +70 -0
- package/src/scheduler/index.ts +1 -7
- package/src/scheduler/log-schedulers.ts +2 -2
- package/src/scheduler/scheduler-runner.ts +6 -45
- package/src/schema.ts +2 -2
- package/src/services/jwt-service.ts +1 -12
- package/src/services/user-session-service.ts +8 -6
- package/src/types/core.types.ts +3 -6
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/channel/eventhub-forwarder.d.ts +0 -17
- package/dist/channel/eventhub-forwarder.js +0 -1
- package/dist/middleware/auth-api-key.d.ts +0 -9
- package/dist/middleware/auth-api-key.js +0 -23
- package/dist/middleware/auth-cookie-middleware.d.ts +0 -11
- package/dist/middleware/auth-cookie-middleware.js +0 -36
- package/dist/middleware/auth-jwt-middleware.d.ts +0 -10
- package/dist/middleware/auth-jwt-middleware.js +0 -32
- package/dist/middleware/auth-query-middleware.d.ts +0 -10
- package/dist/middleware/auth-query-middleware.js +0 -21
- package/src/channel/eventhub-forwarder.ts +0 -25
- package/src/middleware/auth-api-key.ts +0 -32
- package/src/middleware/auth-cookie-middleware.ts +0 -54
- package/src/middleware/auth-jwt-middleware.ts +0 -47
- package/src/middleware/auth-query-middleware.ts +0 -33
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.17",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"exports": {
|
|
20
20
|
".": "./dist/index.js",
|
|
21
|
+
"./middleware": "./dist/middleware/index.js",
|
|
21
22
|
"./channel": "./dist/channel/index.js",
|
|
22
23
|
"./channel/local": "./dist/channel/local/index.js",
|
|
23
24
|
"./channel/serverless": "./dist/channel/serverless/index.js",
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from '../types/core.types.js'
|
|
7
7
|
import { CoreAPIChannel, PikkuChannelHandler } from './channel.types.js'
|
|
8
8
|
import { verifyPermissions } from '../permissions.js'
|
|
9
|
-
import {
|
|
9
|
+
import { pikkuState } from '../pikku-state.js'
|
|
10
10
|
|
|
11
11
|
const validateSchema = (
|
|
12
12
|
logger: CoreSingletonServices['logger'],
|
|
@@ -15,7 +15,7 @@ const validateSchema = (
|
|
|
15
15
|
routingProperty?: string,
|
|
16
16
|
routerValue?: string
|
|
17
17
|
) => {
|
|
18
|
-
const
|
|
18
|
+
const channelsMeta = pikkuState('channel', 'meta')
|
|
19
19
|
for (const channelMeta of channelsMeta) {
|
|
20
20
|
if (routingProperty && routerValue) {
|
|
21
21
|
const channelRoute =
|
|
@@ -1,46 +1,14 @@
|
|
|
1
1
|
import { NotFoundError } from '../errors/errors.js'
|
|
2
|
+
import { pikkuState } from '../pikku-state.js'
|
|
2
3
|
import { coerceQueryStringToArray, validateSchema } from '../schema.js'
|
|
3
4
|
import { UserSessionService } from '../services/user-session-service.js'
|
|
4
5
|
import {
|
|
5
6
|
CoreAPIChannel,
|
|
6
|
-
ChannelsMeta,
|
|
7
|
-
CoreAPIChannels,
|
|
8
7
|
RunChannelOptions,
|
|
9
8
|
RunChannelParams,
|
|
10
9
|
} from './channel.types.js'
|
|
11
10
|
import { match } from 'path-to-regexp'
|
|
12
11
|
|
|
13
|
-
if (!globalThis.pikku?.channels) {
|
|
14
|
-
globalThis.pikku = globalThis.pikku || {}
|
|
15
|
-
globalThis.pikku.channels = []
|
|
16
|
-
globalThis.pikku.channelsMeta = []
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const channels = (data?: any): CoreAPIChannels => {
|
|
20
|
-
if (data) {
|
|
21
|
-
globalThis.pikku.channels = data
|
|
22
|
-
}
|
|
23
|
-
return globalThis.pikku.channels
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const channelsMeta = (data?: any): ChannelsMeta => {
|
|
27
|
-
if (data) {
|
|
28
|
-
globalThis.pikku.channelsMeta = data
|
|
29
|
-
}
|
|
30
|
-
return globalThis.pikku.channelsMeta
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Returns all the registered routes and associated metadata.
|
|
35
|
-
* @internal
|
|
36
|
-
*/
|
|
37
|
-
export const getChannels = () => {
|
|
38
|
-
return {
|
|
39
|
-
channels: channels(),
|
|
40
|
-
channelsMeta: channelsMeta(),
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
12
|
export const addChannel = <
|
|
45
13
|
In,
|
|
46
14
|
Channel extends string,
|
|
@@ -56,18 +24,12 @@ export const addChannel = <
|
|
|
56
24
|
APIPermission
|
|
57
25
|
>
|
|
58
26
|
) => {
|
|
59
|
-
channels
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @ignore
|
|
64
|
-
*/
|
|
65
|
-
export const setChannelsMeta = (_channelsMeta: ChannelsMeta) => {
|
|
66
|
-
channelsMeta(_channelsMeta)
|
|
27
|
+
pikkuState('channel', 'channels').push(channel as any)
|
|
67
28
|
}
|
|
68
29
|
|
|
69
30
|
export const getMatchingChannelConfig = (request: string) => {
|
|
70
|
-
const
|
|
31
|
+
const channels = pikkuState('channel', 'channels')
|
|
32
|
+
const channelsMeta = pikkuState('channel', 'meta')
|
|
71
33
|
for (const channelConfig of channels) {
|
|
72
34
|
const cleanedRoute = channelConfig.route.replace(/^\/\//, '/')
|
|
73
35
|
const cleanedRequest = request.replace(/^\/\//, '/')
|
|
@@ -96,7 +58,6 @@ export const openChannel = async ({
|
|
|
96
58
|
singletonServices,
|
|
97
59
|
coerceToArray = false,
|
|
98
60
|
http,
|
|
99
|
-
userSessionService,
|
|
100
61
|
}: Pick<CoreAPIChannel<unknown, string>, 'route'> &
|
|
101
62
|
Omit<RunChannelParams<unknown>, 'response' | 'request'> & {
|
|
102
63
|
userSessionService?: UserSessionService<any>
|
|
@@ -1,32 +1,29 @@
|
|
|
1
1
|
import { CoreUserSession } from '../types/core.types.js'
|
|
2
2
|
|
|
3
|
-
export type Channel<
|
|
4
|
-
ChannelType = unknown,
|
|
5
|
-
OpeningData = unknown,
|
|
6
|
-
UserSession extends CoreUserSession = CoreUserSession,
|
|
7
|
-
> = {
|
|
3
|
+
export type Channel<ChannelType = unknown, OpeningData = unknown> = {
|
|
8
4
|
channelId: string
|
|
9
5
|
channelName: string
|
|
10
6
|
channelObject?: ChannelType
|
|
11
7
|
openingData?: OpeningData
|
|
12
|
-
userSession?: UserSession
|
|
13
8
|
}
|
|
14
9
|
|
|
15
10
|
export abstract class ChannelStore<
|
|
16
11
|
ChannelType = unknown,
|
|
17
12
|
OpeningData = unknown,
|
|
18
13
|
UserSession extends CoreUserSession = CoreUserSession,
|
|
19
|
-
TypedChannel = Channel<ChannelType, OpeningData
|
|
14
|
+
TypedChannel = Channel<ChannelType, OpeningData>,
|
|
20
15
|
> {
|
|
21
16
|
public abstract addChannel(
|
|
22
|
-
channel: Channel<ChannelType, OpeningData
|
|
17
|
+
channel: Channel<ChannelType, OpeningData>
|
|
23
18
|
): Promise<void> | void
|
|
24
19
|
public abstract removeChannels(channelId: string[]): Promise<void> | void
|
|
25
20
|
public abstract setUserSession(
|
|
26
21
|
channelId: string,
|
|
27
|
-
userSession:
|
|
22
|
+
userSession: UserSession | null
|
|
28
23
|
): Promise<void> | void
|
|
29
|
-
public abstract
|
|
24
|
+
public abstract getChannelAndSession(
|
|
30
25
|
channelId: string
|
|
31
|
-
):
|
|
26
|
+
):
|
|
27
|
+
| Promise<TypedChannel & { session: UserSession }>
|
|
28
|
+
| (TypedChannel & { session: UserSession })
|
|
32
29
|
}
|
package/src/channel/index.ts
CHANGED
|
@@ -3,7 +3,6 @@ export * from './channel.types.js'
|
|
|
3
3
|
export * from './log-channels.js'
|
|
4
4
|
export * from './pikku-abstract-channel-handler.js'
|
|
5
5
|
export * from './eventhub-service.js'
|
|
6
|
-
export * from './eventhub-forwarder.js'
|
|
7
6
|
export * from './eventhub-service.js'
|
|
8
7
|
export * from './channel-store.js'
|
|
9
8
|
export * from './eventhub-store.js'
|
|
@@ -4,6 +4,8 @@ import { JSONValue } from '../../types/core.types.js'
|
|
|
4
4
|
import { PikkuHTTPAbstractRequest } from '../../http/pikku-http-abstract-request.js'
|
|
5
5
|
import { PikkuHTTPAbstractResponse } from '../../http/pikku-http-abstract-response.js'
|
|
6
6
|
import { runLocalChannel } from './local-channel-runner.js'
|
|
7
|
+
import { resetPikkuState } from '../../pikku-state.js'
|
|
8
|
+
import { addChannel } from '../channel-runner.js'
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Minimal stubs for dependencies that runChannel expects.
|
|
@@ -49,28 +51,16 @@ class MockResponse extends PikkuHTTPAbstractResponse {
|
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
const mockCreateSessionServices = async () => ({ sessionServiceMock: true })
|
|
52
|
-
function resetGlobalChannels(channels: any[] = [], channelsMeta: any[] = []) {
|
|
53
|
-
// If necessary, reinitialize globalThis.pikku
|
|
54
|
-
if (!globalThis.pikku) {
|
|
55
|
-
globalThis.pikku = {}
|
|
56
|
-
}
|
|
57
|
-
globalThis.pikku.channels = channels
|
|
58
|
-
globalThis.pikku.channelsMeta = channelsMeta
|
|
59
|
-
globalThis.pikku.openChannels = new Map()
|
|
60
|
-
}
|
|
61
54
|
|
|
62
55
|
beforeEach(() => {
|
|
63
|
-
|
|
56
|
+
resetPikkuState()
|
|
64
57
|
})
|
|
65
58
|
|
|
66
59
|
afterEach(() => {
|
|
67
|
-
|
|
60
|
+
resetPikkuState()
|
|
68
61
|
})
|
|
69
62
|
|
|
70
63
|
test('runChannel should return undefined and 404 if no matching channel is found', async () => {
|
|
71
|
-
// No channels configured
|
|
72
|
-
resetGlobalChannels()
|
|
73
|
-
|
|
74
64
|
const mockResponse = new MockResponse()
|
|
75
65
|
|
|
76
66
|
const result = await runLocalChannel({
|
|
@@ -92,12 +82,12 @@ test('runChannel should return undefined and 404 if no matching channel is found
|
|
|
92
82
|
})
|
|
93
83
|
|
|
94
84
|
test('runChannel should return a channel handler if channel matches and no auth required', async () => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
85
|
+
resetPikkuState()
|
|
86
|
+
addChannel({
|
|
87
|
+
name: 'test',
|
|
88
|
+
route: '/test-channel',
|
|
89
|
+
auth: false,
|
|
90
|
+
})
|
|
101
91
|
|
|
102
92
|
// Provide a fake channelPermissionService if needed
|
|
103
93
|
const singletonServicesWithPerm = {
|
|
@@ -64,7 +64,7 @@ export const runLocalChannel = async ({
|
|
|
64
64
|
const allServices = {
|
|
65
65
|
...singletonServices,
|
|
66
66
|
...sessionServices,
|
|
67
|
-
userSessionService,
|
|
67
|
+
userSession: userSessionService,
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
channelHandler.registerOnOpen(() => {
|
|
@@ -101,7 +101,7 @@ export const runLocalChannel = async ({
|
|
|
101
101
|
await runMiddleware(
|
|
102
102
|
{
|
|
103
103
|
...singletonServices,
|
|
104
|
-
userSessionService,
|
|
104
|
+
userSession: userSessionService,
|
|
105
105
|
},
|
|
106
106
|
{ http },
|
|
107
107
|
route.middleware || [],
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { pikkuState } from '../pikku-state.js'
|
|
1
2
|
import { Logger } from '../services/index.js'
|
|
2
|
-
import { getChannels } from './channel-runner.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Logs all the loaded channels.
|
|
6
6
|
* @param logger - A logger for logging information.
|
|
7
7
|
*/
|
|
8
8
|
export const logChannels = (logger: Logger) => {
|
|
9
|
-
const
|
|
9
|
+
const channels = pikkuState('channel', 'channels')
|
|
10
10
|
if (channels.length === 0) {
|
|
11
11
|
logger.info('No channels added')
|
|
12
12
|
return
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SessionServices } from '../../types/core.types.js'
|
|
2
2
|
import { closeSessionServices } from '../../utils.js'
|
|
3
3
|
import { processMessageHandlers } from '../channel-handler.js'
|
|
4
|
-
import {
|
|
4
|
+
import { openChannel } from '../channel-runner.js'
|
|
5
5
|
import type {
|
|
6
6
|
CoreAPIChannel,
|
|
7
7
|
RunChannelOptions,
|
|
@@ -13,6 +13,7 @@ import { ChannelStore } from '../channel-store.js'
|
|
|
13
13
|
import { handleError } from '../../handle-error.js'
|
|
14
14
|
import { RemoteUserSessionService } from '../../services/user-session-service.js'
|
|
15
15
|
import { runMiddleware } from '../../middleware-runner.js'
|
|
16
|
+
import { pikkuState } from '../../pikku-state.js'
|
|
16
17
|
|
|
17
18
|
export interface RunServerlessChannelParams<ChannelData>
|
|
18
19
|
extends RunChannelParams<ChannelData> {
|
|
@@ -32,7 +33,7 @@ const getVariablesForChannel = ({
|
|
|
32
33
|
channelHandlerFactory: PikkuChannelHandlerFactory
|
|
33
34
|
openingData?: unknown
|
|
34
35
|
}) => {
|
|
35
|
-
const
|
|
36
|
+
const channels = pikkuState('channel', 'channels')
|
|
36
37
|
const channelConfig = channels.find(
|
|
37
38
|
(channelConfig) => channelConfig.name === channelName
|
|
38
39
|
)
|
|
@@ -129,7 +130,7 @@ export const runChannelConnect = async ({
|
|
|
129
130
|
await runMiddleware(
|
|
130
131
|
{
|
|
131
132
|
...singletonServices,
|
|
132
|
-
userSessionService,
|
|
133
|
+
userSession: userSessionService,
|
|
133
134
|
},
|
|
134
135
|
{ http },
|
|
135
136
|
channelConfig.middleware || [],
|
|
@@ -142,8 +143,8 @@ export const runChannelDisconnect = async ({
|
|
|
142
143
|
...params
|
|
143
144
|
}: RunServerlessChannelParams<unknown>): Promise<void> => {
|
|
144
145
|
let sessionServices: SessionServices | undefined
|
|
145
|
-
const {
|
|
146
|
-
await params.channelStore.
|
|
146
|
+
const { openingData, channelName, session } =
|
|
147
|
+
await params.channelStore.getChannelAndSession(params.channelId)
|
|
147
148
|
const { channel, channelConfig } = getVariablesForChannel({
|
|
148
149
|
...params,
|
|
149
150
|
openingData,
|
|
@@ -153,7 +154,7 @@ export const runChannelDisconnect = async ({
|
|
|
153
154
|
sessionServices = await params.createSessionServices(
|
|
154
155
|
singletonServices,
|
|
155
156
|
{},
|
|
156
|
-
|
|
157
|
+
session
|
|
157
158
|
)
|
|
158
159
|
}
|
|
159
160
|
await channelConfig.onDisconnect?.(
|
|
@@ -171,8 +172,8 @@ export const runChannelMessage = async (
|
|
|
171
172
|
data: unknown
|
|
172
173
|
): Promise<unknown> => {
|
|
173
174
|
let sessionServices: SessionServices | undefined
|
|
174
|
-
const {
|
|
175
|
-
await params.channelStore.
|
|
175
|
+
const { openingData, channelName, session } =
|
|
176
|
+
await params.channelStore.getChannelAndSession(params.channelId)
|
|
176
177
|
const { channelHandler, channelConfig } = getVariablesForChannel({
|
|
177
178
|
...params,
|
|
178
179
|
openingData,
|
|
@@ -182,7 +183,7 @@ export const runChannelMessage = async (
|
|
|
182
183
|
sessionServices = await params.createSessionServices(
|
|
183
184
|
singletonServices,
|
|
184
185
|
{},
|
|
185
|
-
|
|
186
|
+
session
|
|
186
187
|
)
|
|
187
188
|
}
|
|
188
189
|
let response: unknown
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { pikkuState } from '../pikku-state.js'
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Base class for custom errors.
|
|
3
5
|
* @extends {Error}
|
|
@@ -21,19 +23,7 @@ export interface ErrorDetails {
|
|
|
21
23
|
message: string
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
* Map of API errors to their details.
|
|
26
|
-
*/
|
|
27
|
-
if (!globalThis.pikku?.apiErrors) {
|
|
28
|
-
globalThis.pikku = globalThis.pikku || {}
|
|
29
|
-
globalThis.pikku.apiErrors = new Map<any, ErrorDetails>([])
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const apiErrors = (): Map<any, ErrorDetails> => {
|
|
33
|
-
return globalThis.pikku.apiErrors
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export const getErrors = () => apiErrors()
|
|
26
|
+
export const getErrors = () => pikkuState('errors', 'errors')
|
|
37
27
|
|
|
38
28
|
/**
|
|
39
29
|
* Adds an error to the API errors map.
|
|
@@ -41,7 +31,7 @@ export const getErrors = () => apiErrors()
|
|
|
41
31
|
* @param details - The details of the error.
|
|
42
32
|
*/
|
|
43
33
|
export const addError = (error: any, { status, message }: ErrorDetails) => {
|
|
44
|
-
|
|
34
|
+
pikkuState('errors', 'errors').set(error, { status, message })
|
|
45
35
|
}
|
|
46
36
|
|
|
47
37
|
/**
|
|
@@ -64,11 +54,10 @@ export const addErrors = (
|
|
|
64
54
|
export const getErrorResponse = (
|
|
65
55
|
error: Error
|
|
66
56
|
): { status: number; message: string } | undefined => {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
)
|
|
57
|
+
const errors = Array.from(pikkuState('errors', 'errors').entries())
|
|
58
|
+
const foundError = errors.find(([e]) => e.name === error.constructor.name)
|
|
70
59
|
if (foundError) {
|
|
71
60
|
return foundError[1]
|
|
72
61
|
}
|
|
73
|
-
return
|
|
62
|
+
return pikkuState('errors', 'errors').get(error)
|
|
74
63
|
}
|
package/src/errors/errors.ts
CHANGED
|
@@ -121,14 +121,13 @@ addError(ProxyAuthenticationRequiredError, {
|
|
|
121
121
|
})
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
|
-
* The server
|
|
124
|
+
* The server request expired
|
|
125
125
|
* @group Error
|
|
126
126
|
*/
|
|
127
127
|
export class RequestTimeoutError extends PikkuError {}
|
|
128
128
|
addError(RequestTimeoutError, {
|
|
129
129
|
status: 408,
|
|
130
|
-
message:
|
|
131
|
-
'The server did not receive a timely response from an upstream server.',
|
|
130
|
+
message: 'The request timeout has expired.',
|
|
132
131
|
})
|
|
133
132
|
|
|
134
133
|
/**
|
package/src/handle-error.ts
CHANGED
|
@@ -4,7 +4,8 @@ import { NotFoundError } from '../errors/errors.js'
|
|
|
4
4
|
import { PikkuHTTPAbstractRequest } from './pikku-http-abstract-request.js'
|
|
5
5
|
import { PikkuHTTPAbstractResponse } from './pikku-http-abstract-response.js'
|
|
6
6
|
import { JSONValue, PikkuMiddleware } from '../types/core.types.js'
|
|
7
|
-
import { runHTTPRoute,
|
|
7
|
+
import { runHTTPRoute, addRoute } from './http-route-runner.js'
|
|
8
|
+
import { resetPikkuState } from '../pikku-state.js'
|
|
8
9
|
|
|
9
10
|
class PikkuTestRequest extends PikkuHTTPAbstractRequest {
|
|
10
11
|
public getBody(): Promise<unknown> {
|
|
@@ -39,7 +40,7 @@ describe('runHTTPRoute', () => {
|
|
|
39
40
|
let response: any
|
|
40
41
|
|
|
41
42
|
beforeEach(() => {
|
|
42
|
-
|
|
43
|
+
resetPikkuState()
|
|
43
44
|
|
|
44
45
|
singletonServices = {
|
|
45
46
|
logger: {
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { verifyPermissions } from '../permissions.js'
|
|
2
2
|
import {
|
|
3
3
|
CoreHTTPFunctionRoute,
|
|
4
|
-
HTTPRoutesMeta,
|
|
5
4
|
RunRouteOptions,
|
|
6
5
|
RunRouteParams,
|
|
7
6
|
PikkuHTTP,
|
|
8
|
-
HTTPRouteMiddleware,
|
|
9
7
|
} from './http-routes.types.js'
|
|
10
|
-
import { SessionServices } from '../types/core.types.js'
|
|
8
|
+
import { PikkuMiddleware, SessionServices } from '../types/core.types.js'
|
|
11
9
|
import { match } from 'path-to-regexp'
|
|
12
10
|
import { PikkuHTTPAbstractRequest } from './pikku-http-abstract-request.js'
|
|
13
11
|
import { PikkuHTTPAbstractResponse } from './pikku-http-abstract-response.js'
|
|
@@ -24,59 +22,7 @@ import { coerceQueryStringToArray, validateSchema } from '../schema.js'
|
|
|
24
22
|
import { LocalUserSessionService } from '../services/user-session-service.js'
|
|
25
23
|
import { runMiddleware } from '../middleware-runner.js'
|
|
26
24
|
import { handleError } from '../handle-error.js'
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Initialize global state for HTTP routes and middleware if not already available
|
|
30
|
-
*/
|
|
31
|
-
if (!globalThis.pikku?.httpRoutes) {
|
|
32
|
-
globalThis.pikku = globalThis.pikku || {}
|
|
33
|
-
globalThis.pikku.httpMiddleware = []
|
|
34
|
-
globalThis.pikku.httpRoutes = []
|
|
35
|
-
globalThis.pikku.httpRoutesMeta = []
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Get or set the global HTTP routes
|
|
40
|
-
*
|
|
41
|
-
* @param {CoreHTTPFunctionRoute<any, any, any>[]} [data] - Optional routes data to set
|
|
42
|
-
* @returns {CoreHTTPFunctionRoute<any, any, any>[]} Current routes
|
|
43
|
-
*/
|
|
44
|
-
const httpRoutes = (
|
|
45
|
-
data?: CoreHTTPFunctionRoute<any, any, any>[]
|
|
46
|
-
): CoreHTTPFunctionRoute<any, any, any>[] => {
|
|
47
|
-
if (data) {
|
|
48
|
-
globalThis.pikku.httpRoutes = data
|
|
49
|
-
}
|
|
50
|
-
return globalThis.pikku.httpRoutes
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Get or set the global HTTP route metadata
|
|
55
|
-
*
|
|
56
|
-
* @param {HTTPRoutesMeta} [data] - Optional route metadata to set
|
|
57
|
-
* @returns {HTTPRoutesMeta} Current route metadata
|
|
58
|
-
*/
|
|
59
|
-
const httpRoutesMeta = (data?: HTTPRoutesMeta): HTTPRoutesMeta => {
|
|
60
|
-
if (data) {
|
|
61
|
-
globalThis.pikku.httpRoutesMeta = data
|
|
62
|
-
}
|
|
63
|
-
return globalThis.pikku.httpRoutesMeta
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Get or set the global HTTP middleware
|
|
68
|
-
*
|
|
69
|
-
* @param {HTTPRouteMiddleware[]} [data] - Optional middleware to set
|
|
70
|
-
* @returns {HTTPRouteMiddleware[]} Current middleware
|
|
71
|
-
*/
|
|
72
|
-
const httpMiddleware = (
|
|
73
|
-
data?: HTTPRouteMiddleware[]
|
|
74
|
-
): HTTPRouteMiddleware[] => {
|
|
75
|
-
if (data) {
|
|
76
|
-
globalThis.pikku.httpMiddleware = data
|
|
77
|
-
}
|
|
78
|
-
return globalThis.pikku.httpMiddleware
|
|
79
|
-
}
|
|
25
|
+
import { pikkuState } from '../pikku-state.js'
|
|
80
26
|
|
|
81
27
|
/**
|
|
82
28
|
* Add middleware to a specific route or globally
|
|
@@ -84,19 +30,19 @@ const httpMiddleware = (
|
|
|
84
30
|
* @param {APIMiddleware[] | string} routeOrMiddleware - Route pattern to match or middleware array
|
|
85
31
|
* @param {APIMiddleware} [middleware] - Middleware to add (required if first param is a string)
|
|
86
32
|
*/
|
|
87
|
-
export const addMiddleware = <APIMiddleware>(
|
|
33
|
+
export const addMiddleware = <APIMiddleware extends PikkuMiddleware>(
|
|
88
34
|
routeOrMiddleware: APIMiddleware[] | string,
|
|
89
|
-
middleware?: APIMiddleware
|
|
35
|
+
middleware?: APIMiddleware[]
|
|
90
36
|
) => {
|
|
91
|
-
if (typeof routeOrMiddleware === 'string') {
|
|
92
|
-
|
|
37
|
+
if (typeof routeOrMiddleware === 'string' && middleware) {
|
|
38
|
+
pikkuState('http', 'middleware').push({
|
|
93
39
|
route: routeOrMiddleware,
|
|
94
|
-
middleware
|
|
40
|
+
middleware,
|
|
95
41
|
})
|
|
96
42
|
} else {
|
|
97
|
-
|
|
43
|
+
pikkuState('http', 'middleware').push({
|
|
98
44
|
route: '*',
|
|
99
|
-
middleware: routeOrMiddleware,
|
|
45
|
+
middleware: routeOrMiddleware as any,
|
|
100
46
|
})
|
|
101
47
|
}
|
|
102
48
|
}
|
|
@@ -125,37 +71,7 @@ export const addRoute = <
|
|
|
125
71
|
APIMiddleware
|
|
126
72
|
>
|
|
127
73
|
) => {
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Remove all routes from the global registry
|
|
133
|
-
*/
|
|
134
|
-
export const clearRoutes = () => {
|
|
135
|
-
httpRoutes([])
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Set the HTTP routes metadata
|
|
140
|
-
*
|
|
141
|
-
* @param {HTTPRoutesMeta} routeMeta - Metadata for routes
|
|
142
|
-
* @ignore
|
|
143
|
-
*/
|
|
144
|
-
export const setHTTPRoutesMeta = (routeMeta: HTTPRoutesMeta) => {
|
|
145
|
-
httpRoutesMeta(routeMeta)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Returns all the registered routes and associated metadata
|
|
150
|
-
*
|
|
151
|
-
* @returns {Object} Object containing routes and routesMeta
|
|
152
|
-
* @internal
|
|
153
|
-
*/
|
|
154
|
-
export const getRoutes = () => {
|
|
155
|
-
return {
|
|
156
|
-
routes: httpRoutes(),
|
|
157
|
-
routesMeta: httpRoutesMeta(),
|
|
158
|
-
}
|
|
74
|
+
pikkuState('http', 'routes').push(route as any)
|
|
159
75
|
}
|
|
160
76
|
|
|
161
77
|
/**
|
|
@@ -166,7 +82,11 @@ export const getRoutes = () => {
|
|
|
166
82
|
* @returns {Object | undefined} Matching route information or undefined if no match
|
|
167
83
|
*/
|
|
168
84
|
const getMatchingRoute = (requestType: string, requestPath: string) => {
|
|
169
|
-
|
|
85
|
+
const routes = pikkuState('http', 'routes')
|
|
86
|
+
const middleware = pikkuState('http', 'middleware')
|
|
87
|
+
const routesMeta = pikkuState('http', 'meta')
|
|
88
|
+
|
|
89
|
+
for (const route of routes) {
|
|
170
90
|
// Skip routes that don't match the request method
|
|
171
91
|
if (route.method !== requestType.toLowerCase()) {
|
|
172
92
|
continue
|
|
@@ -182,13 +102,13 @@ const getMatchingRoute = (requestType: string, requestPath: string) => {
|
|
|
182
102
|
|
|
183
103
|
if (matchedPath) {
|
|
184
104
|
// Get all middleware for this route
|
|
185
|
-
const globalMiddleware =
|
|
105
|
+
const globalMiddleware = middleware
|
|
186
106
|
.filter((m) => m.route === '*' || new RegExp(m.route).test(route.route))
|
|
187
107
|
.map((m) => m.middleware)
|
|
188
108
|
.flat()
|
|
189
109
|
|
|
190
110
|
// Find schema for this route
|
|
191
|
-
const schemaName =
|
|
111
|
+
const schemaName = routesMeta.find(
|
|
192
112
|
(routeMeta) =>
|
|
193
113
|
routeMeta.method === route.method && routeMeta.route === route.route
|
|
194
114
|
)?.input
|
|
@@ -269,7 +189,6 @@ const executeRouteWithMiddleware = async (
|
|
|
269
189
|
createSessionServices,
|
|
270
190
|
skipUserSession,
|
|
271
191
|
} = services
|
|
272
|
-
const { coerceToArray } = options
|
|
273
192
|
|
|
274
193
|
const requiresSession = route.auth !== false
|
|
275
194
|
let sessionServices: any
|
|
@@ -318,7 +237,7 @@ const executeRouteWithMiddleware = async (
|
|
|
318
237
|
data
|
|
319
238
|
)
|
|
320
239
|
|
|
321
|
-
if (coerceToArray && schemaName) {
|
|
240
|
+
if (options.coerceToArray && schemaName) {
|
|
322
241
|
coerceQueryStringToArray(schemaName, data)
|
|
323
242
|
}
|
|
324
243
|
|
package/src/http/index.ts
CHANGED
|
@@ -4,11 +4,6 @@ export * from './pikku-http-abstract-response.js'
|
|
|
4
4
|
|
|
5
5
|
export * from './log-http-routes.js'
|
|
6
6
|
|
|
7
|
-
export {
|
|
8
|
-
runHTTPRoute,
|
|
9
|
-
getRoutes,
|
|
10
|
-
setHTTPRoutesMeta,
|
|
11
|
-
addRoute,
|
|
12
|
-
} from './http-route-runner.js'
|
|
7
|
+
export { runHTTPRoute, addRoute } from './http-route-runner.js'
|
|
13
8
|
|
|
14
9
|
export type * from './http-routes.types.js'
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { pikkuState } from '../pikku-state.js'
|
|
1
2
|
import { Logger } from '../services/index.js'
|
|
2
|
-
import { getRoutes } from './http-route-runner.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Logs all the loaded routes.
|
|
6
6
|
* @param logger - A logger for logging information.
|
|
7
7
|
*/
|
|
8
8
|
export const logRoutes = (logger: Logger) => {
|
|
9
|
-
const
|
|
9
|
+
const routes = pikkuState('http', 'routes')
|
|
10
10
|
if (routes.length === 0) {
|
|
11
11
|
logger.info('No routes added')
|
|
12
12
|
return
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './scheduler/index.js'
|
|
|
12
12
|
export * from './errors/index.js'
|
|
13
13
|
export * from './middleware/index.js'
|
|
14
14
|
|
|
15
|
+
export { pikkuState } from './pikku-state.js'
|
|
15
16
|
export { runMiddleware } from './middleware-runner.js'
|
|
16
17
|
export { addRoute } from './http/http-route-runner.js'
|
|
17
18
|
export { addChannel } from './channel/channel-runner.js'
|