@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.
Files changed (211) hide show
  1. package/CHANGELOG.md +36 -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 +81 -61
  6. package/dist/add/add-cli.d.ts +1 -1
  7. package/dist/add/add-cli.js +42 -19
  8. package/dist/add/add-file-extends-core-type.d.ts +1 -1
  9. package/dist/add/add-file-with-config.d.ts +1 -1
  10. package/dist/add/add-file-with-factory.d.ts +1 -1
  11. package/dist/add/add-file-with-factory.js +2 -0
  12. package/dist/add/add-functions.d.ts +1 -1
  13. package/dist/add/add-functions.js +256 -82
  14. package/dist/add/add-http-route.d.ts +20 -10
  15. package/dist/add/add-http-route.js +156 -66
  16. package/dist/add/add-http-routes.d.ts +5 -0
  17. package/dist/add/add-http-routes.js +160 -0
  18. package/dist/add/add-keyed-wiring.d.ts +12 -0
  19. package/dist/add/add-keyed-wiring.js +97 -0
  20. package/dist/add/add-mcp-prompt.d.ts +1 -1
  21. package/dist/add/add-mcp-prompt.js +14 -9
  22. package/dist/add/add-mcp-resource.d.ts +1 -1
  23. package/dist/add/add-mcp-resource.js +14 -9
  24. package/dist/add/add-middleware.d.ts +1 -4
  25. package/dist/add/add-middleware.js +364 -79
  26. package/dist/add/add-permission.d.ts +1 -1
  27. package/dist/add/add-permission.js +152 -40
  28. package/dist/add/add-queue-worker.d.ts +1 -1
  29. package/dist/add/add-queue-worker.js +18 -12
  30. package/dist/add/add-rpc-invocations.d.ts +3 -3
  31. package/dist/add/add-rpc-invocations.js +24 -10
  32. package/dist/add/add-schedule.d.ts +1 -1
  33. package/dist/add/add-schedule.js +11 -5
  34. package/dist/add/add-secret.d.ts +3 -0
  35. package/dist/add/add-secret.js +82 -0
  36. package/dist/add/add-trigger.d.ts +2 -0
  37. package/dist/add/add-trigger.js +87 -0
  38. package/dist/add/add-variable.d.ts +1 -0
  39. package/dist/add/add-variable.js +8 -0
  40. package/dist/add/add-wire-addon.d.ts +7 -0
  41. package/dist/add/add-wire-addon.js +70 -0
  42. package/dist/add/add-workflow-graph.d.ts +3 -2
  43. package/dist/add/add-workflow-graph.js +143 -406
  44. package/dist/add/add-workflow.d.ts +1 -1
  45. package/dist/add/add-workflow.js +6 -4
  46. package/dist/error-codes.d.ts +15 -1
  47. package/dist/error-codes.js +20 -1
  48. package/dist/index.d.ts +9 -8
  49. package/dist/index.js +5 -4
  50. package/dist/inspector.d.ts +2 -2
  51. package/dist/inspector.js +95 -15
  52. package/dist/schema-generator.d.ts +1 -0
  53. package/dist/schema-generator.js +1 -0
  54. package/dist/types-map.js +10 -1
  55. package/dist/types.d.ts +180 -50
  56. package/dist/utils/compute-required-schemas.d.ts +4 -0
  57. package/dist/utils/compute-required-schemas.js +40 -0
  58. package/dist/utils/contract-hashes.d.ts +52 -0
  59. package/dist/utils/contract-hashes.js +269 -0
  60. package/dist/utils/custom-types-generator.d.ts +9 -0
  61. package/dist/utils/custom-types-generator.js +71 -0
  62. package/dist/utils/detect-schema-vendor.d.ts +22 -0
  63. package/dist/utils/detect-schema-vendor.js +76 -0
  64. package/dist/utils/does-type-extend-core-type.d.ts +1 -1
  65. package/dist/utils/ensure-function-metadata.d.ts +6 -3
  66. package/dist/utils/ensure-function-metadata.js +220 -6
  67. package/dist/utils/extract-function-name.d.ts +5 -16
  68. package/dist/utils/extract-function-name.js +86 -291
  69. package/dist/utils/extract-services.d.ts +2 -1
  70. package/dist/utils/extract-services.js +25 -1
  71. package/dist/utils/filter-inspector-state.d.ts +1 -1
  72. package/dist/utils/filter-inspector-state.js +107 -23
  73. package/dist/utils/filter-utils.d.ts +2 -2
  74. package/dist/utils/get-files-and-methods.d.ts +1 -1
  75. package/dist/utils/get-property-value.d.ts +6 -1
  76. package/dist/utils/get-property-value.js +28 -3
  77. package/dist/utils/hash.d.ts +2 -0
  78. package/dist/utils/hash.js +23 -0
  79. package/dist/utils/middleware.d.ts +9 -32
  80. package/dist/utils/middleware.js +80 -66
  81. package/dist/utils/permissions.d.ts +4 -4
  82. package/dist/utils/permissions.js +10 -10
  83. package/dist/utils/post-process.d.ts +11 -11
  84. package/dist/utils/post-process.js +247 -24
  85. package/dist/utils/resolve-addon-package.d.ts +16 -0
  86. package/dist/utils/resolve-addon-package.js +34 -0
  87. package/dist/utils/resolve-function-types.d.ts +6 -0
  88. package/dist/utils/resolve-function-types.js +29 -0
  89. package/dist/utils/resolve-identifier.d.ts +10 -0
  90. package/dist/utils/resolve-identifier.js +36 -0
  91. package/dist/utils/resolve-versions.d.ts +2 -0
  92. package/dist/utils/resolve-versions.js +78 -0
  93. package/dist/utils/schema-generator.d.ts +9 -0
  94. package/dist/utils/schema-generator.js +209 -0
  95. package/dist/utils/serialize-inspector-state.d.ts +70 -23
  96. package/dist/utils/serialize-inspector-state.js +98 -22
  97. package/dist/utils/serialize-mcp-json.d.ts +2 -0
  98. package/dist/utils/serialize-mcp-json.js +99 -0
  99. package/dist/utils/serialize-middleware-groups-meta.d.ts +12 -0
  100. package/dist/utils/serialize-middleware-groups-meta.js +28 -0
  101. package/dist/utils/serialize-openapi-json.d.ts +85 -0
  102. package/dist/utils/serialize-openapi-json.js +151 -0
  103. package/dist/utils/serialize-permissions-groups-meta.d.ts +6 -0
  104. package/dist/utils/serialize-permissions-groups-meta.js +31 -0
  105. package/dist/utils/validate-auth-sessionless.d.ts +3 -0
  106. package/dist/utils/validate-auth-sessionless.js +14 -0
  107. package/dist/utils/workflow/dsl/deserialize-dsl-workflow.js +34 -102
  108. package/dist/utils/workflow/dsl/extract-dsl-workflow.d.ts +1 -1
  109. package/dist/utils/workflow/dsl/extract-dsl-workflow.js +23 -4
  110. package/dist/utils/workflow/graph/convert-dsl-to-graph.js +12 -10
  111. package/dist/utils/workflow/graph/finalize-workflow-wires.d.ts +3 -0
  112. package/dist/utils/workflow/graph/finalize-workflow-wires.js +276 -0
  113. package/dist/utils/workflow/graph/finalize-workflows.d.ts +2 -0
  114. package/dist/utils/workflow/graph/finalize-workflows.js +75 -0
  115. package/dist/utils/workflow/graph/index.d.ts +2 -0
  116. package/dist/utils/workflow/graph/index.js +2 -0
  117. package/dist/utils/workflow/graph/serialize-workflow-graph.d.ts +0 -8
  118. package/dist/utils/workflow/graph/serialize-workflow-graph.js +1 -3
  119. package/dist/utils/workflow/graph/workflow-graph.types.d.ts +53 -79
  120. package/dist/utils/workflow/graph/workflow-graph.types.js +1 -1
  121. package/dist/visit.d.ts +1 -1
  122. package/dist/visit.js +13 -6
  123. package/package.json +14 -4
  124. package/src/add/add-ai-agent.ts +468 -0
  125. package/src/add/add-channel.ts +103 -79
  126. package/src/add/add-cli.ts +68 -24
  127. package/src/add/add-file-extends-core-type.ts +1 -1
  128. package/src/add/add-file-with-config.ts +1 -1
  129. package/src/add/add-file-with-factory.ts +3 -1
  130. package/src/add/add-functions.ts +349 -103
  131. package/src/add/add-http-route.ts +263 -89
  132. package/src/add/add-http-routes.ts +229 -0
  133. package/src/add/add-keyed-wiring.ts +151 -0
  134. package/src/add/add-mcp-prompt.ts +27 -16
  135. package/src/add/add-mcp-resource.ts +28 -16
  136. package/src/add/add-middleware.ts +482 -80
  137. package/src/add/add-permission.ts +199 -40
  138. package/src/add/add-queue-worker.ts +25 -20
  139. package/src/add/add-rpc-invocations.ts +28 -11
  140. package/src/add/add-schedule.ts +17 -12
  141. package/src/add/add-secret.ts +140 -0
  142. package/src/add/add-trigger.ts +154 -0
  143. package/src/add/add-variable.ts +9 -0
  144. package/src/add/add-wire-addon.ts +80 -0
  145. package/src/add/add-workflow-graph.ts +180 -522
  146. package/src/add/add-workflow.ts +7 -6
  147. package/src/error-codes.ts +25 -1
  148. package/src/index.ts +23 -13
  149. package/src/inspector.ts +139 -19
  150. package/src/schema-generator.ts +1 -0
  151. package/src/types-map.ts +12 -1
  152. package/src/types.ts +199 -69
  153. package/src/utils/compute-required-schemas.ts +48 -0
  154. package/src/utils/contract-hashes.test.ts +553 -0
  155. package/src/utils/contract-hashes.ts +386 -0
  156. package/src/utils/custom-types-generator.ts +88 -0
  157. package/src/utils/detect-schema-vendor.ts +90 -0
  158. package/src/utils/does-type-extend-core-type.ts +1 -1
  159. package/src/utils/ensure-function-metadata.ts +325 -8
  160. package/src/utils/extract-function-name.ts +101 -351
  161. package/src/utils/extract-services.ts +35 -2
  162. package/src/utils/filter-inspector-state.test.ts +37 -25
  163. package/src/utils/filter-inspector-state.ts +146 -32
  164. package/src/utils/filter-utils.test.ts +1 -1
  165. package/src/utils/filter-utils.ts +2 -2
  166. package/src/utils/get-files-and-methods.ts +1 -1
  167. package/src/utils/get-property-value.ts +42 -4
  168. package/src/utils/hash.ts +26 -0
  169. package/src/utils/middleware.test.ts +204 -0
  170. package/src/utils/middleware.ts +131 -69
  171. package/src/utils/permissions.test.ts +35 -12
  172. package/src/utils/permissions.ts +12 -12
  173. package/src/utils/post-process.ts +306 -44
  174. package/src/utils/resolve-addon-package.ts +49 -0
  175. package/src/utils/resolve-function-types.ts +42 -0
  176. package/src/utils/resolve-identifier.ts +46 -0
  177. package/src/utils/resolve-versions.test.ts +249 -0
  178. package/src/utils/resolve-versions.ts +105 -0
  179. package/src/utils/schema-generator.ts +329 -0
  180. package/src/utils/serialize-inspector-state.ts +184 -43
  181. package/src/utils/serialize-mcp-json.ts +145 -0
  182. package/src/utils/serialize-middleware-groups-meta.ts +33 -0
  183. package/src/utils/serialize-openapi-json.ts +277 -0
  184. package/src/utils/serialize-permissions-groups-meta.ts +35 -0
  185. package/src/utils/test-data/inspector-state.json +69 -66
  186. package/src/utils/validate-auth-sessionless.ts +29 -0
  187. package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +43 -119
  188. package/src/utils/workflow/dsl/extract-dsl-workflow.ts +26 -6
  189. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +17 -10
  190. package/src/utils/workflow/graph/finalize-workflow-wires.ts +310 -0
  191. package/src/utils/workflow/graph/finalize-workflows.ts +100 -0
  192. package/src/utils/workflow/graph/index.ts +5 -0
  193. package/src/utils/workflow/graph/serialize-workflow-graph.ts +1 -8
  194. package/src/utils/workflow/graph/workflow-graph.types.ts +29 -78
  195. package/src/visit.ts +19 -7
  196. package/tsconfig.tsbuildinfo +1 -1
  197. package/dist/add/add-forge-credential.d.ts +0 -8
  198. package/dist/add/add-forge-credential.js +0 -77
  199. package/dist/add/add-forge-node.d.ts +0 -7
  200. package/dist/add/add-forge-node.js +0 -77
  201. package/dist/add/add-mcp-tool.d.ts +0 -2
  202. package/dist/add/add-mcp-tool.js +0 -81
  203. package/dist/utils/extract-service-metadata.d.ts +0 -19
  204. package/dist/utils/extract-service-metadata.js +0 -244
  205. package/dist/utils/write-service-metadata.d.ts +0 -13
  206. package/dist/utils/write-service-metadata.js +0 -37
  207. package/src/add/add-forge-credential.ts +0 -119
  208. package/src/add/add-forge-node.ts +0 -132
  209. package/src/add/add-mcp-tool.ts +0 -141
  210. package/src/utils/extract-service-metadata.ts +0 -353
  211. package/src/utils/write-service-metadata.ts +0 -51
