@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.
Files changed (84) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/add/add-channel.d.ts +5 -1
  3. package/dist/add/add-channel.js +51 -32
  4. package/dist/add/add-cli.d.ts +4 -0
  5. package/dist/add/add-cli.js +128 -23
  6. package/dist/add/add-file-extends-core-type.js +3 -2
  7. package/dist/add/add-file-with-factory.d.ts +2 -2
  8. package/dist/add/add-file-with-factory.js +87 -1
  9. package/dist/add/add-functions.js +52 -5
  10. package/dist/add/add-http-route.js +19 -12
  11. package/dist/add/add-mcp-prompt.js +20 -13
  12. package/dist/add/add-mcp-resource.js +24 -14
  13. package/dist/add/add-mcp-tool.js +23 -13
  14. package/dist/add/add-middleware.js +51 -12
  15. package/dist/add/add-permission.d.ts +1 -2
  16. package/dist/add/add-permission.js +275 -19
  17. package/dist/add/add-queue-worker.js +10 -12
  18. package/dist/add/add-schedule.js +9 -10
  19. package/dist/error-codes.d.ts +35 -0
  20. package/dist/error-codes.js +40 -0
  21. package/dist/index.d.ts +4 -0
  22. package/dist/index.js +3 -0
  23. package/dist/inspector.js +20 -1
  24. package/dist/types.d.ts +31 -3
  25. package/dist/utils/ensure-function-metadata.d.ts +6 -0
  26. package/dist/utils/ensure-function-metadata.js +18 -0
  27. package/dist/utils/extract-function-name.d.ts +2 -2
  28. package/dist/utils/extract-function-name.js +13 -8
  29. package/dist/utils/filter-inspector-state.d.ts +6 -0
  30. package/dist/utils/filter-inspector-state.js +382 -0
  31. package/dist/utils/filter-utils.d.ts +10 -0
  32. package/dist/utils/filter-utils.js +66 -2
  33. package/dist/utils/find-root-dir.d.ts +23 -0
  34. package/dist/utils/find-root-dir.js +55 -0
  35. package/dist/utils/get-files-and-methods.d.ts +2 -1
  36. package/dist/utils/get-files-and-methods.js +4 -3
  37. package/dist/utils/get-property-value.d.ts +9 -0
  38. package/dist/utils/get-property-value.js +20 -0
  39. package/dist/utils/middleware.d.ts +1 -1
  40. package/dist/utils/middleware.js +7 -7
  41. package/dist/utils/permissions.d.ts +43 -0
  42. package/dist/utils/permissions.js +178 -0
  43. package/dist/utils/post-process.d.ts +16 -0
  44. package/dist/utils/post-process.js +132 -0
  45. package/dist/utils/serialize-inspector-state.d.ts +179 -0
  46. package/dist/utils/serialize-inspector-state.js +170 -0
  47. package/dist/visit.js +3 -2
  48. package/package.json +4 -4
  49. package/src/add/add-channel.ts +92 -40
  50. package/src/add/add-cli.ts +188 -29
  51. package/src/add/add-file-extends-core-type.ts +5 -2
  52. package/src/add/add-file-with-factory.ts +114 -2
  53. package/src/add/add-functions.ts +60 -5
  54. package/src/add/add-http-route.ts +46 -21
  55. package/src/add/add-mcp-prompt.ts +42 -21
  56. package/src/add/add-mcp-prompt.ts.tmp +0 -0
  57. package/src/add/add-mcp-resource.ts +50 -24
  58. package/src/add/add-mcp-resource.ts.tmp +0 -0
  59. package/src/add/add-mcp-tool.ts +48 -21
  60. package/src/add/add-middleware.ts +74 -15
  61. package/src/add/add-permission.ts +364 -22
  62. package/src/add/add-queue-worker.ts +22 -25
  63. package/src/add/add-schedule.ts +19 -20
  64. package/src/error-codes.ts +43 -0
  65. package/src/index.ts +7 -0
  66. package/src/inspector.ts +22 -1
  67. package/src/types.ts +38 -3
  68. package/src/utils/ensure-function-metadata.ts +24 -0
  69. package/src/utils/extract-function-name.ts +20 -8
  70. package/src/utils/filter-inspector-state.test.ts +1433 -0
  71. package/src/utils/filter-inspector-state.ts +526 -0
  72. package/src/utils/filter-utils.test.ts +350 -1
  73. package/src/utils/filter-utils.ts +82 -2
  74. package/src/utils/find-root-dir.ts +68 -0
  75. package/src/utils/get-files-and-methods.ts +10 -2
  76. package/src/utils/get-property-value.ts +27 -0
  77. package/src/utils/middleware.ts +14 -7
  78. package/src/utils/permissions.test.ts +327 -0
  79. package/src/utils/permissions.ts +262 -0
  80. package/src/utils/post-process.ts +178 -0
  81. package/src/utils/serialize-inspector-state.ts +375 -0
  82. package/src/utils/test-data/inspector-state.json +1680 -0
  83. package/src/visit.ts +4 -2
  84. package/tsconfig.tsbuildinfo +1 -1
@@ -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
- // These create inline middleware, so we use the call expression itself as the name
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'>;