@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.
Files changed (189) hide show
  1. package/CHANGELOG.md +26 -1
  2. package/OPTIMIZATION-PLAN.md +195 -0
  3. package/dist/add/add-ai-agent.d.ts +2 -0
  4. package/dist/add/add-ai-agent.js +314 -0
  5. package/dist/add/add-channel.js +69 -61
  6. package/dist/add/add-cli.js +36 -18
  7. package/dist/add/add-file-with-factory.js +2 -0
  8. package/dist/add/add-functions.js +327 -59
  9. package/dist/add/add-http-route.d.ts +19 -10
  10. package/dist/add/add-http-route.js +153 -44
  11. package/dist/add/add-http-routes.d.ts +5 -0
  12. package/dist/add/add-http-routes.js +159 -0
  13. package/dist/add/add-keyed-wiring.d.ts +12 -0
  14. package/dist/add/add-keyed-wiring.js +97 -0
  15. package/dist/add/add-mcp-prompt.js +14 -9
  16. package/dist/add/add-mcp-resource.js +14 -9
  17. package/dist/add/add-middleware.d.ts +1 -4
  18. package/dist/add/add-middleware.js +364 -79
  19. package/dist/add/add-permission.d.ts +1 -1
  20. package/dist/add/add-permission.js +152 -40
  21. package/dist/add/add-queue-worker.js +18 -12
  22. package/dist/add/add-rpc-invocations.d.ts +3 -0
  23. package/dist/add/add-rpc-invocations.js +65 -25
  24. package/dist/add/add-schedule.js +11 -5
  25. package/dist/add/add-secret.d.ts +3 -0
  26. package/dist/add/add-secret.js +82 -0
  27. package/dist/add/add-trigger.d.ts +2 -0
  28. package/dist/add/add-trigger.js +87 -0
  29. package/dist/add/add-variable.d.ts +1 -0
  30. package/dist/add/add-variable.js +8 -0
  31. package/dist/add/add-workflow-graph.d.ts +7 -0
  32. package/dist/add/add-workflow-graph.js +396 -0
  33. package/dist/add/add-workflow.js +124 -26
  34. package/dist/error-codes.d.ts +16 -1
  35. package/dist/error-codes.js +21 -1
  36. package/dist/index.d.ts +9 -5
  37. package/dist/index.js +5 -2
  38. package/dist/inspector.d.ts +1 -1
  39. package/dist/inspector.js +106 -13
  40. package/dist/schema-generator.d.ts +1 -0
  41. package/dist/schema-generator.js +1 -0
  42. package/dist/types-map.js +10 -1
  43. package/dist/types.d.ts +180 -30
  44. package/dist/utils/compute-required-schemas.d.ts +4 -0
  45. package/dist/utils/compute-required-schemas.js +41 -0
  46. package/dist/utils/contract-hashes.d.ts +35 -0
  47. package/dist/utils/contract-hashes.js +202 -0
  48. package/dist/utils/custom-types-generator.d.ts +9 -0
  49. package/dist/utils/custom-types-generator.js +71 -0
  50. package/dist/utils/detect-schema-vendor.d.ts +22 -0
  51. package/dist/utils/detect-schema-vendor.js +76 -0
  52. package/dist/utils/ensure-function-metadata.d.ts +5 -2
  53. package/dist/utils/ensure-function-metadata.js +220 -6
  54. package/dist/utils/extract-function-name.d.ts +5 -16
  55. package/dist/utils/extract-function-name.js +93 -298
  56. package/dist/utils/extract-services.d.ts +2 -1
  57. package/dist/utils/extract-services.js +25 -1
  58. package/dist/utils/filter-inspector-state.js +107 -23
  59. package/dist/utils/get-property-value.d.ts +8 -2
  60. package/dist/utils/get-property-value.js +33 -4
  61. package/dist/utils/hash.d.ts +2 -0
  62. package/dist/utils/hash.js +23 -0
  63. package/dist/utils/middleware.d.ts +7 -30
  64. package/dist/utils/middleware.js +80 -66
  65. package/dist/utils/permissions.d.ts +2 -2
  66. package/dist/utils/permissions.js +10 -10
  67. package/dist/utils/post-process.d.ts +9 -10
  68. package/dist/utils/post-process.js +231 -24
  69. package/dist/utils/resolve-external-package.d.ts +12 -0
  70. package/dist/utils/resolve-external-package.js +34 -0
  71. package/dist/utils/resolve-function-types.d.ts +6 -0
  72. package/dist/utils/resolve-function-types.js +29 -0
  73. package/dist/utils/resolve-identifier.d.ts +10 -0
  74. package/dist/utils/resolve-identifier.js +36 -0
  75. package/dist/utils/resolve-versions.d.ts +2 -0
  76. package/dist/utils/resolve-versions.js +78 -0
  77. package/dist/utils/schema-generator.d.ts +9 -0
  78. package/dist/utils/schema-generator.js +209 -0
  79. package/dist/utils/serialize-inspector-state.d.ts +73 -13
  80. package/dist/utils/serialize-inspector-state.js +102 -6
  81. package/dist/utils/serialize-mcp-json.d.ts +2 -0
  82. package/dist/utils/serialize-mcp-json.js +99 -0
  83. package/dist/utils/serialize-middleware-groups-meta.d.ts +12 -0
  84. package/dist/utils/serialize-middleware-groups-meta.js +28 -0
  85. package/dist/utils/serialize-openapi-json.d.ts +85 -0
  86. package/dist/utils/serialize-openapi-json.js +151 -0
  87. package/dist/utils/serialize-permissions-groups-meta.d.ts +6 -0
  88. package/dist/utils/serialize-permissions-groups-meta.js +31 -0
  89. package/dist/utils/workflow/dsl/deserialize-dsl-workflow.d.ts +24 -0
  90. package/dist/utils/workflow/dsl/deserialize-dsl-workflow.js +830 -0
  91. package/dist/{workflow/extract-simple-workflow.d.ts → utils/workflow/dsl/extract-dsl-workflow.d.ts} +4 -2
  92. package/dist/{workflow/extract-simple-workflow.js → utils/workflow/dsl/extract-dsl-workflow.js} +572 -72
  93. package/dist/utils/workflow/dsl/index.d.ts +7 -0
  94. package/dist/utils/workflow/dsl/index.js +7 -0
  95. package/dist/{workflow → utils/workflow/dsl}/patterns.d.ts +21 -0
  96. package/dist/{workflow → utils/workflow/dsl}/patterns.js +90 -10
  97. package/dist/{workflow → utils/workflow/dsl}/validation.d.ts +2 -0
  98. package/dist/{workflow → utils/workflow/dsl}/validation.js +25 -7
  99. package/dist/utils/workflow/graph/convert-dsl-to-graph.d.ts +13 -0
  100. package/dist/utils/workflow/graph/convert-dsl-to-graph.js +318 -0
  101. package/dist/utils/workflow/graph/finalize-workflow-wires.d.ts +3 -0
  102. package/dist/utils/workflow/graph/finalize-workflow-wires.js +276 -0
  103. package/dist/utils/workflow/graph/finalize-workflows.d.ts +2 -0
  104. package/dist/utils/workflow/graph/finalize-workflows.js +75 -0
  105. package/dist/utils/workflow/graph/index.d.ts +8 -0
  106. package/dist/utils/workflow/graph/index.js +8 -0
  107. package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +35 -0
  108. package/dist/utils/workflow/graph/serialize-workflow-graph.js +150 -0
  109. package/dist/utils/workflow/graph/workflow-graph.types.d.ts +203 -0
  110. package/dist/utils/workflow/graph/workflow-graph.types.js +38 -0
  111. package/dist/visit.js +13 -2
  112. package/package.json +26 -4
  113. package/src/add/add-ai-agent.ts +468 -0
  114. package/src/add/add-channel.ts +82 -79
  115. package/src/add/add-cli.ts +49 -20
  116. package/src/add/add-file-with-factory.ts +2 -0
  117. package/src/add/add-functions.ts +429 -71
  118. package/src/add/add-http-route.ts +246 -65
  119. package/src/add/add-http-routes.ts +228 -0
  120. package/src/add/add-keyed-wiring.ts +151 -0
  121. package/src/add/add-mcp-prompt.ts +26 -15
  122. package/src/add/add-mcp-resource.ts +27 -15
  123. package/src/add/add-middleware.ts +482 -80
  124. package/src/add/add-permission.ts +199 -40
  125. package/src/add/add-queue-worker.ts +24 -19
  126. package/src/add/add-rpc-invocations.ts +78 -31
  127. package/src/add/add-schedule.ts +16 -11
  128. package/src/add/add-secret.ts +140 -0
  129. package/src/add/add-trigger.ts +154 -0
  130. package/src/add/add-variable.ts +9 -0
  131. package/src/add/add-workflow-graph.ts +522 -0
  132. package/src/add/add-workflow.ts +117 -30
  133. package/src/error-codes.ts +26 -1
  134. package/src/index.ts +27 -8
  135. package/src/inspector.ts +145 -17
  136. package/src/schema-generator.ts +1 -0
  137. package/src/types-map.ts +12 -1
  138. package/src/types.ts +192 -51
  139. package/src/utils/compute-required-schemas.ts +49 -0
  140. package/src/utils/contract-hashes.test.ts +528 -0
  141. package/src/utils/contract-hashes.ts +290 -0
  142. package/src/utils/custom-types-generator.ts +88 -0
  143. package/src/utils/detect-schema-vendor.ts +90 -0
  144. package/src/utils/ensure-function-metadata.ts +324 -7
  145. package/src/utils/extract-function-name.ts +108 -358
  146. package/src/utils/extract-services.ts +35 -2
  147. package/src/utils/filter-inspector-state.test.ts +34 -20
  148. package/src/utils/filter-inspector-state.ts +140 -31
  149. package/src/utils/get-property-value.ts +50 -5
  150. package/src/utils/hash.ts +26 -0
  151. package/src/utils/middleware.test.ts +204 -0
  152. package/src/utils/middleware.ts +129 -67
  153. package/src/utils/permissions.test.ts +35 -12
  154. package/src/utils/permissions.ts +10 -10
  155. package/src/utils/post-process.ts +283 -43
  156. package/src/utils/resolve-external-package.ts +42 -0
  157. package/src/utils/resolve-function-types.ts +42 -0
  158. package/src/utils/resolve-identifier.ts +46 -0
  159. package/src/utils/resolve-versions.test.ts +249 -0
  160. package/src/utils/resolve-versions.ts +105 -0
  161. package/src/utils/schema-generator.ts +329 -0
  162. package/src/utils/serialize-inspector-state.ts +181 -20
  163. package/src/utils/serialize-mcp-json.ts +145 -0
  164. package/src/utils/serialize-middleware-groups-meta.ts +33 -0
  165. package/src/utils/serialize-openapi-json.ts +277 -0
  166. package/src/utils/serialize-permissions-groups-meta.ts +35 -0
  167. package/src/utils/test-data/inspector-state.json +69 -66
  168. package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +1104 -0
  169. package/src/{workflow/extract-simple-workflow.ts → utils/workflow/dsl/extract-dsl-workflow.ts} +678 -85
  170. package/src/utils/workflow/dsl/index.ts +11 -0
  171. package/src/{workflow → utils/workflow/dsl}/patterns.ts +108 -11
  172. package/src/{workflow → utils/workflow/dsl}/validation.ts +34 -7
  173. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +422 -0
  174. package/src/utils/workflow/graph/finalize-workflow-wires.ts +310 -0
  175. package/src/utils/workflow/graph/finalize-workflows.ts +100 -0
  176. package/src/utils/workflow/graph/index.ts +11 -0
  177. package/src/utils/workflow/graph/serialize-workflow-graph.ts +216 -0
  178. package/src/utils/workflow/graph/workflow-graph.types.ts +231 -0
  179. package/src/visit.ts +14 -2
  180. package/tsconfig.tsbuildinfo +1 -1
  181. package/dist/add/add-mcp-tool.d.ts +0 -2
  182. package/dist/add/add-mcp-tool.js +0 -81
  183. package/dist/utils/extract-service-metadata.d.ts +0 -19
  184. package/dist/utils/extract-service-metadata.js +0 -244
  185. package/dist/utils/write-service-metadata.d.ts +0 -13
  186. package/dist/utils/write-service-metadata.js +0 -37
  187. package/src/add/add-mcp-tool.ts +0 -141
  188. package/src/utils/extract-service-metadata.ts +0 -353
  189. package/src/utils/write-service-metadata.ts +0 -51
