@pikku/core 0.9.12-next.0 → 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 +8 -0
- package/dist/errors/errors.d.ts +2 -0
- package/dist/errors/errors.js +6 -0
- package/dist/function/function-runner.d.ts +5 -4
- package/dist/function/function-runner.js +10 -4
- package/dist/function/functions.types.d.ts +67 -1
- package/dist/function/functions.types.js +43 -1
- package/dist/index.d.ts +1 -7
- package/dist/index.js +1 -7
- 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 +0 -18
- package/dist/middleware-runner.js +0 -21
- package/dist/permissions.d.ts +82 -20
- package/dist/permissions.js +175 -62
- package/dist/pikku-state.d.ts +22 -2
- package/dist/pikku-state.js +7 -1
- package/dist/types/core.types.d.ts +58 -1
- package/dist/types/core.types.js +23 -1
- package/dist/utils.d.ts +1 -1
- package/dist/wirings/channel/channel-handler.js +6 -5
- package/dist/wirings/channel/channel-runner.d.ts +3 -1
- package/dist/wirings/channel/channel-runner.js +4 -21
- package/dist/wirings/channel/channel.types.d.ts +12 -13
- package/dist/wirings/cli/channel/cli-channel-runner.js +5 -2
- package/dist/wirings/cli/cli-runner.d.ts +10 -0
- package/dist/wirings/cli/cli-runner.js +44 -20
- package/dist/wirings/cli/cli.types.d.ts +54 -27
- package/dist/wirings/cli/command-parser.js +34 -4
- package/dist/wirings/cli/index.d.ts +1 -1
- package/dist/wirings/cli/index.js +1 -1
- package/dist/wirings/http/http-runner.d.ts +31 -1
- package/dist/wirings/http/http-runner.js +36 -1
- package/dist/wirings/http/http.types.d.ts +2 -1
- package/dist/wirings/http/index.d.ts +1 -1
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.js +2 -0
- package/dist/wirings/mcp/mcp.types.d.ts +35 -14
- package/dist/wirings/scheduler/scheduler-runner.js +1 -0
- package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
- package/package.json +6 -5
- package/src/errors/errors.ts +6 -0
- package/src/factory-functions.test.ts +60 -1
- package/src/function/function-runner.test.ts +8 -3
- package/src/function/function-runner.ts +18 -5
- package/src/function/functions.types.ts +85 -2
- package/src/index.ts +1 -21
- 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.ts +0 -25
- package/src/permissions.test.ts +26 -27
- package/src/permissions.ts +215 -104
- package/src/pikku-state.ts +35 -3
- package/src/types/core.types.ts +70 -3
- package/src/utils.ts +1 -1
- package/src/wirings/channel/channel-handler.ts +11 -10
- package/src/wirings/channel/channel-runner.ts +18 -27
- package/src/wirings/channel/channel.types.ts +24 -15
- package/src/wirings/cli/channel/cli-channel-runner.ts +8 -3
- package/src/wirings/cli/cli-runner.test.ts +80 -59
- package/src/wirings/cli/cli-runner.ts +57 -21
- package/src/wirings/cli/cli.types.ts +74 -44
- package/src/wirings/cli/command-parser.test.ts +91 -86
- package/src/wirings/cli/command-parser.ts +38 -4
- package/src/wirings/cli/index.ts +1 -0
- package/src/wirings/http/http-runner.ts +41 -1
- package/src/wirings/http/http.types.ts +3 -1
- package/src/wirings/http/index.ts +7 -1
- package/src/wirings/mcp/mcp-endpoint-registry.ts +1 -1
- package/src/wirings/mcp/mcp-runner.ts +2 -0
- package/src/wirings/mcp/mcp.types.ts +48 -12
- package/src/wirings/scheduler/scheduler-runner.ts +1 -0
- package/src/wirings/scheduler/scheduler.types.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -1
package/src/pikku-state.ts
CHANGED
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
MCPToolMeta,
|
|
33
33
|
MCPPromptMeta,
|
|
34
34
|
} from './wirings/mcp/mcp.types.js'
|
|
35
|
-
import {
|
|
35
|
+
import { CLIMeta, CLIProgramState } from './wirings/cli/cli.types.js'
|
|
36
36
|
|
|
37
37
|
interface PikkuState {
|
|
38
38
|
function: {
|
|
@@ -76,7 +76,7 @@ interface PikkuState {
|
|
|
76
76
|
promptsMeta: MCPPromptMeta
|
|
77
77
|
}
|
|
78
78
|
cli: {
|
|
79
|
-
meta: Record<string,
|
|
79
|
+
meta: CLIMeta | Record<string, any> // Backward compatible with old published CLI format
|
|
80
80
|
programs: Record<string, CLIProgramState>
|
|
81
81
|
}
|
|
82
82
|
middleware: {
|
|
@@ -105,6 +105,32 @@ interface PikkuState {
|
|
|
105
105
|
}
|
|
106
106
|
>
|
|
107
107
|
}
|
|
108
|
+
permissions: {
|
|
109
|
+
tagGroup: Record<string, CorePermissionGroup | CorePikkuPermission[]>
|
|
110
|
+
httpGroup: Record<string, CorePermissionGroup | CorePikkuPermission[]>
|
|
111
|
+
tagGroupMeta: Record<
|
|
112
|
+
string,
|
|
113
|
+
{
|
|
114
|
+
exportName: string | null
|
|
115
|
+
sourceFile: string
|
|
116
|
+
position: number
|
|
117
|
+
services: FunctionServicesMeta
|
|
118
|
+
permissionCount: number
|
|
119
|
+
isFactory: boolean
|
|
120
|
+
}
|
|
121
|
+
>
|
|
122
|
+
httpGroupMeta: Record<
|
|
123
|
+
string,
|
|
124
|
+
{
|
|
125
|
+
exportName: string | null
|
|
126
|
+
sourceFile: string
|
|
127
|
+
position: number
|
|
128
|
+
services: FunctionServicesMeta
|
|
129
|
+
permissionCount: number
|
|
130
|
+
isFactory: boolean
|
|
131
|
+
}
|
|
132
|
+
>
|
|
133
|
+
}
|
|
108
134
|
misc: {
|
|
109
135
|
errors: Map<PikkuError, ErrorDetails>
|
|
110
136
|
schemas: Map<string, any>
|
|
@@ -149,7 +175,7 @@ export const resetPikkuState = () => {
|
|
|
149
175
|
promptsMeta: {} as MCPPromptMeta,
|
|
150
176
|
},
|
|
151
177
|
cli: {
|
|
152
|
-
meta: {},
|
|
178
|
+
meta: { programs: {}, renderers: {} },
|
|
153
179
|
programs: {},
|
|
154
180
|
},
|
|
155
181
|
middleware: {
|
|
@@ -158,6 +184,12 @@ export const resetPikkuState = () => {
|
|
|
158
184
|
tagGroupMeta: {},
|
|
159
185
|
httpGroupMeta: {},
|
|
160
186
|
},
|
|
187
|
+
permissions: {
|
|
188
|
+
tagGroup: {},
|
|
189
|
+
httpGroup: {},
|
|
190
|
+
tagGroupMeta: {},
|
|
191
|
+
httpGroupMeta: {},
|
|
192
|
+
},
|
|
161
193
|
misc: {
|
|
162
194
|
errors: globalThis.pikkuState?.misc?.errors || new Map(),
|
|
163
195
|
schemas: new Map(),
|
package/src/types/core.types.ts
CHANGED
|
@@ -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'
|
|
@@ -46,6 +47,27 @@ export type MiddlewareMetadata =
|
|
|
46
47
|
inline?: boolean // true if inline middleware
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Metadata for permissions at any level
|
|
52
|
+
* - type: 'http' = HTTP route permission group (references httpGroup in pikkuState)
|
|
53
|
+
* - type: 'tag' = Tag-based permission group (references tagGroup in pikkuState)
|
|
54
|
+
* - type: 'wire' = Wire-level individual permission
|
|
55
|
+
*/
|
|
56
|
+
export type PermissionMetadata =
|
|
57
|
+
| {
|
|
58
|
+
type: 'http'
|
|
59
|
+
route: string // Route pattern (e.g., '*' for all, '/api/*' for specific)
|
|
60
|
+
}
|
|
61
|
+
| {
|
|
62
|
+
type: 'tag'
|
|
63
|
+
tag: string // Tag name
|
|
64
|
+
}
|
|
65
|
+
| {
|
|
66
|
+
type: 'wire'
|
|
67
|
+
name: string
|
|
68
|
+
inline?: boolean // true if inline permission
|
|
69
|
+
}
|
|
70
|
+
|
|
49
71
|
export type FunctionRuntimeMeta = {
|
|
50
72
|
pikkuFuncName: string
|
|
51
73
|
inputSchemaName: string | null
|
|
@@ -62,7 +84,8 @@ export type FunctionMeta = FunctionRuntimeMeta &
|
|
|
62
84
|
tags: string[]
|
|
63
85
|
docs: PikkuDocs
|
|
64
86
|
isDirectFunction: boolean // true if it's pikkuFunc(fn), false if it's pikkuFunc({ func: fn })
|
|
65
|
-
middleware: MiddlewareMetadata[] // Function-level middleware
|
|
87
|
+
middleware: MiddlewareMetadata[] // Function-level middleware
|
|
88
|
+
permissions: PermissionMetadata[] // Function-level permissions
|
|
66
89
|
}>
|
|
67
90
|
|
|
68
91
|
export type FunctionsRuntimeMeta = Record<string, FunctionRuntimeMeta>
|
|
@@ -127,6 +150,8 @@ export interface CoreUserSession {}
|
|
|
127
150
|
export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
|
|
128
151
|
/** The schema library used to validate data */
|
|
129
152
|
schema?: SchemaService
|
|
153
|
+
/** The JWT service used to encode and decode tokens */
|
|
154
|
+
jwt?: JWTService
|
|
130
155
|
/** The core configuration for the application. */
|
|
131
156
|
config: Config
|
|
132
157
|
/** The logger used by the application. */
|
|
@@ -162,6 +187,24 @@ export type CorePikkuMiddleware<
|
|
|
162
187
|
next: () => Promise<void>
|
|
163
188
|
) => Promise<void>
|
|
164
189
|
|
|
190
|
+
/**
|
|
191
|
+
* Configuration object for creating middleware with metadata
|
|
192
|
+
*
|
|
193
|
+
* @template SingletonServices - The singleton services type
|
|
194
|
+
* @template UserSession - The user session type
|
|
195
|
+
*/
|
|
196
|
+
export type CorePikkuMiddlewareConfig<
|
|
197
|
+
SingletonServices extends CoreSingletonServices = CoreSingletonServices,
|
|
198
|
+
UserSession extends CoreUserSession = CoreUserSession,
|
|
199
|
+
> = {
|
|
200
|
+
/** The middleware function */
|
|
201
|
+
func: CorePikkuMiddleware<SingletonServices, UserSession>
|
|
202
|
+
/** Optional human-readable name for the middleware */
|
|
203
|
+
name?: string
|
|
204
|
+
/** Optional description of what the middleware does */
|
|
205
|
+
description?: string
|
|
206
|
+
}
|
|
207
|
+
|
|
165
208
|
/**
|
|
166
209
|
* A factory function that takes input and returns middleware
|
|
167
210
|
* Used when middleware needs configuration/input parameters
|
|
@@ -186,14 +229,38 @@ export type CorePikkuMiddlewareGroup<
|
|
|
186
229
|
|
|
187
230
|
/**
|
|
188
231
|
* Factory function for creating middleware with tree-shaking support
|
|
232
|
+
* Supports both direct function and configuration object syntax
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```typescript
|
|
236
|
+
* // Direct function syntax
|
|
237
|
+
* export const logMiddleware = pikkuMiddleware(
|
|
238
|
+
* async ({ logger }, _interaction, next) => {
|
|
239
|
+
* logger.info('Request started')
|
|
240
|
+
* await next()
|
|
241
|
+
* }
|
|
242
|
+
* )
|
|
243
|
+
*
|
|
244
|
+
* // Configuration object syntax with metadata
|
|
245
|
+
* export const logMiddleware = pikkuMiddleware({
|
|
246
|
+
* name: 'Request Logger',
|
|
247
|
+
* description: 'Logs request information',
|
|
248
|
+
* func: async ({ logger }, _interaction, next) => {
|
|
249
|
+
* logger.info('Request started')
|
|
250
|
+
* await next()
|
|
251
|
+
* }
|
|
252
|
+
* })
|
|
253
|
+
* ```
|
|
189
254
|
*/
|
|
190
255
|
export const pikkuMiddleware = <
|
|
191
256
|
SingletonServices extends CoreSingletonServices = CoreSingletonServices,
|
|
192
257
|
UserSession extends CoreUserSession = CoreUserSession,
|
|
193
258
|
>(
|
|
194
|
-
middleware:
|
|
259
|
+
middleware:
|
|
260
|
+
| CorePikkuMiddleware<SingletonServices, UserSession>
|
|
261
|
+
| CorePikkuMiddlewareConfig<SingletonServices, UserSession>
|
|
195
262
|
): CorePikkuMiddleware<SingletonServices, UserSession> => {
|
|
196
|
-
return middleware
|
|
263
|
+
return typeof middleware === 'function' ? middleware : middleware.func
|
|
197
264
|
}
|
|
198
265
|
|
|
199
266
|
/**
|
package/src/utils.ts
CHANGED
|
@@ -41,7 +41,7 @@ export const isSerializable = (data: any): boolean => {
|
|
|
41
41
|
|
|
42
42
|
const EMPTY_ARRAY = Object.freeze([])
|
|
43
43
|
|
|
44
|
-
export const freezeDedupe = <T
|
|
44
|
+
export const freezeDedupe = <T>(
|
|
45
45
|
arr?: readonly T[] | T[] | undefined
|
|
46
46
|
): readonly T[] => {
|
|
47
47
|
if (!arr || arr.length === 0) return EMPTY_ARRAY
|
|
@@ -85,16 +85,16 @@ export const processMessageHandlers = (
|
|
|
85
85
|
return
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
const {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
)
|
|
88
|
+
const {
|
|
89
|
+
pikkuFuncName,
|
|
90
|
+
middleware: inheritedMiddleware,
|
|
91
|
+
permissions: inheritedPermissions,
|
|
92
|
+
} = getRouteMeta(channelConfig.name, routingProperty, routerValue)
|
|
93
93
|
|
|
94
|
-
const
|
|
95
|
-
typeof onMessage === 'function' ?
|
|
94
|
+
const wirePermissions =
|
|
95
|
+
typeof onMessage === 'function' ? undefined : onMessage.permissions
|
|
96
96
|
|
|
97
|
-
const
|
|
97
|
+
const wireMiddleware =
|
|
98
98
|
typeof onMessage === 'function' ? [] : onMessage.middleware
|
|
99
99
|
|
|
100
100
|
return await runPikkuFunc(
|
|
@@ -109,9 +109,10 @@ export const processMessageHandlers = (
|
|
|
109
109
|
}),
|
|
110
110
|
data: () => data,
|
|
111
111
|
userSession: services.userSession,
|
|
112
|
-
permissions,
|
|
113
112
|
inheritedMiddleware,
|
|
114
|
-
wireMiddleware
|
|
113
|
+
wireMiddleware,
|
|
114
|
+
inheritedPermissions,
|
|
115
|
+
wirePermissions,
|
|
115
116
|
tags: channelConfig.tags,
|
|
116
117
|
interaction: { channel: channelHandler.getChannel() },
|
|
117
118
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { NotFoundError } from '../../errors/errors.js'
|
|
2
2
|
import { addFunction } from '../../function/function-runner.js'
|
|
3
|
+
import { CorePikkuPermission } from '../../function/functions.types.js'
|
|
3
4
|
import { pikkuState } from '../../pikku-state.js'
|
|
4
5
|
import { coerceTopLevelDataFromSchema, validateSchema } from '../../schema.js'
|
|
5
6
|
import { UserSessionService } from '../../services/user-session-service.js'
|
|
7
|
+
import { CorePikkuMiddleware } from '../../types/core.types.js'
|
|
6
8
|
import { httpRouter } from '../http/routers/http-router.js'
|
|
7
9
|
import {
|
|
8
10
|
ChannelMeta,
|
|
@@ -18,11 +20,17 @@ import {
|
|
|
18
20
|
export const wireChannel = <
|
|
19
21
|
In,
|
|
20
22
|
Channel extends string,
|
|
23
|
+
PikkuPermission extends CorePikkuPermission<In>,
|
|
24
|
+
PikkuMiddleware extends CorePikkuMiddleware,
|
|
21
25
|
ChannelFunction,
|
|
22
|
-
ChannelFunctionSessionless,
|
|
23
|
-
PikkuPermission,
|
|
24
26
|
>(
|
|
25
|
-
channel: CoreChannel<
|
|
27
|
+
channel: CoreChannel<
|
|
28
|
+
In,
|
|
29
|
+
Channel,
|
|
30
|
+
PikkuPermission,
|
|
31
|
+
PikkuMiddleware,
|
|
32
|
+
ChannelFunction
|
|
33
|
+
>
|
|
26
34
|
) => {
|
|
27
35
|
// Get the channel metadata
|
|
28
36
|
const channelsMeta = pikkuState('channel', 'meta')
|
|
@@ -35,27 +43,20 @@ export const wireChannel = <
|
|
|
35
43
|
|
|
36
44
|
// Register onConnect function if provided
|
|
37
45
|
if (channel.onConnect && channelMeta.connect) {
|
|
38
|
-
addFunction(channelMeta.connect.pikkuFuncName,
|
|
39
|
-
func: channel.onConnect as any,
|
|
40
|
-
})
|
|
46
|
+
addFunction(channelMeta.connect.pikkuFuncName, channel.onConnect as any)
|
|
41
47
|
}
|
|
42
48
|
|
|
43
49
|
// Register onDisconnect function if provided
|
|
44
50
|
if (channel.onDisconnect && channelMeta.disconnect) {
|
|
45
|
-
addFunction(
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
addFunction(
|
|
52
|
+
channelMeta.disconnect.pikkuFuncName,
|
|
53
|
+
channel.onDisconnect as any
|
|
54
|
+
)
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
// Register onMessage function if provided
|
|
51
58
|
if (channel.onMessage && channelMeta.message?.pikkuFuncName) {
|
|
52
|
-
|
|
53
|
-
typeof channel.onMessage === 'function'
|
|
54
|
-
? channel.onMessage
|
|
55
|
-
: channel.onMessage.func
|
|
56
|
-
addFunction(channelMeta.message.pikkuFuncName, {
|
|
57
|
-
func: messageFunc,
|
|
58
|
-
})
|
|
59
|
+
addFunction(channelMeta.message.pikkuFuncName, channel.onMessage as any)
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
// Register functions in onMessageWiring
|
|
@@ -70,18 +71,8 @@ export const wireChannel = <
|
|
|
70
71
|
const wiringMeta = channelWirings[wiringKey]
|
|
71
72
|
if (!wiringMeta) return
|
|
72
73
|
|
|
73
|
-
// Extract the function from the handler
|
|
74
|
-
const wiringFunc =
|
|
75
|
-
typeof handler === 'function'
|
|
76
|
-
? { func: handler }
|
|
77
|
-
: {
|
|
78
|
-
func: handler.func,
|
|
79
|
-
auth: handler.auth,
|
|
80
|
-
permissions: handler.permissions,
|
|
81
|
-
}
|
|
82
|
-
|
|
83
74
|
// Register the function using the pikku name from metadata
|
|
84
|
-
addFunction(wiringMeta.pikkuFuncName,
|
|
75
|
+
addFunction(wiringMeta.pikkuFuncName, handler as any)
|
|
85
76
|
})
|
|
86
77
|
})
|
|
87
78
|
}
|
|
@@ -10,9 +10,12 @@ import {
|
|
|
10
10
|
CreateSessionServices,
|
|
11
11
|
CorePikkuMiddleware,
|
|
12
12
|
MiddlewareMetadata,
|
|
13
|
+
PermissionMetadata,
|
|
13
14
|
} from '../../types/core.types.js'
|
|
14
15
|
import {
|
|
16
|
+
CorePermissionGroup,
|
|
15
17
|
CorePikkuFunction,
|
|
18
|
+
CorePikkuFunctionConfig,
|
|
16
19
|
CorePikkuFunctionSessionless,
|
|
17
20
|
CorePikkuPermission,
|
|
18
21
|
} from '../../function/functions.types.js'
|
|
@@ -37,6 +40,7 @@ export interface ChannelMessageMeta {
|
|
|
37
40
|
pikkuFuncName: string
|
|
38
41
|
docs?: PikkuDocs
|
|
39
42
|
middleware?: MiddlewareMetadata[]
|
|
43
|
+
permissions?: PermissionMetadata[]
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
export interface ChannelMeta {
|
|
@@ -53,6 +57,7 @@ export interface ChannelMeta {
|
|
|
53
57
|
docs?: PikkuDocs
|
|
54
58
|
tags?: string[]
|
|
55
59
|
middleware?: MiddlewareMetadata[] // Pre-resolved middleware chain (tag + explicit)
|
|
60
|
+
permissions?: PermissionMetadata[] // Pre-resolved permission chain (tag + explicit)
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
export type ChannelsMeta = Record<string, ChannelMeta>
|
|
@@ -60,15 +65,24 @@ export type ChannelsMeta = Record<string, ChannelMeta>
|
|
|
60
65
|
export type CoreChannel<
|
|
61
66
|
ChannelData,
|
|
62
67
|
Channel extends string,
|
|
63
|
-
ChannelConnect =
|
|
68
|
+
ChannelConnect = CorePikkuFunctionConfig<
|
|
64
69
|
| CorePikkuFunction<void, unknown, ChannelData>
|
|
65
70
|
| CorePikkuFunctionSessionless<void, unknown, ChannelData>,
|
|
66
|
-
|
|
71
|
+
CorePikkuPermission<void>,
|
|
72
|
+
CorePikkuMiddleware
|
|
73
|
+
>,
|
|
74
|
+
ChannelDisconnect = CorePikkuFunctionConfig<
|
|
67
75
|
| CorePikkuFunction<void, void, ChannelData>
|
|
68
76
|
| CorePikkuFunctionSessionless<void, void, ChannelData>,
|
|
69
|
-
|
|
77
|
+
CorePikkuPermission<void>,
|
|
78
|
+
CorePikkuMiddleware
|
|
79
|
+
>,
|
|
80
|
+
ChannelFunctionMessage = CorePikkuFunctionConfig<
|
|
70
81
|
| CorePikkuFunction<unknown, unknown, ChannelData>
|
|
71
82
|
| CorePikkuFunctionSessionless<unknown, unknown, ChannelData>,
|
|
83
|
+
CorePikkuPermission<unknown>,
|
|
84
|
+
CorePikkuMiddleware
|
|
85
|
+
>,
|
|
72
86
|
PikkuPermission = CorePikkuPermission<ChannelData>,
|
|
73
87
|
PikkuMiddleware = CorePikkuMiddleware,
|
|
74
88
|
> = {
|
|
@@ -76,13 +90,7 @@ export type CoreChannel<
|
|
|
76
90
|
route: Channel
|
|
77
91
|
onConnect?: ChannelConnect
|
|
78
92
|
onDisconnect?: ChannelDisconnect
|
|
79
|
-
onMessage?:
|
|
80
|
-
| {
|
|
81
|
-
func: ChannelFunctionMessage
|
|
82
|
-
permissions?: Record<string, PikkuPermission[] | PikkuPermission>
|
|
83
|
-
auth?: boolean
|
|
84
|
-
}
|
|
85
|
-
| ChannelFunctionMessage
|
|
93
|
+
onMessage?: ChannelFunctionMessage
|
|
86
94
|
onMessageWiring?: Record<
|
|
87
95
|
string,
|
|
88
96
|
Record<
|
|
@@ -90,13 +98,14 @@ export type CoreChannel<
|
|
|
90
98
|
| ChannelFunctionMessage
|
|
91
99
|
| {
|
|
92
100
|
func: ChannelFunctionMessage
|
|
93
|
-
permissions?:
|
|
101
|
+
permissions?: CorePermissionGroup<PikkuPermission>
|
|
94
102
|
auth?: boolean
|
|
103
|
+
middleware?: PikkuMiddleware[]
|
|
95
104
|
}
|
|
96
105
|
>
|
|
97
106
|
>
|
|
98
107
|
middleware?: PikkuMiddleware[]
|
|
99
|
-
permissions?:
|
|
108
|
+
permissions?: CorePermissionGroup<PikkuPermission>
|
|
100
109
|
auth?: boolean
|
|
101
110
|
docs?: Partial<{
|
|
102
111
|
description: string
|
|
@@ -107,16 +116,16 @@ export type CoreChannel<
|
|
|
107
116
|
tags?: string[]
|
|
108
117
|
}
|
|
109
118
|
|
|
110
|
-
export interface PikkuChannel<OpeningData, Out> {
|
|
119
|
+
export interface PikkuChannel<OpeningData, out Out> {
|
|
111
120
|
// The channel identifier
|
|
112
121
|
channelId: string
|
|
113
122
|
// The data the channel was created with. This could be query parameters
|
|
114
123
|
// or parameters in the url.
|
|
115
124
|
openingData: OpeningData
|
|
116
125
|
// The data to send. This will fail is the stream has been closed.
|
|
117
|
-
send
|
|
126
|
+
send(data: Out, isBinary?: boolean): Promise<void> | void
|
|
118
127
|
// This will close the channel.
|
|
119
|
-
close
|
|
128
|
+
close(): Promise<void> | void
|
|
120
129
|
// The current state of the channel
|
|
121
130
|
state: 'initial' | 'open' | 'closed'
|
|
122
131
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { pikkuState } from '../../../pikku-state.js'
|
|
2
|
-
import { CorePikkuCLIRender } from '../cli.types.js'
|
|
2
|
+
import { CorePikkuCLIRender, CLIMeta } from '../cli.types.js'
|
|
3
3
|
import { generateCommandHelp, parseCLIArguments } from '../command-parser.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -27,8 +27,13 @@ export async function executeCLIViaChannel({
|
|
|
27
27
|
defaultRenderer?: CorePikkuCLIRender<any>
|
|
28
28
|
}): Promise<void> {
|
|
29
29
|
// Get CLI metadata from state
|
|
30
|
-
const allCLIMeta = pikkuState('cli', 'meta')
|
|
31
|
-
|
|
30
|
+
const allCLIMeta = pikkuState('cli', 'meta') as unknown as CLIMeta | undefined
|
|
31
|
+
if (!allCLIMeta) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
'[PKU342] CLI metadata not found. No CLI wirings were registered. See https://pikku.dev/errors/pku342 for more information.'
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
const programMeta = allCLIMeta.programs[programName]
|
|
32
37
|
|
|
33
38
|
if (!programMeta) {
|
|
34
39
|
console.error(`Error: CLI program "${programName}" not found`)
|
|
@@ -30,7 +30,7 @@ describe('CLI Runner', () => {
|
|
|
30
30
|
|
|
31
31
|
describe('runCLICommand', () => {
|
|
32
32
|
test('should throw NotFoundError when program not found', async () => {
|
|
33
|
-
pikkuState('cli', 'meta', {})
|
|
33
|
+
pikkuState('cli', 'meta', { programs: {}, renderers: {} })
|
|
34
34
|
|
|
35
35
|
await assert.rejects(
|
|
36
36
|
async () =>
|
|
@@ -46,11 +46,14 @@ describe('CLI Runner', () => {
|
|
|
46
46
|
|
|
47
47
|
test('should throw NotFoundError when command not found', async () => {
|
|
48
48
|
pikkuState('cli', 'meta', {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
programs: {
|
|
50
|
+
'test-cli': {
|
|
51
|
+
program: 'test-cli',
|
|
52
|
+
commands: {},
|
|
53
|
+
options: {},
|
|
54
|
+
},
|
|
53
55
|
},
|
|
56
|
+
renderers: {},
|
|
54
57
|
})
|
|
55
58
|
|
|
56
59
|
pikkuState('cli', 'programs', {
|
|
@@ -82,18 +85,21 @@ describe('CLI Runner', () => {
|
|
|
82
85
|
|
|
83
86
|
// Setup metadata
|
|
84
87
|
pikkuState('cli', 'meta', {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
programs: {
|
|
89
|
+
'test-cli': {
|
|
90
|
+
program: 'test-cli',
|
|
91
|
+
commands: {
|
|
92
|
+
greet: {
|
|
93
|
+
command: 'greet <name>',
|
|
94
|
+
pikkuFuncName: 'greetFunc',
|
|
95
|
+
positionals: [{ name: 'name', required: true }],
|
|
96
|
+
options: {},
|
|
97
|
+
},
|
|
93
98
|
},
|
|
99
|
+
options: {},
|
|
94
100
|
},
|
|
95
|
-
options: {},
|
|
96
101
|
},
|
|
102
|
+
renderers: {},
|
|
97
103
|
})
|
|
98
104
|
|
|
99
105
|
pikkuState('cli', 'programs', {
|
|
@@ -143,18 +149,21 @@ describe('CLI Runner', () => {
|
|
|
143
149
|
}
|
|
144
150
|
|
|
145
151
|
pikkuState('cli', 'meta', {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
programs: {
|
|
153
|
+
'test-cli': {
|
|
154
|
+
program: 'test-cli',
|
|
155
|
+
commands: {
|
|
156
|
+
test: {
|
|
157
|
+
command: 'test',
|
|
158
|
+
pikkuFuncName: 'testFunc',
|
|
159
|
+
positionals: [],
|
|
160
|
+
options: {},
|
|
161
|
+
},
|
|
154
162
|
},
|
|
163
|
+
options: {},
|
|
155
164
|
},
|
|
156
|
-
options: {},
|
|
157
165
|
},
|
|
166
|
+
renderers: {},
|
|
158
167
|
})
|
|
159
168
|
|
|
160
169
|
pikkuState('cli', 'programs', {
|
|
@@ -200,18 +209,21 @@ describe('CLI Runner', () => {
|
|
|
200
209
|
const testFunc = async () => ({ success: true })
|
|
201
210
|
|
|
202
211
|
pikkuState('cli', 'meta', {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
212
|
+
programs: {
|
|
213
|
+
'test-cli': {
|
|
214
|
+
program: 'test-cli',
|
|
215
|
+
commands: {
|
|
216
|
+
greet: {
|
|
217
|
+
command: 'greet <name>',
|
|
218
|
+
pikkuFuncName: 'greetFunc',
|
|
219
|
+
positionals: [{ name: 'name', required: true }],
|
|
220
|
+
options: {},
|
|
221
|
+
},
|
|
211
222
|
},
|
|
223
|
+
options: {},
|
|
212
224
|
},
|
|
213
|
-
options: {},
|
|
214
225
|
},
|
|
226
|
+
renderers: {},
|
|
215
227
|
})
|
|
216
228
|
|
|
217
229
|
pikkuState('cli', 'programs', {
|
|
@@ -249,18 +261,21 @@ describe('CLI Runner', () => {
|
|
|
249
261
|
const testFunc = async () => ({ success: true })
|
|
250
262
|
|
|
251
263
|
pikkuState('cli', 'meta', {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
264
|
+
programs: {
|
|
265
|
+
'test-cli': {
|
|
266
|
+
program: 'test-cli',
|
|
267
|
+
commands: {
|
|
268
|
+
secure: {
|
|
269
|
+
command: 'secure',
|
|
270
|
+
pikkuFuncName: 'secureFunc',
|
|
271
|
+
positionals: [],
|
|
272
|
+
options: {},
|
|
273
|
+
},
|
|
260
274
|
},
|
|
275
|
+
options: {},
|
|
261
276
|
},
|
|
262
|
-
options: {},
|
|
263
277
|
},
|
|
278
|
+
renderers: {},
|
|
264
279
|
})
|
|
265
280
|
|
|
266
281
|
pikkuState('function', 'meta', {
|
|
@@ -292,24 +307,27 @@ describe('CLI Runner', () => {
|
|
|
292
307
|
const greetFunc = async () => 'Hello'
|
|
293
308
|
|
|
294
309
|
pikkuState('cli', 'meta', {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
310
|
+
programs: {
|
|
311
|
+
'my-cli': {
|
|
312
|
+
program: 'my-cli',
|
|
313
|
+
commands: {
|
|
314
|
+
greet: {
|
|
315
|
+
command: 'greet <name>',
|
|
316
|
+
pikkuFuncName: 'greetFunc',
|
|
317
|
+
positionals: [{ name: 'name', required: true }],
|
|
318
|
+
options: {
|
|
319
|
+
loud: {
|
|
320
|
+
description: 'Use loud greeting',
|
|
321
|
+
short: 'l',
|
|
322
|
+
default: false,
|
|
323
|
+
},
|
|
307
324
|
},
|
|
308
325
|
},
|
|
309
326
|
},
|
|
327
|
+
options: {},
|
|
310
328
|
},
|
|
311
|
-
options: {},
|
|
312
329
|
},
|
|
330
|
+
renderers: {},
|
|
313
331
|
})
|
|
314
332
|
|
|
315
333
|
wireCLI({
|
|
@@ -330,11 +348,14 @@ describe('CLI Runner', () => {
|
|
|
330
348
|
}
|
|
331
349
|
|
|
332
350
|
pikkuState('cli', 'meta', {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
351
|
+
programs: {
|
|
352
|
+
'my-cli': {
|
|
353
|
+
program: 'my-cli',
|
|
354
|
+
commands: {},
|
|
355
|
+
options: {},
|
|
356
|
+
},
|
|
337
357
|
},
|
|
358
|
+
renderers: {},
|
|
338
359
|
})
|
|
339
360
|
|
|
340
361
|
wireCLI({
|
|
@@ -349,7 +370,7 @@ describe('CLI Runner', () => {
|
|
|
349
370
|
})
|
|
350
371
|
|
|
351
372
|
test('should throw error when CLI metadata not found', () => {
|
|
352
|
-
pikkuState('cli', 'meta', {})
|
|
373
|
+
pikkuState('cli', 'meta', { programs: {}, renderers: {} })
|
|
353
374
|
|
|
354
375
|
assert.throws(() => {
|
|
355
376
|
wireCLI({
|