@@ -0,0 +1,269 @@
1
+ import { parseVersionedId } from '@pikku/core';
2
+ import { ErrorCode } from '../error-codes.js';
3
+ import { canonicalJSON, hashString } from './hash.js';
4
+ function isHashEntry(v) {
5
+ return typeof v === 'object';
6
+ }
7
+ export function createEmptyManifest() {
8
+ return {
9
+ manifestVersion: 1,
10
+ contracts: {},
11
+ };
12
+ }
13
+ export function serializeManifest(manifest) {
14
+ const sortedContracts = {};
15
+ for (const key of Object.keys(manifest.contracts).sort()) {
16
+ const entry = manifest.contracts[key];
17
+ const sortedVersions = {};
18
+ const numericKeys = Object.keys(entry.versions)
19
+ .map(Number)
20
+ .sort((a, b) => a - b);
21
+ for (const vk of numericKeys) {
22
+ sortedVersions[String(vk)] = entry.versions[String(vk)];
23
+ }
24
+ sortedContracts[key] = {
25
+ latest: entry.latest,
26
+ versions: sortedVersions,
27
+ };
28
+ }
29
+ const sorted = {
30
+ manifestVersion: manifest.manifestVersion,
31
+ contracts: sortedContracts,
32
+ };
33
+ return JSON.stringify(sorted, null, 2) + '\n';
34
+ }
35
+ export function computeContractHash(data) {
36
+ return hashString(canonicalJSON(data), 16);
37
+ }
38
+ function computeInputHash(functionKey, inputSchema) {
39
+ return hashString(canonicalJSON({ functionKey, inputSchema }), 8);
40
+ }
41
+ function computeOutputHash(functionKey, outputSchema) {
42
+ return hashString(canonicalJSON({ functionKey, outputSchema }), 8);
43
+ }
44
+ function resolveSchema(typeNames, allSchemas, typesMap) {
45
+ if (!typeNames) {
46
+ return null;
47
+ }
48
+ const filtered = typeNames.filter((n) => n !== 'void');
49
+ if (filtered.length === 0) {
50
+ return null;
51
+ }
52
+ const parts = [];
53
+ for (const name of filtered) {
54
+ let key;
55
+ try {
56
+ key = typesMap.getUniqueName(name);
57
+ }
58
+ catch {
59
+ key = name;
60
+ }
61
+ const schema = allSchemas[key];
62
+ if (schema) {
63
+ parts.push(schema);
64
+ }
65
+ }
66
+ if (parts.length === 0) {
67
+ return null;
68
+ }
69
+ return parts.length === 1 ? parts[0] : parts;
70
+ }
71
+ export function buildCurrentContracts(functionsMeta, allSchemas, typesMap) {
72
+ const result = new Map();
73
+ for (const [funcId, meta] of Object.entries(functionsMeta)) {
74
+ if (meta.remote === true) {
75
+ continue;
76
+ }
77
+ const parsed = parseVersionedId(funcId);
78
+ const functionKey = parsed.baseName;
79
+ const version = parsed.version ?? meta.version ?? 1;
80
+ const inputSchema = resolveSchema(meta.inputs, allSchemas, typesMap);
81
+ const outputSchema = resolveSchema(meta.outputs, allSchemas, typesMap);
82
+ const contractHash = computeContractHash({
83
+ functionKey,
84
+ inputSchema,
85
+ outputSchema,
86
+ });
87
+ const inputHash = computeInputHash(functionKey, inputSchema);
88
+ const outputHash = computeOutputHash(functionKey, outputSchema);
89
+ result.set(funcId, {
90
+ functionKey,
91
+ version,
92
+ contractHash,
93
+ inputHash,
94
+ outputHash,
95
+ });
96
+ }
97
+ return result;
98
+ }
99
+ export function computeContractHashes(allSchemas, typesMap, functionsMeta) {
100
+ const contracts = buildCurrentContracts(functionsMeta, allSchemas, typesMap);
101
+ for (const [funcId, entry] of contracts) {
102
+ const meta = functionsMeta[funcId];
103
+ if (meta) {
104
+ meta.contractHash = entry.contractHash;
105
+ meta.inputHash = entry.inputHash;
106
+ meta.outputHash = entry.outputHash;
107
+ }
108
+ }
109
+ return contracts;
110
+ }
111
+ function groupByFunctionKey(contracts) {
112
+ const grouped = new Map();
113
+ for (const entry of contracts.values()) {
114
+ const existing = grouped.get(entry.functionKey) ?? [];
115
+ existing.push(entry);
116
+ grouped.set(entry.functionKey, existing);
117
+ }
118
+ return grouped;
119
+ }
120
+ function entryChanged(existing, current) {
121
+ if (isHashEntry(existing)) {
122
+ return (existing.inputHash !== current.inputHash ||
123
+ existing.outputHash !== current.outputHash);
124
+ }
125
+ return existing !== current.contractHash;
126
+ }
127
+ export function validateContracts(manifest, currentContracts) {
128
+ const errors = [];
129
+ const grouped = groupByFunctionKey(currentContracts);
130
+ const reportedKeys = new Set();
131
+ for (const [functionKey, entries] of grouped) {
132
+ const manifestEntry = manifest.contracts[functionKey];
133
+ if (!manifestEntry) {
134
+ continue;
135
+ }
136
+ for (const current of entries) {
137
+ const { version, contractHash, inputHash, outputHash } = current;
138
+ const existingEntry = manifestEntry.versions[String(version)];
139
+ if (existingEntry !== undefined) {
140
+ if (entryChanged(existingEntry, current)) {
141
+ reportedKeys.add(`${functionKey}@${version}`);
142
+ const prevInputHash = isHashEntry(existingEntry)
143
+ ? existingEntry.inputHash
144
+ : existingEntry;
145
+ const prevOutputHash = isHashEntry(existingEntry)
146
+ ? existingEntry.outputHash
147
+ : existingEntry;
148
+ errors.push({
149
+ code: ErrorCode.FUNCTION_VERSION_MODIFIED,
150
+ message: `Contract for ${functionKey}@v${version} has changed (recorded: ${isHashEntry(existingEntry) ? `${existingEntry.inputHash}/${existingEntry.outputHash}` : existingEntry}, current: ${contractHash}). Existing versions are immutable.`,
151
+ functionKey,
152
+ version,
153
+ previousHash: isHashEntry(existingEntry)
154
+ ? existingEntry.inputHash
155
+ : existingEntry,
156
+ currentHash: contractHash,
157
+ previousInputHash: prevInputHash,
158
+ currentInputHash: inputHash,
159
+ previousOutputHash: prevOutputHash,
160
+ currentOutputHash: outputHash,
161
+ });
162
+ }
163
+ }
164
+ else {
165
+ if (version <= manifestEntry.latest) {
166
+ errors.push({
167
+ code: ErrorCode.VERSION_REGRESSION_OR_CONFLICT,
168
+ message: `Version ${version} for ${functionKey} is <= latest (${manifestEntry.latest}) but not recorded. Possible merge conflict.`,
169
+ functionKey,
170
+ version,
171
+ latestVersion: manifestEntry.latest,
172
+ });
173
+ }
174
+ else if (version > manifestEntry.latest + 1) {
175
+ errors.push({
176
+ code: ErrorCode.VERSION_GAP_NOT_ALLOWED,
177
+ message: `Version ${version} for ${functionKey} skips versions. Latest is ${manifestEntry.latest}, next must be ${manifestEntry.latest + 1}.`,
178
+ functionKey,
179
+ version,
180
+ latestVersion: manifestEntry.latest,
181
+ expectedNextVersion: manifestEntry.latest + 1,
182
+ });
183
+ }
184
+ }
185
+ }
186
+ }
187
+ for (const [functionKey, manifestEntry] of Object.entries(manifest.contracts)) {
188
+ const latestEntry = manifestEntry.versions[String(manifestEntry.latest)];
189
+ const currentEntries = grouped.get(functionKey);
190
+ if (!currentEntries) {
191
+ continue;
192
+ }
193
+ const currentLatest = currentEntries.find((e) => e.version === manifestEntry.latest);
194
+ if (currentLatest &&
195
+ entryChanged(latestEntry, currentLatest) &&
196
+ !reportedKeys.has(`${functionKey}@${manifestEntry.latest}`)) {
197
+ const prevInputHash = isHashEntry(latestEntry)
198
+ ? latestEntry.inputHash
199
+ : undefined;
200
+ const prevOutputHash = isHashEntry(latestEntry)
201
+ ? latestEntry.outputHash
202
+ : undefined;
203
+ errors.push({
204
+ code: ErrorCode.CONTRACT_CHANGED_REQUIRES_BUMP,
205
+ message: `Contract for ${functionKey} changed. Set \`version: ${manifestEntry.latest + 1}\` on the function or run 'pikku versions update'.`,
206
+ functionKey,
207
+ previousInputHash: prevInputHash,
208
+ currentInputHash: currentLatest.inputHash,
209
+ previousOutputHash: prevOutputHash,
210
+ currentOutputHash: currentLatest.outputHash,
211
+ nextVersion: manifestEntry.latest + 1,
212
+ });
213
+ }
214
+ }
215
+ for (const [functionKey, manifestEntry] of Object.entries(manifest.contracts)) {
216
+ const numericKeys = Object.keys(manifestEntry.versions).map(Number);
217
+ if (numericKeys.length === 0) {
218
+ continue;
219
+ }
220
+ const maxVersion = Math.max(...numericKeys);
221
+ if (manifestEntry.latest !== maxVersion) {
222
+ errors.push({
223
+ code: ErrorCode.MANIFEST_INTEGRITY_ERROR,
224
+ message: `Manifest integrity error for ${functionKey}: latest field (${manifestEntry.latest}) inconsistent with version keys (max: ${maxVersion}).`,
225
+ functionKey,
226
+ latestVersion: manifestEntry.latest,
227
+ expectedNextVersion: maxVersion,
228
+ });
229
+ }
230
+ }
231
+ return { valid: errors.length === 0, errors };
232
+ }
233
+ export function updateManifest(existing, currentContracts) {
234
+ const manifest = {
235
+ manifestVersion: existing.manifestVersion,
236
+ contracts: JSON.parse(JSON.stringify(existing.contracts)),
237
+ };
238
+ const grouped = groupByFunctionKey(currentContracts);
239
+ for (const [functionKey, entries] of grouped) {
240
+ if (!manifest.contracts[functionKey]) {
241
+ manifest.contracts[functionKey] = { latest: 0, versions: {} };
242
+ }
243
+ const entry = manifest.contracts[functionKey];
244
+ for (const { version, inputHash, outputHash } of entries) {
245
+ entry.versions[String(version)] = { inputHash, outputHash };
246
+ entry.latest = Math.max(entry.latest, version);
247
+ }
248
+ }
249
+ return manifest;
250
+ }
251
+ export function extractContractsFromMeta(functionsMeta) {
252
+ const result = new Map();
253
+ for (const [funcId, meta] of Object.entries(functionsMeta)) {
254
+ if (meta.remote === true || !meta.contractHash) {
255
+ continue;
256
+ }
257
+ const parsed = parseVersionedId(funcId);
258
+ const functionKey = parsed.baseName;
259
+ const version = parsed.version ?? meta.version ?? 1;
260
+ result.set(funcId, {
261
+ functionKey,
262
+ version,
263
+ contractHash: meta.contractHash,
264
+ inputHash: meta.inputHash ?? '',
265
+ outputHash: meta.outputHash ?? '',
266
+ });
267
+ }
268
+ return result;
269
+ }
@@ -0,0 +1,9 @@
1
+ import type { 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
+ }
@@ -0,0 +1,22 @@
1
+ import type * as ts from 'typescript';
2
+ import type { SchemaVendor, InspectorLogger } from '../types.js';
3
+ /**
4
+ * Detect the schema vendor by tracing the type back to its library origin.
5
+ * This handles locally-defined schemas like `export const MySchema = z.object({...})`
6
+ * by checking where the type itself originates from.
7
+ *
8
+ * Supports multiple schema libraries in the same project (e.g., during migration
9
+ * from one library to another).
10
+ */
11
+ export declare const detectSchemaVendor: (identifier: ts.Identifier, checker: ts.TypeChecker) => SchemaVendor;
12
+ /**
13
+ * Detect schema vendor and log a fatal error if unknown.
14
+ * Returns the vendor if successful, or undefined if unknown (after logging error).
15
+ *
16
+ * @param identifier - The TypeScript identifier for the schema variable
17
+ * @param checker - TypeScript type checker
18
+ * @param logger - Inspector logger for error reporting
19
+ * @param context - Description of what the schema is for (e.g., "Credential 'myCredential'")
20
+ * @param sourceFile - Source file path for error message
21
+ */
22
+ export declare const detectSchemaVendorOrError: (identifier: ts.Identifier, checker: ts.TypeChecker, logger: InspectorLogger, context: string, sourceFile: string) => Exclude<SchemaVendor, "unknown"> | undefined;
@@ -0,0 +1,76 @@
1
+ import { ErrorCode } from '../error-codes.js';
2
+ /**
3
+ * Detect the schema vendor by tracing the type back to its library origin.
4
+ * This handles locally-defined schemas like `export const MySchema = z.object({...})`
5
+ * by checking where the type itself originates from.
6
+ *
7
+ * Supports multiple schema libraries in the same project (e.g., during migration
8
+ * from one library to another).
9
+ */
10
+ export const detectSchemaVendor = (identifier, checker) => {
11
+ const type = checker.getTypeAtLocation(identifier);
12
+ if (!type)
13
+ return 'unknown';
14
+ // Check the type's symbol declarations to find the library origin
15
+ const checkTypeOrigin = (t) => {
16
+ const symbol = t.getSymbol() || t.aliasSymbol;
17
+ if (symbol) {
18
+ const decls = symbol.getDeclarations();
19
+ if (decls) {
20
+ for (const decl of decls) {
21
+ const fileName = decl.getSourceFile().fileName;
22
+ if (fileName.includes('node_modules/zod'))
23
+ return 'zod';
24
+ if (fileName.includes('node_modules/valibot'))
25
+ return 'valibot';
26
+ if (fileName.includes('node_modules/arktype'))
27
+ return 'arktype';
28
+ if (fileName.includes('node_modules/@effect/schema'))
29
+ return 'effect';
30
+ }
31
+ }
32
+ }
33
+ // Check base types for class/interface hierarchies
34
+ const baseTypes = t.getBaseTypes?.();
35
+ if (baseTypes) {
36
+ for (const baseType of baseTypes) {
37
+ const result = checkTypeOrigin(baseType);
38
+ if (result)
39
+ return result;
40
+ }
41
+ }
42
+ return null;
43
+ };
44
+ const vendor = checkTypeOrigin(type);
45
+ if (vendor)
46
+ return vendor;
47
+ // Fallback: check type arguments (for generic types like z.ZodObject<...>)
48
+ if (type.typeArguments) {
49
+ for (const arg of type.typeArguments || []) {
50
+ const result = checkTypeOrigin(arg);
51
+ if (result)
52
+ return result;
53
+ }
54
+ }
55
+ return 'unknown';
56
+ };
57
+ /**
58
+ * Detect schema vendor and log a fatal error if unknown.
59
+ * Returns the vendor if successful, or undefined if unknown (after logging error).
60
+ *
61
+ * @param identifier - The TypeScript identifier for the schema variable
62
+ * @param checker - TypeScript type checker
63
+ * @param logger - Inspector logger for error reporting
64
+ * @param context - Description of what the schema is for (e.g., "Credential 'myCredential'")
65
+ * @param sourceFile - Source file path for error message
66
+ */
67
+ export const detectSchemaVendorOrError = (identifier, checker, logger, context, sourceFile) => {
68
+ const vendor = detectSchemaVendor(identifier, checker);
69
+ if (vendor === 'unknown') {
70
+ logger.critical(ErrorCode.INLINE_SCHEMA, `${context} schema vendor could not be determined from '${sourceFile}'. ` +
71
+ `Supported vendors: zod, valibot, arktype, @effect/schema. ` +
72
+ `Ensure your schema is imported from a supported validation library.`);
73
+ return undefined;
74
+ }
75
+ return vendor;
76
+ };
@@ -1,2 +1,2 @@
1
- import * as ts from 'typescript';
1
+ import type * as ts from 'typescript';
2
2
  export declare const doesTypeExtendsCore: (type: ts.Type, checker: ts.TypeChecker, visitedTypes: Set<ts.Type>, coreType: string) => boolean;
@@ -1,6 +1,9 @@
1
- import { InspectorState } from '../types.js';
1
+ import * as ts from 'typescript';
2
+ import type { InspectorState } from '../types.js';
2
3
  /**
3
- * Ensures that function metadata exists for a given pikkuFuncName.
4
+ * Ensures that function metadata exists for a given pikkuFuncId.
4
5
  * Creates stub metadata if it doesn't exist (useful for inline functions).
6
+ * When funcInitializer and checker are provided, resolves types and
7
+ * extracts tags/middleware/permissions from the pikkuFunc() config.
5
8
  */
6
- export declare function ensureFunctionMetadata(state: InspectorState, pikkuFuncName: string, fallbackName?: string): void;
9
+ export declare function ensureFunctionMetadata(state: InspectorState, pikkuFuncId: string, fallbackName?: string, funcInitializer?: ts.Node, checker?: ts.TypeChecker, isHelper?: boolean): void;