@pikku/inspector 0.11.1 → 0.12.0
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 +26 -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 +69 -61
- package/dist/add/add-cli.js +36 -18
- package/dist/add/add-file-with-factory.js +2 -0
- package/dist/add/add-functions.js +327 -59
- package/dist/add/add-http-route.d.ts +19 -10
- package/dist/add/add-http-route.js +153 -44
- package/dist/add/add-http-routes.d.ts +5 -0
- package/dist/add/add-http-routes.js +159 -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.js +14 -9
- 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.js +18 -12
- package/dist/add/add-rpc-invocations.d.ts +3 -0
- package/dist/add/add-rpc-invocations.js +65 -25
- 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-workflow-graph.d.ts +7 -0
- package/dist/add/add-workflow-graph.js +396 -0
- package/dist/add/add-workflow.js +124 -26
- package/dist/error-codes.d.ts +16 -1
- package/dist/error-codes.js +21 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.js +5 -2
- package/dist/inspector.d.ts +1 -1
- package/dist/inspector.js +106 -13
- 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 -30
- package/dist/utils/compute-required-schemas.d.ts +4 -0
- package/dist/utils/compute-required-schemas.js +41 -0
- package/dist/utils/contract-hashes.d.ts +35 -0
- package/dist/utils/contract-hashes.js +202 -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/ensure-function-metadata.d.ts +5 -2
- 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 +93 -298
- package/dist/utils/extract-services.d.ts +2 -1
- package/dist/utils/extract-services.js +25 -1
- package/dist/utils/filter-inspector-state.js +107 -23
- package/dist/utils/get-property-value.d.ts +8 -2
- package/dist/utils/get-property-value.js +33 -4
- package/dist/utils/hash.d.ts +2 -0
- package/dist/utils/hash.js +23 -0
- package/dist/utils/middleware.d.ts +7 -30
- package/dist/utils/middleware.js +80 -66
- package/dist/utils/permissions.d.ts +2 -2
- package/dist/utils/permissions.js +10 -10
- package/dist/utils/post-process.d.ts +9 -10
- package/dist/utils/post-process.js +231 -24
- package/dist/utils/resolve-external-package.d.ts +12 -0
- package/dist/utils/resolve-external-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 +73 -13
- package/dist/utils/serialize-inspector-state.js +102 -6
- 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/workflow/dsl/deserialize-dsl-workflow.d.ts +24 -0
- package/dist/utils/workflow/dsl/deserialize-dsl-workflow.js +830 -0
- package/dist/{workflow/extract-simple-workflow.d.ts → utils/workflow/dsl/extract-dsl-workflow.d.ts} +4 -2
- package/dist/{workflow/extract-simple-workflow.js → utils/workflow/dsl/extract-dsl-workflow.js} +572 -72
- package/dist/utils/workflow/dsl/index.d.ts +7 -0
- package/dist/utils/workflow/dsl/index.js +7 -0
- package/dist/{workflow → utils/workflow/dsl}/patterns.d.ts +21 -0
- package/dist/{workflow → utils/workflow/dsl}/patterns.js +90 -10
- package/dist/{workflow → utils/workflow/dsl}/validation.d.ts +2 -0
- package/dist/{workflow → utils/workflow/dsl}/validation.js +25 -7
- package/dist/utils/workflow/graph/convert-dsl-to-graph.d.ts +13 -0
- package/dist/utils/workflow/graph/convert-dsl-to-graph.js +318 -0
- 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 +8 -0
- package/dist/utils/workflow/graph/index.js +8 -0
- package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +35 -0
- package/dist/utils/workflow/graph/serialize-workflow-graph.js +150 -0
- package/dist/utils/workflow/graph/workflow-graph.types.d.ts +203 -0
- package/dist/utils/workflow/graph/workflow-graph.types.js +38 -0
- package/dist/visit.js +13 -2
- package/package.json +26 -4
- package/src/add/add-ai-agent.ts +468 -0
- package/src/add/add-channel.ts +82 -79
- package/src/add/add-cli.ts +49 -20
- package/src/add/add-file-with-factory.ts +2 -0
- package/src/add/add-functions.ts +429 -71
- package/src/add/add-http-route.ts +246 -65
- package/src/add/add-http-routes.ts +228 -0
- package/src/add/add-keyed-wiring.ts +151 -0
- package/src/add/add-mcp-prompt.ts +26 -15
- package/src/add/add-mcp-resource.ts +27 -15
- package/src/add/add-middleware.ts +482 -80
- package/src/add/add-permission.ts +199 -40
- package/src/add/add-queue-worker.ts +24 -19
- package/src/add/add-rpc-invocations.ts +78 -31
- package/src/add/add-schedule.ts +16 -11
- 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-workflow-graph.ts +522 -0
- package/src/add/add-workflow.ts +117 -30
- package/src/error-codes.ts +26 -1
- package/src/index.ts +27 -8
- package/src/inspector.ts +145 -17
- package/src/schema-generator.ts +1 -0
- package/src/types-map.ts +12 -1
- package/src/types.ts +192 -51
- package/src/utils/compute-required-schemas.ts +49 -0
- package/src/utils/contract-hashes.test.ts +528 -0
- package/src/utils/contract-hashes.ts +290 -0
- package/src/utils/custom-types-generator.ts +88 -0
- package/src/utils/detect-schema-vendor.ts +90 -0
- package/src/utils/ensure-function-metadata.ts +324 -7
- package/src/utils/extract-function-name.ts +108 -358
- package/src/utils/extract-services.ts +35 -2
- package/src/utils/filter-inspector-state.test.ts +34 -20
- package/src/utils/filter-inspector-state.ts +140 -31
- package/src/utils/get-property-value.ts +50 -5
- package/src/utils/hash.ts +26 -0
- package/src/utils/middleware.test.ts +204 -0
- package/src/utils/middleware.ts +129 -67
- package/src/utils/permissions.test.ts +35 -12
- package/src/utils/permissions.ts +10 -10
- package/src/utils/post-process.ts +283 -43
- package/src/utils/resolve-external-package.ts +42 -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 +181 -20
- 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/workflow/dsl/deserialize-dsl-workflow.ts +1104 -0
- package/src/{workflow/extract-simple-workflow.ts → utils/workflow/dsl/extract-dsl-workflow.ts} +678 -85
- package/src/utils/workflow/dsl/index.ts +11 -0
- package/src/{workflow → utils/workflow/dsl}/patterns.ts +108 -11
- package/src/{workflow → utils/workflow/dsl}/validation.ts +34 -7
- package/src/utils/workflow/graph/convert-dsl-to-graph.ts +422 -0
- 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 +11 -0
- package/src/utils/workflow/graph/serialize-workflow-graph.ts +216 -0
- package/src/utils/workflow/graph/workflow-graph.types.ts +231 -0
- package/src/visit.ts +14 -2
- package/tsconfig.tsbuildinfo +1 -1
- 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-mcp-tool.ts +0 -141
- package/src/utils/extract-service-metadata.ts +0 -353
- package/src/utils/write-service-metadata.ts +0 -51
package/dist/types.d.ts
CHANGED
|
@@ -2,13 +2,21 @@ import * as ts from 'typescript';
|
|
|
2
2
|
import { ChannelsMeta } from '@pikku/core/channel';
|
|
3
3
|
import { HTTPWiringsMeta } from '@pikku/core/http';
|
|
4
4
|
import { ScheduledTasksMeta } from '@pikku/core/scheduler';
|
|
5
|
+
import { TriggerMeta, TriggerSourceMeta } from '@pikku/core/trigger';
|
|
5
6
|
import { QueueWorkersMeta } from '@pikku/core/queue';
|
|
6
7
|
import { WorkflowsMeta } from '@pikku/core/workflow';
|
|
7
8
|
import { MCPResourceMeta, MCPToolMeta, MCPPromptMeta } from '@pikku/core/mcp';
|
|
9
|
+
import { AIAgentMeta } from '@pikku/core/ai-agent';
|
|
8
10
|
import { CLIMeta } from '@pikku/core/cli';
|
|
11
|
+
import { NodesMeta } from '@pikku/core/node';
|
|
12
|
+
import { SecretDefinitions } from '@pikku/core/secret';
|
|
13
|
+
import { VariableDefinitions } from '@pikku/core/variable';
|
|
9
14
|
import { TypesMap } from './types-map.js';
|
|
10
|
-
import { FunctionsMeta, FunctionServicesMeta } from '@pikku/core';
|
|
15
|
+
import { FunctionsMeta, FunctionServicesMeta, FunctionWiresMeta, JSONValue } from '@pikku/core';
|
|
16
|
+
import type { OpenAPISpecInfo } from './utils/serialize-openapi-json.js';
|
|
11
17
|
import { ErrorCode } from './error-codes.js';
|
|
18
|
+
import type { VersionManifest, VersionValidateError } from './utils/contract-hashes.js';
|
|
19
|
+
import type { SerializedWorkflowGraphs } from './utils/workflow/graph/workflow-graph.types.js';
|
|
12
20
|
export type PathToNameAndType = Map<string, {
|
|
13
21
|
variable: string;
|
|
14
22
|
type: string | null;
|
|
@@ -24,7 +32,8 @@ export interface MiddlewareGroupMeta {
|
|
|
24
32
|
sourceFile: string;
|
|
25
33
|
position: number;
|
|
26
34
|
services: FunctionServicesMeta;
|
|
27
|
-
|
|
35
|
+
count: number;
|
|
36
|
+
instanceIds: string[];
|
|
28
37
|
isFactory: boolean;
|
|
29
38
|
}
|
|
30
39
|
export interface PermissionGroupMeta {
|
|
@@ -32,7 +41,8 @@ export interface PermissionGroupMeta {
|
|
|
32
41
|
sourceFile: string;
|
|
33
42
|
position: number;
|
|
34
43
|
services: FunctionServicesMeta;
|
|
35
|
-
|
|
44
|
+
count: number;
|
|
45
|
+
instanceIds: string[];
|
|
36
46
|
isFactory: boolean;
|
|
37
47
|
}
|
|
38
48
|
export interface InspectorHTTPState {
|
|
@@ -42,6 +52,19 @@ export interface InspectorHTTPState {
|
|
|
42
52
|
routeMiddleware: Map<string, MiddlewareGroupMeta>;
|
|
43
53
|
routePermissions: Map<string, PermissionGroupMeta>;
|
|
44
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Schema vendor types for Standard Schema compliant validators
|
|
57
|
+
*/
|
|
58
|
+
export type SchemaVendor = 'zod' | 'valibot' | 'arktype' | 'effect' | 'unknown';
|
|
59
|
+
/**
|
|
60
|
+
* Schema reference for deferred conversion to JSON Schema at build time.
|
|
61
|
+
* Supports Standard Schema compliant validators (Zod, Valibot, ArkType, Effect Schema).
|
|
62
|
+
*/
|
|
63
|
+
export interface SchemaRef {
|
|
64
|
+
variableName: string;
|
|
65
|
+
sourceFile: string;
|
|
66
|
+
vendor?: SchemaVendor;
|
|
67
|
+
}
|
|
45
68
|
export interface InspectorFunctionState {
|
|
46
69
|
typesMap: TypesMap;
|
|
47
70
|
meta: FunctionsMeta;
|
|
@@ -54,28 +77,57 @@ export interface InspectorChannelState {
|
|
|
54
77
|
meta: ChannelsMeta;
|
|
55
78
|
files: Set<string>;
|
|
56
79
|
}
|
|
80
|
+
export interface InspectorMiddlewareDefinition {
|
|
81
|
+
services: FunctionServicesMeta;
|
|
82
|
+
wires?: FunctionWiresMeta;
|
|
83
|
+
sourceFile: string;
|
|
84
|
+
position: number;
|
|
85
|
+
exportedName: string | null;
|
|
86
|
+
factory?: boolean;
|
|
87
|
+
name?: string;
|
|
88
|
+
description?: string;
|
|
89
|
+
package?: string;
|
|
90
|
+
}
|
|
91
|
+
export interface InspectorMiddlewareInstance {
|
|
92
|
+
definitionId: string;
|
|
93
|
+
sourceFile: string;
|
|
94
|
+
position: number;
|
|
95
|
+
isFactoryCall: boolean;
|
|
96
|
+
}
|
|
57
97
|
export interface InspectorMiddlewareState {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
sourceFile: string;
|
|
61
|
-
position: number;
|
|
62
|
-
exportedName: string | null;
|
|
63
|
-
factory?: boolean;
|
|
64
|
-
name?: string;
|
|
65
|
-
description?: string;
|
|
66
|
-
}>;
|
|
98
|
+
definitions: Record<string, InspectorMiddlewareDefinition>;
|
|
99
|
+
instances: Record<string, InspectorMiddlewareInstance>;
|
|
67
100
|
tagMiddleware: Map<string, MiddlewareGroupMeta>;
|
|
68
101
|
}
|
|
102
|
+
export interface InspectorChannelMiddlewareState {
|
|
103
|
+
definitions: Record<string, InspectorMiddlewareDefinition>;
|
|
104
|
+
instances: Record<string, InspectorMiddlewareInstance>;
|
|
105
|
+
tagMiddleware: Map<string, MiddlewareGroupMeta>;
|
|
106
|
+
}
|
|
107
|
+
export interface InspectorAIMiddlewareState {
|
|
108
|
+
definitions: Record<string, InspectorMiddlewareDefinition>;
|
|
109
|
+
}
|
|
110
|
+
export interface InspectorPermissionDefinition {
|
|
111
|
+
services: FunctionServicesMeta;
|
|
112
|
+
wires?: FunctionWiresMeta;
|
|
113
|
+
sourceFile: string;
|
|
114
|
+
position: number;
|
|
115
|
+
exportedName: string | null;
|
|
116
|
+
factory?: boolean;
|
|
117
|
+
name?: string;
|
|
118
|
+
description?: string;
|
|
119
|
+
package?: string;
|
|
120
|
+
requiresData?: boolean;
|
|
121
|
+
}
|
|
122
|
+
export interface InspectorPermissionInstance {
|
|
123
|
+
definitionId: string;
|
|
124
|
+
sourceFile: string;
|
|
125
|
+
position: number;
|
|
126
|
+
isFactoryCall: boolean;
|
|
127
|
+
}
|
|
69
128
|
export interface InspectorPermissionState {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
sourceFile: string;
|
|
73
|
-
position: number;
|
|
74
|
-
exportedName: string | null;
|
|
75
|
-
factory?: boolean;
|
|
76
|
-
name?: string;
|
|
77
|
-
description?: string;
|
|
78
|
-
}>;
|
|
129
|
+
definitions: Record<string, InspectorPermissionDefinition>;
|
|
130
|
+
instances: Record<string, InspectorPermissionInstance>;
|
|
79
131
|
tagPermissions: Map<string, PermissionGroupMeta>;
|
|
80
132
|
}
|
|
81
133
|
export type InspectorFilters = {
|
|
@@ -86,14 +138,53 @@ export type InspectorFilters = {
|
|
|
86
138
|
httpRoutes?: string[];
|
|
87
139
|
httpMethods?: string[];
|
|
88
140
|
};
|
|
141
|
+
export type ExternalPackageConfig = {
|
|
142
|
+
package: string;
|
|
143
|
+
rpcEndpoint?: string;
|
|
144
|
+
secretOverrides?: Record<string, string>;
|
|
145
|
+
forceInclude?: boolean;
|
|
146
|
+
};
|
|
147
|
+
export type ModelConfigEntry = string | {
|
|
148
|
+
model: string;
|
|
149
|
+
temperature?: number;
|
|
150
|
+
maxSteps?: number;
|
|
151
|
+
};
|
|
152
|
+
export type InspectorModelConfig = {
|
|
153
|
+
models?: Record<string, ModelConfigEntry>;
|
|
154
|
+
agentDefaults?: {
|
|
155
|
+
temperature?: number;
|
|
156
|
+
maxSteps?: number;
|
|
157
|
+
};
|
|
158
|
+
agentOverrides?: Record<string, {
|
|
159
|
+
model?: string;
|
|
160
|
+
temperature?: number;
|
|
161
|
+
maxSteps?: number;
|
|
162
|
+
}>;
|
|
163
|
+
};
|
|
89
164
|
export type InspectorOptions = Partial<{
|
|
90
165
|
setupOnly: boolean;
|
|
166
|
+
rootDir: string;
|
|
167
|
+
isExternalPackage: boolean;
|
|
91
168
|
types: Partial<{
|
|
92
169
|
configFileType: string;
|
|
93
170
|
userSessionType: string;
|
|
94
171
|
singletonServicesFactoryType: string;
|
|
95
172
|
wireServicesFactoryType: string;
|
|
96
173
|
}>;
|
|
174
|
+
externalPackages: Record<string, ExternalPackageConfig>;
|
|
175
|
+
schemaConfig: {
|
|
176
|
+
tsconfig: string;
|
|
177
|
+
schemasFromTypes?: string[];
|
|
178
|
+
schema?: {
|
|
179
|
+
additionalProperties?: boolean;
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
openAPI: {
|
|
183
|
+
additionalInfo: OpenAPISpecInfo;
|
|
184
|
+
};
|
|
185
|
+
tags: string[];
|
|
186
|
+
manifest: VersionManifest;
|
|
187
|
+
modelConfig: InspectorModelConfig;
|
|
97
188
|
}>;
|
|
98
189
|
export interface InspectorLogger {
|
|
99
190
|
info: (message: string) => void;
|
|
@@ -148,6 +239,12 @@ export interface InspectorFilesAndMethods {
|
|
|
148
239
|
typePath: string;
|
|
149
240
|
};
|
|
150
241
|
}
|
|
242
|
+
export interface InspectorDiagnostic {
|
|
243
|
+
code: string;
|
|
244
|
+
message: string;
|
|
245
|
+
sourceFile: string;
|
|
246
|
+
position: number;
|
|
247
|
+
}
|
|
151
248
|
export interface InspectorState {
|
|
152
249
|
rootDir: string;
|
|
153
250
|
singletonServicesTypeImportMap: PathToNameAndType;
|
|
@@ -161,9 +258,16 @@ export interface InspectorState {
|
|
|
161
258
|
filesAndMethods: InspectorFilesAndMethods;
|
|
162
259
|
filesAndMethodsErrors: Map<string, PathToNameAndType>;
|
|
163
260
|
typesLookup: Map<string, ts.Type[]>;
|
|
261
|
+
schemaLookup: Map<string, SchemaRef>;
|
|
262
|
+
schemas: Record<string, JSONValue>;
|
|
164
263
|
http: InspectorHTTPState;
|
|
165
264
|
functions: InspectorFunctionState;
|
|
166
265
|
channels: InspectorChannelState;
|
|
266
|
+
triggers: {
|
|
267
|
+
meta: TriggerMeta;
|
|
268
|
+
sourceMeta: TriggerSourceMeta;
|
|
269
|
+
files: Set<string>;
|
|
270
|
+
};
|
|
167
271
|
scheduledTasks: {
|
|
168
272
|
meta: ScheduledTasksMeta;
|
|
169
273
|
files: Set<string>;
|
|
@@ -178,6 +282,12 @@ export interface InspectorState {
|
|
|
178
282
|
path: string;
|
|
179
283
|
exportedName: string;
|
|
180
284
|
}>;
|
|
285
|
+
graphMeta: SerializedWorkflowGraphs;
|
|
286
|
+
graphFiles: Map<string, {
|
|
287
|
+
path: string;
|
|
288
|
+
exportedName: string;
|
|
289
|
+
}>;
|
|
290
|
+
invokedWorkflows: Set<string>;
|
|
181
291
|
};
|
|
182
292
|
rpc: {
|
|
183
293
|
internalMeta: Record<string, string>;
|
|
@@ -191,6 +301,7 @@ export interface InspectorState {
|
|
|
191
301
|
exportedName: string;
|
|
192
302
|
}>;
|
|
193
303
|
invokedFunctions: Set<string>;
|
|
304
|
+
usedExternalPackages: Set<string>;
|
|
194
305
|
};
|
|
195
306
|
mcpEndpoints: {
|
|
196
307
|
resourcesMeta: MCPResourceMeta;
|
|
@@ -198,11 +309,37 @@ export interface InspectorState {
|
|
|
198
309
|
promptsMeta: MCPPromptMeta;
|
|
199
310
|
files: Set<string>;
|
|
200
311
|
};
|
|
312
|
+
agents: {
|
|
313
|
+
agentsMeta: AIAgentMeta;
|
|
314
|
+
files: Map<string, {
|
|
315
|
+
path: string;
|
|
316
|
+
exportedName: string;
|
|
317
|
+
}>;
|
|
318
|
+
};
|
|
201
319
|
cli: {
|
|
202
320
|
meta: CLIMeta;
|
|
203
321
|
files: Set<string>;
|
|
204
322
|
};
|
|
323
|
+
nodes: {
|
|
324
|
+
meta: NodesMeta;
|
|
325
|
+
files: Set<string>;
|
|
326
|
+
};
|
|
327
|
+
secrets: {
|
|
328
|
+
definitions: SecretDefinitions;
|
|
329
|
+
files: Set<string>;
|
|
330
|
+
};
|
|
331
|
+
variables: {
|
|
332
|
+
definitions: VariableDefinitions;
|
|
333
|
+
files: Set<string>;
|
|
334
|
+
};
|
|
335
|
+
manifest: {
|
|
336
|
+
initial: VersionManifest | null;
|
|
337
|
+
current: VersionManifest | null;
|
|
338
|
+
errors: VersionValidateError[];
|
|
339
|
+
};
|
|
205
340
|
middleware: InspectorMiddlewareState;
|
|
341
|
+
channelMiddleware: InspectorChannelMiddlewareState;
|
|
342
|
+
aiMiddleware: InspectorAIMiddlewareState;
|
|
206
343
|
permissions: InspectorPermissionState;
|
|
207
344
|
serviceAggregation: {
|
|
208
345
|
requiredServices: Set<string>;
|
|
@@ -212,14 +349,27 @@ export interface InspectorState {
|
|
|
212
349
|
allSingletonServices: string[];
|
|
213
350
|
allWireServices: string[];
|
|
214
351
|
};
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
description: string;
|
|
219
|
-
package: string;
|
|
220
|
-
path: string;
|
|
221
|
-
version: string;
|
|
222
|
-
interface: string;
|
|
223
|
-
expandedProperties: Record<string, string>;
|
|
352
|
+
resolvedIOTypes: Record<string, {
|
|
353
|
+
inputType: string;
|
|
354
|
+
outputType: string;
|
|
224
355
|
}>;
|
|
356
|
+
middlewareGroupsMeta: {
|
|
357
|
+
definitions: Record<string, InspectorMiddlewareDefinition>;
|
|
358
|
+
instances: Record<string, InspectorMiddlewareInstance>;
|
|
359
|
+
httpGroups: Record<string, MiddlewareGroupMeta>;
|
|
360
|
+
tagGroups: Record<string, MiddlewareGroupMeta>;
|
|
361
|
+
channelMiddleware: {
|
|
362
|
+
definitions: Record<string, InspectorMiddlewareDefinition>;
|
|
363
|
+
instances: Record<string, InspectorMiddlewareInstance>;
|
|
364
|
+
tagGroups: Record<string, MiddlewareGroupMeta>;
|
|
365
|
+
};
|
|
366
|
+
};
|
|
367
|
+
permissionsGroupsMeta: {
|
|
368
|
+
definitions: Record<string, InspectorPermissionDefinition>;
|
|
369
|
+
httpGroups: Record<string, PermissionGroupMeta>;
|
|
370
|
+
tagGroups: Record<string, PermissionGroupMeta>;
|
|
371
|
+
};
|
|
372
|
+
requiredSchemas: Set<string>;
|
|
373
|
+
openAPISpec: Record<string, any> | null;
|
|
374
|
+
diagnostics: InspectorDiagnostic[];
|
|
225
375
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FunctionsMeta } from '@pikku/core';
|
|
2
|
+
import type { TypesMap } from '../types-map.js';
|
|
3
|
+
import type { SchemaRef } from '../types.js';
|
|
4
|
+
export declare function computeRequiredSchemas(functionsMeta: FunctionsMeta, typesMap: TypesMap, additionalTypes?: string[], schemaLookup?: Map<string, SchemaRef>): Set<string>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const PRIMITIVE_TYPES = new Set([
|
|
2
|
+
'boolean',
|
|
3
|
+
'string',
|
|
4
|
+
'number',
|
|
5
|
+
'null',
|
|
6
|
+
'undefined',
|
|
7
|
+
'void',
|
|
8
|
+
'any',
|
|
9
|
+
'unknown',
|
|
10
|
+
'never',
|
|
11
|
+
]);
|
|
12
|
+
export function computeRequiredSchemas(functionsMeta, typesMap, additionalTypes, schemaLookup) {
|
|
13
|
+
return new Set([
|
|
14
|
+
...Object.values(functionsMeta)
|
|
15
|
+
.map(({ inputs, outputs }) => {
|
|
16
|
+
const types = [];
|
|
17
|
+
if (inputs?.[0]) {
|
|
18
|
+
try {
|
|
19
|
+
types.push(typesMap.getUniqueName(inputs[0]));
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
types.push(inputs[0]);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (outputs?.[0]) {
|
|
26
|
+
try {
|
|
27
|
+
types.push(typesMap.getUniqueName(outputs[0]));
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
types.push(outputs[0]);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return types;
|
|
34
|
+
})
|
|
35
|
+
.flat()
|
|
36
|
+
.filter((s) => !!s && !PRIMITIVE_TYPES.has(s)),
|
|
37
|
+
...typesMap.customTypes.keys(),
|
|
38
|
+
...(additionalTypes || []),
|
|
39
|
+
...(schemaLookup ? Array.from(schemaLookup.keys()) : []),
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { FunctionsMeta, JSONValue } from '@pikku/core';
|
|
2
|
+
import { TypesMap } from '../types-map.js';
|
|
3
|
+
import { ErrorCode } from '../error-codes.js';
|
|
4
|
+
export type ContractEntry = {
|
|
5
|
+
functionKey: string;
|
|
6
|
+
version: number;
|
|
7
|
+
contractHash: string;
|
|
8
|
+
};
|
|
9
|
+
export type VersionValidateError = {
|
|
10
|
+
code: ErrorCode;
|
|
11
|
+
message: string;
|
|
12
|
+
};
|
|
13
|
+
export type VersionManifestEntry = {
|
|
14
|
+
latest: number;
|
|
15
|
+
versions: Record<string, string>;
|
|
16
|
+
};
|
|
17
|
+
export type VersionManifest = {
|
|
18
|
+
manifestVersion: 1;
|
|
19
|
+
contracts: Record<string, VersionManifestEntry>;
|
|
20
|
+
};
|
|
21
|
+
export declare function createEmptyManifest(): VersionManifest;
|
|
22
|
+
export declare function serializeManifest(manifest: VersionManifest): string;
|
|
23
|
+
export declare function computeContractHash(data: {
|
|
24
|
+
functionKey: string;
|
|
25
|
+
inputSchema: unknown;
|
|
26
|
+
outputSchema: unknown;
|
|
27
|
+
}): string;
|
|
28
|
+
export declare function buildCurrentContracts(functionsMeta: FunctionsMeta, allSchemas: Record<string, JSONValue>, typesMap: TypesMap): Map<string, ContractEntry>;
|
|
29
|
+
export declare function computeContractHashes(allSchemas: Record<string, JSONValue>, typesMap: TypesMap, functionsMeta: FunctionsMeta): Map<string, ContractEntry>;
|
|
30
|
+
export declare function validateContracts(manifest: VersionManifest, currentContracts: Map<string, ContractEntry>): {
|
|
31
|
+
valid: boolean;
|
|
32
|
+
errors: VersionValidateError[];
|
|
33
|
+
};
|
|
34
|
+
export declare function updateManifest(existing: VersionManifest, currentContracts: Map<string, ContractEntry>): VersionManifest;
|
|
35
|
+
export declare function extractContractsFromMeta(functionsMeta: FunctionsMeta): Map<string, ContractEntry>;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { parseVersionedId } from '@pikku/core';
|
|
2
|
+
import { ErrorCode } from '../error-codes.js';
|
|
3
|
+
import { canonicalJSON, hashString } from './hash.js';
|
|
4
|
+
export function createEmptyManifest() {
|
|
5
|
+
return {
|
|
6
|
+
manifestVersion: 1,
|
|
7
|
+
contracts: {},
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export function serializeManifest(manifest) {
|
|
11
|
+
const sortedContracts = {};
|
|
12
|
+
for (const key of Object.keys(manifest.contracts).sort()) {
|
|
13
|
+
const entry = manifest.contracts[key];
|
|
14
|
+
const sortedVersions = {};
|
|
15
|
+
const numericKeys = Object.keys(entry.versions)
|
|
16
|
+
.map(Number)
|
|
17
|
+
.sort((a, b) => a - b);
|
|
18
|
+
for (const vk of numericKeys) {
|
|
19
|
+
sortedVersions[String(vk)] = entry.versions[String(vk)];
|
|
20
|
+
}
|
|
21
|
+
sortedContracts[key] = {
|
|
22
|
+
latest: entry.latest,
|
|
23
|
+
versions: sortedVersions,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const sorted = {
|
|
27
|
+
manifestVersion: manifest.manifestVersion,
|
|
28
|
+
contracts: sortedContracts,
|
|
29
|
+
};
|
|
30
|
+
return JSON.stringify(sorted, null, 2) + '\n';
|
|
31
|
+
}
|
|
32
|
+
export function computeContractHash(data) {
|
|
33
|
+
return hashString(canonicalJSON(data), 16);
|
|
34
|
+
}
|
|
35
|
+
function resolveSchema(typeNames, allSchemas, typesMap) {
|
|
36
|
+
if (!typeNames) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const filtered = typeNames.filter((n) => n !== 'void');
|
|
40
|
+
if (filtered.length === 0) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const parts = [];
|
|
44
|
+
for (const name of filtered) {
|
|
45
|
+
let key;
|
|
46
|
+
try {
|
|
47
|
+
key = typesMap.getUniqueName(name);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
key = name;
|
|
51
|
+
}
|
|
52
|
+
const schema = allSchemas[key];
|
|
53
|
+
if (schema) {
|
|
54
|
+
parts.push(schema);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (parts.length === 0) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return parts.length === 1 ? parts[0] : parts;
|
|
61
|
+
}
|
|
62
|
+
export function buildCurrentContracts(functionsMeta, allSchemas, typesMap) {
|
|
63
|
+
const result = new Map();
|
|
64
|
+
for (const [funcId, meta] of Object.entries(functionsMeta)) {
|
|
65
|
+
if (meta.remote === true) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const parsed = parseVersionedId(funcId);
|
|
69
|
+
const functionKey = parsed.baseName;
|
|
70
|
+
const version = parsed.version ?? meta.version ?? 1;
|
|
71
|
+
const inputSchema = resolveSchema(meta.inputs, allSchemas, typesMap);
|
|
72
|
+
const outputSchema = resolveSchema(meta.outputs, allSchemas, typesMap);
|
|
73
|
+
const contractHash = computeContractHash({
|
|
74
|
+
functionKey,
|
|
75
|
+
inputSchema,
|
|
76
|
+
outputSchema,
|
|
77
|
+
});
|
|
78
|
+
result.set(funcId, { functionKey, version, contractHash });
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
export function computeContractHashes(allSchemas, typesMap, functionsMeta) {
|
|
83
|
+
const contracts = buildCurrentContracts(functionsMeta, allSchemas, typesMap);
|
|
84
|
+
for (const [funcId, entry] of contracts) {
|
|
85
|
+
const meta = functionsMeta[funcId];
|
|
86
|
+
if (meta) {
|
|
87
|
+
meta.contractHash = entry.contractHash;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return contracts;
|
|
91
|
+
}
|
|
92
|
+
function groupByFunctionKey(contracts) {
|
|
93
|
+
const grouped = new Map();
|
|
94
|
+
for (const entry of contracts.values()) {
|
|
95
|
+
const existing = grouped.get(entry.functionKey) ?? [];
|
|
96
|
+
existing.push(entry);
|
|
97
|
+
grouped.set(entry.functionKey, existing);
|
|
98
|
+
}
|
|
99
|
+
return grouped;
|
|
100
|
+
}
|
|
101
|
+
export function validateContracts(manifest, currentContracts) {
|
|
102
|
+
const errors = [];
|
|
103
|
+
const grouped = groupByFunctionKey(currentContracts);
|
|
104
|
+
const reportedKeys = new Set();
|
|
105
|
+
for (const [functionKey, entries] of grouped) {
|
|
106
|
+
const manifestEntry = manifest.contracts[functionKey];
|
|
107
|
+
if (!manifestEntry) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
for (const { version, contractHash } of entries) {
|
|
111
|
+
const existingHash = manifestEntry.versions[String(version)];
|
|
112
|
+
if (existingHash !== undefined) {
|
|
113
|
+
if (existingHash !== contractHash) {
|
|
114
|
+
reportedKeys.add(`${functionKey}@${version}`);
|
|
115
|
+
errors.push({
|
|
116
|
+
code: ErrorCode.FUNCTION_VERSION_MODIFIED,
|
|
117
|
+
message: `Contract for ${functionKey}@v${version} has changed (recorded: ${existingHash}, current: ${contractHash}). Existing versions are immutable.`,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
if (version <= manifestEntry.latest) {
|
|
123
|
+
errors.push({
|
|
124
|
+
code: ErrorCode.VERSION_REGRESSION_OR_CONFLICT,
|
|
125
|
+
message: `Version ${version} for ${functionKey} is <= latest (${manifestEntry.latest}) but not recorded. Possible merge conflict.`,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
else if (version > manifestEntry.latest + 1) {
|
|
129
|
+
errors.push({
|
|
130
|
+
code: ErrorCode.VERSION_GAP_NOT_ALLOWED,
|
|
131
|
+
message: `Version ${version} for ${functionKey} skips versions. Latest is ${manifestEntry.latest}, next must be ${manifestEntry.latest + 1}.`,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
for (const [functionKey, manifestEntry] of Object.entries(manifest.contracts)) {
|
|
138
|
+
const latestHash = manifestEntry.versions[String(manifestEntry.latest)];
|
|
139
|
+
const currentEntries = grouped.get(functionKey);
|
|
140
|
+
if (!currentEntries) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const currentLatest = currentEntries.find((e) => e.version === manifestEntry.latest);
|
|
144
|
+
if (currentLatest &&
|
|
145
|
+
currentLatest.contractHash !== latestHash &&
|
|
146
|
+
!reportedKeys.has(`${functionKey}@${manifestEntry.latest}`)) {
|
|
147
|
+
errors.push({
|
|
148
|
+
code: ErrorCode.CONTRACT_CHANGED_REQUIRES_BUMP,
|
|
149
|
+
message: `Contract for ${functionKey} changed. Set \`version: ${manifestEntry.latest + 1}\` on the function or run 'pikku versions update'.`,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
for (const [functionKey, manifestEntry] of Object.entries(manifest.contracts)) {
|
|
154
|
+
const numericKeys = Object.keys(manifestEntry.versions).map(Number);
|
|
155
|
+
if (numericKeys.length === 0) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const maxVersion = Math.max(...numericKeys);
|
|
159
|
+
if (manifestEntry.latest !== maxVersion) {
|
|
160
|
+
errors.push({
|
|
161
|
+
code: ErrorCode.MANIFEST_INTEGRITY_ERROR,
|
|
162
|
+
message: `Manifest integrity error for ${functionKey}: latest field (${manifestEntry.latest}) inconsistent with version keys (max: ${maxVersion}).`,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { valid: errors.length === 0, errors };
|
|
167
|
+
}
|
|
168
|
+
export function updateManifest(existing, currentContracts) {
|
|
169
|
+
const manifest = {
|
|
170
|
+
manifestVersion: existing.manifestVersion,
|
|
171
|
+
contracts: JSON.parse(JSON.stringify(existing.contracts)),
|
|
172
|
+
};
|
|
173
|
+
const grouped = groupByFunctionKey(currentContracts);
|
|
174
|
+
for (const [functionKey, entries] of grouped) {
|
|
175
|
+
if (!manifest.contracts[functionKey]) {
|
|
176
|
+
manifest.contracts[functionKey] = { latest: 0, versions: {} };
|
|
177
|
+
}
|
|
178
|
+
const entry = manifest.contracts[functionKey];
|
|
179
|
+
for (const { version, contractHash } of entries) {
|
|
180
|
+
entry.versions[String(version)] = contractHash;
|
|
181
|
+
entry.latest = Math.max(entry.latest, version);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return manifest;
|
|
185
|
+
}
|
|
186
|
+
export function extractContractsFromMeta(functionsMeta) {
|
|
187
|
+
const result = new Map();
|
|
188
|
+
for (const [funcId, meta] of Object.entries(functionsMeta)) {
|
|
189
|
+
if (meta.remote === true || !meta.contractHash) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
const parsed = parseVersionedId(funcId);
|
|
193
|
+
const functionKey = parsed.baseName;
|
|
194
|
+
const version = parsed.version ?? meta.version ?? 1;
|
|
195
|
+
result.set(funcId, {
|
|
196
|
+
functionKey,
|
|
197
|
+
version,
|
|
198
|
+
contractHash: meta.contractHash,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TypesMap } from '../types-map.js';
|
|
2
|
+
/**
|
|
3
|
+
* NOTE: Code generation normally belongs in @pikku/cli, not the inspector.
|
|
4
|
+
* This is here because the schema generator needs the custom types content
|
|
5
|
+
* as a virtual TypeScript source file (in-memory, no disk write) so that
|
|
6
|
+
* ts-json-schema-generator can discover inline/custom types from typesMap.
|
|
7
|
+
*/
|
|
8
|
+
export declare function sanitizeTypeName(name: string): string;
|
|
9
|
+
export declare function generateCustomTypes(typesMap: TypesMap, requiredTypes: Set<string>): string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NOTE: Code generation normally belongs in @pikku/cli, not the inspector.
|
|
3
|
+
* This is here because the schema generator needs the custom types content
|
|
4
|
+
* as a virtual TypeScript source file (in-memory, no disk write) so that
|
|
5
|
+
* ts-json-schema-generator can discover inline/custom types from typesMap.
|
|
6
|
+
*/
|
|
7
|
+
export function sanitizeTypeName(name) {
|
|
8
|
+
return name.replace(/[^a-zA-Z0-9_$]/g, '_');
|
|
9
|
+
}
|
|
10
|
+
export function generateCustomTypes(typesMap, requiredTypes) {
|
|
11
|
+
const typeDeclarations = Array.from(typesMap.customTypes.entries())
|
|
12
|
+
.filter(([_name, { type }]) => {
|
|
13
|
+
const hasUndefinedGeneric = /\b(Name|In|Out|Key)\b/.test(type) && /\[.*\]/.test(type);
|
|
14
|
+
return !hasUndefinedGeneric;
|
|
15
|
+
})
|
|
16
|
+
.map(([originalName, { type, references }]) => {
|
|
17
|
+
const name = sanitizeTypeName(originalName);
|
|
18
|
+
references.forEach((refName) => {
|
|
19
|
+
if (refName !== '__object' && !refName.startsWith('__object_')) {
|
|
20
|
+
requiredTypes.add(refName);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const typeString = type;
|
|
24
|
+
const typeNameRegex = /\b[A-Z][a-zA-Z0-9]*\b/g;
|
|
25
|
+
const potentialTypes = typeString.match(typeNameRegex) || [];
|
|
26
|
+
potentialTypes.forEach((typeName) => {
|
|
27
|
+
if (typeString.includes(`"${typeName}"`) ||
|
|
28
|
+
[
|
|
29
|
+
'Pick',
|
|
30
|
+
'Omit',
|
|
31
|
+
'Partial',
|
|
32
|
+
'Required',
|
|
33
|
+
'Record',
|
|
34
|
+
'Readonly',
|
|
35
|
+
].includes(typeName)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const typeMeta = typesMap.getTypeMeta(typeName);
|
|
40
|
+
if (typeMeta.path) {
|
|
41
|
+
requiredTypes.add(typeMeta.originalName);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Type not found in map (ambient/builtin type)
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
if (name === type)
|
|
49
|
+
return null;
|
|
50
|
+
return `export type ${name} = ${type}`;
|
|
51
|
+
});
|
|
52
|
+
const importsByPath = new Map();
|
|
53
|
+
for (const typeName of requiredTypes) {
|
|
54
|
+
try {
|
|
55
|
+
const typeMeta = typesMap.getTypeMeta(typeName);
|
|
56
|
+
if (typeMeta.path) {
|
|
57
|
+
if (!importsByPath.has(typeMeta.path)) {
|
|
58
|
+
importsByPath.set(typeMeta.path, new Set());
|
|
59
|
+
}
|
|
60
|
+
importsByPath.get(typeMeta.path).add(typeMeta.originalName);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Type not found in map
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const importLines = Array.from(importsByPath.entries())
|
|
68
|
+
.map(([path, types]) => `import type { ${Array.from(types).join(', ')} } from '${path}'`)
|
|
69
|
+
.join('\n');
|
|
70
|
+
return `${importLines}\n\n${typeDeclarations.filter(Boolean).join('\n')}`;
|
|
71
|
+
}
|