@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
@@ -0,0 +1,170 @@
1
+ import { TypesMap } from '../types-map.js';
2
+ /**
3
+ * Serializes InspectorState to a JSON-compatible format
4
+ * Omits typesLookup (not needed for filtering/generation) and converts Maps/Sets to arrays
5
+ */
6
+ export function serializeInspectorState(state) {
7
+ // Helper to serialize TypesMap
8
+ const serializeTypesMap = (typesMap) => {
9
+ // Access private map via type assertion
10
+ const mapEntries = Array.from(typesMap.map.entries());
11
+ const customTypesEntries = Array.from(typesMap.customTypes.entries());
12
+ return {
13
+ map: mapEntries,
14
+ customTypes: customTypesEntries,
15
+ };
16
+ };
17
+ return {
18
+ rootDir: state.rootDir,
19
+ singletonServicesTypeImportMap: Array.from(state.singletonServicesTypeImportMap.entries()),
20
+ sessionServicesTypeImportMap: Array.from(state.sessionServicesTypeImportMap.entries()),
21
+ userSessionTypeImportMap: Array.from(state.userSessionTypeImportMap.entries()),
22
+ configTypeImportMap: Array.from(state.configTypeImportMap.entries()),
23
+ singletonServicesFactories: Array.from(state.singletonServicesFactories.entries()),
24
+ sessionServicesFactories: Array.from(state.sessionServicesFactories.entries()),
25
+ sessionServicesMeta: Array.from(state.sessionServicesMeta.entries()),
26
+ configFactories: Array.from(state.configFactories.entries()),
27
+ filesAndMethods: state.filesAndMethods,
28
+ filesAndMethodsErrors: Array.from(state.filesAndMethodsErrors.entries()).map(([key, mapValue]) => [key, Array.from(mapValue.entries())]),
29
+ functions: {
30
+ typesMap: serializeTypesMap(state.functions.typesMap),
31
+ meta: state.functions.meta,
32
+ files: Array.from(state.functions.files.entries()),
33
+ },
34
+ http: {
35
+ metaInputTypes: Array.from(state.http.metaInputTypes.entries()),
36
+ meta: state.http.meta,
37
+ files: Array.from(state.http.files),
38
+ routeMiddleware: Array.from(state.http.routeMiddleware.entries()),
39
+ routePermissions: Array.from(state.http.routePermissions.entries()),
40
+ },
41
+ channels: {
42
+ files: Array.from(state.channels.files),
43
+ meta: state.channels.meta,
44
+ },
45
+ scheduledTasks: {
46
+ meta: state.scheduledTasks.meta,
47
+ files: Array.from(state.scheduledTasks.files),
48
+ },
49
+ queueWorkers: {
50
+ meta: state.queueWorkers.meta,
51
+ files: Array.from(state.queueWorkers.files),
52
+ },
53
+ rpc: {
54
+ internalMeta: state.rpc.internalMeta,
55
+ internalFiles: Array.from(state.rpc.internalFiles.entries()),
56
+ exposedMeta: state.rpc.exposedMeta,
57
+ exposedFiles: Array.from(state.rpc.exposedFiles.entries()),
58
+ invokedFunctions: Array.from(state.rpc.invokedFunctions),
59
+ },
60
+ mcpEndpoints: {
61
+ resourcesMeta: state.mcpEndpoints.resourcesMeta,
62
+ toolsMeta: state.mcpEndpoints.toolsMeta,
63
+ promptsMeta: state.mcpEndpoints.promptsMeta,
64
+ files: Array.from(state.mcpEndpoints.files),
65
+ },
66
+ cli: {
67
+ meta: state.cli.meta,
68
+ files: Array.from(state.cli.files),
69
+ },
70
+ middleware: {
71
+ meta: state.middleware.meta,
72
+ tagMiddleware: Array.from(state.middleware.tagMiddleware.entries()),
73
+ },
74
+ permissions: {
75
+ meta: state.permissions.meta,
76
+ tagPermissions: Array.from(state.permissions.tagPermissions.entries()),
77
+ },
78
+ serviceAggregation: {
79
+ requiredServices: Array.from(state.serviceAggregation.requiredServices),
80
+ usedFunctions: Array.from(state.serviceAggregation.usedFunctions),
81
+ usedMiddleware: Array.from(state.serviceAggregation.usedMiddleware),
82
+ usedPermissions: Array.from(state.serviceAggregation.usedPermissions),
83
+ },
84
+ };
85
+ }
86
+ /**
87
+ * Deserializes JSON data back to InspectorState
88
+ * Creates a partial state suitable for filtering/generation (without typesLookup)
89
+ */
90
+ export function deserializeInspectorState(data) {
91
+ // Helper to deserialize TypesMap
92
+ const deserializeTypesMap = (serialized) => {
93
+ const typesMap = new TypesMap();
94
+ typesMap.map = new Map(serialized.map);
95
+ // Restore public customTypes
96
+ typesMap.customTypes = new Map(serialized.customTypes);
97
+ return typesMap;
98
+ };
99
+ return {
100
+ rootDir: data.rootDir,
101
+ singletonServicesTypeImportMap: new Map(data.singletonServicesTypeImportMap),
102
+ sessionServicesTypeImportMap: new Map(data.sessionServicesTypeImportMap),
103
+ userSessionTypeImportMap: new Map(data.userSessionTypeImportMap),
104
+ configTypeImportMap: new Map(data.configTypeImportMap),
105
+ singletonServicesFactories: new Map(data.singletonServicesFactories),
106
+ sessionServicesFactories: new Map(data.sessionServicesFactories),
107
+ sessionServicesMeta: new Map(data.sessionServicesMeta),
108
+ configFactories: new Map(data.configFactories),
109
+ filesAndMethods: data.filesAndMethods,
110
+ filesAndMethodsErrors: new Map(data.filesAndMethodsErrors.map(([key, entries]) => [
111
+ key,
112
+ new Map(entries),
113
+ ])),
114
+ functions: {
115
+ typesMap: deserializeTypesMap(data.functions.typesMap),
116
+ meta: data.functions.meta,
117
+ files: new Map(data.functions.files),
118
+ },
119
+ http: {
120
+ metaInputTypes: new Map(data.http.metaInputTypes),
121
+ meta: data.http.meta,
122
+ files: new Set(data.http.files),
123
+ routeMiddleware: new Map(data.http.routeMiddleware),
124
+ routePermissions: new Map(data.http.routePermissions),
125
+ },
126
+ channels: {
127
+ files: new Set(data.channels.files),
128
+ meta: data.channels.meta,
129
+ },
130
+ scheduledTasks: {
131
+ meta: data.scheduledTasks.meta,
132
+ files: new Set(data.scheduledTasks.files),
133
+ },
134
+ queueWorkers: {
135
+ meta: data.queueWorkers.meta,
136
+ files: new Set(data.queueWorkers.files),
137
+ },
138
+ rpc: {
139
+ internalMeta: data.rpc.internalMeta,
140
+ internalFiles: new Map(data.rpc.internalFiles),
141
+ exposedMeta: data.rpc.exposedMeta,
142
+ exposedFiles: new Map(data.rpc.exposedFiles),
143
+ invokedFunctions: new Set(data.rpc.invokedFunctions),
144
+ },
145
+ mcpEndpoints: {
146
+ resourcesMeta: data.mcpEndpoints.resourcesMeta,
147
+ toolsMeta: data.mcpEndpoints.toolsMeta,
148
+ promptsMeta: data.mcpEndpoints.promptsMeta,
149
+ files: new Set(data.mcpEndpoints.files),
150
+ },
151
+ cli: {
152
+ meta: data.cli.meta,
153
+ files: new Set(data.cli.files),
154
+ },
155
+ middleware: {
156
+ meta: data.middleware.meta,
157
+ tagMiddleware: new Map(data.middleware.tagMiddleware),
158
+ },
159
+ permissions: {
160
+ meta: data.permissions.meta,
161
+ tagPermissions: new Map(data.permissions.tagPermissions),
162
+ },
163
+ serviceAggregation: {
164
+ requiredServices: new Set(data.serviceAggregation.requiredServices),
165
+ usedFunctions: new Set(data.serviceAggregation.usedFunctions),
166
+ usedMiddleware: new Set(data.serviceAggregation.usedMiddleware),
167
+ usedPermissions: new Set(data.serviceAggregation.usedPermissions),
168
+ },
169
+ };
170
+ }
package/dist/visit.js CHANGED
@@ -12,14 +12,14 @@ import { addChannel } from './add/add-channel.js';
12
12
  import { addRPCInvocations } from './add/add-rpc-invocations.js';
