@pikku/inspector 0.9.6-next.0 → 0.10.1
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 +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 +87 -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 +4 -3
- 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 +114 -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 +10 -2
- 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/dist/utils/middleware.js
CHANGED
|
@@ -5,7 +5,7 @@ import { extractFunctionName } from './extract-function-name.js';
|
|
|
5
5
|
* Resolves each identifier to its pikkuFuncName using extractFunctionName
|
|
6
6
|
* Also handles call expressions (like logCommandInfoAndTime({...}))
|
|
7
7
|
*/
|
|
8
|
-
export function extractMiddlewarePikkuNames(arrayNode, checker) {
|
|
8
|
+
export function extractMiddlewarePikkuNames(arrayNode, checker, rootDir) {
|
|
9
9
|
if (!ts.isArrayLiteralExpression(arrayNode)) {
|
|
10
10
|
return [];
|
|
11
11
|
}
|
|
@@ -13,13 +13,13 @@ export function extractMiddlewarePikkuNames(arrayNode, checker) {
|
|
|
13
13
|
for (const element of arrayNode.elements) {
|
|
14
14
|
if (ts.isIdentifier(element)) {
|
|
15
15
|
// Resolve the identifier to its pikkuFuncName
|
|
16
|
-
const { pikkuFuncName } = extractFunctionName(element, checker);
|
|
16
|
+
const { pikkuFuncName } = extractFunctionName(element, checker, rootDir);
|
|
17
17
|
names.push(pikkuFuncName);
|
|
18
18
|
}
|
|
19
19
|
else if (ts.isCallExpression(element)) {
|
|
20
|
-
// Handle call expressions like logCommandInfoAndTime({...})
|
|
21
|
-
//
|
|
22
|
-
const { pikkuFuncName } = extractFunctionName(element, checker);
|
|
20
|
+
// Handle call expressions like rateLimiter(10) or logCommandInfoAndTime({...})
|
|
21
|
+
// Extract the function being called (e.g., 'rateLimiter' from 'rateLimiter(10)')
|
|
22
|
+
const { pikkuFuncName } = extractFunctionName(element.expression, checker, rootDir);
|
|
23
23
|
names.push(pikkuFuncName);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -84,7 +84,7 @@ export function resolveHTTPMiddleware(state, route, tags, explicitMiddlewareNode
|
|
|
84
84
|
}
|
|
85
85
|
// 3. Explicit wire middleware (inline is OK here)
|
|
86
86
|
if (explicitMiddlewareNode) {
|
|
87
|
-
const middlewareNames = extractMiddlewarePikkuNames(explicitMiddlewareNode, checker);
|
|
87
|
+
const middlewareNames = extractMiddlewarePikkuNames(explicitMiddlewareNode, checker, state.rootDir);
|
|
88
88
|
for (const name of middlewareNames) {
|
|
89
89
|
const meta = state.middleware.meta[name];
|
|
90
90
|
resolved.push({
|
|
@@ -117,7 +117,7 @@ function resolveTagAndExplicitMiddleware(state, tags, explicitMiddlewareNode, ch
|
|
|
117
117
|
}
|
|
118
118
|
// 2. Explicit middleware (inline is OK here - used directly in wire/function)
|
|
119
119
|
if (explicitMiddlewareNode) {
|
|
120
|
-
const middlewareNames = extractMiddlewarePikkuNames(explicitMiddlewareNode, checker);
|
|
120
|
+
const middlewareNames = extractMiddlewarePikkuNames(explicitMiddlewareNode, checker, state.rootDir);
|
|
121
121
|
for (const name of middlewareNames) {
|
|
122
122
|
const meta = state.middleware.meta[name];
|
|
123
123
|
resolved.push({
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { PermissionMetadata } from '@pikku/core';
|
|
3
|
+
import { InspectorState } from '../types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Extract permission pikkuFuncNames from an expression (array or object literal)
|
|
6
|
+
* Resolves each identifier to its pikkuFuncName using extractFunctionName
|
|
7
|
+
* Also handles call expressions (like rolePermission({...}))
|
|
8
|
+
*
|
|
9
|
+
* Supports both formats:
|
|
10
|
+
* - Array: [permission1, permission2]
|
|
11
|
+
* - Record: { groupName: permission1, anotherGroup: [permission2, permission3] }
|
|
12
|
+
*/
|
|
13
|
+
export declare function extractPermissionPikkuNames(node: ts.Expression, checker: ts.TypeChecker, rootDir: string): string[];
|
|
14
|
+
/**
|
|
15
|
+
* Get permissions array from an object literal expression property
|
|
16
|
+
* Returns the initializer node for the 'permissions' property if it exists
|
|
17
|
+
*/
|
|
18
|
+
export declare function getPermissionsNode(obj: ts.ObjectLiteralExpression): ts.Expression | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Check if a route matches a pattern with wildcards
|
|
21
|
+
* Pattern can be exact match or use * as wildcard
|
|
22
|
+
* e.g., '/api/*' matches '/api/users', '/api/posts/123', etc.
|
|
23
|
+
*/
|
|
24
|
+
export declare function routeMatchesPattern(route: string, pattern: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Resolve permissions for an HTTP wiring based on:
|
|
27
|
+
* 1. Global HTTP permissions (addHTTPPermission('*', [...]))
|
|
28
|
+
* 2. Route-specific HTTP permissions (addHTTPPermission('/pattern', [...]))
|
|
29
|
+
* 3. Tag-based permissions (addPermission('tag', [...]))
|
|
30
|
+
* 4. Explicit wiring permissions (wireHTTP({ permissions: [...] }))
|
|
31
|
+
* Returns undefined if no permissions are found, otherwise returns array with at least one item
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveHTTPPermissions(state: InspectorState, route: string, tags: string[] | undefined, explicitPermissionsNode: ts.Expression | undefined, checker: ts.TypeChecker): PermissionMetadata[] | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Convenience wrapper: Extract permissions node from object and resolve
|
|
36
|
+
* Use this in add-* files for cleaner code
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolvePermissions(state: InspectorState, obj: ts.ObjectLiteralExpression, tags: string[] | undefined, checker: ts.TypeChecker): PermissionMetadata[] | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Convenience wrapper for HTTP: Extract permissions and resolve with HTTP-specific logic
|
|
41
|
+
* Use this in add-http-route.ts for cleaner code
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolveHTTPPermissionsFromObject(state: InspectorState, route: string, obj: ts.ObjectLiteralExpression, tags: string[] | undefined, checker: ts.TypeChecker): PermissionMetadata[] | undefined;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
import { extractFunctionName } from './extract-function-name.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extract permission pikkuFuncNames from an expression (array or object literal)
|
|
5
|
+
* Resolves each identifier to its pikkuFuncName using extractFunctionName
|
|
6
|
+
* Also handles call expressions (like rolePermission({...}))
|
|
7
|
+
*
|
|
8
|
+
* Supports both formats:
|
|
9
|
+
* - Array: [permission1, permission2]
|
|
10
|
+
* - Record: { groupName: permission1, anotherGroup: [permission2, permission3] }
|
|
11
|
+
*/
|
|
12
|
+
export function extractPermissionPikkuNames(node, checker, rootDir) {
|
|
13
|
+
const names = [];
|
|
14
|
+
// Helper to extract from a single element
|
|
15
|
+
const extractFromElement = (element) => {
|
|
16
|
+
if (ts.isIdentifier(element)) {
|
|
17
|
+
const { pikkuFuncName } = extractFunctionName(element, checker, rootDir);
|
|
18
|
+
names.push(pikkuFuncName);
|
|
19
|
+
}
|
|
20
|
+
else if (ts.isCallExpression(element)) {
|
|
21
|
+
// Handle call expressions like hasEmailQuota(100) or rolePermission({...})
|
|
22
|
+
// Extract the function being called (e.g., 'hasEmailQuota' from 'hasEmailQuota(100)')
|
|
23
|
+
const { pikkuFuncName } = extractFunctionName(element.expression, checker, rootDir);
|
|
24
|
+
names.push(pikkuFuncName);
|
|
25
|
+
}
|
|
26
|
+
else if (ts.isArrayLiteralExpression(element)) {
|
|
27
|
+
// Nested array (for Record values that are arrays)
|
|
28
|
+
for (const nestedElement of element.elements) {
|
|
29
|
+
extractFromElement(nestedElement);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
if (ts.isArrayLiteralExpression(node)) {
|
|
34
|
+
// Array format: [permission1, permission2]
|
|
35
|
+
for (const element of node.elements) {
|
|
36
|
+
extractFromElement(element);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else if (ts.isObjectLiteralExpression(node)) {
|
|
40
|
+
// Record format: { groupName: permission1, anotherGroup: [permission2] }
|
|
41
|
+
for (const prop of node.properties) {
|
|
42
|
+
if (ts.isPropertyAssignment(prop)) {
|
|
43
|
+
extractFromElement(prop.initializer);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return names;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get permissions array from an object literal expression property
|
|
51
|
+
* Returns the initializer node for the 'permissions' property if it exists
|
|
52
|
+
*/
|
|
53
|
+
export function getPermissionsNode(obj) {
|
|
54
|
+
const permissionsProp = obj.properties.find((p) => ts.isPropertyAssignment(p) &&
|
|
55
|
+
ts.isIdentifier(p.name) &&
|
|
56
|
+
p.name.text === 'permissions');
|
|
57
|
+
return permissionsProp?.initializer;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Check if a route matches a pattern with wildcards
|
|
61
|
+
* Pattern can be exact match or use * as wildcard
|
|
62
|
+
* e.g., '/api/*' matches '/api/users', '/api/posts/123', etc.
|
|
63
|
+
*/
|
|
64
|
+
export function routeMatchesPattern(route, pattern) {
|
|
65
|
+
if (route === pattern)
|
|
66
|
+
return true;
|
|
67
|
+
// Convert pattern to regex: replace * with .*
|
|
68
|
+
const regexPattern = pattern
|
|
69
|
+
.replace(/[.+?^${}()|[\]\\]/g, '\\$&') // Escape regex special chars except *
|
|
70
|
+
.replace(/\*/g, '.*'); // Replace * with .*
|
|
71
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
72
|
+
return regex.test(route);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Resolve permissions for an HTTP wiring based on:
|
|
76
|
+
* 1. Global HTTP permissions (addHTTPPermission('*', [...]))
|
|
77
|
+
* 2. Route-specific HTTP permissions (addHTTPPermission('/pattern', [...]))
|
|
78
|
+
* 3. Tag-based permissions (addPermission('tag', [...]))
|
|
79
|
+
* 4. Explicit wiring permissions (wireHTTP({ permissions: [...] }))
|
|
80
|
+
* Returns undefined if no permissions are found, otherwise returns array with at least one item
|
|
81
|
+
*/
|
|
82
|
+
export function resolveHTTPPermissions(state, route, tags, explicitPermissionsNode, checker) {
|
|
83
|
+
const resolved = [];
|
|
84
|
+
// 1. HTTP route permission groups (includes '*' for global)
|
|
85
|
+
for (const [pattern, _groupMeta] of state.http.routePermissions.entries()) {
|
|
86
|
+
if (routeMatchesPattern(route, pattern)) {
|
|
87
|
+
// Just reference the group by route pattern
|
|
88
|
+
resolved.push({
|
|
89
|
+
type: 'http',
|
|
90
|
+
route: pattern,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// 2. Tag-based permission groups
|
|
95
|
+
if (tags && tags.length > 0) {
|
|
96
|
+
for (const tag of tags) {
|
|
97
|
+
if (state.permissions.tagPermissions.has(tag)) {
|
|
98
|
+
// Just reference the group by tag
|
|
99
|
+
resolved.push({
|
|
100
|
+
type: 'tag',
|
|
101
|
+
tag,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// 3. Explicit wire permissions (inline is OK here)
|
|
107
|
+
if (explicitPermissionsNode) {
|
|
108
|
+
const permissionNames = extractPermissionPikkuNames(explicitPermissionsNode, checker, state.rootDir);
|
|
109
|
+
for (const name of permissionNames) {
|
|
110
|
+
const meta = state.permissions.meta[name];
|
|
111
|
+
resolved.push({
|
|
112
|
+
type: 'wire',
|
|
113
|
+
name,
|
|
114
|
+
inline: meta?.exportedName === null,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return resolved.length > 0 ? resolved : undefined;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Resolve tag-based and explicit permissions (common logic for wires and functions)
|
|
122
|
+
* 1. Tag-based permissions (addPermission('tag', [...]))
|
|
123
|
+
* 2. Explicit permissions (wireHTTP/pikkuFunc({ permissions: [...] }))
|
|
124
|
+
*/
|
|
125
|
+
function resolveTagAndExplicitPermissions(state, tags, explicitPermissionsNode, checker) {
|
|
126
|
+
const resolved = [];
|
|
127
|
+
// 1. Tag-based permission groups
|
|
128
|
+
if (tags && tags.length > 0) {
|
|
129
|
+
for (const tag of tags) {
|
|
130
|
+
if (state.permissions.tagPermissions.has(tag)) {
|
|
131
|
+
// Just reference the group by tag
|
|
132
|
+
resolved.push({
|
|
133
|
+
type: 'tag',
|
|
134
|
+
tag,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// 2. Explicit permissions (inline is OK here - used directly in wire/function)
|
|
140
|
+
if (explicitPermissionsNode) {
|
|
141
|
+
const permissionNames = extractPermissionPikkuNames(explicitPermissionsNode, checker, state.rootDir);
|
|
142
|
+
for (const name of permissionNames) {
|
|
143
|
+
const meta = state.permissions.meta[name];
|
|
144
|
+
resolved.push({
|
|
145
|
+
type: 'wire',
|
|
146
|
+
name,
|
|
147
|
+
inline: meta?.exportedName === null,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return resolved;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Resolve permissions for a function based on:
|
|
155
|
+
* 1. Tag-based permissions (addPermission('tag', [...]))
|
|
156
|
+
* 2. Explicit function permissions (pikkuFunc({ permissions: [...] }))
|
|
157
|
+
* Returns undefined if no permissions are found, otherwise returns array with at least one item
|
|
158
|
+
*/
|
|
159
|
+
function resolveFunctionPermissionsInternal(state, tags, explicitPermissionsNode, checker) {
|
|
160
|
+
const resolved = resolveTagAndExplicitPermissions(state, tags, explicitPermissionsNode, checker);
|
|
161
|
+
return resolved.length > 0 ? resolved : undefined;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Convenience wrapper: Extract permissions node from object and resolve
|
|
165
|
+
* Use this in add-* files for cleaner code
|
|
166
|
+
*/
|
|
167
|
+
export function resolvePermissions(state, obj, tags, checker) {
|
|
168
|
+
const explicitPermissionsNode = getPermissionsNode(obj);
|
|
169
|
+
return resolveFunctionPermissionsInternal(state, tags, explicitPermissionsNode, checker);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Convenience wrapper for HTTP: Extract permissions and resolve with HTTP-specific logic
|
|
173
|
+
* Use this in add-http-route.ts for cleaner code
|
|
174
|
+
*/
|
|
175
|
+
export function resolveHTTPPermissionsFromObject(state, route, obj, tags, checker) {
|
|
176
|
+
const explicitPermissionsNode = getPermissionsNode(obj);
|
|
177
|
+
return resolveHTTPPermissions(state, route, tags, explicitPermissionsNode, checker);
|
|
178
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { InspectorState } from '../types.js';
|
|
2
|
+
import { MiddlewareMetadata, PermissionMetadata } from '@pikku/core';
|
|
3
|
+
/**
|
|
4
|
+
* Helper to extract wire-level middleware/permission names from metadata.
|
|
5
|
+
* Only extracts type:'wire' variants (individual middleware/permissions).
|
|
6
|
+
* Skips type:'http' and type:'tag' (reference groups, not individuals).
|
|
7
|
+
*/
|
|
8
|
+
export declare function extractWireNames(list?: MiddlewareMetadata[] | PermissionMetadata[]): string[];
|
|
9
|
+
/**
|
|
10
|
+
* Aggregates all required services from wired functions, middleware, and permissions.
|
|
11
|
+
* Must be called after AST traversal completes.
|
|
12
|
+
*
|
|
13
|
+
* Note: usedFunctions, usedMiddleware, and usedPermissions are tracked directly
|
|
14
|
+
* in the add-* methods during AST traversal for efficiency.
|
|
15
|
+
*/
|
|
16
|
+
export declare function aggregateRequiredServices(state: InspectorState): void;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper to extract wire-level middleware/permission names from metadata.
|
|
3
|
+
* Only extracts type:'wire' variants (individual middleware/permissions).
|
|
4
|
+
* Skips type:'http' and type:'tag' (reference groups, not individuals).
|
|
5
|
+
*/
|
|
6
|
+
export function extractWireNames(list) {
|
|
7
|
+
if (!list)
|
|
8
|
+
return [];
|
|
9
|
+
return list
|
|
10
|
+
.filter((item) => item.type === 'wire')
|
|
11
|
+
.map((item) => item.name);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Helper to expand middleware/permission groups into individual names
|
|
15
|
+
* and add their services to the aggregation.
|
|
16
|
+
* This handles tag-based and HTTP-pattern-based middleware/permission groups.
|
|
17
|
+
*/
|
|
18
|
+
function expandAndAddGroupServices(list, state, addServices, isMiddleware) {
|
|
19
|
+
if (!list)
|
|
20
|
+
return;
|
|
21
|
+
for (const item of list) {
|
|
22
|
+
if (item.type === 'tag') {
|
|
23
|
+
// Expand tag-based group
|
|
24
|
+
const groupMeta = isMiddleware
|
|
25
|
+
? state.middleware.tagMiddleware.get(item.tag)
|
|
26
|
+
: state.permissions.tagPermissions.get(item.tag);
|
|
27
|
+
if (groupMeta?.services) {
|
|
28
|
+
addServices(groupMeta.services);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else if (item.type === 'http' && 'route' in item) {
|
|
32
|
+
// Expand HTTP-pattern-based group
|
|
33
|
+
const groupMeta = isMiddleware
|
|
34
|
+
? state.http.routeMiddleware.get(item.route)
|
|
35
|
+
: state.http.routePermissions.get(item.route);
|
|
36
|
+
if (groupMeta?.services) {
|
|
37
|
+
addServices(groupMeta.services);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Aggregates all required services from wired functions, middleware, and permissions.
|
|
44
|
+
* Must be called after AST traversal completes.
|
|
45
|
+
*
|
|
46
|
+
* Note: usedFunctions, usedMiddleware, and usedPermissions are tracked directly
|
|
47
|
+
* in the add-* methods during AST traversal for efficiency.
|
|
48
|
+
*/
|
|
49
|
+
export function aggregateRequiredServices(state) {
|
|
50
|
+
const { requiredServices, usedFunctions, usedMiddleware, usedPermissions } = state.serviceAggregation;
|
|
51
|
+
// Internal services (always excluded from tree-shaking)
|
|
52
|
+
const internalServices = new Set(['rpc', 'mcp', 'channel', 'userSession']);
|
|
53
|
+
const addServices = (services) => {
|
|
54
|
+
if (!services || !services.services)
|
|
55
|
+
return;
|
|
56
|
+
services.services.forEach((service) => {
|
|
57
|
+
if (!internalServices.has(service)) {
|
|
58
|
+
requiredServices.add(service);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
// 1. Services from used functions
|
|
63
|
+
usedFunctions.forEach((funcName) => {
|
|
64
|
+
const funcMeta = state.functions.meta[funcName];
|
|
65
|
+
if (funcMeta?.services) {
|
|
66
|
+
addServices(funcMeta.services);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
// 2. Services from used middleware (individual + groups)
|
|
70
|
+
usedMiddleware.forEach((middlewareName) => {
|
|
71
|
+
const middlewareMeta = state.middleware.meta[middlewareName];
|
|
72
|
+
if (middlewareMeta?.services) {
|
|
73
|
+
addServices(middlewareMeta.services);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
// 3. Services from used permissions (individual + groups)
|
|
77
|
+
usedPermissions.forEach((permissionName) => {
|
|
78
|
+
const permissionMeta = state.permissions.meta[permissionName];
|
|
79
|
+
if (permissionMeta?.services) {
|
|
80
|
+
addServices(permissionMeta.services);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
// 4. Services from middleware/permission groups used in wirings
|
|
84
|
+
// We need to check all wirings and expand any tag/HTTP-pattern groups they use
|
|
85
|
+
for (const method of [
|
|
86
|
+
'get',
|
|
87
|
+
'post',
|
|
88
|
+
'put',
|
|
89
|
+
'patch',
|
|
90
|
+
'delete',
|
|
91
|
+
'head',
|
|
92
|
+
'options',
|
|
93
|
+
]) {
|
|
94
|
+
for (const routeMeta of Object.values(state.http.meta[method])) {
|
|
95
|
+
expandAndAddGroupServices(routeMeta.middleware, state, addServices, true);
|
|
96
|
+
expandAndAddGroupServices(routeMeta.permissions, state, addServices, false);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Also check other wiring types (channels, queues, schedulers, MCP)
|
|
100
|
+
for (const channelMeta of Object.values(state.channels.meta)) {
|
|
101
|
+
expandAndAddGroupServices(channelMeta.middleware, state, addServices, true);
|
|
102
|
+
expandAndAddGroupServices(channelMeta.permissions, state, addServices, false);
|
|
103
|
+
}
|
|
104
|
+
for (const queueMeta of Object.values(state.queueWorkers.meta)) {
|
|
105
|
+
expandAndAddGroupServices(queueMeta.middleware, state, addServices, true);
|
|
106
|
+
// expandAndAddGroupServices(queueMeta.permissions, state, addServices, false)
|
|
107
|
+
}
|
|
108
|
+
for (const scheduleMeta of Object.values(state.scheduledTasks.meta)) {
|
|
109
|
+
expandAndAddGroupServices(scheduleMeta.middleware, state, addServices, true);
|
|
110
|
+
// expandAndAddGroupServices(scheduleMeta.permissions, state, addServices, false)
|
|
111
|
+
}
|
|
112
|
+
for (const toolMeta of Object.values(state.mcpEndpoints.toolsMeta)) {
|
|
113
|
+
expandAndAddGroupServices(toolMeta.middleware, state, addServices, true);
|
|
114
|
+
expandAndAddGroupServices(toolMeta.permissions, state, addServices, false);
|
|
115
|
+
}
|
|
116
|
+
for (const promptMeta of Object.values(state.mcpEndpoints.promptsMeta)) {
|
|
117
|
+
expandAndAddGroupServices(promptMeta.middleware, state, addServices, true);
|
|
118
|
+
expandAndAddGroupServices(promptMeta.permissions, state, addServices, false);
|
|
119
|
+
}
|
|
120
|
+
for (const resourceMeta of Object.values(state.mcpEndpoints.resourcesMeta)) {
|
|
121
|
+
expandAndAddGroupServices(resourceMeta.middleware, state, addServices, true);
|
|
122
|
+
expandAndAddGroupServices(resourceMeta.permissions, state, addServices, false);
|
|
123
|
+
}
|
|
124
|
+
// 5. Services from session service factories
|
|
125
|
+
for (const singletonServices of state.sessionServicesMeta.values()) {
|
|
126
|
+
singletonServices.forEach((service) => {
|
|
127
|
+
if (!internalServices.has(service)) {
|
|
128
|
+
requiredServices.add(service);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { InspectorState } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Serializable version of InspectorState that can be saved to JSON
|
|
4
|
+
* Omits typesLookup (contains non-serializable ts.Type objects) and converts Maps/Sets to arrays
|
|
5
|
+
*/
|
|
6
|
+
export interface SerializableInspectorState {
|
|
7
|
+
rootDir: string;
|
|
8
|
+
singletonServicesTypeImportMap: Array<[
|
|
9
|
+
string,
|
|
10
|
+
{
|
|
11
|
+
variable: string;
|
|
12
|
+
type: string | null;
|
|
13
|
+
typePath: string | null;
|
|
14
|
+
}[]
|
|
15
|
+
]>;
|
|
16
|
+
sessionServicesTypeImportMap: Array<[
|
|
17
|
+
string,
|
|
18
|
+
{
|
|
19
|
+
variable: string;
|
|
20
|
+
type: string | null;
|
|
21
|
+
typePath: string | null;
|
|
22
|
+
}[]
|
|
23
|
+
]>;
|
|
24
|
+
userSessionTypeImportMap: Array<[
|
|
25
|
+
string,
|
|
26
|
+
{
|
|
27
|
+
variable: string;
|
|
28
|
+
type: string | null;
|
|
29
|
+
typePath: string | null;
|
|
30
|
+
}[]
|
|
31
|
+
]>;
|
|
32
|
+
configTypeImportMap: Array<[
|
|
33
|
+
string,
|
|
34
|
+
{
|
|
35
|
+
variable: string;
|
|
36
|
+
type: string | null;
|
|
37
|
+
typePath: string | null;
|
|
38
|
+
}[]
|
|
39
|
+
]>;
|
|
40
|
+
singletonServicesFactories: Array<[
|
|
41
|
+
string,
|
|
42
|
+
{
|
|
43
|
+
variable: string;
|
|
44
|
+
type: string | null;
|
|
45
|
+
typePath: string | null;
|
|
46
|
+
}[]
|
|
47
|
+
]>;
|
|
48
|
+
sessionServicesFactories: Array<[
|
|
49
|
+
string,
|
|
50
|
+
{
|
|
51
|
+
variable: string;
|
|
52
|
+
type: string | null;
|
|
53
|
+
typePath: string | null;
|
|
54
|
+
}[]
|
|
55
|
+
]>;
|
|
56
|
+
sessionServicesMeta: Array<[string, string[]]>;
|
|
57
|
+
configFactories: Array<[
|
|
58
|
+
string,
|
|
59
|
+
{
|
|
60
|
+
variable: string;
|
|
61
|
+
type: string | null;
|
|
62
|
+
typePath: string | null;
|
|
63
|
+
}[]
|
|
64
|
+
]>;
|
|
65
|
+
filesAndMethods: InspectorState['filesAndMethods'];
|
|
66
|
+
filesAndMethodsErrors: Array<[
|
|
67
|
+
string,
|
|
68
|
+
Array<[
|
|
69
|
+
string,
|
|
70
|
+
{
|
|
71
|
+
variable: string;
|
|
72
|
+
type: string | null;
|
|
73
|
+
typePath: string | null;
|
|
74
|
+
}[]
|
|
75
|
+
]>
|
|
76
|
+
]>;
|
|
77
|
+
functions: {
|
|
78
|
+
typesMap: {
|
|
79
|
+
map: Array<[string, {
|
|
80
|
+
originalName: string;
|
|
81
|
+
path: string | null;
|
|
82
|
+
}]>;
|
|
83
|
+
customTypes: Array<[string, {
|
|
84
|
+
type: string;
|
|
85
|
+
references: string[];
|
|
86
|
+
}]>;
|
|
87
|
+
};
|
|
88
|
+
meta: InspectorState['functions']['meta'];
|
|
89
|
+
files: Array<[string, {
|
|
90
|
+
path: string;
|
|
91
|
+
exportedName: string;
|
|
92
|
+
}]>;
|
|
93
|
+
};
|
|
94
|
+
http: {
|
|
95
|
+
metaInputTypes: Array<[
|
|
96
|
+
string,
|
|
97
|
+
{
|
|
98
|
+
query: string[] | undefined;
|
|
99
|
+
params: string[] | undefined;
|
|
100
|
+
body: string[] | undefined;
|
|
101
|
+
}
|
|
102
|
+
]>;
|
|
103
|
+
meta: InspectorState['http']['meta'];
|
|
104
|
+
files: string[];
|
|
105
|
+
routeMiddleware: Array<[
|
|
106
|
+
string,
|
|
107
|
+
InspectorState['http']['routeMiddleware'] extends Map<string, infer V> ? V : never
|
|
108
|
+
]>;
|
|
109
|
+
routePermissions: Array<[
|
|
110
|
+
string,
|
|
111
|
+
InspectorState['http']['routePermissions'] extends Map<string, infer V> ? V : never
|
|
112
|
+
]>;
|
|
113
|
+
};
|
|
114
|
+
channels: {
|
|
115
|
+
files: string[];
|
|
116
|
+
meta: InspectorState['channels']['meta'];
|
|
117
|
+
};
|
|
118
|
+
scheduledTasks: {
|
|
119
|
+
meta: InspectorState['scheduledTasks']['meta'];
|
|
120
|
+
files: string[];
|
|
121
|
+
};
|
|
122
|
+
queueWorkers: {
|
|
123
|
+
meta: InspectorState['queueWorkers']['meta'];
|
|
124
|
+
files: string[];
|
|
125
|
+
};
|
|
126
|
+
rpc: {
|
|
127
|
+
internalMeta: InspectorState['rpc']['internalMeta'];
|
|
128
|
+
internalFiles: Array<[string, {
|
|
129
|
+
path: string;
|
|
130
|
+
exportedName: string;
|
|
131
|
+
}]>;
|
|
132
|
+
exposedMeta: InspectorState['rpc']['exposedMeta'];
|
|
133
|
+
exposedFiles: Array<[string, {
|
|
134
|
+
path: string;
|
|
135
|
+
exportedName: string;
|
|
136
|
+
}]>;
|
|
137
|
+
invokedFunctions: string[];
|
|
138
|
+
};
|
|
139
|
+
mcpEndpoints: {
|
|
140
|
+
resourcesMeta: InspectorState['mcpEndpoints']['resourcesMeta'];
|
|
141
|
+
toolsMeta: InspectorState['mcpEndpoints']['toolsMeta'];
|
|
142
|
+
promptsMeta: InspectorState['mcpEndpoints']['promptsMeta'];
|
|
143
|
+
files: string[];
|
|
144
|
+
};
|
|
145
|
+
cli: {
|
|
146
|
+
meta: InspectorState['cli']['meta'];
|
|
147
|
+
files: string[];
|
|
148
|
+
};
|
|
149
|
+
middleware: {
|
|
150
|
+
meta: InspectorState['middleware']['meta'];
|
|
151
|
+
tagMiddleware: Array<[
|
|
152
|
+
string,
|
|
153
|
+
InspectorState['middleware']['tagMiddleware'] extends Map<string, infer V> ? V : never
|
|
154
|
+
]>;
|
|
155
|
+
};
|
|
156
|
+
permissions: {
|
|
157
|
+
meta: InspectorState['permissions']['meta'];
|
|
158
|
+
tagPermissions: Array<[
|
|
159
|
+
string,
|
|
160
|
+
InspectorState['permissions']['tagPermissions'] extends Map<string, infer V> ? V : never
|
|
161
|
+
]>;
|
|
162
|
+
};
|
|
163
|
+
serviceAggregation: {
|
|
164
|
+
requiredServices: string[];
|
|
165
|
+
usedFunctions: string[];
|
|
166
|
+
usedMiddleware: string[];
|
|
167
|
+
usedPermissions: string[];
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Serializes InspectorState to a JSON-compatible format
|
|
172
|
+
* Omits typesLookup (not needed for filtering/generation) and converts Maps/Sets to arrays
|
|
173
|
+
*/
|
|
174
|
+
export declare function serializeInspectorState(state: InspectorState): SerializableInspectorState;
|
|
175
|
+
/**
|
|
176
|
+
* Deserializes JSON data back to InspectorState
|
|
177
|
+
* Creates a partial state suitable for filtering/generation (without typesLookup)
|
|
178
|
+
*/
|
|
179
|
+
export declare function deserializeInspectorState(data: SerializableInspectorState): Omit<InspectorState, 'typesLookup'>;
|