@pikku/inspector 0.12.75 → 0.12.81

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 (219) hide show
  1. package/CHANGELOG.md +330 -0
  2. package/dist/add/add-analytics.d.ts +9 -0
  3. package/dist/add/add-analytics.js +178 -0
  4. package/dist/add/add-auth.js +0 -54
  5. package/dist/add/add-feature-flag.d.ts +2 -0
  6. package/dist/add/add-feature-flag.js +162 -0
  7. package/dist/add/add-wire-addon.js +1 -0
  8. package/dist/add/add-wire-remote-addon.js +1 -0
  9. package/dist/index.d.ts +3 -1
  10. package/dist/index.js +3 -1
  11. package/dist/inspector.js +4 -0
  12. package/dist/surface/collect-surface.d.ts +58 -0
  13. package/dist/surface/collect-surface.js +613 -0
  14. package/dist/types.d.ts +20 -11
  15. package/dist/utils/filter-inspector-state.js +14 -0
  16. package/dist/utils/post-process.js +15 -0
  17. package/dist/utils/read-module-specifiers.d.ts +8 -0
  18. package/dist/utils/read-module-specifiers.js +23 -0
  19. package/dist/utils/read-tsconfig-out-dir.d.ts +5 -0
  20. package/dist/utils/read-tsconfig-out-dir.js +12 -0
  21. package/dist/utils/resolve-deploy-target.d.ts +7 -0
  22. package/dist/utils/resolve-deploy-target.js +15 -7
  23. package/dist/utils/serialize-inspector-state.d.ts +5 -0
  24. package/dist/utils/serialize-inspector-state.js +8 -0
  25. package/dist/visit.js +4 -0
  26. package/package.json +16 -6
  27. package/run-tests.sh +21 -6
  28. package/src/add/add-addon-bans.ts +0 -85
  29. package/src/add/add-agent-scorer.test.ts +0 -197
  30. package/src/add/add-agent-scorer.ts +0 -83
  31. package/src/add/add-agent.test.ts +0 -87
  32. package/src/add/add-agent.ts +0 -638
  33. package/src/add/add-approval-description.ts +0 -76
  34. package/src/add/add-auth.test.ts +0 -791
  35. package/src/add/add-auth.ts +0 -424
  36. package/src/add/add-channel.ts +0 -778
  37. package/src/add/add-cli-renderers.test.ts +0 -74
  38. package/src/add/add-cli.ts +0 -1006
  39. package/src/add/add-credential.ts +0 -186
  40. package/src/add/add-feature.test.ts +0 -306
  41. package/src/add/add-feature.ts +0 -253
  42. package/src/add/add-file-extends-core-type.ts +0 -66
  43. package/src/add/add-file-with-config.ts +0 -45
  44. package/src/add/add-file-with-factory.test.ts +0 -134
  45. package/src/add/add-file-with-factory.ts +0 -288
  46. package/src/add/add-functions.test.ts +0 -743
  47. package/src/add/add-functions.ts +0 -1548
  48. package/src/add/add-gateway.ts +0 -143
  49. package/src/add/add-http-route-ref.test.ts +0 -149
  50. package/src/add/add-http-route.ts +0 -530
  51. package/src/add/add-http-routes.ts +0 -471
  52. package/src/add/add-keyed-wiring.ts +0 -180
  53. package/src/add/add-mcp-prompt.ts +0 -157
  54. package/src/add/add-mcp-resource.ts +0 -175
  55. package/src/add/add-middleware.test.ts +0 -196
  56. package/src/add/add-middleware.ts +0 -879
  57. package/src/add/add-permission-auth.test.ts +0 -59
  58. package/src/add/add-permission.ts +0 -311
  59. package/src/add/add-personas.test.ts +0 -406
  60. package/src/add/add-personas.ts +0 -287
  61. package/src/add/add-queue-worker.ts +0 -117
  62. package/src/add/add-rpc-invocations.test.ts +0 -287
  63. package/src/add/add-rpc-invocations.ts +0 -221
  64. package/src/add/add-scenario-step.test.ts +0 -509
  65. package/src/add/add-schedule.ts +0 -120
  66. package/src/add/add-scope.test.ts +0 -419
  67. package/src/add/add-scope.ts +0 -221
  68. package/src/add/add-secret.ts +0 -10
  69. package/src/add/add-subject-scenario-steps.test.ts +0 -161
  70. package/src/add/add-system-role.test.ts +0 -297
  71. package/src/add/add-system-role.ts +0 -162
  72. package/src/add/add-trigger.ts +0 -165
  73. package/src/add/add-variable.ts +0 -10
  74. package/src/add/add-wire-addon.test.ts +0 -185
  75. package/src/add/add-wire-addon.ts +0 -146
  76. package/src/add/add-wire-remote-addon.ts +0 -80
  77. package/src/add/add-workflow-edge-cases.test.ts +0 -201
  78. package/src/add/add-workflow-fanout.test.ts +0 -166
  79. package/src/add/add-workflow-graph-foreach.test.ts +0 -174
  80. package/src/add/add-workflow-graph-input.test.ts +0 -94
  81. package/src/add/add-workflow-graph-notes.test.ts +0 -74
  82. package/src/add/add-workflow-graph.ts +0 -644
  83. package/src/add/add-workflow-on-error.test.ts +0 -118
  84. package/src/add/add-workflow-return-switch.test.ts +0 -121
  85. package/src/add/add-workflow-silent-drops.test.ts +0 -261
  86. package/src/add/add-workflow-sleep-expression.test.ts +0 -96
  87. package/src/add/add-workflow.test.ts +0 -155
  88. package/src/add/add-workflow.ts +0 -482
  89. package/src/add/addon-bans.test.ts +0 -121
  90. package/src/add/addon-contracts.test.ts +0 -221
  91. package/src/add/allow-escape-hatches.test.ts +0 -144
  92. package/src/add/audit-meta.test.ts +0 -75
  93. package/src/add/classified-sink-check.test.ts +0 -347
  94. package/src/add/config-value-metadata.test.ts +0 -263
  95. package/src/add/dynamic-import-check.test.ts +0 -119
  96. package/src/add/expect-eventually-scenario-only.test.ts +0 -108
  97. package/src/add/function-body-span.test.ts +0 -96
  98. package/src/add/inline-wiring-function.test.ts +0 -104
  99. package/src/add/pii-check.test.ts +0 -258
  100. package/src/add/rpc-type-cast.test.ts +0 -123
  101. package/src/add/scenario-instrumentation.test.ts +0 -89
  102. package/src/add/scenario-instrumentation.ts +0 -42
  103. package/src/add/scenario-marker.test.ts +0 -89
  104. package/src/add/scenario-not-extractable.test.ts +0 -159
  105. package/src/add/scenario-services.test.ts +0 -103
  106. package/src/add/scenario-skip.test.ts +0 -83
  107. package/src/add/validate-workflow-graph-addons.test.ts +0 -102
  108. package/src/add/wire-name-literal.test.ts +0 -117
  109. package/src/error-codes-emitted.test.ts +0 -76
  110. package/src/error-codes.ts +0 -145
  111. package/src/index.ts +0 -66
  112. package/src/inspector.ts +0 -575
  113. package/src/schema-generator.ts +0 -1
  114. package/src/source-file-cache.ts +0 -73
  115. package/src/tsconfig-paths.test.ts +0 -90
  116. package/src/types-map.ts +0 -141
  117. package/src/types.ts +0 -775
  118. package/src/utils/annotate-http-route-auth.test.ts +0 -161
  119. package/src/utils/annotate-http-route-auth.ts +0 -53
  120. package/src/utils/check-classified-sinks.ts +0 -215
  121. package/src/utils/check-pii-output.ts +0 -120
  122. package/src/utils/compute-diagnostics.test.ts +0 -106
  123. package/src/utils/compute-required-schemas.ts +0 -48
  124. package/src/utils/contract-hashes.test.ts +0 -553
  125. package/src/utils/contract-hashes.ts +0 -387
  126. package/src/utils/custom-types-generator.test.ts +0 -124
  127. package/src/utils/custom-types-generator.ts +0 -150
  128. package/src/utils/detect-schema-vendor.test.ts +0 -123
  129. package/src/utils/detect-schema-vendor.ts +0 -120
  130. package/src/utils/does-type-extend-core-type.ts +0 -53
  131. package/src/utils/ensure-function-metadata.ts +0 -385
  132. package/src/utils/extract-function-name.ts +0 -612
  133. package/src/utils/extract-function-node.ts +0 -70
  134. package/src/utils/extract-node-value.test.ts +0 -117
  135. package/src/utils/extract-node-value.ts +0 -172
  136. package/src/utils/extract-secret-usage.test.ts +0 -81
  137. package/src/utils/extract-secret-usage.ts +0 -73
  138. package/src/utils/extract-services.ts +0 -70
  139. package/src/utils/extract-surface-usage.test.ts +0 -147
  140. package/src/utils/extract-surface-usage.ts +0 -121
  141. package/src/utils/filter-inspector-state.test.ts +0 -2232
  142. package/src/utils/filter-inspector-state.ts +0 -1298
  143. package/src/utils/filter-utils.test.ts +0 -843
  144. package/src/utils/filter-utils.ts +0 -161
  145. package/src/utils/find-root-dir.ts +0 -68
  146. package/src/utils/find-zod-transform.test.ts +0 -70
  147. package/src/utils/find-zod-transform.ts +0 -103
  148. package/src/utils/get-exported-variable-name.ts +0 -48
  149. package/src/utils/get-files-and-methods.ts +0 -157
  150. package/src/utils/get-property-value.test.ts +0 -141
  151. package/src/utils/get-property-value.ts +0 -331
  152. package/src/utils/hash.ts +0 -26
  153. package/src/utils/literal-properties.ts +0 -97
  154. package/src/utils/load-addon-functions-meta.test.ts +0 -157
  155. package/src/utils/load-addon-functions-meta.ts +0 -508
  156. package/src/utils/load-addon-scopes.test.ts +0 -138
  157. package/src/utils/middleware.test.ts +0 -204
  158. package/src/utils/middleware.ts +0 -303
  159. package/src/utils/nested-project-filter.test.ts +0 -53
  160. package/src/utils/nested-project-filter.ts +0 -28
  161. package/src/utils/permissions-shorthand.test.ts +0 -79
  162. package/src/utils/permissions.test.ts +0 -125
  163. package/src/utils/permissions.ts +0 -129
  164. package/src/utils/post-process.test.ts +0 -1094
  165. package/src/utils/post-process.ts +0 -1604
  166. package/src/utils/resolve-addon-package.ts +0 -106
  167. package/src/utils/resolve-core-type.test.ts +0 -142
  168. package/src/utils/resolve-core-type.ts +0 -35
  169. package/src/utils/resolve-deploy-target.test.ts +0 -135
  170. package/src/utils/resolve-deploy-target.ts +0 -65
  171. package/src/utils/resolve-function-meta.ts +0 -25
  172. package/src/utils/resolve-function-types.ts +0 -42
  173. package/src/utils/resolve-identifier.ts +0 -46
  174. package/src/utils/resolve-ref-contract.ts +0 -71
  175. package/src/utils/resolve-versions.test.ts +0 -499
  176. package/src/utils/resolve-versions.ts +0 -228
  177. package/src/utils/schema-cache.test.ts +0 -124
  178. package/src/utils/schema-generator.test.ts +0 -272
  179. package/src/utils/schema-generator.ts +0 -780
  180. package/src/utils/secret-alias-services.test.ts +0 -146
  181. package/src/utils/secret-alias-services.ts +0 -58
  182. package/src/utils/serialize-inspector-state.ts +0 -742
  183. package/src/utils/serialize-mcp-json.ts +0 -150
  184. package/src/utils/serialize-middleware-groups-meta.ts +0 -36
  185. package/src/utils/serialize-openapi-json.ts +0 -277
  186. package/src/utils/serialize-permissions-groups-meta.ts +0 -7
  187. package/src/utils/single-declaration.ts +0 -57
  188. package/src/utils/type-utils.ts +0 -145
  189. package/src/utils/validate-auth-sessionless.ts +0 -30
  190. package/src/utils/validate-exposed-functions-gated.test.ts +0 -230
  191. package/src/utils/validate-exposed-functions-gated.ts +0 -103
  192. package/src/utils/validate-tags-resolve-to-middleware.test.ts +0 -108
  193. package/src/utils/validate-tags-resolve-to-middleware.ts +0 -48
  194. package/src/utils/workflow/derive-workflow-plan.test.ts +0 -178
  195. package/src/utils/workflow/derive-workflow-plan.ts +0 -117
  196. package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +0 -1465
  197. package/src/utils/workflow/dsl/deserialize-fanout-body.test.ts +0 -71
  198. package/src/utils/workflow/dsl/deserialize-fanout-fidelity.test.ts +0 -99
  199. package/src/utils/workflow/dsl/deserialize-graph-next.test.ts +0 -161
  200. package/src/utils/workflow/dsl/deserialize-roundtrip-bindings.test.ts +0 -121
  201. package/src/utils/workflow/dsl/deserialize-roundtrip-values.test.ts +0 -116
  202. package/src/utils/workflow/dsl/deserialize-roundtrip.test.ts +0 -145
  203. package/src/utils/workflow/dsl/extract-approval-policy.test.ts +0 -71
  204. package/src/utils/workflow/dsl/extract-dsl-workflow.ts +0 -2254
  205. package/src/utils/workflow/dsl/index.ts +0 -11
  206. package/src/utils/workflow/dsl/patterns.ts +0 -440
  207. package/src/utils/workflow/dsl/validation.ts +0 -203
  208. package/src/utils/workflow/graph/convert-dsl-to-graph-skip.test.ts +0 -35
  209. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +0 -543
  210. package/src/utils/workflow/graph/fanout-node-identity.test.ts +0 -105
  211. package/src/utils/workflow/graph/finalize-workflow-wires.ts +0 -310
  212. package/src/utils/workflow/graph/finalize-workflows.test.ts +0 -50
  213. package/src/utils/workflow/graph/finalize-workflows.ts +0 -130
  214. package/src/utils/workflow/graph/index.ts +0 -28
  215. package/src/utils/workflow/graph/serialize-workflow-graph.ts +0 -240
  216. package/src/utils/workflow/graph/workflow-graph.types.ts +0 -281
  217. package/src/visit.ts +0 -181
  218. package/tsconfig.json +0 -19
  219. package/tsconfig.tsbuildinfo +0 -1
