@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.
- package/CHANGELOG.md +36 -1
- package/OPTIMIZATION-PLAN.md +195 -0
- package/dist/add/add-ai-agent.d.ts +2 -0
- package/dist/add/add-ai-agent.js +314 -0
- package/dist/add/add-channel.js +81 -61
- package/dist/add/add-cli.d.ts +1 -1
- package/dist/add/add-cli.js +42 -19
- package/dist/add/add-file-extends-core-type.d.ts +1 -1
- package/dist/add/add-file-with-config.d.ts +1 -1
- package/dist/add/add-file-with-factory.d.ts +1 -1
- package/dist/add/add-file-with-factory.js +2 -0
- package/dist/add/add-functions.d.ts +1 -1
- package/dist/add/add-functions.js +256 -82
- package/dist/add/add-http-route.d.ts +20 -10
- package/dist/add/add-http-route.js +156 -66
- package/dist/add/add-http-routes.d.ts +5 -0
- package/dist/add/add-http-routes.js +160 -0
- package/dist/add/add-keyed-wiring.d.ts +12 -0
- package/dist/add/add-keyed-wiring.js +97 -0
- package/dist/add/add-mcp-prompt.d.ts +1 -1
- package/dist/add/add-mcp-prompt.js +14 -9
- package/dist/add/add-mcp-resource.d.ts +1 -1
- package/dist/add/add-mcp-resource.js +14 -9
- package/dist/add/add-middleware.d.ts +1 -4
- package/dist/add/add-middleware.js +364 -79
- package/dist/add/add-permission.d.ts +1 -1
- package/dist/add/add-permission.js +152 -40
- package/dist/add/add-queue-worker.d.ts +1 -1
- package/dist/add/add-queue-worker.js +18 -12
- package/dist/add/add-rpc-invocations.d.ts +3 -3
- package/dist/add/add-rpc-invocations.js +24 -10
- package/dist/add/add-schedule.d.ts +1 -1
- package/dist/add/add-schedule.js +11 -5
- package/dist/add/add-secret.d.ts +3 -0
- package/dist/add/add-secret.js +82 -0
- package/dist/add/add-trigger.d.ts +2 -0
- package/dist/add/add-trigger.js +87 -0
- package/dist/add/add-variable.d.ts +1 -0
- package/dist/add/add-variable.js +8 -0
- package/dist/add/add-wire-addon.d.ts +7 -0
- package/dist/add/add-wire-addon.js +70 -0
- package/dist/add/add-workflow-graph.d.ts +3 -2
- package/dist/add/add-workflow-graph.js +143 -406
- package/dist/add/add-workflow.d.ts +1 -1
- package/dist/add/add-workflow.js +6 -4
- package/dist/error-codes.d.ts +15 -1
- package/dist/error-codes.js +20 -1
- package/dist/index.d.ts +9 -8
- package/dist/index.js +5 -4
- package/dist/inspector.d.ts +2 -2
- package/dist/inspector.js +95 -15
- package/dist/schema-generator.d.ts +1 -0
- package/dist/schema-generator.js +1 -0
- package/dist/types-map.js +10 -1
- package/dist/types.d.ts +180 -50
- package/dist/utils/compute-required-schemas.d.ts +4 -0
- package/dist/utils/compute-required-schemas.js +40 -0
- package/dist/utils/contract-hashes.d.ts +52 -0
- package/dist/utils/contract-hashes.js +269 -0
- package/dist/utils/custom-types-generator.d.ts +9 -0
- package/dist/utils/custom-types-generator.js +71 -0
- package/dist/utils/detect-schema-vendor.d.ts +22 -0
- package/dist/utils/detect-schema-vendor.js +76 -0
- package/dist/utils/does-type-extend-core-type.d.ts +1 -1
- package/dist/utils/ensure-function-metadata.d.ts +6 -3
- package/dist/utils/ensure-function-metadata.js +220 -6
- package/dist/utils/extract-function-name.d.ts +5 -16
- package/dist/utils/extract-function-name.js +86 -291
- package/dist/utils/extract-services.d.ts +2 -1
- package/dist/utils/extract-services.js +25 -1
- package/dist/utils/filter-inspector-state.d.ts +1 -1
- package/dist/utils/filter-inspector-state.js +107 -23
- package/dist/utils/filter-utils.d.ts +2 -2
- package/dist/utils/get-files-and-methods.d.ts +1 -1
- package/dist/utils/get-property-value.d.ts +6 -1
- package/dist/utils/get-property-value.js +28 -3
- package/dist/utils/hash.d.ts +2 -0
- package/dist/utils/hash.js +23 -0
- package/dist/utils/middleware.d.ts +9 -32
- package/dist/utils/middleware.js +80 -66
- package/dist/utils/permissions.d.ts +4 -4
- package/dist/utils/permissions.js +10 -10
- package/dist/utils/post-process.d.ts +11 -11
- package/dist/utils/post-process.js +247 -24
- package/dist/utils/resolve-addon-package.d.ts +16 -0
- package/dist/utils/resolve-addon-package.js +34 -0
- package/dist/utils/resolve-function-types.d.ts +6 -0
- package/dist/utils/resolve-function-types.js +29 -0
- package/dist/utils/resolve-identifier.d.ts +10 -0
- package/dist/utils/resolve-identifier.js +36 -0
- package/dist/utils/resolve-versions.d.ts +2 -0
- package/dist/utils/resolve-versions.js +78 -0
- package/dist/utils/schema-generator.d.ts +9 -0
- package/dist/utils/schema-generator.js +209 -0
- package/dist/utils/serialize-inspector-state.d.ts +70 -23
- package/dist/utils/serialize-inspector-state.js +98 -22
- package/dist/utils/serialize-mcp-json.d.ts +2 -0
- package/dist/utils/serialize-mcp-json.js +99 -0
- package/dist/utils/serialize-middleware-groups-meta.d.ts +12 -0
- package/dist/utils/serialize-middleware-groups-meta.js +28 -0
- package/dist/utils/serialize-openapi-json.d.ts +85 -0
- package/dist/utils/serialize-openapi-json.js +151 -0
- package/dist/utils/serialize-permissions-groups-meta.d.ts +6 -0
- package/dist/utils/serialize-permissions-groups-meta.js +31 -0
- package/dist/utils/validate-auth-sessionless.d.ts +3 -0
- package/dist/utils/validate-auth-sessionless.js +14 -0
- package/dist/utils/workflow/dsl/deserialize-dsl-workflow.js +34 -102
- package/dist/utils/workflow/dsl/extract-dsl-workflow.d.ts +1 -1
- package/dist/utils/workflow/dsl/extract-dsl-workflow.js +23 -4
- package/dist/utils/workflow/graph/convert-dsl-to-graph.js +12 -10
- package/dist/utils/workflow/graph/finalize-workflow-wires.d.ts +3 -0
- package/dist/utils/workflow/graph/finalize-workflow-wires.js +276 -0
- package/dist/utils/workflow/graph/finalize-workflows.d.ts +2 -0
- package/dist/utils/workflow/graph/finalize-workflows.js +75 -0
- package/dist/utils/workflow/graph/index.d.ts +2 -0
- package/dist/utils/workflow/graph/index.js +2 -0
- package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +0 -8
- package/dist/utils/workflow/graph/serialize-workflow-graph.js +1 -3
- package/dist/utils/workflow/graph/workflow-graph.types.d.ts +53 -79
- package/dist/utils/workflow/graph/workflow-graph.types.js +1 -1
- package/dist/visit.d.ts +1 -1
- package/dist/visit.js +13 -6
- package/package.json +14 -4
- package/src/add/add-ai-agent.ts +468 -0
- package/src/add/add-channel.ts +103 -79
- package/src/add/add-cli.ts +68 -24
- package/src/add/add-file-extends-core-type.ts +1 -1
- package/src/add/add-file-with-config.ts +1 -1
- package/src/add/add-file-with-factory.ts +3 -1
- package/src/add/add-functions.ts +349 -103
- package/src/add/add-http-route.ts +263 -89
- package/src/add/add-http-routes.ts +229 -0
- package/src/add/add-keyed-wiring.ts +151 -0
- package/src/add/add-mcp-prompt.ts +27 -16
- package/src/add/add-mcp-resource.ts +28 -16
- package/src/add/add-middleware.ts +482 -80
- package/src/add/add-permission.ts +199 -40
- package/src/add/add-queue-worker.ts +25 -20
- package/src/add/add-rpc-invocations.ts +28 -11
- package/src/add/add-schedule.ts +17 -12
- package/src/add/add-secret.ts +140 -0
- package/src/add/add-trigger.ts +154 -0
- package/src/add/add-variable.ts +9 -0
- package/src/add/add-wire-addon.ts +80 -0
- package/src/add/add-workflow-graph.ts +180 -522
- package/src/add/add-workflow.ts +7 -6
- package/src/error-codes.ts +25 -1
- package/src/index.ts +23 -13
- package/src/inspector.ts +139 -19
- package/src/schema-generator.ts +1 -0
- package/src/types-map.ts +12 -1
- package/src/types.ts +199 -69
- package/src/utils/compute-required-schemas.ts +48 -0
- package/src/utils/contract-hashes.test.ts +553 -0
- package/src/utils/contract-hashes.ts +386 -0
- package/src/utils/custom-types-generator.ts +88 -0
- package/src/utils/detect-schema-vendor.ts +90 -0
- package/src/utils/does-type-extend-core-type.ts +1 -1
- package/src/utils/ensure-function-metadata.ts +325 -8
- package/src/utils/extract-function-name.ts +101 -351
- package/src/utils/extract-services.ts +35 -2
- package/src/utils/filter-inspector-state.test.ts +37 -25
- package/src/utils/filter-inspector-state.ts +146 -32
- package/src/utils/filter-utils.test.ts +1 -1
- package/src/utils/filter-utils.ts +2 -2
- package/src/utils/get-files-and-methods.ts +1 -1
- package/src/utils/get-property-value.ts +42 -4
- package/src/utils/hash.ts +26 -0
- package/src/utils/middleware.test.ts +204 -0
- package/src/utils/middleware.ts +131 -69
- package/src/utils/permissions.test.ts +35 -12
- package/src/utils/permissions.ts +12 -12
- package/src/utils/post-process.ts +306 -44
- package/src/utils/resolve-addon-package.ts +49 -0
- package/src/utils/resolve-function-types.ts +42 -0
- package/src/utils/resolve-identifier.ts +46 -0
- package/src/utils/resolve-versions.test.ts +249 -0
- package/src/utils/resolve-versions.ts +105 -0
- package/src/utils/schema-generator.ts +329 -0
- package/src/utils/serialize-inspector-state.ts +184 -43
- package/src/utils/serialize-mcp-json.ts +145 -0
- package/src/utils/serialize-middleware-groups-meta.ts +33 -0
- package/src/utils/serialize-openapi-json.ts +277 -0
- package/src/utils/serialize-permissions-groups-meta.ts +35 -0
- package/src/utils/test-data/inspector-state.json +69 -66
- package/src/utils/validate-auth-sessionless.ts +29 -0
- package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +43 -119
- package/src/utils/workflow/dsl/extract-dsl-workflow.ts +26 -6
- package/src/utils/workflow/graph/convert-dsl-to-graph.ts +17 -10
- package/src/utils/workflow/graph/finalize-workflow-wires.ts +310 -0
- package/src/utils/workflow/graph/finalize-workflows.ts +100 -0
- package/src/utils/workflow/graph/index.ts +5 -0
- package/src/utils/workflow/graph/serialize-workflow-graph.ts +1 -8
- package/src/utils/workflow/graph/workflow-graph.types.ts +29 -78
- package/src/visit.ts +19 -7
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/add/add-forge-credential.d.ts +0 -8
- package/dist/add/add-forge-credential.js +0 -77
- package/dist/add/add-forge-node.d.ts +0 -7
- package/dist/add/add-forge-node.js +0 -77
- package/dist/add/add-mcp-tool.d.ts +0 -2
- package/dist/add/add-mcp-tool.js +0 -81
- package/dist/utils/extract-service-metadata.d.ts +0 -19
- package/dist/utils/extract-service-metadata.js +0 -244
- package/dist/utils/write-service-metadata.d.ts +0 -13
- package/dist/utils/write-service-metadata.js +0 -37
- package/src/add/add-forge-credential.ts +0 -119
- package/src/add/add-forge-node.ts +0 -132
- package/src/add/add-mcp-tool.ts +0 -141
- package/src/utils/extract-service-metadata.ts +0 -353
- package/src/utils/write-service-metadata.ts +0 -51
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
|
-
import { PermissionMetadata } from '@pikku/core';
|
|
3
|
-
import { InspectorState } from '../types.js';
|
|
2
|
+
import type { PermissionMetadata } from '@pikku/core';
|
|
3
|
+
import type { InspectorState } from '../types.js';
|
|
4
4
|
/**
|
|
5
|
-
* Extract permission
|
|
6
|
-
* Resolves each identifier to its
|
|
5
|
+
* Extract permission pikkuFuncIds from an expression (array or object literal)
|
|
6
|
+
* Resolves each identifier to its pikkuFuncId using extractFunctionName
|
|
7
7
|
* Also handles call expressions (like rolePermission({...}))
|
|
8
8
|
*
|
|
9
9
|
* Supports both formats:
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as ts from 'typescript';
|
|
2
2
|
import { extractFunctionName } from './extract-function-name.js';
|
|
3
3
|
/**
|
|
4
|
-
* Extract permission
|
|
5
|
-
* Resolves each identifier to its
|
|
4
|
+
* Extract permission pikkuFuncIds from an expression (array or object literal)
|
|
5
|
+
* Resolves each identifier to its pikkuFuncId using extractFunctionName
|
|
6
6
|
* Also handles call expressions (like rolePermission({...}))
|
|
7
7
|
*
|
|
8
8
|
* Supports both formats:
|
|
@@ -14,14 +14,14 @@ export function extractPermissionPikkuNames(node, checker, rootDir) {
|
|
|
14
14
|
// Helper to extract from a single element
|
|
15
15
|
const extractFromElement = (element) => {
|
|
16
16
|
if (ts.isIdentifier(element)) {
|
|
17
|
-
const {
|
|
18
|
-
names.push(
|
|
17
|
+
const { pikkuFuncId } = extractFunctionName(element, checker, rootDir);
|
|
18
|
+
names.push(pikkuFuncId);
|
|
19
19
|
}
|
|
20
20
|
else if (ts.isCallExpression(element)) {
|
|
21
21
|
// Handle call expressions like hasEmailQuota(100) or rolePermission({...})
|
|
22
22
|
// Extract the function being called (e.g., 'hasEmailQuota' from 'hasEmailQuota(100)')
|
|
23
|
-
const {
|
|
24
|
-
names.push(
|
|
23
|
+
const { pikkuFuncId } = extractFunctionName(element.expression, checker, rootDir);
|
|
24
|
+
names.push(pikkuFuncId);
|
|
25
25
|
}
|
|
26
26
|
else if (ts.isArrayLiteralExpression(element)) {
|
|
27
27
|
// Nested array (for Record values that are arrays)
|
|
@@ -107,11 +107,11 @@ export function resolveHTTPPermissions(state, route, tags, explicitPermissionsNo
|
|
|
107
107
|
if (explicitPermissionsNode) {
|
|
108
108
|
const permissionNames = extractPermissionPikkuNames(explicitPermissionsNode, checker, state.rootDir);
|
|
109
109
|
for (const name of permissionNames) {
|
|
110
|
-
const
|
|
110
|
+
const def = state.permissions.definitions[name];
|
|
111
111
|
resolved.push({
|
|
112
112
|
type: 'wire',
|
|
113
113
|
name,
|
|
114
|
-
inline:
|
|
114
|
+
inline: def?.exportedName === null,
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
117
|
}
|
|
@@ -140,11 +140,11 @@ function resolveTagAndExplicitPermissions(state, tags, explicitPermissionsNode,
|
|
|
140
140
|
if (explicitPermissionsNode) {
|
|
141
141
|
const permissionNames = extractPermissionPikkuNames(explicitPermissionsNode, checker, state.rootDir);
|
|
142
142
|
for (const name of permissionNames) {
|
|
143
|
-
const
|
|
143
|
+
const def = state.permissions.definitions[name];
|
|
144
144
|
resolved.push({
|
|
145
145
|
type: 'wire',
|
|
146
146
|
name,
|
|
147
|
-
inline:
|
|
147
|
+
inline: def?.exportedName === null,
|
|
148
148
|
});
|
|
149
149
|
}
|
|
150
150
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { MiddlewareMetadata, PermissionMetadata } from '@pikku/core';
|
|
1
|
+
import type { InspectorState, InspectorLogger, InspectorOptions, InspectorModelConfig } from '../types.js';
|
|
2
|
+
import type { MiddlewareMetadata, PermissionMetadata } from '@pikku/core';
|
|
4
3
|
/**
|
|
5
4
|
* Helper to extract wire-level middleware/permission names from metadata.
|
|
6
5
|
* Only extracts type:'wire' variants (individual middleware/permissions).
|
|
@@ -15,11 +14,12 @@ export declare function extractWireNames(list?: MiddlewareMetadata[] | Permissio
|
|
|
15
14
|
* in the add-* methods during AST traversal for efficiency.
|
|
16
15
|
*/
|
|
17
16
|
export declare function aggregateRequiredServices(state: InspectorState | Omit<InspectorState, 'typesLookup'>): void;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
export declare function
|
|
17
|
+
export declare function validateSecretOverrides(logger: InspectorLogger, state: InspectorState | Omit<InspectorState, 'typesLookup'>): void;
|
|
18
|
+
export declare function validateVariableOverrides(logger: InspectorLogger, state: InspectorState | Omit<InspectorState, 'typesLookup'>): void;
|
|
19
|
+
export declare function computeResolvedIOTypes(state: InspectorState): void;
|
|
20
|
+
export declare function computeMiddlewareGroupsMeta(state: InspectorState): void;
|
|
21
|
+
export declare function computePermissionsGroupsMeta(state: InspectorState): void;
|
|
22
|
+
export declare function computeRequiredSchemas(state: InspectorState, options: InspectorOptions): void;
|
|
23
|
+
export declare function validateAgentModels(logger: InspectorLogger, state: InspectorState | Omit<InspectorState, 'typesLookup'>, modelConfig?: InspectorModelConfig): void;
|
|
24
|
+
export declare function validateAgentOverrides(logger: InspectorLogger, state: InspectorState | Omit<InspectorState, 'typesLookup'>, modelConfig?: InspectorModelConfig): void;
|
|
25
|
+
export declare function computeDiagnostics(state: InspectorState): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { extractTypeKeys } from './type-utils.js';
|
|
2
|
-
import {
|
|
2
|
+
import { ErrorCode } from '../error-codes.js';
|
|
3
3
|
/**
|
|
4
4
|
* Helper to extract wire-level middleware/permission names from metadata.
|
|
5
5
|
* Only extracts type:'wire' variants (individual middleware/permissions).
|
|
@@ -99,14 +99,14 @@ export function aggregateRequiredServices(state) {
|
|
|
99
99
|
});
|
|
100
100
|
// 2. Services from used middleware (individual + groups)
|
|
101
101
|
usedMiddleware.forEach((middlewareName) => {
|
|
102
|
-
const middlewareMeta = state.middleware.
|
|
102
|
+
const middlewareMeta = state.middleware.definitions[middlewareName];
|
|
103
103
|
if (middlewareMeta?.services) {
|
|
104
104
|
addServices(middlewareMeta.services);
|
|
105
105
|
}
|
|
106
106
|
});
|
|
107
107
|
// 3. Services from used permissions (individual + groups)
|
|
108
108
|
usedPermissions.forEach((permissionName) => {
|
|
109
|
-
const permissionMeta = state.permissions.
|
|
109
|
+
const permissionMeta = state.permissions.definitions[permissionName];
|
|
110
110
|
if (permissionMeta?.services) {
|
|
111
111
|
addServices(permissionMeta.services);
|
|
112
112
|
}
|
|
@@ -161,29 +161,252 @@ export function aggregateRequiredServices(state) {
|
|
|
161
161
|
});
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
* to generate documentation for AI consumption.
|
|
168
|
-
*
|
|
169
|
-
* Must be called after aggregateRequiredServices() to ensure types are loaded.
|
|
170
|
-
*/
|
|
171
|
-
export function extractServiceInterfaceMetadata(state, checker) {
|
|
172
|
-
if (!('typesLookup' in state)) {
|
|
164
|
+
export function validateSecretOverrides(logger, state) {
|
|
165
|
+
const { wireAddonDeclarations } = state.rpc;
|
|
166
|
+
if (!wireAddonDeclarations || wireAddonDeclarations.size === 0)
|
|
173
167
|
return;
|
|
168
|
+
const secretNames = new Set(state.secrets.definitions.map((d) => d.name));
|
|
169
|
+
for (const [namespace, addonDecl] of wireAddonDeclarations.entries()) {
|
|
170
|
+
if (!addonDecl.secretOverrides)
|
|
171
|
+
continue;
|
|
172
|
+
for (const secretKey of Object.keys(addonDecl.secretOverrides)) {
|
|
173
|
+
if (!secretNames.has(secretKey)) {
|
|
174
|
+
const availableSecrets = Array.from(secretNames);
|
|
175
|
+
logger.critical(ErrorCode.INVALID_VALUE, `Secret override '${secretKey}' in addon '${namespace}' (${addonDecl.package}) does not exist. Available secrets: ${availableSecrets.join(', ') || 'none'}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
174
178
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
179
|
+
}
|
|
180
|
+
export function validateVariableOverrides(logger, state) {
|
|
181
|
+
const { wireAddonDeclarations } = state.rpc;
|
|
182
|
+
if (!wireAddonDeclarations || wireAddonDeclarations.size === 0)
|
|
183
|
+
return;
|
|
184
|
+
const variableNames = new Set(state.variables.definitions.map((d) => d.name));
|
|
185
|
+
for (const [namespace, addonDecl] of wireAddonDeclarations.entries()) {
|
|
186
|
+
if (!addonDecl.variableOverrides)
|
|
187
|
+
continue;
|
|
188
|
+
for (const variableKey of Object.keys(addonDecl.variableOverrides)) {
|
|
189
|
+
if (!variableNames.has(variableKey)) {
|
|
190
|
+
const availableVariables = Array.from(variableNames);
|
|
191
|
+
logger.critical(ErrorCode.INVALID_VALUE, `Variable override '${variableKey}' in addon '${namespace}' (${addonDecl.package}) does not exist. Available variables: ${availableVariables.join(', ') || 'none'}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
180
194
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
|
|
195
|
+
}
|
|
196
|
+
export function computeResolvedIOTypes(state) {
|
|
197
|
+
const { functions } = state;
|
|
198
|
+
for (const [pikkuFuncId, meta] of Object.entries(functions.meta)) {
|
|
199
|
+
const input = meta.inputs?.[0];
|
|
200
|
+
const output = meta.outputs?.[0];
|
|
201
|
+
let inputType = 'null';
|
|
202
|
+
if (input) {
|
|
203
|
+
try {
|
|
204
|
+
inputType = functions.typesMap.getTypeMeta(input).uniqueName;
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
inputType = input;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
let outputType = 'null';
|
|
211
|
+
if (output) {
|
|
212
|
+
try {
|
|
213
|
+
outputType = functions.typesMap.getTypeMeta(output).uniqueName;
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
outputType = output;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
state.resolvedIOTypes[pikkuFuncId] = { inputType, outputType };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const serializeGroupMap = (groupMap) => {
|
|
223
|
+
const result = {};
|
|
224
|
+
for (const [key, meta] of groupMap.entries()) {
|
|
225
|
+
result[key] = {
|
|
226
|
+
exportName: meta.exportName,
|
|
227
|
+
sourceFile: meta.sourceFile,
|
|
228
|
+
position: meta.position,
|
|
229
|
+
services: meta.services,
|
|
230
|
+
count: meta.count,
|
|
231
|
+
instanceIds: meta.instanceIds,
|
|
232
|
+
isFactory: meta.isFactory,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
return result;
|
|
236
|
+
};
|
|
237
|
+
export function computeMiddlewareGroupsMeta(state) {
|
|
238
|
+
state.middlewareGroupsMeta = {
|
|
239
|
+
definitions: state.middleware.definitions,
|
|
240
|
+
instances: state.middleware.instances,
|
|
241
|
+
httpGroups: serializeGroupMap(state.http.routeMiddleware),
|
|
242
|
+
tagGroups: serializeGroupMap(state.middleware.tagMiddleware),
|
|
243
|
+
channelMiddleware: {
|
|
244
|
+
definitions: state.channelMiddleware.definitions,
|
|
245
|
+
instances: state.channelMiddleware.instances,
|
|
246
|
+
tagGroups: serializeGroupMap(state.channelMiddleware.tagMiddleware),
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
export function computePermissionsGroupsMeta(state) {
|
|
251
|
+
const httpGroups = {};
|
|
252
|
+
for (const [pattern, meta] of state.http.routePermissions.entries()) {
|
|
253
|
+
httpGroups[pattern] = {
|
|
254
|
+
exportName: meta.exportName,
|
|
255
|
+
sourceFile: meta.sourceFile,
|
|
256
|
+
position: meta.position,
|
|
257
|
+
services: meta.services,
|
|
258
|
+
count: meta.count,
|
|
259
|
+
instanceIds: meta.instanceIds,
|
|
260
|
+
isFactory: meta.isFactory,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
const tagGroups = {};
|
|
264
|
+
for (const [tag, meta] of state.permissions.tagPermissions.entries()) {
|
|
265
|
+
tagGroups[tag] = {
|
|
266
|
+
exportName: meta.exportName,
|
|
267
|
+
sourceFile: meta.sourceFile,
|
|
268
|
+
position: meta.position,
|
|
269
|
+
services: meta.services,
|
|
270
|
+
count: meta.count,
|
|
271
|
+
instanceIds: meta.instanceIds,
|
|
272
|
+
isFactory: meta.isFactory,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
state.permissionsGroupsMeta = {
|
|
276
|
+
definitions: state.permissions.definitions,
|
|
277
|
+
httpGroups,
|
|
278
|
+
tagGroups,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
const PRIMITIVE_TYPES = new Set([
|
|
282
|
+
'boolean',
|
|
283
|
+
'string',
|
|
284
|
+
'number',
|
|
285
|
+
'null',
|
|
286
|
+
'undefined',
|
|
287
|
+
'void',
|
|
288
|
+
'any',
|
|
289
|
+
'unknown',
|
|
290
|
+
'never',
|
|
291
|
+
]);
|
|
292
|
+
export function computeRequiredSchemas(state, options) {
|
|
293
|
+
const { functions, schemaLookup } = state;
|
|
294
|
+
const schemasFromTypes = options.schemaConfig?.schemasFromTypes;
|
|
295
|
+
state.requiredSchemas = new Set([
|
|
296
|
+
...Object.values(functions.meta)
|
|
297
|
+
.flatMap(({ inputs, outputs }) => {
|
|
298
|
+
const types = [];
|
|
299
|
+
if (inputs?.[0]) {
|
|
300
|
+
try {
|
|
301
|
+
types.push(functions.typesMap.getUniqueName(inputs[0]));
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
types.push(inputs[0]);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (outputs?.[0]) {
|
|
308
|
+
try {
|
|
309
|
+
types.push(functions.typesMap.getUniqueName(outputs[0]));
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
types.push(outputs[0]);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return types;
|
|
316
|
+
})
|
|
317
|
+
.filter((s) => !!s && !PRIMITIVE_TYPES.has(s)),
|
|
318
|
+
...functions.typesMap.customTypes.keys(),
|
|
319
|
+
...(schemasFromTypes || []),
|
|
320
|
+
...Array.from(schemaLookup.keys()),
|
|
321
|
+
]);
|
|
322
|
+
}
|
|
323
|
+
export function validateAgentModels(logger, state, modelConfig) {
|
|
324
|
+
const aliases = modelConfig?.models ?? {};
|
|
325
|
+
for (const [, meta] of Object.entries(state.agents.agentsMeta)) {
|
|
326
|
+
const model = meta.model;
|
|
327
|
+
if (!model) {
|
|
328
|
+
logger.critical(ErrorCode.MISSING_MODEL, `AI agent '${meta.name}' is missing the 'model' property.`);
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if (model.includes('/'))
|
|
332
|
+
continue;
|
|
333
|
+
if (!aliases[model]) {
|
|
334
|
+
const available = Object.keys(aliases);
|
|
335
|
+
logger.critical(ErrorCode.INVALID_MODEL, `AI agent '${meta.name}' uses model alias '${model}' which is not defined in pikku.config.json models. ` +
|
|
336
|
+
`Available aliases: ${available.join(', ') || 'none'}`);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
export function validateAgentOverrides(logger, state, modelConfig) {
|
|
341
|
+
const overrides = modelConfig?.agentOverrides ?? {};
|
|
342
|
+
const aliases = modelConfig?.models ?? {};
|
|
343
|
+
const agentNames = new Set(Object.values(state.agents.agentsMeta).map((m) => m.name));
|
|
344
|
+
for (const [agentName, override] of Object.entries(overrides)) {
|
|
345
|
+
if (!agentNames.has(agentName)) {
|
|
346
|
+
logger.warn(`agentOverrides references unknown agent '${agentName}'`);
|
|
347
|
+
}
|
|
348
|
+
if (override.model &&
|
|
349
|
+
!override.model.includes('/') &&
|
|
350
|
+
!aliases[override.model]) {
|
|
351
|
+
logger.critical(ErrorCode.INVALID_MODEL, `agentOverrides['${agentName}'].model uses alias '${override.model}' which is not defined in models.`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
export function computeDiagnostics(state) {
|
|
356
|
+
const diagnostics = [];
|
|
357
|
+
for (const [id, meta] of Object.entries(state.functions.meta)) {
|
|
358
|
+
if (meta.services && !meta.services.optimized) {
|
|
359
|
+
diagnostics.push({
|
|
360
|
+
code: ErrorCode.SERVICES_NOT_DESTRUCTURED,
|
|
361
|
+
message: `Function '${id}' does not destructure its services parameter, preventing tree-shaking optimization.`,
|
|
362
|
+
sourceFile: meta.pikkuFuncId,
|
|
363
|
+
position: 0,
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
if (meta.wires && !meta.wires.optimized) {
|
|
367
|
+
diagnostics.push({
|
|
368
|
+
code: ErrorCode.WIRES_NOT_DESTRUCTURED,
|
|
369
|
+
message: `Function '${id}' does not destructure its wires parameter, preventing tree-shaking optimization.`,
|
|
370
|
+
sourceFile: meta.pikkuFuncId,
|
|
371
|
+
position: 0,
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
for (const [id, def] of Object.entries(state.middleware.definitions)) {
|
|
376
|
+
if (def.services && !def.services.optimized) {
|
|
377
|
+
diagnostics.push({
|
|
378
|
+
code: ErrorCode.SERVICES_NOT_DESTRUCTURED,
|
|
379
|
+
message: `Middleware '${id}' does not destructure its services parameter, preventing tree-shaking optimization.`,
|
|
380
|
+
sourceFile: def.sourceFile,
|
|
381
|
+
position: def.position,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
if (def.wires && !def.wires.optimized) {
|
|
385
|
+
diagnostics.push({
|
|
386
|
+
code: ErrorCode.WIRES_NOT_DESTRUCTURED,
|
|
387
|
+
message: `Middleware '${id}' does not destructure its wires parameter, preventing tree-shaking optimization.`,
|
|
388
|
+
sourceFile: def.sourceFile,
|
|
389
|
+
position: def.position,
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
for (const [id, def] of Object.entries(state.permissions.definitions)) {
|
|
394
|
+
if (def.services && !def.services.optimized) {
|
|
395
|
+
diagnostics.push({
|
|
396
|
+
code: ErrorCode.SERVICES_NOT_DESTRUCTURED,
|
|
397
|
+
message: `Permission '${id}' does not destructure its services parameter, preventing tree-shaking optimization.`,
|
|
398
|
+
sourceFile: def.sourceFile,
|
|
399
|
+
position: def.position,
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
if (def.wires && !def.wires.optimized) {
|
|
403
|
+
diagnostics.push({
|
|
404
|
+
code: ErrorCode.WIRES_NOT_DESTRUCTURED,
|
|
405
|
+
message: `Permission '${id}' does not destructure its wires parameter, preventing tree-shaking optimization.`,
|
|
406
|
+
sourceFile: def.sourceFile,
|
|
407
|
+
position: def.position,
|
|
408
|
+
});
|
|
409
|
+
}
|
|
187
410
|
}
|
|
188
|
-
state.
|
|
411
|
+
state.diagnostics = diagnostics;
|
|
189
412
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the addon package name from an imported identifier.
|
|
4
|
+
* Checks if the identifier's import module specifier matches any
|
|
5
|
+
* configured addon package.
|
|
6
|
+
*
|
|
7
|
+
* This is a general utility — any wire handler that processes a `func`
|
|
8
|
+
* property can use it to detect when the function comes from an
|
|
9
|
+
* addon package.
|
|
10
|
+
*/
|
|
11
|
+
export declare const resolveAddonName: (identifier: ts.Identifier, checker: ts.TypeChecker, wireAddonDeclarations?: Map<string, {
|
|
12
|
+
package: string;
|
|
13
|
+
rpcEndpoint?: string;
|
|
14
|
+
secretOverrides?: Record<string, string>;
|
|
15
|
+
variableOverrides?: Record<string, string>;
|
|
16
|
+
}>) => string | null;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the addon package name from an imported identifier.
|
|
4
|
+
* Checks if the identifier's import module specifier matches any
|
|
5
|
+
* configured addon package.
|
|
6
|
+
*
|
|
7
|
+
* This is a general utility — any wire handler that processes a `func`
|
|
8
|
+
* property can use it to detect when the function comes from an
|
|
9
|
+
* addon package.
|
|
10
|
+
*/
|
|
11
|
+
export const resolveAddonName = (identifier, checker, wireAddonDeclarations) => {
|
|
12
|
+
if (!wireAddonDeclarations || wireAddonDeclarations.size === 0) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const sym = checker.getSymbolAtLocation(identifier);
|
|
16
|
+
if (!sym)
|
|
17
|
+
return null;
|
|
18
|
+
const decl = sym.declarations?.[0];
|
|
19
|
+
if (!decl || !ts.isImportSpecifier(decl))
|
|
20
|
+
return null;
|
|
21
|
+
// ImportSpecifier -> NamedImports -> ImportClause -> ImportDeclaration
|
|
22
|
+
const importDecl = decl.parent?.parent?.parent;
|
|
23
|
+
if (!importDecl || !ts.isImportDeclaration(importDecl))
|
|
24
|
+
return null;
|
|
25
|
+
if (!ts.isStringLiteral(importDecl.moduleSpecifier))
|
|
26
|
+
return null;
|
|
27
|
+
const moduleSpecifier = importDecl.moduleSpecifier.text;
|
|
28
|
+
for (const addonDecl of wireAddonDeclarations.values()) {
|
|
29
|
+
if (addonDecl.package === moduleSpecifier) {
|
|
30
|
+
return addonDecl.package;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TypesMap } from '../types-map.js';
|
|
2
|
+
import type { FunctionsMeta } from '@pikku/core';
|
|
3
|
+
export declare function resolveFunctionIOTypes(pikkuFuncId: string, functionsMeta: FunctionsMeta, typesMap: TypesMap, requiredTypes: Set<string>): {
|
|
4
|
+
inputType: string;
|
|
5
|
+
outputType: string;
|
|
6
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function resolveFunctionIOTypes(pikkuFuncId, functionsMeta, typesMap, requiredTypes) {
|
|
2
|
+
const functionMeta = functionsMeta[pikkuFuncId];
|
|
3
|
+
if (!functionMeta) {
|
|
4
|
+
throw new Error(`Function ${pikkuFuncId} not found in functionsMeta. Please check your configuration.`);
|
|
5
|
+
}
|
|
6
|
+
const input = functionMeta.inputs ? functionMeta.inputs[0] : undefined;
|
|
7
|
+
const output = functionMeta.outputs ? functionMeta.outputs[0] : undefined;
|
|
8
|
+
let inputType = 'null';
|
|
9
|
+
if (input) {
|
|
10
|
+
try {
|
|
11
|
+
inputType = typesMap.getTypeMeta(input).uniqueName;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
inputType = input;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
let outputType = 'null';
|
|
18
|
+
if (output) {
|
|
19
|
+
try {
|
|
20
|
+
outputType = typesMap.getTypeMeta(output).uniqueName;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
outputType = output;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
requiredTypes.add(inputType);
|
|
27
|
+
requiredTypes.add(outputType);
|
|
28
|
+
return { inputType, outputType };
|
|
29
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve an identifier to its definition, optionally unwrapping
|
|
4
|
+
* known "define" wrapper functions (e.g. defineHTTPRoutes, defineCLICommands).
|
|
5
|
+
*
|
|
6
|
+
* When the identifier resolves to a variable whose initializer is a call
|
|
7
|
+
* to one of the `unwrapFunctionNames`, the first argument of that call
|
|
8
|
+
* is returned instead.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveIdentifier(node: ts.Identifier, checker: ts.TypeChecker, unwrapFunctionNames?: string[]): ts.Node | undefined;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve an identifier to its definition, optionally unwrapping
|
|
4
|
+
* known "define" wrapper functions (e.g. defineHTTPRoutes, defineCLICommands).
|
|
5
|
+
*
|
|
6
|
+
* When the identifier resolves to a variable whose initializer is a call
|
|
7
|
+
* to one of the `unwrapFunctionNames`, the first argument of that call
|
|
8
|
+
* is returned instead.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveIdentifier(node, checker, unwrapFunctionNames) {
|
|
11
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
12
|
+
if (!symbol)
|
|
13
|
+
return undefined;
|
|
14
|
+
// Handle aliased symbols (imports)
|
|
15
|
+
let resolvedSymbol = symbol;
|
|
16
|
+
if (resolvedSymbol.flags & ts.SymbolFlags.Alias) {
|
|
17
|
+
resolvedSymbol = checker.getAliasedSymbol(resolvedSymbol) ?? resolvedSymbol;
|
|
18
|
+
}
|
|
19
|
+
const decl = resolvedSymbol.valueDeclaration || resolvedSymbol.declarations?.[0];
|
|
20
|
+
if (!decl)
|
|
21
|
+
return undefined;
|
|
22
|
+
// Follow to the actual value (handles imports, variable declarations)
|
|
23
|
+
if (ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
24
|
+
// Check if it's a call to one of the unwrap functions
|
|
25
|
+
if (ts.isCallExpression(decl.initializer) &&
|
|
26
|
+
unwrapFunctionNames &&
|
|
27
|
+
unwrapFunctionNames.length > 0) {
|
|
28
|
+
const expr = decl.initializer.expression;
|
|
29
|
+
if (ts.isIdentifier(expr) && unwrapFunctionNames.includes(expr.text)) {
|
|
30
|
+
return decl.initializer.arguments[0];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return decl.initializer;
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { parseVersionedId, formatVersionedId } from '@pikku/core';
|
|
2
|
+
import { ErrorCode } from '../error-codes.js';
|
|
3
|
+
export function resolveLatestVersions(state, logger) {
|
|
4
|
+
const functionsMeta = state.functions.meta;
|
|
5
|
+
const groups = new Map();
|
|
6
|
+
for (const [id, meta] of Object.entries(functionsMeta)) {
|
|
7
|
+
const parsed = parseVersionedId(id);
|
|
8
|
+
const baseName = parsed.version !== null ? parsed.baseName : id;
|
|
9
|
+
let group = groups.get(baseName);
|
|
10
|
+
if (!group) {
|
|
11
|
+
group = { explicit: [], unversioned: null };
|
|
12
|
+
groups.set(baseName, group);
|
|
13
|
+
}
|
|
14
|
+
if (parsed.version !== null) {
|
|
15
|
+
group.explicit.push({ id, version: parsed.version });
|
|
16
|
+
}
|
|
17
|
+
else if (meta.version !== undefined) {
|
|
18
|
+
group.explicit.push({ id, version: meta.version });
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
group.unversioned = id;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
for (const [baseName, group] of groups) {
|
|
25
|
+
if (group.explicit.length === 0) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
const seen = new Map();
|
|
29
|
+
for (const entry of group.explicit) {
|
|
30
|
+
const existing = seen.get(entry.version);
|
|
31
|
+
if (existing) {
|
|
32
|
+
logger.critical(ErrorCode.DUPLICATE_FUNCTION_VERSION, `Duplicate version ${entry.version} for function '${baseName}': '${existing}' and '${entry.id}'.`);
|
|
33
|
+
}
|
|
34
|
+
seen.set(entry.version, entry.id);
|
|
35
|
+
}
|
|
36
|
+
const maxVersion = Math.max(...group.explicit.map((e) => e.version));
|
|
37
|
+
if (group.unversioned) {
|
|
38
|
+
const implicitVersion = maxVersion + 1;
|
|
39
|
+
const oldId = group.unversioned;
|
|
40
|
+
const newId = formatVersionedId(baseName, implicitVersion);
|
|
41
|
+
const meta = functionsMeta[oldId];
|
|
42
|
+
meta.pikkuFuncId = newId;
|
|
43
|
+
meta.version = implicitVersion;
|
|
44
|
+
delete functionsMeta[oldId];
|
|
45
|
+
functionsMeta[newId] = meta;
|
|
46
|
+
const fileEntry = state.functions.files.get(oldId);
|
|
47
|
+
if (fileEntry) {
|
|
48
|
+
state.functions.files.delete(oldId);
|
|
49
|
+
state.functions.files.set(newId, fileEntry);
|
|
50
|
+
}
|
|
51
|
+
const rpcFileEntry = state.rpc.internalFiles.get(oldId);
|
|
52
|
+
if (rpcFileEntry) {
|
|
53
|
+
state.rpc.internalFiles.delete(oldId);
|
|
54
|
+
state.rpc.internalFiles.set(newId, rpcFileEntry);
|
|
55
|
+
}
|
|
56
|
+
if (state.rpc.invokedFunctions.has(oldId)) {
|
|
57
|
+
state.rpc.invokedFunctions.delete(oldId);
|
|
58
|
+
state.rpc.invokedFunctions.add(newId);
|
|
59
|
+
}
|
|
60
|
+
if (state.serviceAggregation.usedFunctions.has(oldId)) {
|
|
61
|
+
state.serviceAggregation.usedFunctions.delete(oldId);
|
|
62
|
+
state.serviceAggregation.usedFunctions.add(newId);
|
|
63
|
+
}
|
|
64
|
+
state.rpc.internalMeta[baseName] = newId;
|
|
65
|
+
state.rpc.internalMeta[newId] = newId;
|
|
66
|
+
if (state.rpc.exposedMeta[baseName] === oldId) {
|
|
67
|
+
state.rpc.exposedMeta[baseName] = newId;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
const latest = group.explicit.reduce((a, b) => a.version > b.version ? a : b);
|
|
72
|
+
state.rpc.internalMeta[baseName] = latest.id;
|
|
73
|
+
}
|
|
74
|
+
for (const entry of group.explicit) {
|
|
75
|
+
state.rpc.invokedFunctions.add(entry.id);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { JSONValue } from '@pikku/core';
|
|
2
|
+
import type { InspectorLogger, InspectorState } from '../types.js';
|
|
3
|
+
export declare function generateAllSchemas(logger: InspectorLogger, config: {
|
|
4
|
+
tsconfig: string;
|
|
5
|
+
schemasFromTypes?: string[];
|
|
6
|
+
schema?: {
|
|
7
|
+
additionalProperties?: boolean;
|
|
8
|
+
};
|
|
9
|
+
}, state: InspectorState): Promise<Record<string, JSONValue>>;
|