@pikku/inspector 0.12.1 → 0.12.3

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 (53) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/add/add-ai-agent.js +4 -0
  3. package/dist/add/add-approval-description.d.ts +5 -0
  4. package/dist/add/add-approval-description.js +52 -0
  5. package/dist/add/add-channel.js +44 -4
  6. package/dist/add/add-cli.js +94 -18
  7. package/dist/add/add-file-with-factory.js +1 -0
  8. package/dist/add/add-functions.js +22 -3
  9. package/dist/add/add-gateway.d.ts +2 -0
  10. package/dist/add/add-gateway.js +62 -0
  11. package/dist/add/add-http-route.js +5 -0
  12. package/dist/add/add-mcp-prompt.js +5 -0
  13. package/dist/add/add-mcp-resource.js +5 -0
  14. package/dist/add/add-queue-worker.js +5 -0
  15. package/dist/add/add-schedule.js +5 -0
  16. package/dist/add/add-wire-addon.js +7 -0
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.js +1 -0
  19. package/dist/inspector.js +11 -0
  20. package/dist/types.d.ts +15 -0
  21. package/dist/utils/load-addon-functions-meta.d.ts +12 -0
  22. package/dist/utils/load-addon-functions-meta.js +76 -0
  23. package/dist/utils/post-process.js +26 -0
  24. package/dist/utils/resolve-function-meta.d.ts +11 -0
  25. package/dist/utils/resolve-function-meta.js +17 -0
  26. package/dist/utils/serialize-inspector-state.d.ts +6 -0
  27. package/dist/utils/serialize-inspector-state.js +12 -0
  28. package/dist/utils/serialize-mcp-json.js +13 -7
  29. package/dist/visit.js +4 -0
  30. package/package.json +3 -3
  31. package/src/add/add-ai-agent.ts +6 -0
  32. package/src/add/add-approval-description.ts +76 -0
  33. package/src/add/add-channel.ts +47 -11
  34. package/src/add/add-cli.ts +140 -30
  35. package/src/add/add-file-with-factory.ts +1 -0
  36. package/src/add/add-functions.ts +28 -3
  37. package/src/add/add-gateway.ts +101 -0
  38. package/src/add/add-http-route.ts +6 -0
  39. package/src/add/add-mcp-prompt.ts +6 -0
  40. package/src/add/add-mcp-resource.ts +6 -0
  41. package/src/add/add-queue-worker.ts +6 -0
  42. package/src/add/add-schedule.ts +6 -0
  43. package/src/add/add-wire-addon.ts +8 -0
  44. package/src/index.ts +1 -0
  45. package/src/inspector.ts +16 -0
  46. package/src/types.ts +16 -0
  47. package/src/utils/load-addon-functions-meta.ts +94 -0
  48. package/src/utils/post-process.ts +25 -0
  49. package/src/utils/resolve-function-meta.ts +25 -0
  50. package/src/utils/serialize-inspector-state.ts +18 -0
  51. package/src/utils/serialize-mcp-json.ts +12 -7
  52. package/src/visit.ts +4 -0
  53. package/tsconfig.tsbuildinfo +1 -1
@@ -18,6 +18,8 @@ import {
18
18
  } from '../utils/middleware.js'
19
19
  import { extractWireNames } from '../utils/post-process.js'
20
20
  import { resolveIdentifier } from '../utils/resolve-identifier.js'
21
+ import { resolveFunctionMeta } from '../utils/resolve-function-meta.js'
22
+ import { resolveAddonName } from '../utils/resolve-addon-package.js'
21
23
  import { validateAuthSessionless } from '../utils/validate-auth-sessionless.js'
22
24
 
