@pikku/core 0.6.13 → 0.6.15

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.
Files changed (82) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/channel/channel-handler.d.ts +2 -2
  3. package/dist/channel/channel-handler.js +4 -4
  4. package/dist/channel/channel-runner.d.ts +5 -4
  5. package/dist/channel/channel-runner.js +8 -14
  6. package/dist/channel/channel.types.d.ts +11 -18
  7. package/dist/channel/local/local-channel-handler.d.ts +1 -3
  8. package/dist/channel/local/local-channel-handler.js +0 -3
  9. package/dist/channel/local/local-channel-runner.js +49 -33
  10. package/dist/channel/pikku-abstract-channel-handler.d.ts +4 -7
  11. package/dist/channel/pikku-abstract-channel-handler.js +1 -5
  12. package/dist/channel/serverless/serverless-channel-runner.js +45 -38
  13. package/dist/handle-error.d.ts +14 -0
  14. package/dist/handle-error.js +53 -0
  15. package/dist/http/http-route-runner.d.ts +34 -11
  16. package/dist/http/http-route-runner.js +177 -106
  17. package/dist/http/http-routes.types.d.ts +15 -9
  18. package/dist/http/index.d.ts +0 -1
  19. package/dist/http/index.js +0 -1
  20. package/dist/http/pikku-http-abstract-request.d.ts +4 -1
  21. package/dist/http/pikku-http-abstract-request.js +7 -0
  22. package/dist/index.d.ts +2 -0
  23. package/dist/index.js +2 -0
  24. package/dist/middleware/auth-api-key.d.ts +9 -0
  25. package/dist/middleware/auth-api-key.js +23 -0
  26. package/dist/middleware/auth-cookie-middleware.d.ts +11 -0
  27. package/dist/middleware/auth-cookie-middleware.js +36 -0
  28. package/dist/middleware/auth-jwt-middleware.d.ts +10 -0
  29. package/dist/middleware/auth-jwt-middleware.js +32 -0
  30. package/dist/middleware/auth-query-middleware.d.ts +10 -0
  31. package/dist/middleware/auth-query-middleware.js +21 -0
  32. package/dist/middleware/index.d.ts +4 -0
  33. package/dist/middleware/index.js +4 -0
  34. package/dist/middleware-runner.d.ts +22 -0
  35. package/dist/middleware-runner.js +28 -0
  36. package/dist/scheduler/scheduler.types.d.ts +2 -0
  37. package/dist/schema.d.ts +1 -1
  38. package/dist/schema.js +3 -6
  39. package/dist/services/index.d.ts +1 -0
  40. package/dist/services/index.js +1 -0
  41. package/dist/services/user-session-service.d.ts +20 -3
  42. package/dist/services/user-session-service.js +35 -1
  43. package/dist/types/core.types.d.ts +11 -15
  44. package/dist/types/functions.types.d.ts +4 -4
  45. package/lcov.info +1572 -1729
  46. package/package.json +1 -2
  47. package/src/channel/channel-handler.ts +6 -11
  48. package/src/channel/channel-runner.ts +13 -32
  49. package/src/channel/channel.types.ts +13 -39
  50. package/src/channel/local/local-channel-handler.ts +1 -7
  51. package/src/channel/local/local-channel-runner.test.ts +2 -5
  52. package/src/channel/local/local-channel-runner.ts +72 -54
  53. package/src/channel/pikku-abstract-channel-handler.test.ts +3 -28
  54. package/src/channel/pikku-abstract-channel-handler.ts +3 -9
  55. package/src/channel/serverless/serverless-channel-runner.ts +68 -56
  56. package/src/handle-error.ts +67 -0
  57. package/src/http/http-route-runner.test.ts +12 -45
  58. package/src/http/http-route-runner.ts +256 -182
  59. package/src/http/http-routes.types.ts +15 -10
  60. package/src/http/index.ts +0 -2
  61. package/src/http/pikku-http-abstract-request.ts +8 -1
  62. package/src/index.ts +2 -0
  63. package/src/middleware/auth-api-key.ts +32 -0
  64. package/src/middleware/auth-cookie-middleware.ts +54 -0
  65. package/src/middleware/auth-jwt-middleware.ts +47 -0
  66. package/src/middleware/auth-query-middleware.ts +33 -0
  67. package/src/middleware/index.ts +4 -0
  68. package/src/middleware-runner.ts +43 -0
  69. package/src/scheduler/scheduler.types.ts +2 -0
  70. package/src/schema.ts +4 -8
  71. package/src/services/index.ts +1 -0
  72. package/src/services/user-session-service.ts +45 -3
  73. package/src/types/core.types.ts +19 -18
  74. package/src/types/functions.types.ts +11 -7
  75. package/tsconfig.tsbuildinfo +1 -1
  76. package/dist/http/http-session-service.d.ts +0 -15
  77. package/dist/http/http-session-service.js +0 -1
  78. package/dist/http/pikku-http-session-service.d.ts +0 -45
  79. package/dist/http/pikku-http-session-service.js +0 -92
  80. package/src/http/http-session-service.ts +0 -19
  81. package/src/http/pikku-http-session-service.test.ts +0 -106
  82. package/src/http/pikku-http-session-service.ts +0 -135
