@pikku/inspector 0.12.6 → 0.12.8
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 +28 -0
- package/dist/add/add-ai-agent.js +24 -7
- package/dist/add/add-channel.js +2 -2
- package/dist/add/add-cli.js +13 -10
- package/dist/add/add-file-with-factory.js +22 -5
- package/dist/add/add-functions.js +2 -0
- package/dist/add/add-http-route.js +1 -0
- package/dist/add/add-rpc-invocations.js +2 -2
- package/dist/add/add-workflow.d.ts +5 -0
- package/dist/add/add-workflow.js +19 -1
- package/dist/inspector.js +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/utils/filter-inspector-state.js +204 -5
- package/dist/utils/load-addon-functions-meta.js +47 -0
- package/dist/utils/post-process.js +63 -0
- package/dist/utils/schema-generator.js +124 -33
- package/dist/utils/serialize-inspector-state.d.ts +1 -0
- package/dist/utils/serialize-inspector-state.js +2 -0
- package/dist/visit.js +1 -1
- package/package.json +2 -2
- package/src/add/add-ai-agent.ts +25 -10
- package/src/add/add-channel.ts +2 -2
- package/src/add/add-cli.ts +17 -16
- package/src/add/add-file-with-factory.ts +26 -7
- package/src/add/add-functions.ts +2 -0
- package/src/add/add-http-route.ts +6 -1
- package/src/add/add-queue-worker.ts +5 -1
- package/src/add/add-rpc-invocations.ts +2 -2
- package/src/add/add-workflow.ts +21 -1
- package/src/inspector.ts +1 -0
- package/src/types.ts +1 -0
- package/src/utils/filter-inspector-state.ts +239 -8
- package/src/utils/load-addon-functions-meta.ts +59 -0
- package/src/utils/post-process.ts +74 -0
- package/src/utils/schema-generator.ts +191 -41
- package/src/utils/serialize-inspector-state.ts +3 -0
- package/src/visit.ts +2 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as ts from 'typescript'
|
|
2
2
|
import { dirname, join, resolve } from 'path'
|
|
3
3
|
import { createGenerator, RootlessError } from 'ts-json-schema-generator'
|
|
4
|
-
import { tsImport } from 'tsx/esm/api'
|
|
4
|
+
import { register, tsImport } from 'tsx/esm/api'
|
|
5
5
|
import * as z from 'zod'
|
|
6
6
|
import { zodToTs, createAuxiliaryTypeStore } from 'zod-to-ts'
|
|
7
7
|
import type { FunctionsMeta, JSONValue } from '@pikku/core'
|
|
@@ -60,6 +60,10 @@ function primitiveTypeToSchema(typeStr: string): JSONValue | null {
|
|
|
60
60
|
return { type: 'null' }
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
if (normalized === 'any' || normalized === 'unknown') {
|
|
64
|
+
return {}
|
|
65
|
+
}
|
|
66
|
+
|
|
63
67
|
return null
|
|
64
68
|
}
|
|
65
69
|
|
|
@@ -145,7 +149,7 @@ function generateTSSchemas(
|
|
|
145
149
|
httpWiringsMeta: HTTPWiringsMeta,
|
|
146
150
|
additionalTypes?: string[],
|
|
147
151
|
additionalProperties: boolean = false,
|
|
148
|
-
|
|
152
|
+
generatedZodSchemas?: Record<string, JSONValue>
|
|
149
153
|
): Record<string, JSONValue> {
|
|
150
154
|
const schemasSet = new Set(typesMap.customTypes.keys())
|
|
151
155
|
for (const { inputs, outputs } of Object.values(functionMeta)) {
|
|
@@ -182,6 +186,19 @@ function generateTSSchemas(
|
|
|
182
186
|
}
|
|
183
187
|
}
|
|
184
188
|
|
|
189
|
+
// Skip ts-json-schema-generator if all schemas are already covered by Zod/primitives.
|
|
190
|
+
// Use generatedZodSchemas (actually converted) rather than schemaLookup (all attempted)
|
|
191
|
+
// so that failed Zod conversions fall through to TS schema generation.
|
|
192
|
+
const uncoveredSchemas = [...schemasSet].filter(
|
|
193
|
+
(s) => !PRIMITIVE_TYPES.has(s) && !generatedZodSchemas?.[s]
|
|
194
|
+
)
|
|
195
|
+
if (uncoveredSchemas.length === 0) {
|
|
196
|
+
return {}
|
|
197
|
+
}
|
|
198
|
+
logger.debug(
|
|
199
|
+
`generateTSSchemas needed for ${uncoveredSchemas.length} types: ${uncoveredSchemas.slice(0, 3).join(', ')}${uncoveredSchemas.length > 3 ? '...' : ''}`
|
|
200
|
+
)
|
|
201
|
+
|
|
185
202
|
const virtualFilePath = join(
|
|
186
203
|
dirname(resolve(tsconfig)),
|
|
187
204
|
'__pikku_virtual_types__.ts'
|
|
@@ -210,7 +227,7 @@ function generateTSSchemas(
|
|
|
210
227
|
if (PRIMITIVE_TYPES.has(schema)) {
|
|
211
228
|
return
|
|
212
229
|
}
|
|
213
|
-
if (
|
|
230
|
+
if (generatedZodSchemas?.[schema]) {
|
|
214
231
|
return
|
|
215
232
|
}
|
|
216
233
|
try {
|
|
@@ -236,6 +253,97 @@ function generateTSSchemas(
|
|
|
236
253
|
return schemas
|
|
237
254
|
}
|
|
238
255
|
|
|
256
|
+
/**
|
|
257
|
+
* Import all source files in parallel using tsx's register() API.
|
|
258
|
+
*
|
|
259
|
+
* tsx's register() sets up the TypeScript loader once, then all subsequent
|
|
260
|
+
* import() calls reuse that loader. This is dramatically faster than calling
|
|
261
|
+
* tsImport() per-file because tsImport() sets up and tears down a fresh
|
|
262
|
+
* compilation context for each call (~170ms each).
|
|
263
|
+
*
|
|
264
|
+
* With register() + parallel import():
|
|
265
|
+
* - 71 files: ~350ms total
|
|
266
|
+
* - vs tsImport loop: ~12,000ms (71 * 170ms)
|
|
267
|
+
*
|
|
268
|
+
* Falls back to serial tsImport() per-file if register() is unavailable.
|
|
269
|
+
*/
|
|
270
|
+
async function batchImportWithRegister(
|
|
271
|
+
logger: InspectorLogger,
|
|
272
|
+
sourceFiles: string[]
|
|
273
|
+
): Promise<Map<string, Record<string, any>> | null> {
|
|
274
|
+
if (sourceFiles.length === 0) return new Map()
|
|
275
|
+
|
|
276
|
+
let unregister: (() => void) | undefined
|
|
277
|
+
try {
|
|
278
|
+
unregister = register()
|
|
279
|
+
|
|
280
|
+
const modules = new Map<string, Record<string, any>>()
|
|
281
|
+
const results = await Promise.allSettled(
|
|
282
|
+
sourceFiles.map(async (srcPath) => {
|
|
283
|
+
const mod = await import(srcPath)
|
|
284
|
+
modules.set(srcPath, mod)
|
|
285
|
+
})
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
const failures = results.filter((r) => r.status === 'rejected')
|
|
289
|
+
if (failures.length > 0) {
|
|
290
|
+
logger.debug(
|
|
291
|
+
`${failures.length}/${sourceFiles.length} files failed to import via register()`
|
|
292
|
+
)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return modules
|
|
296
|
+
} catch (e) {
|
|
297
|
+
logger.debug(`tsx register() batch import failed: ${(e as Error).message}`)
|
|
298
|
+
return null
|
|
299
|
+
} finally {
|
|
300
|
+
unregister?.()
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function processZodSchema(
|
|
305
|
+
schemaName: string,
|
|
306
|
+
zodSchema: any,
|
|
307
|
+
schemas: Record<string, JSONValue>,
|
|
308
|
+
typesMap: TypesMap,
|
|
309
|
+
auxiliaryTypeStore: ReturnType<typeof createAuxiliaryTypeStore>,
|
|
310
|
+
printer: ts.Printer,
|
|
311
|
+
fakeSourceFile: ts.SourceFile,
|
|
312
|
+
logger: InspectorLogger
|
|
313
|
+
): void {
|
|
314
|
+
const schema = z.toJSONSchema(zodSchema, {
|
|
315
|
+
unrepresentable: 'any',
|
|
316
|
+
override: ({ zodSchema, jsonSchema }) => {
|
|
317
|
+
if ((zodSchema as any)._zod?.def?.type === 'date') {
|
|
318
|
+
;(jsonSchema as any).type = 'string'
|
|
319
|
+
;(jsonSchema as any).format = 'date-time'
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
}) as any
|
|
323
|
+
|
|
324
|
+
if (schema.required && schema.properties) {
|
|
325
|
+
schema.required = schema.required.filter((fieldName: string) => {
|
|
326
|
+
const prop = schema.properties[fieldName]
|
|
327
|
+
return prop && prop.default === undefined
|
|
328
|
+
})
|
|
329
|
+
if (schema.required.length === 0) {
|
|
330
|
+
delete schema.required
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const { node: tsType } = zodToTs(zodSchema, { auxiliaryTypeStore })
|
|
335
|
+
|
|
336
|
+
const typeText = printer.printNode(
|
|
337
|
+
ts.EmitHint.Unspecified,
|
|
338
|
+
tsType,
|
|
339
|
+
fakeSourceFile
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
typesMap.addCustomType(schemaName, typeText, [])
|
|
343
|
+
schemas[schemaName] = schema
|
|
344
|
+
logger.debug(`• Generated schema from Zod: ${schemaName}`)
|
|
345
|
+
}
|
|
346
|
+
|
|
239
347
|
async function generateZodSchemas(
|
|
240
348
|
logger: InspectorLogger,
|
|
241
349
|
schemaLookup: Map<string, SchemaRef>,
|
|
@@ -252,6 +360,7 @@ async function generateZodSchemas(
|
|
|
252
360
|
ts.ScriptKind.TS
|
|
253
361
|
)
|
|
254
362
|
|
|
363
|
+
// Validate all schemas are zod (or unspecified vendor)
|
|
255
364
|
for (const [schemaName, ref] of schemaLookup.entries()) {
|
|
256
365
|
if (ref.vendor && ref.vendor !== 'zod') {
|
|
257
366
|
throw new Error(
|
|
@@ -260,55 +369,96 @@ async function generateZodSchemas(
|
|
|
260
369
|
`Please use Zod or contribute support for ${ref.vendor}.`
|
|
261
370
|
)
|
|
262
371
|
}
|
|
372
|
+
}
|
|
263
373
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
374
|
+
// Collect unique source files and batch-import them in parallel
|
|
375
|
+
const uniqueSourceFiles = [
|
|
376
|
+
...new Set([...schemaLookup.values()].map((ref) => ref.sourceFile)),
|
|
377
|
+
]
|
|
378
|
+
console.log(
|
|
379
|
+
`[TIMING] Zod schemas: ${schemaLookup.size} schemas from ${uniqueSourceFiles.length} files`
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
const importStart = performance.now()
|
|
383
|
+
const importedModules = await batchImportWithRegister(
|
|
384
|
+
logger,
|
|
385
|
+
uniqueSourceFiles
|
|
386
|
+
)
|
|
387
|
+
console.log(
|
|
388
|
+
`[TIMING] Batch import: ${(performance.now() - importStart).toFixed(0)}ms`
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
const processStart = performance.now()
|
|
392
|
+
// Track schemas that need per-file tsImport fallback
|
|
393
|
+
const fallbackSchemas: [string, SchemaRef][] = []
|
|
394
|
+
|
|
395
|
+
for (const [schemaName, ref] of schemaLookup.entries()) {
|
|
396
|
+
const mod = importedModules?.get(ref.sourceFile)
|
|
397
|
+
if (mod) {
|
|
398
|
+
const zodSchema = mod[ref.variableName]
|
|
267
399
|
if (!zodSchema) {
|
|
268
400
|
logger.warn(
|
|
269
|
-
`Could not find exported schema '${ref.variableName}' in ${ref.sourceFile} for ${schemaName}. Available exports: ${Object.keys(
|
|
401
|
+
`Could not find exported schema '${ref.variableName}' in ${ref.sourceFile} for ${schemaName}. Available exports: ${Object.keys(mod).join(', ')}`
|
|
270
402
|
)
|
|
271
403
|
continue
|
|
272
404
|
}
|
|
405
|
+
try {
|
|
406
|
+
processZodSchema(
|
|
407
|
+
schemaName,
|
|
408
|
+
zodSchema,
|
|
409
|
+
schemas,
|
|
410
|
+
typesMap,
|
|
411
|
+
auxiliaryTypeStore,
|
|
412
|
+
printer,
|
|
413
|
+
fakeSourceFile,
|
|
414
|
+
logger
|
|
415
|
+
)
|
|
416
|
+
} catch (e) {
|
|
417
|
+
logger.warn(
|
|
418
|
+
`Could not convert Zod schema '${schemaName}': ${e instanceof Error ? e.message : e}`
|
|
419
|
+
)
|
|
420
|
+
}
|
|
421
|
+
} else {
|
|
422
|
+
fallbackSchemas.push([schemaName, ref])
|
|
423
|
+
}
|
|
424
|
+
}
|
|
273
425
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
})
|
|
289
|
-
if (schema.required.length === 0) {
|
|
290
|
-
delete schema.required
|
|
426
|
+
// Fallback: use tsImport for any schemas that batch import couldn't handle
|
|
427
|
+
if (fallbackSchemas.length > 0) {
|
|
428
|
+
logger.debug(
|
|
429
|
+
`Falling back to tsImport for ${fallbackSchemas.length} schema(s)`
|
|
430
|
+
)
|
|
431
|
+
for (const [schemaName, ref] of fallbackSchemas) {
|
|
432
|
+
try {
|
|
433
|
+
const module = await tsImport(ref.sourceFile, import.meta.url)
|
|
434
|
+
const zodSchema = module[ref.variableName]
|
|
435
|
+
if (!zodSchema) {
|
|
436
|
+
logger.warn(
|
|
437
|
+
`Could not find exported schema '${ref.variableName}' in ${ref.sourceFile} for ${schemaName}. Available exports: ${Object.keys(module).join(', ')}`
|
|
438
|
+
)
|
|
439
|
+
continue
|
|
291
440
|
}
|
|
441
|
+
processZodSchema(
|
|
442
|
+
schemaName,
|
|
443
|
+
zodSchema,
|
|
444
|
+
schemas,
|
|
445
|
+
typesMap,
|
|
446
|
+
auxiliaryTypeStore,
|
|
447
|
+
printer,
|
|
448
|
+
fakeSourceFile,
|
|
449
|
+
logger
|
|
450
|
+
)
|
|
451
|
+
} catch (e) {
|
|
452
|
+
logger.warn(
|
|
453
|
+
`Could not convert Zod schema '${schemaName}': ${e instanceof Error ? e.message : e}`
|
|
454
|
+
)
|
|
292
455
|
}
|
|
293
|
-
|
|
294
|
-
schemas[schemaName] = schema
|
|
295
|
-
const { node: tsType } = zodToTs(zodSchema, { auxiliaryTypeStore })
|
|
296
|
-
|
|
297
|
-
const typeText = printer.printNode(
|
|
298
|
-
ts.EmitHint.Unspecified,
|
|
299
|
-
tsType,
|
|
300
|
-
fakeSourceFile
|
|
301
|
-
)
|
|
302
|
-
|
|
303
|
-
typesMap.addCustomType(schemaName, typeText, [])
|
|
304
|
-
logger.debug(`• Generated schema from Zod: ${schemaName}`)
|
|
305
|
-
} catch (e) {
|
|
306
|
-
logger.warn(
|
|
307
|
-
`Could not convert Zod schema '${schemaName}': ${e instanceof Error ? e.message : e}`
|
|
308
|
-
)
|
|
309
456
|
}
|
|
310
457
|
}
|
|
311
458
|
|
|
459
|
+
console.log(
|
|
460
|
+
`[TIMING] Process schemas: ${(performance.now() - processStart).toFixed(0)}ms (${Object.keys(schemas).length} generated)`
|
|
461
|
+
)
|
|
312
462
|
return schemas
|
|
313
463
|
}
|
|
314
464
|
|
|
@@ -347,7 +497,7 @@ export async function generateAllSchemas(
|
|
|
347
497
|
state.http.meta,
|
|
348
498
|
config.schemasFromTypes,
|
|
349
499
|
config.schema?.additionalProperties,
|
|
350
|
-
|
|
500
|
+
zodSchemas
|
|
351
501
|
)
|
|
352
502
|
|
|
353
503
|
cachedCustomTypesContent = customTypesContent
|
|
@@ -45,6 +45,7 @@ export interface SerializableInspectorState {
|
|
|
45
45
|
]
|
|
46
46
|
>
|
|
47
47
|
wireServicesMeta: Array<[string, string[]]>
|
|
48
|
+
addonRequiredParentServices: string[]
|
|
48
49
|
configFactories: Array<
|
|
49
50
|
[
|
|
50
51
|
string,
|
|
@@ -303,6 +304,7 @@ export function serializeInspectorState(
|
|
|
303
304
|
),
|
|
304
305
|
wireServicesFactories: Array.from(state.wireServicesFactories.entries()),
|
|
305
306
|
wireServicesMeta: Array.from(state.wireServicesMeta.entries()),
|
|
307
|
+
addonRequiredParentServices: state.addonRequiredParentServices,
|
|
306
308
|
configFactories: Array.from(state.configFactories.entries()),
|
|
307
309
|
filesAndMethods: state.filesAndMethods,
|
|
308
310
|
filesAndMethodsErrors: Array.from(
|
|
@@ -474,6 +476,7 @@ export function deserializeInspectorState(
|
|
|
474
476
|
singletonServicesFactories: new Map(data.singletonServicesFactories),
|
|
475
477
|
wireServicesFactories: new Map(data.wireServicesFactories),
|
|
476
478
|
wireServicesMeta: new Map(data.wireServicesMeta),
|
|
479
|
+
addonRequiredParentServices: data.addonRequiredParentServices || [],
|
|
477
480
|
configFactories: new Map(data.configFactories),
|
|
478
481
|
filesAndMethods: data.filesAndMethods,
|
|
479
482
|
filesAndMethodsErrors: new Map(
|