@pikku/inspector 0.12.75 → 0.12.82

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 (223) hide show
  1. package/CHANGELOG.md +357 -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-middleware.js +66 -42
  8. package/dist/add/add-wire-addon.js +7 -4
  9. package/dist/add/add-wire-remote-addon.js +1 -0
  10. package/dist/error-codes.d.ts +1 -0
  11. package/dist/error-codes.js +1 -0
  12. package/dist/index.d.ts +3 -1
  13. package/dist/index.js +3 -1
  14. package/dist/inspector.js +5 -0
  15. package/dist/surface/collect-surface.d.ts +58 -0
  16. package/dist/surface/collect-surface.js +613 -0
  17. package/dist/types.d.ts +36 -12
  18. package/dist/utils/filter-inspector-state.js +14 -0
  19. package/dist/utils/load-addon-functions-meta.js +24 -11
  20. package/dist/utils/post-process.js +15 -0
  21. package/dist/utils/read-module-specifiers.d.ts +8 -0
  22. package/dist/utils/read-module-specifiers.js +23 -0
  23. package/dist/utils/read-tsconfig-out-dir.d.ts +5 -0
  24. package/dist/utils/read-tsconfig-out-dir.js +12 -0
  25. package/dist/utils/resolve-deploy-target.d.ts +7 -0
  26. package/dist/utils/resolve-deploy-target.js +15 -7
  27. package/dist/utils/serialize-inspector-state.d.ts +6 -0
  28. package/dist/utils/serialize-inspector-state.js +10 -0
  29. package/dist/visit.js +4 -0
  30. package/package.json +16 -6
  31. package/run-tests.sh +21 -6
  32. package/src/add/add-addon-bans.ts +0 -85
  33. package/src/add/add-agent-scorer.test.ts +0 -197
  34. package/src/add/add-agent-scorer.ts +0 -83
  35. package/src/add/add-agent.test.ts +0 -87
  36. package/src/add/add-agent.ts +0 -638
  37. package/src/add/add-approval-description.ts +0 -76
  38. package/src/add/add-auth.test.ts +0 -791
  39. package/src/add/add-auth.ts +0 -424
  40. package/src/add/add-channel.ts +0 -778
  41. package/src/add/add-cli-renderers.test.ts +0 -74
  42. package/src/add/add-cli.ts +0 -1006
  43. package/src/add/add-credential.ts +0 -186
  44. package/src/add/add-feature.test.ts +0 -306
  45. package/src/add/add-feature.ts +0 -253
  46. package/src/add/add-file-extends-core-type.ts +0 -66
  47. package/src/add/add-file-with-config.ts +0 -45
  48. package/src/add/add-file-with-factory.test.ts +0 -134
  49. package/src/add/add-file-with-factory.ts +0 -288
  50. package/src/add/add-functions.test.ts +0 -743
  51. package/src/add/add-functions.ts +0 -1548
  52. package/src/add/add-gateway.ts +0 -143
  53. package/src/add/add-http-route-ref.test.ts +0 -149
  54. package/src/add/add-http-route.ts +0 -530
  55. package/src/add/add-http-routes.ts +0 -471
  56. package/src/add/add-keyed-wiring.ts +0 -180
  57. package/src/add/add-mcp-prompt.ts +0 -157
  58. package/src/add/add-mcp-resource.ts +0 -175
  59. package/src/add/add-middleware.test.ts +0 -196
  60. package/src/add/add-middleware.ts +0 -879
  61. package/src/add/add-permission-auth.test.ts +0 -59
  62. package/src/add/add-permission.ts +0 -311
  63. package/src/add/add-personas.test.ts +0 -406
  64. package/src/add/add-personas.ts +0 -287
  65. package/src/add/add-queue-worker.ts +0 -117
  66. package/src/add/add-rpc-invocations.test.ts +0 -287
  67. package/src/add/add-rpc-invocations.ts +0 -221
  68. package/src/add/add-scenario-step.test.ts +0 -509
  69. package/src/add/add-schedule.ts +0 -120
  70. package/src/add/add-scope.test.ts +0 -419
  71. package/src/add/add-scope.ts +0 -221
  72. package/src/add/add-secret.ts +0 -10
  73. package/src/add/add-subject-scenario-steps.test.ts +0 -161
  74. package/src/add/add-system-role.test.ts +0 -297
  75. package/src/add/add-system-role.ts +0 -162
  76. package/src/add/add-trigger.ts +0 -165
  77. package/src/add/add-variable.ts +0 -10
  78. package/src/add/add-wire-addon.test.ts +0 -185
  79. package/src/add/add-wire-addon.ts +0 -146
  80. package/src/add/add-wire-remote-addon.ts +0 -80
  81. package/src/add/add-workflow-edge-cases.test.ts +0 -201
  82. package/src/add/add-workflow-fanout.test.ts +0 -166
  83. package/src/add/add-workflow-graph-foreach.test.ts +0 -174
  84. package/src/add/add-workflow-graph-input.test.ts +0 -94
  85. package/src/add/add-workflow-graph-notes.test.ts +0 -74
  86. package/src/add/add-workflow-graph.ts +0 -644
  87. package/src/add/add-workflow-on-error.test.ts +0 -118
  88. package/src/add/add-workflow-return-switch.test.ts +0 -121
  89. package/src/add/add-workflow-silent-drops.test.ts +0 -261
  90. package/src/add/add-workflow-sleep-expression.test.ts +0 -96
  91. package/src/add/add-workflow.test.ts +0 -155
  92. package/src/add/add-workflow.ts +0 -482
  93. package/src/add/addon-bans.test.ts +0 -121
  94. package/src/add/addon-contracts.test.ts +0 -221
  95. package/src/add/allow-escape-hatches.test.ts +0 -144
  96. package/src/add/audit-meta.test.ts +0 -75
  97. package/src/add/classified-sink-check.test.ts +0 -347
  98. package/src/add/config-value-metadata.test.ts +0 -263
  99. package/src/add/dynamic-import-check.test.ts +0 -119
  100. package/src/add/expect-eventually-scenario-only.test.ts +0 -108
  101. package/src/add/function-body-span.test.ts +0 -96
  102. package/src/add/inline-wiring-function.test.ts +0 -104
  103. package/src/add/pii-check.test.ts +0 -258
  104. package/src/add/rpc-type-cast.test.ts +0 -123
  105. package/src/add/scenario-instrumentation.test.ts +0 -89
  106. package/src/add/scenario-instrumentation.ts +0 -42
  107. package/src/add/scenario-marker.test.ts +0 -89
  108. package/src/add/scenario-not-extractable.test.ts +0 -159
  109. package/src/add/scenario-services.test.ts +0 -103
  110. package/src/add/scenario-skip.test.ts +0 -83
  111. package/src/add/validate-workflow-graph-addons.test.ts +0 -102
  112. package/src/add/wire-name-literal.test.ts +0 -117
  113. package/src/error-codes-emitted.test.ts +0 -76
  114. package/src/error-codes.ts +0 -145
  115. package/src/index.ts +0 -66
  116. package/src/inspector.ts +0 -575
  117. package/src/schema-generator.ts +0 -1
  118. package/src/source-file-cache.ts +0 -73
  119. package/src/tsconfig-paths.test.ts +0 -90
  120. package/src/types-map.ts +0 -141
  121. package/src/types.ts +0 -775
  122. package/src/utils/annotate-http-route-auth.test.ts +0 -161
  123. package/src/utils/annotate-http-route-auth.ts +0 -53
  124. package/src/utils/check-classified-sinks.ts +0 -215
  125. package/src/utils/check-pii-output.ts +0 -120
  126. package/src/utils/compute-diagnostics.test.ts +0 -106
  127. package/src/utils/compute-required-schemas.ts +0 -48
  128. package/src/utils/contract-hashes.test.ts +0 -553
  129. package/src/utils/contract-hashes.ts +0 -387
  130. package/src/utils/custom-types-generator.test.ts +0 -124
  131. package/src/utils/custom-types-generator.ts +0 -150
  132. package/src/utils/detect-schema-vendor.test.ts +0 -123
  133. package/src/utils/detect-schema-vendor.ts +0 -120
  134. package/src/utils/does-type-extend-core-type.ts +0 -53
  135. package/src/utils/ensure-function-metadata.ts +0 -385
  136. package/src/utils/extract-function-name.ts +0 -612
  137. package/src/utils/extract-function-node.ts +0 -70
  138. package/src/utils/extract-node-value.test.ts +0 -117
  139. package/src/utils/extract-node-value.ts +0 -172
  140. package/src/utils/extract-secret-usage.test.ts +0 -81
  141. package/src/utils/extract-secret-usage.ts +0 -73
  142. package/src/utils/extract-services.ts +0 -70
  143. package/src/utils/extract-surface-usage.test.ts +0 -147
  144. package/src/utils/extract-surface-usage.ts +0 -121
  145. package/src/utils/filter-inspector-state.test.ts +0 -2232
  146. package/src/utils/filter-inspector-state.ts +0 -1298
  147. package/src/utils/filter-utils.test.ts +0 -843
  148. package/src/utils/filter-utils.ts +0 -161
  149. package/src/utils/find-root-dir.ts +0 -68
  150. package/src/utils/find-zod-transform.test.ts +0 -70
  151. package/src/utils/find-zod-transform.ts +0 -103
  152. package/src/utils/get-exported-variable-name.ts +0 -48
  153. package/src/utils/get-files-and-methods.ts +0 -157
  154. package/src/utils/get-property-value.test.ts +0 -141
  155. package/src/utils/get-property-value.ts +0 -331
  156. package/src/utils/hash.ts +0 -26
  157. package/src/utils/literal-properties.ts +0 -97
  158. package/src/utils/load-addon-functions-meta.test.ts +0 -157
  159. package/src/utils/load-addon-functions-meta.ts +0 -508
  160. package/src/utils/load-addon-scopes.test.ts +0 -138
  161. package/src/utils/middleware.test.ts +0 -204
  162. package/src/utils/middleware.ts +0 -303
  163. package/src/utils/nested-project-filter.test.ts +0 -53
  164. package/src/utils/nested-project-filter.ts +0 -28
  165. package/src/utils/permissions-shorthand.test.ts +0 -79
  166. package/src/utils/permissions.test.ts +0 -125
  167. package/src/utils/permissions.ts +0 -129
  168. package/src/utils/post-process.test.ts +0 -1094
  169. package/src/utils/post-process.ts +0 -1604
  170. package/src/utils/resolve-addon-package.ts +0 -106
  171. package/src/utils/resolve-core-type.test.ts +0 -142
  172. package/src/utils/resolve-core-type.ts +0 -35
  173. package/src/utils/resolve-deploy-target.test.ts +0 -135
  174. package/src/utils/resolve-deploy-target.ts +0 -65
  175. package/src/utils/resolve-function-meta.ts +0 -25
  176. package/src/utils/resolve-function-types.ts +0 -42
  177. package/src/utils/resolve-identifier.ts +0 -46
  178. package/src/utils/resolve-ref-contract.ts +0 -71
  179. package/src/utils/resolve-versions.test.ts +0 -499
  180. package/src/utils/resolve-versions.ts +0 -228
  181. package/src/utils/schema-cache.test.ts +0 -124
  182. package/src/utils/schema-generator.test.ts +0 -272
  183. package/src/utils/schema-generator.ts +0 -780
  184. package/src/utils/secret-alias-services.test.ts +0 -146
  185. package/src/utils/secret-alias-services.ts +0 -58
  186. package/src/utils/serialize-inspector-state.ts +0 -742
  187. package/src/utils/serialize-mcp-json.ts +0 -150
  188. package/src/utils/serialize-middleware-groups-meta.ts +0 -36
  189. package/src/utils/serialize-openapi-json.ts +0 -277
  190. package/src/utils/serialize-permissions-groups-meta.ts +0 -7
  191. package/src/utils/single-declaration.ts +0 -57
  192. package/src/utils/type-utils.ts +0 -145
  193. package/src/utils/validate-auth-sessionless.ts +0 -30
  194. package/src/utils/validate-exposed-functions-gated.test.ts +0 -230
  195. package/src/utils/validate-exposed-functions-gated.ts +0 -103
  196. package/src/utils/validate-tags-resolve-to-middleware.test.ts +0 -108
  197. package/src/utils/validate-tags-resolve-to-middleware.ts +0 -48
  198. package/src/utils/workflow/derive-workflow-plan.test.ts +0 -178
  199. package/src/utils/workflow/derive-workflow-plan.ts +0 -117
  200. package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +0 -1465
  201. package/src/utils/workflow/dsl/deserialize-fanout-body.test.ts +0 -71
  202. package/src/utils/workflow/dsl/deserialize-fanout-fidelity.test.ts +0 -99
  203. package/src/utils/workflow/dsl/deserialize-graph-next.test.ts +0 -161
  204. package/src/utils/workflow/dsl/deserialize-roundtrip-bindings.test.ts +0 -121
  205. package/src/utils/workflow/dsl/deserialize-roundtrip-values.test.ts +0 -116
  206. package/src/utils/workflow/dsl/deserialize-roundtrip.test.ts +0 -145
  207. package/src/utils/workflow/dsl/extract-approval-policy.test.ts +0 -71
  208. package/src/utils/workflow/dsl/extract-dsl-workflow.ts +0 -2254
  209. package/src/utils/workflow/dsl/index.ts +0 -11
  210. package/src/utils/workflow/dsl/patterns.ts +0 -440
  211. package/src/utils/workflow/dsl/validation.ts +0 -203
  212. package/src/utils/workflow/graph/convert-dsl-to-graph-skip.test.ts +0 -35
  213. package/src/utils/workflow/graph/convert-dsl-to-graph.ts +0 -543
  214. package/src/utils/workflow/graph/fanout-node-identity.test.ts +0 -105
  215. package/src/utils/workflow/graph/finalize-workflow-wires.ts +0 -310
  216. package/src/utils/workflow/graph/finalize-workflows.test.ts +0 -50
  217. package/src/utils/workflow/graph/finalize-workflows.ts +0 -130
  218. package/src/utils/workflow/graph/index.ts +0 -28
  219. package/src/utils/workflow/graph/serialize-workflow-graph.ts +0 -240
  220. package/src/utils/workflow/graph/workflow-graph.types.ts +0 -281
  221. package/src/visit.ts +0 -181
  222. package/tsconfig.json +0 -19
  223. 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
- }