@pikku/core 0.9.11 → 0.10.0
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 +14 -0
- package/dist/errors/errors.d.ts +2 -0
- package/dist/errors/errors.js +6 -0
- package/dist/function/function-runner.d.ts +15 -9
- package/dist/function/function-runner.js +55 -37
- package/dist/function/functions.types.d.ts +67 -1
- package/dist/function/functions.types.js +43 -1
- package/dist/index.d.ts +2 -6
- package/dist/index.js +2 -6
- package/dist/middleware/auth-apikey.d.ts +19 -11
- package/dist/middleware/auth-apikey.js +33 -33
- package/dist/middleware/auth-bearer.d.ts +34 -7
- package/dist/middleware/auth-bearer.js +53 -36
- package/dist/middleware/auth-cookie.d.ts +30 -12
- package/dist/middleware/auth-cookie.js +51 -43
- package/dist/middleware/timeout.d.ts +6 -2
- package/dist/middleware/timeout.js +7 -9
- package/dist/middleware-runner.d.ts +46 -43
- package/dist/middleware-runner.js +100 -69
- package/dist/permissions.d.ts +82 -20
- package/dist/permissions.js +176 -62
- package/dist/pikku-state.d.ts +46 -1
- package/dist/pikku-state.js +16 -1
- package/dist/services/content-service.d.ts +2 -3
- package/dist/services/index.d.ts +0 -1
- package/dist/services/index.js +0 -1
- package/dist/services/local-content.d.ts +2 -4
- package/dist/types/core.types.d.ts +110 -4
- package/dist/types/core.types.js +44 -1
- package/dist/utils.d.ts +1 -1
- package/dist/wirings/channel/channel-handler.d.ts +2 -2
- package/dist/wirings/channel/channel-handler.js +16 -12
- package/dist/wirings/channel/channel-runner.d.ts +2 -2
- package/dist/wirings/channel/channel-runner.js +6 -24
- package/dist/wirings/channel/channel.types.d.ts +15 -14
- package/dist/wirings/channel/local/local-channel-runner.js +12 -12
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +7 -8
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +12 -0
- package/dist/wirings/cli/channel/cli-channel-runner.js +83 -0
- package/dist/wirings/cli/channel/index.d.ts +1 -0
- package/dist/wirings/cli/channel/index.js +1 -0
- package/dist/wirings/cli/cli-runner.d.ts +42 -0
- package/dist/wirings/cli/cli-runner.js +352 -0
- package/dist/wirings/cli/cli.types.d.ts +204 -0
- package/dist/wirings/cli/cli.types.js +1 -0
- package/dist/wirings/cli/command-parser.d.ts +19 -0
- package/dist/wirings/cli/command-parser.js +403 -0
- package/dist/wirings/cli/index.d.ts +5 -0
- package/dist/wirings/cli/index.js +5 -0
- package/dist/wirings/http/http-runner.d.ts +59 -10
- package/dist/wirings/http/http-runner.js +138 -131
- package/dist/wirings/http/http.types.d.ts +11 -10
- package/dist/wirings/http/index.d.ts +1 -1
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/http/pikku-fetch-http-response.js +3 -1
- package/dist/wirings/http/routers/http-router.d.ts +0 -2
- package/dist/wirings/http/routers/path-to-regex.d.ts +1 -1
- package/dist/wirings/http/routers/path-to-regex.js +5 -34
- package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.d.ts +4 -5
- package/dist/wirings/mcp/mcp-runner.js +32 -34
- package/dist/wirings/mcp/mcp.types.d.ts +38 -14
- package/dist/wirings/queue/queue-runner.d.ts +2 -2
- package/dist/wirings/queue/queue-runner.js +25 -27
- package/dist/wirings/queue/queue.types.d.ts +6 -5
- package/dist/wirings/rpc/index.d.ts +1 -1
- package/dist/wirings/rpc/index.js +1 -1
- package/dist/wirings/rpc/rpc-runner.d.ts +6 -18
- package/dist/wirings/rpc/rpc-runner.js +13 -8
- package/dist/wirings/scheduler/scheduler-runner.d.ts +2 -2
- package/dist/wirings/scheduler/scheduler-runner.js +38 -35
- package/dist/wirings/scheduler/scheduler.types.d.ts +5 -4
- package/package.json +9 -7
- package/src/errors/errors.ts +6 -0
- package/src/factory-functions.test.ts +60 -1
- package/src/function/function-runner.test.ts +81 -26
- package/src/function/function-runner.ts +89 -57
- package/src/function/functions.types.ts +85 -2
- package/src/index.ts +6 -19
- package/src/middleware/auth-apikey.ts +42 -57
- package/src/middleware/auth-bearer.ts +66 -49
- package/src/middleware/auth-cookie.ts +63 -82
- package/src/middleware/timeout.ts +10 -14
- package/src/middleware-runner.test.ts +24 -16
- package/src/middleware-runner.ts +115 -87
- package/src/permissions.test.ts +26 -27
- package/src/permissions.ts +216 -104
- package/src/pikku-state.ts +79 -2
- package/src/services/content-service.ts +5 -4
- package/src/services/index.ts +0 -1
- package/src/services/local-content.ts +9 -4
- package/src/types/core.types.ts +143 -5
- package/src/utils.ts +1 -1
- package/src/wirings/channel/channel-handler.ts +18 -21
- package/src/wirings/channel/channel-runner.ts +19 -32
- package/src/wirings/channel/channel.types.ts +29 -16
- package/src/wirings/channel/local/local-channel-runner.ts +25 -15
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +15 -17
- package/src/wirings/cli/channel/cli-channel-runner.ts +123 -0
- package/src/wirings/cli/channel/index.ts +1 -0
- package/src/wirings/cli/cli-runner.test.ts +403 -0
- package/src/wirings/cli/cli-runner.ts +539 -0
- package/src/wirings/cli/cli.types.ts +350 -0
- package/src/wirings/cli/command-parser.test.ts +445 -0
- package/src/wirings/cli/command-parser.ts +504 -0
- package/src/wirings/cli/index.ts +13 -0
- package/src/wirings/http/http-runner.test.ts +8 -7
- package/src/wirings/http/http-runner.ts +165 -158
- package/src/wirings/http/http.types.ts +58 -11
- package/src/wirings/http/index.ts +7 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +3 -1
- package/src/wirings/http/routers/http-router.ts +0 -2
- package/src/wirings/http/routers/path-to-regex.test.ts +4 -5
- package/src/wirings/http/routers/path-to-regex.ts +6 -43
- package/src/wirings/mcp/mcp-endpoint-registry.ts +1 -1
- package/src/wirings/mcp/mcp-runner.ts +58 -55
- package/src/wirings/mcp/mcp.types.ts +65 -14
- package/src/wirings/queue/queue-runner.ts +44 -47
- package/src/wirings/queue/queue.types.ts +10 -6
- package/src/wirings/rpc/index.ts +1 -1
- package/src/wirings/rpc/rpc-runner.ts +27 -9
- package/src/wirings/scheduler/scheduler-runner.ts +58 -56
- package/src/wirings/scheduler/scheduler.types.ts +10 -3
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Logger, LogLevel } from '../services/logger.js';
|
|
2
2
|
import { VariablesService } from '../services/variables-service.js';
|
|
3
3
|
import { SchemaService } from '../services/schema-service.js';
|
|
4
|
+
import { JWTService } from '../services/jwt-service.js';
|
|
4
5
|
import { PikkuHTTP } from '../wirings/http/http.types.js';
|
|
5
6
|
import { UserSessionService } from '../services/user-session-service.js';
|
|
6
7
|
import { PikkuChannel } from '../wirings/channel/channel.types.js';
|
|
@@ -8,18 +9,54 @@ import { PikkuRPC } from '../wirings/rpc/rpc-types.js';
|
|
|
8
9
|
import { PikkuMCP } from '../wirings/mcp/mcp.types.js';
|
|
9
10
|
import { PikkuScheduledTask } from '../wirings/scheduler/scheduler.types.js';
|
|
10
11
|
import { PikkuQueue } from '../wirings/queue/queue.types.js';
|
|
12
|
+
import { PikkuCLI } from '../wirings/cli/cli.types.js';
|
|
11
13
|
export declare enum PikkuWiringTypes {
|
|
12
14
|
http = "http",
|
|
13
15
|
scheduler = "scheduler",
|
|
14
16
|
channel = "channel",
|
|
15
17
|
rpc = "rpc",
|
|
16
18
|
queue = "queue",
|
|
17
|
-
mcp = "mcp"
|
|
19
|
+
mcp = "mcp",
|
|
20
|
+
cli = "cli"
|
|
18
21
|
}
|
|
19
22
|
export interface FunctionServicesMeta {
|
|
20
23
|
optimized: boolean;
|
|
21
24
|
services: string[];
|
|
22
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Metadata for middleware at any level
|
|
28
|
+
* - type: 'http' = HTTP route middleware group (references httpGroup in pikkuState)
|
|
29
|
+
* - type: 'tag' = Tag-based middleware group (references tagGroup in pikkuState)
|
|
30
|
+
* - type: 'wire' = Wire-level individual middleware
|
|
31
|
+
*/
|
|
32
|
+
export type MiddlewareMetadata = {
|
|
33
|
+
type: 'http';
|
|
34
|
+
route: string;
|
|
35
|
+
} | {
|
|
36
|
+
type: 'tag';
|
|
37
|
+
tag: string;
|
|
38
|
+
} | {
|
|
39
|
+
type: 'wire';
|
|
40
|
+
name: string;
|
|
41
|
+
inline?: boolean;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Metadata for permissions at any level
|
|
45
|
+
* - type: 'http' = HTTP route permission group (references httpGroup in pikkuState)
|
|
46
|
+
* - type: 'tag' = Tag-based permission group (references tagGroup in pikkuState)
|
|
47
|
+
* - type: 'wire' = Wire-level individual permission
|
|
48
|
+
*/
|
|
49
|
+
export type PermissionMetadata = {
|
|
50
|
+
type: 'http';
|
|
51
|
+
route: string;
|
|
52
|
+
} | {
|
|
53
|
+
type: 'tag';
|
|
54
|
+
tag: string;
|
|
55
|
+
} | {
|
|
56
|
+
type: 'wire';
|
|
57
|
+
name: string;
|
|
58
|
+
inline?: boolean;
|
|
59
|
+
};
|
|
23
60
|
export type FunctionRuntimeMeta = {
|
|
24
61
|
pikkuFuncName: string;
|
|
25
62
|
inputSchemaName: string | null;
|
|
@@ -34,6 +71,8 @@ export type FunctionMeta = FunctionRuntimeMeta & Partial<{
|
|
|
34
71
|
tags: string[];
|
|
35
72
|
docs: PikkuDocs;
|
|
36
73
|
isDirectFunction: boolean;
|
|
74
|
+
middleware: MiddlewareMetadata[];
|
|
75
|
+
permissions: PermissionMetadata[];
|
|
37
76
|
}>;
|
|
38
77
|
export type FunctionsRuntimeMeta = Record<string, FunctionRuntimeMeta>;
|
|
39
78
|
export type FunctionsMeta = Record<string, FunctionMeta>;
|
|
@@ -82,6 +121,8 @@ export interface CoreUserSession {
|
|
|
82
121
|
export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
|
|
83
122
|
/** The schema library used to validate data */
|
|
84
123
|
schema?: SchemaService;
|
|
124
|
+
/** The JWT service used to encode and decode tokens */
|
|
125
|
+
jwt?: JWTService;
|
|
85
126
|
/** The core configuration for the application. */
|
|
86
127
|
config: Config;
|
|
87
128
|
/** The logger used by the application. */
|
|
@@ -99,6 +140,7 @@ export type PikkuInteraction<In = unknown, Out = unknown> = Partial<{
|
|
|
99
140
|
channel: PikkuChannel<unknown, Out>;
|
|
100
141
|
scheduledTask: PikkuScheduledTask;
|
|
101
142
|
queue: PikkuQueue;
|
|
143
|
+
cli: PikkuCLI;
|
|
102
144
|
}>;
|
|
103
145
|
/**
|
|
104
146
|
* A function that can wrap an interaction and be called before or after
|
|
@@ -107,9 +149,73 @@ export type CorePikkuMiddleware<SingletonServices extends CoreSingletonServices
|
|
|
107
149
|
userSession: UserSessionService<UserSession>;
|
|
108
150
|
}, interactions: PikkuInteraction, next: () => Promise<void>) => Promise<void>;
|
|
109
151
|
/**
|
|
110
|
-
*
|
|
152
|
+
* Configuration object for creating middleware with metadata
|
|
153
|
+
*
|
|
154
|
+
* @template SingletonServices - The singleton services type
|
|
155
|
+
* @template UserSession - The user session type
|
|
156
|
+
*/
|
|
157
|
+
export type CorePikkuMiddlewareConfig<SingletonServices extends CoreSingletonServices = CoreSingletonServices, UserSession extends CoreUserSession = CoreUserSession> = {
|
|
158
|
+
/** The middleware function */
|
|
159
|
+
func: CorePikkuMiddleware<SingletonServices, UserSession>;
|
|
160
|
+
/** Optional human-readable name for the middleware */
|
|
161
|
+
name?: string;
|
|
162
|
+
/** Optional description of what the middleware does */
|
|
163
|
+
description?: string;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* A factory function that takes input and returns middleware
|
|
167
|
+
* Used when middleware needs configuration/input parameters
|
|
111
168
|
*/
|
|
112
|
-
export
|
|
169
|
+
export type CorePikkuMiddlewareFactory<In = any, SingletonServices extends CoreSingletonServices = CoreSingletonServices, UserSession extends CoreUserSession = CoreUserSession> = (input: In) => CorePikkuMiddleware<SingletonServices, UserSession>;
|
|
170
|
+
/**
|
|
171
|
+
* A group of middleware (combination of regular middleware and factories)
|
|
172
|
+
* Used with addMiddleware() and addHTTPMiddleware() to group related middleware together
|
|
173
|
+
*/
|
|
174
|
+
export type CorePikkuMiddlewareGroup<SingletonServices extends CoreSingletonServices = CoreSingletonServices, UserSession extends CoreUserSession = CoreUserSession> = Array<CorePikkuMiddleware<SingletonServices, UserSession> | CorePikkuMiddlewareFactory<any, SingletonServices, UserSession>>;
|
|
175
|
+
/**
|
|
176
|
+
* Factory function for creating middleware with tree-shaking support
|
|
177
|
+
* Supports both direct function and configuration object syntax
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```typescript
|
|
181
|
+
* // Direct function syntax
|
|
182
|
+
* export const logMiddleware = pikkuMiddleware(
|
|
183
|
+
* async ({ logger }, _interaction, next) => {
|
|
184
|
+
* logger.info('Request started')
|
|
185
|
+
* await next()
|
|
186
|
+
* }
|
|
187
|
+
* )
|
|
188
|
+
*
|
|
189
|
+
* // Configuration object syntax with metadata
|
|
190
|
+
* export const logMiddleware = pikkuMiddleware({
|
|
191
|
+
* name: 'Request Logger',
|
|
192
|
+
* description: 'Logs request information',
|
|
193
|
+
* func: async ({ logger }, _interaction, next) => {
|
|
194
|
+
* logger.info('Request started')
|
|
195
|
+
* await next()
|
|
196
|
+
* }
|
|
197
|
+
* })
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
export declare const pikkuMiddleware: <SingletonServices extends CoreSingletonServices = CoreSingletonServices, UserSession extends CoreUserSession = CoreUserSession>(middleware: CorePikkuMiddleware<SingletonServices, UserSession> | CorePikkuMiddlewareConfig<SingletonServices, UserSession>) => CorePikkuMiddleware<SingletonServices, UserSession>;
|
|
201
|
+
/**
|
|
202
|
+
* Factory function for creating middleware factories
|
|
203
|
+
* Use this when your middleware needs configuration/input parameters
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```typescript
|
|
207
|
+
* export const logMiddleware = pikkuMiddlewareFactory<LogOptions>(({
|
|
208
|
+
* message,
|
|
209
|
+
* level = 'info'
|
|
210
|
+
* }) => {
|
|
211
|
+
* return pikkuMiddleware(async ({ logger }, _interaction, next) => {
|
|
212
|
+
* logger[level](message)
|
|
213
|
+
* await next()
|
|
214
|
+
* })
|
|
215
|
+
* })
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
export declare const pikkuMiddlewareFactory: <In = any>(factory: CorePikkuMiddlewareFactory<In>) => CorePikkuMiddlewareFactory<In>;
|
|
113
219
|
/**
|
|
114
220
|
* Represents the core services used by Pikku, including singleton services and the request/response interaction.
|
|
115
221
|
*/
|
|
@@ -128,7 +234,7 @@ export type CreateSessionServices<SingletonServices extends CoreSingletonService
|
|
|
128
234
|
/**
|
|
129
235
|
* Defines a function type for creating config.
|
|
130
236
|
*/
|
|
131
|
-
export type CreateConfig<Config extends CoreConfig> = (variables?: VariablesService) => Promise<Config>;
|
|
237
|
+
export type CreateConfig<Config extends CoreConfig, RemainingArgs extends any[] = unknown[]> = (variables?: VariablesService, ...args: RemainingArgs) => Promise<Config>;
|
|
132
238
|
/**
|
|
133
239
|
* Represents the documentation for a route, including summary, description, tags, and errors.
|
|
134
240
|
*/
|
package/dist/types/core.types.js
CHANGED
|
@@ -6,10 +6,53 @@ export var PikkuWiringTypes;
|
|
|
6
6
|
PikkuWiringTypes["rpc"] = "rpc";
|
|
7
7
|
PikkuWiringTypes["queue"] = "queue";
|
|
8
8
|
PikkuWiringTypes["mcp"] = "mcp";
|
|
9
|
+
PikkuWiringTypes["cli"] = "cli";
|
|
9
10
|
})(PikkuWiringTypes || (PikkuWiringTypes = {}));
|
|
10
11
|
/**
|
|
11
12
|
* Factory function for creating middleware with tree-shaking support
|
|
13
|
+
* Supports both direct function and configuration object syntax
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // Direct function syntax
|
|
18
|
+
* export const logMiddleware = pikkuMiddleware(
|
|
19
|
+
* async ({ logger }, _interaction, next) => {
|
|
20
|
+
* logger.info('Request started')
|
|
21
|
+
* await next()
|
|
22
|
+
* }
|
|
23
|
+
* )
|
|
24
|
+
*
|
|
25
|
+
* // Configuration object syntax with metadata
|
|
26
|
+
* export const logMiddleware = pikkuMiddleware({
|
|
27
|
+
* name: 'Request Logger',
|
|
28
|
+
* description: 'Logs request information',
|
|
29
|
+
* func: async ({ logger }, _interaction, next) => {
|
|
30
|
+
* logger.info('Request started')
|
|
31
|
+
* await next()
|
|
32
|
+
* }
|
|
33
|
+
* })
|
|
34
|
+
* ```
|
|
12
35
|
*/
|
|
13
36
|
export const pikkuMiddleware = (middleware) => {
|
|
14
|
-
return middleware;
|
|
37
|
+
return typeof middleware === 'function' ? middleware : middleware.func;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Factory function for creating middleware factories
|
|
41
|
+
* Use this when your middleware needs configuration/input parameters
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* export const logMiddleware = pikkuMiddlewareFactory<LogOptions>(({
|
|
46
|
+
* message,
|
|
47
|
+
* level = 'info'
|
|
48
|
+
* }) => {
|
|
49
|
+
* return pikkuMiddleware(async ({ logger }, _interaction, next) => {
|
|
50
|
+
* logger[level](message)
|
|
51
|
+
* await next()
|
|
52
|
+
* })
|
|
53
|
+
* })
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export const pikkuMiddlewareFactory = (factory) => {
|
|
57
|
+
return factory;
|
|
15
58
|
};
|
package/dist/utils.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ import { Logger } from './services/logger.js';
|
|
|
2
2
|
export declare const closeSessionServices: (logger: Logger, sessionServices: Record<string, any>) => Promise<void>;
|
|
3
3
|
export declare const createWeakUID: () => string;
|
|
4
4
|
export declare const isSerializable: (data: any) => boolean;
|
|
5
|
-
export declare const freezeDedupe: <T
|
|
5
|
+
export declare const freezeDedupe: <T>(arr?: readonly T[] | T[] | undefined) => readonly T[];
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { CoreServices
|
|
1
|
+
import { CoreServices } from '../../types/core.types.js';
|
|
2
2
|
import { CoreChannel, PikkuChannelHandler } from './channel.types.js';
|
|
3
|
-
export declare const processMessageHandlers: (services: CoreServices,
|
|
3
|
+
export declare const processMessageHandlers: (services: CoreServices, channelConfig: CoreChannel<any, any>, channelHandler: PikkuChannelHandler) => (rawData: any) => Promise<unknown>;
|
|
@@ -32,10 +32,10 @@ const validateAuth = (requiresSession, session, onMessage) => {
|
|
|
32
32
|
}
|
|
33
33
|
return true;
|
|
34
34
|
};
|
|
35
|
-
export const processMessageHandlers = (services,
|
|
35
|
+
export const processMessageHandlers = (services, channelConfig, channelHandler) => {
|
|
36
36
|
const logger = services.logger;
|
|
37
37
|
const requiresSession = channelConfig.auth !== false;
|
|
38
|
-
const processMessage = async (data, onMessage,
|
|
38
|
+
const processMessage = async (data, onMessage, routingProperty, routerValue) => {
|
|
39
39
|
if (!validateAuth(requiresSession, channelHandler, onMessage)) {
|
|
40
40
|
const routeMessage = routingProperty
|
|
41
41
|
? `route '${routingProperty}:${routerValue}'`
|
|
@@ -45,19 +45,23 @@ export const processMessageHandlers = (services, session, channelConfig, channel
|
|
|
45
45
|
channelHandler.getChannel().send(`Unauthorized for ${routeMessage}`);
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
|
-
const { pikkuFuncName } = getRouteMeta(channelConfig.name, routingProperty, routerValue);
|
|
49
|
-
const
|
|
50
|
-
const
|
|
48
|
+
const { pikkuFuncName, middleware: inheritedMiddleware, permissions: inheritedPermissions, } = getRouteMeta(channelConfig.name, routingProperty, routerValue);
|
|
49
|
+
const wirePermissions = typeof onMessage === 'function' ? undefined : onMessage.permissions;
|
|
50
|
+
const wireMiddleware = typeof onMessage === 'function' ? [] : onMessage.middleware;
|
|
51
51
|
return await runPikkuFunc(PikkuWiringTypes.channel, channelConfig.name, pikkuFuncName, {
|
|
52
|
+
singletonServices: services,
|
|
52
53
|
getAllServices: () => ({
|
|
53
54
|
...services,
|
|
54
55
|
channel: channelHandler.getChannel(),
|
|
55
56
|
}),
|
|
56
|
-
data,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
data: () => data,
|
|
58
|
+
userSession: services.userSession,
|
|
59
|
+
inheritedMiddleware,
|
|
60
|
+
wireMiddleware,
|
|
61
|
+
inheritedPermissions,
|
|
62
|
+
wirePermissions,
|
|
60
63
|
tags: channelConfig.tags,
|
|
64
|
+
interaction: { channel: channelHandler.getChannel() },
|
|
61
65
|
});
|
|
62
66
|
};
|
|
63
67
|
const onMessage = async (rawData) => {
|
|
@@ -72,14 +76,14 @@ export const processMessageHandlers = (services, session, channelConfig, channel
|
|
|
72
76
|
const routerValue = messageData[routingProperty];
|
|
73
77
|
if (routerValue && routes[routerValue]) {
|
|
74
78
|
processed = true;
|
|
75
|
-
result = await processMessage(messageData, routes[routerValue],
|
|
79
|
+
result = await processMessage(messageData, routes[routerValue], routingProperty, routerValue);
|
|
76
80
|
break;
|
|
77
81
|
}
|
|
78
82
|
}
|
|
79
83
|
// Default handler if no routes matched but json data was parsed
|
|
80
84
|
if (!processed && channelConfig.onMessage) {
|
|
81
85
|
processed = true;
|
|
82
|
-
result = await processMessage(messageData, channelConfig.onMessage
|
|
86
|
+
result = await processMessage(messageData, channelConfig.onMessage);
|
|
83
87
|
}
|
|
84
88
|
}
|
|
85
89
|
catch (error) {
|
|
@@ -89,7 +93,7 @@ export const processMessageHandlers = (services, session, channelConfig, channel
|
|
|
89
93
|
// Default handler if no routes matched and json data wasn't parsed
|
|
90
94
|
if (!processed && channelConfig.onMessage) {
|
|
91
95
|
processed = true;
|
|
92
|
-
result = await processMessage(rawData, channelConfig.onMessage
|
|
96
|
+
result = await processMessage(rawData, channelConfig.onMessage);
|
|
93
97
|
}
|
|
94
98
|
if (!processed) {
|
|
95
99
|
logger.error(`No handler found for message in channel ${channelConfig.name} for ${JSON.stringify(rawData)}`);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CorePikkuPermission } from '../../function/functions.types.js';
|
|
1
2
|
import { UserSessionService } from '../../services/user-session-service.js';
|
|
2
3
|
import { CorePikkuMiddleware } from '../../types/core.types.js';
|
|
3
4
|
import { ChannelMeta, CoreChannel, RunChannelOptions, RunChannelParams } from './channel.types.js';
|
|
@@ -5,12 +6,11 @@ import { ChannelMeta, CoreChannel, RunChannelOptions, RunChannelParams } from '.
|
|
|
5
6
|
* Adds a channel and registers all functions referenced in it using the
|
|
6
7
|
* function names already stored in the channel metadata
|
|
7
8
|
*/
|
|
8
|
-
export declare const wireChannel: <In, Channel extends string,
|
|
9
|
+
export declare const wireChannel: <In, Channel extends string, PikkuPermission extends CorePikkuPermission<In>, PikkuMiddleware extends CorePikkuMiddleware, ChannelFunction>(channel: CoreChannel<In, Channel, PikkuPermission, PikkuMiddleware, ChannelFunction>) => void;
|
|
9
10
|
export declare const openChannel: ({ route, singletonServices, coerceDataFromSchema, request, }: Pick<CoreChannel<unknown, string>, "route"> & RunChannelParams<unknown> & {
|
|
10
11
|
userSession: UserSessionService<any>;
|
|
11
12
|
} & RunChannelOptions) => Promise<{
|
|
12
13
|
openingData: unknown;
|
|
13
14
|
channelConfig: CoreChannel<unknown, any>;
|
|
14
15
|
meta: ChannelMeta;
|
|
15
|
-
httpMiddleware: CorePikkuMiddleware[] | undefined;
|
|
16
16
|
}>;
|
|
@@ -17,24 +17,15 @@ export const wireChannel = (channel) => {
|
|
|
17
17
|
pikkuState('channel', 'channels').set(channel.name, channel);
|
|
18
18
|
// Register onConnect function if provided
|
|
19
19
|
if (channel.onConnect && channelMeta.connect) {
|
|
20
|
-
addFunction(channelMeta.connect.pikkuFuncName,
|
|
21
|
-
func: channel.onConnect,
|
|
22
|
-
});
|
|
20
|
+
addFunction(channelMeta.connect.pikkuFuncName, channel.onConnect);
|
|
23
21
|
}
|
|
24
22
|
// Register onDisconnect function if provided
|
|
25
23
|
if (channel.onDisconnect && channelMeta.disconnect) {
|
|
26
|
-
addFunction(channelMeta.disconnect.pikkuFuncName,
|
|
27
|
-
func: channel.onDisconnect,
|
|
28
|
-
});
|
|
24
|
+
addFunction(channelMeta.disconnect.pikkuFuncName, channel.onDisconnect);
|
|
29
25
|
}
|
|
30
26
|
// Register onMessage function if provided
|
|
31
27
|
if (channel.onMessage && channelMeta.message?.pikkuFuncName) {
|
|
32
|
-
|
|
33
|
-
? channel.onMessage
|
|
34
|
-
: channel.onMessage.func;
|
|
35
|
-
addFunction(channelMeta.message.pikkuFuncName, {
|
|
36
|
-
func: messageFunc,
|
|
37
|
-
});
|
|
28
|
+
addFunction(channelMeta.message.pikkuFuncName, channel.onMessage);
|
|
38
29
|
}
|
|
39
30
|
// Register functions in onMessageWiring
|
|
40
31
|
if (channel.onMessageWiring && channelMeta.messageWirings) {
|
|
@@ -48,16 +39,8 @@ export const wireChannel = (channel) => {
|
|
|
48
39
|
const wiringMeta = channelWirings[wiringKey];
|
|
49
40
|
if (!wiringMeta)
|
|
50
41
|
return;
|
|
51
|
-
// Extract the function from the handler
|
|
52
|
-
const wiringFunc = typeof handler === 'function'
|
|
53
|
-
? { func: handler }
|
|
54
|
-
: {
|
|
55
|
-
func: handler.func,
|
|
56
|
-
auth: handler.auth,
|
|
57
|
-
permissions: handler.permissions,
|
|
58
|
-
};
|
|
59
42
|
// Register the function using the pikku name from metadata
|
|
60
|
-
addFunction(wiringMeta.pikkuFuncName,
|
|
43
|
+
addFunction(wiringMeta.pikkuFuncName, handler);
|
|
61
44
|
});
|
|
62
45
|
});
|
|
63
46
|
}
|
|
@@ -85,7 +68,6 @@ const getMatchingChannelConfig = (request) => {
|
|
|
85
68
|
channelConfig,
|
|
86
69
|
schemaName: channelMeta.input,
|
|
87
70
|
meta: channelMeta,
|
|
88
|
-
httpMiddleware: matchedPath.middleware,
|
|
89
71
|
};
|
|
90
72
|
};
|
|
91
73
|
export const openChannel = async ({ route, singletonServices, coerceDataFromSchema = true, request, }) => {
|
|
@@ -94,7 +76,7 @@ export const openChannel = async ({ route, singletonServices, coerceDataFromSche
|
|
|
94
76
|
singletonServices.logger.info(`Channel not found: ${route}`);
|
|
95
77
|
throw new NotFoundError(`Channel not found: ${route}`);
|
|
96
78
|
}
|
|
97
|
-
const { params, channelConfig, schemaName, meta
|
|
79
|
+
const { params, channelConfig, schemaName, meta } = matchingChannel;
|
|
98
80
|
const requiresSession = channelConfig.auth !== false;
|
|
99
81
|
request?.setParams(params);
|
|
100
82
|
singletonServices.logger.info(`Matched channel: ${channelConfig.name} | route: ${channelConfig.route} | auth: ${requiresSession.toString()}`);
|
|
@@ -106,5 +88,5 @@ export const openChannel = async ({ route, singletonServices, coerceDataFromSche
|
|
|
106
88
|
}
|
|
107
89
|
await validateSchema(singletonServices.logger, singletonServices.schema, schemaName, openingData);
|
|
108
90
|
}
|
|
109
|
-
return { openingData, channelConfig, meta
|
|
91
|
+
return { openingData, channelConfig, meta };
|
|
110
92
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PikkuError } from '../../errors/error-handler.js';
|
|
2
2
|
import { HTTPFunctionMetaInputTypes, PikkuHTTPRequest, PikkuHTTPResponse } from '../http/http.types.js';
|
|
3
|
-
import { PikkuDocs, CoreSingletonServices, CreateSessionServices, CorePikkuMiddleware } from '../../types/core.types.js';
|
|
4
|
-
import { CorePikkuFunction, CorePikkuFunctionSessionless, CorePikkuPermission } from '../../function/functions.types.js';
|
|
3
|
+
import { PikkuDocs, CoreSingletonServices, CreateSessionServices, CorePikkuMiddleware, MiddlewareMetadata, PermissionMetadata } from '../../types/core.types.js';
|
|
4
|
+
import { CorePermissionGroup, CorePikkuFunction, CorePikkuFunctionConfig, CorePikkuFunctionSessionless, CorePikkuPermission } from '../../function/functions.types.js';
|
|
5
5
|
export type RunChannelOptions = Partial<{
|
|
6
6
|
skipUserSession: boolean;
|
|
7
7
|
respondWith404: boolean;
|
|
@@ -19,6 +19,8 @@ export type RunChannelParams<ChannelData> = {
|
|
|
19
19
|
export interface ChannelMessageMeta {
|
|
20
20
|
pikkuFuncName: string;
|
|
21
21
|
docs?: PikkuDocs;
|
|
22
|
+
middleware?: MiddlewareMetadata[];
|
|
23
|
+
permissions?: PermissionMetadata[];
|
|
22
24
|
}
|
|
23
25
|
export interface ChannelMeta {
|
|
24
26
|
name: string;
|
|
@@ -33,25 +35,24 @@ export interface ChannelMeta {
|
|
|
33
35
|
messageWirings: Record<string, Record<string, ChannelMessageMeta>>;
|
|
34
36
|
docs?: PikkuDocs;
|
|
35
37
|
tags?: string[];
|
|
38
|
+
middleware?: MiddlewareMetadata[];
|
|
39
|
+
permissions?: PermissionMetadata[];
|
|
36
40
|
}
|
|
37
41
|
export type ChannelsMeta = Record<string, ChannelMeta>;
|
|
38
|
-
export type CoreChannel<ChannelData, Channel extends string, ChannelConnect = CorePikkuFunction<void, unknown, ChannelData> | CorePikkuFunctionSessionless<void, unknown, ChannelData>, ChannelDisconnect = CorePikkuFunction<void, void, ChannelData> | CorePikkuFunctionSessionless<void, void, ChannelData>, ChannelFunctionMessage = CorePikkuFunction<unknown, unknown, ChannelData> | CorePikkuFunctionSessionless<unknown, unknown, ChannelData>, PikkuPermission = CorePikkuPermission<ChannelData
|
|
42
|
+
export type CoreChannel<ChannelData, Channel extends string, ChannelConnect = CorePikkuFunctionConfig<CorePikkuFunction<void, unknown, ChannelData> | CorePikkuFunctionSessionless<void, unknown, ChannelData>, CorePikkuPermission<void>, CorePikkuMiddleware>, ChannelDisconnect = CorePikkuFunctionConfig<CorePikkuFunction<void, void, ChannelData> | CorePikkuFunctionSessionless<void, void, ChannelData>, CorePikkuPermission<void>, CorePikkuMiddleware>, ChannelFunctionMessage = CorePikkuFunctionConfig<CorePikkuFunction<unknown, unknown, ChannelData> | CorePikkuFunctionSessionless<unknown, unknown, ChannelData>, CorePikkuPermission<unknown>, CorePikkuMiddleware>, PikkuPermission = CorePikkuPermission<ChannelData>, PikkuMiddleware = CorePikkuMiddleware> = {
|
|
39
43
|
name: string;
|
|
40
44
|
route: Channel;
|
|
41
45
|
onConnect?: ChannelConnect;
|
|
42
46
|
onDisconnect?: ChannelDisconnect;
|
|
43
|
-
onMessage?:
|
|
44
|
-
func: ChannelFunctionMessage;
|
|
45
|
-
permissions?: Record<string, PikkuPermission[] | PikkuPermission>;
|
|
46
|
-
auth?: boolean;
|
|
47
|
-
} | ChannelFunctionMessage;
|
|
47
|
+
onMessage?: ChannelFunctionMessage;
|
|
48
48
|
onMessageWiring?: Record<string, Record<string, ChannelFunctionMessage | {
|
|
49
49
|
func: ChannelFunctionMessage;
|
|
50
|
-
permissions?:
|
|
50
|
+
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
51
51
|
auth?: boolean;
|
|
52
|
+
middleware?: PikkuMiddleware[];
|
|
52
53
|
}>>;
|
|
53
|
-
middleware?:
|
|
54
|
-
permissions?:
|
|
54
|
+
middleware?: PikkuMiddleware[];
|
|
55
|
+
permissions?: CorePermissionGroup<PikkuPermission>;
|
|
55
56
|
auth?: boolean;
|
|
56
57
|
docs?: Partial<{
|
|
57
58
|
description: string;
|
|
@@ -61,11 +62,11 @@ export type CoreChannel<ChannelData, Channel extends string, ChannelConnect = Co
|
|
|
61
62
|
}>;
|
|
62
63
|
tags?: string[];
|
|
63
64
|
};
|
|
64
|
-
export interface PikkuChannel<OpeningData, Out> {
|
|
65
|
+
export interface PikkuChannel<OpeningData, out Out> {
|
|
65
66
|
channelId: string;
|
|
66
67
|
openingData: OpeningData;
|
|
67
|
-
send
|
|
68
|
-
close
|
|
68
|
+
send(data: Out, isBinary?: boolean): Promise<void> | void;
|
|
69
|
+
close(): Promise<void> | void;
|
|
69
70
|
state: 'initial' | 'open' | 'closed';
|
|
70
71
|
}
|
|
71
72
|
export interface PikkuChannelHandler<OpeningData = unknown, Out = unknown> {
|
|
@@ -3,7 +3,7 @@ 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 { PikkuLocalChannelHandler } from './local-channel-handler.js';
|
|
6
|
-
import { PikkuWiringTypes } from '../../../types/core.types.js';
|
|
6
|
+
import { PikkuWiringTypes, } from '../../../types/core.types.js';
|
|
7
7
|
import { handleHTTPError } from '../../../handle-error.js';
|
|
8
8
|
import { combineMiddleware, runMiddleware } from '../../../middleware-runner.js';
|
|
9
9
|
import { PikkuUserSessionService } from '../../../services/user-session-service.js';
|
|
@@ -18,10 +18,10 @@ export const runLocalChannel = async ({ singletonServices, channelId, request, r
|
|
|
18
18
|
http = createHTTPInteraction(request, response);
|
|
19
19
|
route = http?.request?.path();
|
|
20
20
|
}
|
|
21
|
-
let openingData, channelConfig, meta
|
|
21
|
+
let openingData, channelConfig, meta;
|
|
22
22
|
try {
|
|
23
23
|
;
|
|
24
|
-
({ openingData, channelConfig, meta
|
|
24
|
+
({ openingData, channelConfig, meta } = await openChannel({
|
|
25
25
|
channelId,
|
|
26
26
|
createSessionServices,
|
|
27
27
|
respondWith404,
|
|
@@ -46,25 +46,26 @@ export const runLocalChannel = async ({ singletonServices, channelId, request, r
|
|
|
46
46
|
if (createSessionServices) {
|
|
47
47
|
sessionServices = await createSessionServices(singletonServices, { http, channel }, session);
|
|
48
48
|
}
|
|
49
|
-
const
|
|
49
|
+
const getAllServices = (channel, requiresAuth) => rpcService.injectRPCService({
|
|
50
50
|
...singletonServices,
|
|
51
51
|
...sessionServices,
|
|
52
|
-
userSession
|
|
53
|
-
});
|
|
52
|
+
userSession,
|
|
53
|
+
}, interaction, requiresAuth);
|
|
54
|
+
const interaction = { channel };
|
|
54
55
|
channelHandler.registerOnOpen(() => {
|
|
55
56
|
if (channelConfig.onConnect && meta.connect) {
|
|
56
|
-
runPikkuFuncDirectly(meta.connect.pikkuFuncName,
|
|
57
|
+
runPikkuFuncDirectly(meta.connect.pikkuFuncName, getAllServices(channel, false), openingData);
|
|
57
58
|
}
|
|
58
59
|
});
|
|
59
60
|
channelHandler.registerOnClose(async () => {
|
|
60
61
|
if (channelConfig.onDisconnect && meta.disconnect) {
|
|
61
|
-
runPikkuFuncDirectly(meta.disconnect.pikkuFuncName,
|
|
62
|
+
runPikkuFuncDirectly(meta.disconnect.pikkuFuncName, getAllServices(channel, false), openingData);
|
|
62
63
|
}
|
|
63
64
|
if (sessionServices) {
|
|
64
65
|
await closeSessionServices(singletonServices.logger, sessionServices);
|
|
65
66
|
}
|
|
66
67
|
});
|
|
67
|
-
channelHandler.registerOnMessage(processMessageHandlers(
|
|
68
|
+
channelHandler.registerOnMessage(processMessageHandlers(getAllServices(channel), channelConfig, channelHandler));
|
|
68
69
|
}
|
|
69
70
|
catch (e) {
|
|
70
71
|
handleHTTPError(e, http, channelId, singletonServices.logger, logWarningsForStatusCodes, respondWith404, bubbleErrors);
|
|
@@ -79,9 +80,8 @@ export const runLocalChannel = async ({ singletonServices, channelId, request, r
|
|
|
79
80
|
...singletonServices,
|
|
80
81
|
userSession,
|
|
81
82
|
}, { http }, combineMiddleware(PikkuWiringTypes.channel, channelConfig.name, {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
httpMiddleware,
|
|
83
|
+
wireInheritedMiddleware: meta.middleware,
|
|
84
|
+
wireMiddleware: channelConfig.middleware,
|
|
85
85
|
}), main);
|
|
86
86
|
return channelHandler;
|
|
87
87
|
};
|
|
@@ -35,7 +35,7 @@ export const runChannelConnect = async ({ singletonServices, channelId, channelO
|
|
|
35
35
|
http = createHTTPInteraction(new PikkuFetchHTTPRequest(request), response);
|
|
36
36
|
}
|
|
37
37
|
const userSession = new PikkuUserSessionService(channelStore, channelId);
|
|
38
|
-
const { channelConfig, openingData, meta
|
|
38
|
+
const { channelConfig, openingData, meta } = await openChannel({
|
|
39
39
|
channelId,
|
|
40
40
|
createSessionServices,
|
|
41
41
|
request,
|
|
@@ -78,9 +78,8 @@ export const runChannelConnect = async ({ singletonServices, channelId, channelO
|
|
|
78
78
|
...singletonServices,
|
|
79
79
|
userSession,
|
|
80
80
|
}, { http }, combineMiddleware(PikkuWiringTypes.channel, channelConfig.name, {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
httpMiddleware,
|
|
81
|
+
wireInheritedMiddleware: meta.middleware,
|
|
82
|
+
wireMiddleware: channelConfig.middleware,
|
|
84
83
|
}), main);
|
|
85
84
|
};
|
|
86
85
|
export const runChannelDisconnect = async ({ singletonServices, ...params }) => {
|
|
@@ -92,7 +91,7 @@ export const runChannelDisconnect = async ({ singletonServices, ...params }) =>
|
|
|
92
91
|
channelName,
|
|
93
92
|
});
|
|
94
93
|
if (!sessionServices && params.createSessionServices) {
|
|
95
|
-
sessionServices = await params.createSessionServices(singletonServices, {}, session);
|
|
94
|
+
sessionServices = await params.createSessionServices(singletonServices, { channel }, session);
|
|
96
95
|
}
|
|
97
96
|
if (channelConfig.onDisconnect && meta.disconnect) {
|
|
98
97
|
await runPikkuFuncDirectly(meta.disconnect.pikkuFuncName, { ...singletonServices, ...sessionServices, channel }, undefined);
|
|
@@ -105,17 +104,17 @@ export const runChannelDisconnect = async ({ singletonServices, ...params }) =>
|
|
|
105
104
|
export const runChannelMessage = async ({ singletonServices, ...params }, data) => {
|
|
106
105
|
let sessionServices;
|
|
107
106
|
const { openingData, channelName, session } = await params.channelStore.getChannelAndSession(params.channelId);
|
|
108
|
-
const { channelHandler, channelConfig } = getVariablesForChannel({
|
|
107
|
+
const { channel, channelHandler, channelConfig } = getVariablesForChannel({
|
|
109
108
|
...params,
|
|
110
109
|
openingData,
|
|
111
110
|
channelName,
|
|
112
111
|
});
|
|
113
112
|
if (params.createSessionServices) {
|
|
114
|
-
sessionServices = await params.createSessionServices(singletonServices, {}, session);
|
|
113
|
+
sessionServices = await params.createSessionServices(singletonServices, { channel }, session);
|
|
115
114
|
}
|
|
116
115
|
let response;
|
|
117
116
|
try {
|
|
118
|
-
const onMessage = processMessageHandlers({ ...singletonServices, ...sessionServices },
|
|
117
|
+
const onMessage = processMessageHandlers({ ...singletonServices, ...sessionServices }, channelConfig, channelHandler);
|
|
119
118
|
response = await onMessage(data);
|
|
120
119
|
}
|
|
121
120
|
finally {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CorePikkuCLIRender } from '../cli.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Execute a CLI program via WebSocket channel
|
|
4
|
+
* This is the main entry point for CLI-over-Channel clients
|
|
5
|
+
*/
|
|
6
|
+
export declare function executeCLIViaChannel({ programName, pikkuWS, args, renderers, defaultRenderer, }: {
|
|
7
|
+
programName: string;
|
|
8
|
+
pikkuWS: any;
|
|
9
|
+
args?: string[];
|
|
10
|
+
renderers?: Record<string, CorePikkuCLIRender<any>>;
|
|
11
|
+
defaultRenderer?: CorePikkuCLIRender<any>;
|
|
12
|
+
}): Promise<void>;
|