@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.
Files changed (75) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/dist/channel/channel-handler.js +16 -38
  3. package/dist/channel/channel-runner.d.ts +7 -8
  4. package/dist/channel/channel-runner.js +58 -7
  5. package/dist/channel/channel.types.d.ts +14 -27
  6. package/dist/channel/local/local-channel-runner.js +9 -4
  7. package/dist/channel/log-channels.js +4 -4
  8. package/dist/channel/serverless/serverless-channel-runner.js +17 -6
  9. package/dist/function/function-runner.d.ts +12 -0
  10. package/dist/function/function-runner.js +38 -0
  11. package/dist/{types → function}/functions.types.d.ts +12 -7
  12. package/dist/function/index.d.ts +2 -0
  13. package/dist/function/index.js +2 -0
  14. package/dist/handle-error.d.ts +1 -1
  15. package/dist/http/{http-route-runner.d.ts → http-runner.d.ts} +4 -4
  16. package/dist/http/{http-route-runner.js → http-runner.js} +81 -43
  17. package/dist/http/{http-routes.types.d.ts → http.types.d.ts} +41 -12
  18. package/dist/http/index.d.ts +2 -2
  19. package/dist/http/index.js +1 -1
  20. package/dist/http/log-http-routes.js +7 -5
  21. package/dist/http/pikku-fetch-http-request.d.ts +1 -1
  22. package/dist/http/pikku-fetch-http-response.d.ts +4 -2
  23. package/dist/http/pikku-fetch-http-response.js +64 -12
  24. package/dist/index.d.ts +3 -2
  25. package/dist/index.js +3 -2
  26. package/dist/middleware/auth-apikey.js +5 -4
  27. package/dist/middleware/auth-bearer.js +5 -4
  28. package/dist/middleware/auth-cookie.js +10 -9
  29. package/dist/permissions.d.ts +2 -2
  30. package/dist/pikku-function.d.ts +1 -0
  31. package/dist/pikku-function.js +1 -0
  32. package/dist/pikku-state.d.ts +10 -5
  33. package/dist/pikku-state.js +7 -3
  34. package/dist/scheduler/scheduler-runner.d.ts +1 -1
  35. package/dist/scheduler/scheduler-runner.js +24 -6
  36. package/dist/scheduler/scheduler.types.d.ts +3 -2
  37. package/dist/services/content-service.d.ts +33 -37
  38. package/dist/types/core.types.d.ts +15 -1
  39. package/dist/utils.d.ts +2 -0
  40. package/dist/utils.js +15 -0
  41. package/lcov.info +1240 -965
  42. package/package.json +2 -1
  43. package/src/channel/channel-handler.ts +16 -78
  44. package/src/channel/channel-runner.ts +72 -17
  45. package/src/channel/channel.types.ts +25 -63
  46. package/src/channel/local/local-channel-runner.test.ts +10 -11
  47. package/src/channel/local/local-channel-runner.ts +20 -7
  48. package/src/channel/log-channels.ts +4 -4
  49. package/src/channel/serverless/serverless-channel-runner.ts +26 -15
  50. package/src/function/function-runner.ts +91 -0
  51. package/src/{types → function}/functions.types.ts +25 -11
  52. package/src/function/index.ts +2 -0
  53. package/src/handle-error.ts +1 -1
  54. package/src/http/{http-route-runner.test.ts → http-runner.test.ts} +29 -6
  55. package/src/http/{http-route-runner.ts → http-runner.ts} +106 -73
  56. package/src/http/{http-routes.types.ts → http.types.ts} +55 -16
  57. package/src/http/index.ts +2 -2
  58. package/src/http/log-http-routes.ts +7 -5
  59. package/src/http/pikku-fetch-http-request.ts +1 -5
  60. package/src/http/pikku-fetch-http-response.ts +67 -13
  61. package/src/index.ts +3 -2
  62. package/src/middleware/auth-apikey.ts +5 -4
  63. package/src/middleware/auth-bearer.ts +5 -4
  64. package/src/middleware/auth-cookie.ts +14 -9
  65. package/src/permissions.ts +2 -4
  66. package/src/pikku-function.ts +1 -0
  67. package/src/pikku-state.ts +25 -9
  68. package/src/scheduler/scheduler-runner.ts +31 -13
  69. package/src/scheduler/scheduler.types.ts +12 -8
  70. package/src/services/content-service.ts +36 -40
  71. package/src/types/core.types.ts +20 -1
  72. package/src/utils.ts +19 -0
  73. package/tsconfig.tsbuildinfo +1 -1
  74. /package/dist/{types → function}/functions.types.js +0 -0
  75. /package/dist/http/{http-routes.types.js → http.types.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/core",
3
- "version": "0.6.27",
3
+ "version": "0.7.1",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "module": "dist/index.js",
@@ -19,6 +19,7 @@
19
19
  "exports": {
20
20
  ".": "./dist/index.js",
21
21
  "./middleware": "./dist/middleware/index.js",
22
+ "./function": "./dist/function/index.js",
22
23
  "./channel": "./dist/channel/index.js",
23
24
  "./channel/local": "./dist/channel/local/index.js",
24
25
  "./channel/serverless": "./dist/channel/serverless/index.js",
@@ -1,5 +1,4 @@
1
1
  import {
2
- CoreSingletonServices,
3
2
  CoreServices,
4
3
  JSONValue,
5
4
  CoreUserSession,
@@ -9,18 +8,15 @@ import {
9
8
  CoreAPIChannel,
10
9
  PikkuChannelHandler,
11
10
  } from './channel.types.js'
12
- import { verifyPermissions } from '../permissions.js'
13
11
  import { pikkuState } from '../pikku-state.js'
12
+ import { runPikkuFunc } from '../function/function-runner.js'
14
13
 
15
14
  const getRouteMeta = (
16
15
  channelName: string,
17
16
  routingProperty?: string,
18
17
  routerValue?: string
19
18
  ): ChannelMessageMeta => {
20
- const channelsMeta = pikkuState('channel', 'meta')
21
- const channelMeta = channelsMeta.find(
22
- (channelMeta) => channelMeta.name === channelName
23
- )
19
+ const channelMeta = pikkuState('channel', 'meta')[channelName]
24
20
  if (!channelMeta) {
25
21
  throw new Error(`Channel ${channelName} not found`)
26
22
  }
@@ -44,19 +40,6 @@ const getRouteMeta = (
44
40
  return route
45
41
  }
46
42
 
47
- const validateSchema = (
48
- logger: CoreSingletonServices['logger'],
49
- data: JSONValue,
50
- channelRoute: ChannelMessageMeta
51
- ) => {
52
- const schemaNames = channelRoute.inputs
53
- if (schemaNames) {
54
- // TODO
55
- // loadSchema(schemaNames, logger)
56
- // validateJson(schemaNames, data)
57
- }
58
- }
59
-
60
43
  const validateAuth = (
61
44
  requiresSession: boolean,
62
45
  session: CoreUserSession | undefined,
@@ -75,40 +58,6 @@ const validateAuth = (
75
58
  return true
76
59
  }
77
60
 
78
- const validatePermissions = async (
79
- services: CoreServices,
80
- session: CoreUserSession | undefined,
81
- onMessage: any,
82
- data: unknown
83
- ) => {
84
- const permissions =
85
- typeof onMessage === 'function' ? {} : onMessage.permissions
86
- return await verifyPermissions(permissions, services, data, session)
87
- }
88
-
89
- const runFunction = async (
90
- services: CoreServices,
91
- channelHandler: PikkuChannelHandler,
92
- channelMessageMeta: ChannelMessageMeta,
93
- session: CoreUserSession | undefined,
94
- onMessage: any,
95
- data: unknown
96
- ) => {
97
- const func: any = typeof onMessage === 'function' ? onMessage : onMessage.func
98
- if (channelMessageMeta.type?.toLowerCase().includes('function')) {
99
- return await func(
100
- {
101
- ...services,
102
- channel: channelHandler.getChannel(),
103
- },
104
- data,
105
- session
106
- )
107
- } else {
108
- return await func(services, channelHandler.getChannel(), data)
109
- }
110
- }
111
-
112
61
  export const processMessageHandlers = (
113
62
  services: CoreServices,
114
63
  session: CoreUserSession | undefined,
@@ -137,36 +86,25 @@ export const processMessageHandlers = (
137
86
  return
138
87
  }
139
88
 
140
- const routeMeta = getRouteMeta(
89
+ const { pikkuFuncName } = getRouteMeta(
141
90
  channelConfig.name,
142
91
  routingProperty,
143
92
  routerValue
144
93
  )
145
94
 
146
- if (routeMeta) {
147
- await validateSchema(services.logger, data, routeMeta)
148
- }
149
-
150
- const hasPermission = await validatePermissions(
151
- services,
152
- channelHandler,
153
- onMessage,
154
- data
155
- )
156
- if (!hasPermission) {
157
- logger.error(
158
- `Channel ${channelConfig.name} requires permissions for ${routingProperty || 'default message route'}`
159
- )
160
- }
95
+ const permissions =
96
+ typeof onMessage === 'function' ? {} : onMessage.permissions
161
97
 
162
- return await runFunction(
163
- services,
164
- channelHandler,
165
- routeMeta,
98
+ return await runPikkuFunc(pikkuFuncName, {
99
+ singletonServices: services,
100
+ getAllServices: () => ({
101
+ ...services,
102
+ channel: channelHandler.getChannel(),
103
+ }),
104
+ data,
166
105
  session,
167
- onMessage,
168
- data
169
- )
106
+ permissions,
107
+ })
170
108
  }
171
109
 
172
110
  const onMessage = async (rawData): Promise<unknown> => {
@@ -215,9 +153,9 @@ export const processMessageHandlers = (
215
153
 
216
154
  if (!processed) {
217
155
  logger.error(
218
- `No handler found for message in channel ${channelConfig.name} for ${rawData}`
156
+ `No handler found for message in channel ${channelConfig.name} for ${JSON.stringify(rawData)}`
219
157
  )
220
- logger.error(`Channel ${channelConfig}`)
158
+ logger.error(`Channel ${JSON.stringify(channelConfig)}`)
221
159
  }
222
160
 
223
161
  return result
@@ -1,14 +1,20 @@
1
1
  import { NotFoundError } from '../errors/errors.js'
2
+ import { addFunction } from '../function/function-runner.js'
2
3
  import { pikkuState } from '../pikku-state.js'
3
4
  import { coerceTopLevelDataFromSchema, validateSchema } from '../schema.js'
4
5
  import { UserSessionService } from '../services/user-session-service.js'
5
6
  import {
7
+ ChannelMeta,
6
8
  CoreAPIChannel,
7
9
  RunChannelOptions,
8
10
  RunChannelParams,
9
11
  } from './channel.types.js'
10
12
  import { match } from 'path-to-regexp'
11
13
 
14
+ /**
15
+ * Adds a channel and registers all functions referenced in it using the
16
+ * function names already stored in the channel metadata
17
+ */
12
18
  export const addChannel = <
13
19
  In,
14
20
  Channel extends string,
@@ -16,21 +22,68 @@ export const addChannel = <
16
22
  ChannelFunctionSessionless,
17
23
  APIPermission,
18
24
  >(
19
- channel: CoreAPIChannel<
20
- In,
21
- Channel,
22
- ChannelFunction,
23
- ChannelFunctionSessionless,
24
- APIPermission
25
- >
25
+ channel: CoreAPIChannel<In, Channel, ChannelFunction, APIPermission>
26
26
  ) => {
27
- pikkuState('channel', 'channels').push(channel as any)
27
+ // Get the channel metadata
28
+ const channelsMeta = pikkuState('channel', 'meta')
29
+ const channelMeta = channelsMeta[channel.name]
30
+ if (!channelMeta) {
31
+ throw new Error(`Channel metadata not found for channel: ${channel.name}`)
32
+ }
33
+
34
+ pikkuState('channel', 'channels').set(channel.name, channel as any)
35
+
36
+ // Register onConnect function if provided
37
+ if (channel.onConnect && channelMeta.connectPikkuFuncName) {
38
+ addFunction(channelMeta.connectPikkuFuncName, channel.onConnect as any)
39
+ }
40
+
41
+ // Register onDisconnect function if provided
42
+ if (channel.onDisconnect && channelMeta.disconnectPikkuFuncName) {
43
+ addFunction(
44
+ channelMeta.disconnectPikkuFuncName,
45
+ channel.onDisconnect as any
46
+ )
47
+ }
48
+
49
+ // Register onMessage function if provided
50
+ if (channel.onMessage && channelMeta.message?.pikkuFuncName) {
51
+ const messageFunc =
52
+ typeof channel.onMessage === 'function'
53
+ ? channel.onMessage
54
+ : channel.onMessage.func
55
+ addFunction(channelMeta.message.pikkuFuncName, messageFunc as any)
56
+ }
57
+
58
+ // Register functions in onMessageRoute
59
+ if (channel.onMessageRoute && channelMeta.messageRoutes) {
60
+ // Iterate through each channel in onMessageRoute
61
+ Object.entries(channel.onMessageRoute).forEach(([channelKey, routes]) => {
62
+ const channelRoutes = channelMeta.messageRoutes[channelKey]
63
+ if (!channelRoutes) return
64
+
65
+ // Iterate through each route in the channel
66
+ Object.entries(routes).forEach(([routeKey, handler]) => {
67
+ const routeMeta = channelRoutes[routeKey]
68
+ if (!routeMeta) return
69
+
70
+ // Extract the function from the handler
71
+ const routeFunc = typeof handler === 'function' ? handler : handler.func
72
+
73
+ // Register the function using the pikku name from metadata
74
+ addFunction(routeMeta.pikkuFuncName, routeFunc as any)
75
+ })
76
+ })
77
+ }
78
+
79
+ // Store the channel configuration
80
+ pikkuState('channel', 'channels').set(channel.name, channel as any)
28
81
  }
29
82
 
30
- export const getMatchingChannelConfig = (request: string) => {
83
+ const getMatchingChannelConfig = (request: string) => {
31
84
  const channels = pikkuState('channel', 'channels')
32
85
  const channelsMeta = pikkuState('channel', 'meta')
33
- for (const channelConfig of channels) {
86
+ for (const channelConfig of channels.values()) {
34
87
  const cleanedRoute = channelConfig.route.replace(/^\/\//, '/')
35
88
  const cleanedRequest = request.replace(/^\/\//, '/')
36
89
  const matchFunc = match(cleanedRoute, {
@@ -38,18 +91,19 @@ export const getMatchingChannelConfig = (request: string) => {
38
91
  })
39
92
  const matchedPath = matchFunc(cleanedRequest)
40
93
  if (matchedPath) {
41
- const schemaName = channelsMeta.find(
42
- (channelMeta) => channelMeta.route === channelConfig.route
43
- )?.input
94
+ const channelMeta = channelsMeta[channelConfig.name]
95
+ if (!channelMeta) {
96
+ throw new Error(`Channel ${channelConfig.name} not found in metadata`)
97
+ }
44
98
  return {
45
99
  matchedPath,
46
100
  params: matchedPath.params,
47
101
  channelConfig,
48
- schemaName,
102
+ schemaName: channelMeta.input,
103
+ meta: channelMeta,
49
104
  }
50
105
  }
51
106
  }
52
-
53
107
  return null
54
108
  }
55
109
 
@@ -64,6 +118,7 @@ export const openChannel = async ({
64
118
  } & RunChannelOptions): Promise<{
65
119
  openingData: unknown
66
120
  channelConfig: CoreAPIChannel<unknown, any>
121
+ meta: ChannelMeta
67
122
  }> => {
68
123
  const matchingChannel = getMatchingChannelConfig(route)
69
124
  if (!matchingChannel) {
@@ -71,7 +126,7 @@ export const openChannel = async ({
71
126
  throw new NotFoundError(`Channel not found: ${route}`)
72
127
  }
73
128
 
74
- const { params, channelConfig, schemaName } = matchingChannel
129
+ const { params, channelConfig, schemaName, meta } = matchingChannel
75
130
 
76
131
  const requiresSession = channelConfig.auth !== false
77
132
  request?.setParams(params)
@@ -94,5 +149,5 @@ export const openChannel = async ({
94
149
  )
95
150
  }
96
151
 
97
- return { openingData, channelConfig }
152
+ return { openingData, channelConfig, meta }
98
153
  }
@@ -3,15 +3,18 @@ import {
3
3
  HTTPFunctionMetaInputTypes,
4
4
  PikkuHTTPRequest,
5
5
  PikkuHTTPResponse,
6
- } from '../http/http-routes.types.js'
6
+ } from '../http/http.types.js'
7
7
  import {
8
8
  APIDocs,
9
- CoreServices,
10
9
  CoreSingletonServices,
11
10
  CreateSessionServices,
12
11
  PikkuMiddleware,
13
12
  } from '../types/core.types.js'
14
- import { CoreAPIFunction, CoreAPIPermission } from '../types/functions.types.js'
13
+ import {
14
+ CoreAPIFunction,
15
+ CoreAPIFunctionSessionless,
16
+ CoreAPIPermission,
17
+ } from '../function/functions.types.js'
15
18
 
16
19
  export type RunChannelOptions = Partial<{
17
20
  skipUserSession: boolean
@@ -30,10 +33,10 @@ export type RunChannelParams<ChannelData> = {
30
33
  }
31
34
 
32
35
  export interface ChannelMessageMeta {
36
+ pikkuFuncName: string
33
37
  inputs: string[] | null
34
38
  outputs: string[] | null
35
39
  docs?: APIDocs
36
- type: null | string
37
40
  }
38
41
 
39
42
  export interface ChannelMeta {
@@ -44,88 +47,49 @@ export interface ChannelMeta {
44
47
  input: string | null
45
48
  inputTypes?: HTTPFunctionMetaInputTypes
46
49
  connect: boolean
50
+ connectPikkuFuncName: string | null
47
51
  disconnect: boolean
52
+ disconnectPikkuFuncName: string | null
48
53
  message: ChannelMessageMeta | null
49
54
  messageRoutes: Record<string, Record<string, ChannelMessageMeta>>
50
55
  docs?: APIDocs
51
56
  tags?: string[]
52
57
  }
53
58
 
54
- export type ChannelsMeta = ChannelMeta[]
55
-
56
- export type CoreChannelConnection<
57
- ChannelData,
58
- Out = unknown,
59
- Services extends CoreServices = CoreServices,
60
- > = (
61
- services: Services,
62
- channel: PikkuChannel<ChannelData, Out>
63
- ) => Promise<void>
64
-
65
- export type CoreChannelDisconnection<
66
- ChannelData,
67
- Services extends CoreServices = CoreServices,
68
- > = (
69
- services: Services,
70
- channel: PikkuChannel<ChannelData, never>
71
- ) => Promise<void>
72
-
73
- /**
74
- * Represents a core channel function that performs an operation using core services and a user session.
75
- *
76
- * @template In - The input type.
77
- * @template Services - The services type, defaults to `CoreServices`.
78
- * @template Session - The session type, defaults to `CoreUserSession`.
79
- */
80
- export type CoreChannelMessage<
81
- In,
82
- Out,
83
- ChannelData,
84
- Services extends CoreServices = CoreServices,
85
- > = (
86
- services: Services,
87
- channel: PikkuChannel<ChannelData, Out>,
88
- data: In
89
- ) => Promise<void | Out>
90
-
91
- export type CoreAPIChannelMessage<
92
- ChannelFunctionMessage = CoreChannelMessage<unknown, unknown, unknown>,
93
- > = {
94
- func: ChannelFunctionMessage
95
- route: string
96
- }
59
+ export type ChannelsMeta = Record<string, ChannelMeta>
97
60
 
98
61
  export type CoreAPIChannel<
99
62
  ChannelData,
100
63
  Channel extends string,
101
- ChannelFunctionConnection = CoreChannelConnection<ChannelData>,
102
- ChannelFunctionDisconnection = CoreChannelDisconnection<ChannelData>,
103
- ChannelFunctionDefaultMessage =
104
- | CoreChannelMessage<unknown, unknown, unknown>
105
- | CoreAPIFunction<unknown, unknown>,
106
- ChannelFunctionMessageRoute =
107
- | CoreChannelMessage<unknown, unknown, unknown>
108
- | CoreAPIFunction<unknown, unknown>,
64
+ ChannelConnect =
65
+ | CoreAPIFunction<void, unknown, ChannelData>
66
+ | CoreAPIFunctionSessionless<void, unknown, ChannelData>,
67
+ ChannelDisconnect =
68
+ | CoreAPIFunction<void, void, ChannelData>
69
+ | CoreAPIFunctionSessionless<void, void, ChannelData>,
70
+ ChannelFunctionMessage =
71
+ | CoreAPIFunction<unknown, unknown, ChannelData>
72
+ | CoreAPIFunctionSessionless<unknown, unknown, ChannelData>,
109
73
  APIPermission = CoreAPIPermission<ChannelData>,
110
74
  > = {
111
75
  name: string
112
76
  route: Channel
113
- onConnect?: ChannelFunctionConnection
114
- onDisconnect?: ChannelFunctionDisconnection
77
+ onConnect?: ChannelConnect
78
+ onDisconnect?: ChannelDisconnect
115
79
  onMessage?:
116
80
  | {
117
- func: ChannelFunctionDefaultMessage
81
+ func: ChannelFunctionMessage
118
82
  permissions?: Record<string, APIPermission[] | APIPermission>
119
83
  auth?: boolean
120
84
  }
121
- | ChannelFunctionDefaultMessage
85
+ | ChannelFunctionMessage
122
86
  onMessageRoute?: Record<
123
87
  string,
124
88
  Record<
125
89
  string,
126
- | ChannelFunctionMessageRoute
90
+ | ChannelFunctionMessage
127
91
  | {
128
- func: ChannelFunctionMessageRoute
92
+ func: ChannelFunctionMessage
129
93
  permissions?: Record<string, APIPermission[] | APIPermission>
130
94
  auth?: boolean
131
95
  }
@@ -143,8 +107,6 @@ export type CoreAPIChannel<
143
107
  tags?: string[]
144
108
  }
145
109
 
146
- export type CoreAPIChannels = CoreAPIChannel<any, string>[]
147
-
148
110
  export interface PikkuChannel<OpeningData, Out> {
149
111
  // The channel identifier
150
112
  channelId: string
@@ -1,14 +1,14 @@
1
1
  import { test, beforeEach, afterEach } from 'node:test'
2
2
  import * as assert from 'node:assert/strict'
3
3
  import { runLocalChannel } from './local-channel-runner.js'
4
- import { resetPikkuState } from '../../pikku-state.js'
4
+ import { pikkuState, resetPikkuState } from '../../pikku-state.js'
5
5
  import { addChannel } from '../channel-runner.js'
6
6
  import {
7
7
  HTTPMethod,
8
8
  PikkuHTTPRequest,
9
9
  PikkuHTTPResponse,
10
10
  PikkuQuery,
11
- } from '../../http/http-routes.types.js'
11
+ } from '../../http/http.types.js'
12
12
  import { SerializeOptions } from 'cookie'
13
13
 
14
14
  /**
@@ -126,22 +126,21 @@ test('runChannel should return undefined and 404 if no matching channel is found
126
126
 
127
127
  test('runChannel should return a channel handler if channel matches and no auth required', async () => {
128
128
  resetPikkuState()
129
+
130
+ pikkuState('channel', 'meta', {
131
+ test: {
132
+ name: 'test',
133
+ route: '/test-channel',
134
+ },
135
+ } as any)
129
136
  addChannel({
130
137
  name: 'test',
131
138
  route: '/test-channel',
132
139
  auth: false,
133
140
  })
134
141
 
135
- // Provide a fake channelPermissionService if needed
136
- const singletonServicesWithPerm = {
137
- ...mockSingletonServices,
138
- channelPermissionService: {
139
- verifyChannelAccess: async () => {},
140
- },
141
- }
142
-
143
142
  const result = await runLocalChannel({
144
- singletonServices: singletonServicesWithPerm,
143
+ singletonServices: mockSingletonServices,
145
144
  channelId: 'test-channel-id',
146
145
  request: new PikkuMockRequest('/test-channel', 'get'),
147
146
  response: new PikkuMockResponse(),
@@ -1,5 +1,5 @@
1
1
  import { openChannel } from '../channel-runner.js'
2
- import { createHTTPInteraction } from '../../http/http-route-runner.js'
2
+ import { createHTTPInteraction } from '../../http/http-runner.js'
3
3
  import { closeSessionServices } from '../../utils.js'
4
4
  import { processMessageHandlers } from '../channel-handler.js'
5
5
  import {
@@ -12,7 +12,8 @@ import { SessionServices } from '../../types/core.types.js'
12
12
  import { handleError } from '../../handle-error.js'
13
13
  import { runMiddleware } from '../../middleware-runner.js'
14
14
  import { PikkuUserSessionService } from '../../services/user-session-service.js'
15
- import { PikkuHTTP } from '../../http/http-routes.types.js'
15
+ import { PikkuHTTP } from '../../http/http.types.js'
16
+ import { runPikkuFuncDirectly } from '../../function/function-runner.js'
16
17
 
17
18
  export const runLocalChannel = async ({
18
19
  singletonServices,
@@ -42,7 +43,7 @@ export const runLocalChannel = async ({
42
43
 
43
44
  const main = async () => {
44
45
  try {
45
- const { openingData, channelConfig } = await openChannel({
46
+ const { openingData, channelConfig, meta } = await openChannel({
46
47
  channelId,
47
48
  createSessionServices,
48
49
  respondWith404,
@@ -77,11 +78,23 @@ export const runLocalChannel = async ({
77
78
  }
78
79
 
79
80
  channelHandler.registerOnOpen(() => {
80
- channelConfig.onConnect?.(allServices, channel)
81
+ if (channelConfig.onConnect && meta.connectPikkuFuncName) {
82
+ runPikkuFuncDirectly(
83
+ meta.connectPikkuFuncName,
84
+ { ...allServices, channel },
85
+ openingData
86
+ )
87
+ }
81
88
  })
82
89
 
83
90
  channelHandler.registerOnClose(async () => {
84
- channelConfig.onDisconnect?.(allServices, channel)
91
+ if (channelConfig.onDisconnect && meta.disconnectPikkuFuncName) {
92
+ runPikkuFuncDirectly(
93
+ meta.disconnectPikkuFuncName,
94
+ { ...allServices, channel },
95
+ openingData
96
+ )
97
+ }
85
98
  if (sessionServices) {
86
99
  await closeSessionServices(singletonServices.logger, sessionServices)
87
100
  }
@@ -91,7 +104,7 @@ export const runLocalChannel = async ({
91
104
  processMessageHandlers(
92
105
  allServices,
93
106
  session,
94
- channelConfig,
107
+ channelConfig as any,
95
108
  channelHandler
96
109
  )
97
110
  )
@@ -122,5 +135,5 @@ export const runLocalChannel = async ({
122
135
  main
123
136
  )
124
137
 
125
- return channelHandler!
138
+ return channelHandler
126
139
  }
@@ -7,14 +7,14 @@ import { Logger } from '../services/index.js'
7
7
  */
8
8
  export const logChannels = (logger: Logger) => {
9
9
  const channels = pikkuState('channel', 'channels')
10
- if (channels.length === 0) {
10
+ if (channels.size === 0) {
11
11
  logger.info('No channels added')
12
12
  return
13
13
  }
14
14
 
15
15
  let scheduledChannels = 'Channels:'
16
- for (const { name, route } of channels) {
17
- scheduledChannels += `\n\t- ${name} at ${route}`
18
- }
16
+ channels.forEach((channel) => {
17
+ scheduledChannels += `\n\t- ${channel.name} at ${channel.route}`
18
+ })
19
19
  logger.info(scheduledChannels)
20
20
  }
@@ -8,14 +8,15 @@ import type {
8
8
  RunChannelParams,
9
9
  PikkuChannelHandlerFactory,
10
10
  } from '../channel.types.js'
11
- import { createHTTPInteraction } from '../../http/http-route-runner.js'
11
+ import { createHTTPInteraction } from '../../http/http-runner.js'
12
12
  import { ChannelStore } from '../channel-store.js'
13
13
  import { handleError } from '../../handle-error.js'
14
14
  import { PikkuUserSessionService } from '../../services/user-session-service.js'
15
15
  import { runMiddleware } from '../../middleware-runner.js'
16
16
  import { pikkuState } from '../../pikku-state.js'
17
17
  import { PikkuFetchHTTPRequest } from '../../http/pikku-fetch-http-request.js'
18
- import { PikkuHTTP } from '../../http/http-routes.types.js'
18
+ import { PikkuHTTP } from '../../http/http.types.js'
19
+ import { runPikkuFuncDirectly } from '../../function/function-runner.js'
19
20
 
20
21
  export interface RunServerlessChannelParams<ChannelData>
21
22
  extends RunChannelParams<ChannelData> {
@@ -36,12 +37,15 @@ const getVariablesForChannel = ({
36
37
  openingData?: unknown
37
38
  }) => {
38
39
  const channels = pikkuState('channel', 'channels')
39
- const channelConfig = channels.find(
40
- (channelConfig) => channelConfig.name === channelName
41
- )
40
+ const channelConfig = channels[channelName]
41
+ const channelsMeta = pikkuState('channel', 'meta')
42
+ const meta = channelsMeta[channelName]
42
43
  if (!channelConfig) {
43
44
  throw new Error(`Channel not found: ${channelName}`)
44
45
  }
46
+ if (!meta) {
47
+ throw new Error(`Channel meta not found: ${channelName}`)
48
+ }
45
49
  const channelHandler = channelHandlerFactory(
46
50
  channelId,
47
51
  channelConfig.name,
@@ -51,6 +55,7 @@ const getVariablesForChannel = ({
51
55
  channelConfig,
52
56
  channelHandler,
53
57
  channel: channelHandler.getChannel(),
58
+ meta,
54
59
  }
55
60
  }
56
61
 
@@ -80,7 +85,7 @@ export const runChannelConnect = async ({
80
85
 
81
86
  const userSession = new PikkuUserSessionService(channelStore, channelId)
82
87
 
83
- const { channelConfig, openingData } = await openChannel({
88
+ const { channelConfig, openingData, meta } = await openChannel({
84
89
  channelId,
85
90
  createSessionServices,
86
91
  request,
@@ -110,10 +115,13 @@ export const runChannelConnect = async ({
110
115
  await userSession.get()
111
116
  )
112
117
  }
113
- await channelConfig.onConnect?.(
114
- { ...singletonServices, ...sessionServices },
115
- channel
116
- )
118
+ if (channelConfig.onConnect && meta.connectPikkuFuncName) {
119
+ await runPikkuFuncDirectly(
120
+ meta.connectPikkuFuncName,
121
+ { ...singletonServices, ...sessionServices, channel },
122
+ openingData
123
+ )
124
+ }
117
125
  http?.response?.status(101)
118
126
  } catch (e: any) {
119
127
  handleError(
@@ -150,7 +158,7 @@ export const runChannelDisconnect = async ({
150
158
  let sessionServices: SessionServices | undefined
151
159
  const { openingData, channelName, session } =
152
160
  await params.channelStore.getChannelAndSession(params.channelId)
153
- const { channel, channelConfig } = getVariablesForChannel({
161
+ const { channel, channelConfig, meta } = getVariablesForChannel({
154
162
  ...params,
155
163
  openingData,
156
164
  channelName,
@@ -162,10 +170,13 @@ export const runChannelDisconnect = async ({
162
170
  session
163
171
  )
164
172
  }
165
- await channelConfig.onDisconnect?.(
166
- { ...singletonServices, ...sessionServices },
167
- channel
168
- )
173
+ if (channelConfig.onDisconnect && meta.disconnectPikkuFuncName) {
174
+ await runPikkuFuncDirectly(
175
+ meta.disconnectPikkuFuncName,
176
+ { ...singletonServices, ...sessionServices, channel },
177
+ undefined
178
+ )
179
+ }
169
180
  await params.channelStore.removeChannels([channel.channelId])
170
181
  if (sessionServices) {
171
182
  await closeSessionServices(singletonServices.logger, sessionServices)