@pikku/inspector 0.9.2 → 0.9.4
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 +25 -0
- package/dist/add-functions.d.ts +2 -2
- package/dist/add-functions.js +45 -25
- package/dist/add-http-route.js +2 -2
- package/dist/add-middleware.d.ts +7 -0
- package/dist/add-middleware.js +35 -0
- package/dist/add-permission.d.ts +7 -0
- package/dist/add-permission.js +35 -0
- package/dist/add-rpc-invocations.d.ts +6 -0
- package/dist/add-rpc-invocations.js +36 -0
- package/dist/inspector.js +20 -3
- package/dist/types.d.ts +30 -7
- package/dist/utils.d.ts +5 -1
- package/dist/utils.js +35 -1
- package/dist/visit.js +7 -1
- package/package.json +2 -2
- package/src/add-functions.ts +53 -24
- package/src/add-http-route.ts +2 -2
- package/src/add-middleware.ts +51 -0
- package/src/add-permission.ts +53 -0
- package/src/add-rpc-invocations.ts +49 -0
- package/src/inspector.ts +20 -3
- package/src/types.ts +32 -4
- package/src/utils.ts +43 -2
- package/src/visit.ts +8 -1
- package/tsconfig.tsbuildinfo +1 -1
package/src/add-functions.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
|
-
import {
|
|
2
|
+
import { InspectorLogger, InspectorState } from './types.js'
|
|
3
3
|
import { TypesMap } from './types-map.js'
|
|
4
4
|
import {
|
|
5
5
|
extractFunctionName,
|
|
@@ -84,6 +84,25 @@ const resolveTypeImports = (
|
|
|
84
84
|
typeRef.typeArguments?.forEach(visitType)
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
|
+
|
|
88
|
+
// Always traverse type arguments for thorough type collection
|
|
89
|
+
if (currentType.aliasTypeArguments) {
|
|
90
|
+
currentType.aliasTypeArguments.forEach(visitType)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Always handle intersections and unions
|
|
94
|
+
if (currentType.isUnionOrIntersection()) {
|
|
95
|
+
currentType.types.forEach(visitType)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Always handle object types with type arguments
|
|
99
|
+
if (
|
|
100
|
+
currentType.flags & ts.TypeFlags.Object &&
|
|
101
|
+
(currentType as ts.ObjectType).objectFlags & ts.ObjectFlags.Reference
|
|
102
|
+
) {
|
|
103
|
+
const typeRef = currentType as ts.TypeReference
|
|
104
|
+
typeRef.typeArguments?.forEach(visitType)
|
|
105
|
+
}
|
|
87
106
|
}
|
|
88
107
|
|
|
89
108
|
visitType(type)
|
|
@@ -232,7 +251,6 @@ export function addFunctions(
|
|
|
232
251
|
node: ts.Node,
|
|
233
252
|
checker: ts.TypeChecker,
|
|
234
253
|
state: InspectorState,
|
|
235
|
-
filters: InspectorFilters,
|
|
236
254
|
logger: InspectorLogger
|
|
237
255
|
) {
|
|
238
256
|
if (!ts.isCallExpression(node)) return
|
|
@@ -267,7 +285,10 @@ export function addFunctions(
|
|
|
267
285
|
// determine the actual handler expression:
|
|
268
286
|
// either the `func` prop or the first argument directly
|
|
269
287
|
let handlerNode: ts.Expression = args[0]!
|
|
288
|
+
let isDirectFunction = true // Default to direct function format
|
|
289
|
+
|
|
270
290
|
if (ts.isObjectLiteralExpression(handlerNode)) {
|
|
291
|
+
isDirectFunction = false // This is object format with func property
|
|
271
292
|
tags = (getPropertyValue(handlerNode, 'tags') as string[]) || undefined
|
|
272
293
|
expose = getPropertyValue(handlerNode, 'expose') as boolean | undefined
|
|
273
294
|
docs = getPropertyValue(handlerNode, 'docs') as PikkuDocs | undefined
|
|
@@ -282,7 +303,7 @@ export function addFunctions(
|
|
|
282
303
|
!fnProp ||
|
|
283
304
|
(!ts.isArrowFunction(fnProp) && !ts.isFunctionExpression(fnProp))
|
|
284
305
|
) {
|
|
285
|
-
|
|
306
|
+
logger.error(`• No valid 'func' property found for ${pikkuFuncName}.`)
|
|
286
307
|
return
|
|
287
308
|
}
|
|
288
309
|
handlerNode = fnProp
|
|
@@ -292,7 +313,7 @@ export function addFunctions(
|
|
|
292
313
|
!ts.isArrowFunction(handlerNode) &&
|
|
293
314
|
!ts.isFunctionExpression(handlerNode)
|
|
294
315
|
) {
|
|
295
|
-
|
|
316
|
+
logger.error(`• Handler for ${name} is not a function.`)
|
|
296
317
|
return
|
|
297
318
|
}
|
|
298
319
|
|
|
@@ -334,7 +355,7 @@ export function addFunctions(
|
|
|
334
355
|
genericTypes[0]
|
|
335
356
|
)
|
|
336
357
|
// if (inputTypes.length === 0) {
|
|
337
|
-
//
|
|
358
|
+
// logger.debug(
|
|
338
359
|
// `\x1b[31m• Unknown input type for '${name}', assuming void.\x1b[0m`
|
|
339
360
|
// )
|
|
340
361
|
// }
|
|
@@ -365,7 +386,7 @@ export function addFunctions(
|
|
|
365
386
|
}
|
|
366
387
|
|
|
367
388
|
if (inputNames.length > 1) {
|
|
368
|
-
|
|
389
|
+
logger.warn(
|
|
369
390
|
'More than one input type detected, only the first one will be used as a schema.'
|
|
370
391
|
)
|
|
371
392
|
}
|
|
@@ -374,34 +395,42 @@ export function addFunctions(
|
|
|
374
395
|
pikkuFuncName,
|
|
375
396
|
name,
|
|
376
397
|
services,
|
|
377
|
-
|
|
398
|
+
inputSchemaName: inputNames[0] ?? null,
|
|
399
|
+
outputSchemaName: outputNames[0] ?? null,
|
|
378
400
|
inputs: inputNames.filter((n) => n !== 'void') ?? null,
|
|
379
401
|
outputs: outputNames.filter((n) => n !== 'void') ?? null,
|
|
380
|
-
expose,
|
|
381
|
-
tags,
|
|
382
|
-
docs,
|
|
402
|
+
expose: expose || undefined,
|
|
403
|
+
tags: tags || undefined,
|
|
404
|
+
docs: docs || undefined,
|
|
405
|
+
isDirectFunction,
|
|
383
406
|
}
|
|
384
407
|
|
|
385
|
-
if (
|
|
408
|
+
if (exportedName || explicitName) {
|
|
386
409
|
if (!exportedName) {
|
|
387
|
-
|
|
410
|
+
logger.error(
|
|
388
411
|
`• Function with explicit name '${name}' is not exported, this is not allowed.`
|
|
389
412
|
)
|
|
390
413
|
return
|
|
391
414
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
415
|
+
|
|
416
|
+
if (expose) {
|
|
417
|
+
state.rpc.exposedMeta[name] = pikkuFuncName
|
|
418
|
+
state.rpc.exposedFiles.set(name, {
|
|
419
|
+
path: node.getSourceFile().fileName,
|
|
420
|
+
exportedName,
|
|
421
|
+
})
|
|
395
422
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
423
|
+
|
|
424
|
+
// We add it to internal meta to allow autocomplete for everything
|
|
425
|
+
state.rpc.internalMeta[name] = pikkuFuncName
|
|
426
|
+
|
|
427
|
+
// But we only import the actual function if it's actually invoked to keep
|
|
428
|
+
// bundle size down
|
|
429
|
+
if (state.rpc.invokedFunctions.has(pikkuFuncName)) {
|
|
430
|
+
state.rpc.internalFiles.set(name, {
|
|
431
|
+
path: node.getSourceFile().fileName,
|
|
432
|
+
exportedName,
|
|
433
|
+
})
|
|
399
434
|
}
|
|
400
|
-
state.functions.files.set(name, {
|
|
401
|
-
path: node.getSourceFile().fileName,
|
|
402
|
-
exportedName,
|
|
403
|
-
})
|
|
404
|
-
} else {
|
|
405
|
-
console.log(`• Function name '${name}' not exported, skipping.`)
|
|
406
435
|
}
|
|
407
436
|
}
|
package/src/add-http-route.ts
CHANGED
|
@@ -116,7 +116,7 @@ export const addHTTPRoute = (
|
|
|
116
116
|
|
|
117
117
|
// --- record route ---
|
|
118
118
|
state.http.files.add(node.getSourceFile().fileName)
|
|
119
|
-
state.http.meta
|
|
119
|
+
state.http.meta[method][route] = {
|
|
120
120
|
pikkuFuncName: funcName,
|
|
121
121
|
route,
|
|
122
122
|
method: method as HTTPMethod,
|
|
@@ -125,5 +125,5 @@ export const addHTTPRoute = (
|
|
|
125
125
|
inputTypes,
|
|
126
126
|
docs,
|
|
127
127
|
tags,
|
|
128
|
-
}
|
|
128
|
+
}
|
|
129
129
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as ts from 'typescript'
|
|
2
|
+
import { InspectorLogger, InspectorState } from './types.js'
|
|
3
|
+
import { extractFunctionName, extractServicesFromFunction } from './utils.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Inspect pikkuMiddleware calls and extract first-arg destructuring
|
|
7
|
+
* for tree shaking optimization.
|
|
8
|
+
*/
|
|
9
|
+
export function addMiddleware(
|
|
10
|
+
node: ts.Node,
|
|
11
|
+
checker: ts.TypeChecker,
|
|
12
|
+
state: InspectorState,
|
|
13
|
+
logger: InspectorLogger
|
|
14
|
+
) {
|
|
15
|
+
if (!ts.isCallExpression(node)) return
|
|
16
|
+
|
|
17
|
+
const { expression, arguments: args } = node
|
|
18
|
+
|
|
19
|
+
// only handle calls like pikkuMiddleware(...)
|
|
20
|
+
if (!ts.isIdentifier(expression)) {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (expression.text !== 'pikkuMiddleware') {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const handlerNode = args[0]
|
|
29
|
+
if (!handlerNode) return
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
!ts.isArrowFunction(handlerNode) &&
|
|
33
|
+
!ts.isFunctionExpression(handlerNode)
|
|
34
|
+
) {
|
|
35
|
+
logger.error(`• Handler for pikkuMiddleware is not a function.`)
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const services = extractServicesFromFunction(handlerNode)
|
|
40
|
+
const { pikkuFuncName, exportedName } = extractFunctionName(node, checker)
|
|
41
|
+
state.middleware.meta[pikkuFuncName] = {
|
|
42
|
+
services,
|
|
43
|
+
sourceFile: node.getSourceFile().fileName,
|
|
44
|
+
position: node.getStart(),
|
|
45
|
+
exportedName,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
logger.debug(
|
|
49
|
+
`• Found middleware with services: ${services.services.join(', ')}`
|
|
50
|
+
)
|
|
51
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as ts from 'typescript'
|
|
2
|
+
import { InspectorLogger, InspectorState } from './types.js'
|
|
3
|
+
import { extractFunctionName, extractServicesFromFunction } from './utils.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Inspect pikkuPermission calls and extract first-arg destructuring
|
|
7
|
+
* for tree shaking optimization.
|
|
8
|
+
*/
|
|
9
|
+
export function addPermission(
|
|
10
|
+
node: ts.Node,
|
|
11
|
+
checker: ts.TypeChecker,
|
|
12
|
+
state: InspectorState,
|
|
13
|
+
logger: InspectorLogger
|
|
14
|
+
) {
|
|
15
|
+
if (!ts.isCallExpression(node)) return
|
|
16
|
+
|
|
17
|
+
const { expression, arguments: args } = node
|
|
18
|
+
|
|
19
|
+
// only handle calls like pikkuPermission(...)
|
|
20
|
+
if (!ts.isIdentifier(expression)) {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (expression.text !== 'pikkuPermission') {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const handlerNode = args[0]
|
|
29
|
+
if (!handlerNode) return
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
!ts.isArrowFunction(handlerNode) &&
|
|
33
|
+
!ts.isFunctionExpression(handlerNode)
|
|
34
|
+
) {
|
|
35
|
+
logger.error(`• Handler for pikkuPermission is not a function.`)
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const services = extractServicesFromFunction(handlerNode)
|
|
40
|
+
|
|
41
|
+
const { pikkuFuncName, exportedName } = extractFunctionName(node, checker)
|
|
42
|
+
|
|
43
|
+
state.permissions.meta[pikkuFuncName] = {
|
|
44
|
+
services,
|
|
45
|
+
sourceFile: node.getSourceFile().fileName,
|
|
46
|
+
position: node.getStart(),
|
|
47
|
+
exportedName,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
logger.debug(
|
|
51
|
+
`• Found permission with services: ${services.services.join(', ')}`
|
|
52
|
+
)
|
|
53
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as ts from 'typescript'
|
|
2
|
+
import { InspectorState, InspectorLogger } from './types.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Scan for rpc.invoke() calls to track which functions are actually being invoked
|
|
6
|
+
*/
|
|
7
|
+
export function addRPCInvocations(
|
|
8
|
+
node: ts.Node,
|
|
9
|
+
state: InspectorState,
|
|
10
|
+
logger: InspectorLogger
|
|
11
|
+
) {
|
|
12
|
+
// Look for property access expressions: rpc.invoke
|
|
13
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
14
|
+
const { expression, name } = node
|
|
15
|
+
|
|
16
|
+
// Check if this is accessing 'invoke' property
|
|
17
|
+
if (name.text === 'invoke') {
|
|
18
|
+
// Check if the object is 'rpc' (or a variable containing rpc)
|
|
19
|
+
if (ts.isIdentifier(expression) && expression.text === 'rpc') {
|
|
20
|
+
// This is rpc.invoke - now we need to find the parent call expression
|
|
21
|
+
const parent = node.parent
|
|
22
|
+
if (ts.isCallExpression(parent) && parent.expression === node) {
|
|
23
|
+
// This is rpc.invoke('function-name')
|
|
24
|
+
const [firstArg] = parent.arguments
|
|
25
|
+
if (firstArg) {
|
|
26
|
+
// Extract the function name from string literal
|
|
27
|
+
if (ts.isStringLiteral(firstArg)) {
|
|
28
|
+
const functionName = firstArg.text
|
|
29
|
+
logger.debug(`• Found RPC invocation: ${functionName}`)
|
|
30
|
+
state.rpc.invokedFunctions.add(functionName)
|
|
31
|
+
}
|
|
32
|
+
// Handle template literals like `function-${name}`
|
|
33
|
+
else if (
|
|
34
|
+
ts.isTemplateExpression(firstArg) ||
|
|
35
|
+
ts.isNoSubstitutionTemplateLiteral(firstArg)
|
|
36
|
+
) {
|
|
37
|
+
logger.warn(
|
|
38
|
+
`• Found dynamic RPC invocation: ${firstArg.getText()}`
|
|
39
|
+
)
|
|
40
|
+
logger.warn(
|
|
41
|
+
`\tYou can only use string literals for RPC function names, with ' or " and not \``
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/inspector.ts
CHANGED
|
@@ -36,11 +36,18 @@ export const inspect = (
|
|
|
36
36
|
functions: {
|
|
37
37
|
typesMap: new TypesMap(),
|
|
38
38
|
meta: {},
|
|
39
|
-
files: new Map(),
|
|
40
39
|
},
|
|
41
40
|
http: {
|
|
42
41
|
metaInputTypes: new Map(),
|
|
43
|
-
meta:
|
|
42
|
+
meta: {
|
|
43
|
+
get: {},
|
|
44
|
+
post: {},
|
|
45
|
+
put: {},
|
|
46
|
+
delete: {},
|
|
47
|
+
head: {},
|
|
48
|
+
patch: {},
|
|
49
|
+
options: {},
|
|
50
|
+
},
|
|
44
51
|
files: new Set(),
|
|
45
52
|
},
|
|
46
53
|
channels: {
|
|
@@ -56,7 +63,11 @@ export const inspect = (
|
|
|
56
63
|
files: new Set(),
|
|
57
64
|
},
|
|
58
65
|
rpc: {
|
|
59
|
-
|
|
66
|
+
internalMeta: {},
|
|
67
|
+
internalFiles: new Map(),
|
|
68
|
+
exposedMeta: {},
|
|
69
|
+
exposedFiles: new Map(),
|
|
70
|
+
invokedFunctions: new Set(),
|
|
60
71
|
},
|
|
61
72
|
mcpEndpoints: {
|
|
62
73
|
resourcesMeta: {},
|
|
@@ -64,6 +75,12 @@ export const inspect = (
|
|
|
64
75
|
promptsMeta: {},
|
|
65
76
|
files: new Set(),
|
|
66
77
|
},
|
|
78
|
+
middleware: {
|
|
79
|
+
meta: {},
|
|
80
|
+
},
|
|
81
|
+
permissions: {
|
|
82
|
+
meta: {},
|
|
83
|
+
},
|
|
67
84
|
}
|
|
68
85
|
|
|
69
86
|
// First sweep: add all functions
|
package/src/types.ts
CHANGED
|
@@ -4,8 +4,7 @@ import { ScheduledTasksMeta } from '@pikku/core/scheduler'
|
|
|
4
4
|
import { queueWorkersMeta } from '@pikku/core/queue'
|
|
5
5
|
import { MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from '@pikku/core'
|
|
6
6
|
import { TypesMap } from './types-map.js'
|
|
7
|
-
import { FunctionsMeta } from '@pikku/core'
|
|
8
|
-
import { RPCMeta } from '@pikku/core/rpc'
|
|
7
|
+
import { FunctionsMeta, FunctionServicesMeta } from '@pikku/core'
|
|
9
8
|
|
|
10
9
|
export type PathToNameAndType = Map<
|
|
11
10
|
string,
|
|
@@ -29,7 +28,6 @@ export interface InspectorHTTPState {
|
|
|
29
28
|
|
|
30
29
|
export interface InspectorFunctionState {
|
|
31
30
|
typesMap: TypesMap
|
|
32
|
-
files: Map<string, { path: string; exportedName: string }>
|
|
33
31
|
meta: FunctionsMeta
|
|
34
32
|
}
|
|
35
33
|
|
|
@@ -38,6 +36,30 @@ export interface InspectorChannelState {
|
|
|
38
36
|
files: Set<string>
|
|
39
37
|
}
|
|
40
38
|
|
|
39
|
+
export interface InspectorMiddlewareState {
|
|
40
|
+
meta: Record<
|
|
41
|
+
string,
|
|
42
|
+
{
|
|
43
|
+
services: FunctionServicesMeta
|
|
44
|
+
sourceFile: string
|
|
45
|
+
position: number
|
|
46
|
+
exportedName: string | null
|
|
47
|
+
}
|
|
48
|
+
>
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface InspectorPermissionState {
|
|
52
|
+
meta: Record<
|
|
53
|
+
string,
|
|
54
|
+
{
|
|
55
|
+
services: FunctionServicesMeta
|
|
56
|
+
sourceFile: string
|
|
57
|
+
position: number
|
|
58
|
+
exportedName: string | null
|
|
59
|
+
}
|
|
60
|
+
>
|
|
61
|
+
}
|
|
62
|
+
|
|
41
63
|
export type InspectorFilters = {
|
|
42
64
|
tags?: string[]
|
|
43
65
|
types?: string[]
|
|
@@ -69,7 +91,11 @@ export interface InspectorState {
|
|
|
69
91
|
files: Set<string>
|
|
70
92
|
}
|
|
71
93
|
rpc: {
|
|
72
|
-
|
|
94
|
+
internalMeta: Record<string, string>
|
|
95
|
+
internalFiles: Map<string, { path: string; exportedName: string }>
|
|
96
|
+
exposedMeta: Record<string, string>
|
|
97
|
+
exposedFiles: Map<string, { path: string; exportedName: string }>
|
|
98
|
+
invokedFunctions: Set<string> // Track functions called via rpc.invoke()
|
|
73
99
|
}
|
|
74
100
|
mcpEndpoints: {
|
|
75
101
|
resourcesMeta: MCPResourceMeta
|
|
@@ -77,4 +103,6 @@ export interface InspectorState {
|
|
|
77
103
|
promptsMeta: MCPPromptMeta
|
|
78
104
|
files: Set<string>
|
|
79
105
|
}
|
|
106
|
+
middleware: InspectorMiddlewareState
|
|
107
|
+
permissions: InspectorPermissionState
|
|
80
108
|
}
|
package/src/utils.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
2
|
import { InspectorFilters, InspectorLogger } from './types.js'
|
|
3
|
-
import { PikkuWiringTypes } from '@pikku/core'
|
|
3
|
+
import { PikkuWiringTypes, FunctionServicesMeta } from '@pikku/core'
|
|
4
4
|
|
|
5
5
|
type ExtractedFunctionName = {
|
|
6
6
|
pikkuFuncName: string
|
|
@@ -289,7 +289,7 @@ export function extractFunctionName(
|
|
|
289
289
|
const decls = resolvedSym.declarations ?? []
|
|
290
290
|
if (decls.length > 0) {
|
|
291
291
|
const decl = decls[0]!
|
|
292
|
-
// Check if the declaration is a variable that uses
|
|
292
|
+
// Check if the declaration is a variable that uses a pikkuFun
|
|
293
293
|
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
294
294
|
if (
|
|
295
295
|
ts.isCallExpression(decl.initializer) &&
|
|
@@ -321,6 +321,8 @@ export function extractFunctionName(
|
|
|
321
321
|
ts.isIdentifier(decl.name)
|
|
322
322
|
) {
|
|
323
323
|
result.exportedName = decl.name.text
|
|
324
|
+
// CRITICAL FIX: Use exported name as pikkuFuncName for consistency
|
|
325
|
+
result.pikkuFuncName = decl.name.text
|
|
324
326
|
} else if (ts.isIdentifier(decl.name)) {
|
|
325
327
|
// If not exported, still capture the variable name
|
|
326
328
|
result.localName = decl.name.text
|
|
@@ -717,6 +719,12 @@ export function extractFunctionName(
|
|
|
717
719
|
|
|
718
720
|
// Apply name priority logic
|
|
719
721
|
populateNameByPriority(result)
|
|
722
|
+
|
|
723
|
+
// CRITICAL FIX: If we have an exported name, use it as the pikkuFuncName for consistent lookup
|
|
724
|
+
if (result.exportedName && !result.explicitName) {
|
|
725
|
+
result.pikkuFuncName = result.exportedName
|
|
726
|
+
}
|
|
727
|
+
|
|
720
728
|
return result
|
|
721
729
|
}
|
|
722
730
|
|
|
@@ -910,3 +918,36 @@ export const matchesFilters = (
|
|
|
910
918
|
|
|
911
919
|
return true
|
|
912
920
|
}
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* Extract services from a function's first parameter destructuring pattern
|
|
924
|
+
*/
|
|
925
|
+
export function extractServicesFromFunction(
|
|
926
|
+
handlerNode: ts.FunctionExpression | ts.ArrowFunction
|
|
927
|
+
): FunctionServicesMeta {
|
|
928
|
+
const services: FunctionServicesMeta = {
|
|
929
|
+
optimized: true,
|
|
930
|
+
services: [],
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
const firstParam = handlerNode.parameters[0]
|
|
934
|
+
if (firstParam) {
|
|
935
|
+
if (ts.isObjectBindingPattern(firstParam.name)) {
|
|
936
|
+
for (const elem of firstParam.name.elements) {
|
|
937
|
+
const original =
|
|
938
|
+
elem.propertyName && ts.isIdentifier(elem.propertyName)
|
|
939
|
+
? elem.propertyName.text
|
|
940
|
+
: ts.isIdentifier(elem.name)
|
|
941
|
+
? elem.name.text
|
|
942
|
+
: undefined
|
|
943
|
+
if (original) {
|
|
944
|
+
services.services.push(original)
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
} else if (ts.isIdentifier(firstParam.name)) {
|
|
948
|
+
services.optimized = false
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
return services
|
|
953
|
+
}
|
package/src/visit.ts
CHANGED
|
@@ -10,6 +10,9 @@ import { addMCPPrompt } from './add-mcp-prompt.js'
|
|
|
10
10
|
import { InspectorFilters, InspectorState, InspectorLogger } from './types.js'
|
|
11
11
|
import { addFunctions } from './add-functions.js'
|
|
12
12
|
import { addChannel } from './add-channel.js'
|
|
13
|
+
import { addRPCInvocations } from './add-rpc-invocations.js'
|
|
14
|
+
import { addMiddleware } from './add-middleware.js'
|
|
15
|
+
import { addPermission } from './add-permission.js'
|
|
13
16
|
|
|
14
17
|
export const visitSetup = (
|
|
15
18
|
checker: ts.TypeChecker,
|
|
@@ -54,7 +57,7 @@ export const visitSetup = (
|
|
|
54
57
|
)
|
|
55
58
|
|
|
56
59
|
addFileWithFactory(node, checker, state.configFactories, 'CreateConfig')
|
|
57
|
-
|
|
60
|
+
addRPCInvocations(node, state, logger)
|
|
58
61
|
|
|
59
62
|
ts.forEachChild(node, (child) =>
|
|
60
63
|
visitSetup(checker, child, state, filters, logger)
|
|
@@ -68,6 +71,7 @@ export const visitRoutes = (
|
|
|
68
71
|
filters: InspectorFilters,
|
|
69
72
|
logger: InspectorLogger
|
|
70
73
|
) => {
|
|
74
|
+
addFunctions(node, checker, state, logger)
|
|
71
75
|
addHTTPRoute(node, checker, state, filters, logger)
|
|
72
76
|
addSchedule(node, checker, state, filters, logger)
|
|
73
77
|
addQueueWorker(node, checker, state, filters, logger)
|
|
@@ -75,6 +79,9 @@ export const visitRoutes = (
|
|
|
75
79
|
addMCPResource(node, checker, state, filters, logger)
|
|
76
80
|
addMCPTool(node, checker, state, filters, logger)
|
|
77
81
|
addMCPPrompt(node, checker, state, filters, logger)
|
|
82
|
+
addMiddleware(node, checker, state, logger)
|
|
83
|
+
addPermission(node, checker, state, logger)
|
|
84
|
+
|
|
78
85
|
ts.forEachChild(node, (child) =>
|
|
79
86
|
visitRoutes(checker, child, state, filters, logger)
|
|
80
87
|
)
|