23
25
  /**
@@ -92,6 +94,13 @@ function getHandlerNameFromExpression(
92
94
 
93
95
  // Handle call expressions
94
96
  if (ts.isCallExpression(expr)) {
97
+ // Handle addon('namespace:funcName') calls
98
+ if (ts.isIdentifier(expr.expression) && expr.expression.text === 'addon') {
99
+ const [firstArg] = expr.arguments
100
+ if (firstArg && ts.isStringLiteral(firstArg)) {
101
+ return firstArg.text
102
+ }
103
+ }
95
104
  const { pikkuFuncId } = extractFunctionName(expr, checker, rootDir)
96
105
  return pikkuFuncId
97
106
  }
@@ -460,11 +469,11 @@ export function addMessagesRoutes(
460
469
  continue
461
470
  }
462
471
 
463
- const fnMeta = state.functions.meta[handlerName]
472
+ const fnMeta = resolveFunctionMeta(state, handlerName)
464
473
  if (!fnMeta) {
465
474
  logger.critical(
466
475
  ErrorCode.FUNCTION_METADATA_NOT_FOUND,
467
- `No function metadata found for handler '${handlerName}'`
476
+ `No function metadata found for channel handler '${handlerName}' on route '${routeKey}'. If this is an inline function, it must be exported for the inspector to discover it.`
468
477
  )
469
478
  continue
470
479
  }
@@ -478,8 +487,17 @@ export function addMessagesRoutes(
478
487
  ? resolveMiddleware(state, init, routeTags, checker)
479
488
  : undefined
480
489
 
490
+ // Resolve package name for addon functions (e.g. 'swaggerPetstore:addPet')
491
+ const colonIdx = handlerName.indexOf(':')
492
+ const addonNs =
493
+ colonIdx !== -1 ? handlerName.substring(0, colonIdx) : null
494
+ const packageName = addonNs
495
+ ? state.rpc.wireAddonDeclarations.get(addonNs)?.package
496
+ : undefined
497
+
481
498
  result[channelKey]![routeKey] = {
482
499
  pikkuFuncId: handlerName,
500
+ packageName,
483
501
  middleware: routeMiddleware,
484
502
  }
485
503
  }
@@ -527,6 +545,7 @@ export const addChannel: AddWiring = (
527
545
  if (disabled) return
528
546
 
529
547
  const query = getPropertyValue(obj, 'query') as string[] | []
548
+ const binary = getPropertyValue(obj, 'binary') as boolean | undefined
530
549
 
531
550
  const connect = getPropertyAssignmentInitializer(
532
551
  obj,
@@ -563,8 +582,12 @@ export const addChannel: AddWiring = (
563
582
  )
564
583
  return
565
584
  }
585
+ const msgPackageName = ts.isIdentifier(onMsgProp)
586
+ ? resolveAddonName(onMsgProp, checker, state.rpc.wireAddonDeclarations)
587
+ : null
566
588
  message = {
567
589
  pikkuFuncId: msgFuncId,
590
+ ...(msgPackageName && { packageName: msgPackageName }),
568
591
  }
569
592
  }
570
593
 
@@ -578,15 +601,20 @@ export const addChannel: AddWiring = (
578
601
  // --- track used functions/middleware for service aggregation ---
579
602
  // Track connect/disconnect/message handlers
580
603
  let connectFuncId: string | undefined
604
+ let connectPackageName: string | null = null
581
605
  if (connect) {
582
606
  const extracted = extractFunctionName(connect, checker, state.rootDir)
583
607
  connectFuncId = extracted.pikkuFuncId.startsWith('__temp_')
584
608
  ? makeContextBasedId('channel', name, 'connect')
585
609
  : extracted.pikkuFuncId
610
+ connectPackageName = ts.isIdentifier(connect)
611
+ ? resolveAddonName(connect, checker, state.rpc.wireAddonDeclarations)
612
+ : null
586
613
  state.serviceAggregation.usedFunctions.add(connectFuncId)
587
614
  }
588
615
 
589
616
  let disconnectFuncId: string | undefined
617
+ let disconnectPackageName: string | null = null
590
618
  if (disconnect) {
591
619
  const extracted = extractFunctionName(
592
620
  disconnect as any,
@@ -596,6 +624,9 @@ export const addChannel: AddWiring = (
596
624
  disconnectFuncId = extracted.pikkuFuncId.startsWith('__temp_')
597
625
  ? makeContextBasedId('channel', name, 'disconnect')
598
626
  : extracted.pikkuFuncId
627
+ disconnectPackageName = ts.isIdentifier(disconnect)
628
+ ? resolveAddonName(disconnect, checker, state.rpc.wireAddonDeclarations)
629
+ : null
599
630
  state.serviceAggregation.usedFunctions.add(disconnectFuncId)
600
631
  }
601
632
 
@@ -620,13 +651,7 @@ export const addChannel: AddWiring = (
620
651
  ].filter(Boolean) as string[]
621
652
  for (const funcId of handlersToValidate) {
622
653
  if (
623
- !validateAuthSessionless(
624
- logger,
625
- obj,
626
- state,
627
- funcId,
628
- `Channel '${name}'`
629
- )
654
+ !validateAuthSessionless(logger, obj, state, funcId, `Channel '${name}'`)
630
655
  ) {
631
656
  return
632
657
  }
@@ -639,10 +664,21 @@ export const addChannel: AddWiring = (
639
664
  input: null,
640
665
  params: params.length ? params : undefined,
641
666
  query: query?.length ? query : undefined,
642
- connect: connectFuncId ? { pikkuFuncId: connectFuncId } : null,
643
- disconnect: disconnectFuncId ? { pikkuFuncId: disconnectFuncId } : null,
667
+ connect: connectFuncId
668
+ ? {
669
+ pikkuFuncId: connectFuncId,
670
+ ...(connectPackageName && { packageName: connectPackageName }),
671
+ }
672
+ : null,
673
+ disconnect: disconnectFuncId
674
+ ? {
675
+ pikkuFuncId: disconnectFuncId,
676
+ ...(disconnectPackageName && { packageName: disconnectPackageName }),
677
+ }
678
+ : null,
644
679
  message,
645
680
  messageWirings,
681
+ binary: binary === undefined ? undefined : binary,
646
682
  summary,
647
683
  description,
648
684
  errors,
@@ -7,11 +7,16 @@ import type {
7
7
  InspectorState,
8
8
  } from '../types.js'
9
9
  import type { CLIProgramMeta, CLICommandMeta } from '@pikku/core/cli'
10
- import { extractFunctionName } from '../utils/extract-function-name.js'
10
+ import {
11
+ extractFunctionName,
12
+ makeContextBasedId,
13
+ } from '../utils/extract-function-name.js'
11
14
  import { resolveMiddleware } from '../utils/middleware.js'
15
+ import { resolveFunctionMeta } from '../utils/resolve-function-meta.js'
12
16
  import { extractWireNames } from '../utils/post-process.js'
13
17
  import { getPropertyValue } from '../utils/get-property-value.js'
14
18
  import { resolveIdentifier } from '../utils/resolve-identifier.js'
19
+ import { resolveAddonName } from '../utils/resolve-addon-package.js'
15
20
  import { validateAuthSessionless } from '../utils/validate-auth-sessionless.js'
16
21
 
17
22
  // Track if we've warned about missing Config type to avoid duplicate warnings
@@ -153,14 +158,18 @@ function processCLIConfig(
153
158
  }
154
159
  break
155
160
 
156
- case 'render':
157
- // Extract the actual renderer function name
158
- programMeta.defaultRenderName = extractFunctionName(
161
+ case 'render': {
162
+ let renderFuncId = extractFunctionName(
159
163
  prop.initializer,
160
164
  typeChecker,
161
165
  inspectorState.rootDir
162
166
  ).pikkuFuncId
167
+ if (renderFuncId.startsWith('__temp_')) {
168
+ renderFuncId = makeContextBasedId('cli-render', programName)
169
+ }
170
+ programMeta.defaultRenderName = renderFuncId
163
171
  break
172
+ }
164
173
  }
165
174
  }
166
175
 
@@ -273,12 +282,16 @@ function processCommand(
273
282
  ts.isArrowFunction(node) ||
274
283
  ts.isFunctionExpression(node)
275
284
  ) {
285
+ let pikkuFuncId = extractFunctionName(
286
+ node,
287
+ typeChecker,
288
+ inspectorState.rootDir
289
+ ).pikkuFuncId
290
+ if (pikkuFuncId.startsWith('__temp_')) {
291
+ pikkuFuncId = makeContextBasedId('cli', programName, ...fullPath)
292
+ }
276
293
  return {
277
- pikkuFuncId: extractFunctionName(
278
- node,
279
- typeChecker,
280
- inspectorState.rootDir
281
- ).pikkuFuncId,
294
+ pikkuFuncId,
282
295
  positionals: [],
283
296
  options: {},
284
297
  }
@@ -333,12 +346,53 @@ function processCommand(
333
346
  const propName = prop.name.text
334
347
 
335
348
  if (propName === 'func') {
336
- pikkuFuncId = extractFunctionName(
337
- prop.initializer,
338
- typeChecker,
339
- inspectorState.rootDir
340
- ).pikkuFuncId
341
- meta.pikkuFuncId = pikkuFuncId
349
+ if (
350
+ ts.isCallExpression(prop.initializer) &&
351
+ ts.isIdentifier(prop.initializer.expression) &&
352
+ prop.initializer.expression.text === 'addon'
353
+ ) {
354
+ const [firstArg] = prop.initializer.arguments
355
+ if (!firstArg || !ts.isStringLiteral(firstArg)) {
356
+ throw new Error(
357
+ `addon() call requires a string literal argument in the form "namespace:funcName"`
358
+ )
359
+ }
360
+ pikkuFuncId = firstArg.text
361
+ const addonNamespace = pikkuFuncId.split(':')[0]
362
+ if (!addonNamespace || !pikkuFuncId.includes(':')) {
363
+ throw new Error(
364
+ `Malformed addon function ID "${pikkuFuncId}": expected "namespace:funcName" format`
365
+ )
366
+ }
367
+ if (!inspectorState.rpc.wireAddonDeclarations.has(addonNamespace)) {
368
+ throw new Error(
369
+ `Unknown addon namespace "${addonNamespace}" in "${pikkuFuncId}": no matching wireAddonDeclarations entry found`
370
+ )
371
+ }
372
+ meta.pikkuFuncId = pikkuFuncId
373
+ meta.packageName =
374
+ inspectorState.rpc.wireAddonDeclarations.get(addonNamespace)!.package
375
+ } else {
376
+ pikkuFuncId = extractFunctionName(
377
+ prop.initializer,
378
+ typeChecker,
379
+ inspectorState.rootDir
380
+ ).pikkuFuncId
381
+ if (pikkuFuncId.startsWith('__temp_')) {
382
+ pikkuFuncId = makeContextBasedId('cli', programName, ...fullPath)
383
+ }
384
+ meta.pikkuFuncId = pikkuFuncId
385
+ const cliPackageName = ts.isIdentifier(prop.initializer)
386
+ ? resolveAddonName(
387
+ prop.initializer,
388
+ typeChecker,
389
+ inspectorState.rpc.wireAddonDeclarations
390
+ )
391
+ : null
392
+ if (cliPackageName) {
393
+ meta.packageName = cliPackageName
394
+ }
395
+ }
342
396
  } else if (
343
397
  propName === 'options' &&
344
398
  ts.isObjectLiteralExpression(prop.initializer)
@@ -393,13 +447,22 @@ function processCommand(
393
447
  // Already handled in first pass
394
448
  break
395
449
 
396
- case 'render':
397
- meta.renderName = extractFunctionName(
450
+ case 'render': {
451
+ let renderFuncId = extractFunctionName(
398
452
  prop.initializer,
399
453
  typeChecker,
400
454
  inspectorState.rootDir
401
455
  ).pikkuFuncId
456
+ if (renderFuncId.startsWith('__temp_')) {
457
+ renderFuncId = makeContextBasedId(
458
+ 'cli-render',
459
+ programName,
460
+ ...fullPath
461
+ )
462
+ }
463
+ meta.renderName = renderFuncId
402
464
  break
465
+ }
403
466
 
404
467
  case 'options':
405
468
  // Process with pikkuFuncId from first pass
@@ -550,22 +613,31 @@ function processOptions(
550
613
  }
551
614
 
552
615
  // Extract enum values from the function input type if available
553
- // Get the input type if we have a pikkuFuncId
554
- let inputTypes: ts.Type[] | undefined
616
+ let derivedChoices: string[] | null = null
617
+
555
618
  if (pikkuFuncId) {
556
- inputTypes = inspectorState.typesLookup.get(pikkuFuncId)
557
- }
619
+ // 1. Try TypeScript types first (most precise — handles unions, TS enums)
620
+ const inputTypes = inspectorState.typesLookup.get(pikkuFuncId)
621
+ if (inputTypes && inputTypes.length > 0) {
622
+ derivedChoices = extractEnumFromPropertyType(
623
+ inputTypes[0]!,
624
+ optionName,
625
+ typeChecker
626
+ )
627
+ }
558
628
 
559
- let derivedChoices: string[] | null = null
629
+ // 2. Fallback: try JSON schema (works for addon functions)
630
+ if (!derivedChoices) {
631
+ derivedChoices = extractEnumFromJsonSchema(
632
+ inspectorState,
633
+ pikkuFuncId,
634
+ optionName
635
+ )
636
+ }
637
+ }
560
638
 
561
- if (inputTypes && inputTypes.length > 0) {
562
- derivedChoices = extractEnumFromPropertyType(
563
- inputTypes[0]!,
564
- optionName,
565
- typeChecker
566
- )
567
- } else {
568
- // Fallback: try to extract from Config type
639
+ // 3. Last resort: try Config type
640
+ if (!derivedChoices) {
569
641
  derivedChoices = extractEnumFromConfigType(
570
642
  logger,
571
643
  optionName,
@@ -727,6 +799,44 @@ function extractEnumFromConfigType(
727
799
  return extractEnumFromPropertyType(configType, propertyName, typeChecker)
728
800
  }
729
801
 
802
+ /**
803
+ * Extracts enum values from the function's JSON schema.
804
+ * Works for addon functions whose schemas are generated from OpenAPI/Zod.
805
+ */
806
+ function extractEnumFromJsonSchema(
807
+ inspectorState: InspectorState,
808
+ pikkuFuncId: string,
809
+ propertyName: string
810
+ ): string[] | null {
811
+ const fnMeta = resolveFunctionMeta(inspectorState, pikkuFuncId)
812
+ if (!fnMeta?.inputSchemaName) return null
813
+
814
+ const schema = inspectorState.schemas[fnMeta.inputSchemaName] as any
815
+ if (!schema?.properties?.[propertyName]) return null
816
+
817
+ const prop = schema.properties[propertyName]
818
+
819
+ // Direct enum on property
820
+ if (prop.enum && Array.isArray(prop.enum)) {
821
+ const strings = prop.enum.filter((v: unknown) => typeof v === 'string')
822
+ if (strings.length > 0) return strings
823
+ }
824
+
825
+ // Array with enum items (e.g. z.array(z.enum([...])))
826
+ if (
827
+ prop.type === 'array' &&
828
+ prop.items?.enum &&
829
+ Array.isArray(prop.items.enum)
830
+ ) {
831
+ const strings = prop.items.enum.filter(
832
+ (v: unknown) => typeof v === 'string'
833
+ )
834
+ if (strings.length > 0) return strings
835
+ }
836
+
837
+ return null
838
+ }
839
+
730
840
  /**
731
841
  * Gets the property name from a property assignment
732
842
  */
