@pikku/inspector 0.9.6-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 +6 -0
- package/dist/add/add-channel.d.ts +5 -1
- package/dist/add/add-channel.js +51 -32
- package/dist/add/add-cli.d.ts +4 -0
- package/dist/add/add-cli.js +128 -23
- package/dist/add/add-file-extends-core-type.js +3 -2
- package/dist/add/add-file-with-factory.d.ts +2 -2
- package/dist/add/add-file-with-factory.js +34 -1
- package/dist/add/add-functions.js +52 -5
- package/dist/add/add-http-route.js +19 -12
- package/dist/add/add-mcp-prompt.js +20 -13
- package/dist/add/add-mcp-resource.js +24 -14
- package/dist/add/add-mcp-tool.js +23 -13
- package/dist/add/add-middleware.js +51 -12
- package/dist/add/add-permission.d.ts +1 -2
- package/dist/add/add-permission.js +275 -19
- package/dist/add/add-queue-worker.js +10 -12
- package/dist/add/add-schedule.js +9 -10
- package/dist/error-codes.d.ts +35 -0
- package/dist/error-codes.js +40 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/inspector.js +20 -1
- package/dist/types.d.ts +31 -3
- package/dist/utils/ensure-function-metadata.d.ts +6 -0
- package/dist/utils/ensure-function-metadata.js +18 -0
- package/dist/utils/extract-function-name.d.ts +2 -2
- package/dist/utils/extract-function-name.js +13 -8
- package/dist/utils/filter-inspector-state.d.ts +6 -0
- package/dist/utils/filter-inspector-state.js +382 -0
- package/dist/utils/filter-utils.d.ts +10 -0
- package/dist/utils/filter-utils.js +66 -2
- package/dist/utils/find-root-dir.d.ts +23 -0
- package/dist/utils/find-root-dir.js +55 -0
- package/dist/utils/get-files-and-methods.d.ts +2 -1
- package/dist/utils/get-files-and-methods.js +2 -1
- package/dist/utils/get-property-value.d.ts +9 -0
- package/dist/utils/get-property-value.js +20 -0
- package/dist/utils/middleware.d.ts +1 -1
- package/dist/utils/middleware.js +7 -7
- package/dist/utils/permissions.d.ts +43 -0
- package/dist/utils/permissions.js +178 -0
- package/dist/utils/post-process.d.ts +16 -0
- package/dist/utils/post-process.js +132 -0
- package/dist/utils/serialize-inspector-state.d.ts +179 -0
- package/dist/utils/serialize-inspector-state.js +170 -0
- package/dist/visit.js +3 -2
- package/package.json +4 -4
- package/src/add/add-channel.ts +92 -40
- package/src/add/add-cli.ts +188 -29
- package/src/add/add-file-extends-core-type.ts +5 -2
- package/src/add/add-file-with-factory.ts +45 -2
- package/src/add/add-functions.ts +60 -5
- package/src/add/add-http-route.ts +46 -21
- package/src/add/add-mcp-prompt.ts +42 -21
- package/src/add/add-mcp-prompt.ts.tmp +0 -0
- package/src/add/add-mcp-resource.ts +50 -24
- package/src/add/add-mcp-resource.ts.tmp +0 -0
- package/src/add/add-mcp-tool.ts +48 -21
- package/src/add/add-middleware.ts +74 -15
- package/src/add/add-permission.ts +364 -22
- package/src/add/add-queue-worker.ts +22 -25
- package/src/add/add-schedule.ts +19 -20
- package/src/error-codes.ts +43 -0
- package/src/index.ts +7 -0
- package/src/inspector.ts +22 -1
- package/src/types.ts +38 -3
- package/src/utils/ensure-function-metadata.ts +24 -0
- package/src/utils/extract-function-name.ts +20 -8
- package/src/utils/filter-inspector-state.test.ts +1433 -0
- package/src/utils/filter-inspector-state.ts +526 -0
- package/src/utils/filter-utils.test.ts +350 -1
- package/src/utils/filter-utils.ts +82 -2
- package/src/utils/find-root-dir.ts +68 -0
- package/src/utils/get-files-and-methods.ts +8 -0
- package/src/utils/get-property-value.ts +27 -0
- package/src/utils/middleware.ts +14 -7
- package/src/utils/permissions.test.ts +327 -0
- package/src/utils/permissions.ts +262 -0
- package/src/utils/post-process.ts +178 -0
- package/src/utils/serialize-inspector-state.ts +375 -0
- package/src/utils/test-data/inspector-state.json +1680 -0
- package/src/visit.ts +4 -2
- package/tsconfig.tsbuildinfo +1 -1
package/src/inspector.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { visitSetup, visitRoutes } from './visit.js'
|
|
|
3
3
|
import { TypesMap } from './types-map.js'
|
|
4
4
|
import { InspectorState, InspectorLogger, InspectorOptions } from './types.js'
|
|
5
5
|
import { getFilesAndMethods } from './utils/get-files-and-methods.js'
|
|
6
|
+
import { findCommonAncestor } from './utils/find-root-dir.js'
|
|
7
|
+
import { aggregateRequiredServices } from './utils/post-process.js'
|
|
6
8
|
|
|
7
9
|
export const inspect = (
|
|
8
10
|
logger: InspectorLogger,
|
|
@@ -16,13 +18,18 @@ export const inspect = (
|
|
|
16
18
|
const checker = program.getTypeChecker()
|
|
17
19
|
const sourceFiles = program.getSourceFiles()
|
|
18
20
|
|
|
21
|
+
// Infer root directory from source files
|
|
22
|
+
const rootDir = findCommonAncestor(routeFiles)
|
|
23
|
+
|
|
19
24
|
const state: InspectorState = {
|
|
25
|
+
rootDir,
|
|
20
26
|
singletonServicesTypeImportMap: new Map(),
|
|
21
27
|
sessionServicesTypeImportMap: new Map(),
|
|
22
28
|
userSessionTypeImportMap: new Map(),
|
|
23
29
|
configTypeImportMap: new Map(),
|
|
24
30
|
singletonServicesFactories: new Map(),
|
|
25
31
|
sessionServicesFactories: new Map(),
|
|
32
|
+
sessionServicesMeta: new Map(),
|
|
26
33
|
configFactories: new Map(),
|
|
27
34
|
filesAndMethods: {},
|
|
28
35
|
filesAndMethodsErrors: new Map(),
|
|
@@ -45,6 +52,7 @@ export const inspect = (
|
|
|
45
52
|
},
|
|
46
53
|
files: new Set(),
|
|
47
54
|
routeMiddleware: new Map(),
|
|
55
|
+
routePermissions: new Map(),
|
|
48
56
|
},
|
|
49
57
|
channels: {
|
|
50
58
|
files: new Set(),
|
|
@@ -72,7 +80,10 @@ export const inspect = (
|
|
|
72
80
|
files: new Set(),
|
|
73
81
|
},
|
|
74
82
|
cli: {
|
|
75
|
-
meta: {
|
|
83
|
+
meta: {
|
|
84
|
+
programs: {},
|
|
85
|
+
renderers: {},
|
|
86
|
+
},
|
|
76
87
|
files: new Set(),
|
|
77
88
|
},
|
|
78
89
|
middleware: {
|
|
@@ -81,6 +92,13 @@ export const inspect = (
|
|
|
81
92
|
},
|
|
82
93
|
permissions: {
|
|
83
94
|
meta: {},
|
|
95
|
+
tagPermissions: new Map(),
|
|
96
|
+
},
|
|
97
|
+
serviceAggregation: {
|
|
98
|
+
requiredServices: new Set(),
|
|
99
|
+
usedFunctions: new Set(),
|
|
100
|
+
usedMiddleware: new Set(),
|
|
101
|
+
usedPermissions: new Set(),
|
|
84
102
|
},
|
|
85
103
|
}
|
|
86
104
|
|
|
@@ -103,5 +121,8 @@ export const inspect = (
|
|
|
103
121
|
state.filesAndMethods = result
|
|
104
122
|
state.filesAndMethodsErrors = errors
|
|
105
123
|
|
|
124
|
+
// Post-processing: Aggregate required services from wired functions/middleware/permissions
|
|
125
|
+
aggregateRequiredServices(state)
|
|
126
|
+
|
|
106
127
|
return state
|
|
107
128
|
}
|
package/src/types.ts
CHANGED
|
@@ -3,10 +3,11 @@ import { ChannelsMeta } from '@pikku/core/channel'
|
|
|
3
3
|
import { HTTPWiringsMeta } from '@pikku/core/http'
|
|
4
4
|
import { ScheduledTasksMeta } from '@pikku/core/scheduler'
|
|
5
5
|
import { queueWorkersMeta } from '@pikku/core/queue'
|
|
6
|
-
import { MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from '@pikku/core'
|
|
7
|
-
import { CLIMeta } from '@pikku/core'
|
|
6
|
+
import { MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from '@pikku/core/mcp'
|
|
7
|
+
import { CLIMeta } from '@pikku/core/cli'
|
|
8
8
|
import { TypesMap } from './types-map.js'
|
|
9
9
|
import { FunctionsMeta, FunctionServicesMeta } from '@pikku/core'
|
|
10
|
+
import { ErrorCode } from './error-codes.js'
|
|
10
11
|
|
|
11
12
|
export type PathToNameAndType = Map<
|
|
12
13
|
string,
|
|
@@ -31,6 +32,15 @@ export interface MiddlewareGroupMeta {
|
|
|
31
32
|
isFactory: boolean // true if wrapped in () => add...()
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
export interface PermissionGroupMeta {
|
|
36
|
+
exportName: string | null // null if not exported
|
|
37
|
+
sourceFile: string
|
|
38
|
+
position: number
|
|
39
|
+
services: FunctionServicesMeta
|
|
40
|
+
permissionCount: number
|
|
41
|
+
isFactory: boolean // true if wrapped in () => add...()
|
|
42
|
+
}
|
|
43
|
+
|
|
34
44
|
export interface InspectorHTTPState {
|
|
35
45
|
metaInputTypes: MetaInputTypes
|
|
36
46
|
meta: HTTPWiringsMeta
|
|
@@ -39,6 +49,10 @@ export interface InspectorHTTPState {
|
|
|
39
49
|
// Pattern '*' matches all routes (from addHTTPMiddleware('*', [...]))
|
|
40
50
|
// Pattern '/api/*' matches specific routes (from addHTTPMiddleware('/api/*', [...]))
|
|
41
51
|
routeMiddleware: Map<string, MiddlewareGroupMeta>
|
|
52
|
+
// HTTP permission calls tracking - route pattern -> group metadata
|
|
53
|
+
// Pattern '*' matches all routes (from addHTTPPermission('*', [...]))
|
|
54
|
+
// Pattern '/api/*' matches specific routes (from addHTTPPermission('/api/*', [...]))
|
|
55
|
+
routePermissions: Map<string, PermissionGroupMeta>
|
|
42
56
|
}
|
|
43
57
|
|
|
44
58
|
export interface InspectorFunctionState {
|
|
@@ -62,6 +76,8 @@ export interface InspectorMiddlewareState {
|
|
|
62
76
|
position: number
|
|
63
77
|
exportedName: string | null
|
|
64
78
|
factory?: boolean // true if wrapped with pikkuMiddlewareFactory
|
|
79
|
+
name?: string // optional name from pikkuMiddleware({ name: '...' })
|
|
80
|
+
description?: string // optional description from pikkuMiddleware({ description: '...' })
|
|
65
81
|
}
|
|
66
82
|
>
|
|
67
83
|
// Tag-based middleware calls tracking - tag -> group metadata
|
|
@@ -70,6 +86,7 @@ export interface InspectorMiddlewareState {
|
|
|
70
86
|
}
|
|
71
87
|
|
|
72
88
|
export interface InspectorPermissionState {
|
|
89
|
+
// Individual permission function metadata
|
|
73
90
|
meta: Record<
|
|
74
91
|
string,
|
|
75
92
|
{
|
|
@@ -77,14 +94,23 @@ export interface InspectorPermissionState {
|
|
|
77
94
|
sourceFile: string
|
|
78
95
|
position: number
|
|
79
96
|
exportedName: string | null
|
|
97
|
+
factory?: boolean // true if wrapped with pikkuPermissionFactory
|
|
98
|
+
name?: string // optional name from pikkuPermission({ name: '...' })
|
|
99
|
+
description?: string // optional description from pikkuPermission({ description: '...' })
|
|
80
100
|
}
|
|
81
101
|
>
|
|
102
|
+
// Tag-based permission calls tracking - tag -> group metadata
|
|
103
|
+
// e.g., export const adminPermissions = () => addPermission('admin', [...])
|
|
104
|
+
tagPermissions: Map<string, PermissionGroupMeta>
|
|
82
105
|
}
|
|
83
106
|
|
|
84
107
|
export type InspectorFilters = {
|
|
108
|
+
names?: string[] // Wildcard support: "email-*" matches "email-worker", "email-sender"
|
|
85
109
|
tags?: string[]
|
|
86
110
|
types?: string[]
|
|
87
111
|
directories?: string[]
|
|
112
|
+
httpRoutes?: string[] // HTTP route patterns: "/api/*", "/webhooks/*"
|
|
113
|
+
httpMethods?: string[] // HTTP methods: "GET", "POST", "DELETE", etc.
|
|
88
114
|
}
|
|
89
115
|
|
|
90
116
|
export type InspectorOptions = Partial<{
|
|
@@ -94,7 +120,6 @@ export type InspectorOptions = Partial<{
|
|
|
94
120
|
singletonServicesFactoryType: string
|
|
95
121
|
sessionServicesFactoryType: string
|
|
96
122
|
}>
|
|
97
|
-
filters: InspectorFilters
|
|
98
123
|
}>
|
|
99
124
|
|
|
100
125
|
export interface InspectorLogger {
|
|
@@ -102,6 +127,8 @@ export interface InspectorLogger {
|
|
|
102
127
|
error: (message: string) => void
|
|
103
128
|
warn: (message: string) => void
|
|
104
129
|
debug: (message: string) => void
|
|
130
|
+
critical: (code: ErrorCode, message: string) => void
|
|
131
|
+
hasCriticalErrors: () => boolean
|
|
105
132
|
}
|
|
106
133
|
|
|
107
134
|
export type AddWiring = (
|
|
@@ -157,12 +184,14 @@ export interface InspectorFilesAndMethods {
|
|
|
157
184
|
}
|
|
158
185
|
|
|
159
186
|
export interface InspectorState {
|
|
187
|
+
rootDir: string // Root directory inferred from source files
|
|
160
188
|
singletonServicesTypeImportMap: PathToNameAndType
|
|
161
189
|
sessionServicesTypeImportMap: PathToNameAndType
|
|
162
190
|
userSessionTypeImportMap: PathToNameAndType
|
|
163
191
|
configTypeImportMap: PathToNameAndType
|
|
164
192
|
singletonServicesFactories: PathToNameAndType
|
|
165
193
|
sessionServicesFactories: PathToNameAndType
|
|
194
|
+
sessionServicesMeta: Map<string, string[]> // variable name -> singleton services consumed
|
|
166
195
|
configFactories: PathToNameAndType
|
|
167
196
|
filesAndMethods: InspectorFilesAndMethods
|
|
168
197
|
filesAndMethodsErrors: Map<string, PathToNameAndType>
|
|
@@ -197,4 +226,10 @@ export interface InspectorState {
|
|
|
197
226
|
}
|
|
198
227
|
middleware: InspectorMiddlewareState
|
|
199
228
|
permissions: InspectorPermissionState
|
|
229
|
+
serviceAggregation: {
|
|
230
|
+
requiredServices: Set<string> // All services needed across the app
|
|
231
|
+
usedFunctions: Set<string> // Function names actually wired/exposed
|
|
232
|
+
usedMiddleware: Set<string> // Middleware names used by wired functions
|
|
233
|
+
usedPermissions: Set<string> // Permission names used by wired functions
|
|
234
|
+
}
|
|
200
235
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { InspectorState } from '../types.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Ensures that function metadata exists for a given pikkuFuncName.
|
|
5
|
+
* Creates stub metadata if it doesn't exist (useful for inline functions).
|
|
6
|
+
*/
|
|
7
|
+
export function ensureFunctionMetadata(
|
|
8
|
+
state: InspectorState,
|
|
9
|
+
pikkuFuncName: string,
|
|
10
|
+
fallbackName?: string
|
|
11
|
+
): void {
|
|
12
|
+
if (!state.functions.meta[pikkuFuncName]) {
|
|
13
|
+
state.functions.meta[pikkuFuncName] = {
|
|
14
|
+
pikkuFuncName,
|
|
15
|
+
name: fallbackName || pikkuFuncName,
|
|
16
|
+
services: { optimized: false, services: [] },
|
|
17
|
+
inputSchemaName: null,
|
|
18
|
+
outputSchemaName: null,
|
|
19
|
+
inputs: [],
|
|
20
|
+
outputs: [],
|
|
21
|
+
middleware: undefined,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
|
+
import { toRelativePath } from './find-root-dir.js'
|
|
2
3
|
|
|
3
4
|
export type ExtractedFunctionName = {
|
|
4
5
|
pikkuFuncName: string
|
|
@@ -16,7 +17,8 @@ export type ExtractedFunctionName = {
|
|
|
16
17
|
*/
|
|
17
18
|
export function makeDeterministicAnonName(
|
|
18
19
|
start: ts.Node,
|
|
19
|
-
checker: ts.TypeChecker
|
|
20
|
+
checker: ts.TypeChecker,
|
|
21
|
+
rootDir: string
|
|
20
22
|
): string {
|
|
21
23
|
let node: ts.Node = start
|
|
22
24
|
let target: ts.Node = start
|
|
@@ -45,7 +47,8 @@ export function makeDeterministicAnonName(
|
|
|
45
47
|
target = decl.initializer
|
|
46
48
|
// Return early - we found the function directly
|
|
47
49
|
const sf = target.getSourceFile()
|
|
48
|
-
const
|
|
50
|
+
const relativePath = toRelativePath(sf.fileName, rootDir)
|
|
51
|
+
const file = relativePath.replace(/[^A-Za-z0-9_]/g, '_')
|
|
49
52
|
const { line, character } = ts.getLineAndCharacterOfPosition(
|
|
50
53
|
sf,
|
|
51
54
|
target.getStart()
|
|
@@ -91,7 +94,8 @@ export function makeDeterministicAnonName(
|
|
|
91
94
|
target = decl.initializer
|
|
92
95
|
// Return early - we found the function directly
|
|
93
96
|
const sf = target.getSourceFile()
|
|
94
|
-
const
|
|
97
|
+
const relativePath = toRelativePath(sf.fileName, rootDir)
|
|
98
|
+
const file = relativePath.replace(/[^A-Za-z0-9_]/g, '_')
|
|
95
99
|
const { line, character } = ts.getLineAndCharacterOfPosition(
|
|
96
100
|
sf,
|
|
97
101
|
target.getStart()
|
|
@@ -103,7 +107,8 @@ export function makeDeterministicAnonName(
|
|
|
103
107
|
target = decl
|
|
104
108
|
// Return early
|
|
105
109
|
const sf = target.getSourceFile()
|
|
106
|
-
const
|
|
110
|
+
const relativePath = toRelativePath(sf.fileName, rootDir)
|
|
111
|
+
const file = relativePath.replace(/[^A-Za-z0-9_]/g, '_')
|
|
107
112
|
const { line, character } = ts.getLineAndCharacterOfPosition(
|
|
108
113
|
sf,
|
|
109
114
|
target.getStart()
|
|
@@ -238,7 +243,8 @@ export function makeDeterministicAnonName(
|
|
|
238
243
|
}
|
|
239
244
|
|
|
240
245
|
const sf = target.getSourceFile()
|
|
241
|
-
const
|
|
246
|
+
const relativePath = toRelativePath(sf.fileName, rootDir)
|
|
247
|
+
const file = relativePath.replace(/[^A-Za-z0-9_]/g, '_')
|
|
242
248
|
const { line, character } = ts.getLineAndCharacterOfPosition(
|
|
243
249
|
sf,
|
|
244
250
|
target.getStart()
|
|
@@ -255,7 +261,8 @@ export function makeDeterministicAnonName(
|
|
|
255
261
|
*/
|
|
256
262
|
export function extractFunctionName(
|
|
257
263
|
callExpr: ts.Node,
|
|
258
|
-
checker: ts.TypeChecker
|
|
264
|
+
checker: ts.TypeChecker,
|
|
265
|
+
rootDir: string
|
|
259
266
|
): ExtractedFunctionName {
|
|
260
267
|
const parent: any = callExpr.parent
|
|
261
268
|
|
|
@@ -304,7 +311,8 @@ export function extractFunctionName(
|
|
|
304
311
|
// Use the function directly for position calculation
|
|
305
312
|
result.pikkuFuncName = makeDeterministicAnonName(
|
|
306
313
|
firstArg,
|
|
307
|
-
checker
|
|
314
|
+
checker,
|
|
315
|
+
rootDir
|
|
308
316
|
)
|
|
309
317
|
|
|
310
318
|
// Continue with name extraction
|
|
@@ -678,7 +686,11 @@ export function extractFunctionName(
|
|
|
678
686
|
// Generate the deterministic function name based on the original call expression
|
|
679
687
|
// (the config), not the resolved inner function. This ensures the metadata key
|
|
680
688
|
// matches what will be looked up at runtime when referencing the config object.
|
|
681
|
-
result.pikkuFuncName = makeDeterministicAnonName(
|
|
689
|
+
result.pikkuFuncName = makeDeterministicAnonName(
|
|
690
|
+
originalCallExpr,
|
|
691
|
+
checker,
|
|
692
|
+
rootDir
|
|
693
|
+
)
|
|
682
694
|
|
|
683
695
|
// Continue with regular name extraction for remaining cases
|
|
684
696
|
// 1) const foo = pikkuFunc(...)
|