@pikku/inspector 0.9.4 → 0.9.6-next.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.
Files changed (95) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/{add-channel.d.ts → add/add-channel.d.ts} +2 -2
  3. package/dist/{add-channel.js → add/add-channel.js} +12 -5
  4. package/dist/add/add-cli.d.ts +5 -0
  5. package/dist/add/add-cli.js +461 -0
  6. package/dist/{add-file-extends-core-type.d.ts → add/add-file-extends-core-type.d.ts} +2 -2
  7. package/dist/{add-file-extends-core-type.js → add/add-file-extends-core-type.js} +17 -5
  8. package/dist/{add-file-with-config.d.ts → add/add-file-with-config.d.ts} +1 -1
  9. package/dist/{add-file-with-config.js → add/add-file-with-config.js} +1 -1
  10. package/dist/{add-file-with-factory.d.ts → add/add-file-with-factory.d.ts} +1 -1
  11. package/dist/{add-file-with-factory.js → add/add-file-with-factory.js} +4 -4
  12. package/dist/add/add-functions.d.ts +6 -0
  13. package/dist/{add-functions.js → add/add-functions.js} +26 -6
  14. package/dist/{add-http-route.d.ts → add/add-http-route.d.ts} +2 -3
  15. package/dist/{add-http-route.js → add/add-http-route.js} +10 -4
  16. package/dist/add/add-mcp-prompt.d.ts +2 -0
  17. package/dist/{add-mcp-prompt.js → add/add-mcp-prompt.js} +10 -4
  18. package/dist/add/add-mcp-resource.d.ts +2 -0
  19. package/dist/{add-mcp-resource.js → add/add-mcp-resource.js} +10 -4
  20. package/dist/add/add-mcp-tool.d.ts +2 -0
  21. package/dist/{add-mcp-tool.js → add/add-mcp-tool.js} +10 -4
  22. package/dist/add/add-middleware.d.ts +5 -0
  23. package/dist/add/add-middleware.js +251 -0
  24. package/dist/add/add-permission.d.ts +6 -0
  25. package/dist/{add-permission.js → add/add-permission.js} +4 -3
  26. package/dist/add/add-queue-worker.d.ts +2 -0
  27. package/dist/{add-queue-worker.js → add/add-queue-worker.js} +10 -4
  28. package/dist/{add-rpc-invocations.d.ts → add/add-rpc-invocations.d.ts} +1 -1
  29. package/dist/add/add-schedule.d.ts +2 -0
  30. package/dist/{add-schedule.js → add/add-schedule.js} +10 -4
  31. package/dist/index.d.ts +2 -0
  32. package/dist/index.js +1 -0
  33. package/dist/inspector.d.ts +2 -3
  34. package/dist/inspector.js +19 -8
  35. package/dist/types.d.ts +79 -0
  36. package/dist/{utils.d.ts → utils/extract-function-name.d.ts} +7 -15
  37. package/dist/{utils.js → utils/extract-function-name.js} +23 -142
  38. package/dist/utils/extract-services.d.ts +6 -0
  39. package/dist/utils/extract-services.js +29 -0
  40. package/dist/utils/filter-utils.d.ts +9 -0
  41. package/dist/utils/filter-utils.js +45 -0
  42. package/dist/utils/get-files-and-methods.d.ts +21 -0
  43. package/dist/utils/get-files-and-methods.js +60 -0
  44. package/dist/utils/middleware.d.ts +39 -0
  45. package/dist/utils/middleware.js +157 -0
  46. package/dist/utils/type-utils.d.ts +3 -0
  47. package/dist/utils/type-utils.js +50 -0
  48. package/dist/visit.d.ts +3 -3
  49. package/dist/visit.js +33 -30
  50. package/package.json +3 -4
  51. package/run-tests.sh +1 -1
  52. package/src/{add-channel.ts → add/add-channel.ts} +19 -19
  53. package/src/add/add-cli.ts +663 -0
  54. package/src/{add-file-extends-core-type.ts → add/add-file-extends-core-type.ts} +21 -6
  55. package/src/{add-file-with-config.ts → add/add-file-with-config.ts} +2 -2
  56. package/src/{add-file-with-factory.ts → add/add-file-with-factory.ts} +5 -5
  57. package/src/{add-functions.ts → add/add-functions.ts} +30 -15
  58. package/src/{add-http-route.ts → add/add-http-route.ts} +23 -14
  59. package/src/{add-mcp-prompt.ts → add/add-mcp-prompt.ts} +18 -15
  60. package/src/{add-mcp-resource.ts → add/add-mcp-resource.ts} +18 -15
  61. package/src/{add-mcp-tool.ts → add/add-mcp-tool.ts} +18 -15
  62. package/src/add/add-middleware.ts +326 -0
  63. package/src/{add-permission.ts → add/add-permission.ts} +4 -8
  64. package/src/{add-queue-worker.ts → add/add-queue-worker.ts} +17 -14
  65. package/src/{add-rpc-invocations.ts → add/add-rpc-invocations.ts} +1 -1
  66. package/src/{add-schedule.ts → add/add-schedule.ts} +17 -14
  67. package/src/index.ts +5 -0
  68. package/src/inspector.ts +20 -17
  69. package/src/types.ts +92 -0
  70. package/src/{utils.ts → utils/extract-function-name.ts} +25 -199
  71. package/src/utils/extract-services.ts +35 -0
  72. package/src/{utils.test.ts → utils/filter-utils.test.ts} +2 -2
  73. package/src/utils/filter-utils.ts +72 -0
  74. package/src/utils/get-files-and-methods.ts +143 -0
  75. package/src/utils/middleware.ts +234 -0
  76. package/src/utils/type-utils.ts +74 -0
  77. package/src/visit.ts +47 -33
  78. package/tsconfig.tsbuildinfo +1 -1
  79. package/dist/add-functions.d.ts +0 -7
  80. package/dist/add-mcp-prompt.d.ts +0 -3
  81. package/dist/add-mcp-resource.d.ts +0 -3
  82. package/dist/add-mcp-tool.d.ts +0 -3
  83. package/dist/add-middleware.d.ts +0 -7
  84. package/dist/add-middleware.js +0 -35
  85. package/dist/add-permission.d.ts +0 -7
  86. package/dist/add-queue-worker.d.ts +0 -3
  87. package/dist/add-schedule.d.ts +0 -3
  88. package/src/add-middleware.ts +0 -51
  89. /package/dist/{add-rpc-invocations.js → add/add-rpc-invocations.js} +0 -0
  90. /package/dist/{does-type-extend-core-type.d.ts → utils/does-type-extend-core-type.d.ts} +0 -0
  91. /package/dist/{does-type-extend-core-type.js → utils/does-type-extend-core-type.js} +0 -0
  92. /package/dist/{get-property-value.d.ts → utils/get-property-value.d.ts} +0 -0
  93. /package/dist/{get-property-value.js → utils/get-property-value.js} +0 -0
  94. /package/src/{does-type-extend-core-type.ts → utils/does-type-extend-core-type.ts} +0 -0
  95. /package/src/{get-property-value.ts → utils/get-property-value.ts} +0 -0
