@pikku/inspector 0.11.2 → 0.12.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 (211) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/OPTIMIZATION-PLAN.md +195 -0
  3. package/dist/add/add-ai-agent.d.ts +2 -0
  4. package/dist/add/add-ai-agent.js +314 -0
  5. package/dist/add/add-channel.js +81 -61
  6. package/dist/add/add-cli.d.ts +1 -1
  7. package/dist/add/add-cli.js +42 -19
  8. package/dist/add/add-file-extends-core-type.d.ts +1 -1
  9. package/dist/add/add-file-with-config.d.ts +1 -1
  10. package/dist/add/add-file-with-factory.d.ts +1 -1
  11. package/dist/add/add-file-with-factory.js +2 -0
  12. package/dist/add/add-functions.d.ts +1 -1
  13. package/dist/add/add-functions.js +256 -82
  14. package/dist/add/add-http-route.d.ts +20 -10
  15. package/dist/add/add-http-route.js +156 -66
  16. package/dist/add/add-http-routes.d.ts +5 -0
  17. package/dist/add/add-http-routes.js +160 -0
  18. package/dist/add/add-keyed-wiring.d.ts +12 -0
  19. package/dist/add/add-keyed-wiring.js +97 -0
  20. package/dist/add/add-mcp-prompt.d.ts +1 -1
  21. package/dist/add/add-mcp-prompt.js +14 -9
  22. package/dist/add/add-mcp-resource.d.ts +1 -1
  23. package/dist/add/add-mcp-resource.js +14 -9
  24. package/dist/add/add-middleware.d.ts +1 -4
  25. package/dist/add/add-middleware.js +364 -79
  26. package/dist/add/add-permission.d.ts +1 -1
  27. package/dist/add/add-permission.js +152 -40
  28. package/dist/add/add-queue-worker.d.ts +1 -1
  29. package/dist/add/add-queue-worker.js +18 -12
  30. package/dist/add/add-rpc-invocations.d.ts +3 -3
  31. package/dist/add/add-rpc-invocations.js +24 -10
  32. package/dist/add/add-schedule.d.ts +1 -1
  33. package/dist/add/add-schedule.js +11 -5
  34. package/dist/add/add-secret.d.ts +3 -0
  35. package/dist/add/add-secret.js +82 -0
  36. package/dist/add/add-trigger.d.ts +2 -0
  37. package/dist/add/add-trigger.js +87 -0
  38. package/dist/add/add-variable.d.ts +1 -0
  39. package/dist/add/add-variable.js +8 -0
  40. package/dist/add/add-wire-addon.d.ts +7 -0
  41. package/dist/add/add-wire-addon.js +70 -0
  42. package/dist/add/add-workflow-graph.d.ts +3 -2
  43. package/dist/add/add-workflow-graph.js +143 -406
  44. package/dist/add/add-workflow.d.ts +1 -1
  45. package/dist/add/add-workflow.js +6 -4
  46. package/dist/error-codes.d.ts +15 -1
  47. package/dist/error-codes.js +20 -1
  48. package/dist/index.d.ts +9 -8
  49. package/dist/index.js +5 -4
  50. package/dist/inspector.d.ts +2 -2
  51. package/dist/inspector.js +95 -15
  52. package/dist/schema-generator.d.ts +1 -0
  53. package/dist/schema-generator.js +1 -0
  54. package/dist/types-map.js +10 -1
  55. package/dist/types.d.ts +180 -50
  56. package/dist/utils/compute-required-schemas.d.ts +4 -0
  57. package/dist/utils/compute-required-schemas.js +40 -0
  58. package/dist/utils/contract-hashes.d.ts +52 -0
  59. package/dist/utils/contract-hashes.js +269 -0
  60. package/dist/utils/custom-types-generator.d.ts +9 -0
  61. package/dist/utils/custom-types-generator.js +71 -0
  62. package/dist/utils/detect-schema-vendor.d.ts +22 -0
  63. package/dist/utils/detect-schema-vendor.js +76 -0
  64. package/dist/utils/does-type-extend-core-type.d.ts +1 -1
  65. package/dist/utils/ensure-function-metadata.d.ts +6 -3
  66. package/dist/utils/ensure-function-metadata.js +220 -6
  67. package/dist/utils/extract-function-name.d.ts +5 -16
  68. package/dist/utils/extract-function-name.js +86 -291
  69. package/dist/utils/extract-services.d.ts +2 -1
  70. package/dist/utils/extract-services.js +25 -1
  71. package/dist/utils/filter-inspector-state.d.ts +1 -1
  72. package/dist/utils/filter-inspector-state.js +107 -23
  73. package/dist/utils/filter-utils.d.ts +2 -2
  74. package/dist/utils/get-files-and-methods.d.ts +1 -1
  75. package/dist/utils/get-property-value.d.ts +6 -1
  76. package/dist/utils/get-property-value.js +28 -3
  77. package/dist/utils/hash.d.ts +2 -0
  78. package/dist/utils/hash.js +23 -0
  79. package/dist/utils/middleware.d.ts +9 -32
  80. package/dist/utils/middleware.js +80 -66
  81. package/dist/utils/permissions.d.ts +4 -4
  82. package/dist/utils/permissions.js +10 -10
  83. package/dist/utils/post-process.d.ts +11 -11
  84. package/dist/utils/post-process.js +247 -24
  85. package/dist/utils/resolve-addon-package.d.ts +16 -0
  86. package/dist/utils/resolve-addon-package.js +34 -0
  87. package/dist/utils/resolve-function-types.d.ts +6 -0
  88. package/dist/utils/resolve-function-types.js +29 -0
  89. package/dist/utils/resolve-identifier.d.ts +10 -0
  90. package/dist/utils/resolve-identifier.js +36 -0
  91. package/dist/utils/resolve-versions.d.ts +2 -0
  92. package/dist/utils/resolve-versions.js +78 -0
  93. package/dist/utils/schema-generator.d.ts +9 -0
  94. package/dist/utils/schema-generator.js +209 -0
  95. package/dist/utils/serialize-inspector-state.d.ts +70 -23
  96. package/dist/utils/serialize-inspector-state.js +98 -22
  97. package/dist/utils/serialize-mcp-json.d.ts +2 -0
  98. package/dist/utils/serialize-mcp-json.js +99 -0
  99. package/dist/utils/serialize-middleware-groups-meta.d.ts +12 -0
  100. package/dist/utils/serialize-middleware-groups-meta.js +28 -0
  101. package/dist/utils/serialize-openapi-json.d.ts +85 -0
  102. package/dist/utils/serialize-openapi-json.js +151 -0
  103. package/dist/utils/serialize-permissions-groups-meta.d.ts +6 -0
  104. package/dist/utils/serialize-permissions-groups-meta.js +31 -0
  105. package/dist/utils/validate-auth-sessionless.d.ts +3 -0
  106. package/dist/utils/validate-auth-sessionless.js +14 -0
  107. package/dist/utils/workflow/dsl/deserialize-dsl-workflow.js +34 -102
  108. package/dist/utils/workflow/dsl/extract-dsl-workflow.d.ts +1 -1
  109. package/dist/utils/workflow/dsl/extract-dsl-workflow.js +23 -4
  110. package/dist/utils/workflow/graph/convert-dsl-to-graph.js +12 -10
  111. package/dist/utils/workflow/graph/finalize-workflow-wires.d.ts +3 -0
  112. package/dist/utils/workflow/graph/finalize-workflow-wires.js +276 -0
  113. package/dist/utils/workflow/graph/finalize-workflows.d.ts +2 -0
  114. package/dist/utils/workflow/graph/finalize-workflows.js +75 -0
  115. package/dist/utils/workflow/graph/index.d.ts +2 -0
  116. package/dist/utils/workflow/graph/index.js +2 -0
  117. package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +0 -8
  118. package/dist/utils/workflow/graph/serialize-workflow-graph.js +1 -3
  119. package/dist/utils/workflow/graph/workflow-graph.types.d.ts +53 -79
  120. package/dist/utils/workflow/graph/workflow-graph.types.js +1 -1
  121. package/dist/visit.d.ts +1 -1
  122. package/dist/visit.js +13 -6
  123. package/package.json +14 -4
  124. package/src/add/add-ai-agent.ts +468 -0
  125. package/src/add/add-channel.ts +103 -79
  126. package/src/add/add-cli.ts +68 -24
  127. package/src/add/add-file-extends-core-type.ts +1 -1
  128. package/src/add/add-file-with-config.ts +1 -1
  129. package/src/add/add-file-with-factory.ts +3 -1
  130. package/src/add/add-functions.ts +349 -103
  131. package/src/add/add-http-route.ts +263 -89
  132. package/src/add/add-http-routes.ts +229 -0
  133. package/src/add/add-keyed-wiring.ts +151 -0
  134. package/src/add/add-mcp-prompt.ts +27 -16
  135. package/src/add/add-mcp-resource.ts +28 -16
  136. package/src/add/add-middleware.ts +482 -80
  137. package/src/add/add-permission.ts +199 -40
  138. package/src/add/add-queue-worker.ts +25 -20
  139. package/src/add/add-rpc-invocations.ts +28 -11
  140. package/src/add/add-schedule.ts +17 -12
  141. package/src/add/add-secret.ts +140 -0
  142. package/src/add/add-trigger.ts +154 -0
  143. package/src/add/add-variable.ts +9 -0
  144. package/src/add/add-wire-addon.ts +80 -0
  145. package/src/add/add-workflow-graph.ts +180 -522
  146. package/src/add/add-workflow.ts +7 -6
  147. package/src/error-codes.ts +25 -1
  148. package/src/index.ts +23 -13
  149. package/src/inspector.ts +139 -19
  150. package/src/schema-generator.ts +1 -0
  151. package/src/types-map.ts +12 -1
  152. package/src/types.ts +199 -69
  153. package/src/utils/compute-required-schemas.ts +48 -0
  154. package/src/utils/contract-hashes.test.ts +553 -0
  155. package/src/utils/contract-hashes.ts +386 -0
  156. package/src/utils/custom-types-generator.ts +88 -0
  157. package/src/utils/detect-schema-vendor.ts +90 -0
  158. package/src/utils/does-type-extend-core-type.ts +1 -1
  159. package/src/utils/ensure-function-metadata.ts +325 -8
  160. package/src/utils/extract-function-name.ts +101 -351
  161. package/src/utils/extract-services.ts +35 -2
  162. package/src/utils/filter-inspector-state.test.ts +37 -25
  163. package/src/utils/filter-inspector-state.ts +146 -32
  164. package/src/utils/filter-utils.test.ts +1 -1
  165. package/src/utils/filter-utils.ts +2 -2
  166. package/src/utils/get-files-and-methods.ts +1 -1
  167. package/src/utils/get-property-value.ts +42 -4
  168. package/src/utils/hash.ts +26 -0
  169. package/src/utils/middleware.test.ts +204 -0
  170. package/src/utils/middleware.ts +131 -69
  171. package/src/utils/permissions.test.ts +35 -12
  172. package/src/utils/permissions.ts +12 -12
  173. package/src/utils/post-process.ts +306 -44
  174. package/src/utils/resolve-addon-package.ts +49 -0
  175. package/src/utils/resolve-function-types.ts +42 -0
  176. package/src/utils/resolve-identifier.ts +46 -0
  177. package/src/utils/resolve-versions.test.ts +249 -0
  178. package/src/utils/resolve-versions.ts +105 -0
  179. package/src/utils/schema-generator.ts +329 -0
  180. package/src/utils/serialize-inspector-state.ts +184 -43
  181. package/src/utils/serialize-mcp-json.ts +145 -0
  182. package/src/utils/serialize-middleware-groups-meta.ts +33 -0
  183. package/src/utils/serialize-openapi-json.ts +277 -0
  184. package/src/utils/serialize-permissions-groups-meta.ts +35 -0
  185. package/src/utils/test-data/inspector-state.json +69 -66
  186. package/src/utils/validate-auth-sessionless.ts +29 -0
  187. package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +43 -119
  188. package/src/utils/workflow/dsl/extract-dsl-workflow.ts +26 -6
  189. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +17 -10
  190. package/src/utils/workflow/graph/finalize-workflow-wires.ts +310 -0
  191. package/src/utils/workflow/graph/finalize-workflows.ts +100 -0
  192. package/src/utils/workflow/graph/index.ts +5 -0
  193. package/src/utils/workflow/graph/serialize-workflow-graph.ts +1 -8
  194. package/src/utils/workflow/graph/workflow-graph.types.ts +29 -78
  195. package/src/visit.ts +19 -7
  196. package/tsconfig.tsbuildinfo +1 -1
  197. package/dist/add/add-forge-credential.d.ts +0 -8
  198. package/dist/add/add-forge-credential.js +0 -77
  199. package/dist/add/add-forge-node.d.ts +0 -7
  200. package/dist/add/add-forge-node.js +0 -77
  201. package/dist/add/add-mcp-tool.d.ts +0 -2
  202. package/dist/add/add-mcp-tool.js +0 -81
  203. package/dist/utils/extract-service-metadata.d.ts +0 -19
  204. package/dist/utils/extract-service-metadata.js +0 -244
  205. package/dist/utils/write-service-metadata.d.ts +0 -13
  206. package/dist/utils/write-service-metadata.js +0 -37
  207. package/src/add/add-forge-credential.ts +0 -119
  208. package/src/add/add-forge-node.ts +0 -132
  209. package/src/add/add-mcp-tool.ts +0 -141
  210. package/src/utils/extract-service-metadata.ts +0 -353
  211. package/src/utils/write-service-metadata.ts +0 -51