@@ -9,6 +9,7 @@ const wrapperFunctionMap: Record<string, string> = {
9
9
  pikkuServices: 'CreateSingletonServices',
10
10
  pikkuAddonServices: 'CreateSingletonServices',
11
11
  pikkuWireServices: 'CreateWireServices',
12
+ pikkuAddonWireServices: 'CreateWireServices',
12
13
  }
13
14
 
14
15
  export const addFileWithFactory = (
@@ -339,7 +339,8 @@ export const addFunctions: AddWiring = (
339
339
  let remote: boolean | undefined
340
340
  let mcp: boolean | undefined
341
341
  let readonly_: boolean | undefined
342
- let requiresApproval: boolean | undefined
342
+ let approvalRequired: boolean | undefined
343
+ let approvalDescription: string | undefined
343
344
  let version: number | undefined
344
345
  let objectNode: ts.ObjectLiteralExpression | undefined
345
346
  let nodeDisplayName: string | null = null
@@ -421,10 +422,33 @@ export const addFunctions: AddWiring = (
421
422
  remote = getPropertyValue(firstArg, 'remote') as boolean | undefined
422
423
  mcp = getPropertyValue(firstArg, 'mcp') as boolean | undefined
423
424
  readonly_ = getPropertyValue(firstArg, 'readonly') as boolean | undefined
424
- requiresApproval = getPropertyValue(firstArg, 'requiresApproval') as
425
+ approvalRequired = getPropertyValue(firstArg, 'approvalRequired') as
425
426
  | boolean
426
427
  | undefined
427
428
 
429
+ // Extract approvalDescription identifier reference
430
+ for (const prop of firstArg.properties) {
431
+ if (
432
+ ts.isPropertyAssignment(prop) &&
433
+ ts.isIdentifier(prop.name) &&
434
+ prop.name.text === 'approvalDescription' &&
435
+ ts.isIdentifier(prop.initializer)
436
+ ) {
437
+ const { pikkuFuncId: descId } = extractFunctionName(
438
+ prop.initializer,
439
+ checker,
440
+ state.rootDir
441
+ )
442
+ if (descId && !descId.startsWith('__temp_')) {
443
+ approvalDescription = descId
444
+ } else {
445
+ // Try resolving the identifier directly
446
+ approvalDescription = prop.initializer.text
447
+ }
448
+ break
449
+ }
450
+ }
451
+
428
452
  const versionRaw = getPropertyValue(firstArg, 'version')
429
453
  if (versionRaw !== null && versionRaw !== undefined) {
430
454
  const parsed = Number(versionRaw)
@@ -759,7 +783,8 @@ export const addFunctions: AddWiring = (
759
783
  remote: remote || undefined,
760
784
  mcp: mcpEnabled || undefined,
761
785
  readonly: readonly_ || undefined,
762
- requiresApproval: requiresApproval || undefined,
786
+ approvalRequired: approvalRequired || undefined,
787
+ approvalDescription: approvalDescription || undefined,
763
788
  version,
764
789
  title,
765
790
  tags: tags || undefined,
@@ -0,0 +1,101 @@
1
+ import * as ts from 'typescript'
2
+ import {
3
+ getPropertyValue,
4
+ getCommonWireMetaData,
5
+ } from '../utils/get-property-value.js'
6
+ import type { AddWiring } from '../types.js'
7
+ import {
8
+ extractFunctionName,
9
+ makeContextBasedId,
10
+ } from '../utils/extract-function-name.js'
11
+ import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
12
+ import { resolveMiddleware } from '../utils/middleware.js'
13
+ import { extractWireNames } from '../utils/post-process.js'
14
+ import { resolveAddonName } from '../utils/resolve-addon-package.js'
15
+ import type { GatewayTransportType } from '@pikku/core/gateway'
16
+
17
+ import { ErrorCode } from '../error-codes.js'
18
+
19
+ export const addGateway: AddWiring = (
20
+ logger,
21
+ node,
22
+ checker,
23
+ state,
24
+ _options
25
+ ) => {
26
+ if (!ts.isCallExpression(node)) {
27
+ return
28
+ }
29
+
30
+ const args = node.arguments
31
+ const firstArg = args[0]
32
+ const expression = node.expression
33
+
34
+ if (!ts.isIdentifier(expression) || expression.text !== 'wireGateway') {
35
+ return
36
+ }
37
+
38
+ if (!firstArg || !ts.isObjectLiteralExpression(firstArg)) {
39
+ return
40
+ }
41
+
42
+ const obj = firstArg
43
+
44
+ const nameValue = getPropertyValue(obj, 'name') as string | null
45
+ const typeValue = getPropertyValue(obj, 'type') as GatewayTransportType | null
46
+ const routeValue = getPropertyValue(obj, 'route') as string | undefined
47
+ const { disabled, tags, summary, description, errors } =
48
+ getCommonWireMetaData(obj, 'Gateway', nameValue, logger)
49
+
50
+ if (disabled) return
51
+
52
+ const funcInitializer = getPropertyAssignmentInitializer(
53
+ obj,
54
+ 'func',
55
+ true,
56
+ checker
57
+ )
58
+ if (!funcInitializer) {
59
+ logger.critical(
60
+ ErrorCode.MISSING_FUNC,
61
+ `No valid 'func' property for gateway '${nameValue}'.`
62
+ )
63
+ return
64
+ }
65
+
66
+ const extracted = extractFunctionName(funcInitializer, checker, state.rootDir)
67
+ let pikkuFuncId = extracted.pikkuFuncId
68
+ if (pikkuFuncId.startsWith('__temp_') && nameValue) {
69
+ pikkuFuncId = makeContextBasedId('gateway', nameValue)
70
+ }
71
+
72
+ const packageName = ts.isIdentifier(funcInitializer)
73
+ ? resolveAddonName(funcInitializer, checker, state.rpc.wireAddonDeclarations)
74
+ : null
75
+
76
+ if (!nameValue || !typeValue) {
77
+ return
78
+ }
79
+
80
+ const middleware = resolveMiddleware(state, obj, tags, checker)
81
+
82
+ state.serviceAggregation.usedFunctions.add(pikkuFuncId)
83
+ extractWireNames(middleware).forEach((name) =>
84
+ state.serviceAggregation.usedMiddleware.add(name)
85
+ )
86
+
87
+ state.gateways.files.add(node.getSourceFile().fileName)
88
+ state.gateways.meta[nameValue] = {
89
+ pikkuFuncId,
90
+ ...(packageName && { packageName }),
91
+ name: nameValue,
92
+ type: typeValue,
93
+ route: routeValue,
94
+ gateway: true,
95
+ summary,
96
+ description,
97
+ errors,
98
+ tags,
99
+ middleware,
100
+ }
101
+ }
@@ -21,6 +21,7 @@ import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js'
21
21
  import { ErrorCode } from '../error-codes.js'
22
22
  import { validateAuthSessionless } from '../utils/validate-auth-sessionless.js'
23
23
  import { detectSchemaVendorOrError } from '../utils/detect-schema-vendor.js'
24
+ import { resolveAddonName } from '../utils/resolve-addon-package.js'
24
25
 
25
26
  import type { InspectorLogger } from '../types.js'
26
27
 
@@ -203,6 +204,10 @@ export function registerHTTPRoute({
203
204
  funcName = makeContextBasedId('http', method, fullRoute)
204
205
  }
205
206
 
207
+ const packageName = ts.isIdentifier(funcInitializer)
208
+ ? resolveAddonName(funcInitializer, checker, state.rpc.wireAddonDeclarations)
209
+ : null
210
+
206
211
  ensureFunctionMetadata(
207
212
  state,
208
213
  funcName,
@@ -320,6 +325,7 @@ export function registerHTTPRoute({
320
325
  state.http.files.add(sourceFile.fileName)
321
326
  state.http.meta[method][fullRoute] = {
322
327
  pikkuFuncId: funcName,
328
+ ...(packageName && { packageName }),
323
329
  route: fullRoute,
324
330
  method: method as HTTPMethod,
325
331
  params: params.length > 0 ? params : undefined,
@@ -13,6 +13,7 @@ import {
13
13
  import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
14
14
  import { resolveMiddleware } from '../utils/middleware.js'
15
15
  import { resolvePermissions } from '../utils/permissions.js'
16
+ import { resolveAddonName } from '../utils/resolve-addon-package.js'
16
17
  import { ErrorCode } from '../error-codes.js'
17
18
 
18
19
  export const addMCPPrompt: AddWiring = (
@@ -72,6 +73,10 @@ export const addMCPPrompt: AddWiring = (
72
73
  pikkuFuncId = makeContextBasedId('mcp', 'prompt', nameValue)
73
74
  }
74
75
 
76
+ const packageName = ts.isIdentifier(funcInitializer)
77
+ ? resolveAddonName(funcInitializer, checker, state.rpc.wireAddonDeclarations)
78
+ : null
79
+
75
80
  ensureFunctionMetadata(
76
81
  state,
77
82
  pikkuFuncId,
@@ -128,6 +133,7 @@ export const addMCPPrompt: AddWiring = (
128
133
 
129
134
  state.mcpEndpoints.promptsMeta[nameValue] = {
130
135
  pikkuFuncId,
136
+ ...(packageName && { packageName }),
131
137
  name: nameValue,
132
138
  description,
133
139
  summary,
@@ -13,6 +13,7 @@ import {
13
13
  import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
14
14
  import { resolveMiddleware } from '../utils/middleware.js'
15
15
  import { resolvePermissions } from '../utils/permissions.js'
16
+ import { resolveAddonName } from '../utils/resolve-addon-package.js'
16
17
  import { ErrorCode } from '../error-codes.js'
17
18
 
18
19
  export const addMCPResource: AddWiring = (
@@ -81,6 +82,10 @@ export const addMCPResource: AddWiring = (
81
82
  pikkuFuncId = makeContextBasedId('mcp', 'resource', uriValue)
82
83
  }
83
84
 
85
+ const packageName = ts.isIdentifier(funcInitializer)
86
+ ? resolveAddonName(funcInitializer, checker, state.rpc.wireAddonDeclarations)
87
+ : null
88
+
84
89
  ensureFunctionMetadata(
85
90
  state,
86
91
  pikkuFuncId,
@@ -145,6 +150,7 @@ export const addMCPResource: AddWiring = (
145
150
 
146
151
  state.mcpEndpoints.resourcesMeta[uriValue] = {
147
152
  pikkuFuncId,
153
+ ...(packageName && { packageName }),
148
154
  uri: uriValue,
149
155
  title: titleValue,
150
156
  description,
@@ -11,6 +11,7 @@ import {
11
11
  import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
12
12
  import { resolveMiddleware } from '../utils/middleware.js'
13
13
  import { extractWireNames } from '../utils/post-process.js'
14
+ import { resolveAddonName } from '../utils/resolve-addon-package.js'
14
15
  import { ErrorCode } from '../error-codes.js'
15
16
 
16
17
  export const addQueueWorker: AddWiring = (logger, node, checker, state) => {
@@ -65,6 +66,10 @@ export const addQueueWorker: AddWiring = (logger, node, checker, state) => {
65
66
  pikkuFuncId = makeContextBasedId('queue', name)
66
67
  }
67
68
 
69
+ const packageName = ts.isIdentifier(funcInitializer)
70
+ ? resolveAddonName(funcInitializer, checker, state.rpc.wireAddonDeclarations)
71
+ : null
72
+
68
73
  if (!name) {
69
74
  logger.critical(
70
75
  ErrorCode.MISSING_QUEUE_NAME,
@@ -85,6 +90,7 @@ export const addQueueWorker: AddWiring = (logger, node, checker, state) => {
85
90
  state.queueWorkers.files.add(node.getSourceFile().fileName)
86
91
  state.queueWorkers.meta[name] = {
87
92
  pikkuFuncId,
93
+ ...(packageName && { packageName }),
88
94
  name,
89
95
  summary,
90
96
  description,
@@ -11,6 +11,7 @@ import {
11
11
  import { getPropertyAssignmentInitializer } from '../utils/type-utils.js'
12
12
  import { resolveMiddleware } from '../utils/middleware.js'
13
13
  import { extractWireNames } from '../utils/post-process.js'
14
+ import { resolveAddonName } from '../utils/resolve-addon-package.js'
14
15
 
15
16
  import { ErrorCode } from '../error-codes.js'
16
17
  export const addSchedule: AddWiring = (
@@ -71,6 +72,10 @@ export const addSchedule: AddWiring = (
71
72
  pikkuFuncId = makeContextBasedId('scheduler', nameValue)
72
73
  }
73
74
 
75
+ const packageName = ts.isIdentifier(funcInitializer)
76
+ ? resolveAddonName(funcInitializer, checker, state.rpc.wireAddonDeclarations)
77
+ : null
78
+
74
79
  if (!nameValue || !scheduleValue) {
75
80
  return
76
81
  }
@@ -87,6 +92,7 @@ export const addSchedule: AddWiring = (
87
92
  state.scheduledTasks.files.add(node.getSourceFile().fileName)
88
93
  state.scheduledTasks.meta[nameValue] = {
89
94
  pikkuFuncId,
95
+ ...(packageName && { packageName }),
90
96
  name: nameValue,
91
97
  schedule: scheduleValue,
92
98
  summary,