@@ -1,123 +0,0 @@
1
- import { test, describe, before, after } from 'node:test'
2
- import assert from 'node:assert/strict'
3
- import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'fs'
4
- import { tmpdir } from 'os'
5
- import { join } from 'path'
6
- import * as ts from 'typescript'
7
-
8
- import { detectSchemaVendorOrError } from './detect-schema-vendor.js'
9
-
10
- let projectDir: string
11
- let program: ts.Program
12
- let checker: ts.TypeChecker
13
- let sourceFile: ts.SourceFile
14
-
15
- const criticals: string[] = []
16
- const logger = {
17
- debug() {},
18
- info() {},
19
- warn() {},
20
- error() {},
21
- critical(_code: unknown, message: string) {
22
- criticals.push(message)
23
- },
24
- } as any
25
-
26
- const initializerIdentifier = (name: string): ts.Identifier => {
27
- let found: ts.Identifier | undefined
28
- const visit = (node: ts.Node) => {
29
- if (
30
- ts.isVariableDeclaration(node) &&
31
- ts.isIdentifier(node.name) &&
32
- node.name.text === name &&
33
- node.initializer &&
34
- ts.isIdentifier(node.initializer)
35
- ) {
36
- found = node.initializer
37
- }
38
- ts.forEachChild(node, visit)
39
- }
40
- visit(sourceFile)
41
- assert.ok(found, `no identifier initializer found for '${name}'`)
42
- return found
43
- }
44
-
45
- before(() => {
46
- projectDir = mkdtempSync(join(tmpdir(), 'pikku-schema-vendor-'))
47
- mkdirSync(join(projectDir, 'src'))
48
- writeFileSync(
49
- join(projectDir, 'src', 'schemas.ts'),
50
- [
51
- // Imported from a file that does not exist — exactly what a schema built
52
- // from an ungenerated '.pikku/db/zod.gen.ts' looks like to the checker.
53
- `import { UngeneratedSchema } from './not-written-yet.js'`,
54
- `export const unresolved = UngeneratedSchema`,
55
- `const plainObject = { a: 1 }`,
56
- `export const resolvedButNotASchema = plainObject`,
57
- '',
58
- ].join('\n')
59
- )
60
-
61
- program = ts.createProgram([join(projectDir, 'src', 'schemas.ts')], {
62
- target: ts.ScriptTarget.ESNext,
63
- module: ts.ModuleKind.NodeNext,
64
- moduleResolution: ts.ModuleResolutionKind.NodeNext,
65
- strict: true,
66
- skipLibCheck: true,
67
- noEmit: true,
68
- })
69
- checker = program.getTypeChecker()
70
- sourceFile = program.getSourceFile(join(projectDir, 'src', 'schemas.ts'))!
71
- })
72
-
73
- after(() => {
74
- rmSync(projectDir, { recursive: true, force: true })
75
- })
76
-
77
- describe('detectSchemaVendorOrError', () => {
78
- test('reports a type the checker could not resolve as a resolution failure', () => {
79
- criticals.length = 0
80
-
81
- const vendor = detectSchemaVendorOrError(
82
- initializerIdentifier('unresolved'),
83
- checker,
84
- logger,
85
- `Function 'createTodo' input`,
86
- 'src/schemas.ts'
87
- )
88
-
89
- assert.equal(vendor, undefined)
90
- assert.equal(criticals.length, 1)
91
- const [message] = criticals
92
- assert.match(message, /could not be TYPED/)
93
- assert.match(message, /UngeneratedSchema/)
94
- assert.match(message, /pikku db generate/)
95
- // The unactionable advice must NOT be given for a type that simply failed
96
- // to resolve — the schema may well already be zod.
97
- assert.doesNotMatch(
98
- message,
99
- /Ensure your schema is imported from a supported validation library/
100
- )
101
- })
102
-
103
- test('still reports a resolvable non-vendor type as an unsupported library', () => {
104
- criticals.length = 0
105
-
106
- const vendor = detectSchemaVendorOrError(
107
- initializerIdentifier('resolvedButNotASchema'),
108
- checker,
109
- logger,
110
- `Function 'createTodo' input`,
111
- 'src/schemas.ts'
112
- )
113
-
114
- assert.equal(vendor, undefined)
115
- assert.equal(criticals.length, 1)
116
- const [message] = criticals
117
- assert.match(
118
- message,
119
- /Ensure your schema is imported from a supported validation library/
120
- )
121
- assert.doesNotMatch(message, /could not be TYPED/)
122
- })
123
- })
@@ -1,120 +0,0 @@
1
- import * as ts from 'typescript'
2
- import type { SchemaVendor, InspectorLogger } from '../types.js'
3
- import { ErrorCode } from '../error-codes.js'
4
-
5
- /**
6
- * Whether the checker could type the identifier at all.
7
- *
8
- * `any` here is not a schema written in an exotic library — it is TypeScript telling us
9
- * it could not resolve the declaration, which happens when the schema comes from a file
10
- * outside the program (not matched by tsconfig `include`) or from a generated file that
11
- * has not been written yet (`.pikku/db/zod.gen.ts` before `pikku db generate` runs).
12
- * The distinction matters because the two have opposite fixes, and conflating them told
13
- * users to "import from a supported validation library" about a plain `z.object`.
14
- */
15
- const isUnresolved = (type: ts.Type): boolean =>
16
- (type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0
17
-
18
- /**
19
- * Detect the schema vendor by tracing the type back to its library origin.
20
- * This handles locally-defined schemas like `export const MySchema = z.object({...})`
21
- * by checking where the type itself originates from.
22
- *
23
- * Supports multiple schema libraries in the same project (e.g., during migration
24
- * from one library to another).
25
- */
26
- export const detectSchemaVendor = (
27
- identifier: ts.Identifier,
28
- checker: ts.TypeChecker
29
- ): SchemaVendor => {
30
- const type = checker.getTypeAtLocation(identifier)
31
- if (!type) return 'unknown'
32
-
33
- // Check the type's symbol declarations to find the library origin
34
- const checkTypeOrigin = (t: ts.Type): SchemaVendor | null => {
35
- const symbol = t.getSymbol() || t.aliasSymbol
36
- if (symbol) {
37
- const decls = symbol.getDeclarations()
38
- if (decls) {
39
- for (const decl of decls) {
40
- const fileName = decl.getSourceFile().fileName
41
- if (fileName.includes('node_modules/zod')) return 'zod'
42
- if (fileName.includes('node_modules/valibot')) return 'valibot'
43
- if (fileName.includes('node_modules/arktype')) return 'arktype'
44
- if (fileName.includes('node_modules/@effect/schema')) return 'effect'
45
- }
46
- }
47
- }
48
-
49
- // Check base types for class/interface hierarchies
50
- const baseTypes = t.getBaseTypes?.()
51
- if (baseTypes) {
52
- for (const baseType of baseTypes) {
53
- const result = checkTypeOrigin(baseType)
54
- if (result) return result
55
- }
56
- }
57
-
58
- return null
59
- }
60
-
61
- const vendor = checkTypeOrigin(type)
62
- if (vendor) return vendor
63
-
64
- // Fallback: check type arguments (for generic types like z.ZodObject<...>)
65
- if ((type as ts.TypeReference).typeArguments) {
66
- for (const arg of (type as ts.TypeReference).typeArguments || []) {
67
- const result = checkTypeOrigin(arg)
68
- if (result) return result
69
- }
70
- }
71
-
72
- return 'unknown'
73
- }
74
-
75
- /**
76
- * Detect schema vendor and log a fatal error if unknown.
77
- * Returns the vendor if successful, or undefined if unknown (after logging error).
78
- *
79
- * @param identifier - The TypeScript identifier for the schema variable
80
- * @param checker - TypeScript type checker
81
- * @param logger - Inspector logger for error reporting
82
- * @param context - Description of what the schema is for (e.g., "Credential 'myCredential'")
83
- * @param sourceFile - Source file path for error message
84
- */
85
- export const detectSchemaVendorOrError = (
86
- identifier: ts.Identifier,
87
- checker: ts.TypeChecker,
88
- logger: InspectorLogger,
89
- context: string,
90
- sourceFile: string
91
- ): Exclude<SchemaVendor, 'unknown'> | undefined => {
92
- const vendor = detectSchemaVendor(identifier, checker)
93
- if (vendor === 'unknown') {
94
- // Two different failures used to share one message. Reporting the wrong one is not a
95
- // cosmetic problem: the schema is dropped either way (`inputSchemaName: null`, no
96
- // generated schema file), so the message is the only thing standing between the user
97
- // and a function that silently validates nothing — and "use a supported validation
98
- // library" is unactionable when the schema already IS `z.object({...})`.
99
- if (isUnresolved(checker.getTypeAtLocation(identifier))) {
100
- logger.critical(
101
- ErrorCode.INLINE_SCHEMA,
102
- `${context} schema '${identifier.text}' could not be TYPED from '${sourceFile}' — ` +
103
- `TypeScript resolved it to 'any', so its vendor cannot be traced. This is a ` +
104
- `resolution problem, not a schema problem: the file it is imported from is either ` +
105
- `outside your tsconfig 'include', or has not been generated yet (a schema built ` +
106
- `from '.pikku/db/zod.gen.ts' needs 'pikku db generate' to have run first). ` +
107
- `Fix the import so the type resolves, then re-run.`
108
- )
109
- return undefined
110
- }
111
- logger.critical(
112
- ErrorCode.INLINE_SCHEMA,
113
- `${context} schema vendor could not be determined from '${sourceFile}'. ` +
114
- `Supported vendors: zod, valibot, arktype, @effect/schema. ` +
115
- `Ensure your schema is imported from a supported validation library.`
116
- )
117
- return undefined
118
- }
119
- return vendor
120
- }
@@ -1,53 +0,0 @@
1
- import type * as ts from 'typescript'
2
-
3
- export const doesTypeExtendsCore = (
4
- type: ts.Type,
5
- checker: ts.TypeChecker,
6
- visitedTypes: Set<ts.Type>,
7
- coreType: string
8
- ): boolean => {
9
- if (!type || !checker) return false
10
-
11
- // Avoid infinite recursion by checking if we've already visited this type
12
- if (visitedTypes.has(type)) {
13
- return false
14
- }
15
- visitedTypes.add(type)
16
-
17
- const typeSymbol = type.getSymbol()
18
- if (typeSymbol) {
19
- // Check if the type is the core type
20
- if (typeSymbol.getName() === coreType) {
21
- return true
22
- }
23
-
24
- // For interface and class types, check their base types
25
- if (type.isClassOrInterface()) {
26
- const baseTypes = type.getBaseTypes() || []
27
- for (const baseType of baseTypes) {
28
- if (doesTypeExtendsCore(baseType, checker, visitedTypes, coreType)) {
29
- return true
30
- }
31
- }
32
- }
33
- }
34
-
35
- // For type aliases, get the aliased type
36
- if (type.aliasSymbol) {
37
- const aliasedType = checker.getDeclaredTypeOfSymbol(type.aliasSymbol)
38
- if (doesTypeExtendsCore(aliasedType, checker, visitedTypes, coreType)) {
39
- return true
40
- }
41
- }
42
-
43
- // For union and intersection types, check all constituent types
44
- if (type.isUnionOrIntersection()) {
45
- for (const subType of type.types) {
46
- if (doesTypeExtendsCore(subType, checker, visitedTypes, coreType)) {
47
- return true
48
- }
49
- }
50
- }
51
-
52
- return false
53
- }
@@ -1,385 +0,0 @@
1
- import * as ts from 'typescript'
2
- import type { InspectorState } from '../types.js'
3
- import { funcIdToTypeName } from './extract-function-name.js'
4
- import { getCommonWireMetaData } from './get-property-value.js'
5
- import { resolveMiddleware } from './middleware.js'
6
- import { resolvePermissions } from './permissions.js'
7
-
8
- function isVoidLike(type: ts.Type): boolean {
9
- return !!(
10
- type.flags &
11
- (ts.TypeFlags.Void | ts.TypeFlags.Undefined | ts.TypeFlags.VoidLike)
12
- )
13
- }
14
-
15
- function isPromiseOfVoid(checker: ts.TypeChecker, type: ts.Type): boolean {
16
- if (!type?.symbol) return false
17
- const isPromise =
18
- type.symbol.name === 'Promise' &&
19
- checker.getFullyQualifiedName(type.symbol).includes('Promise')
20
- if (!isPromise) return false
21
- const inner =
22
- type.aliasTypeArguments?.[0] ??
23
- (type as ts.TypeReference).typeArguments?.[0]
24
- return !!inner && isVoidLike(inner)
25
- }
26
-
27
- function unwrapPromise(checker: ts.TypeChecker, type: ts.Type): ts.Type {
28
- if (type.isUnion()) {
29
- const nonVoid = type.types.filter(
30
- (t) => !isVoidLike(t) && !isPromiseOfVoid(checker, t)
31
- )
32
- if (nonVoid.length === 1) {
33
- return unwrapPromise(checker, nonVoid[0]!)
34
- }
35
- if (nonVoid.length > 1) {
36
- return unwrapPromise(checker, nonVoid[0]!)
37
- }
38
- return type
39
- }
40
- if (!type?.symbol) return type
41
- const isPromise =
42
- type.symbol.name === 'Promise' &&
43
- checker.getFullyQualifiedName(type.symbol).includes('Promise')
44
- if (isPromise && type.aliasTypeArguments?.length === 1) {
45
- return type.aliasTypeArguments[0]!
46
- }
47
- if (isPromise && (type as ts.TypeReference).typeArguments?.length === 1) {
48
- return (type as ts.TypeReference).typeArguments![0]!
49
- }
50
- return type
51
- }
52
-
53
- function resolveTypeName(
54
- checker: ts.TypeChecker,
55
- type: ts.Type,
56
- state: InspectorState,
57
- funcName: string,
58
- direction: 'Input' | 'Output'
59
- ): string | null {
60
- if (type.flags & (ts.TypeFlags.VoidLike | ts.TypeFlags.Null)) return null
61
-
62
- const typeStr = checker.typeToString(
63
- type,
64
- undefined,
65
- ts.TypeFormatFlags.NoTruncation
66
- )
67
- if (
68
- !typeStr ||
69
- typeStr === 'void' ||
70
- typeStr === 'undefined' ||
71
- typeStr === 'null'
72
- )
73
- return null
74
-
75
- const isSimpleName = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(typeStr)
76
- if (isSimpleName) {
77
- const symbol = type.aliasSymbol || type.getSymbol()
78
- if (symbol) {
79
- const decl = symbol.getDeclarations()?.[0]
80
- if (decl) {
81
- const path = decl.getSourceFile().fileName
82
- if (!state.functions.typesMap.exists(typeStr, path)) {
83
- state.functions.typesMap.addType(typeStr, path)
84
- }
85
- }
86
- }
87
- return typeStr
88
- }
89
-
90
- const aliasName = funcIdToTypeName(funcName) + direction
91
- state.functions.typesMap.addCustomType(aliasName, typeStr, [])
92
- return aliasName
93
- }
94
-
95
- function getFirstCallSignature(type: ts.Type): ts.Signature | undefined {
96
- const sigs = type.getCallSignatures()
97
- if (sigs.length > 0) return sigs[0]
98
- if (type.isUnion()) {
99
- for (const member of type.types) {
100
- const memberSigs = member.getCallSignatures()
101
- if (memberSigs.length > 0) return memberSigs[0]
102
- }
103
- }
104
- return undefined
105
- }
106
-
107
- function resolveFromConfigTypeArgs(
108
- state: InspectorState,
109
- pikkuFuncId: string,
110
- configType: ts.Type,
111
- checker: ts.TypeChecker,
112
- meta: NonNullable<InspectorState['functions']['meta'][string]>
113
- ): void {
114
- const typeArgs =
115
- configType.aliasTypeArguments ??
116
- (configType as ts.TypeReference).typeArguments
117
- if (!typeArgs || typeArgs.length < 2) return
118
-
119
- const inputType = typeArgs[0]!
120
- const outputType = typeArgs[1]!
121
-
122
- if (!meta.inputs || meta.inputs.length === 0) {
123
- const inputName = resolveTypeName(
124
- checker,
125
- inputType,
126
- state,
127
- pikkuFuncId,
128
- 'Input'
129
- )
130
- if (inputName) {
131
- meta.inputs = [inputName]
132
- meta.inputSchemaName = inputName
133
- }
134
- }
135
-
136
- if (!meta.outputs || meta.outputs.length === 0) {
137
- const resolvedOutput = unwrapPromise(checker, outputType)
138
- const outputName = resolveTypeName(
139
- checker,
140
- resolvedOutput,
141
- state,
142
- pikkuFuncId,
143
- 'Output'
144
- )
145
- if (outputName) {
146
- meta.outputs = [outputName]
147
- meta.outputSchemaName = outputName
148
- }
149
- }
150
- }
151
-
152
- function resolveFuncConfigTypes(
153
- state: InspectorState,
154
- pikkuFuncId: string,
155
- funcInitializer: ts.Node,
156
- checker: ts.TypeChecker
157
- ): void {
158
- const meta = state.functions.meta[pikkuFuncId]
159
- if (!meta || (meta.inputs && meta.inputs.length > 0)) return
160
-
161
- const configType = checker.getTypeAtLocation(funcInitializer)
162
- const funcProp = configType.getProperty('func')
163
- if (!funcProp) return
164
-
165
- const funcType = checker.getTypeOfSymbolAtLocation(funcProp, funcInitializer)
166
- const sig = getFirstCallSignature(funcType)
167
- if (!sig) return
168
- const params = sig.getParameters()
169
- if (params.length >= 2) {
170
- const inputType = checker.getTypeOfSymbolAtLocation(
171
- params[1]!,
172
- funcInitializer
173
- )
174
- const inputName = resolveTypeName(
175
- checker,
176
- inputType,
177
- state,
178
- pikkuFuncId,
179
- 'Input'
180
- )
181
- if (inputName) {
182
- meta.inputs = [inputName]
183
- meta.inputSchemaName = inputName
184
- }
185
- }
186
-
187
- const rawReturnType = checker.getReturnTypeOfSignature(sig)
188
- const outputType = unwrapPromise(checker, rawReturnType)
189
- const outputName = resolveTypeName(
190
- checker,
191
- outputType,
192
- state,
193
- pikkuFuncId,
194
- 'Output'
195
- )
196
- if (outputName) {
197
- meta.outputs = [outputName]
198
- meta.outputSchemaName = outputName
199
- }
200
-
201
- resolveFromConfigTypeArgs(state, pikkuFuncId, configType, checker, meta)
202
- }
203
-
204
- function resolveToPikkuFuncCall(
205
- node: ts.Node,
206
- checker: ts.TypeChecker
207
- ): ts.CallExpression | null {
208
- if (
209
- ts.isCallExpression(node) &&
210
- ts.isIdentifier(node.expression) &&
211
- node.expression.text.startsWith('pikku')
212
- ) {
213
- return node
214
- }
215
-
216
- if (ts.isIdentifier(node)) {
217
- const sym = checker.getSymbolAtLocation(node)
218
- if (sym) {
219
- let resolved = sym
220
- if (resolved.flags & ts.SymbolFlags.Alias) {
221
- resolved = checker.getAliasedSymbol(resolved) ?? resolved
222
- }
223
- const decl = resolved.declarations?.[0]
224
- if (decl && ts.isVariableDeclaration(decl) && decl.initializer) {
225
- return resolveToPikkuFuncCall(decl.initializer, checker)
226
- }
227
- }
228
- }
229
-
230
- return null
231
- }
232
-
233
- /**
234
- * Ensures that function metadata exists for a given pikkuFuncId.
235
- * Creates stub metadata if it doesn't exist (useful for inline functions).
236
- * When funcInitializer and checker are provided, resolves types and
237
- * extracts tags/middleware/permissions from the pikkuFunc() config.
238
- */
239
- export function ensureFunctionMetadata(
240
- state: InspectorState,
241
- pikkuFuncId: string,
242
- fallbackName?: string,
243
- funcInitializer?: ts.Node,
244
- checker?: ts.TypeChecker,
245
- isHelper?: boolean
246
- ): void {
247
- if (!state.functions.meta[pikkuFuncId]) {
248
- state.functions.meta[pikkuFuncId] = {
249
- pikkuFuncId,
250
- functionType: isHelper ? 'helper' : 'inline',
251
- name: fallbackName || pikkuFuncId,
252
- services: { optimized: false, services: [] },
253
- inputSchemaName: null,
254
- outputSchemaName: null,
255
- inputs: [],
256
- outputs: [],
257
- middleware: undefined,
258
- }
259
- }
260
-
261
- const meta = state.functions.meta[pikkuFuncId]!
262
-
263
- if (funcInitializer && checker) {
264
- let pikkuFuncCall: ts.CallExpression | null = null
265
-
266
- if (ts.isCallExpression(funcInitializer)) {
267
- pikkuFuncCall = funcInitializer
268
- resolveFuncConfigTypes(state, pikkuFuncId, pikkuFuncCall, checker)
269
- if (!state.typesLookup.has(pikkuFuncId)) {
270
- populateTypesLookup(state, pikkuFuncId, pikkuFuncCall, checker)
271
- }
272
- } else {
273
- pikkuFuncCall = resolveToPikkuFuncCall(funcInitializer, checker)
274
- }
275
-
276
- if (pikkuFuncCall) {
277
- const firstArg = pikkuFuncCall.arguments[0]
278
- if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
279
- if (!meta.tags) {
280
- const { tags } = getCommonWireMetaData(
281
- firstArg,
282
- 'Function',
283
- fallbackName || pikkuFuncId,
284
- undefined,
285
- checker
286
- )
287
- if (tags) {
288
- meta.tags = tags
289
- }
290
- }
291
- if (!meta.middleware) {
292
- meta.middleware = resolveMiddleware(
293
- state,
294
- firstArg,
295
- meta.tags,
296
- checker
297
- )
298
- }
299
- if (!meta.permissions) {
300
- meta.permissions = resolvePermissions(
301
- state,
302
- firstArg,
303
- meta.tags,
304
- checker
305
- )
306
- }
307
- }
308
- }
309
- }
310
- }
311
-
312
- /**
313
- * Register metadata for a `func:` inlined into a wiring (queue/scheduler/
314
- * trigger/gateway/…).
315
- *
316
- * An inline function has no exported name, so `addFunctions` skips it (it bails
317
- * on `__temp_` ids) and only the wiring's context-based id exists. Without this
318
- * the wiring points at a function that was never registered and the worker
319
- * resolves to nothing at runtime ("Missing generated metadata for ...").
320
- *
321
- * The stub also carries no session info, so the runtime would treat it as
322
- * session-required and every invocation would fail with "Authentication
323
- * required". Derive `sessionless` from the helper the function was built with —
324
- * the same rule `addFunctions` applies to named ones (`!== 'pikkuFunc'`).
325
- */
326
- export function ensureInlineWiringFunction(
327
- state: InspectorState,
328
- pikkuFuncId: string,
329
- fallbackName: string | undefined,
330
- funcInitializer: ts.Node,
331
- checker: ts.TypeChecker,
332
- isHelper?: boolean
333
- ): void {
334
- ensureFunctionMetadata(
335
- state,
336
- pikkuFuncId,
337
- fallbackName,
338
- funcInitializer,
339
- checker,
340
- isHelper
341
- )
342
-
343
- const meta = state.functions.meta[pikkuFuncId]
344
- if (
345
- meta &&
346
- meta.sessionless === undefined &&
347
- ts.isCallExpression(funcInitializer) &&
348
- ts.isIdentifier(funcInitializer.expression)
349
- ) {
350
- meta.sessionless = funcInitializer.expression.text !== 'pikkuFunc'
351
- }
352
- }
353
-
354
- function populateTypesLookup(
355
- state: InspectorState,
356
- pikkuFuncId: string,
357
- funcInitializer: ts.CallExpression,
358
- checker: ts.TypeChecker
359
- ): void {
360
- const typeArgs = funcInitializer.typeArguments
361
- if (typeArgs && typeArgs.length >= 1) {
362
- const inputType = checker.getTypeFromTypeNode(typeArgs[0]!)
363
- state.typesLookup.set(pikkuFuncId, [inputType])
364
- return
365
- }
366
-
367
- const configType = checker.getTypeAtLocation(funcInitializer)
368
- const funcProp = configType.getProperty('func')
369
- if (!funcProp) return
370
-
371
- const funcType = checker.getTypeOfSymbolAtLocation(funcProp, funcInitializer)
372
- const sig = getFirstCallSignature(funcType)
373
- if (!sig) return
374
-
375
- const params = sig.getParameters()
376
- if (params.length >= 2) {
377
- const inputType = checker.getTypeOfSymbolAtLocation(
378
- params[1]!,
379
- funcInitializer
380
- )
381
- if (!(inputType.flags & ts.TypeFlags.VoidLike)) {
382
- state.typesLookup.set(pikkuFuncId, [inputType])
383
- }
384
- }
385
- }