@@ -0,0 +1,60 @@
1
+ const getMetaTypes = (type, map, desiredType, errors) => {
2
+ if (desiredType) {
3
+ for (const [file, meta] of map.entries()) {
4
+ for (const { type: entryType, variable, typePath } of meta) {
5
+ if (entryType === desiredType) {
6
+ if (entryType === null || typePath === null) {
7
+ throw new Error(`Unknown state due to metaType calculation: entryType or typePath is null for ${desiredType} in ${file}`);
8
+ }
9
+ return { file, variable, type: entryType, typePath };
10
+ }
11
+ }
12
+ }
13
+ if (errors) {
14
+ errors.set(`No ${desiredType} found that extends ${type}`, map);
15
+ }
16
+ return;
17
+ }
18
+ const totalValues = Array.from(map.values()).flat();
19
+ if (totalValues.length === 0) {
20
+ const helpMessage = type === 'CoreConfig'
21
+ ? `No ${type} found. Make sure you have exported a createConfig function in your codebase:\n\n` +
22
+ `export const createConfig: CreateConfig<Config> = async () => {\n` +
23
+ ` return {}\n` +
24
+ `}\n\n` +
25
+ `Possible issues:\n` +
26
+ `- srcDirectories in pikku.config.json doesn't include the file with the createConfig method`
27
+ : `No ${type} found`;
28
+ if (errors) {
29
+ errors.set(helpMessage, map);
30
+ }
31
+ }
32
+ else if (totalValues.length > 1) {
33
+ if (errors) {
34
+ errors.set(`More than one ${type} found`, map);
35
+ }
36
+ }
37
+ else {
38
+ const entry = Array.from(map.entries())[0];
39
+ if (entry) {
40
+ const [file, [{ type: entryType, variable, typePath }]] = entry;
41
+ if (entryType === null || typePath === null) {
42
+ throw new Error(`Unknown state due to metaType calculation: entryType or typePath is null for ${type} in ${file}`);
43
+ }
44
+ return { file, type: entryType, variable, typePath };
45
+ }
46
+ }
47
+ return;
48
+ };
49
+ export const getFilesAndMethods = ({ singletonServicesTypeImportMap, sessionServicesTypeImportMap, userSessionTypeImportMap, sessionServicesFactories, singletonServicesFactories, configFactories, }, { configFileType, userSessionType, singletonServicesFactoryType, sessionServicesFactoryType, } = {}) => {
50
+ const errors = new Map();
51
+ const result = {
52
+ userSessionType: getMetaTypes('CoreUserSession', userSessionTypeImportMap, userSessionType, errors),
53
+ singletonServicesType: getMetaTypes('CoreSingletonServices', singletonServicesTypeImportMap, undefined, errors),
54
+ sessionServicesType: getMetaTypes('CoreServices', sessionServicesTypeImportMap, undefined, errors),
55
+ pikkuConfigFactory: getMetaTypes('CoreConfig', configFactories, configFileType, errors),
56
+ singletonServicesFactory: getMetaTypes('CreateSingletonServices', singletonServicesFactories, singletonServicesFactoryType, errors),
57
+ sessionServicesFactory: getMetaTypes('CreateSessionServices', sessionServicesFactories, sessionServicesFactoryType, errors),
58
+ };
59
+ return { result, errors };
60
+ };
@@ -0,0 +1,39 @@
1
+ import * as ts from 'typescript';
2
+ import { MiddlewareMetadata } from '@pikku/core';
3
+ import { InspectorState } from '../types.js';
4
+ /**
5
+ * Extract middleware pikkuFuncNames from an array literal expression
6
+ * Resolves each identifier to its pikkuFuncName using extractFunctionName
7
+ * Also handles call expressions (like logCommandInfoAndTime({...}))
8
+ */
9
+ export declare function extractMiddlewarePikkuNames(arrayNode: ts.Expression, checker: ts.TypeChecker): string[];
10
+ /**
11
+ * Get middleware array from an object literal expression property
12
+ * Returns the initializer node for the 'middleware' property if it exists
13
+ */
14
+ export declare function getMiddlewareNode(obj: ts.ObjectLiteralExpression): ts.Expression | undefined;
15
+ /**
16
+ * Check if a route matches a pattern with wildcards
17
+ * Pattern can be exact match or use * as wildcard
18
+ * e.g., '/api/*' matches '/api/users', '/api/posts/123', etc.
19
+ */
20
+ export declare function routeMatchesPattern(route: string, pattern: string): boolean;
21
+ /**
22
+ * Resolve middleware for an HTTP wiring based on:
23
+ * 1. Global HTTP middleware (addd([...]))
24
+ * 2. Route-specific HTTP middleware (addHTTPMiddleware('/pattern', [...]))
25
+ * 3. Tag-based middleware (addMiddleware('tag', [...]))
26
+ * 4. Explicit wiring middleware (wireHTTP({ middleware: [...] }))
27
+ * Returns undefined if no middleware is found, otherwise returns array with at least one item
28
+ */
29
+ export declare function resolveHTTPMiddleware(state: InspectorState, route: string, tags: string[] | undefined, explicitMiddlewareNode: ts.Expression | undefined, checker: ts.TypeChecker): MiddlewareMetadata[] | undefined;
30
+ /**
31
+ * Convenience wrapper: Extract middleware node from object and resolve
32
+ * Use this in add-* files for cleaner code
33
+ */
34
+ export declare function resolveMiddleware(state: InspectorState, obj: ts.ObjectLiteralExpression, tags: string[] | undefined, checker: ts.TypeChecker): MiddlewareMetadata[] | undefined;
35
+ /**
36
+ * Convenience wrapper for HTTP: Extract middleware and resolve with HTTP-specific logic
37
+ * Use this in add-http-route.ts for cleaner code
38
+ */
39
+ export declare function resolveHTTPMiddlewareFromObject(state: InspectorState, route: string, obj: ts.ObjectLiteralExpression, tags: string[] | undefined, checker: ts.TypeChecker): MiddlewareMetadata[] | undefined;
@@ -0,0 +1,157 @@
1
+ import * as ts from 'typescript';
2
+ import { extractFunctionName } from './extract-function-name.js';
3
+ /**
4
+ * Extract middleware pikkuFuncNames from an array literal expression
5
+ * Resolves each identifier to its pikkuFuncName using extractFunctionName
6
+ * Also handles call expressions (like logCommandInfoAndTime({...}))
7
+ */
8
+ export function extractMiddlewarePikkuNames(arrayNode, checker) {
9
+ if (!ts.isArrayLiteralExpression(arrayNode)) {
10
+ return [];
11
+ }
12
+ const names = [];
13
+ for (const element of arrayNode.elements) {
14
+ if (ts.isIdentifier(element)) {
15
+ // Resolve the identifier to its pikkuFuncName
16
+ const { pikkuFuncName } = extractFunctionName(element, checker);
17
+ names.push(pikkuFuncName);
18
+ }
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);
23
+ names.push(pikkuFuncName);
24
+ }
25
+ }
26
+ return names;
27
+ }
28
+ /**
29
+ * Get middleware array from an object literal expression property
30
+ * Returns the initializer node for the 'middleware' property if it exists
31
+ */
32
+ export function getMiddlewareNode(obj) {
33
+ const middlewareProp = obj.properties.find((p) => ts.isPropertyAssignment(p) &&
34
+ ts.isIdentifier(p.name) &&
35
+ p.name.text === 'middleware');
36
+ return middlewareProp?.initializer;
37
+ }
38
+ /**
39
+ * Check if a route matches a pattern with wildcards
40
+ * Pattern can be exact match or use * as wildcard
41
+ * e.g., '/api/*' matches '/api/users', '/api/posts/123', etc.
42
+ */
43
+ export function routeMatchesPattern(route, pattern) {
44
+ if (route === pattern)
45
+ return true;
46
+ // Convert pattern to regex: replace * with .*
47
+ const regexPattern = pattern
48
+ .replace(/[.+?^${}()|[\]\\]/g, '\\$&') // Escape regex special chars except *
49
+ .replace(/\*/g, '.*'); // Replace * with .*
50
+ const regex = new RegExp(`^${regexPattern}$`);
51
+ return regex.test(route);
52
+ }
53
+ /**
54
+ * Resolve middleware for an HTTP wiring based on:
55
+ * 1. Global HTTP middleware (addd([...]))
56
+ * 2. Route-specific HTTP middleware (addHTTPMiddleware('/pattern', [...]))
57
+ * 3. Tag-based middleware (addMiddleware('tag', [...]))
58
+ * 4. Explicit wiring middleware (wireHTTP({ middleware: [...] }))
59
+ * Returns undefined if no middleware is found, otherwise returns array with at least one item
60
+ */
61
+ export function resolveHTTPMiddleware(state, route, tags, explicitMiddlewareNode, checker) {
62
+ const resolved = [];
63
+ // 1. HTTP route middleware groups (includes '*' for global)
64
+ for (const [pattern, _groupMeta] of state.http.routeMiddleware.entries()) {
65
+ if (routeMatchesPattern(route, pattern)) {
66
+ // Just reference the group by route pattern
67
+ resolved.push({
68
+ type: 'http',
69
+ route: pattern,
70
+ });
71
+ }
72
+ }
73
+ // 2. Tag-based middleware groups
74
+ if (tags && tags.length > 0) {
75
+ for (const tag of tags) {
76
+ if (state.middleware.tagMiddleware.has(tag)) {
77
+ // Just reference the group by tag
78
+ resolved.push({
79
+ type: 'tag',
80
+ tag,
81
+ });
82
+ }
83
+ }
84
+ }
85
+ // 3. Explicit wire middleware (inline is OK here)
86
+ if (explicitMiddlewareNode) {
87
+ const middlewareNames = extractMiddlewarePikkuNames(explicitMiddlewareNode, checker);
88
+ for (const name of middlewareNames) {
89
+ const meta = state.middleware.meta[name];
90
+ resolved.push({
91
+ type: 'wire',
92
+ name,
93
+ inline: meta?.exportedName === null,
94
+ });
95
+ }
96
+ }
97
+ return resolved.length > 0 ? resolved : undefined;
98
+ }
99
+ /**
100
+ * Resolve tag-based and explicit middleware (common logic for wires and functions)
101
+ * 1. Tag-based middleware (addMiddleware('tag', [...]))
102
+ * 2. Explicit middleware (wireHTTP/pikkuFunc({ middleware: [...] }))
103
+ */
104
+ function resolveTagAndExplicitMiddleware(state, tags, explicitMiddlewareNode, checker) {
105
+ const resolved = [];
106
+ // 1. Tag-based middleware groups
107
+ if (tags && tags.length > 0) {
108
+ for (const tag of tags) {
109
+ if (state.middleware.tagMiddleware.has(tag)) {
110
+ // Just reference the group by tag
111
+ resolved.push({
112
+ type: 'tag',
113
+ tag,
114
+ });
115
+ }
116
+ }
117
+ }
118
+ // 2. Explicit middleware (inline is OK here - used directly in wire/function)
119
+ if (explicitMiddlewareNode) {
120
+ const middlewareNames = extractMiddlewarePikkuNames(explicitMiddlewareNode, checker);
121
+ for (const name of middlewareNames) {
122
+ const meta = state.middleware.meta[name];
123
+ resolved.push({
124
+ type: 'wire',
125
+ name,
126
+ inline: meta?.exportedName === null,
127
+ });
128
+ }
129
+ }
130
+ return resolved;
131
+ }
132
+ /**
133
+ * Resolve middleware for a function based on:
134
+ * 1. Tag-based middleware (addMiddleware('tag', [...]))
135
+ * 2. Explicit function middleware (pikkuFunc({ middleware: [...] }))
136
+ * Returns undefined if no middleware is found, otherwise returns array with at least one item
137
+ */
138
+ function resolveFunctionMiddlewareInternal(state, tags, explicitMiddlewareNode, checker) {
139
+ const resolved = resolveTagAndExplicitMiddleware(state, tags, explicitMiddlewareNode, checker);
140
+ return resolved.length > 0 ? resolved : undefined;
141
+ }
142
+ /**
143
+ * Convenience wrapper: Extract middleware node from object and resolve
144
+ * Use this in add-* files for cleaner code
145
+ */
146
+ export function resolveMiddleware(state, obj, tags, checker) {
147
+ const explicitMiddlewareNode = getMiddlewareNode(obj);
148
+ return resolveFunctionMiddlewareInternal(state, tags, explicitMiddlewareNode, checker);
149
+ }
150
+ /**
151
+ * Convenience wrapper for HTTP: Extract middleware and resolve with HTTP-specific logic
152
+ * Use this in add-http-route.ts for cleaner code
153
+ */
154
+ export function resolveHTTPMiddlewareFromObject(state, route, obj, tags, checker) {
155
+ const explicitMiddlewareNode = getMiddlewareNode(obj);
156
+ return resolveHTTPMiddleware(state, route, tags, explicitMiddlewareNode, checker);
157
+ }
@@ -0,0 +1,3 @@
1
+ import * as ts from 'typescript';
2
+ export declare const extractTypeKeys: (type: ts.Type) => string[];
3
+ export declare function getPropertyAssignmentInitializer(obj: ts.ObjectLiteralExpression, propName: string, followShorthand?: boolean, checker?: ts.TypeChecker): ts.Expression | undefined;
@@ -0,0 +1,50 @@
1
+ import * as ts from 'typescript';
2
+ export const extractTypeKeys = (type) => {
3
+ return type.getProperties().map((symbol) => symbol.getName());
4
+ };
5
+ export function getPropertyAssignmentInitializer(obj, propName, followShorthand = false, checker) {
6
+ for (const prop of obj.properties) {
7
+ // ① foo: () => {}
8
+ if (ts.isPropertyAssignment(prop) &&
9
+ ts.isIdentifier(prop.name) &&
10
+ prop.name.text === propName) {
11
+ return prop.initializer;
12
+ }
13
+ // ② foo() { … }
14
+ if (ts.isMethodDeclaration(prop) &&
15
+ ts.isIdentifier(prop.name) &&
16
+ prop.name.text === propName) {
17
+ return prop.name; // the method node *is* the function
18
+ }
19
+ // ③ { foo } (shorthand)
20
+ if (followShorthand &&
21
+ ts.isShorthandPropertyAssignment(prop) &&
22
+ prop.name.text === propName) {
23
+ if (!checker)
24
+ return prop.name; // best effort without a checker
25
+ let sym = checker.getSymbolAtLocation(prop.name);
26
+ if (sym && sym.flags & ts.SymbolFlags.Alias) {
27
+ sym = checker.getAliasedSymbol(sym);
28
+ }
29
+ const decl = sym?.declarations?.[0];
30
+ // const foo = () => {}
31
+ if (decl &&
32
+ ts.isVariableDeclaration(decl) &&
33
+ decl.initializer &&
34
+ (ts.isArrowFunction(decl.initializer) ||
35
+ ts.isFunctionExpression(decl.initializer))) {
36
+ return decl.initializer;
37
+ }
38
+ // function foo() {}
39
+ if (decl &&
40
+ (ts.isFunctionDeclaration(decl) ||
41
+ ts.isArrowFunction(decl) ||
42
+ ts.isFunctionExpression(decl))) {
43
+ return decl;
44
+ }
45
+ // fallback – just give back the identifier
46
+ return prop.name;
47
+ }
48
+ }
49
+ return undefined;
50
+ }
package/dist/visit.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import * as ts from 'typescript';
2
- import { InspectorFilters, InspectorState, InspectorLogger } from './types.js';
3
- export declare const visitSetup: (checker: ts.TypeChecker, node: ts.Node, state: InspectorState, filters: InspectorFilters, logger: InspectorLogger) => void;
4
- export declare const visitRoutes: (checker: ts.TypeChecker, node: ts.Node, state: InspectorState, filters: InspectorFilters, logger: InspectorLogger) => void;
2
+ import { InspectorState, InspectorLogger, InspectorOptions } from './types.js';
3
+ export declare const visitSetup: (logger: InspectorLogger, checker: ts.TypeChecker, node: ts.Node, state: InspectorState, options: InspectorOptions) => void;
4
+ export declare const visitRoutes: (logger: InspectorLogger, checker: ts.TypeChecker, node: ts.Node, state: InspectorState, options: InspectorOptions) => void;
package/dist/visit.js CHANGED
@@ -1,37 +1,40 @@
1
1
  import * as ts from 'typescript';