@@ -5,12 +5,20 @@ import {
5
5
  getCommonWireMetaData,
6
6
  } from '../utils/get-property-value.js'
7
7
  import { pathToRegexp } from 'path-to-regexp'
8
- import { extractFunctionName } from '../utils/extract-function-name.js'
8
+ import {
9
+ extractFunctionName,
10
+ makeContextBasedId,
11
+ } from '../utils/extract-function-name.js'
9
12
  import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
10
13
  import type { ChannelMessageMeta, ChannelMeta } from '@pikku/core/channel'
11
14
  import type { InspectorState, AddWiring } from '../types.js'
12
- import { resolveMiddleware } from '../utils/middleware.js'
15
+ import {
16
+ resolveMiddleware,
17
+ resolveChannelMiddleware,
18
+ } from '../utils/middleware.js'
13
19
  import { extractWireNames } from '../utils/post-process.js'
20
+ import { resolveIdentifier } from '../utils/resolve-identifier.js'
21
+ import { validateAuthSessionless } from '../utils/validate-auth-sessionless.js'
14
22
 
15
23
  /**
16
24
  * Safely get the "initializer" expression of a property-like AST node:
@@ -61,31 +69,31 @@ function getHandlerNameFromExpression(
61
69
  ts.isFunctionExpression(decl.initializer)
62
70
  ) {
63
71
  // Extract function name from the declaration's initializer
64
- const { pikkuFuncName } = extractFunctionName(
72
+ const { pikkuFuncId } = extractFunctionName(
65
73
  decl.initializer,
66
74
  checker,
67
75
  rootDir
68
76
  )
69
- return pikkuFuncName
77
+ return pikkuFuncId
70
78
  }
71
79
  }
72
80
  // For function declarations, use directly
73
81
  else if (ts.isFunctionDeclaration(decl)) {
74
- const { pikkuFuncName } = extractFunctionName(decl, checker, rootDir)
75
- return pikkuFuncName
82
+ const { pikkuFuncId } = extractFunctionName(decl, checker, rootDir)
83
+ return pikkuFuncId
76
84
  }
77
85
  }
78
86
  }
79
87
 
80
88
  // Fallback: try to extract directly from the identifier
81
- const { pikkuFuncName } = extractFunctionName(expr, checker, rootDir)
82
- return pikkuFuncName
89
+ const { pikkuFuncId } = extractFunctionName(expr, checker, rootDir)
90
+ return pikkuFuncId
83
91
  }
84
92
 
85
93
  // Handle call expressions
86
94
  if (ts.isCallExpression(expr)) {
87
- const { pikkuFuncName } = extractFunctionName(expr, checker, rootDir)
88
- return pikkuFuncName
95
+ const { pikkuFuncId } = extractFunctionName(expr, checker, rootDir)
96
+ return pikkuFuncId
89
97
  }
90
98
 
91
99
  // Handle object literals with 'func' property
@@ -125,8 +133,20 @@ export function addMessagesRoutes(
125
133
  return result
126
134
 
127
135
  for (const chanElem of onMsgRouteProp.properties) {
128
- const chanInit = getInitializerOf(chanElem)
129
- if (!chanInit || !ts.isObjectLiteralExpression(chanInit)) continue
136
+ let chanInit = getInitializerOf(chanElem)
137
+ if (!chanInit) continue
138
+
139
+ // If the value is an identifier, resolve it (handles defineChannelRoutes)
140
+ if (ts.isIdentifier(chanInit)) {
141
+ const resolved = resolveIdentifier(chanInit, checker, [
142
+ 'defineChannelRoutes',
143
+ ])
144
+ if (resolved && ts.isObjectLiteralExpression(resolved)) {
145
+ chanInit = resolved
146
+ }
147
+ }
148
+
149
+ if (!ts.isObjectLiteralExpression(chanInit)) continue
130
150
 
131
151
  const channelKey = chanElem.name!.getText()
132
152
  result[channelKey] = {}
@@ -193,12 +213,12 @@ export function addMessagesRoutes(
193
213
  ts.isFunctionExpression(importDecl.initializer) ||
194
214
  ts.isCallExpression(importDecl.initializer)
195
215
  ) {
196
- const { pikkuFuncName } = extractFunctionName(
216
+ const { pikkuFuncId } = extractFunctionName(
197
217
  importDecl.initializer,
198
218
  checker,
199
219
  state.rootDir
200
220
  )
201
- const handlerName = pikkuFuncName
221
+ const handlerName = pikkuFuncId
202
222
 
203
223
  // Look up in the registry
204
224
  const fnMeta = state.functions.meta[handlerName]
@@ -217,7 +237,7 @@ export function addMessagesRoutes(
217
237
  : undefined
218
238
 
219
239
  result[channelKey]![routeKey] = {
220
- pikkuFuncName: handlerName,
240
+ pikkuFuncId: handlerName,
221
241
  middleware: routeMiddleware,
222
242
  }
223
243
  continue
@@ -225,12 +245,12 @@ export function addMessagesRoutes(
225
245
  }
226
246
  } else if (ts.isFunctionDeclaration(importDecl)) {
227
247
  // Extract from the function declaration
228
- const { pikkuFuncName } = extractFunctionName(
248
+ const { pikkuFuncId } = extractFunctionName(
229
249
  importDecl,
230
250
  checker,
231
251
  state.rootDir
232
252
  )
233
- const handlerName = pikkuFuncName
253
+ const handlerName = pikkuFuncId
234
254
 
235
255
  // Look up in the registry
236
256
  const fnMeta = state.functions.meta[handlerName]
@@ -249,7 +269,7 @@ export function addMessagesRoutes(
249
269
  : undefined
250
270
 
251
271
  result[channelKey]![routeKey] = {
252
- pikkuFuncName: handlerName,
272
+ pikkuFuncId: handlerName,
253
273
  middleware: routeMiddleware,
254
274
  }
255
275
  continue
@@ -275,12 +295,12 @@ export function addMessagesRoutes(
275
295
  ts.isVariableDeclaration(exportDecl) &&
276
296
  exportDecl.initializer
277
297
  ) {
278
- const { pikkuFuncName } = extractFunctionName(
298
+ const { pikkuFuncId } = extractFunctionName(
279
299
  exportDecl.initializer,
280
300
  checker,
281
301
  state.rootDir
282
302
  )
283
- const handlerName = pikkuFuncName
303
+ const handlerName = pikkuFuncId
284
304
 
285
305
  const fnMeta = state.functions.meta[handlerName]
286
306
  if (fnMeta) {
@@ -300,18 +320,18 @@ export function addMessagesRoutes(
300
320
  : undefined
301
321
 
302
322
  result[channelKey]![routeKey] = {
303
- pikkuFuncName: handlerName,
323
+ pikkuFuncId: handlerName,
304
324
  middleware: routeMiddleware,
305
325
  }
306
326
  continue
307
327
  }
308
328
  } else if (ts.isFunctionDeclaration(exportDecl)) {
309
- const { pikkuFuncName } = extractFunctionName(
329
+ const { pikkuFuncId } = extractFunctionName(
310
330
  exportDecl,
311
331
  checker,
312
332
  state.rootDir
313
333
  )
314
- const handlerName = pikkuFuncName
334
+ const handlerName = pikkuFuncId
315
335
 
316
336
  const fnMeta = state.functions.meta[handlerName]
317
337
  if (fnMeta) {
@@ -331,7 +351,7 @@ export function addMessagesRoutes(
331
351
  : undefined
332
352
 
333
353
  result[channelKey]![routeKey] = {
334
- pikkuFuncName: handlerName,
354
+ pikkuFuncId: handlerName,
335
355
  middleware: routeMiddleware,
336
356
  }
337
357
  continue
@@ -365,7 +385,7 @@ export function addMessagesRoutes(
365
385
  continue
366
386
  }
367
387
  result[channelKey]![routeKey] = {
368
- pikkuFuncName: possibleMatch,
388
+ pikkuFuncId: possibleMatch,
369
389
  }
370
390
  continue
371
391
  }
@@ -392,12 +412,12 @@ export function addMessagesRoutes(
392
412
  // If we found the actual function, extract its name
393
413
  if (actualFunction) {
394
414
  // Extract the function name directly from the actual function
395
- const { pikkuFuncName } = extractFunctionName(
415
+ const { pikkuFuncId } = extractFunctionName(
396
416
  actualFunction,
397
417
  checker,
398
418
  state.rootDir
399
419
  )
400
- const handlerName = pikkuFuncName
420
+ const handlerName = pikkuFuncId
401
421
 
402
422
  // Now use this handlerName to look up in the registry
403
423
  const fnMeta = state.functions.meta[handlerName]
@@ -417,7 +437,7 @@ export function addMessagesRoutes(
417
437
  : undefined
418
438
 
419
439
  result[channelKey]![routeKey] = {
420
- pikkuFuncName: handlerName,
440
+ pikkuFuncId: handlerName,
421
441
  middleware: routeMiddleware,
422
442
  }
423
443
  continue // Skip the normal processing below
@@ -459,7 +479,7 @@ export function addMessagesRoutes(
459
479
  : undefined
460
480
 
461
481
  result[channelKey]![routeKey] = {
462
- pikkuFuncName: handlerName,
482
+ pikkuFuncId: handlerName,
463
483
  middleware: routeMiddleware,
464
484
  }
465
485
  }
@@ -501,12 +521,11 @@ export const addChannel: AddWiring = (
501
521
  .map((k) => k.name)
502
522
  : []
503
523
 
504
- const { tags, summary, description, errors } = getCommonWireMetaData(
505
- obj,
506
- 'Channel',
507
- name,
508
- logger
509
- )
524
+ const { disabled, tags, summary, description, errors } =
525
+ getCommonWireMetaData(obj, 'Channel', name, logger)
526
+
527
+ if (disabled) return
528
+
510
529
  const query = getPropertyValue(obj, 'query') as string[] | []
511
530
 
512
531
  const connect = getPropertyAssignmentInitializer(
@@ -532,21 +551,20 @@ export const addChannel: AddWiring = (
532
551
  )
533
552
 
534
553
  if (onMsgProp) {
535
- const { pikkuFuncName } = extractFunctionName(
536
- onMsgProp,
537
- checker,
538
- state.rootDir
539
- )
540
- const fnMeta = state.functions.meta[pikkuFuncName]
554
+ const extracted = extractFunctionName(onMsgProp, checker, state.rootDir)
555
+ const msgFuncId = extracted.pikkuFuncId.startsWith('__temp_')
556
+ ? makeContextBasedId('channel', name, 'message')
557
+ : extracted.pikkuFuncId
558
+ const fnMeta = state.functions.meta[msgFuncId]
541
559
  if (!fnMeta) {
542
560
  logger.critical(
543
561
  ErrorCode.FUNCTION_METADATA_NOT_FOUND,
544
- `No function metadata found for onMessage handler '${pikkuFuncName}'`
562
+ `No function metadata found for onMessage handler '${msgFuncId}'`
545
563
  )
546
564
  return
547
565
  }
548
566
  message = {
549
- pikkuFuncName,
567
+ pikkuFuncId: msgFuncId,
550
568
  }
551
569
  }
552
570
 
@@ -555,40 +573,65 @@ export const addChannel: AddWiring = (
555
573
 
556
574
  // --- resolve middleware ---
557
575
  const middleware = resolveMiddleware(state, obj, tags, checker)
576
+ const channelMiddleware = resolveChannelMiddleware(state, obj, tags, checker)
558
577
 
559
578
  // --- track used functions/middleware for service aggregation ---
560
579
  // Track connect/disconnect/message handlers
580
+ let connectFuncId: string | undefined
561
581
  if (connect) {
562
- const connectFuncName = extractFunctionName(
563
- connect,
564
- checker,
565
- state.rootDir
566
- ).pikkuFuncName
567
- state.serviceAggregation.usedFunctions.add(connectFuncName)
582
+ const extracted = extractFunctionName(connect, checker, state.rootDir)
583
+ connectFuncId = extracted.pikkuFuncId.startsWith('__temp_')
584
+ ? makeContextBasedId('channel', name, 'connect')
585
+ : extracted.pikkuFuncId
586
+ state.serviceAggregation.usedFunctions.add(connectFuncId)
568
587
  }
588
+
589
+ let disconnectFuncId: string | undefined
569
590
  if (disconnect) {
570
- const disconnectFuncName = extractFunctionName(
591
+ const extracted = extractFunctionName(
571
592
  disconnect as any,
572
593
  checker,
573
594
  state.rootDir
574
- ).pikkuFuncName
575
- state.serviceAggregation.usedFunctions.add(disconnectFuncName)
595
+ )
596
+ disconnectFuncId = extracted.pikkuFuncId.startsWith('__temp_')
597
+ ? makeContextBasedId('channel', name, 'disconnect')
598
+ : extracted.pikkuFuncId
599
+ state.serviceAggregation.usedFunctions.add(disconnectFuncId)
576
600
  }
601
+
577
602
  if (message) {
578
- state.serviceAggregation.usedFunctions.add(message.pikkuFuncName)
603
+ state.serviceAggregation.usedFunctions.add(message.pikkuFuncId)
579
604
  }
580
- // Track message wiring handlers
605
+
581
606
  for (const channelHandlers of Object.values(messageWirings)) {
582
607
  for (const handler of Object.values(channelHandlers)) {
583
- state.serviceAggregation.usedFunctions.add(handler.pikkuFuncName)
608
+ state.serviceAggregation.usedFunctions.add(handler.pikkuFuncId)
584
609
  }
585
610
  }
586
- // Track middleware
587
611
  extractWireNames(middleware).forEach((name) =>
588
612
  state.serviceAggregation.usedMiddleware.add(name)
589
613
  )
590
614
 
591
- // record into state
615
+ // --- validate auth/sessionless ---
616
+ const handlersToValidate = [
617
+ connectFuncId,
618
+ disconnectFuncId,
619
+ message?.pikkuFuncId,
620
+ ].filter(Boolean) as string[]
621
+ for (const funcId of handlersToValidate) {
622
+ if (
623
+ !validateAuthSessionless(
624
+ logger,
625
+ obj,
626
+ state,
627
+ funcId,
628
+ `Channel '${name}'`
629
+ )
630
+ ) {
631
+ return
632
+ }
633
+ }
634
+
592
635
  state.channels.files.add(node.getSourceFile().fileName)
593
636
  state.channels.meta[name] = {
594
637
  name,
@@ -596,28 +639,8 @@ export const addChannel: AddWiring = (
596
639
  input: null,
597
640
  params: params.length ? params : undefined,
598
641
  query: query?.length ? query : undefined,
599
- // inputTypes: getInputTypes(
600
- // state.channels.metaInputTypes,
601
- // 'get',
602
- // null, // TODO
603
- // query,
604
- // params
605
- // ),
606
- connect: connect
607
- ? {
608
- pikkuFuncName: extractFunctionName(connect, checker, state.rootDir)
609
- .pikkuFuncName,
610
- }
611
- : null,
612
- disconnect: disconnect
613
- ? {
614
- pikkuFuncName: extractFunctionName(
615
- disconnect as any,
616
- checker,
617
- state.rootDir
618
- ).pikkuFuncName,
619
- }
620
- : null,
642
+ connect: connectFuncId ? { pikkuFuncId: connectFuncId } : null,
643
+ disconnect: disconnectFuncId ? { pikkuFuncId: disconnectFuncId } : null,
621
644
  message,
622
645
  messageWirings,
623
646
  summary,
@@ -625,5 +648,6 @@ export const addChannel: AddWiring = (
625
648
  errors,
626
649
  tags: tags ?? undefined,
627
650
  middleware,
651
+ channelMiddleware,
628
652
  }
629
653
  }
@@ -1,15 +1,18 @@
1
- import ts, { TypeChecker } from 'typescript'
2
- import {
1
+ import type { TypeChecker } from 'typescript'
2
+ import ts from 'typescript'
3
+ import type {
3
4
  AddWiring,
4
5
  InspectorLogger,
5
6
  InspectorOptions,
6
7
  InspectorState,
7
8
  } from '../types.js'
8
- import { CLIProgramMeta, CLICommandMeta } from '@pikku/core/cli'
9
+ import type { CLIProgramMeta, CLICommandMeta } from '@pikku/core/cli'
9
10
  import { extractFunctionName } from '../utils/extract-function-name.js'
10
11
  import { resolveMiddleware } from '../utils/middleware.js'
11
12
  import { extractWireNames } from '../utils/post-process.js'
12
13
  import { getPropertyValue } from '../utils/get-property-value.js'
14
+ import { resolveIdentifier } from '../utils/resolve-identifier.js'
15
+ import { validateAuthSessionless } from '../utils/validate-auth-sessionless.js'
13
16
 
14
17
  // Track if we've warned about missing Config type to avoid duplicate warnings
15
18
  const configTypeWarningShown = new Set<string>()
@@ -106,6 +109,10 @@ function processCLIConfig(
106
109
  return null
107
110
  }
108
111
 
112
+ if (getPropertyValue(node, 'disabled') === true) {
113
+ return null
114
+ }
115
+
109
116
  // Second pass: process other properties with program tags available
110
117
  for (const prop of node.properties) {
111
118
  if (!ts.isPropertyAssignment(prop)) continue
@@ -152,7 +159,7 @@ function processCLIConfig(
152
159
  prop.initializer,
153
160
  typeChecker,
154
161
  inspectorState.rootDir
155
- ).pikkuFuncName
162
+ ).pikkuFuncId
156
163
  break
157
164
  }
158
165
  }
@@ -177,6 +184,30 @@ function processCommands(
177
184
  let defaultCommandName: string | null = null
178
185
 
179
186
  for (const prop of node.properties) {
187
+ // Handle spread assignments: { ...externalCommands }
188
+ if (ts.isSpreadAssignment(prop)) {
189
+ let spreadTarget: ts.Node | undefined = prop.expression
190
+ if (ts.isIdentifier(prop.expression)) {
191
+ spreadTarget = resolveIdentifier(prop.expression, typeChecker, [
192
+ 'defineCLICommands',
193
+ ])
194
+ }
195
+ if (spreadTarget && ts.isObjectLiteralExpression(spreadTarget)) {
196
+ const spreadCommands = processCommands(
197
+ logger,
198
+ spreadTarget,
199
+ sourceFile,
200
+ typeChecker,
201
+ programName,
202
+ inspectorState,
203
+ options,
204
+ programTags
205
+ )
206
+ Object.assign(commands, spreadCommands)
207
+ }
208
+ continue
209
+ }
210
+
180
211
  if (!ts.isPropertyAssignment(prop)) continue
181
212
 
182
213
  const commandName = getPropertyName(prop)
@@ -243,11 +274,11 @@ function processCommand(
243
274
  ts.isFunctionExpression(node)
244
275
  ) {
245
276
  return {
246
- pikkuFuncName: extractFunctionName(
277
+ pikkuFuncId: extractFunctionName(
247
278
  node,
248
279
  typeChecker,
249
280
  inspectorState.rootDir
250
- ).pikkuFuncName,
281
+ ).pikkuFuncId,
251
282
  positionals: [],
252
283
  options: {},
253
284
  }
@@ -285,13 +316,13 @@ function processCommand(
285
316
  }
286
317
 
287
318
  const meta: CLICommandMeta = {
288
- pikkuFuncName: '',
319
+ pikkuFuncId: '',
289
320
  positionals: [],
290
321
  options: {},
291
322
  }
292
323
 
293
- // First pass: extract pikkuFuncName and tags so we can use them when processing options/middleware
294
- let pikkuFuncName: string | undefined
324
+ // First pass: extract pikkuFuncId and tags so we can use them when processing options/middleware
325
+ let pikkuFuncId: string | undefined
295
326
  let optionsNode: ts.ObjectLiteralExpression | undefined
296
327
  let tags: string[] | undefined
297
328
 
@@ -302,12 +333,12 @@ function processCommand(
302
333
  const propName = prop.name.text
303
334
 
304
335
  if (propName === 'func') {
305
- pikkuFuncName = extractFunctionName(
336
+ pikkuFuncId = extractFunctionName(
306
337
  prop.initializer,
307
338
  typeChecker,
308
339
  inspectorState.rootDir
309
- ).pikkuFuncName
310
- meta.pikkuFuncName = pikkuFuncName
340
+ ).pikkuFuncId
341
+ meta.pikkuFuncId = pikkuFuncId
311
342
  } else if (
312
343
  propName === 'options' &&
313
344
  ts.isObjectLiteralExpression(prop.initializer)
@@ -367,11 +398,11 @@ function processCommand(
367
398
  prop.initializer,
368
399
  typeChecker,
369
400
  inspectorState.rootDir
370
- ).pikkuFuncName
401
+ ).pikkuFuncId
371
402
  break
372
403
 
373
404
  case 'options':
374
- // Process with pikkuFuncName from first pass
405
+ // Process with pikkuFuncId from first pass
375
406
  if (optionsNode) {
376
407
  meta.options = processOptions(
377
408
  logger,
@@ -379,7 +410,7 @@ function processCommand(
379
410
  typeChecker,
380
411
  inspectorState,
381
412
  options,
382
- pikkuFuncName
413
+ pikkuFuncId
383
414
  )
384
415
  }
385
416
  break
@@ -424,12 +455,25 @@ function processCommand(
424
455
  }
425
456
  }
426
457
 
458
+ // --- validate auth/sessionless ---
459
+ if (
460
+ meta.pikkuFuncId &&
461
+ !validateAuthSessionless(
462
+ logger,
463
+ node,
464
+ inspectorState,
465
+ meta.pikkuFuncId,
466
+ `CLI command '${name}'`
467
+ )
468
+ ) {
469
+ return null
470
+ }
471
+
427
472
  // --- track used functions/middleware for service aggregation ---
428
- inspectorState.serviceAggregation.usedFunctions.add(meta.pikkuFuncName)
473
+ inspectorState.serviceAggregation.usedFunctions.add(meta.pikkuFuncId)
429
474
  extractWireNames(meta.middleware).forEach((name) =>
430
475
  inspectorState.serviceAggregation.usedMiddleware.add(name)
431
476
  )
432
- // Note: subcommands are tracked recursively when they're processed
433
477
 
434
478
  return meta
435
479
  }
@@ -443,7 +487,7 @@ function processOptions(
443
487
  typeChecker: TypeChecker,
444
488
  inspectorState: InspectorState,
445
489
  inspectorOptions: InspectorOptions,
446
- pikkuFuncName?: string
490
+ pikkuFuncId?: string
447
491
  ): Record<string, any> {
448
492
  const options: Record<string, any> = {}
449
493
 
@@ -506,10 +550,10 @@ function processOptions(
506
550
  }
507
551
 
508
552
  // Extract enum values from the function input type if available
509
- // Get the input type if we have a pikkuFuncName
553
+ // Get the input type if we have a pikkuFuncId
510
554
  let inputTypes: ts.Type[] | undefined
511
- if (pikkuFuncName) {
512
- inputTypes = inspectorState.typesLookup.get(pikkuFuncName)
555
+ if (pikkuFuncId) {
556
+ inputTypes = inspectorState.typesLookup.get(pikkuFuncId)
513
557
  }
514
558
 
515
559
  let derivedChoices: string[] | null = null
@@ -772,7 +816,7 @@ export const addCLIRenderers: AddWiring = (
772
816
  if (args.length === 0) return
773
817
 
774
818
  // Extract renderer name
775
- const { pikkuFuncName, exportedName } = extractFunctionName(
819
+ const { pikkuFuncId, exportedName } = extractFunctionName(
776
820
  node,
777
821
  typeChecker,
778
822
  inspectorState.rootDir
@@ -808,8 +852,8 @@ export const addCLIRenderers: AddWiring = (
808
852
  }
809
853
 
810
854
  // Store renderer metadata
811
- inspectorState.cli.meta.renderers[pikkuFuncName] = {
812
- name: pikkuFuncName,
855
+ inspectorState.cli.meta.renderers[pikkuFuncId] = {
856
+ name: pikkuFuncId,
813
857
  exportedName: exportedName ?? undefined,
814
858
  services,
815
859
  filePath,
@@ -1,5 +1,5 @@
1
1
  import * as ts from 'typescript'
2
- import { PathToNameAndType, InspectorState } from '../types.js'
2
+ import type { PathToNameAndType, InspectorState } from '../types.js'
3
3
 
4
4
  export const addFileExtendsCoreType = (
5
5
  node: ts.Node,
@@ -1,6 +1,6 @@
1
1
  import * as ts from 'typescript'
2
2
  import { doesTypeExtendsCore } from '../utils/does-type-extend-core-type.js'
3
- import { PathToNameAndType } from '../types.js'
3
+ import type { PathToNameAndType } from '../types.js'
4
4
 
5
5
  export const addFileWithConfig = (
6
6
  node: ts.Node,
@@ -1,11 +1,13 @@
1
1
  import * as ts from 'typescript'
2
- import { PathToNameAndType, InspectorState } from '../types.js'
2
+ import type { PathToNameAndType, InspectorState } from '../types.js'
3
3
  import { extractServicesFromFunction } from '../utils/extract-services.js'
4
4
 
5
5
  // Mapping of wrapper function names to their corresponding types
6
6
  const wrapperFunctionMap: Record<string, string> = {
7
7
  pikkuConfig: 'CreateConfig',
8
+ pikkuAddonConfig: 'CreateConfig',
8
9
  pikkuServices: 'CreateSingletonServices',
10
+ pikkuAddonServices: 'CreateSingletonServices',
9
11
  pikkuWireServices: 'CreateWireServices',
10
12
  }
11
13