@@ -1,4 +1,4 @@
1
- import { CoreUserSession, SessionServices } from '../../types/core.types.js'
1
+ import { SessionServices } from '../../types/core.types.js'
2
2
  import { closeSessionServices } from '../../utils.js'
3
3
  import { processMessageHandlers } from '../channel-handler.js'
4
4
  import { getChannels, openChannel } from '../channel-runner.js'
@@ -8,11 +8,11 @@ import type {
8
8
  RunChannelParams,
9
9
  PikkuChannelHandlerFactory,
10
10
  } from '../channel.types.js'
11
- import {
12
- createHTTPInteraction,
13
- handleError,
14
- } from '../../http/http-route-runner.js'
11
+ import { createHTTPInteraction } from '../../http/http-route-runner.js'
15
12
  import { ChannelStore } from '../channel-store.js'
13
+ import { handleError } from '../../handle-error.js'
14
+ import { RemoteUserSessionService } from '../../services/user-session-service.js'
15
+ import { runMiddleware } from '../../middleware-runner.js'
16
16
 
17
17
  export interface RunServerlessChannelParams<ChannelData>
18
18
  extends RunChannelParams<ChannelData> {
@@ -23,14 +23,12 @@ export interface RunServerlessChannelParams<ChannelData>
23
23
 
24
24
  const getVariablesForChannel = ({
25
25
  channelId,
26
- userSession,
27
26
  channelName,
28
27
  channelHandlerFactory,
29
28
  openingData,
30
29
  }: {
31
30
  channelId: string
32
31
  channelName: string
33
- userSession?: CoreUserSession
34
32
  channelHandlerFactory: PikkuChannelHandlerFactory
35
33
  openingData?: unknown
36
34
  }) => {
@@ -44,8 +42,7 @@ const getVariablesForChannel = ({
44
42
  const channelHandler = channelHandlerFactory(
45
43
  channelId,
46
44
  channelConfig.name,
47
- openingData,
48
- userSession
45
+ openingData
49
46
  )
50
47
  return {
51
48
  channelConfig,
@@ -73,54 +70,71 @@ export const runChannelConnect = async ({
73
70
  RunServerlessChannelParams<unknown>) => {
74
71
  let sessionServices: SessionServices | undefined
75
72
  const http = createHTTPInteraction(request, response)
76
- try {
77
- const { userSession, channelConfig, openingData } = await openChannel({
78
- channelId,
79
- createSessionServices,
80
- http,
81
- route,
82
- singletonServices,
83
- coerceToArray,
84
- })
85
- await channelStore.addChannel({
86
- channelId,
87
- channelName: channelConfig.name,
88
- openingData,
89
- channelObject,
90
- })
91
- const { channel } = getVariablesForChannel({
92
- channelId,
93
- userSession,
94
- channelHandlerFactory,
95
- channelName: channelConfig.name,
96
- })
97
- if (createSessionServices) {
98
- sessionServices = await createSessionServices(
99
- singletonServices,
100
- { http },
101
- userSession
73
+ const userSessionService = new RemoteUserSessionService(
74
+ channelStore,
75
+ channelId
76
+ )
77
+
78
+ const { channelConfig, openingData } = await openChannel({
79
+ channelId,
80
+ createSessionServices,
81
+ http,
82
+ route,
83
+ singletonServices,
84
+ coerceToArray,
85
+ })
86
+
87
+ const main = async () => {
88
+ try {
89
+ await channelStore.addChannel({
90
+ channelId,
91
+ channelName: channelConfig.name,
92
+ openingData,
93
+ channelObject,
94
+ })
95
+ const { channel } = getVariablesForChannel({
96
+ channelId,
97
+ channelHandlerFactory,
98
+ channelName: channelConfig.name,
99
+ })
100
+ if (createSessionServices) {
101
+ sessionServices = await createSessionServices(
102
+ singletonServices,
103
+ { http },
104
+ await userSessionService.get()
105
+ )
106
+ }
107
+ await channelConfig.onConnect?.(
108
+ { ...singletonServices, ...sessionServices },
109
+ channel
102
110
  )
103
- }
104
- await channelConfig.onConnect?.(
105
- { ...singletonServices, ...sessionServices },
106
- channel
107
- )
108
- http?.response?.setStatus(101)
109
- } catch (e: any) {
110
- handleError(
111
- e,
112
- http,
113
- channelId,
114
- singletonServices.logger,
115
- logWarningsForStatusCodes,
116
- respondWith404,
117
- bubbleErrors
118
- )
119
- } finally {
120
- if (sessionServices) {
121
- await closeSessionServices(singletonServices.logger, sessionServices)
111
+ http?.response?.setStatus(101)
112
+ } catch (e: any) {
113
+ handleError(
114
+ e,
115
+ http,
116
+ channelId,
117
+ singletonServices.logger,
118
+ logWarningsForStatusCodes,
119
+ respondWith404,
120
+ bubbleErrors
121
+ )
122
+ } finally {
123
+ if (sessionServices) {
124
+ await closeSessionServices(singletonServices.logger, sessionServices)
125
+ }
122
126
  }
123
127
  }
128
+
129
+ await runMiddleware(
130
+ {
131
+ ...singletonServices,
132
+ userSessionService,
133
+ },
134
+ { http },
135
+ channelConfig.middleware || [],
136
+ main
137
+ )
124
138
  }
125
139
 
126
140
  export const runChannelDisconnect = async ({
@@ -132,7 +146,6 @@ export const runChannelDisconnect = async ({
132
146
  await params.channelStore.getChannel(params.channelId)
133
147
  const { channel, channelConfig } = getVariablesForChannel({
134
148
  ...params,
135
- userSession,
136
149
  openingData,
137
150
  channelName,
138
151
  })
@@ -162,7 +175,6 @@ export const runChannelMessage = async (
162
175
  await params.channelStore.getChannel(params.channelId)
163
176
  const { channelHandler, channelConfig } = getVariablesForChannel({
164
177
  ...params,
165
- userSession,
166
178
  openingData,
167
179
  channelName,
168
180
  })
@@ -0,0 +1,67 @@
1
+ import { getErrorResponse } from './errors/error-handler.js'
2
+ import { NotFoundError } from './errors/errors.js'
3
+ import { Logger } from './services/logger.js'
4
+ import { PikkuHTTP } from './http/http-routes.types.js'
5
+
6
+ /**
7
+ * Handle errors that occur during route processing
8
+ *
9
+ * @param {any} e - The error that occurred
10
+ * @param {PikkuHTTP | undefined} http - HTTP interaction object
11
+ * @param {string} trackerId - Unique ID for tracking this error
12
+ * @param {Logger} logger - Logger service
13
+ * @param {number[]} logWarningsForStatusCodes - HTTP status codes to log as warnings
14
+ * @param {boolean} respondWith404 - Whether to respond with 404 for NotFoundError
15
+ * @param {boolean} bubbleError - Whether to throw the error after handling
16
+ */
17
+ export const handleError = (
18
+ e: any,
19
+ http: PikkuHTTP | undefined,
20
+ trackerId: string,
21
+ logger: Logger,
22
+ logWarningsForStatusCodes: number[],
23
+ respondWith404: boolean,
24
+ bubbleError: boolean
25
+ ) => {
26
+ // Skip 404 handling if configured to do so
27
+ if (e instanceof NotFoundError && !respondWith404) {
28
+ return
29
+ }
30
+
31
+ // Get appropriate error response
32
+ const errorResponse = getErrorResponse(e)
33
+
34
+ if (errorResponse != null) {
35
+ // Set status and response body
36
+ http?.response?.setStatus(errorResponse.status)
37
+ http?.response?.setJson({
38
+ message: errorResponse.message,
39
+ payload: (e as any).payload,
40
+ traceId: trackerId,
41
+ })
42
+
43
+ // Log certain status codes as warnings
44
+ if (logWarningsForStatusCodes.includes(errorResponse.status)) {
45
+ logger.warn(`Warning id: ${trackerId}`)
46
+ logger.warn(e)
47
+ }
48
+ } else {
49
+ // Handle unexpected errors
50
+ logger.warn(`Error id: ${trackerId}`)
51
+ logger.error(e)
52
+ http?.response?.setStatus(500)
53
+ http?.response?.setJson({ errorId: trackerId })
54
+ }
55
+
56
+ // Handle 404 errors specifically
57
+ if (e instanceof NotFoundError) {
58
+ http?.response?.end()
59
+ }
60
+
61
+ // Either bubble up or end the response
62
+ if (bubbleError) {
63
+ throw e
64
+ } else {
65
+ http?.response?.end()
66
+ }
67
+ }
@@ -1,15 +1,10 @@
1
1
  import { test, describe, beforeEach, afterEach } from 'node:test'
2
2
  import * as assert from 'assert'
3
- import { NotFoundError, NotImplementedError } from '../errors/errors.js'
3
+ 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
- import { JSONValue } from '../types/core.types.js'
7
- import {
8
- getUserSession,
9
- runHTTPRoute,
10
- clearRoutes,
11
- addRoute,
12
- } from './http-route-runner.js'
6
+ import { JSONValue, PikkuMiddleware } from '../types/core.types.js'
7
+ import { runHTTPRoute, clearRoutes, addRoute } from './http-route-runner.js'
13
8
 
14
9
  class PikkuTestRequest extends PikkuHTTPAbstractRequest {
15
10
  public getBody(): Promise<unknown> {
@@ -32,6 +27,11 @@ class PikkuTestResponse extends PikkuHTTPAbstractResponse {
32
27
  }
33
28
  }
34
29
 
30
+ const sessionMiddleware: PikkuMiddleware = async (services, _, next) => {
31
+ services.userSessionService.set({ userId: 'test' } as any)
32
+ await next()
33
+ }
34
+
35
35
  describe('runHTTPRoute', () => {
36
36
  let singletonServices: any
37
37
  let createSessionServices: any
@@ -47,13 +47,10 @@ describe('runHTTPRoute', () => {
47
47
  warn: () => {},
48
48
  error: () => {},
49
49
  },
50
- httpSessionService: {
51
- getUserSession: async () => {},
52
- },
53
50
  }
54
51
 
55
52
  createSessionServices = async () => ({})
56
- request = new PikkuTestRequest()
53
+ request = new PikkuTestRequest('path', 'get')
57
54
  response = new PikkuTestResponse()
58
55
 
59
56
  request.getData = async () => ({})
@@ -91,6 +88,7 @@ describe('runHTTPRoute', () => {
91
88
  route: 'test',
92
89
  method: 'get',
93
90
  func: routeFunc,
91
+ middleware: [sessionMiddleware],
94
92
  })
95
93
 
96
94
  const result = await runHTTPRoute({
@@ -116,6 +114,7 @@ describe('runHTTPRoute', () => {
116
114
  method: 'get',
117
115
  func: routeFunc,
118
116
  permissions,
117
+ middleware: [sessionMiddleware],
119
118
  })
120
119
 
121
120
  await runHTTPRoute({
@@ -141,6 +140,7 @@ describe('runHTTPRoute', () => {
141
140
  route: 'test',
142
141
  method: 'get',
143
142
  func: routeFunc,
143
+ middleware: [sessionMiddleware],
144
144
  })
145
145
 
146
146
  await assert.rejects(
@@ -158,36 +158,3 @@ describe('runHTTPRoute', () => {
158
158
  )
159
159
  })
160
160
  })
161
-
162
- describe('getUserSession', () => {
163
- let sessionService: any
164
- let request: any
165
-
166
- beforeEach(() => {
167
- sessionService = {
168
- getUserSession: async () => ({}),
169
- }
170
- request = new PikkuTestRequest()
171
- })
172
-
173
- test('should return user session when sessionService is provided', async () => {
174
- const userSession = { id: '123', username: 'test' }
175
- sessionService.getUserSession = async () => userSession
176
-
177
- const result = await getUserSession(sessionService, true, request)
178
-
179
- assert.deepStrictEqual(result, userSession)
180
- })
181
-
182
- test('should throw NotImplementedError when session is required but sessionService is not provided', async () => {
183
- await assert.rejects(
184
- async () => getUserSession(undefined, true, request),
185
- NotImplementedError
186
- )
187
- })
188
-
189
- test('should return undefined when session is not required and sessionService is not provided', async () => {
190
- const result = await getUserSession(undefined, false, request)
191
- assert.strictEqual(result, undefined)
192
- })
193
- })