@pikku/inspector 0.9.5 → 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 +14 -0
- package/dist/add/add-channel.d.ts +17 -0
- package/dist/{add-channel.js → add/add-channel.js} +60 -34
- package/dist/add/add-cli.d.ts +9 -0
- package/dist/add/add-cli.js +566 -0
- package/dist/{add-file-extends-core-type.d.ts → add/add-file-extends-core-type.d.ts} +2 -2
- package/dist/{add-file-extends-core-type.js → add/add-file-extends-core-type.js} +17 -4
- package/dist/{add-file-with-config.d.ts → add/add-file-with-config.d.ts} +1 -1
- package/dist/{add-file-with-config.js → add/add-file-with-config.js} +1 -1
- package/dist/{add-file-with-factory.d.ts → add/add-file-with-factory.d.ts} +2 -2
- package/dist/{add-file-with-factory.js → add/add-file-with-factory.js} +38 -5
- package/dist/add/add-functions.d.ts +6 -0
- package/dist/{add-functions.js → add/add-functions.js} +77 -10
- package/dist/{add-http-route.d.ts → add/add-http-route.d.ts} +2 -3
- package/dist/{add-http-route.js → add/add-http-route.js} +26 -13
- package/dist/add/add-mcp-prompt.d.ts +2 -0
- package/dist/add/add-mcp-prompt.js +74 -0
- package/dist/add/add-mcp-resource.d.ts +2 -0
- package/dist/add/add-mcp-resource.js +84 -0
- package/dist/add/add-mcp-tool.d.ts +2 -0
- package/dist/add/add-mcp-tool.js +80 -0
- package/dist/add/add-middleware.d.ts +5 -0
- package/dist/add/add-middleware.js +290 -0
- package/dist/add/add-permission.d.ts +5 -0
- package/dist/add/add-permission.js +292 -0
- package/dist/add/add-queue-worker.d.ts +2 -0
- package/dist/add/add-queue-worker.js +52 -0
- package/dist/{add-rpc-invocations.d.ts → add/add-rpc-invocations.d.ts} +1 -1
- package/dist/add/add-schedule.d.ts +2 -0
- package/dist/{add-schedule.js → add/add-schedule.js} +16 -11
- package/dist/error-codes.d.ts +35 -0
- package/dist/error-codes.js +40 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/inspector.d.ts +2 -3
- package/dist/inspector.js +38 -8
- package/dist/types.d.ts +108 -1
- 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 +31 -0
- package/dist/{utils.js → utils/extract-function-name.js} +35 -149
- package/dist/utils/extract-services.d.ts +6 -0
- package/dist/utils/extract-services.js +29 -0
- 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 +19 -0
- package/dist/utils/filter-utils.js +109 -0
- 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 +22 -0
- package/dist/utils/get-files-and-methods.js +61 -0
- package/dist/utils/get-property-value.d.ts +12 -0
- package/dist/{get-property-value.js → utils/get-property-value.js} +20 -0
- package/dist/utils/middleware.d.ts +39 -0
- package/dist/utils/middleware.js +157 -0
- 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/utils/type-utils.d.ts +3 -0
- package/dist/utils/type-utils.js +50 -0
- package/dist/visit.d.ts +3 -3
- package/dist/visit.js +35 -31
- package/package.json +5 -6
- package/src/{add-channel.ts → add/add-channel.ts} +108 -56
- package/src/add/add-cli.ts +822 -0
- package/src/{add-file-extends-core-type.ts → add/add-file-extends-core-type.ts} +23 -5
- package/src/{add-file-with-config.ts → add/add-file-with-config.ts} +2 -2
- package/src/{add-file-with-factory.ts → add/add-file-with-factory.ts} +49 -6
- package/src/{add-functions.ts → add/add-functions.ts} +89 -19
- package/src/{add-http-route.ts → add/add-http-route.ts} +66 -32
- package/src/add/add-mcp-prompt.ts +128 -0
- package/src/add/add-mcp-prompt.ts.tmp +0 -0
- package/src/add/add-mcp-resource.ts +145 -0
- package/src/add/add-mcp-resource.ts.tmp +0 -0
- package/src/add/add-mcp-tool.ts +137 -0
- package/src/add/add-middleware.ts +385 -0
- package/src/add/add-permission.ts +391 -0
- package/src/add/add-queue-worker.ts +92 -0
- package/src/{add-rpc-invocations.ts → add/add-rpc-invocations.ts} +1 -1
- package/src/{add-schedule.ts → add/add-schedule.ts} +30 -28
- package/src/error-codes.ts +43 -0
- package/src/index.ts +12 -0
- package/src/inspector.ts +41 -17
- package/src/types.ts +128 -1
- package/src/utils/ensure-function-metadata.ts +24 -0
- package/src/{utils.ts → utils/extract-function-name.ts} +44 -206
- package/src/utils/extract-services.ts +35 -0
- package/src/utils/filter-inspector-state.test.ts +1433 -0
- package/src/utils/filter-inspector-state.ts +526 -0
- package/src/{utils.test.ts → utils/filter-utils.test.ts} +351 -2
- package/src/utils/filter-utils.ts +152 -0
- package/src/utils/find-root-dir.ts +68 -0
- package/src/utils/get-files-and-methods.ts +151 -0
- package/src/{get-property-value.ts → utils/get-property-value.ts} +27 -0
- package/src/utils/middleware.ts +241 -0
- 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/utils/type-utils.ts +74 -0
- package/src/visit.ts +50 -34
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/add-channel.d.ts +0 -13
- package/dist/add-functions.d.ts +0 -7
- package/dist/add-mcp-prompt.d.ts +0 -3
- package/dist/add-mcp-prompt.js +0 -61
- package/dist/add-mcp-resource.d.ts +0 -3
- package/dist/add-mcp-resource.js +0 -68
- package/dist/add-mcp-tool.d.ts +0 -3
- package/dist/add-mcp-tool.js +0 -64
- package/dist/add-middleware.d.ts +0 -7
- package/dist/add-middleware.js +0 -35
- package/dist/add-permission.d.ts +0 -7
- package/dist/add-permission.js +0 -35
- package/dist/add-queue-worker.d.ts +0 -3
- package/dist/add-queue-worker.js +0 -48
- package/dist/add-schedule.d.ts +0 -3
- package/dist/get-property-value.d.ts +0 -3
- package/dist/utils.d.ts +0 -39
- package/src/add-mcp-prompt.ts +0 -104
- package/src/add-mcp-resource.ts +0 -116
- package/src/add-mcp-tool.ts +0 -107
- package/src/add-middleware.ts +0 -51
- package/src/add-permission.ts +0 -53
- package/src/add-queue-worker.ts +0 -92
- /package/dist/{add-rpc-invocations.js → add/add-rpc-invocations.js} +0 -0
- /package/dist/{does-type-extend-core-type.d.ts → utils/does-type-extend-core-type.d.ts} +0 -0
- /package/dist/{does-type-extend-core-type.js → utils/does-type-extend-core-type.js} +0 -0
- /package/src/{does-type-extend-core-type.ts → utils/does-type-extend-core-type.ts} +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
|
|
2
|
+
import { extractServicesFromFunction } from '../utils/extract-services.js';
|
|
3
|
+
export const addFileWithFactory = (node, checker, methods = new Map(), expectedTypeName, state) => {
|
|
3
4
|
if (ts.isVariableDeclaration(node)) {
|
|
4
5
|
const fileName = node.getSourceFile().fileName;
|
|
5
6
|
const variableTypeNode = node.type;
|
|
@@ -16,13 +17,29 @@ export const addFileWithFactory = (node, checker, methods = new Map(), expectedT
|
|
|
16
17
|
const sourceFile = declaration.getSourceFile();
|
|
17
18
|
typeDeclarationPath = sourceFile.fileName; // Get the path of the file where the type was declared
|
|
18
19
|
}
|
|
19
|
-
const variables = methods
|
|
20
|
+
const variables = methods.get(fileName) || [];
|
|
20
21
|
variables.push({
|
|
21
22
|
variable: variableName,
|
|
22
23
|
type: typeNameNode.getText(),
|
|
23
24
|
typePath: typeDeclarationPath,
|
|
24
25
|
});
|
|
25
|
-
methods
|
|
26
|
+
methods.set(fileName, variables);
|
|
27
|
+
// Extract singleton services for CreateSessionServices factories
|
|
28
|
+
if (expectedTypeName === 'CreateSessionServices' &&
|
|
29
|
+
state &&
|
|
30
|
+
node.initializer) {
|
|
31
|
+
let functionNode;
|
|
32
|
+
if (ts.isArrowFunction(node.initializer)) {
|
|
33
|
+
functionNode = node.initializer;
|
|
34
|
+
}
|
|
35
|
+
else if (ts.isFunctionExpression(node.initializer)) {
|
|
36
|
+
functionNode = node.initializer;
|
|
37
|
+
}
|
|
38
|
+
if (functionNode) {
|
|
39
|
+
const servicesMeta = extractServicesFromFunction(functionNode);
|
|
40
|
+
state.sessionServicesMeta.set(variableName, servicesMeta.services);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
26
43
|
}
|
|
27
44
|
// Handle qualified type names if necessary
|
|
28
45
|
else if (ts.isQualifiedName(typeNameNode)) {
|
|
@@ -34,13 +51,29 @@ export const addFileWithFactory = (node, checker, methods = new Map(), expectedT
|
|
|
34
51
|
const sourceFile = declaration.getSourceFile();
|
|
35
52
|
typeDeclarationPath = sourceFile.fileName; // Get the path of the file where the type was declared
|
|
36
53
|
}
|
|
37
|
-
const variables = methods
|
|
54
|
+
const variables = methods.get(fileName) || [];
|
|
38
55
|
variables.push({
|
|
39
56
|
variable: variableName,
|
|
40
57
|
type: typeNameNode.getText(),
|
|
41
58
|
typePath: typeDeclarationPath,
|
|
42
59
|
});
|
|
43
|
-
methods
|
|
60
|
+
methods.set(fileName, variables);
|
|
61
|
+
// Extract singleton services for CreateSessionServices factories
|
|
62
|
+
if (expectedTypeName === 'CreateSessionServices' &&
|
|
63
|
+
state &&
|
|
64
|
+
node.initializer) {
|
|
65
|
+
let functionNode;
|
|
66
|
+
if (ts.isArrowFunction(node.initializer)) {
|
|
67
|
+
functionNode = node.initializer;
|
|
68
|
+
}
|
|
69
|
+
else if (ts.isFunctionExpression(node.initializer)) {
|
|
70
|
+
functionNode = node.initializer;
|
|
71
|
+
}
|
|
72
|
+
if (functionNode) {
|
|
73
|
+
const servicesMeta = extractServicesFromFunction(functionNode);
|
|
74
|
+
state.sessionServicesMeta.set(variableName, servicesMeta.services);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
44
77
|
}
|
|
45
78
|
}
|
|
46
79
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { extractFunctionName
|
|
3
|
-
import {
|
|
2
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
3
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
4
|
+
import { getPropertyValue } from '../utils/get-property-value.js';
|
|
5
|
+
import { resolveMiddleware } from '../utils/middleware.js';
|
|
4
6
|
const isValidVariableName = (name) => {
|
|
5
7
|
const regex = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
6
8
|
return regex.test(name);
|
|
@@ -14,7 +16,7 @@ const nullifyTypes = (type) => {
|
|
|
14
16
|
}
|
|
15
17
|
return type;
|
|
16
18
|
};
|
|
17
|
-
const resolveTypeImports = (type, resolvedTypes, isCustom) => {
|
|
19
|
+
const resolveTypeImports = (type, resolvedTypes, isCustom, checker) => {
|
|
18
20
|
const types = [];
|
|
19
21
|
const visitType = (currentType) => {
|
|
20
22
|
const symbol = currentType.aliasSymbol || currentType.getSymbol();
|
|
@@ -25,9 +27,12 @@ const resolveTypeImports = (type, resolvedTypes, isCustom) => {
|
|
|
25
27
|
const sourceFile = declaration.getSourceFile();
|
|
26
28
|
const path = sourceFile.fileName;
|
|
27
29
|
// Skip built-in utility types or TypeScript lib types
|
|
30
|
+
// Skip enum members (but not the enum type itself)
|
|
31
|
+
const isEnumMember = declaration && ts.isEnumMember(declaration);
|
|
28
32
|
if (!path.includes('node_modules/typescript') &&
|
|
29
33
|
symbol.getName() !== '__type' &&
|
|
30
|
-
!isPrimitiveType(currentType)
|
|
34
|
+
!isPrimitiveType(currentType) &&
|
|
35
|
+
!isEnumMember) {
|
|
31
36
|
const originalName = symbol.getName();
|
|
32
37
|
// Check if the type is already in the map
|
|
33
38
|
let uniqueName = resolvedTypes.exists(originalName, path);
|
|
@@ -74,6 +79,26 @@ const resolveTypeImports = (type, resolvedTypes, isCustom) => {
|
|
|
74
79
|
const typeRef = currentType;
|
|
75
80
|
typeRef.typeArguments?.forEach(visitType);
|
|
76
81
|
}
|
|
82
|
+
// Handle anonymous object types with enum properties (e.g., { userType: UserType })
|
|
83
|
+
// Only traverse into enum property types to avoid over-importing other named types
|
|
84
|
+
if (currentType.flags & ts.TypeFlags.Object) {
|
|
85
|
+
const objectType = currentType;
|
|
86
|
+
const typeSymbol = objectType.getSymbol();
|
|
87
|
+
// Only traverse properties for anonymous object types (no symbol or __type symbol)
|
|
88
|
+
// Skip named types, interfaces, and enums to avoid over-importing
|
|
89
|
+
const isAnonymousObject = !typeSymbol || typeSymbol.getName() === '__type';
|
|
90
|
+
if (isAnonymousObject) {
|
|
91
|
+
const properties = objectType.getProperties();
|
|
92
|
+
for (const prop of properties) {
|
|
93
|
+
if (prop.valueDeclaration) {
|
|
94
|
+
const propType = checker.getTypeOfSymbolAtLocation(prop, prop.valueDeclaration);
|
|
95
|
+
if (propType) {
|
|
96
|
+
visitType(propType);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
77
102
|
};
|
|
78
103
|
visitType(type);
|
|
79
104
|
return types;
|
|
@@ -123,7 +148,7 @@ const getNamesAndTypes = (checker, typesMap, direction, funcName, type) => {
|
|
|
123
148
|
const aliasName = funcName.charAt(0).toUpperCase() + funcName.slice(1) + direction;
|
|
124
149
|
// record the alias in your TypesMap
|
|
125
150
|
const references = rawTypes
|
|
126
|
-
.map((t) => resolveTypeImports(t, typesMap, true))
|
|
151
|
+
.map((t) => resolveTypeImports(t, typesMap, true, checker))
|
|
127
152
|
.flat();
|
|
128
153
|
typesMap.addCustomType(aliasName, aliasType, references);
|
|
129
154
|
return {
|
|
@@ -142,7 +167,7 @@ const getNamesAndTypes = (checker, typesMap, direction, funcName, type) => {
|
|
|
142
167
|
return name;
|
|
143
168
|
}
|
|
144
169
|
// non-primitive: import/alias it inline
|
|
145
|
-
return resolveTypeImports(t, typesMap, false);
|
|
170
|
+
return resolveTypeImports(t, typesMap, false, checker);
|
|
146
171
|
})
|
|
147
172
|
.flat();
|
|
148
173
|
return {
|
|
@@ -186,7 +211,7 @@ function unwrapPromise(checker, type) {
|
|
|
186
211
|
* Inspect pikkuFunc calls, extract input/output and first-arg destructuring,
|
|
187
212
|
* then push into state.functions.meta.
|
|
188
213
|
*/
|
|
189
|
-
export
|
|
214
|
+
export const addFunctions = (logger, node, checker, state) => {
|
|
190
215
|
if (!ts.isCallExpression(node))
|
|
191
216
|
return;
|
|
192
217
|
const { expression, arguments: args, typeArguments } = node;
|
|
@@ -205,16 +230,18 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
205
230
|
}
|
|
206
231
|
if (args.length === 0)
|
|
207
232
|
return;
|
|
208
|
-
const { pikkuFuncName, name, explicitName, exportedName } = extractFunctionName(node, checker);
|
|
233
|
+
const { pikkuFuncName, name, explicitName, exportedName } = extractFunctionName(node, checker, state.rootDir);
|
|
209
234
|
let tags;
|
|
210
235
|
let expose;
|
|
211
236
|
let docs;
|
|
237
|
+
let objectNode;
|
|
212
238
|
// determine the actual handler expression:
|
|
213
239
|
// either the `func` prop or the first argument directly
|
|
214
240
|
let handlerNode = args[0];
|
|
215
241
|
let isDirectFunction = true; // Default to direct function format
|
|
216
242
|
if (ts.isObjectLiteralExpression(handlerNode)) {
|
|
217
243
|
isDirectFunction = false; // This is object format with func property
|
|
244
|
+
objectNode = handlerNode;
|
|
218
245
|
tags = getPropertyValue(handlerNode, 'tags') || undefined;
|
|
219
246
|
expose = getPropertyValue(handlerNode, 'expose');
|
|
220
247
|
docs = getPropertyValue(handlerNode, 'docs');
|
|
@@ -222,6 +249,17 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
222
249
|
if (!fnProp ||
|
|
223
250
|
(!ts.isArrowFunction(fnProp) && !ts.isFunctionExpression(fnProp))) {
|
|
224
251
|
logger.error(`• No valid 'func' property found for ${pikkuFuncName}.`);
|
|
252
|
+
// Create stub metadata to prevent "function not found" errors in wirings
|
|
253
|
+
state.functions.meta[pikkuFuncName] = {
|
|
254
|
+
pikkuFuncName,
|
|
255
|
+
name,
|
|
256
|
+
services: { optimized: false, services: [] },
|
|
257
|
+
inputSchemaName: null,
|
|
258
|
+
outputSchemaName: null,
|
|
259
|
+
inputs: [],
|
|
260
|
+
outputs: [],
|
|
261
|
+
middleware: undefined,
|
|
262
|
+
};
|
|
225
263
|
return;
|
|
226
264
|
}
|
|
227
265
|
handlerNode = fnProp;
|
|
@@ -229,6 +267,17 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
229
267
|
if (!ts.isArrowFunction(handlerNode) &&
|
|
230
268
|
!ts.isFunctionExpression(handlerNode)) {
|
|
231
269
|
logger.error(`• Handler for ${name} is not a function.`);
|
|
270
|
+
// Create stub metadata to prevent "function not found" errors in wirings
|
|
271
|
+
state.functions.meta[pikkuFuncName] = {
|
|
272
|
+
pikkuFuncName,
|
|
273
|
+
name,
|
|
274
|
+
services: { optimized: false, services: [] },
|
|
275
|
+
inputSchemaName: null,
|
|
276
|
+
outputSchemaName: null,
|
|
277
|
+
inputs: [],
|
|
278
|
+
outputs: [],
|
|
279
|
+
middleware: undefined,
|
|
280
|
+
};
|
|
232
281
|
return;
|
|
233
282
|
}
|
|
234
283
|
const services = {
|
|
@@ -258,7 +307,7 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
258
307
|
.map((tn) => checker.getTypeFromTypeNode(tn))
|
|
259
308
|
.map((t) => unwrapPromise(checker, t));
|
|
260
309
|
// --- Input Extraction ---
|
|
261
|
-
let { names: inputNames } = getNamesAndTypes(checker, state.functions.typesMap, 'Input', name, genericTypes[0]);
|
|
310
|
+
let { names: inputNames, types: inputTypes } = getNamesAndTypes(checker, state.functions.typesMap, 'Input', name, genericTypes[0]);
|
|
262
311
|
// if (inputTypes.length === 0) {
|
|
263
312
|
// logger.debug(
|
|
264
313
|
// `\x1b[31m• Unknown input type for '${name}', assuming void.\x1b[0m`
|
|
@@ -280,6 +329,10 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
280
329
|
if (inputNames.length > 1) {
|
|
281
330
|
logger.warn('More than one input type detected, only the first one will be used as a schema.');
|
|
282
331
|
}
|
|
332
|
+
// --- resolve middleware ---
|
|
333
|
+
const middleware = objectNode
|
|
334
|
+
? resolveMiddleware(state, objectNode, tags, checker)
|
|
335
|
+
: undefined;
|
|
283
336
|
state.functions.meta[pikkuFuncName] = {
|
|
284
337
|
pikkuFuncName,
|
|
285
338
|
name,
|
|
@@ -292,7 +345,19 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
292
345
|
tags: tags || undefined,
|
|
293
346
|
docs: docs || undefined,
|
|
294
347
|
isDirectFunction,
|
|
348
|
+
middleware,
|
|
295
349
|
};
|
|
350
|
+
// Store the input type for later use
|
|
351
|
+
if (inputTypes.length > 0) {
|
|
352
|
+
state.typesLookup.set(pikkuFuncName, inputTypes);
|
|
353
|
+
}
|
|
354
|
+
// Store function file location for wiring generation
|
|
355
|
+
if (exportedName) {
|
|
356
|
+
state.functions.files.set(pikkuFuncName, {
|
|
357
|
+
path: node.getSourceFile().fileName,
|
|
358
|
+
exportedName,
|
|
359
|
+
});
|
|
360
|
+
}
|
|
296
361
|
if (exportedName || explicitName) {
|
|
297
362
|
if (!exportedName) {
|
|
298
363
|
logger.error(`• Function with explicit name '${name}' is not exported, this is not allowed.`);
|
|
@@ -304,6 +369,8 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
304
369
|
path: node.getSourceFile().fileName,
|
|
305
370
|
exportedName,
|
|
306
371
|
});
|
|
372
|
+
// Track exposed RPC function for service aggregation
|
|
373
|
+
state.serviceAggregation.usedFunctions.add(pikkuFuncName);
|
|
307
374
|
}
|
|
308
375
|
// We add it to internal meta to allow autocomplete for everything
|
|
309
376
|
state.rpc.internalMeta[name] = pikkuFuncName;
|
|
@@ -316,4 +383,4 @@ export function addFunctions(node, checker, state, logger) {
|
|
|
316
383
|
});
|
|
317
384
|
}
|
|
318
385
|
}
|
|
319
|
-
}
|
|
386
|
+
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { InspectorState, InspectorFilters, InspectorLogger } from './types.js';
|
|
1
|
+
import { AddWiring } from '../types.js';
|
|
3
2
|
/**
|
|
4
3
|
* Populate metaInputTypes for a given route based on method, input type,
|
|
5
4
|
* query and params. Returns undefined (we only mutate metaTypes).
|
|
@@ -13,4 +12,4 @@ export declare const getInputTypes: (metaTypes: Map<string, {
|
|
|
13
12
|
* Simplified wireHTTP: re-uses function metadata from state.functions.meta
|
|
14
13
|
* instead of re-inferring types here.
|
|
15
14
|
*/
|
|
16
|
-
export declare const addHTTPRoute:
|
|
15
|
+
export declare const addHTTPRoute: AddWiring;
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { getPropertyValue } from '
|
|
2
|
+
import { getPropertyValue, getPropertyTags, } from '../utils/get-property-value.js';
|
|
3
3
|
import { pathToRegexp } from 'path-to-regexp';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
5
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
6
|
+
import { resolveHTTPMiddlewareFromObject } from '../utils/middleware.js';
|
|
7
|
+
import { resolveHTTPPermissionsFromObject } from '../utils/permissions.js';
|
|
8
|
+
import { extractWireNames } from '../utils/post-process.js';
|
|
9
|
+
import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js';
|
|
10
|
+
import { ErrorCode } from '../error-codes.js';
|
|
6
11
|
/**
|
|
7
12
|
* Populate metaInputTypes for a given route based on method, input type,
|
|
8
13
|
* query and params. Returns undefined (we only mutate metaTypes).
|
|
@@ -23,7 +28,7 @@ export const getInputTypes = (metaTypes, methodType, inputType, queryValues, par
|
|
|
23
28
|
* Simplified wireHTTP: re-uses function metadata from state.functions.meta
|
|
24
29
|
* instead of re-inferring types here.
|
|
25
30
|
*/
|
|
26
|
-
export const addHTTPRoute = (node, checker, state,
|
|
31
|
+
export const addHTTPRoute = (logger, node, checker, state, options) => {
|
|
27
32
|
// only look at calls
|
|
28
33
|
if (!ts.isCallExpression(node))
|
|
29
34
|
return;
|
|
@@ -43,28 +48,34 @@ export const addHTTPRoute = (node, checker, state, filters, logger) => {
|
|
|
43
48
|
const params = keys.filter((k) => k.type === 'param').map((k) => k.name);
|
|
44
49
|
const method = getPropertyValue(obj, 'method')?.toLowerCase() || 'get';
|
|
45
50
|
const docs = getPropertyValue(obj, 'docs') || undefined;
|
|
46
|
-
const tags =
|
|
51
|
+
const tags = getPropertyTags(obj, 'HTTP route', route, logger);
|
|
47
52
|
const query = getPropertyValue(obj, 'query') || [];
|
|
48
|
-
|
|
49
|
-
if (!matchesFilters(filters, { tags }, { type: PikkuWiringTypes.http, name: route, filePath }, logger)) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
// --- find the referenced function ---
|
|
53
|
+
// --- find the referenced function name first for filtering ---
|
|
53
54
|
const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
|
|
54
55
|
if (!funcInitializer) {
|
|
55
|
-
|
|
56
|
+
logger.critical(ErrorCode.MISSING_FUNC, `No valid 'func' property for route '${route}'.`);
|
|
56
57
|
return;
|
|
57
58
|
}
|
|
58
|
-
const funcName = extractFunctionName(funcInitializer, checker).pikkuFuncName;
|
|
59
|
+
const funcName = extractFunctionName(funcInitializer, checker, state.rootDir).pikkuFuncName;
|
|
60
|
+
// Ensure function metadata exists (creates stub for inline functions)
|
|
61
|
+
ensureFunctionMetadata(state, funcName, route);
|
|
59
62
|
// lookup existing function metadata
|
|
60
63
|
const fnMeta = state.functions.meta[funcName];
|
|
61
64
|
if (!fnMeta) {
|
|
62
|
-
|
|
65
|
+
logger.critical(ErrorCode.FUNCTION_METADATA_NOT_FOUND, `No function metadata found for '${funcName}'.`);
|
|
63
66
|
return;
|
|
64
67
|
}
|
|
65
68
|
const input = fnMeta.inputs?.[0] || null;
|
|
66
69
|
// --- compute inputTypes (body/query/params) ---
|
|
67
70
|
const inputTypes = getInputTypes(state.http.metaInputTypes, method, input, query, params);
|
|
71
|
+
// --- resolve middleware ---
|
|
72
|
+
const middleware = resolveHTTPMiddlewareFromObject(state, route, obj, tags, checker);
|
|
73
|
+
// --- resolve permissions ---
|
|
74
|
+
const permissions = resolveHTTPPermissionsFromObject(state, route, obj, tags, checker);
|
|
75
|
+
// --- track used functions/middleware/permissions for service aggregation ---
|
|
76
|
+
state.serviceAggregation.usedFunctions.add(funcName);
|
|
77
|
+
extractWireNames(middleware).forEach((name) => state.serviceAggregation.usedMiddleware.add(name));
|
|
78
|
+
extractWireNames(permissions).forEach((name) => state.serviceAggregation.usedPermissions.add(name));
|
|
68
79
|
// --- record route ---
|
|
69
80
|
state.http.files.add(node.getSourceFile().fileName);
|
|
70
81
|
state.http.meta[method][route] = {
|
|
@@ -76,5 +87,7 @@ export const addHTTPRoute = (node, checker, state, filters, logger) => {
|
|
|
76
87
|
inputTypes,
|
|
77
88
|
docs,
|
|
78
89
|
tags,
|
|
90
|
+
middleware,
|
|
91
|
+
permissions,
|
|
79
92
|
};
|
|
80
93
|
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyValue, getPropertyTags, } from '../utils/get-property-value.js';
|
|
3
|
+
import { extractWireNames } from '../utils/post-process.js';
|
|
4
|
+
import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js';
|
|
5
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
6
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
7
|
+
import { resolveMiddleware } from '../utils/middleware.js';
|
|
8
|
+
import { resolvePermissions } from '../utils/permissions.js';
|
|
9
|
+
import { ErrorCode } from '../error-codes.js';
|
|
10
|
+
export const addMCPPrompt = (logger, node, checker, state, options) => {
|
|
11
|
+
if (!ts.isCallExpression(node)) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const args = node.arguments;
|
|
15
|
+
const firstArg = args[0];
|
|
16
|
+
const expression = node.expression;
|
|
17
|
+
// Check if the call is to wireMCPPrompt
|
|
18
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'wireMCPPrompt') {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!firstArg) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
25
|
+
const obj = firstArg;
|
|
26
|
+
const nameValue = getPropertyValue(obj, 'name');
|
|
27
|
+
const descriptionValue = getPropertyValue(obj, 'description');
|
|
28
|
+
const tags = getPropertyTags(obj, 'MCP prompt', nameValue, logger);
|
|
29
|
+
const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
|
|
30
|
+
if (!funcInitializer) {
|
|
31
|
+
logger.critical(ErrorCode.MISSING_FUNC, `No valid 'func' property for MCP prompt '${nameValue}'.`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const pikkuFuncName = extractFunctionName(funcInitializer, checker, state.rootDir).pikkuFuncName;
|
|
35
|
+
// Ensure function metadata exists (creates stub for inline functions)
|
|
36
|
+
ensureFunctionMetadata(state, pikkuFuncName, nameValue || undefined);
|
|
37
|
+
if (!nameValue) {
|
|
38
|
+
logger.critical(ErrorCode.MISSING_NAME, "MCP prompt is missing the required 'name' property.");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (!descriptionValue) {
|
|
42
|
+
logger.critical(ErrorCode.MISSING_DESCRIPTION, `MCP prompt '${nameValue}' is missing a description.`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// lookup existing function metadata
|
|
46
|
+
const fnMeta = state.functions.meta[pikkuFuncName];
|
|
47
|
+
if (!fnMeta) {
|
|
48
|
+
logger.critical(ErrorCode.FUNCTION_METADATA_NOT_FOUND, `No function metadata found for '${pikkuFuncName}'.`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
52
|
+
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
53
|
+
// --- resolve middleware ---
|
|
54
|
+
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
55
|
+
// --- resolve permissions ---
|
|
56
|
+
const permissions = resolvePermissions(state, obj, tags, checker);
|
|
57
|
+
// --- track used functions/middleware/permissions for service aggregation ---
|
|
58
|
+
state.serviceAggregation.usedFunctions.add(pikkuFuncName);
|
|
59
|
+
extractWireNames(middleware).forEach((name) => state.serviceAggregation.usedMiddleware.add(name));
|
|
60
|
+
extractWireNames(permissions).forEach((name) => state.serviceAggregation.usedPermissions.add(name));
|
|
61
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
62
|
+
state.mcpEndpoints.promptsMeta[nameValue] = {
|
|
63
|
+
pikkuFuncName,
|
|
64
|
+
name: nameValue,
|
|
65
|
+
description: descriptionValue,
|
|
66
|
+
tags,
|
|
67
|
+
inputSchema,
|
|
68
|
+
outputSchema,
|
|
69
|
+
arguments: [], // Will be populated by CLI during serialization
|
|
70
|
+
middleware,
|
|
71
|
+
permissions,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyValue, getPropertyTags, } from '../utils/get-property-value.js';
|
|
3
|
+
import { extractWireNames } from '../utils/post-process.js';
|
|
4
|
+
import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js';
|
|
5
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
6
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
7
|
+
import { resolveMiddleware } from '../utils/middleware.js';
|
|
8
|
+
import { resolvePermissions } from '../utils/permissions.js';
|
|
9
|
+
import { ErrorCode } from '../error-codes.js';
|
|
10
|
+
export const addMCPResource = (logger, node, checker, state, options) => {
|
|
11
|
+
if (!ts.isCallExpression(node)) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const args = node.arguments;
|
|
15
|
+
const firstArg = args[0];
|
|
16
|
+
const expression = node.expression;
|
|
17
|
+
// Check if the call is to wireMCPResource
|
|
18
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'wireMCPResource') {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!firstArg) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
25
|
+
const obj = firstArg;
|
|
26
|
+
const uriValue = getPropertyValue(obj, 'uri');
|
|
27
|
+
const titleValue = getPropertyValue(obj, 'title');
|
|
28
|
+
const descriptionValue = getPropertyValue(obj, 'description');
|
|
29
|
+
const streamingValue = getPropertyValue(obj, 'streaming');
|
|
30
|
+
const tags = getPropertyTags(obj, 'MCP resource', uriValue, logger);
|
|
31
|
+
if (streamingValue === true) {
|
|
32
|
+
logger.warn(`MCP resource '${uriValue}' has streaming enabled, but streaming is not yet supported.`);
|
|
33
|
+
}
|
|
34
|
+
const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
|
|
35
|
+
if (!funcInitializer) {
|
|
36
|
+
logger.critical(ErrorCode.MISSING_FUNC, `No valid 'func' property for MCP resource '${uriValue}'.`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const pikkuFuncName = extractFunctionName(funcInitializer, checker, state.rootDir).pikkuFuncName;
|
|
40
|
+
// Ensure function metadata exists (creates stub for inline functions)
|
|
41
|
+
ensureFunctionMetadata(state, pikkuFuncName, uriValue || undefined);
|
|
42
|
+
if (!uriValue) {
|
|
43
|
+
logger.critical(ErrorCode.MISSING_URI, "MCP resource is missing the required 'uri' property.");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (!titleValue) {
|
|
47
|
+
logger.critical(ErrorCode.MISSING_TITLE, `MCP resource '${uriValue}' is missing the required 'title' property.`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (!descriptionValue) {
|
|
51
|
+
logger.critical(ErrorCode.MISSING_DESCRIPTION, `MCP resource '${uriValue}' is missing a description.`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// lookup existing function metadata
|
|
55
|
+
const fnMeta = state.functions.meta[pikkuFuncName];
|
|
56
|
+
if (!fnMeta) {
|
|
57
|
+
logger.critical(ErrorCode.FUNCTION_METADATA_NOT_FOUND, `No function metadata found for '${pikkuFuncName}'.`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
61
|
+
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
62
|
+
// --- resolve middleware ---
|
|
63
|
+
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
64
|
+
// --- resolve permissions ---
|
|
65
|
+
const permissions = resolvePermissions(state, obj, tags, checker);
|
|
66
|
+
// --- track used functions/middleware/permissions for service aggregation ---
|
|
67
|
+
state.serviceAggregation.usedFunctions.add(pikkuFuncName);
|
|
68
|
+
extractWireNames(middleware).forEach((name) => state.serviceAggregation.usedMiddleware.add(name));
|
|
69
|
+
extractWireNames(permissions).forEach((name) => state.serviceAggregation.usedPermissions.add(name));
|
|
70
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
71
|
+
state.mcpEndpoints.resourcesMeta[uriValue] = {
|
|
72
|
+
pikkuFuncName,
|
|
73
|
+
uri: uriValue,
|
|
74
|
+
title: titleValue,
|
|
75
|
+
description: descriptionValue,
|
|
76
|
+
...(streamingValue !== null && { streaming: streamingValue }),
|
|
77
|
+
tags,
|
|
78
|
+
inputSchema,
|
|
79
|
+
outputSchema,
|
|
80
|
+
middleware,
|
|
81
|
+
permissions,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { getPropertyValue, getPropertyTags, } from '../utils/get-property-value.js';
|
|
3
|
+
import { extractWireNames } from '../utils/post-process.js';
|
|
4
|
+
import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js';
|
|
5
|
+
import { extractFunctionName } from '../utils/extract-function-name.js';
|
|
6
|
+
import { getPropertyAssignmentInitializer } from '../utils/type-utils.js';
|
|
7
|
+
import { resolveMiddleware } from '../utils/middleware.js';
|
|
8
|
+
import { resolvePermissions } from '../utils/permissions.js';
|
|
9
|
+
import { ErrorCode } from '../error-codes.js';
|
|
10
|
+
export const addMCPTool = (logger, node, checker, state, options) => {
|
|
11
|
+
if (!ts.isCallExpression(node)) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const args = node.arguments;
|
|
15
|
+
const firstArg = args[0];
|
|
16
|
+
const expression = node.expression;
|
|
17
|
+
// Check if the call is to wireMCPTool
|
|
18
|
+
if (!ts.isIdentifier(expression) || expression.text !== 'wireMCPTool') {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (!firstArg) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (ts.isObjectLiteralExpression(firstArg)) {
|
|
25
|
+
const obj = firstArg;
|
|
26
|
+
const nameValue = getPropertyValue(obj, 'name');
|
|
27
|
+
const titleValue = getPropertyValue(obj, 'title');
|
|
28
|
+
const descriptionValue = getPropertyValue(obj, 'description');
|
|
29
|
+
const streamingValue = getPropertyValue(obj, 'streaming');
|
|
30
|
+
const tags = getPropertyTags(obj, 'MCP tool', nameValue, logger);
|
|
31
|
+
if (streamingValue === true) {
|
|
32
|
+
logger.warn(`MCP tool '${nameValue}' has streaming enabled, but streaming is not yet supported.`);
|
|
33
|
+
}
|
|
34
|
+
const funcInitializer = getPropertyAssignmentInitializer(obj, 'func', true, checker);
|
|
35
|
+
if (!funcInitializer) {
|
|
36
|
+
logger.critical(ErrorCode.MISSING_FUNC, `No valid 'func' property for MCP tool '${nameValue}'.`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const pikkuFuncName = extractFunctionName(funcInitializer, checker, state.rootDir).pikkuFuncName;
|
|
40
|
+
// Ensure function metadata exists (creates stub for inline functions)
|
|
41
|
+
ensureFunctionMetadata(state, pikkuFuncName, nameValue || undefined);
|
|
42
|
+
if (!nameValue) {
|
|
43
|
+
logger.critical(ErrorCode.MISSING_NAME, "MCP tool is missing the required 'name' property.");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (!descriptionValue) {
|
|
47
|
+
logger.critical(ErrorCode.MISSING_DESCRIPTION, `MCP tool '${nameValue}' is missing a description.`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// lookup existing function metadata
|
|
51
|
+
const fnMeta = state.functions.meta[pikkuFuncName];
|
|
52
|
+
if (!fnMeta) {
|
|
53
|
+
logger.critical(ErrorCode.FUNCTION_METADATA_NOT_FOUND, `No function metadata found for '${pikkuFuncName}'.`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const inputSchema = fnMeta.inputs?.[0] || null;
|
|
57
|
+
const outputSchema = fnMeta.outputs?.[0] || null;
|
|
58
|
+
// --- resolve middleware ---
|
|
59
|
+
const middleware = resolveMiddleware(state, obj, tags, checker);
|
|
60
|
+
// --- resolve permissions ---
|
|
61
|
+
const permissions = resolvePermissions(state, obj, tags, checker);
|
|
62
|
+
// --- track used functions/middleware/permissions for service aggregation ---
|
|
63
|
+
state.serviceAggregation.usedFunctions.add(pikkuFuncName);
|
|
64
|
+
extractWireNames(middleware).forEach((name) => state.serviceAggregation.usedMiddleware.add(name));
|
|
65
|
+
extractWireNames(permissions).forEach((name) => state.serviceAggregation.usedPermissions.add(name));
|
|
66
|
+
state.mcpEndpoints.files.add(node.getSourceFile().fileName);
|
|
67
|
+
state.mcpEndpoints.toolsMeta[nameValue] = {
|
|
68
|
+
pikkuFuncName,
|
|
69
|
+
name: nameValue,
|
|
70
|
+
title: titleValue || undefined,
|
|
71
|
+
description: descriptionValue,
|
|
72
|
+
...(streamingValue !== null && { streaming: streamingValue }),
|
|
73
|
+
tags,
|
|
74
|
+
inputSchema,
|
|
75
|
+
outputSchema,
|
|
76
|
+
middleware,
|
|
77
|
+
permissions,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
};
|