@pikku/core 0.9.11 → 0.9.12-next.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 +6 -0
- package/dist/function/function-runner.d.ts +13 -8
- package/dist/function/function-runner.js +49 -37
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/middleware-runner.d.ts +61 -40
- package/dist/middleware-runner.js +118 -66
- package/dist/permissions.js +1 -0
- package/dist/pikku-state.d.ts +26 -1
- package/dist/pikku-state.js +10 -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 +51 -2
- package/dist/types/core.types.js +21 -0
- package/dist/wirings/channel/channel-handler.d.ts +2 -2
- package/dist/wirings/channel/channel-handler.js +12 -9
- package/dist/wirings/channel/channel-runner.d.ts +0 -2
- package/dist/wirings/channel/channel-runner.js +2 -3
- package/dist/wirings/channel/channel.types.d.ts +5 -3
- 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 +80 -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 +32 -0
- package/dist/wirings/cli/cli-runner.js +328 -0
- package/dist/wirings/cli/cli.types.d.ts +177 -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 +373 -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 +29 -10
- package/dist/wirings/http/http-runner.js +103 -131
- package/dist/wirings/http/http.types.d.ts +10 -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-runner.d.ts +4 -5
- package/dist/wirings/mcp/mcp-runner.js +30 -34
- package/dist/wirings/mcp/mcp.types.d.ts +11 -8
- 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 +37 -35
- package/dist/wirings/scheduler/scheduler.types.d.ts +4 -3
- package/package.json +4 -3
- package/src/function/function-runner.test.ts +73 -23
- package/src/function/function-runner.ts +74 -55
- package/src/index.ts +8 -1
- package/src/middleware-runner.test.ts +24 -16
- package/src/middleware-runner.ts +136 -83
- package/src/permissions.ts +1 -0
- package/src/pikku-state.ts +47 -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 +74 -3
- package/src/wirings/channel/channel-handler.ts +9 -13
- package/src/wirings/channel/channel-runner.ts +2 -6
- package/src/wirings/channel/channel.types.ts +5 -1
- 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 +118 -0
- package/src/wirings/cli/channel/index.ts +1 -0
- package/src/wirings/cli/cli-runner.test.ts +382 -0
- package/src/wirings/cli/cli-runner.ts +503 -0
- package/src/wirings/cli/cli.types.ts +320 -0
- package/src/wirings/cli/command-parser.test.ts +440 -0
- package/src/wirings/cli/command-parser.ts +470 -0
- package/src/wirings/cli/index.ts +12 -0
- package/src/wirings/http/http-runner.test.ts +8 -7
- package/src/wirings/http/http-runner.ts +126 -159
- package/src/wirings/http/http.types.ts +56 -11
- package/src/wirings/http/index.ts +1 -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-runner.ts +56 -55
- package/src/wirings/mcp/mcp.types.ts +23 -8
- 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 +57 -56
- package/src/wirings/scheduler/scheduler.types.ts +9 -2
- package/tsconfig.tsbuildinfo +1 -1
package/src/middleware-runner.ts
CHANGED
|
@@ -3,7 +3,9 @@ import {
|
|
|
3
3
|
CoreSingletonServices,
|
|
4
4
|
PikkuInteraction,
|
|
5
5
|
CorePikkuMiddleware,
|
|
6
|
+
CorePikkuMiddlewareGroup,
|
|
6
7
|
PikkuWiringTypes,
|
|
8
|
+
MiddlewareMetadata,
|
|
7
9
|
} from './types/core.types.js'
|
|
8
10
|
import { pikkuState } from './pikku-state.js'
|
|
9
11
|
import { freezeDedupe } from './utils.js'
|
|
@@ -49,79 +51,89 @@ export const runMiddleware = async <Middleware extends CorePikkuMiddleware>(
|
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
/**
|
|
52
|
-
*
|
|
54
|
+
* Registers global middleware for a specific tag.
|
|
53
55
|
*
|
|
54
|
-
* This function
|
|
55
|
-
* any wiring (HTTP, Channel, Queue, Scheduler, MCP) that includes the matching tag.
|
|
56
|
+
* This function registers middleware at runtime that will be applied to
|
|
57
|
+
* any wiring (HTTP, Channel, Queue, Scheduler, MCP, CLI) that includes the matching tag.
|
|
58
|
+
*
|
|
59
|
+
* For tree-shaking benefits, wrap in a factory function:
|
|
60
|
+
* `export const x = () => addMiddleware('tag', [...])`
|
|
61
|
+
*
|
|
62
|
+
* Accepts an array that can contain:
|
|
63
|
+
* - Direct middleware functions (CorePikkuMiddleware)
|
|
64
|
+
* - Factory middleware functions (CorePikkuMiddlewareFactory)
|
|
56
65
|
*
|
|
57
66
|
* @template PikkuMiddleware The middleware type.
|
|
58
67
|
* @param {string} tag - The tag that the middleware should apply to.
|
|
59
|
-
* @param {
|
|
68
|
+
* @param {CorePikkuMiddlewareGroup} middleware - Array of middleware for this tag.
|
|
60
69
|
*
|
|
61
|
-
* @
|
|
70
|
+
* @returns {CorePikkuMiddlewareGroup} The middleware array (for chaining/wrapping).
|
|
62
71
|
*
|
|
63
72
|
* @example
|
|
64
73
|
* ```typescript
|
|
65
|
-
* //
|
|
66
|
-
* addMiddleware('admin', [
|
|
74
|
+
* // Recommended: tree-shakeable
|
|
75
|
+
* export const adminMiddleware = () => addMiddleware('admin', [
|
|
76
|
+
* authMiddleware,
|
|
77
|
+
* loggingMiddleware({ level: 'info' })
|
|
78
|
+
* ])
|
|
67
79
|
*
|
|
68
|
-
* //
|
|
69
|
-
* addMiddleware('
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* addMiddleware('api', [loggingMiddleware])
|
|
80
|
+
* // Also works: no tree-shaking
|
|
81
|
+
* export const apiMiddleware = addMiddleware('api', [
|
|
82
|
+
* rateLimitMiddleware
|
|
83
|
+
* ])
|
|
73
84
|
* ```
|
|
74
85
|
*/
|
|
75
86
|
export const addMiddleware = <PikkuMiddleware extends CorePikkuMiddleware>(
|
|
76
87
|
tag: string,
|
|
77
|
-
middleware:
|
|
78
|
-
) => {
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (middlewareStore[tag]) {
|
|
83
|
-
throw new Error(
|
|
84
|
-
`Middleware for tag '${tag}' already exists. Use a different tag or remove the existing middleware first.`
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
middlewareStore[tag] = middleware as CorePikkuMiddleware[]
|
|
88
|
+
middleware: CorePikkuMiddlewareGroup
|
|
89
|
+
): CorePikkuMiddlewareGroup => {
|
|
90
|
+
const tagGroups = pikkuState('middleware', 'tagGroup')
|
|
91
|
+
tagGroups[tag] = middleware
|
|
92
|
+
return middleware
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
/**
|
|
92
|
-
*
|
|
96
|
+
* Registers a single middleware function by name in the global middleware store.
|
|
93
97
|
*
|
|
94
|
-
* This function
|
|
95
|
-
*
|
|
98
|
+
* This function is used by CLI-generated code to register middleware functions
|
|
99
|
+
* that can be referenced by name in metadata. It stores middleware in a special
|
|
100
|
+
* namespace to avoid conflicts with tag-based middleware.
|
|
96
101
|
*
|
|
97
|
-
* @param {string
|
|
98
|
-
* @
|
|
102
|
+
* @param {string} name - The unique name (pikkuFuncName) of the middleware function.
|
|
103
|
+
* @param {CorePikkuMiddleware} middleware - The middleware function to register.
|
|
99
104
|
*
|
|
100
105
|
* @example
|
|
101
106
|
* ```typescript
|
|
102
|
-
* //
|
|
103
|
-
*
|
|
107
|
+
* // Called by CLI-generated pikku-middleware.gen.ts
|
|
108
|
+
* registerMiddleware('authMiddleware_src_middleware_ts_10_5', authMiddleware)
|
|
109
|
+
* registerMiddleware('loggingMiddleware_src_middleware_ts_20_10', loggingMiddleware)
|
|
104
110
|
* ```
|
|
105
111
|
*/
|
|
106
|
-
export const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return []
|
|
111
|
-
}
|
|
112
|
-
|
|
112
|
+
export const registerMiddleware = (
|
|
113
|
+
name: string,
|
|
114
|
+
middleware: CorePikkuMiddleware
|
|
115
|
+
) => {
|
|
113
116
|
const middlewareStore = pikkuState('misc', 'middleware')
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// Collect middleware for all matching tags
|
|
117
|
-
for (const tag of tags) {
|
|
118
|
-
const tagMiddleware = middlewareStore[tag]
|
|
119
|
-
if (tagMiddleware) {
|
|
120
|
-
applicableMiddleware.push(...tagMiddleware)
|
|
121
|
-
}
|
|
122
|
-
}
|
|
117
|
+
middlewareStore[name] = [middleware]
|
|
118
|
+
}
|
|
123
119
|
|
|
124
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Retrieves a registered middleware function by its name.
|
|
122
|
+
*
|
|
123
|
+
* This function looks up middleware that was registered with registerMiddleware.
|
|
124
|
+
* It's used internally by the framework to resolve middleware references in metadata.
|
|
125
|
+
*
|
|
126
|
+
* @param {string} name - The unique name (pikkuFuncName) of the middleware function.
|
|
127
|
+
* @returns {CorePikkuMiddleware | undefined} The middleware function, or undefined if not found.
|
|
128
|
+
*
|
|
129
|
+
* @internal
|
|
130
|
+
*/
|
|
131
|
+
export const getMiddlewareByName = (
|
|
132
|
+
name: string
|
|
133
|
+
): CorePikkuMiddleware | undefined => {
|
|
134
|
+
const middlewareStore = pikkuState('misc', 'middleware')
|
|
135
|
+
const middleware = middlewareStore[name]
|
|
136
|
+
return middleware?.[0]
|
|
125
137
|
}
|
|
126
138
|
|
|
127
139
|
const middlewareCache: Record<
|
|
@@ -134,28 +146,28 @@ const middlewareCache: Record<
|
|
|
134
146
|
[PikkuWiringTypes.queue]: {},
|
|
135
147
|
[PikkuWiringTypes.scheduler]: {},
|
|
136
148
|
[PikkuWiringTypes.mcp]: {},
|
|
149
|
+
[PikkuWiringTypes.cli]: {},
|
|
137
150
|
}
|
|
138
151
|
|
|
139
152
|
/**
|
|
140
|
-
* Combines
|
|
153
|
+
* Combines wiring-specific middleware with function-level middleware.
|
|
141
154
|
*
|
|
142
|
-
* This
|
|
143
|
-
*
|
|
155
|
+
* This function resolves middleware metadata into actual middleware functions and combines them.
|
|
156
|
+
* It filters out wire middleware without tags from inheritedMiddleware to avoid duplication
|
|
157
|
+
* (those are passed separately as wireMiddleware).
|
|
144
158
|
*
|
|
145
159
|
* @param {object} options - Configuration object for combining middleware.
|
|
146
|
-
* @param {
|
|
147
|
-
* @param {
|
|
148
|
-
* @param {
|
|
149
|
-
* @
|
|
150
|
-
* @returns {CorePikkuMiddleware[]} Combined array of tag-based and wiring-specific middleware.
|
|
160
|
+
* @param {MiddlewareMetadata[] | undefined} options.inheritedMiddleware - Metadata from wiring (HTTP + tags + wire with tags).
|
|
161
|
+
* @param {CorePikkuMiddleware[] | undefined} options.wireMiddleware - Inline wire middleware.
|
|
162
|
+
* @param {MiddlewareMetadata[] | undefined} options.funcMiddleware - Function middleware metadata.
|
|
163
|
+
* @returns {CorePikkuMiddleware[]} Combined array of resolved middleware.
|
|
151
164
|
*
|
|
152
165
|
* @example
|
|
153
166
|
* ```typescript
|
|
154
|
-
* const combined = combineMiddleware({
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* funcMiddleware:
|
|
158
|
-
* funcTags: funcConfig.tags
|
|
167
|
+
* const combined = combineMiddleware(wireType, wireId, {
|
|
168
|
+
* inheritedMiddleware: meta.middleware,
|
|
169
|
+
* wireMiddleware: [inlineMiddleware],
|
|
170
|
+
* funcMiddleware: funcMeta.middleware
|
|
159
171
|
* })
|
|
160
172
|
* ```
|
|
161
173
|
*/
|
|
@@ -163,38 +175,79 @@ export const combineMiddleware = (
|
|
|
163
175
|
wireType: PikkuWiringTypes,
|
|
164
176
|
uid: string,
|
|
165
177
|
{
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
178
|
+
wireInheritedMiddleware,
|
|
179
|
+
wireMiddleware,
|
|
180
|
+
funcInheritedMiddleware,
|
|
169
181
|
funcMiddleware,
|
|
170
|
-
funcTags,
|
|
171
182
|
}: {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
183
|
+
wireInheritedMiddleware?: MiddlewareMetadata[]
|
|
184
|
+
wireMiddleware?: CorePikkuMiddleware[]
|
|
185
|
+
funcInheritedMiddleware?: MiddlewareMetadata[]
|
|
175
186
|
funcMiddleware?: CorePikkuMiddleware[]
|
|
176
|
-
funcTags?: string[]
|
|
177
187
|
} = {}
|
|
178
188
|
): readonly CorePikkuMiddleware[] => {
|
|
179
189
|
if (middlewareCache[wireType][uid]) {
|
|
180
190
|
return middlewareCache[wireType][uid]
|
|
181
191
|
}
|
|
182
192
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
//
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
193
|
+
const resolved: CorePikkuMiddleware[] = []
|
|
194
|
+
|
|
195
|
+
// 1. Resolve wire inherited middleware (HTTP + tag groups + individual wire middleware)
|
|
196
|
+
if (wireInheritedMiddleware) {
|
|
197
|
+
for (const meta of wireInheritedMiddleware) {
|
|
198
|
+
if (meta.type === 'http') {
|
|
199
|
+
// Look up HTTP middleware group from pikkuState
|
|
200
|
+
const group = pikkuState('middleware', 'httpGroup')[meta.route]
|
|
201
|
+
if (group) {
|
|
202
|
+
// At runtime, all factories should be resolved to middleware
|
|
203
|
+
resolved.push(...(group as CorePikkuMiddleware[]))
|
|
204
|
+
}
|
|
205
|
+
} else if (meta.type === 'tag') {
|
|
206
|
+
// Look up tag middleware group from pikkuState
|
|
207
|
+
const group = pikkuState('middleware', 'tagGroup')[meta.tag]
|
|
208
|
+
if (group) {
|
|
209
|
+
// At runtime, all factories should be resolved to middleware
|
|
210
|
+
resolved.push(...(group as CorePikkuMiddleware[]))
|
|
211
|
+
}
|
|
212
|
+
} else if (meta.type === 'wire') {
|
|
213
|
+
// Individual wire middleware (exported, not inline)
|
|
214
|
+
const middleware = getMiddlewareByName(meta.name)
|
|
215
|
+
if (middleware) {
|
|
216
|
+
resolved.push(middleware)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// 2. Add inline wire middleware
|
|
223
|
+
if (wireMiddleware) {
|
|
224
|
+
resolved.push(...wireMiddleware)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// 3. Resolve function inherited middleware (only tags, wire middleware already handled)
|
|
228
|
+
if (funcInheritedMiddleware) {
|
|
229
|
+
for (const meta of funcInheritedMiddleware) {
|
|
230
|
+
if (meta.type === 'tag') {
|
|
231
|
+
// Look up tag middleware group from pikkuState
|
|
232
|
+
const group = pikkuState('middleware', 'tagGroup')[meta.tag]
|
|
233
|
+
if (group) {
|
|
234
|
+
// At runtime, all factories should be resolved to middleware
|
|
235
|
+
resolved.push(...(group as CorePikkuMiddleware[]))
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Note: wire middleware is already handled in wireInheritedMiddleware
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// 4. Add inline function middleware
|
|
243
|
+
if (funcMiddleware) {
|
|
244
|
+
resolved.push(...funcMiddleware)
|
|
245
|
+
}
|
|
190
246
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
...(funcMiddleware || []),
|
|
196
|
-
...funcTaggedMiddleware,
|
|
197
|
-
]) as readonly CorePikkuMiddleware[]
|
|
247
|
+
// Deduplicate and freeze
|
|
248
|
+
middlewareCache[wireType][uid] = freezeDedupe(
|
|
249
|
+
resolved
|
|
250
|
+
) as readonly CorePikkuMiddleware[]
|
|
198
251
|
|
|
199
252
|
return middlewareCache[wireType][uid]
|
|
200
253
|
}
|
package/src/permissions.ts
CHANGED
package/src/pikku-state.ts
CHANGED
|
@@ -4,7 +4,12 @@ import {
|
|
|
4
4
|
HTTPMethod,
|
|
5
5
|
HTTPWiringsMeta,
|
|
6
6
|
} from './wirings/http/http.types.js'
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
FunctionsMeta,
|
|
9
|
+
CorePikkuMiddleware,
|
|
10
|
+
CorePikkuMiddlewareGroup,
|
|
11
|
+
FunctionServicesMeta,
|
|
12
|
+
} from './types/core.types.js'
|
|
8
13
|
import {
|
|
9
14
|
CoreScheduledTask,
|
|
10
15
|
ScheduledTasksMeta,
|
|
@@ -27,6 +32,7 @@ import {
|
|
|
27
32
|
MCPToolMeta,
|
|
28
33
|
MCPPromptMeta,
|
|
29
34
|
} from './wirings/mcp/mcp.types.js'
|
|
35
|
+
import { CLIProgramMeta, CLIProgramState } from './wirings/cli/cli.types.js'
|
|
30
36
|
|
|
31
37
|
interface PikkuState {
|
|
32
38
|
function: {
|
|
@@ -69,6 +75,36 @@ interface PikkuState {
|
|
|
69
75
|
prompts: Map<string, CoreMCPPrompt>
|
|
70
76
|
promptsMeta: MCPPromptMeta
|
|
71
77
|
}
|
|
78
|
+
cli: {
|
|
79
|
+
meta: Record<string, CLIProgramMeta>
|
|
80
|
+
programs: Record<string, CLIProgramState>
|
|
81
|
+
}
|
|
82
|
+
middleware: {
|
|
83
|
+
tagGroup: Record<string, CorePikkuMiddlewareGroup>
|
|
84
|
+
httpGroup: Record<string, CorePikkuMiddlewareGroup>
|
|
85
|
+
tagGroupMeta: Record<
|
|
86
|
+
string,
|
|
87
|
+
{
|
|
88
|
+
exportName: string | null
|
|
89
|
+
sourceFile: string
|
|
90
|
+
position: number
|
|
91
|
+
services: FunctionServicesMeta
|
|
92
|
+
middlewareCount: number
|
|
93
|
+
isFactory: boolean
|
|
94
|
+
}
|
|
95
|
+
>
|
|
96
|
+
httpGroupMeta: Record<
|
|
97
|
+
string,
|
|
98
|
+
{
|
|
99
|
+
exportName: string | null
|
|
100
|
+
sourceFile: string
|
|
101
|
+
position: number
|
|
102
|
+
services: FunctionServicesMeta
|
|
103
|
+
middlewareCount: number
|
|
104
|
+
isFactory: boolean
|
|
105
|
+
}
|
|
106
|
+
>
|
|
107
|
+
}
|
|
72
108
|
misc: {
|
|
73
109
|
errors: Map<PikkuError, ErrorDetails>
|
|
74
110
|
schemas: Map<string, any>
|
|
@@ -89,7 +125,6 @@ export const resetPikkuState = () => {
|
|
|
89
125
|
},
|
|
90
126
|
http: {
|
|
91
127
|
permissions: new Map(),
|
|
92
|
-
middleware: new Map(),
|
|
93
128
|
routes: new Map(),
|
|
94
129
|
meta: {},
|
|
95
130
|
},
|
|
@@ -113,6 +148,16 @@ export const resetPikkuState = () => {
|
|
|
113
148
|
prompts: new Map(),
|
|
114
149
|
promptsMeta: {} as MCPPromptMeta,
|
|
115
150
|
},
|
|
151
|
+
cli: {
|
|
152
|
+
meta: {},
|
|
153
|
+
programs: {},
|
|
154
|
+
},
|
|
155
|
+
middleware: {
|
|
156
|
+
tagGroup: {},
|
|
157
|
+
httpGroup: {},
|
|
158
|
+
tagGroupMeta: {},
|
|
159
|
+
httpGroupMeta: {},
|
|
160
|
+
},
|
|
116
161
|
misc: {
|
|
117
162
|
errors: globalThis.pikkuState?.misc?.errors || new Map(),
|
|
118
163
|
schemas: new Map(),
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { ReadStream } from 'fs'
|
|
2
|
-
|
|
3
1
|
export interface ContentService {
|
|
4
2
|
/**
|
|
5
3
|
* Signs a content key to generate a secure, time-limited access URL.
|
|
@@ -49,7 +47,10 @@ export interface ContentService {
|
|
|
49
47
|
* @param stream - A readable stream of the file contents.
|
|
50
48
|
* @returns A boolean indicating success.
|
|
51
49
|
*/
|
|
52
|
-
writeFile(
|
|
50
|
+
writeFile(
|
|
51
|
+
assetKey: string,
|
|
52
|
+
stream: ReadableStream | NodeJS.ReadableStream
|
|
53
|
+
): Promise<boolean>
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
56
|
* Copies a file from a local absolute path into storage under a new asset key.
|
|
@@ -64,5 +65,5 @@ export interface ContentService {
|
|
|
64
65
|
* @param assetKey - The key of the file to read.
|
|
65
66
|
* @returns A readable file stream.
|
|
66
67
|
*/
|
|
67
|
-
readFile(assetKey: string): Promise<
|
|
68
|
+
readFile(assetKey: string): Promise<ReadableStream | NodeJS.ReadableStream>
|
|
68
69
|
}
|
package/src/services/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createReadStream, createWriteStream, promises
|
|
1
|
+
import { createReadStream, createWriteStream, promises } from 'fs'
|
|
2
2
|
import { mkdir } from 'fs/promises'
|
|
3
3
|
import { ContentService, Logger } from '@pikku/core/services'
|
|
4
4
|
import { pipeline } from 'stream/promises'
|
|
@@ -38,7 +38,10 @@ export class LocalContent implements ContentService {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
public async writeFile(
|
|
41
|
+
public async writeFile(
|
|
42
|
+
assetKey: string,
|
|
43
|
+
stream: ReadableStream | NodeJS.ReadableStream
|
|
44
|
+
): Promise<boolean> {
|
|
42
45
|
this.logger.debug(`Writing file: ${assetKey}`)
|
|
43
46
|
|
|
44
47
|
const path = `${this.config.localFileUploadPath}/${assetKey}`
|
|
@@ -47,7 +50,7 @@ export class LocalContent implements ContentService {
|
|
|
47
50
|
await this.createDirectoryForFile(path)
|
|
48
51
|
const fileStream = createWriteStream(path)
|
|
49
52
|
// Use pipeline to properly manage stream piping and errors
|
|
50
|
-
await pipeline(stream, fileStream)
|
|
53
|
+
await pipeline(stream as Readable, fileStream)
|
|
51
54
|
return true
|
|
52
55
|
} catch (e) {
|
|
53
56
|
console.error(e)
|
|
@@ -72,7 +75,9 @@ export class LocalContent implements ContentService {
|
|
|
72
75
|
return false
|
|
73
76
|
}
|
|
74
77
|
|
|
75
|
-
public async readFile(
|
|
78
|
+
public async readFile(
|
|
79
|
+
assetKey: string
|
|
80
|
+
): Promise<ReadableStream | NodeJS.ReadableStream> {
|
|
76
81
|
this.logger.debug(`Getting key: ${assetKey}`)
|
|
77
82
|
|
|
78
83
|
const filePath = `${this.config.localFileUploadPath}/${assetKey}`
|
package/src/types/core.types.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { PikkuRPC } from '../wirings/rpc/rpc-types.js'
|
|
|
8
8
|
import { PikkuMCP } from '../wirings/mcp/mcp.types.js'
|
|
9
9
|
import { PikkuScheduledTask } from '../wirings/scheduler/scheduler.types.js'
|
|
10
10
|
import { PikkuQueue } from '../wirings/queue/queue.types.js'
|
|
11
|
+
import { PikkuCLI } from '../wirings/cli/cli.types.js'
|
|
11
12
|
|
|
12
13
|
export enum PikkuWiringTypes {
|
|
13
14
|
http = 'http',
|
|
@@ -16,6 +17,7 @@ export enum PikkuWiringTypes {
|
|
|
16
17
|
rpc = 'rpc',
|
|
17
18
|
queue = 'queue',
|
|
18
19
|
mcp = 'mcp',
|
|
20
|
+
cli = 'cli',
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
export interface FunctionServicesMeta {
|
|
@@ -23,6 +25,27 @@ export interface FunctionServicesMeta {
|
|
|
23
25
|
services: string[]
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Metadata for middleware at any level
|
|
30
|
+
* - type: 'http' = HTTP route middleware group (references httpGroup in pikkuState)
|
|
31
|
+
* - type: 'tag' = Tag-based middleware group (references tagGroup in pikkuState)
|
|
32
|
+
* - type: 'wire' = Wire-level individual middleware
|
|
33
|
+
*/
|
|
34
|
+
export type MiddlewareMetadata =
|
|
35
|
+
| {
|
|
36
|
+
type: 'http'
|
|
37
|
+
route: string // Route pattern (e.g., '*' for all, '/api/*' for specific)
|
|
38
|
+
}
|
|
39
|
+
| {
|
|
40
|
+
type: 'tag'
|
|
41
|
+
tag: string // Tag name
|
|
42
|
+
}
|
|
43
|
+
| {
|
|
44
|
+
type: 'wire'
|
|
45
|
+
name: string
|
|
46
|
+
inline?: boolean // true if inline middleware
|
|
47
|
+
}
|
|
48
|
+
|
|
26
49
|
export type FunctionRuntimeMeta = {
|
|
27
50
|
pikkuFuncName: string
|
|
28
51
|
inputSchemaName: string | null
|
|
@@ -39,6 +62,7 @@ export type FunctionMeta = FunctionRuntimeMeta &
|
|
|
39
62
|
tags: string[]
|
|
40
63
|
docs: PikkuDocs
|
|
41
64
|
isDirectFunction: boolean // true if it's pikkuFunc(fn), false if it's pikkuFunc({ func: fn })
|
|
65
|
+
middleware: MiddlewareMetadata[] // Function-level middleware (type will be undefined)
|
|
42
66
|
}>
|
|
43
67
|
|
|
44
68
|
export type FunctionsRuntimeMeta = Record<string, FunctionRuntimeMeta>
|
|
@@ -121,6 +145,7 @@ export type PikkuInteraction<In = unknown, Out = unknown> = Partial<{
|
|
|
121
145
|
channel: PikkuChannel<unknown, Out>
|
|
122
146
|
scheduledTask: PikkuScheduledTask
|
|
123
147
|
queue: PikkuQueue
|
|
148
|
+
cli: PikkuCLI
|
|
124
149
|
}>
|
|
125
150
|
|
|
126
151
|
/**
|
|
@@ -137,6 +162,28 @@ export type CorePikkuMiddleware<
|
|
|
137
162
|
next: () => Promise<void>
|
|
138
163
|
) => Promise<void>
|
|
139
164
|
|
|
165
|
+
/**
|
|
166
|
+
* A factory function that takes input and returns middleware
|
|
167
|
+
* Used when middleware needs configuration/input parameters
|
|
168
|
+
*/
|
|
169
|
+
export type CorePikkuMiddlewareFactory<
|
|
170
|
+
In = any,
|
|
171
|
+
SingletonServices extends CoreSingletonServices = CoreSingletonServices,
|
|
172
|
+
UserSession extends CoreUserSession = CoreUserSession,
|
|
173
|
+
> = (input: In) => CorePikkuMiddleware<SingletonServices, UserSession>
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* A group of middleware (combination of regular middleware and factories)
|
|
177
|
+
* Used with addMiddleware() and addHTTPMiddleware() to group related middleware together
|
|
178
|
+
*/
|
|
179
|
+
export type CorePikkuMiddlewareGroup<
|
|
180
|
+
SingletonServices extends CoreSingletonServices = CoreSingletonServices,
|
|
181
|
+
UserSession extends CoreUserSession = CoreUserSession,
|
|
182
|
+
> = Array<
|
|
183
|
+
| CorePikkuMiddleware<SingletonServices, UserSession>
|
|
184
|
+
| CorePikkuMiddlewareFactory<any, SingletonServices, UserSession>
|
|
185
|
+
>
|
|
186
|
+
|
|
140
187
|
/**
|
|
141
188
|
* Factory function for creating middleware with tree-shaking support
|
|
142
189
|
*/
|
|
@@ -149,6 +196,29 @@ export const pikkuMiddleware = <
|
|
|
149
196
|
return middleware
|
|
150
197
|
}
|
|
151
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Factory function for creating middleware factories
|
|
201
|
+
* Use this when your middleware needs configuration/input parameters
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```typescript
|
|
205
|
+
* export const logMiddleware = pikkuMiddlewareFactory<LogOptions>(({
|
|
206
|
+
* message,
|
|
207
|
+
* level = 'info'
|
|
208
|
+
* }) => {
|
|
209
|
+
* return pikkuMiddleware(async ({ logger }, _interaction, next) => {
|
|
210
|
+
* logger[level](message)
|
|
211
|
+
* await next()
|
|
212
|
+
* })
|
|
213
|
+
* })
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
export const pikkuMiddlewareFactory = <In = any>(
|
|
217
|
+
factory: CorePikkuMiddlewareFactory<In>
|
|
218
|
+
): CorePikkuMiddlewareFactory<In> => {
|
|
219
|
+
return factory
|
|
220
|
+
}
|
|
221
|
+
|
|
152
222
|
/**
|
|
153
223
|
* Represents the core services used by Pikku, including singleton services and the request/response interaction.
|
|
154
224
|
*/
|
|
@@ -193,9 +263,10 @@ export type CreateSessionServices<
|
|
|
193
263
|
/**
|
|
194
264
|
* Defines a function type for creating config.
|
|
195
265
|
*/
|
|
196
|
-
export type CreateConfig<
|
|
197
|
-
|
|
198
|
-
|
|
266
|
+
export type CreateConfig<
|
|
267
|
+
Config extends CoreConfig,
|
|
268
|
+
RemainingArgs extends any[] = unknown[],
|
|
269
|
+
> = (variables?: VariablesService, ...args: RemainingArgs) => Promise<Config>
|
|
199
270
|
|
|
200
271
|
/**
|
|
201
272
|
* Represents the documentation for a route, including summary, description, tags, and errors.
|
|
@@ -61,7 +61,6 @@ const validateAuth = (
|
|
|
61
61
|
|
|
62
62
|
export const processMessageHandlers = (
|
|
63
63
|
services: CoreServices,
|
|
64
|
-
session: CoreUserSession | undefined,
|
|
65
64
|
channelConfig: CoreChannel<any, any>,
|
|
66
65
|
channelHandler: PikkuChannelHandler
|
|
67
66
|
) => {
|
|
@@ -71,7 +70,6 @@ export const processMessageHandlers = (
|
|
|
71
70
|
const processMessage = async (
|
|
72
71
|
data: JSONValue,
|
|
73
72
|
onMessage: any,
|
|
74
|
-
session: CoreUserSession | undefined,
|
|
75
73
|
routingProperty?: string,
|
|
76
74
|
routerValue?: string
|
|
77
75
|
): Promise<unknown> => {
|
|
@@ -87,7 +85,7 @@ export const processMessageHandlers = (
|
|
|
87
85
|
return
|
|
88
86
|
}
|
|
89
87
|
|
|
90
|
-
const { pikkuFuncName } = getRouteMeta(
|
|
88
|
+
const { pikkuFuncName, middleware: inheritedMiddleware } = getRouteMeta(
|
|
91
89
|
channelConfig.name,
|
|
92
90
|
routingProperty,
|
|
93
91
|
routerValue
|
|
@@ -104,15 +102,18 @@ export const processMessageHandlers = (
|
|
|
104
102
|
channelConfig.name,
|
|
105
103
|
pikkuFuncName,
|
|
106
104
|
{
|
|
105
|
+
singletonServices: services,
|
|
107
106
|
getAllServices: () => ({
|
|
108
107
|
...services,
|
|
109
108
|
channel: channelHandler.getChannel(),
|
|
110
109
|
}),
|
|
111
|
-
data,
|
|
112
|
-
|
|
110
|
+
data: () => data,
|
|
111
|
+
userSession: services.userSession,
|
|
113
112
|
permissions,
|
|
114
|
-
|
|
113
|
+
inheritedMiddleware,
|
|
114
|
+
wireMiddleware: middleware,
|
|
115
115
|
tags: channelConfig.tags,
|
|
116
|
+
interaction: { channel: channelHandler.getChannel() },
|
|
116
117
|
}
|
|
117
118
|
)
|
|
118
119
|
}
|
|
@@ -133,7 +134,6 @@ export const processMessageHandlers = (
|
|
|
133
134
|
result = await processMessage(
|
|
134
135
|
messageData,
|
|
135
136
|
routes[routerValue],
|
|
136
|
-
session,
|
|
137
137
|
routingProperty,
|
|
138
138
|
routerValue
|
|
139
139
|
)
|
|
@@ -144,11 +144,7 @@ export const processMessageHandlers = (
|
|
|
144
144
|
// Default handler if no routes matched but json data was parsed
|
|
145
145
|
if (!processed && channelConfig.onMessage) {
|
|
146
146
|
processed = true
|
|
147
|
-
result = await processMessage(
|
|
148
|
-
messageData,
|
|
149
|
-
channelConfig.onMessage,
|
|
150
|
-
session
|
|
151
|
-
)
|
|
147
|
+
result = await processMessage(messageData, channelConfig.onMessage)
|
|
152
148
|
}
|
|
153
149
|
} catch (error) {
|
|
154
150
|
// Most likely a json error.. ignore
|
|
@@ -158,7 +154,7 @@ export const processMessageHandlers = (
|
|
|
158
154
|
// Default handler if no routes matched and json data wasn't parsed
|
|
159
155
|
if (!processed && channelConfig.onMessage) {
|
|
160
156
|
processed = true
|
|
161
|
-
result = await processMessage(rawData, channelConfig.onMessage
|
|
157
|
+
result = await processMessage(rawData, channelConfig.onMessage)
|
|
162
158
|
}
|
|
163
159
|
|
|
164
160
|
if (!processed) {
|