@@ -3,8 +3,74 @@ import { extractFunctionName } from '../utils/extract-function-name.js';
3
3
  import { extractFunctionNode } from '../utils/extract-function-node.js';
4
4
  import { ErrorCode } from '../error-codes.js';
5
5
  import { extractStringLiteral, isStringLike, isFunctionLike, extractDescription, extractDuration, } from '../utils/extract-node-value.js';
6
- import { extractSimpleWorkflow } from '../workflow/extract-simple-workflow.js';
7
6
  import { getCommonWireMetaData } from '../utils/get-property-value.js';
7
+ import { extractDSLWorkflow } from '../utils/workflow/dsl/extract-dsl-workflow.js';
8
+ /**
9
+ * Recursively check if any step has inline type (non-serializable)
10
+ */
11
+ function hasInlineSteps(steps) {
12
+ for (const step of steps) {
13
+ if (step.type === 'inline') {
14
+ return true;
15
+ }
16
+ else if (step.type === 'branch') {
17
+ for (const branch of step.branches) {
18
+ if (hasInlineSteps(branch.steps))
19
+ return true;
20
+ }
21
+ if (step.elseSteps && hasInlineSteps(step.elseSteps))
22
+ return true;
23
+ }
24
+ else if (step.type === 'switch' && step.cases) {
25
+ for (const c of step.cases) {
26
+ if (c.steps && hasInlineSteps(c.steps))
27
+ return true;
28
+ }
29
+ if (step.defaultSteps && hasInlineSteps(step.defaultSteps))
30
+ return true;
31
+ }
32
+ else if (step.type === 'fanout' && step.child) {
33
+ if (hasInlineSteps([step.child]))
34
+ return true;
35
+ }
36
+ else if (step.type === 'parallel' && step.children) {
37
+ if (hasInlineSteps(step.children))
38
+ return true;
39
+ }
40
+ }
41
+ return false;
42
+ }
43
+ /**
44
+ * Recursively collect all RPC names from workflow steps
45
+ */
46
+ function collectInvokedRPCs(steps, rpcs) {
47
+ for (const step of steps) {
48
+ if (step.type === 'rpc' && step.rpcName) {
49
+ rpcs.add(step.rpcName);
50
+ }
51
+ else if (step.type === 'branch') {
52
+ for (const branch of step.branches) {
53
+ collectInvokedRPCs(branch.steps, rpcs);
54
+ }
55
+ if (step.elseSteps)
56
+ collectInvokedRPCs(step.elseSteps, rpcs);
57
+ }
58
+ else if (step.type === 'switch' && step.cases) {
59
+ for (const c of step.cases) {
60
+ if (c.steps)
61
+ collectInvokedRPCs(c.steps, rpcs);
62
+ }
63
+ if (step.defaultSteps)
64
+ collectInvokedRPCs(step.defaultSteps, rpcs);
65
+ }
66
+ else if (step.type === 'fanout' && step.child) {
67
+ collectInvokedRPCs([step.child], rpcs);
68
+ }
69
+ else if (step.type === 'parallel' && step.children) {
70
+ collectInvokedRPCs(step.children, rpcs);
71
+ }
72
+ }
73
+ }
8
74
  /**
9
75
  * Scan for workflow.do(), workflow.sleep(), and workflow.cancel() calls to extract workflow steps
10
76
  */