2
- import { addFileWithFactory } from './add-file-with-factory.js';
3
- import { addFileExtendsCoreType } from './add-file-extends-core-type.js';
4
- import { addHTTPRoute } from './add-http-route.js';
5
- import { addSchedule } from './add-schedule.js';
6
- import { addQueueWorker } from './add-queue-worker.js';
7
- import { addMCPResource } from './add-mcp-resource.js';
8
- import { addMCPTool } from './add-mcp-tool.js';
9
- import { addMCPPrompt } from './add-mcp-prompt.js';
10
- import { addFunctions } from './add-functions.js';
11
- import { addChannel } from './add-channel.js';
12
- import { addRPCInvocations } from './add-rpc-invocations.js';
13
- import { addMiddleware } from './add-middleware.js';
14
- import { addPermission } from './add-permission.js';
15
- export const visitSetup = (checker, node, state, filters, logger) => {
16
- addFileExtendsCoreType(node, checker, state.singletonServicesTypeImportMap, 'CoreSingletonServices');
17
- addFileExtendsCoreType(node, checker, state.sessionServicesTypeImportMap, 'CoreServices');
18
- addFileExtendsCoreType(node, checker, state.userSessionTypeImportMap, 'CoreUserSession');
2
+ import { addFileWithFactory } from './add/add-file-with-factory.js';
3
+ import { addFileExtendsCoreType } from './add/add-file-extends-core-type.js';
4
+ import { addHTTPRoute } from './add/add-http-route.js';
5
+ import { addSchedule } from './add/add-schedule.js';
6
+ import { addQueueWorker } from './add/add-queue-worker.js';
7
+ import { addMCPResource } from './add/add-mcp-resource.js';
8
+ import { addMCPTool } from './add/add-mcp-tool.js';
9
+ import { addMCPPrompt } from './add/add-mcp-prompt.js';
10
+ import { addFunctions } from './add/add-functions.js';
11
+ import { addChannel } from './add/add-channel.js';
12
+ import { addRPCInvocations } from './add/add-rpc-invocations.js';
13
+ import { addMiddleware } from './add/add-middleware.js';
14
+ import { addPermission } from './add/add-permission.js';
15
+ import { addCLI } from './add/add-cli.js';
16
+ export const visitSetup = (logger, checker, node, state, options) => {
17
+ addFileExtendsCoreType(node, checker, state.singletonServicesTypeImportMap, 'CoreSingletonServices', state);
18
+ addFileExtendsCoreType(node, checker, state.sessionServicesTypeImportMap, 'CoreServices', state);
19
+ addFileExtendsCoreType(node, checker, state.userSessionTypeImportMap, 'CoreUserSession', state);
20
+ addFileExtendsCoreType(node, checker, state.configTypeImportMap, 'CoreConfig', state);
19
21
  addFileWithFactory(node, checker, state.singletonServicesFactories, 'CreateSingletonServices');
20
22
  addFileWithFactory(node, checker, state.sessionServicesFactories, 'CreateSessionServices');
21
23
  addFileWithFactory(node, checker, state.configFactories, 'CreateConfig');
22
24
  addRPCInvocations(node, state, logger);
23
- ts.forEachChild(node, (child) => visitSetup(checker, child, state, filters, logger));
25
+ addMiddleware(logger, node, checker, state, options);
26
+ addPermission(logger, node, checker, state, options);
27
+ ts.forEachChild(node, (child) => visitSetup(logger, checker, child, state, options));
24
28
  };
25
- export const visitRoutes = (checker, node, state, filters, logger) => {
26
- addFunctions(node, checker, state, logger);
27
- addHTTPRoute(node, checker, state, filters, logger);
28
- addSchedule(node, checker, state, filters, logger);
29
- addQueueWorker(node, checker, state, filters, logger);
30
- addChannel(node, checker, state, filters, logger);
31
- addMCPResource(node, checker, state, filters, logger);
32
- addMCPTool(node, checker, state, filters, logger);
33
- addMCPPrompt(node, checker, state, filters, logger);
34
- addMiddleware(node, checker, state, logger);
35
- addPermission(node, checker, state, logger);
36
- ts.forEachChild(node, (child) => visitRoutes(checker, child, state, filters, logger));
29
+ export const visitRoutes = (logger, checker, node, state, options) => {
30
+ addFunctions(logger, node, checker, state, options);
31
+ addHTTPRoute(logger, node, checker, state, options);
32
+ addSchedule(logger, node, checker, state, options);
33
+ addQueueWorker(logger, node, checker, state, options);
34
+ addChannel(logger, node, checker, state, options);
35
+ addCLI(logger, node, checker, state, options);
36
+ addMCPResource(logger, node, checker, state, options);
37
+ addMCPTool(logger, node, checker, state, options);
38
+ addMCPPrompt(logger, node, checker, state, options);
39
+ ts.forEachChild(node, (child) => visitRoutes(logger, checker, child, state, options));
37
40
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/inspector",
3
- "version": "0.9.4",
3
+ "version": "0.9.6-next.0",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -8,8 +8,7 @@
8
8
  "main": "dist/index.js",
9
9
  "scripts": {
10
10
  "tsc": "tsc",
11
- "build:esm": "tsc -b",
12
- "build": "yarn build:esm",
11
+ "build": "tsc -b",
13
12
  "ncu": "npx npm-check-updates -x '/.*glob.*/'",
14
13
  "release": "yarn build && npm test",
15
14
  "test": "bash run-tests.sh",
@@ -17,7 +16,7 @@
17
16
  "test:coverage": "bash run-tests.sh --coverage"
18
17
  },
19
18
  "dependencies": {
20
- "@pikku/core": "^0.9.6",
19
+ "@pikku/core": "^0.9.12-next.0",
21
20
  "path-to-regexp": "^8.2.0",
22
21
  "typescript": "^5.9"
23
22
  },
package/run-tests.sh CHANGED
@@ -46,7 +46,7 @@ if [ "$watch_mode" = true ]; then
46
46
  fi
47
47
 
48
48
  if [ "$coverage_mode" = true ]; then
49
- node_cmd="$node_cmd --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info"
49
+ node_cmd="$node_cmd --test-coverage-include=\"src/**/*.{ts,js}\" --test-coverage-exclude=\"**/dist/**\" --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info"
50
50
  fi
51
51
 
52
52
  # Execute the node command with the expanded list of files
@@ -1,21 +1,16 @@
1
1
  import * as ts from 'typescript'
2
- import { getPropertyValue } from './get-property-value.js'
2
+ import { getPropertyValue } from '../utils/get-property-value.js'
3
3
  import { pathToRegexp } from 'path-to-regexp'
4
4
  import { PikkuDocs, PikkuWiringTypes } from '@pikku/core'
5
- import {
6
- extractFunctionName,
7
- getPropertyAssignmentInitializer,
8
- matchesFilters,
9
- } from './utils.js'
5
+ import { extractFunctionName } from '../utils/extract-function-name.js'
6
+ import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
7
+ import { matchesFilters } from '../utils/filter-utils.js'
10
8
  import type { ChannelMessageMeta, ChannelMeta } from '@pikku/core/channel'
11
- import type {
12
- InspectorFilters,
13
- InspectorState,
14
- InspectorLogger,
15
- } from './types.js'
9
+ import type { InspectorState, AddWiring } from '../types.js'
10
+ import { resolveMiddleware } from '../utils/middleware.js'
16
11
 
17
12
  /**
18
- * Safely get the initializer expression of a property-like AST node:
13
+ * Safely get the "initializer" expression of a property-like AST node:
19
14
  * - for `foo: expr`, returns `expr`
20
15
  * - for `{ foo }` shorthand, returns the identifier `foo`
21
16
  * - otherwise, returns undefined
@@ -363,13 +358,14 @@ export function addMessagesRoutes(
363
358
  * Inspect addChannel calls, look up all handlers in state.functions.meta,
364
359
  * and emit one entry into state.channels.meta.
365
360
  */
366
- export function addChannel(
367
- node: ts.Node,
368
- checker: ts.TypeChecker,
369
- state: InspectorState,
370
- filters: InspectorFilters,
371
- logger: InspectorLogger
372
- ) {
361
+ export const addChannel: AddWiring = (
362
+ logger,
363
+ node,
364
+ checker,
365
+ state,
366
+ options
367
+ ) => {
368
+ const filters = options.filters || {}
373
369
  if (!ts.isCallExpression(node)) return
374
370
  const { expression, arguments: args } = node
375
371
  if (!ts.isIdentifier(expression) || expression.text !== 'wireChannel') return
@@ -450,6 +446,9 @@ export function addChannel(
450
446
  // nested message-routes
451
447
  const messageWirings = addMessagesRoutes(obj, state, checker)
452
448
 
449
+ // --- resolve middleware ---
450
+ const middleware = resolveMiddleware(state, obj, tags, checker)
451
+
453
452
  // record into state
454
453
  state.channels.files.add(node.getSourceFile().fileName)
455
454
  state.channels.meta[name] = {
@@ -478,5 +477,6 @@ export function addChannel(
478
477
  messageWirings,
479
478
  docs: docs ?? undefined,
480
479
  tags: tags ?? undefined,
480
+ middleware,
481
481
  }
482
482
  }