13
13
  import { addMiddleware } from './add/add-middleware.js';
14
14
  import { addPermission } from './add/add-permission.js';
15
- import { addCLI } from './add/add-cli.js';
15
+ import { addCLI, addCLIRenderers } from './add/add-cli.js';
16
16
  export const visitSetup = (logger, checker, node, state, options) => {
17
17
  addFileExtendsCoreType(node, checker, state.singletonServicesTypeImportMap, 'CoreSingletonServices', state);
18
18
  addFileExtendsCoreType(node, checker, state.sessionServicesTypeImportMap, 'CoreServices', state);
19
19
  addFileExtendsCoreType(node, checker, state.userSessionTypeImportMap, 'CoreUserSession', state);
20
20
  addFileExtendsCoreType(node, checker, state.configTypeImportMap, 'CoreConfig', state);
21
21
  addFileWithFactory(node, checker, state.singletonServicesFactories, 'CreateSingletonServices');
22
- addFileWithFactory(node, checker, state.sessionServicesFactories, 'CreateSessionServices');
22
+ addFileWithFactory(node, checker, state.sessionServicesFactories, 'CreateSessionServices', state);
23
23
  addFileWithFactory(node, checker, state.configFactories, 'CreateConfig');
24
24
  addRPCInvocations(node, state, logger);
25
25
  addMiddleware(logger, node, checker, state, options);
@@ -33,6 +33,7 @@ export const visitRoutes = (logger, checker, node, state, options) => {
33
33
  addQueueWorker(logger, node, checker, state, options);
34
34
  addChannel(logger, node, checker, state, options);
35
35
  addCLI(logger, node, checker, state, options);
36
+ addCLIRenderers(logger, node, checker, state, options);
36
37
  addMCPResource(logger, node, checker, state, options);
37
38
  addMCPTool(logger, node, checker, state, options);
38
39
  addMCPPrompt(logger, node, checker, state, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/inspector",
3
- "version": "0.9.6-next.0",
3
+ "version": "0.10.1",
4
4
  "author": "yasser.fadl@gmail.com",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -16,12 +16,12 @@
16
16
  "test:coverage": "bash run-tests.sh --coverage"
17
17
  },
18
18
  "dependencies": {
19
- "@pikku/core": "^0.9.12-next.0",
20
- "path-to-regexp": "^8.2.0",
19
+ "@pikku/core": "^0.10.1",
20
+ "path-to-regexp": "^8.3.0",
21
21
  "typescript": "^5.9"
22
22
  },
23
23
  "devDependencies": {
24
- "@types/node": "^24.2.1"
24
+ "@types/node": "^24.9.1"
25
25
  },
26
26
  "engines": {
27
27
  "node": ">=18"
@@ -1,13 +1,17 @@
1
1
  import * as ts from 'typescript'
2
- import { getPropertyValue } from '../utils/get-property-value.js'
2
+ import { ErrorCode } from '../error-codes.js'
3
+ import {
4
+ getPropertyValue,
5
+ getPropertyTags,
6
+ } from '../utils/get-property-value.js'
3
7
  import { pathToRegexp } from 'path-to-regexp'
4
- import { PikkuDocs, PikkuWiringTypes } from '@pikku/core'
8
+ import { PikkuDocs } from '@pikku/core'
5
9
  import { extractFunctionName } from '../utils/extract-function-name.js'
6
10
  import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
7
- import { matchesFilters } from '../utils/filter-utils.js'
8
11
  import type { ChannelMessageMeta, ChannelMeta } from '@pikku/core/channel'
9
12
  import type { InspectorState, AddWiring } from '../types.js'
10
13
  import { resolveMiddleware } from '../utils/middleware.js'
14
+ import { extractWireNames } from '../utils/post-process.js'
11
15
 
12
16
  /**
13
17
  * Safely get the "initializer" expression of a property-like AST node:
@@ -33,7 +37,8 @@ function getInitializerOf(
33
37
  */
34
38
  function getHandlerNameFromExpression(
35
39
  expr: ts.Expression,
36
- checker: ts.TypeChecker
40
+ checker: ts.TypeChecker,
41
+ rootDir: string
37
42
  ): string | null {
38
43
  // Handle direct identifier case (which includes shorthand properties)
39
44
  if (ts.isIdentifier(expr)) {
@@ -59,27 +64,28 @@ function getHandlerNameFromExpression(
59
64
  // Extract function name from the declaration's initializer
60
65
  const { pikkuFuncName } = extractFunctionName(
61
66
  decl.initializer,
62
- checker
67
+ checker,
68
+ rootDir
63
69
  )
64
70
  return pikkuFuncName
65
71
  }
66
72
  }
67
73
  // For function declarations, use directly
68
74
  else if (ts.isFunctionDeclaration(decl)) {
69
- const { pikkuFuncName } = extractFunctionName(decl, checker)
75
+ const { pikkuFuncName } = extractFunctionName(decl, checker, rootDir)
70
76
  return pikkuFuncName
71
77
  }
72
78
  }
73
79
  }
74
80
 
75
81
  // Fallback: try to extract directly from the identifier
76
- const { pikkuFuncName } = extractFunctionName(expr, checker)
82
+ const { pikkuFuncName } = extractFunctionName(expr, checker, rootDir)
77
83
  return pikkuFuncName
78
84
  }
79
85
 
80
86
  // Handle call expressions
81
87
  if (ts.isCallExpression(expr)) {
82
- const { pikkuFuncName } = extractFunctionName(expr, checker)
88
+ const { pikkuFuncName } = extractFunctionName(expr, checker, rootDir)
83
89
  return pikkuFuncName
84
90
  }
85
91
 
@@ -87,7 +93,7 @@ function getHandlerNameFromExpression(
87
93
  if (ts.isObjectLiteralExpression(expr)) {
88
94
  const fnProp = getPropertyAssignmentInitializer(expr, 'func', true, checker)
89
95
  if (fnProp) {
90
- return getHandlerNameFromExpression(fnProp, checker)
96
+ return getHandlerNameFromExpression(fnProp, checker, rootDir)
91
97
  }
92
98
  }
93
99
 
@@ -99,6 +105,10 @@ function getHandlerNameFromExpression(
99
105
  * in state.functions.meta instead of re-inferring it here.
100
106
  */
101
107
  export function addMessagesRoutes(
108
+ logger: {
109
+ error: (msg: string) => void
110
+ critical: (code: ErrorCode, msg: string) => void
111
+ },
102
112
  obj: ts.ObjectLiteralExpression,
103
113
  state: InspectorState,
104
114
  checker: ts.TypeChecker
@@ -178,7 +188,8 @@ export function addMessagesRoutes(
178
188
  ) {
179
189
  const { pikkuFuncName } = extractFunctionName(
180
190
  importDecl.initializer,
181
- checker
191
+ checker,
192
+ state.rootDir
182
193
  )
183
194
  const handlerName = pikkuFuncName
184
195
 
@@ -195,7 +206,8 @@ export function addMessagesRoutes(
195
206
  // Extract from the function declaration
196
207
  const { pikkuFuncName } = extractFunctionName(
197
208
  importDecl,
198
- checker
209
+ checker,
210
+ state.rootDir
199
211
  )
200
212
  const handlerName = pikkuFuncName
201
213
 
@@ -230,7 +242,8 @@ export function addMessagesRoutes(
230
242
  ) {
231
243
  const { pikkuFuncName } = extractFunctionName(
232
244
  exportDecl.initializer,
233
- checker
245
+ checker,
246
+ state.rootDir
234
247
  )
235
248
  const handlerName = pikkuFuncName
236
249
 
@@ -244,7 +257,8 @@ export function addMessagesRoutes(
244
257
  } else if (ts.isFunctionDeclaration(exportDecl)) {
245
258
  const { pikkuFuncName } = extractFunctionName(
246
259
  exportDecl,
247
- checker
260
+ checker,
261
+ state.rootDir
248
262
  )
249
263
  const handlerName = pikkuFuncName
250
264
 
@@ -277,7 +291,8 @@ export function addMessagesRoutes(
277
291
  if (possibleMatch) {
278
292
  const fnMeta = state.functions.meta[possibleMatch]
279
293
  if (!fnMeta) {
280
- console.error(
294
+ logger.critical(
295
+ ErrorCode.FUNCTION_METADATA_NOT_FOUND,
281
296
  `No function metadata found for handler '${possibleMatch}'`
282
297
  )
283
298
  continue
@@ -312,7 +327,8 @@ export function addMessagesRoutes(
312
327
  // Extract the function name directly from the actual function
313
328
  const { pikkuFuncName } = extractFunctionName(
314
329
  actualFunction,
315
- checker
330
+ checker,
331
+ state.rootDir
316
332
  )
317
333
  const handlerName = pikkuFuncName
318
334
 
@@ -331,9 +347,13 @@ export function addMessagesRoutes(
331
347
  }
332
348
 
333
349
  // Normal processing for non-shorthand properties
334
- const handlerName = getHandlerNameFromExpression(init, checker)
350
+ const handlerName = getHandlerNameFromExpression(
351
+ init,
352
+ checker,
353
+ state.rootDir
354
+ )
335
355
  if (!handlerName) {
336
- console.error(
356
+ logger.error(
337
357
  `Could not resolve handler for message route '${routeKey}'`
338
358
  )
339
359
  continue
@@ -341,7 +361,10 @@ export function addMessagesRoutes(
341
361
 
342
362
  const fnMeta = state.functions.meta[handlerName]
343
363
  if (!fnMeta) {
344
- console.error(`No function metadata found for handler '${handlerName}'`)
364
+ logger.critical(
365
+ ErrorCode.FUNCTION_METADATA_NOT_FOUND,
366
+ `No function metadata found for handler '${handlerName}'`
367
+ )
345
368
  continue
346
369
  }
347
370
 
@@ -365,7 +388,6 @@ export const addChannel: AddWiring = (
365
388
  state,
366
389
  options
367
390
  ) => {
368
- const filters = options.filters || {}
369
391
  if (!ts.isCallExpression(node)) return
370
392
  const { expression, arguments: args } = node
371
393
  if (!ts.isIdentifier(expression) || expression.text !== 'wireChannel') return
@@ -377,7 +399,7 @@ export const addChannel: AddWiring = (
377
399
  const route = (getPropertyValue(obj, 'route') as string) ?? ''
378
400
 
379
401
  if (!name) {
380
- console.error('Channel name is required')
402
+ logger.critical(ErrorCode.MISSING_CHANNEL_NAME, 'Channel name is required')
381
403
  return
382
404
  }
383
405
 
@@ -389,21 +411,9 @@ export const addChannel: AddWiring = (
389
411
  : []
390
412
 
391
413
  const docs = getPropertyValue(obj, 'docs') as PikkuDocs | undefined
392
- const tags = getPropertyValue(obj, 'tags') as string[] | undefined
414
+ const tags = getPropertyTags(obj, 'Channel', route, logger)
393
415
  const query = getPropertyValue(obj, 'query') as string[] | []
394
416
 
395
- const filePath = node.getSourceFile().fileName
396
-
397
- if (
398
- !matchesFilters(
399
- filters,
400
- { tags },
401
- { type: PikkuWiringTypes.channel, name, filePath },
402
- logger
403
- )
404
- )
405
- return
406
-
407
417
  const connect = getPropertyAssignmentInitializer(
408
418
  obj,
409
419
  'onConnect',
@@ -428,7 +438,8 @@ export const addChannel: AddWiring = (
428
438
 
429
439
  if (onMsgProp) {
430
440
  const handlerName =
431
- onMsgProp && getHandlerNameFromExpression(onMsgProp, checker)
441
+ onMsgProp &&
442
+ getHandlerNameFromExpression(onMsgProp, checker, state.rootDir)
432
443
  const fnMeta = handlerName && state.functions.meta[handlerName]
433
444
  if (!fnMeta) {
434
445
  console.error(
@@ -437,18 +448,53 @@ export const addChannel: AddWiring = (
437
448
  throw new Error()
438
449
  } else {
439
450
  message = {
440
- pikkuFuncName: extractFunctionName(onMsgProp as any, checker)
441
- .pikkuFuncName,
451
+ pikkuFuncName: extractFunctionName(
452
+ onMsgProp as any,
453
+ checker,
454
+ state.rootDir
455
+ ).pikkuFuncName,
442
456
  }
443
457
  }
444
458
  }
445
459
 
446
460
  // nested message-routes
447
- const messageWirings = addMessagesRoutes(obj, state, checker)
461
+ const messageWirings = addMessagesRoutes(logger, obj, state, checker)
448
462
 
449
463
  // --- resolve middleware ---
450
464
  const middleware = resolveMiddleware(state, obj, tags, checker)
451
465
 
466
+ // --- track used functions/middleware for service aggregation ---
467
+ // Track connect/disconnect/message handlers
468
+ if (connect) {
469
+ const connectFuncName = extractFunctionName(
470
+ connect,
471
+ checker,
472
+ state.rootDir
473
+ ).pikkuFuncName
474
+ state.serviceAggregation.usedFunctions.add(connectFuncName)
475
+ }
476
+ if (disconnect) {
477
+ const disconnectFuncName = extractFunctionName(
478
+ disconnect as any,
479
+ checker,
480
+ state.rootDir
481
+ ).pikkuFuncName
482
+ state.serviceAggregation.usedFunctions.add(disconnectFuncName)
483
+ }
484
+ if (message) {
485
+ state.serviceAggregation.usedFunctions.add(message.pikkuFuncName)
486
+ }
487
+ // Track message wiring handlers
488
+ for (const channelHandlers of Object.values(messageWirings)) {
489
+ for (const handler of Object.values(channelHandlers)) {
490
+ state.serviceAggregation.usedFunctions.add(handler.pikkuFuncName)
491
+ }
492
+ }
493
+ // Track middleware
494
+ extractWireNames(middleware).forEach((name) =>
495
+ state.serviceAggregation.usedMiddleware.add(name)
496
+ )
497
+
452
498
  // record into state
453
499
  state.channels.files.add(node.getSourceFile().fileName)
454
500
  state.channels.meta[name] = {
@@ -465,12 +511,18 @@ export const addChannel: AddWiring = (
465
511
  // params
466
512
  // ),
467
513
  connect: connect
468
- ? { pikkuFuncName: extractFunctionName(connect, checker).pikkuFuncName }
514
+ ? {
515
+ pikkuFuncName: extractFunctionName(connect, checker, state.rootDir)
516
+ .pikkuFuncName,
517
+ }
469
518
  : null,
470
519
  disconnect: disconnect
471
520
  ? {
472
- pikkuFuncName: extractFunctionName(disconnect as any, checker)
473
- .pikkuFuncName,
521
+ pikkuFuncName: extractFunctionName(
522
+ disconnect as any,
523
+ checker,
524
+ state.rootDir
525
+ ).pikkuFuncName,
474
526
  }
475
527
  : null,
476
528
  message,