@pikku/core 0.11.1 → 0.11.2
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 +24 -0
- package/dist/errors/error-handler.js +3 -3
- package/dist/function/function-runner.d.ts +4 -3
- package/dist/function/function-runner.js +60 -14
- package/dist/function/functions.types.d.ts +84 -5
- package/dist/function/functions.types.js +41 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +5 -2
- package/dist/middleware/auth-apikey.d.ts +1 -1
- package/dist/middleware/auth-bearer.d.ts +1 -1
- package/dist/middleware/auth-cookie.d.ts +1 -1
- package/dist/middleware/timeout.d.ts +1 -1
- package/dist/middleware-runner.d.ts +3 -14
- package/dist/middleware-runner.js +8 -8
- package/dist/permissions.d.ts +3 -86
- package/dist/permissions.js +11 -67
- package/dist/pikku-state.d.ts +32 -104
- package/dist/pikku-state.js +140 -66
- package/dist/schema.d.ts +8 -6
- package/dist/schema.js +25 -13
- package/dist/services/workflow-service.d.ts +38 -0
- package/dist/services/workflow-service.js +1 -0
- package/dist/types/core.types.d.ts +12 -4
- package/dist/types/core.types.js +1 -1
- package/dist/types/state.types.d.ts +135 -0
- package/dist/types/state.types.js +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.js +45 -0
- package/dist/wirings/channel/channel-handler.js +1 -1
- package/dist/wirings/channel/channel-runner.js +5 -5
- package/dist/wirings/channel/log-channels.js +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -2
- package/dist/wirings/cli/channel/cli-channel-runner.js +3 -2
- package/dist/wirings/cli/cli-runner.js +10 -10
- package/dist/wirings/cli/cli.types.d.ts +1 -0
- package/dist/wirings/forge-node/forge-node.types.d.ts +120 -0
- package/dist/wirings/forge-node/forge-node.types.js +38 -0
- package/dist/wirings/forge-node/index.d.ts +1 -0
- package/dist/wirings/forge-node/index.js +1 -0
- package/dist/wirings/http/http-runner.d.ts +2 -2
- package/dist/wirings/http/http-runner.js +21 -12
- package/dist/wirings/http/http.types.d.ts +14 -1
- package/dist/wirings/http/log-http-routes.js +1 -1
- package/dist/wirings/http/routers/path-to-regex.js +2 -2
- package/dist/wirings/mcp/mcp-runner.js +21 -21
- package/dist/wirings/queue/queue-runner.js +6 -6
- 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 +7 -8
- package/dist/wirings/rpc/rpc-runner.js +62 -14
- package/dist/wirings/rpc/rpc-types.d.ts +7 -0
- package/dist/wirings/scheduler/log-schedulers.js +1 -1
- package/dist/wirings/scheduler/scheduler-runner.js +5 -5
- package/dist/wirings/trigger/index.d.ts +2 -0
- package/dist/wirings/trigger/index.js +2 -0
- package/dist/wirings/trigger/trigger-runner.d.ts +29 -0
- package/dist/wirings/trigger/trigger-runner.js +57 -0
- package/dist/wirings/trigger/trigger.types.d.ts +42 -0
- package/dist/wirings/trigger/trigger.types.js +1 -0
- package/dist/wirings/workflow/dsl/index.d.ts +5 -0
- package/dist/wirings/workflow/dsl/index.js +4 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +286 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.js +5 -0
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +5 -0
- package/dist/wirings/workflow/dsl/workflow-runner.js +22 -0
- package/dist/wirings/workflow/graph/graph-node.d.ts +122 -0
- package/dist/wirings/workflow/graph/graph-node.js +58 -0
- package/dist/wirings/workflow/graph/graph-runner.d.ts +35 -0
- package/dist/wirings/workflow/graph/graph-runner.js +452 -0
- package/dist/wirings/workflow/graph/index.d.ts +3 -0
- package/dist/wirings/workflow/graph/index.js +3 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +95 -0
- package/dist/wirings/workflow/graph/workflow-graph.types.js +15 -0
- package/dist/wirings/workflow/index.d.ts +7 -12
- package/dist/wirings/workflow/index.js +6 -11
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +96 -6
- package/dist/wirings/workflow/pikku-workflow-service.js +230 -103
- package/dist/wirings/workflow/wire-workflow.d.ts +42 -0
- package/dist/wirings/workflow/wire-workflow.js +53 -0
- package/dist/wirings/workflow/workflow-utils.d.ts +23 -0
- package/dist/wirings/workflow/workflow-utils.js +66 -0
- package/dist/wirings/workflow/workflow.types.d.ts +133 -211
- package/package.json +10 -1
- package/src/errors/error-handler.ts +3 -3
- package/src/function/function-runner.test.ts +1 -1
- package/src/function/function-runner.ts +86 -16
- package/src/function/functions.types.ts +126 -4
- package/src/index.ts +10 -5
- package/src/middleware-runner.ts +16 -9
- package/src/permissions.test.ts +28 -86
- package/src/permissions.ts +21 -80
- package/src/pikku-state.ts +156 -201
- package/src/schema.ts +42 -13
- package/src/services/workflow-service.ts +74 -0
- package/src/types/core.types.ts +12 -3
- package/src/types/state.types.ts +195 -0
- package/src/utils.ts +55 -0
- package/src/wirings/channel/channel-handler.ts +1 -1
- package/src/wirings/channel/channel-runner.ts +5 -5
- package/src/wirings/channel/local/local-channel-runner.test.ts +3 -1
- package/src/wirings/channel/log-channels.ts +1 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -2
- package/src/wirings/cli/channel/cli-channel-runner.ts +4 -3
- package/src/wirings/cli/cli-runner.test.ts +19 -19
- package/src/wirings/cli/cli-runner.ts +10 -9
- package/src/wirings/cli/cli.types.ts +1 -0
- package/src/wirings/forge-node/forge-node.types.ts +135 -0
- package/src/wirings/forge-node/index.ts +1 -0
- package/src/wirings/http/http-runner.test.ts +2 -2
- package/src/wirings/http/http-runner.ts +30 -13
- package/src/wirings/http/http.types.ts +14 -0
- package/src/wirings/http/log-http-routes.ts +1 -1
- package/src/wirings/http/routers/path-to-regex.test.ts +30 -19
- package/src/wirings/http/routers/path-to-regex.ts +2 -2
- package/src/wirings/mcp/mcp-runner.ts +21 -21
- package/src/wirings/queue/queue-runner.test.ts +19 -19
- package/src/wirings/queue/queue-runner.ts +6 -6
- package/src/wirings/rpc/index.ts +1 -1
- package/src/wirings/rpc/rpc-runner.ts +88 -22
- package/src/wirings/rpc/rpc-types.ts +8 -0
- package/src/wirings/scheduler/log-schedulers.ts +1 -1
- package/src/wirings/scheduler/scheduler-runner.test.ts +27 -27
- package/src/wirings/scheduler/scheduler-runner.ts +5 -5
- package/src/wirings/trigger/index.ts +2 -0
- package/src/wirings/trigger/trigger-runner.ts +96 -0
- package/src/wirings/trigger/trigger.types.ts +56 -0
- package/src/wirings/workflow/dsl/index.ts +30 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +312 -0
- package/src/wirings/workflow/dsl/workflow-runner.ts +27 -0
- package/src/wirings/workflow/graph/graph-node.ts +227 -0
- package/src/wirings/workflow/graph/graph-runner.ts +694 -0
- package/src/wirings/workflow/graph/index.ts +3 -0
- package/src/wirings/workflow/graph/workflow-graph.types.ts +126 -0
- package/src/wirings/workflow/index.ts +53 -26
- package/src/wirings/workflow/pikku-workflow-service.ts +333 -117
- package/src/wirings/workflow/wire-workflow.ts +94 -0
- package/src/wirings/workflow/workflow-utils.ts +120 -0
- package/src/wirings/workflow/workflow.types.ts +166 -277
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/wirings/workflow/workflow-runner.d.ts +0 -34
- package/dist/wirings/workflow/workflow-runner.js +0 -65
- package/src/function/function-runner.ts.bak +0 -188
- package/src/wirings/workflow/workflow-runner.ts +0 -72
package/src/permissions.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { freezeDedupe } from './utils.js'
|
|
|
19
19
|
* @param wire - The wire object containing request/response context and session.
|
|
20
20
|
* @returns A promise that resolves to void.
|
|
21
21
|
*/
|
|
22
|
-
|
|
22
|
+
const verifyPermissions = async <Out = any>(
|
|
23
23
|
permissions: CorePermissionGroup,
|
|
24
24
|
services: CoreServices,
|
|
25
25
|
data: any,
|
|
@@ -53,31 +53,6 @@ export const verifyPermissions = async <Out = any>(
|
|
|
53
53
|
return false
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
/**
|
|
57
|
-
* Registers a single permission function by name in the global permission store.
|
|
58
|
-
*
|
|
59
|
-
* This function is used by CLI-generated code to register permission functions
|
|
60
|
-
* that can be referenced by name in metadata. It stores permissions in a special
|
|
61
|
-
* namespace to avoid conflicts with tag-based permissions.
|
|
62
|
-
*
|
|
63
|
-
* @param {string} name - The unique name (pikkuFuncName) of the permission function.
|
|
64
|
-
* @param {CorePikkuPermission} permission - The permission function to register.
|
|
65
|
-
*
|
|
66
|
-
* @example
|
|
67
|
-
* ```typescript
|
|
68
|
-
* // Called by CLI-generated pikku-permissions.gen.ts
|
|
69
|
-
* registerPermission('adminPermission_src_permissions_ts_10_5', adminPermission)
|
|
70
|
-
* registerPermission('readPermission_src_permissions_ts_20_10', readPermission)
|
|
71
|
-
* ```
|
|
72
|
-
*/
|
|
73
|
-
export const registerPermission = (
|
|
74
|
-
name: string,
|
|
75
|
-
permission: CorePikkuPermission<any>
|
|
76
|
-
) => {
|
|
77
|
-
const permissionStore = pikkuState('misc', 'permissions')
|
|
78
|
-
permissionStore[name] = [permission]
|
|
79
|
-
}
|
|
80
|
-
|
|
81
56
|
/**
|
|
82
57
|
* Retrieves a registered permission function by its name.
|
|
83
58
|
*
|
|
@@ -89,10 +64,8 @@ export const registerPermission = (
|
|
|
89
64
|
*
|
|
90
65
|
* @internal
|
|
91
66
|
*/
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
): CorePikkuPermission | undefined => {
|
|
95
|
-
const permissionStore = pikkuState('misc', 'permissions')
|
|
67
|
+
const getPermissionByName = (name: string): CorePikkuPermission | undefined => {
|
|
68
|
+
const permissionStore = pikkuState(null, 'misc', 'permissions')
|
|
96
69
|
const permission = permissionStore[name]
|
|
97
70
|
if (Array.isArray(permission) && permission.length === 1) {
|
|
98
71
|
return permission[0]
|
|
@@ -130,9 +103,10 @@ export const getPermissionByName = (
|
|
|
130
103
|
*/
|
|
131
104
|
export const addPermission = (
|
|
132
105
|
tag: string,
|
|
133
|
-
permissions: CorePermissionGroup | CorePikkuPermission[]
|
|
106
|
+
permissions: CorePermissionGroup | CorePikkuPermission[],
|
|
107
|
+
packageName: string | null = null
|
|
134
108
|
): CorePermissionGroup | CorePikkuPermission[] => {
|
|
135
|
-
const tagGroups = pikkuState('permissions', 'tagGroup')
|
|
109
|
+
const tagGroups = pikkuState(packageName, 'permissions', 'tagGroup')
|
|
136
110
|
if (tagGroups[tag]) {
|
|
137
111
|
throw new Error(
|
|
138
112
|
`Permissions for tag '${tag}' already exist. Use a different tag or remove the existing permissions first.`
|
|
@@ -142,50 +116,6 @@ export const addPermission = (
|
|
|
142
116
|
return permissions
|
|
143
117
|
}
|
|
144
118
|
|
|
145
|
-
const EMPTY: readonly (CorePermissionGroup | CorePikkuPermission)[] = []
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Retrieves permissions for a given set of tags.
|
|
149
|
-
*
|
|
150
|
-
* This function looks up all permissions registered for any of the provided tags
|
|
151
|
-
* and returns them as a flattened array.
|
|
152
|
-
*
|
|
153
|
-
* @param {string[]} tags - Array of tags to look up permissions for.
|
|
154
|
-
* @returns {any[]} Array of permission functions that apply to the given tags.
|
|
155
|
-
*
|
|
156
|
-
* @example
|
|
157
|
-
* ```typescript
|
|
158
|
-
* // Get all permissions for tags 'api' and 'auth'
|
|
159
|
-
* const permissions = getPermissionsForTags(['api', 'auth'])
|
|
160
|
-
* ```
|
|
161
|
-
*/
|
|
162
|
-
export const getPermissionsForTags = (
|
|
163
|
-
tags?: string[]
|
|
164
|
-
): readonly (CorePermissionGroup | CorePikkuPermission)[] => {
|
|
165
|
-
if (!tags || tags.length === 0) {
|
|
166
|
-
return EMPTY
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const permissionsStore = pikkuState('permissions', 'tagGroup')
|
|
170
|
-
const applicablePermissions: Array<
|
|
171
|
-
CorePermissionGroup | CorePikkuPermission
|
|
172
|
-
> = []
|
|
173
|
-
|
|
174
|
-
// Collect permissions for all matching tags
|
|
175
|
-
for (const tag of new Set(tags)) {
|
|
176
|
-
const tagPermissions = permissionsStore[tag]
|
|
177
|
-
if (tagPermissions) {
|
|
178
|
-
if (Array.isArray(tagPermissions)) {
|
|
179
|
-
applicablePermissions.push(...tagPermissions)
|
|
180
|
-
} else {
|
|
181
|
-
applicablePermissions.push(tagPermissions)
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return applicablePermissions
|
|
187
|
-
}
|
|
188
|
-
|
|
189
119
|
const combinedPermissionsCache: Record<
|
|
190
120
|
PikkuWiringTypes,
|
|
191
121
|
Record<string, readonly (CorePermissionGroup | CorePikkuPermission)[]>
|
|
@@ -224,7 +154,7 @@ const combinedPermissionsCache: Record<
|
|
|
224
154
|
* })
|
|
225
155
|
* ```
|
|
226
156
|
*/
|
|
227
|
-
|
|
157
|
+
const combinePermissions = (
|
|
228
158
|
wireType: PikkuWiringTypes,
|
|
229
159
|
uid: string,
|
|
230
160
|
{
|
|
@@ -232,11 +162,13 @@ export const combinePermissions = (
|
|
|
232
162
|
wirePermissions,
|
|
233
163
|
funcInheritedPermissions,
|
|
234
164
|
funcPermissions,
|
|
165
|
+
packageName = null,
|
|
235
166
|
}: {
|
|
236
167
|
wireInheritedPermissions?: PermissionMetadata[]
|
|
237
168
|
wirePermissions?: CorePermissionGroup | CorePikkuPermission[]
|
|
238
169
|
funcInheritedPermissions?: PermissionMetadata[]
|
|
239
170
|
funcPermissions?: CorePermissionGroup | CorePikkuPermission[]
|
|
171
|
+
packageName?: string | null
|
|
240
172
|
} = {}
|
|
241
173
|
): readonly (CorePermissionGroup | CorePikkuPermission)[] => {
|
|
242
174
|
if (combinedPermissionsCache[wireType][uid]) {
|
|
@@ -250,7 +182,9 @@ export const combinePermissions = (
|
|
|
250
182
|
for (const meta of wireInheritedPermissions) {
|
|
251
183
|
if (meta.type === 'http') {
|
|
252
184
|
// Look up HTTP permission group from pikkuState
|
|
253
|
-
const group = pikkuState('permissions', 'httpGroup')[
|
|
185
|
+
const group = pikkuState(packageName, 'permissions', 'httpGroup')[
|
|
186
|
+
meta.route
|
|
187
|
+
]
|
|
254
188
|
if (group) {
|
|
255
189
|
if (Array.isArray(group)) {
|
|
256
190
|
resolved.push(...group)
|
|
@@ -260,7 +194,9 @@ export const combinePermissions = (
|
|
|
260
194
|
}
|
|
261
195
|
} else if (meta.type === 'tag') {
|
|
262
196
|
// Look up tag permission group from pikkuState
|
|
263
|
-
const group = pikkuState('permissions', 'tagGroup')[
|
|
197
|
+
const group = pikkuState(packageName, 'permissions', 'tagGroup')[
|
|
198
|
+
meta.tag
|
|
199
|
+
]
|
|
264
200
|
if (group) {
|
|
265
201
|
if (Array.isArray(group)) {
|
|
266
202
|
resolved.push(...group)
|
|
@@ -292,7 +228,9 @@ export const combinePermissions = (
|
|
|
292
228
|
for (const meta of funcInheritedPermissions) {
|
|
293
229
|
if (meta.type === 'tag') {
|
|
294
230
|
// Look up tag permission group from pikkuState
|
|
295
|
-
const group = pikkuState('permissions', 'tagGroup')[
|
|
231
|
+
const group = pikkuState(packageName, 'permissions', 'tagGroup')[
|
|
232
|
+
meta.tag
|
|
233
|
+
]
|
|
296
234
|
if (group) {
|
|
297
235
|
if (Array.isArray(group)) {
|
|
298
236
|
resolved.push(...group)
|
|
@@ -338,6 +276,7 @@ export const runPermissions = async (
|
|
|
338
276
|
services,
|
|
339
277
|
wire,
|
|
340
278
|
data,
|
|
279
|
+
packageName = null,
|
|
341
280
|
}: {
|
|
342
281
|
wireInheritedPermissions?: PermissionMetadata[]
|
|
343
282
|
wirePermissions?: CorePermissionGroup | CorePikkuPermission[]
|
|
@@ -346,6 +285,7 @@ export const runPermissions = async (
|
|
|
346
285
|
services: CoreServices
|
|
347
286
|
wire: PikkuWire<any, never, any, never, never, never>
|
|
348
287
|
data: any
|
|
288
|
+
packageName?: string | null
|
|
349
289
|
}
|
|
350
290
|
) => {
|
|
351
291
|
// Combine all permissions: wireInheritedPermissions → wirePermissions → funcInheritedPermissions → funcPermissions
|
|
@@ -354,6 +294,7 @@ export const runPermissions = async (
|
|
|
354
294
|
wirePermissions,
|
|
355
295
|
funcInheritedPermissions,
|
|
356
296
|
funcPermissions,
|
|
297
|
+
packageName,
|
|
357
298
|
})
|
|
358
299
|
|
|
359
300
|
// Check all combined permissions - at least one must pass if any exist
|
package/src/pikku-state.ts
CHANGED
|
@@ -1,230 +1,185 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PikkuPackageState } from './index.js'
|
|
2
|
+
import { HTTPWiringsMeta } from './wirings/http/http.types.js'
|
|
2
3
|
import {
|
|
3
|
-
CoreHTTPFunctionWiring,
|
|
4
|
-
HTTPMethod,
|
|
5
|
-
HTTPWiringsMeta,
|
|
6
|
-
} from './wirings/http/http.types.js'
|
|
7
|
-
import {
|
|
8
|
-
FunctionsMeta,
|
|
9
|
-
CorePikkuMiddleware,
|
|
10
|
-
CorePikkuMiddlewareGroup,
|
|
11
|
-
FunctionServicesMeta,
|
|
12
|
-
} from './types/core.types.js'
|
|
13
|
-
import {
|
|
14
|
-
CoreScheduledTask,
|
|
15
|
-
ScheduledTasksMeta,
|
|
16
|
-
} from './wirings/scheduler/scheduler.types.js'
|
|
17
|
-
import { ErrorDetails, PikkuError } from './errors/error-handler.js'
|
|
18
|
-
import {
|
|
19
|
-
CorePermissionGroup,
|
|
20
|
-
CorePikkuFunctionConfig,
|
|
21
|
-
CorePikkuPermission,
|
|
22
|
-
} from './function/functions.types.js'
|
|
23
|
-
import {
|
|
24
|
-
QueueWorkersMeta,
|
|
25
|
-
CoreQueueWorker,
|
|
26
|
-
} from './wirings/queue/queue.types.js'
|
|
27
|
-
import {
|
|
28
|
-
CoreMCPResource,
|
|
29
|
-
CoreMCPTool,
|
|
30
|
-
CoreMCPPrompt,
|
|
31
4
|
MCPResourceMeta,
|
|
32
5
|
MCPToolMeta,
|
|
33
6
|
MCPPromptMeta,
|
|
34
7
|
} from './wirings/mcp/mcp.types.js'
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
CoreWorkflow,
|
|
38
|
-
WorkflowsMeta,
|
|
39
|
-
} from './wirings/workflow/workflow.types.js'
|
|
8
|
+
import { ScheduledTasksMeta } from './wirings/scheduler/scheduler.types.js'
|
|
9
|
+
import { TriggerMeta } from './wirings/trigger/trigger.types.js'
|
|
40
10
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
11
|
+
declare global {
|
|
12
|
+
// eslint-disable-next-line no-var
|
|
13
|
+
var pikkuState: Map<string, PikkuPackageState> | undefined
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get or set package-scoped pikku state
|
|
18
|
+
*
|
|
19
|
+
* @param packageName - Package name (null for main package, '@scope/package' for external packages)
|
|
20
|
+
* @param type - State category (function, rpc, http, etc.)
|
|
21
|
+
* @param content - Content key within the category
|
|
22
|
+
* @param value - Optional value to set
|
|
23
|
+
* @returns The current value of the state
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Main package
|
|
27
|
+
* pikkuState(null, 'function', 'functions').get(funcName)
|
|
28
|
+
*
|
|
29
|
+
* // External package
|
|
30
|
+
* pikkuState('@acme/stripe-functions', 'rpc', 'meta')
|
|
31
|
+
*/
|
|
32
|
+
export const pikkuState = <
|
|
33
|
+
Type extends keyof PikkuPackageState,
|
|
34
|
+
Content extends keyof PikkuPackageState[Type],
|
|
35
|
+
>(
|
|
36
|
+
packageName: string | null,
|
|
37
|
+
type: Type,
|
|
38
|
+
content: Content,
|
|
39
|
+
value?: PikkuPackageState[Type][Content]
|
|
40
|
+
): PikkuPackageState[Type][Content] => {
|
|
41
|
+
const resolvedPackageName = packageName ?? '__main__'
|
|
42
|
+
|
|
43
|
+
// Initialize package state if it doesn't exist
|
|
44
|
+
if (
|
|
45
|
+
!globalThis.pikkuState ||
|
|
46
|
+
!globalThis.pikkuState.has(resolvedPackageName)
|
|
47
|
+
) {
|
|
48
|
+
initializePikkuState(resolvedPackageName)
|
|
45
49
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
exportedName: string
|
|
52
|
-
path: string
|
|
53
|
-
}
|
|
54
|
-
>
|
|
50
|
+
|
|
51
|
+
const packageState = globalThis.pikkuState!.get(resolvedPackageName)!
|
|
52
|
+
|
|
53
|
+
if (value !== undefined) {
|
|
54
|
+
packageState[type][content] = value
|
|
55
55
|
}
|
|
56
|
+
|
|
57
|
+
return packageState[type][content]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const createEmptyPackageState = (): PikkuPackageState => ({
|
|
61
|
+
function: {
|
|
62
|
+
meta: {},
|
|
63
|
+
functions: new Map(),
|
|
64
|
+
},
|
|
65
|
+
rpc: {
|
|
66
|
+
meta: {},
|
|
67
|
+
files: new Map(),
|
|
68
|
+
externalPackages: new Map(),
|
|
69
|
+
},
|
|
56
70
|
http: {
|
|
57
|
-
middleware: Map
|
|
58
|
-
permissions: Map
|
|
59
|
-
routes:
|
|
60
|
-
meta:
|
|
61
|
-
|
|
71
|
+
middleware: new Map(),
|
|
72
|
+
permissions: new Map(),
|
|
73
|
+
routes: new Map(),
|
|
74
|
+
meta: {
|
|
75
|
+
post: {},
|
|
76
|
+
get: {},
|
|
77
|
+
delete: {},
|
|
78
|
+
patch: {},
|
|
79
|
+
head: {},
|
|
80
|
+
put: {},
|
|
81
|
+
options: {},
|
|
82
|
+
} as HTTPWiringsMeta,
|
|
83
|
+
},
|
|
62
84
|
channel: {
|
|
63
|
-
channels: Map
|
|
64
|
-
meta:
|
|
65
|
-
}
|
|
85
|
+
channels: new Map(),
|
|
86
|
+
meta: {},
|
|
87
|
+
},
|
|
66
88
|
scheduler: {
|
|
67
|
-
tasks: Map
|
|
68
|
-
meta: ScheduledTasksMeta
|
|
69
|
-
}
|
|
89
|
+
tasks: new Map(),
|
|
90
|
+
meta: [] as unknown as ScheduledTasksMeta,
|
|
91
|
+
},
|
|
70
92
|
queue: {
|
|
71
|
-
registrations: Map
|
|
72
|
-
meta:
|
|
73
|
-
}
|
|
93
|
+
registrations: new Map(),
|
|
94
|
+
meta: {},
|
|
95
|
+
},
|
|
74
96
|
workflows: {
|
|
75
|
-
registrations: Map
|
|
76
|
-
|
|
77
|
-
|
|
97
|
+
registrations: new Map(),
|
|
98
|
+
graphRegistrations: new Map(),
|
|
99
|
+
wirings: new Map(),
|
|
100
|
+
graphWirings: new Map(),
|
|
101
|
+
meta: {},
|
|
102
|
+
},
|
|
103
|
+
trigger: {
|
|
104
|
+
triggers: new Map(),
|
|
105
|
+
meta: {} as TriggerMeta,
|
|
106
|
+
},
|
|
78
107
|
mcp: {
|
|
79
|
-
resources: Map
|
|
80
|
-
resourcesMeta: MCPResourceMeta
|
|
81
|
-
tools: Map
|
|
82
|
-
toolsMeta: MCPToolMeta
|
|
83
|
-
prompts: Map
|
|
84
|
-
promptsMeta: MCPPromptMeta
|
|
85
|
-
}
|
|
108
|
+
resources: new Map(),
|
|
109
|
+
resourcesMeta: {} as MCPResourceMeta,
|
|
110
|
+
tools: new Map(),
|
|
111
|
+
toolsMeta: {} as MCPToolMeta,
|
|
112
|
+
prompts: new Map(),
|
|
113
|
+
promptsMeta: {} as MCPPromptMeta,
|
|
114
|
+
},
|
|
86
115
|
cli: {
|
|
87
|
-
meta:
|
|
88
|
-
programs:
|
|
89
|
-
}
|
|
116
|
+
meta: { programs: {}, renderers: {} },
|
|
117
|
+
programs: {},
|
|
118
|
+
},
|
|
90
119
|
middleware: {
|
|
91
|
-
tagGroup:
|
|
92
|
-
httpGroup:
|
|
93
|
-
tagGroupMeta:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
exportName: string | null
|
|
97
|
-
sourceFile: string
|
|
98
|
-
position: number
|
|
99
|
-
services: FunctionServicesMeta
|
|
100
|
-
middlewareCount: number
|
|
101
|
-
isFactory: boolean
|
|
102
|
-
}
|
|
103
|
-
>
|
|
104
|
-
httpGroupMeta: Record<
|
|
105
|
-
string,
|
|
106
|
-
{
|
|
107
|
-
exportName: string | null
|
|
108
|
-
sourceFile: string
|
|
109
|
-
position: number
|
|
110
|
-
services: FunctionServicesMeta
|
|
111
|
-
middlewareCount: number
|
|
112
|
-
isFactory: boolean
|
|
113
|
-
}
|
|
114
|
-
>
|
|
115
|
-
}
|
|
120
|
+
tagGroup: {},
|
|
121
|
+
httpGroup: {},
|
|
122
|
+
tagGroupMeta: {},
|
|
123
|
+
httpGroupMeta: {},
|
|
124
|
+
},
|
|
116
125
|
permissions: {
|
|
117
|
-
tagGroup:
|
|
118
|
-
httpGroup:
|
|
119
|
-
tagGroupMeta:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
exportName: string | null
|
|
123
|
-
sourceFile: string
|
|
124
|
-
position: number
|
|
125
|
-
services: FunctionServicesMeta
|
|
126
|
-
permissionCount: number
|
|
127
|
-
isFactory: boolean
|
|
128
|
-
}
|
|
129
|
-
>
|
|
130
|
-
httpGroupMeta: Record<
|
|
131
|
-
string,
|
|
132
|
-
{
|
|
133
|
-
exportName: string | null
|
|
134
|
-
sourceFile: string
|
|
135
|
-
position: number
|
|
136
|
-
services: FunctionServicesMeta
|
|
137
|
-
permissionCount: number
|
|
138
|
-
isFactory: boolean
|
|
139
|
-
}
|
|
140
|
-
>
|
|
141
|
-
}
|
|
126
|
+
tagGroup: {},
|
|
127
|
+
httpGroup: {},
|
|
128
|
+
tagGroupMeta: {},
|
|
129
|
+
httpGroupMeta: {},
|
|
130
|
+
},
|
|
142
131
|
misc: {
|
|
143
|
-
errors: Map
|
|
144
|
-
schemas: Map
|
|
145
|
-
middleware:
|
|
146
|
-
permissions:
|
|
132
|
+
errors: new Map(),
|
|
133
|
+
schemas: new Map(),
|
|
134
|
+
middleware: {},
|
|
135
|
+
permissions: {},
|
|
136
|
+
},
|
|
137
|
+
package: {
|
|
138
|
+
factories: null,
|
|
139
|
+
singletonServices: null,
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Initialize state for a new package
|
|
145
|
+
*/
|
|
146
|
+
export const initializePikkuState = (packageName: string): void => {
|
|
147
|
+
if (!globalThis.pikkuState) {
|
|
148
|
+
globalThis.pikkuState = new Map()
|
|
149
|
+
}
|
|
150
|
+
if (!globalThis.pikkuState.has(packageName)) {
|
|
151
|
+
globalThis.pikkuState.set(packageName, createEmptyPackageState())
|
|
147
152
|
}
|
|
148
153
|
}
|
|
149
154
|
|
|
150
155
|
export const resetPikkuState = () => {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
routes: new Map(),
|
|
163
|
-
meta: {},
|
|
164
|
-
},
|
|
165
|
-
channel: {
|
|
166
|
-
channels: new Map(),
|
|
167
|
-
meta: {},
|
|
168
|
-
},
|
|
169
|
-
scheduler: {
|
|
170
|
-
tasks: new Map(),
|
|
171
|
-
meta: [] as unknown as ScheduledTasksMeta,
|
|
172
|
-
},
|
|
173
|
-
queue: {
|
|
174
|
-
registrations: new Map(),
|
|
175
|
-
meta: {},
|
|
176
|
-
},
|
|
177
|
-
workflows: {
|
|
178
|
-
registrations: new Map(),
|
|
179
|
-
meta: {},
|
|
180
|
-
},
|
|
181
|
-
mcp: {
|
|
182
|
-
resources: new Map(),
|
|
183
|
-
resourcesMeta: {} as MCPResourceMeta,
|
|
184
|
-
tools: new Map(),
|
|
185
|
-
toolsMeta: {} as MCPToolMeta,
|
|
186
|
-
prompts: new Map(),
|
|
187
|
-
promptsMeta: {} as MCPPromptMeta,
|
|
188
|
-
},
|
|
189
|
-
cli: {
|
|
190
|
-
meta: { programs: {}, renderers: {} },
|
|
191
|
-
programs: {},
|
|
192
|
-
},
|
|
193
|
-
middleware: {
|
|
194
|
-
tagGroup: {},
|
|
195
|
-
httpGroup: {},
|
|
196
|
-
tagGroupMeta: {},
|
|
197
|
-
httpGroupMeta: {},
|
|
198
|
-
},
|
|
199
|
-
permissions: {
|
|
200
|
-
tagGroup: {},
|
|
201
|
-
httpGroup: {},
|
|
202
|
-
tagGroupMeta: {},
|
|
203
|
-
httpGroupMeta: {},
|
|
204
|
-
},
|
|
205
|
-
misc: {
|
|
206
|
-
errors: globalThis.pikkuState?.misc?.errors || new Map(),
|
|
207
|
-
schemas: new Map(),
|
|
208
|
-
middleware: {},
|
|
209
|
-
permissions: {},
|
|
210
|
-
},
|
|
211
|
-
} as PikkuState
|
|
156
|
+
// Preserve the errors map before resetting
|
|
157
|
+
const existingErrors = globalThis.pikkuState?.get('__main__')?.misc.errors
|
|
158
|
+
|
|
159
|
+
globalThis.pikkuState = new Map()
|
|
160
|
+
initializePikkuState('__main__')
|
|
161
|
+
|
|
162
|
+
// Restore the errors map if it existed
|
|
163
|
+
if (existingErrors) {
|
|
164
|
+
const mainState = globalThis.pikkuState.get('__main__')!
|
|
165
|
+
mainState.misc.errors = existingErrors
|
|
166
|
+
}
|
|
212
167
|
}
|
|
213
168
|
|
|
214
169
|
if (!globalThis.pikkuState) {
|
|
215
170
|
resetPikkuState()
|
|
216
171
|
}
|
|
217
172
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Register service factories for an external package.
|
|
175
|
+
* These factories are used to create services when the package's functions are invoked.
|
|
176
|
+
*
|
|
177
|
+
* @param packageName - The package name (e.g., '@pikku/templates-function-external')
|
|
178
|
+
* @param factories - The service factory functions
|
|
179
|
+
*/
|
|
180
|
+
export const addPackageServiceFactories = (
|
|
181
|
+
packageName: string,
|
|
182
|
+
factories: NonNullable<PikkuPackageState['package']['factories']>
|
|
183
|
+
): void => {
|
|
184
|
+
pikkuState(packageName, 'package', 'factories', factories)
|
|
230
185
|
}
|
package/src/schema.ts
CHANGED
|
@@ -4,25 +4,32 @@ import { UnprocessableContentError } from './errors/errors.js'
|
|
|
4
4
|
import { pikkuState } from './pikku-state.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Adds a schema to the
|
|
7
|
+
* Adds a schema to the schemas map for a specific package.
|
|
8
8
|
* @param name - The name of the schema.
|
|
9
9
|
* @param value - The schema value.
|
|
10
|
+
* @param packageName - The package name (null for main package, '@scope/package' for external packages).
|
|
10
11
|
* @ignore
|
|
11
12
|
*/
|
|
12
|
-
export const addSchema = (
|
|
13
|
-
|
|
13
|
+
export const addSchema = (
|
|
14
|
+
name: string,
|
|
15
|
+
value: any,
|
|
16
|
+
packageName: string | null = null
|
|
17
|
+
) => {
|
|
18
|
+
pikkuState(packageName, 'misc', 'schemas').set(name, value)
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
/**
|
|
17
|
-
* Retrieves a schema from the
|
|
22
|
+
* Retrieves a schema from the schemas map for a specific package.
|
|
18
23
|
* @param name - The name of the schema.
|
|
24
|
+
* @param packageName - The package name (null for main package, '@scope/package' for external packages).
|
|
19
25
|
* @returns The schema value or undefined if not found.
|
|
20
26
|
* @ignore
|
|
21
27
|
*/
|
|
22
28
|
export const getSchema = (
|
|
23
|
-
name: string
|
|
29
|
+
name: string,
|
|
30
|
+
packageName: string | null = null
|
|
24
31
|
): Record<string, unknown> | undefined => {
|
|
25
|
-
return pikkuState('misc', 'schemas').get(name)
|
|
32
|
+
return pikkuState(packageName, 'misc', 'schemas').get(name)
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
/**
|
|
@@ -36,7 +43,7 @@ export const compileAllSchemas = (
|
|
|
36
43
|
if (!schemaService) {
|
|
37
44
|
throw new Error('SchemaService needs to be defined to load schemas')
|
|
38
45
|
}
|
|
39
|
-
const schemas = pikkuState('misc', 'schemas')
|
|
46
|
+
const schemas = pikkuState(null, 'misc', 'schemas')
|
|
40
47
|
for (const [name, schema] of schemas) {
|
|
41
48
|
schemaService.compileSchema(name, schema)
|
|
42
49
|
}
|
|
@@ -47,14 +54,15 @@ const validateAllSchemasLoaded = (
|
|
|
47
54
|
logger: Logger,
|
|
48
55
|
schemaService: SchemaService
|
|
49
56
|
) => {
|
|
50
|
-
const routesMeta = pikkuState('http', 'meta')
|
|
57
|
+
const routesMeta = pikkuState(null, 'http', 'meta')
|
|
51
58
|
const validators = schemaService.getSchemaNames()
|
|
52
59
|
|
|
53
60
|
const missingSchemas: string[] = []
|
|
54
61
|
|
|
55
62
|
for (const routePaths of Object.values(routesMeta)) {
|
|
56
63
|
for (const meta of Object.values(routePaths)) {
|
|
57
|
-
const inputs = pikkuState('function', 'meta')[meta.pikkuFuncName]
|
|
64
|
+
const inputs = pikkuState(null, 'function', 'meta')[meta.pikkuFuncName]
|
|
65
|
+
?.inputs
|
|
58
66
|
const input = inputs?.[0]
|
|
59
67
|
if (!input || validators.has(input)) {
|
|
60
68
|
continue
|
|
@@ -74,8 +82,12 @@ const validateAllSchemasLoaded = (
|
|
|
74
82
|
}
|
|
75
83
|
}
|
|
76
84
|
|
|
77
|
-
export const coerceTopLevelDataFromSchema = (
|
|
78
|
-
|
|
85
|
+
export const coerceTopLevelDataFromSchema = (
|
|
86
|
+
schemaName: string,
|
|
87
|
+
data: any,
|
|
88
|
+
packageName: string | null = null
|
|
89
|
+
) => {
|
|
90
|
+
const schema = pikkuState(packageName, 'misc', 'schemas').get(schemaName)
|
|
79
91
|
for (const key in schema.properties) {
|
|
80
92
|
const property = schema.properties[key]
|
|
81
93
|
if (typeof property === 'boolean') {
|
|
@@ -97,7 +109,8 @@ export const validateSchema = async (
|
|
|
97
109
|
logger: Logger,
|
|
98
110
|
schemaService: SchemaService | undefined,
|
|
99
111
|
schemaName: string | undefined | null,
|
|
100
|
-
data: any
|
|
112
|
+
data: any,
|
|
113
|
+
packageName: string | null = null
|
|
101
114
|
) => {
|
|
102
115
|
if (schemaService) {
|
|
103
116
|
if (!schemaName) {
|
|
@@ -108,7 +121,23 @@ export const validateSchema = async (
|
|
|
108
121
|
return
|
|
109
122
|
}
|
|
110
123
|
}
|
|
111
|
-
|
|
124
|
+
logger.debug(
|
|
125
|
+
`[validateSchema] Validating schema '${schemaName}' for package '${packageName ?? 'main'}' with data:`,
|
|
126
|
+
JSON.stringify(data)
|
|
127
|
+
)
|
|
128
|
+
const schemas = pikkuState(packageName, 'misc', 'schemas')
|
|
129
|
+
const schema = schemas.get(schemaName)
|
|
130
|
+
if (schema === undefined) {
|
|
131
|
+
const availableSchemas = Array.from(schemas.keys())
|
|
132
|
+
logger.error(
|
|
133
|
+
`Schema '${schemaName}' not found for package '${packageName ?? 'main'}'. Available schemas: ${availableSchemas.join(', ') || '(none)'}`
|
|
134
|
+
)
|
|
135
|
+
} else {
|
|
136
|
+
logger.debug(
|
|
137
|
+
`[validateSchema] Found schema '${schemaName}':`,
|
|
138
|
+
JSON.stringify(schema)
|
|
139
|
+
)
|
|
140
|
+
}
|
|
112
141
|
await schemaService.compileSchema(schemaName, schema)
|
|
113
142
|
await schemaService.validateSchema(schemaName, data)
|
|
114
143
|
}
|