@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.
- package/CHANGELOG.md +23 -0
- package/dist/add/add-ai-agent.js +4 -0
- package/dist/add/add-approval-description.d.ts +5 -0
- package/dist/add/add-approval-description.js +52 -0
- package/dist/add/add-channel.js +44 -4
- package/dist/add/add-cli.js +94 -18
- package/dist/add/add-file-with-factory.js +1 -0
- package/dist/add/add-functions.js +22 -3
- package/dist/add/add-gateway.d.ts +2 -0
- package/dist/add/add-gateway.js +62 -0
- package/dist/add/add-http-route.js +5 -0
- package/dist/add/add-mcp-prompt.js +5 -0
- package/dist/add/add-mcp-resource.js +5 -0
- package/dist/add/add-queue-worker.js +5 -0
- package/dist/add/add-schedule.js +5 -0
- package/dist/add/add-wire-addon.js +7 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/inspector.js +11 -0
- package/dist/types.d.ts +15 -0
- package/dist/utils/load-addon-functions-meta.d.ts +12 -0
- package/dist/utils/load-addon-functions-meta.js +76 -0
- package/dist/utils/post-process.js +26 -0
- package/dist/utils/resolve-function-meta.d.ts +11 -0
- package/dist/utils/resolve-function-meta.js +17 -0
- package/dist/utils/serialize-inspector-state.d.ts +6 -0
- package/dist/utils/serialize-inspector-state.js +12 -0
- package/dist/utils/serialize-mcp-json.js +13 -7
- package/dist/visit.js +4 -0
- package/package.json +3 -3
- package/src/add/add-ai-agent.ts +6 -0
- package/src/add/add-approval-description.ts +76 -0
- package/src/add/add-channel.ts +47 -11
- package/src/add/add-cli.ts +140 -30
- package/src/add/add-file-with-factory.ts +1 -0
- package/src/add/add-functions.ts +28 -3
- package/src/add/add-gateway.ts +101 -0
- package/src/add/add-http-route.ts +6 -0
- package/src/add/add-mcp-prompt.ts +6 -0
- package/src/add/add-mcp-resource.ts +6 -0
- package/src/add/add-queue-worker.ts +6 -0
- package/src/add/add-schedule.ts +6 -0
- package/src/add/add-wire-addon.ts +8 -0
- package/src/index.ts +1 -0
- package/src/inspector.ts +16 -0
- package/src/types.ts +16 -0
- package/src/utils/load-addon-functions-meta.ts +94 -0
- package/src/utils/post-process.ts +25 -0
- package/src/utils/resolve-function-meta.ts +25 -0
- package/src/utils/serialize-inspector-state.ts +18 -0
- package/src/utils/serialize-mcp-json.ts +12 -7
- package/src/visit.ts +4 -0
- package/tsconfig.tsbuildinfo +1 -1
package/src/add/add-channel.ts
CHANGED
|
@@ -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
|
|
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
|
|
643
|
-
|
|
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,
|
package/src/add/add-cli.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
337
|
-
prop.initializer
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
)
|
|
341
|
-
|
|
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
|
-
|
|
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
|
-
|
|
554
|
-
|
|
616
|
+
let derivedChoices: string[] | null = null
|
|
617
|
+
|
|
555
618
|
if (pikkuFuncId) {
|
|
556
|
-
|
|
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
|
-
|
|
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
|
-
|
|
562
|
-
|
|
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 = (
|
package/src/add/add-functions.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
package/src/add/add-schedule.ts
CHANGED
|
@@ -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,
|