@@ -66,11 +132,10 @@ function getWorkflowInvocations(node, checker, state, workflowName, steps) {
66
132
  }
67
133
  }
68
134
  }
69
- // Don't recurse into nested functions - only look at top-level workflow calls
135
+ // Recurse into children, including arrow functions (for Promise.all callbacks)
136
+ // but skip function declarations (which would be separate functions)
70
137
  ts.forEachChild(node, (child) => {
71
- if (ts.isFunctionDeclaration(child) ||
72
- ts.isFunctionExpression(child) ||
73
- ts.isArrowFunction(child)) {
138
+ if (ts.isFunctionDeclaration(child)) {
74
139
  return;
75
140
  }
76
141
  getWorkflowInvocations(child, checker, state, workflowName, steps);
@@ -92,10 +157,10 @@ export const addWorkflow = (logger, node, checker, state) => {
92
157
  }
93
158
  let wrapperType = null;
94
159
  if (expression.text === 'pikkuWorkflowFunc') {
95
- wrapperType = 'regular';
160
+ wrapperType = 'dsl';
96
161
  }
97
- else if (expression.text === 'pikkuSimpleWorkflowFunc') {
98
- wrapperType = 'simple';
162
+ else if (expression.text === 'pikkuWorkflowComplexFunc') {
163
+ wrapperType = 'regular';
99
164
  }
100
165
  else {
101
166
  return;
@@ -104,7 +169,7 @@ export const addWorkflow = (logger, node, checker, state) => {
104
169
  return;
105
170
  }
106
171
  // Extract workflow name and metadata using same logic as add-functions
107
- const { pikkuFuncName, name, exportedName } = extractFunctionName(node, checker, state.rootDir);
172
+ const { pikkuFuncId, name, exportedName } = extractFunctionName(node, checker, state.rootDir);
108
173
  const workflowName = exportedName || name;
109
174
  if (!workflowName) {
110
175
  logger.critical(ErrorCode.MISSING_NAME, `Could not determine workflow name from export.`);
@@ -119,6 +184,8 @@ export const addWorkflow = (logger, node, checker, state) => {
119
184
  let errors;
120
185
  if (ts.isObjectLiteralExpression(firstArg)) {
121
186
  const metadata = getCommonWireMetaData(firstArg, 'Workflow', workflowName, logger);
187
+ if (metadata.disabled)
188
+ return;
122
189
  tags = metadata.tags;
123
190
  summary = metadata.summary;
124
191
  description = metadata.description;
@@ -136,40 +203,71 @@ export const addWorkflow = (logger, node, checker, state) => {
136
203
  }
137
204
  // Track workflow file for wiring generation
138
205
  if (exportedName) {
139
- state.workflows.files.set(pikkuFuncName, {
206
+ state.workflows.files.set(pikkuFuncId, {
140
207
  path: node.getSourceFile().fileName,
141
208
  exportedName,
142
209
  });
143
210
  }
144
211
  let steps = [];
145
- let simple = undefined;
146
- // Try simple workflow extraction first
212
+ let context = undefined;
213
+ let dsl = undefined;
214
+ // Try DSL workflow extraction first
147
215
  // Pass the whole CallExpression node so findWorkflowFunction can find the arrow function
148
- const result = extractSimpleWorkflow(node, checker);
216
+ const result = extractDSLWorkflow(node, checker);
149
217
  if (result.status === 'ok' && result.steps) {
150
- // Simple extraction succeeded
218
+ // Extraction succeeded
151
219
  steps = result.steps;
152
- simple = true;
220
+ context = result.context;
221
+ // Check if workflow contains inline steps (non-serializable)
222
+ if (hasInlineSteps(steps)) {
223
+ if (wrapperType === 'dsl') {
224
+ // pikkuWorkflowFunc should not have inline steps
225
+ logger.critical(ErrorCode.INVALID_DSL_WORKFLOW, `Workflow '${workflowName}' uses pikkuWorkflowFunc but contains inline steps which are not allowed in DSL workflows. Use pikkuWorkflowComplexFunc instead.`);
226
+ return;
227
+ }
228
+ // pikkuWorkflowComplexFunc with inline steps is marked as non-dsl
229
+ dsl = false;
230
+ }
231
+ else {
232
+ // pikkuWorkflowComplexFunc is always non-dsl, pikkuWorkflowFunc is dsl
233
+ dsl = wrapperType === 'dsl';
234
+ }
235
+ // Collect all invoked RPCs from workflow steps
236
+ const rpcs = new Set();
237
+ collectInvokedRPCs(steps, rpcs);
238
+ for (const rpc of rpcs) {
239
+ state.rpc.invokedFunctions.add(rpc);
240
+ }
153
241
  }
154
242
  else {
155
- // Simple extraction failed
156
- if (wrapperType === 'simple') {
157
- // For pikkuSimpleWorkflowFunc, this is a critical error
158
- logger.critical(ErrorCode.INVALID_SIMPLE_WORKFLOW, `Workflow '${workflowName}' uses pikkuSimpleWorkflowFunc but does not conform to simple workflow DSL:\n${result.reason || 'Unknown error'}`);
243
+ // DSL extraction failed
244
+ if (wrapperType === 'dsl') {
245
+ // For pikkuWorkflowFunc, this is a critical error
246
+ // But still track RPC invocations for function registration
247
+ getWorkflowInvocations(resolvedFunc, checker, state, workflowName, steps);
248
+ logger.critical(ErrorCode.INVALID_DSL_WORKFLOW, `Workflow '${workflowName}' uses pikkuWorkflowFunc but does not conform to DSL workflow rules:\n${result.reason || 'Unknown error'}`);
159
249
  return;
160
250
  }
161
251
  else {
162
- // For pikkuWorkflowFunc, fall back to basic extraction
163
- logger.debug(`Workflow '${workflowName}' could not be extracted as simple workflow: ${result.reason || 'Unknown error'}. Falling back to basic extraction.`);
164
- simple = false;
252
+ // For pikkuWorkflowComplexFunc, fall back to basic extraction
253
+ logger.debug(`Workflow '${workflowName}' could not be extracted as DSL workflow: ${result.reason || 'Unknown error'}. Falling back to basic extraction.`);
254
+ dsl = false;
165
255
  }
166
256
  }
167
- getWorkflowInvocations(resolvedFunc, checker, state, workflowName, steps);
257
+ /**
258
+ * For non-dsl workflows or pikkuWorkflowComplexFunc, run basic extraction
259
+ * to ensure all RPC invocations are tracked for function registration.
260
+ * This catches RPCs in Promise.all callbacks and other patterns DSL can't extract.
261
+ */
262
+ if (!dsl || wrapperType === 'regular') {
263
+ getWorkflowInvocations(resolvedFunc, checker, state, workflowName, steps);
264
+ }
168
265
  state.workflows.meta[workflowName] = {
169
- pikkuFuncName,
170
- workflowName,
266
+ pikkuFuncId,
267
+ name: workflowName,
171
268
  steps,
172
- simple,
269
+ context,
270
+ dsl,
173
271
  summary,
174
272
  description,
175
273
  errors,
@@ -9,6 +9,7 @@
9
9
  export declare enum ErrorCode {
10
10
  MISSING_NAME = "PKU111",
11
11
  MISSING_DESCRIPTION = "PKU123",
12
+ INVALID_VALUE = "PKU124",
12
13
  MISSING_URI = "PKU220",
13
14
  MISSING_FUNC = "PKU236",
14
15
  INVALID_TAGS_TYPE = "PKU247",
@@ -19,14 +20,17 @@ export declare enum ErrorCode {
19
20
  CLI_CLIENTSIDE_RENDERER_HAS_SERVICES = "PKU672",
20
21
  DYNAMIC_STEP_NAME = "PKU529",
21
22
  WORKFLOW_ORCHESTRATOR_NOT_CONFIGURED = "PKU600",
22
- INVALID_SIMPLE_WORKFLOW = "PKU641",
23
+ INVALID_DSL_WORKFLOW = "PKU641",
23
24
  CONFIG_TYPE_NOT_FOUND = "PKU426",
24
25
  CONFIG_TYPE_UNDEFINED = "PKU427",
25
26
  SCHEMA_NO_ROOT = "PKU431",
26
27
  SCHEMA_GENERATION_ERROR = "PKU456",
27
28
  SCHEMA_LOAD_ERROR = "PKU488",
29
+ INLINE_SCHEMA = "PKU489",
28
30
  FUNCTION_METADATA_NOT_FOUND = "PKU559",
29
31
  HANDLER_NOT_RESOLVED = "PKU568",
32
+ ROUTE_PARAM_MISMATCH = "PKU571",
33
+ ROUTE_QUERY_MISMATCH = "PKU572",
30
34
  MIDDLEWARE_HANDLER_INVALID = "PKU685",
31
35
  MIDDLEWARE_TAG_INVALID = "PKU715",
32
36
  MIDDLEWARE_EMPTY_ARRAY = "PKU736",
@@ -35,5 +39,16 @@ export declare enum ErrorCode {
35
39
  PERMISSION_TAG_INVALID = "PKU836",
36
40
  PERMISSION_EMPTY_ARRAY = "PKU937",
37
41
  PERMISSION_PATTERN_INVALID = "PKU975",
42
+ DUPLICATE_FUNCTION_VERSION = "PKU850",
43
+ MANIFEST_MISSING = "PKU860",
44
+ FUNCTION_VERSION_MODIFIED = "PKU861",
45
+ CONTRACT_CHANGED_REQUIRES_BUMP = "PKU862",
46
+ VERSION_REGRESSION_OR_CONFLICT = "PKU863",
47
+ VERSION_GAP_NOT_ALLOWED = "PKU864",
48
+ MANIFEST_INTEGRITY_ERROR = "PKU865",
49
+ MISSING_MODEL = "PKU145",
50
+ INVALID_MODEL = "PKU146",
51
+ SERVICES_NOT_DESTRUCTURED = "PKU410",
52
+ WIRES_NOT_DESTRUCTURED = "PKU411",
38
53
  WORKFLOW_MULTI_QUEUE_NOT_SUPPORTED = "PKU901"
39
54
  }
@@ -11,6 +11,7 @@ export var ErrorCode;
11
11
  // Validation errors
12
12
  ErrorCode["MISSING_NAME"] = "PKU111";
13
13
  ErrorCode["MISSING_DESCRIPTION"] = "PKU123";
14
+ ErrorCode["INVALID_VALUE"] = "PKU124";
14
15
  ErrorCode["MISSING_URI"] = "PKU220";
15
16
  ErrorCode["MISSING_FUNC"] = "PKU236";
16
17
  ErrorCode["INVALID_TAGS_TYPE"] = "PKU247";
@@ -21,16 +22,20 @@ export var ErrorCode;
21
22
  ErrorCode["CLI_CLIENTSIDE_RENDERER_HAS_SERVICES"] = "PKU672";
22
23
  ErrorCode["DYNAMIC_STEP_NAME"] = "PKU529";
23
24
  ErrorCode["WORKFLOW_ORCHESTRATOR_NOT_CONFIGURED"] = "PKU600";
24
- ErrorCode["INVALID_SIMPLE_WORKFLOW"] = "PKU641";
25
+ ErrorCode["INVALID_DSL_WORKFLOW"] = "PKU641";
25
26
  // Configuration errors
26
27
  ErrorCode["CONFIG_TYPE_NOT_FOUND"] = "PKU426";
27
28
  ErrorCode["CONFIG_TYPE_UNDEFINED"] = "PKU427";
28
29
  ErrorCode["SCHEMA_NO_ROOT"] = "PKU431";
29
30
  ErrorCode["SCHEMA_GENERATION_ERROR"] = "PKU456";
30
31
  ErrorCode["SCHEMA_LOAD_ERROR"] = "PKU488";
32
+ ErrorCode["INLINE_SCHEMA"] = "PKU489";
31
33
  // Function errors
32
34
  ErrorCode["FUNCTION_METADATA_NOT_FOUND"] = "PKU559";
33
35
  ErrorCode["HANDLER_NOT_RESOLVED"] = "PKU568";
36
+ // HTTP Route errors
37
+ ErrorCode["ROUTE_PARAM_MISMATCH"] = "PKU571";
38
+ ErrorCode["ROUTE_QUERY_MISMATCH"] = "PKU572";
34
39
  // Middleware/Permission errors
35
40
  ErrorCode["MIDDLEWARE_HANDLER_INVALID"] = "PKU685";
36
41
  ErrorCode["MIDDLEWARE_TAG_INVALID"] = "PKU715";
@@ -40,6 +45,21 @@ export var ErrorCode;
40
45
  ErrorCode["PERMISSION_TAG_INVALID"] = "PKU836";
41
46
  ErrorCode["PERMISSION_EMPTY_ARRAY"] = "PKU937";
42
47
  ErrorCode["PERMISSION_PATTERN_INVALID"] = "PKU975";
48
+ // Versioning errors
49
+ ErrorCode["DUPLICATE_FUNCTION_VERSION"] = "PKU850";
50
+ // Contract versioning errors
51
+ ErrorCode["MANIFEST_MISSING"] = "PKU860";
52
+ ErrorCode["FUNCTION_VERSION_MODIFIED"] = "PKU861";
53
+ ErrorCode["CONTRACT_CHANGED_REQUIRES_BUMP"] = "PKU862";
54
+ ErrorCode["VERSION_REGRESSION_OR_CONFLICT"] = "PKU863";
55
+ ErrorCode["VERSION_GAP_NOT_ALLOWED"] = "PKU864";
56
+ ErrorCode["MANIFEST_INTEGRITY_ERROR"] = "PKU865";
57
+ // Model configuration errors
58
+ ErrorCode["MISSING_MODEL"] = "PKU145";
59
+ ErrorCode["INVALID_MODEL"] = "PKU146";
60
+ // Optimization diagnostics
61
+ ErrorCode["SERVICES_NOT_DESTRUCTURED"] = "PKU410";
62
+ ErrorCode["WIRES_NOT_DESTRUCTURED"] = "PKU411";
43
63
  // Feature Flag
44
64
  ErrorCode["WORKFLOW_MULTI_QUEUE_NOT_SUPPORTED"] = "PKU901";
45
65
  })(ErrorCode || (ErrorCode = {}));
package/dist/index.d.ts CHANGED
@@ -1,12 +1,16 @@
1
1
  export { inspect, getInitialInspectorState } from './inspector.js';
2
- export { getFilesAndMethods } from './utils/get-files-and-methods.js';
3
2
  export type { TypesMap } from './types-map.js';
4
3
  export type * from './types.js';
5
- export type { InspectorState } from './types.js';
6
- export type { FilesAndMethods, FilesAndMethodsErrors, } from './utils/get-files-and-methods.js';
4
+ export type { FilesAndMethodsErrors } from './utils/get-files-and-methods.js';
7
5
  export { ErrorCode } from './error-codes.js';
8
6
  export { serializeInspectorState, deserializeInspectorState, } from './utils/serialize-inspector-state.js';
9
7
  export type { SerializableInspectorState } from './utils/serialize-inspector-state.js';
10
8
  export { filterInspectorState } from './utils/filter-inspector-state.js';
11
- export { writeAllServiceMetadata } from './utils/write-service-metadata.js';
12
- export type { ServiceMetadata } from './utils/extract-service-metadata.js';
9
+ export { generateCustomTypes, sanitizeTypeName, } from './utils/custom-types-generator.js';
10
+ export { createEmptyManifest, serializeManifest, } from './utils/contract-hashes.js';
11
+ export type { ContractEntry, VersionValidateError, VersionManifest, VersionManifestEntry, } from './utils/contract-hashes.js';
12
+ export { serializeMCPJson } from './utils/serialize-mcp-json.js';
13
+ export type { OpenAPISpecInfo } from './utils/serialize-openapi-json.js';
14
+ export { deserializeDslWorkflow, deserializeGraphWorkflow, deserializeAllDslWorkflows, } from './utils/workflow/dsl/index.js';
15
+ export { getFilesAndMethods } from './utils/get-files-and-methods.js';
16
+ export type { SerializedWorkflowGraph, SerializedWorkflowGraphs, } from './utils/workflow/graph/index.js';
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  export { inspect, getInitialInspectorState } from './inspector.js';
2
- export { getFilesAndMethods } from './utils/get-files-and-methods.js';
3
2
  export { ErrorCode } from './error-codes.js';
4
3
  export { serializeInspectorState, deserializeInspectorState, } from './utils/serialize-inspector-state.js';
5
4
  export { filterInspectorState } from './utils/filter-inspector-state.js';
6
- export { writeAllServiceMetadata } from './utils/write-service-metadata.js';
5
+ export { generateCustomTypes, sanitizeTypeName, } from './utils/custom-types-generator.js';
6
+ export { createEmptyManifest, serializeManifest, } from './utils/contract-hashes.js';
7
+ export { serializeMCPJson } from './utils/serialize-mcp-json.js';
8
+ export { deserializeDslWorkflow, deserializeGraphWorkflow, deserializeAllDslWorkflows, } from './utils/workflow/dsl/index.js';
9
+ export { getFilesAndMethods } from './utils/get-files-and-methods.js';
@@ -5,4 +5,4 @@ import { InspectorState, InspectorLogger, InspectorOptions } from './types.js';
5
5
  * @returns A fresh InspectorState with empty collections
6
6
  */
7
7
  export declare function getInitialInspectorState(rootDir: string): InspectorState;
8
- export declare const inspect: (logger: InspectorLogger, routeFiles: string[], options?: InspectorOptions) => InspectorState;
8
+ export declare const inspect: (logger: InspectorLogger, routeFiles: string[], options?: InspectorOptions) => Promise<InspectorState>;
package/dist/inspector.js CHANGED
@@ -4,7 +4,14 @@ import { visitSetup, visitRoutes } from './visit.js';
4
4
  import { TypesMap } from './types-map.js';
5
5
  import { getFilesAndMethods } from './utils/get-files-and-methods.js';
6
6
  import { findCommonAncestor } from './utils/find-root-dir.js';
7
- import { aggregateRequiredServices, extractServiceInterfaceMetadata, } from './utils/post-process.js';
7
+ import { aggregateRequiredServices, validateSecretOverrides, validateAgentModels, validateAgentOverrides, computeResolvedIOTypes, computeMiddlewareGroupsMeta, computePermissionsGroupsMeta, computeRequiredSchemas, computeDiagnostics, } from './utils/post-process.js';
8
+ import { generateOpenAPISpec } from './utils/serialize-openapi-json.js';
9
+ import { pikkuState } from '@pikku/core';
10
+ import { resolveLatestVersions } from './utils/resolve-versions.js';
11
+ import { finalizeWorkflows } from './utils/workflow/graph/finalize-workflows.js';
12
+ import { finalizeWorkflowHelperTypes, finalizeWorkflowWires, } from './utils/workflow/graph/finalize-workflow-wires.js';
13
+ import { generateAllSchemas } from './utils/schema-generator.js';
14
+ import { computeContractHashes, extractContractsFromMeta, updateManifest, createEmptyManifest, validateContracts, } from './utils/contract-hashes.js';
8
15
  /**
9
16
  * Creates an initial/empty inspector state with all required properties initialized
10
17
  * @param rootDir - The root directory for the project
@@ -24,6 +31,8 @@ export function getInitialInspectorState(rootDir) {
24
31
  filesAndMethods: {},
25
32
  filesAndMethodsErrors: new Map(),
26
33
  typesLookup: new Map(),
34
+ schemaLookup: new Map(),
35
+ schemas: {},
27
36
  functions: {
28
37
  typesMap: new TypesMap(),
29
38
  meta: {},
@@ -48,6 +57,11 @@ export function getInitialInspectorState(rootDir) {
48
57
  files: new Set(),
49
58
  meta: {},
50
59
  },
60
+ triggers: {
61
+ meta: {},
62
+ sourceMeta: {},
63
+ files: new Set(),
64
+ },
51
65
  scheduledTasks: {
52
66
  meta: {},
53
67
  files: new Set(),
@@ -59,6 +73,9 @@ export function getInitialInspectorState(rootDir) {
59
73
  workflows: {
60
74
  meta: {},
61
75
  files: new Map(),
76
+ graphMeta: {},
77
+ graphFiles: new Map(),
78
+ invokedWorkflows: new Set(),
62
79
  },
63
80
  rpc: {
64
81
  internalMeta: {},
@@ -66,6 +83,7 @@ export function getInitialInspectorState(rootDir) {
66
83
  exposedMeta: {},
67
84
  exposedFiles: new Map(),
68
85
  invokedFunctions: new Set(),
86
+ usedExternalPackages: new Set(),
69
87
  },
70
88
  mcpEndpoints: {
71
89
  resourcesMeta: {},
@@ -73,6 +91,10 @@ export function getInitialInspectorState(rootDir) {
73
91
  promptsMeta: {},
74
92
  files: new Set(),
75
93
  },
94
+ agents: {
95
+ agentsMeta: {},
96
+ files: new Map(),
97
+ },
76
98
  cli: {
77
99
  meta: {
78
100
  programs: {},
@@ -80,12 +102,39 @@ export function getInitialInspectorState(rootDir) {
80
102
  },
81
103
  files: new Set(),
82
104
  },
83
- middleware: {
105
+ nodes: {
84
106
  meta: {},
107
+ files: new Set(),
108
+ },
109
+ secrets: {
110
+ definitions: [],
111
+ files: new Set(),
112
+ },
113
+ variables: {
114
+ definitions: [],
115
+ files: new Set(),
116
+ },
117
+ manifest: {
118
+ initial: null,
119
+ current: null,
120
+ errors: [],
121
+ },
122
+ middleware: {
123
+ definitions: {},
124
+ instances: {},
125
+ tagMiddleware: new Map(),
126
+ },
127
+ channelMiddleware: {
128
+ definitions: {},
129
+ instances: {},
85
130
  tagMiddleware: new Map(),
86
131
  },
132
+ aiMiddleware: {
133
+ definitions: {},
134
+ },
87
135
  permissions: {
88
- meta: {},
136
+ definitions: {},
137
+ instances: {},
89
138
  tagPermissions: new Map(),
90
139
  },
91
140
  serviceAggregation: {
@@ -96,17 +145,36 @@ export function getInitialInspectorState(rootDir) {
96
145
  allSingletonServices: [],
97
146
  allWireServices: [],
98
147
  },
99
- serviceMetadata: [],
148
+ resolvedIOTypes: {},
149
+ middlewareGroupsMeta: {
150
+ definitions: {},
151
+ instances: {},
152
+ httpGroups: {},
153
+ tagGroups: {},
154
+ channelMiddleware: {
155
+ definitions: {},
156
+ instances: {},
157
+ tagGroups: {},
158
+ },
159
+ },
160
+ permissionsGroupsMeta: {
161
+ definitions: {},
162
+ httpGroups: {},
163
+ tagGroups: {},
164
+ },
165
+ requiredSchemas: new Set(),
166
+ openAPISpec: null,
167
+ diagnostics: [],
100
168
  };
101
169
  }
102
- export const inspect = (logger, routeFiles, options = {}) => {
170
+ export const inspect = async (logger, routeFiles, options = {}) => {
103
171
  const startProgram = performance.now();
104
172
  const program = ts.createProgram(routeFiles, {
105
173
  target: ts.ScriptTarget.ESNext,
106
- module: ts.ModuleKind.CommonJS,
174
+ module: ts.ModuleKind.Node16,
107
175
  skipLibCheck: true,
108
176
  skipDefaultLibCheck: true,
109
- moduleResolution: ts.ModuleResolutionKind.Node10,
177
+ moduleResolution: ts.ModuleResolutionKind.Node16,
110
178
  types: [],
111
179
  allowJs: false,
112
180
  checkJs: false,
@@ -115,11 +183,15 @@ export const inspect = (logger, routeFiles, options = {}) => {
115
183
  const startChecker = performance.now();
116
184
  const checker = program.getTypeChecker();
117
185
  logger.debug(`Got type checker in ${(performance.now() - startChecker).toFixed(2)}ms`);
186
+ // Use provided rootDir or infer from source files
187
+ const rootDir = options.rootDir || findCommonAncestor(routeFiles);
118
188
  const startSourceFiles = performance.now();
119
- const sourceFiles = program.getSourceFiles();
189
+ // Filter source files to only include files within the project rootDir
190
+ // This prevents picking up types from external packages (including workspace symlinks)
191
+ const sourceFiles = program
192
+ .getSourceFiles()
193
+ .filter((sf) => sf.fileName.startsWith(rootDir));
120
194
  logger.debug(`Got source files in ${(performance.now() - startSourceFiles).toFixed(2)}ms`);
121
- // Infer root directory from source files
122
- const rootDir = findCommonAncestor(routeFiles);
123
195
  const state = getInitialInspectorState(rootDir);
124
196
  // First sweep: add all functions
125
197
  const startSetup = performance.now();
@@ -134,6 +206,20 @@ export const inspect = (logger, routeFiles, options = {}) => {
134
206
  ts.forEachChild(sourceFile, (child) => visitRoutes(logger, checker, child, state, options));
135
207
  }
136
208
  logger.debug(`Visit routes phase completed in ${(performance.now() - startRoutes).toFixed(2)}ms`);
209
+ resolveLatestVersions(state, logger);
210
+ if (options.schemaConfig) {
211
+ state.schemas = await generateAllSchemas(logger, options.schemaConfig, state);
212
+ computeContractHashes(state.schemas, state.functions.typesMap, state.functions.meta);
213
+ computeRequiredSchemas(state, options);
214
+ }
215
+ state.manifest.initial = options.manifest ?? null;
216
+ const contracts = extractContractsFromMeta(state.functions.meta);
217
+ const baseManifest = state.manifest.initial ?? createEmptyManifest();
218
+ state.manifest.current = updateManifest(baseManifest, contracts);
219
+ state.manifest.errors = validateContracts(baseManifest, contracts).errors;
220
+ finalizeWorkflows(state);
221
+ finalizeWorkflowHelperTypes(state);
222
+ finalizeWorkflowWires(state);
137
223
  }
138
224
  // Populate filesAndMethods
139
225
  const startFilesAndMethods = performance.now();
@@ -145,9 +231,16 @@ export const inspect = (logger, routeFiles, options = {}) => {
145
231
  const startAggregate = performance.now();
146
232
  aggregateRequiredServices(state);
147
233
  logger.debug(`Aggregate required services completed in ${(performance.now() - startAggregate).toFixed(2)}ms`);
148
- const startServiceMeta = performance.now();
149
- extractServiceInterfaceMetadata(state, checker);
150
- logger.debug(`Extract service metadata completed in ${(performance.now() - startServiceMeta).toFixed(2)}ms`);
234
+ computeResolvedIOTypes(state);
235
+ computeMiddlewareGroupsMeta(state);
236
+ computePermissionsGroupsMeta(state);
237
+ computeDiagnostics(state);
238
+ if (options.openAPI) {
239
+ state.openAPISpec = await generateOpenAPISpec(logger, state.functions.meta, state.http.meta, state.schemas, options.openAPI.additionalInfo, pikkuState(null, 'misc', 'errors'));
240
+ }
241
+ validateSecretOverrides(logger, state, options.externalPackages);
242
+ validateAgentModels(logger, state, options.modelConfig);
243
+ validateAgentOverrides(logger, state, options.modelConfig);
151
244
  }
152
245
  return state;
153
246
  };
@@ -0,0 +1 @@
1
+ export { generateAllSchemas } from './utils/schema-generator.js';
@@ -0,0 +1 @@
1
+ export { generateAllSchemas } from './utils/schema-generator.js';
package/dist/types-map.js CHANGED
@@ -17,7 +17,16 @@ export class TypesMap {
17
17
  return meta.uniqueName;
18
18
  }
19
19
  getTypeMeta(name) {
20
- if (['string', 'number', 'boolean', 'null'].includes(name)) {
20
+ if ([
21
+ 'string',
22
+ 'number',
23
+ 'boolean',
24
+ 'null',
25
+ 'undefined',
26
+ 'void',
27
+ 'unknown',
28
+ 'never',
29
+ ].includes(name)) {
21
30
  return {
22
31
  originalName: name,
23
32
  uniqueName: name,