@pikku/core 0.6.27 → 0.7.1
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 +16 -1
- package/dist/channel/channel-handler.js +16 -38
- package/dist/channel/channel-runner.d.ts +7 -8
- package/dist/channel/channel-runner.js +58 -7
- package/dist/channel/channel.types.d.ts +14 -27
- package/dist/channel/local/local-channel-runner.js +9 -4
- package/dist/channel/log-channels.js +4 -4
- package/dist/channel/serverless/serverless-channel-runner.js +17 -6
- package/dist/function/function-runner.d.ts +12 -0
- package/dist/function/function-runner.js +38 -0
- package/dist/{types → function}/functions.types.d.ts +12 -7
- package/dist/function/index.d.ts +2 -0
- package/dist/function/index.js +2 -0
- package/dist/handle-error.d.ts +1 -1
- package/dist/http/{http-route-runner.d.ts → http-runner.d.ts} +4 -4
- package/dist/http/{http-route-runner.js → http-runner.js} +81 -43
- package/dist/http/{http-routes.types.d.ts → http.types.d.ts} +41 -12
- package/dist/http/index.d.ts +2 -2
- package/dist/http/index.js +1 -1
- package/dist/http/log-http-routes.js +7 -5
- package/dist/http/pikku-fetch-http-request.d.ts +1 -1
- package/dist/http/pikku-fetch-http-response.d.ts +4 -2
- package/dist/http/pikku-fetch-http-response.js +64 -12
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/middleware/auth-apikey.js +5 -4
- package/dist/middleware/auth-bearer.js +5 -4
- package/dist/middleware/auth-cookie.js +10 -9
- package/dist/permissions.d.ts +2 -2
- package/dist/pikku-function.d.ts +1 -0
- package/dist/pikku-function.js +1 -0
- package/dist/pikku-state.d.ts +10 -5
- package/dist/pikku-state.js +7 -3
- package/dist/scheduler/scheduler-runner.d.ts +1 -1
- package/dist/scheduler/scheduler-runner.js +24 -6
- package/dist/scheduler/scheduler.types.d.ts +3 -2
- package/dist/services/content-service.d.ts +33 -37
- package/dist/types/core.types.d.ts +15 -1
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +15 -0
- package/lcov.info +1240 -965
- package/package.json +2 -1
- package/src/channel/channel-handler.ts +16 -78
- package/src/channel/channel-runner.ts +72 -17
- package/src/channel/channel.types.ts +25 -63
- package/src/channel/local/local-channel-runner.test.ts +10 -11
- package/src/channel/local/local-channel-runner.ts +20 -7
- package/src/channel/log-channels.ts +4 -4
- package/src/channel/serverless/serverless-channel-runner.ts +26 -15
- package/src/function/function-runner.ts +91 -0
- package/src/{types → function}/functions.types.ts +25 -11
- package/src/function/index.ts +2 -0
- package/src/handle-error.ts +1 -1
- package/src/http/{http-route-runner.test.ts → http-runner.test.ts} +29 -6
- package/src/http/{http-route-runner.ts → http-runner.ts} +106 -73
- package/src/http/{http-routes.types.ts → http.types.ts} +55 -16
- package/src/http/index.ts +2 -2
- package/src/http/log-http-routes.ts +7 -5
- package/src/http/pikku-fetch-http-request.ts +1 -5
- package/src/http/pikku-fetch-http-response.ts +67 -13
- package/src/index.ts +3 -2
- package/src/middleware/auth-apikey.ts +5 -4
- package/src/middleware/auth-bearer.ts +5 -4
- package/src/middleware/auth-cookie.ts +14 -9
- package/src/permissions.ts +2 -4
- package/src/pikku-function.ts +1 -0
- package/src/pikku-state.ts +25 -9
- package/src/scheduler/scheduler-runner.ts +31 -13
- package/src/scheduler/scheduler.types.ts +12 -8
- package/src/services/content-service.ts +36 -40
- package/src/types/core.types.ts +20 -1
- package/src/utils.ts +19 -0
- package/tsconfig.tsbuildinfo +1 -1
- /package/dist/{types → function}/functions.types.js +0 -0
- /package/dist/http/{http-routes.types.js → http.types.js} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { SerializeOptions } from 'cookie'
|
|
2
|
-
import { PikkuError } from '../errors/error-handler.js'
|
|
3
|
-
import {
|
|
1
|
+
import type { SerializeOptions } from 'cookie'
|
|
2
|
+
import type { PikkuError } from '../errors/error-handler.js'
|
|
3
|
+
import type {
|
|
4
4
|
APIDocs,
|
|
5
5
|
CoreServices,
|
|
6
6
|
CoreSingletonServices,
|
|
@@ -8,11 +8,12 @@ import {
|
|
|
8
8
|
CreateSessionServices,
|
|
9
9
|
PikkuMiddleware,
|
|
10
10
|
} from '../types/core.types.js'
|
|
11
|
-
import {
|
|
11
|
+
import type {
|
|
12
12
|
CoreAPIFunction,
|
|
13
13
|
CoreAPIFunctionSessionless,
|
|
14
14
|
CoreAPIPermission,
|
|
15
|
-
|
|
15
|
+
CorePermissionGroup,
|
|
16
|
+
} from '../function/functions.types.js'
|
|
16
17
|
|
|
17
18
|
type ExtractRouteParams<S extends string> =
|
|
18
19
|
S extends `${string}:${infer Param}/${infer Rest}`
|
|
@@ -32,6 +33,7 @@ export type RunRouteOptions = Partial<{
|
|
|
32
33
|
logWarningsForStatusCodes: number[]
|
|
33
34
|
coerceDataFromSchema: boolean
|
|
34
35
|
bubbleErrors: boolean
|
|
36
|
+
generateRequestId: () => string
|
|
35
37
|
}>
|
|
36
38
|
|
|
37
39
|
export type RunRouteParams = {
|
|
@@ -117,10 +119,11 @@ export type CoreHTTPFunctionRoute<
|
|
|
117
119
|
route: R
|
|
118
120
|
method: HTTPMethod
|
|
119
121
|
func: APIFunction
|
|
120
|
-
permissions?:
|
|
122
|
+
permissions?: CorePermissionGroup<APIPermission>
|
|
121
123
|
auth?: true
|
|
122
124
|
tags?: string[]
|
|
123
125
|
middleware?: APIMiddleware[]
|
|
126
|
+
sse?: undefined
|
|
124
127
|
})
|
|
125
128
|
| (CoreHTTPFunction & {
|
|
126
129
|
route: R
|
|
@@ -130,16 +133,38 @@ export type CoreHTTPFunctionRoute<
|
|
|
130
133
|
auth?: false
|
|
131
134
|
tags?: string[]
|
|
132
135
|
middleware?: APIMiddleware[]
|
|
136
|
+
sse?: undefined
|
|
137
|
+
})
|
|
138
|
+
| (CoreHTTPFunction & {
|
|
139
|
+
route: R
|
|
140
|
+
method: 'get'
|
|
141
|
+
func: APIFunction
|
|
142
|
+
permissions?: CorePermissionGroup<APIPermission>
|
|
143
|
+
auth?: true
|
|
144
|
+
sse?: boolean
|
|
145
|
+
tags?: string[]
|
|
146
|
+
middleware?: APIMiddleware[]
|
|
147
|
+
})
|
|
148
|
+
| (CoreHTTPFunction & {
|
|
149
|
+
route: R
|
|
150
|
+
method: 'get'
|
|
151
|
+
func: APIFunctionSessionless
|
|
152
|
+
permissions?: undefined
|
|
153
|
+
auth?: false
|
|
154
|
+
sse?: boolean
|
|
155
|
+
tags?: string[]
|
|
156
|
+
middleware?: APIMiddleware[]
|
|
133
157
|
})
|
|
134
158
|
| (CoreHTTPFunction & {
|
|
135
159
|
route: R
|
|
136
160
|
method: 'post'
|
|
137
161
|
func: APIFunction
|
|
138
|
-
permissions?:
|
|
162
|
+
permissions?: CorePermissionGroup<APIPermission>
|
|
139
163
|
auth?: true
|
|
140
164
|
query?: Array<keyof In>
|
|
141
165
|
tags?: string[]
|
|
142
166
|
middleware?: APIMiddleware[]
|
|
167
|
+
sse?: undefined
|
|
143
168
|
})
|
|
144
169
|
| (CoreHTTPFunction & {
|
|
145
170
|
route: R
|
|
@@ -150,15 +175,9 @@ export type CoreHTTPFunctionRoute<
|
|
|
150
175
|
query?: Array<keyof In>
|
|
151
176
|
tags?: string[]
|
|
152
177
|
middleware?: APIMiddleware[]
|
|
178
|
+
sse?: undefined
|
|
153
179
|
})
|
|
154
180
|
|
|
155
|
-
/**
|
|
156
|
-
* Represents an array of core API routes.
|
|
157
|
-
*/
|
|
158
|
-
export type CoreHTTPFunctionRoutes = Array<
|
|
159
|
-
CoreHTTPFunctionRoute<any, any, string>
|
|
160
|
-
>
|
|
161
|
-
|
|
162
181
|
/**
|
|
163
182
|
* Represents the input types for route metadata, including parameters, query, and body types.
|
|
164
183
|
*/
|
|
@@ -171,7 +190,8 @@ export type HTTPFunctionMetaInputTypes = {
|
|
|
171
190
|
/**
|
|
172
191
|
* Represents metadata for a set of routes, including route details, methods, input/output types, and documentation.
|
|
173
192
|
*/
|
|
174
|
-
export type
|
|
193
|
+
export type HTTPRouteMeta = {
|
|
194
|
+
pikkuFuncName: string
|
|
175
195
|
route: string
|
|
176
196
|
method: HTTPMethod
|
|
177
197
|
params?: string[]
|
|
@@ -181,6 +201,14 @@ export type HTTPRoutesMeta = Array<{
|
|
|
181
201
|
inputTypes?: HTTPFunctionMetaInputTypes
|
|
182
202
|
docs?: APIDocs
|
|
183
203
|
tags?: string[]
|
|
204
|
+
sse?: true
|
|
205
|
+
}
|
|
206
|
+
export type HTTPRoutesMeta = Array<HTTPRouteMeta>
|
|
207
|
+
|
|
208
|
+
export type HTTPFunctionsMeta = Array<{
|
|
209
|
+
name: string
|
|
210
|
+
inputs: string[] | null
|
|
211
|
+
outputs: string[] | null
|
|
184
212
|
}>
|
|
185
213
|
|
|
186
214
|
export type HTTPRouteMiddleware = {
|
|
@@ -205,7 +233,18 @@ export interface PikkuHTTPResponse {
|
|
|
205
233
|
status(code: number): this
|
|
206
234
|
cookie(name: string, value: string | null, options: SerializeOptions): this
|
|
207
235
|
header(name: string, value: string | string[]): this
|
|
208
|
-
arrayBuffer(
|
|
236
|
+
arrayBuffer(
|
|
237
|
+
data:
|
|
238
|
+
| ArrayBuffer
|
|
239
|
+
| ArrayBufferView
|
|
240
|
+
| Blob
|
|
241
|
+
| string
|
|
242
|
+
| FormData
|
|
243
|
+
| URLSearchParams
|
|
244
|
+
| ReadableStream
|
|
245
|
+
): this
|
|
209
246
|
json(data: unknown): this
|
|
210
247
|
redirect(location: string, status?: number): this
|
|
248
|
+
close?: () => void
|
|
249
|
+
setMode?: (mode: 'stream') => void
|
|
211
250
|
}
|
package/src/http/index.ts
CHANGED
|
@@ -3,6 +3,6 @@ export * from './pikku-fetch-http-response.js'
|
|
|
3
3
|
export * from './incomingmessage-to-request-convertor.js'
|
|
4
4
|
export * from './log-http-routes.js'
|
|
5
5
|
|
|
6
|
-
export { fetch, fetchData,
|
|
6
|
+
export { fetch, fetchData, addHTTPRoute } from './http-runner.js'
|
|
7
7
|
|
|
8
|
-
export type * from './http
|
|
8
|
+
export type * from './http.types.js'
|
|
@@ -6,15 +6,17 @@ import { Logger } from '../services/index.js'
|
|
|
6
6
|
* @param logger - A logger for logging information.
|
|
7
7
|
*/
|
|
8
8
|
export const logRoutes = (logger: Logger) => {
|
|
9
|
-
const
|
|
10
|
-
if (
|
|
9
|
+
const routesByType = pikkuState('http', 'routes')
|
|
10
|
+
if (routesByType.size === 0) {
|
|
11
11
|
logger.info('No routes added')
|
|
12
12
|
return
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
let routesMessage = 'Routes loaded:'
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
routesByType.forEach((routes) => {
|
|
17
|
+
routes.forEach((route) => {
|
|
18
|
+
routesMessage += `\n\t- ${route.method.toUpperCase()} -> ${route.route}`
|
|
19
|
+
})
|
|
20
|
+
})
|
|
19
21
|
logger.info(routesMessage)
|
|
20
22
|
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { parse as parseQuery } from 'picoquery'
|
|
2
2
|
import { parse as parseCookie } from 'cookie'
|
|
3
|
-
import {
|
|
4
|
-
HTTPMethod,
|
|
5
|
-
PikkuHTTPRequest,
|
|
6
|
-
PikkuQuery,
|
|
7
|
-
} from './http-routes.types.js'
|
|
3
|
+
import { HTTPMethod, PikkuHTTPRequest, PikkuQuery } from './http.types.js'
|
|
8
4
|
import { UnprocessableContentError } from '../errors/errors.js'
|
|
9
5
|
|
|
10
6
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PikkuHTTPResponse } from './http
|
|
1
|
+
import { PikkuHTTPResponse } from './http.types.js'
|
|
2
2
|
import {
|
|
3
3
|
SerializeOptions as CookieSerializeOptions,
|
|
4
4
|
serialize as serializeCookie,
|
|
@@ -10,6 +10,16 @@ export class PikkuFetchHTTPResponse implements PikkuHTTPResponse {
|
|
|
10
10
|
#cookies = new Map<string, { value: string; flags: CookieSerializeOptions }>()
|
|
11
11
|
|
|
12
12
|
#body: BodyInit | null = null
|
|
13
|
+
#responseMode: 'stream' | null = null
|
|
14
|
+
#send: ((data: string) => void) | null = null
|
|
15
|
+
#close: (() => void) | null = null
|
|
16
|
+
|
|
17
|
+
public setMode(mode: 'stream') {
|
|
18
|
+
this.#responseMode = 'stream'
|
|
19
|
+
if (mode === 'stream') {
|
|
20
|
+
this.#body = this.createStream()
|
|
21
|
+
}
|
|
22
|
+
}
|
|
13
23
|
|
|
14
24
|
public status(code: number): this {
|
|
15
25
|
this.#statusCode = code
|
|
@@ -36,33 +46,49 @@ export class PikkuFetchHTTPResponse implements PikkuHTTPResponse {
|
|
|
36
46
|
}
|
|
37
47
|
|
|
38
48
|
public arrayBuffer(data: XMLHttpRequestBodyInit): this {
|
|
39
|
-
this.#
|
|
40
|
-
|
|
49
|
+
if (this.#responseMode === 'stream') {
|
|
50
|
+
this.#send!(data as string)
|
|
51
|
+
} else {
|
|
52
|
+
this.#body = data
|
|
53
|
+
this.header('Content-Type', 'application/octet-stream')
|
|
54
|
+
}
|
|
41
55
|
return this
|
|
42
56
|
}
|
|
43
57
|
|
|
44
58
|
public json(data: unknown): this {
|
|
45
|
-
this.#
|
|
46
|
-
|
|
59
|
+
if (this.#responseMode === 'stream') {
|
|
60
|
+
this.#send!(JSON.stringify(data))
|
|
61
|
+
} else {
|
|
62
|
+
this.#body = JSON.stringify(data)
|
|
63
|
+
this.header('Content-Type', 'application/json')
|
|
64
|
+
}
|
|
47
65
|
return this
|
|
48
66
|
}
|
|
49
67
|
|
|
50
68
|
public text(content: string): this {
|
|
51
|
-
this.#
|
|
52
|
-
|
|
69
|
+
if (this.#responseMode === 'stream') {
|
|
70
|
+
this.#send!(content)
|
|
71
|
+
} else {
|
|
72
|
+
this.#body = content
|
|
73
|
+
this.header('Content-Type', 'text/plain')
|
|
74
|
+
}
|
|
53
75
|
return this
|
|
54
76
|
}
|
|
55
77
|
|
|
56
78
|
public html(content: string): this {
|
|
57
|
-
this.#
|
|
58
|
-
|
|
79
|
+
if (this.#responseMode === 'stream') {
|
|
80
|
+
this.#send!(content)
|
|
81
|
+
} else {
|
|
82
|
+
this.#body = content
|
|
83
|
+
this.header('Content-Type', 'text/html')
|
|
84
|
+
}
|
|
59
85
|
return this
|
|
60
86
|
}
|
|
61
87
|
|
|
62
|
-
public body(body: BodyInit): this {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
88
|
+
// public body(body: BodyInit): this {
|
|
89
|
+
// this.#body = body
|
|
90
|
+
// return this
|
|
91
|
+
// }
|
|
66
92
|
|
|
67
93
|
public redirect(location: string, status: number = 302): this {
|
|
68
94
|
this.#statusCode = status
|
|
@@ -70,6 +96,13 @@ export class PikkuFetchHTTPResponse implements PikkuHTTPResponse {
|
|
|
70
96
|
return this
|
|
71
97
|
}
|
|
72
98
|
|
|
99
|
+
public close(): this {
|
|
100
|
+
if (this.#close) {
|
|
101
|
+
this.#close()
|
|
102
|
+
}
|
|
103
|
+
return this
|
|
104
|
+
}
|
|
105
|
+
|
|
73
106
|
public toResponse(args?: Record<string, any>): Response {
|
|
74
107
|
const cookieHeader = Array.from(this.#cookies.entries()).map(
|
|
75
108
|
([name, { value, flags }]) => serializeCookie(name, value, flags)
|
|
@@ -81,4 +114,25 @@ export class PikkuFetchHTTPResponse implements PikkuHTTPResponse {
|
|
|
81
114
|
headers: this.#headers,
|
|
82
115
|
})
|
|
83
116
|
}
|
|
117
|
+
|
|
118
|
+
private createStream(): ReadableStream<Uint8Array> {
|
|
119
|
+
const encoder = new TextEncoder()
|
|
120
|
+
return new ReadableStream({
|
|
121
|
+
start: (controller) => {
|
|
122
|
+
const send = (data: string) => {
|
|
123
|
+
controller.enqueue(encoder.encode(`data: ${data}\n\n`))
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const close = () => {
|
|
127
|
+
controller.close()
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
this.#send = send
|
|
131
|
+
this.#close = close
|
|
132
|
+
|
|
133
|
+
// Force initial flush
|
|
134
|
+
controller.enqueue(encoder.encode(':\n\n'))
|
|
135
|
+
},
|
|
136
|
+
})
|
|
137
|
+
}
|
|
84
138
|
}
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @module @pikku/core
|
|
3
3
|
*/
|
|
4
4
|
export * from './types/core.types.js'
|
|
5
|
-
export * from './
|
|
5
|
+
export * from './function/index.js'
|
|
6
6
|
export * from './pikku-request.js'
|
|
7
7
|
export * from './pikku-response.js'
|
|
8
8
|
export * from './services/index.js'
|
|
@@ -12,8 +12,9 @@ export * from './scheduler/index.js'
|
|
|
12
12
|
export * from './errors/index.js'
|
|
13
13
|
export * from './middleware/index.js'
|
|
14
14
|
export * from './time-utils.js'
|
|
15
|
+
export * from './utils.js'
|
|
15
16
|
export { pikkuState } from './pikku-state.js'
|
|
16
17
|
export { runMiddleware } from './middleware-runner.js'
|
|
17
|
-
export {
|
|
18
|
+
export { addHTTPRoute, addMiddleware } from './http/http-runner.js'
|
|
18
19
|
export { addChannel } from './channel/channel-runner.js'
|
|
19
20
|
export { addScheduledTask } from './scheduler/scheduler-runner.js'
|
|
@@ -33,7 +33,8 @@ export const authAPIKey = <
|
|
|
33
33
|
}
|
|
34
34
|
)) => {
|
|
35
35
|
const middleware: PikkuMiddleware = async (services, { http }, next) => {
|
|
36
|
-
|
|
36
|
+
const { userSession: userSessionService, jwt: jwtService } = services
|
|
37
|
+
if (!http?.request || userSessionService.get()) {
|
|
37
38
|
return next()
|
|
38
39
|
}
|
|
39
40
|
|
|
@@ -47,15 +48,15 @@ export const authAPIKey = <
|
|
|
47
48
|
if (apiKey) {
|
|
48
49
|
let userSession: UserSession | null = null
|
|
49
50
|
if (jwt) {
|
|
50
|
-
if (!
|
|
51
|
+
if (!jwtService) {
|
|
51
52
|
throw new Error('JWT service is required for JWT decoding.')
|
|
52
53
|
}
|
|
53
|
-
userSession = await
|
|
54
|
+
userSession = await jwtService.decode(apiKey)
|
|
54
55
|
} else {
|
|
55
56
|
userSession = await getSessionForAPIKey!(services as any, apiKey)
|
|
56
57
|
}
|
|
57
58
|
if (userSession) {
|
|
58
|
-
|
|
59
|
+
userSessionService.setInitial(userSession)
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
return next()
|
|
@@ -28,8 +28,9 @@ export const authBearer = <
|
|
|
28
28
|
) => Promise<UserSession> | UserSession
|
|
29
29
|
} = {}): PikkuMiddleware => {
|
|
30
30
|
const middleware: PikkuMiddleware = async (services, { http }, next) => {
|
|
31
|
+
const { userSession: userSessionService, jwt: jwtService } = services
|
|
31
32
|
// Skip if session already exists.
|
|
32
|
-
if (!http?.request ||
|
|
33
|
+
if (!http?.request || userSessionService.get()) {
|
|
33
34
|
return next()
|
|
34
35
|
}
|
|
35
36
|
|
|
@@ -43,10 +44,10 @@ export const authBearer = <
|
|
|
43
44
|
}
|
|
44
45
|
let userSession: UserSession | null = null
|
|
45
46
|
if (jwt) {
|
|
46
|
-
if (!
|
|
47
|
+
if (!jwtService) {
|
|
47
48
|
throw new Error('JWT service is required for JWT decoding.')
|
|
48
49
|
}
|
|
49
|
-
userSession = await
|
|
50
|
+
userSession = await jwtService.decode(bearerToken)
|
|
50
51
|
} else if (token) {
|
|
51
52
|
if (bearerToken === token.value) {
|
|
52
53
|
userSession = token.userSession
|
|
@@ -56,7 +57,7 @@ export const authBearer = <
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
if (userSession) {
|
|
59
|
-
|
|
60
|
+
userSessionService.setInitial(userSession)
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
return next()
|
|
@@ -44,7 +44,12 @@ export const authCookie = <
|
|
|
44
44
|
}
|
|
45
45
|
)): PikkuMiddleware => {
|
|
46
46
|
const middleware: PikkuMiddleware = async (services, { http }, next) => {
|
|
47
|
-
|
|
47
|
+
const {
|
|
48
|
+
userSession: userSessionService,
|
|
49
|
+
jwt: jwtService,
|
|
50
|
+
logger,
|
|
51
|
+
} = services
|
|
52
|
+
if (!http?.request || userSessionService.get()) {
|
|
48
53
|
return next()
|
|
49
54
|
}
|
|
50
55
|
|
|
@@ -52,10 +57,10 @@ export const authCookie = <
|
|
|
52
57
|
const cookieValue = http.request.cookie(name)
|
|
53
58
|
if (cookieValue) {
|
|
54
59
|
if (jwt) {
|
|
55
|
-
if (!
|
|
60
|
+
if (!jwtService) {
|
|
56
61
|
throw new Error('JWT service is required for JWT decoding.')
|
|
57
62
|
}
|
|
58
|
-
userSession = await
|
|
63
|
+
userSession = await jwtService.decode(cookieValue)
|
|
59
64
|
} else if (getSessionForCookieValue) {
|
|
60
65
|
userSession = await getSessionForCookieValue(
|
|
61
66
|
services as any,
|
|
@@ -66,7 +71,7 @@ export const authCookie = <
|
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
if (userSession) {
|
|
69
|
-
|
|
74
|
+
userSessionService.setInitial(userSession)
|
|
70
75
|
}
|
|
71
76
|
await next()
|
|
72
77
|
|
|
@@ -75,22 +80,22 @@ export const authCookie = <
|
|
|
75
80
|
return
|
|
76
81
|
}
|
|
77
82
|
|
|
78
|
-
if (
|
|
79
|
-
const session =
|
|
83
|
+
if (userSessionService.sessionChanged) {
|
|
84
|
+
const session = userSessionService.get()
|
|
80
85
|
if (jwt) {
|
|
81
|
-
if (!
|
|
86
|
+
if (!jwtService) {
|
|
82
87
|
throw new Error('JWT service is required for JWT encoding.')
|
|
83
88
|
}
|
|
84
89
|
http.response.cookie(
|
|
85
90
|
name,
|
|
86
|
-
await
|
|
91
|
+
await jwtService.encode(expiresIn, session),
|
|
87
92
|
{
|
|
88
93
|
...options,
|
|
89
94
|
expires: getRelativeTimeOffsetFromNow(expiresIn),
|
|
90
95
|
}
|
|
91
96
|
)
|
|
92
97
|
} else {
|
|
93
|
-
|
|
98
|
+
logger.warn('No JWT service available, unable to set cookie')
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
101
|
}
|
package/src/permissions.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CoreServices, CoreUserSession } from './types/core.types.js'
|
|
2
|
-
import {
|
|
2
|
+
import { CorePermissionGroup } from './function/functions.types.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* This function validates permissions by iterating over permission groups and executing the corresponding permission functions. If all functions in at least one group return true, the permission is considered valid.
|
|
@@ -9,9 +9,7 @@ import { CoreAPIPermission } from './types/functions.types.js'
|
|
|
9
9
|
* @returns A promise that resolves to void.
|
|
10
10
|
*/
|
|
11
11
|
export const verifyPermissions = async (
|
|
12
|
-
permissions:
|
|
13
|
-
| Record<string, CoreAPIPermission<any>[] | CoreAPIPermission<any>>
|
|
14
|
-
| undefined,
|
|
12
|
+
permissions: CorePermissionGroup,
|
|
15
13
|
services: CoreServices,
|
|
16
14
|
data: any,
|
|
17
15
|
session?: CoreUserSession
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const callFunction = () => {}
|
package/src/pikku-state.ts
CHANGED
|
@@ -1,23 +1,35 @@
|
|
|
1
|
-
import { ChannelsMeta,
|
|
1
|
+
import { ChannelsMeta, CoreAPIChannel } from './channel/channel.types.js'
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
CoreHTTPFunctionRoute,
|
|
4
|
+
HTTPMethod,
|
|
4
5
|
HTTPRoutesMeta,
|
|
5
|
-
} from './http/http
|
|
6
|
-
import { PikkuMiddleware } from './types/core.types.js'
|
|
6
|
+
} from './http/http.types.js'
|
|
7
|
+
import { FunctionsMeta, PikkuMiddleware } from './types/core.types.js'
|
|
7
8
|
import {
|
|
8
9
|
CoreScheduledTask,
|
|
9
10
|
ScheduledTasksMeta,
|
|
10
11
|
} from './scheduler/scheduler.types.js'
|
|
11
12
|
import { ErrorDetails, PikkuError } from './errors/error-handler.js'
|
|
13
|
+
import {
|
|
14
|
+
CoreAPIFunction,
|
|
15
|
+
CoreAPIFunctionSessionless,
|
|
16
|
+
} from './function/functions.types.js'
|
|
12
17
|
|
|
13
18
|
interface PikkuState {
|
|
19
|
+
functions: {
|
|
20
|
+
meta: FunctionsMeta
|
|
21
|
+
nameToFunction: Map<
|
|
22
|
+
string,
|
|
23
|
+
CoreAPIFunction<any, any> | CoreAPIFunctionSessionless<any, any>
|
|
24
|
+
>
|
|
25
|
+
}
|
|
14
26
|
http: {
|
|
15
27
|
middleware: Array<{ route: string; middleware: PikkuMiddleware[] }>
|
|
16
|
-
routes:
|
|
28
|
+
routes: Map<HTTPMethod, Map<string, CoreHTTPFunctionRoute<any, any, any>>>
|
|
17
29
|
meta: HTTPRoutesMeta
|
|
18
30
|
}
|
|
19
31
|
channel: {
|
|
20
|
-
channels:
|
|
32
|
+
channels: Map<string, CoreAPIChannel<any, any>>
|
|
21
33
|
meta: ChannelsMeta
|
|
22
34
|
}
|
|
23
35
|
scheduler: {
|
|
@@ -32,14 +44,18 @@ interface PikkuState {
|
|
|
32
44
|
|
|
33
45
|
export const resetPikkuState = () => {
|
|
34
46
|
globalThis.pikkuState = {
|
|
47
|
+
functions: {
|
|
48
|
+
meta: {},
|
|
49
|
+
nameToFunction: new Map(),
|
|
50
|
+
},
|
|
35
51
|
http: {
|
|
36
52
|
middleware: [],
|
|
37
|
-
routes:
|
|
53
|
+
routes: new Map(),
|
|
38
54
|
meta: [],
|
|
39
55
|
},
|
|
40
56
|
channel: {
|
|
41
|
-
channels:
|
|
42
|
-
meta:
|
|
57
|
+
channels: new Map(),
|
|
58
|
+
meta: {},
|
|
43
59
|
},
|
|
44
60
|
scheduler: {
|
|
45
61
|
tasks: new Map(),
|
|
@@ -5,10 +5,11 @@ import type {
|
|
|
5
5
|
CreateSessionServices,
|
|
6
6
|
} from '../types/core.types.js'
|
|
7
7
|
import type { CoreScheduledTask } from './scheduler.types.js'
|
|
8
|
-
import type { CoreAPIFunctionSessionless } from '../
|
|
8
|
+
import type { CoreAPIFunctionSessionless } from '../function/functions.types.js'
|
|
9
9
|
import { getErrorResponse } from '../errors/error-handler.js'
|
|
10
10
|
import { closeSessionServices } from '../utils.js'
|
|
11
11
|
import { pikkuState } from '../pikku-state.js'
|
|
12
|
+
import { addFunction, runPikkuFunc } from '../function/function-runner.js'
|
|
12
13
|
|
|
13
14
|
export type RunScheduledTasksParams = {
|
|
14
15
|
name: string
|
|
@@ -26,6 +27,13 @@ export const addScheduledTask = <
|
|
|
26
27
|
>(
|
|
27
28
|
scheduledTask: CoreScheduledTask<APIFunction>
|
|
28
29
|
) => {
|
|
30
|
+
const meta = pikkuState('scheduler', 'meta')
|
|
31
|
+
const taskMeta = meta[scheduledTask.name]
|
|
32
|
+
if (!taskMeta) {
|
|
33
|
+
throw new Error('Task metadata not found')
|
|
34
|
+
}
|
|
35
|
+
addFunction(taskMeta.pikkuFuncName, scheduledTask.func)
|
|
36
|
+
|
|
29
37
|
const tasks = pikkuState('scheduler', 'tasks')
|
|
30
38
|
if (tasks.has(scheduledTask.name)) {
|
|
31
39
|
throw new Error(`Scheduled task already exists: ${scheduledTask.name}`)
|
|
@@ -51,33 +59,43 @@ export async function runScheduledTask<
|
|
|
51
59
|
let sessionServices: CoreServices | undefined
|
|
52
60
|
try {
|
|
53
61
|
const task = pikkuState('scheduler', 'tasks').get(name)
|
|
54
|
-
|
|
62
|
+
const meta = pikkuState('scheduler', 'meta')[name]
|
|
55
63
|
if (!task) {
|
|
56
64
|
throw new ScheduledTaskNotFoundError(`Scheduled task not found: ${name}`)
|
|
57
65
|
}
|
|
66
|
+
if (!meta) {
|
|
67
|
+
throw new ScheduledTaskNotFoundError(
|
|
68
|
+
`Scheduled task meta not found: ${name}`
|
|
69
|
+
)
|
|
70
|
+
}
|
|
58
71
|
|
|
59
72
|
singletonServices.logger.info(
|
|
60
73
|
`Running schedule task: ${name} | schedule: ${task.schedule}`
|
|
61
74
|
)
|
|
62
75
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
76
|
+
const getAllServices = async () => {
|
|
77
|
+
if (createSessionServices) {
|
|
78
|
+
const sessionServices = await createSessionServices(
|
|
79
|
+
singletonServices,
|
|
80
|
+
{},
|
|
81
|
+
session
|
|
82
|
+
)
|
|
83
|
+
return { ...singletonServices, ...sessionServices }
|
|
84
|
+
}
|
|
85
|
+
return singletonServices
|
|
71
86
|
}
|
|
72
87
|
|
|
73
|
-
await
|
|
88
|
+
return await runPikkuFunc(meta.pikkuFuncName, {
|
|
89
|
+
singletonServices,
|
|
90
|
+
getAllServices,
|
|
91
|
+
session,
|
|
92
|
+
data: undefined,
|
|
93
|
+
})
|
|
74
94
|
} catch (e: any) {
|
|
75
95
|
const errorResponse = getErrorResponse(e)
|
|
76
|
-
|
|
77
96
|
if (errorResponse != null) {
|
|
78
97
|
singletonServices.logger.error(e)
|
|
79
98
|
}
|
|
80
|
-
|
|
81
99
|
throw e
|
|
82
100
|
} finally {
|
|
83
101
|
if (sessionServices) {
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { APIDocs, CoreUserSession } from '../types/core.types.js'
|
|
2
|
-
import { CoreAPIFunctionSessionless } from '../
|
|
2
|
+
import { CoreAPIFunctionSessionless } from '../function/functions.types.js'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Represents metadata for scheduled tasks, including title, schedule, and documentation.
|
|
6
6
|
*/
|
|
7
7
|
export type ScheduledTasksMeta<UserSession extends CoreUserSession = any> =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
Record<
|
|
9
|
+
string,
|
|
10
|
+
{
|
|
11
|
+
pikkuFuncName: string
|
|
12
|
+
name: string
|
|
13
|
+
schedule: string
|
|
14
|
+
session?: UserSession
|
|
15
|
+
docs?: APIDocs
|
|
16
|
+
tags?: string[]
|
|
17
|
+
}
|
|
18
|
+
>
|
|
15
19
|
|
|
16
20
|
/**
|
|
17
21
|
* Represents a core scheduled task.
|