@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,530 +0,0 @@
1
- import * as ts from 'typescript'
2
- import {
3
- getPropertyValue,
4
- getCommonWireMetaData,
5
- } from '../utils/get-property-value.js'
6
- import { pathToRegexp } from 'path-to-regexp'
7
- import type { HTTPMethod } from '@pikku/core/http'
8
- import {
9
- extractFunctionName,
10
- makeContextBasedId,
11
- } from '../utils/extract-function-name.js'
12
- import {
13
- getPropertyAssignmentInitializer,
14
- extractTypeKeys,
15
- } from '../utils/type-utils.js'
16
- import type {
17
- AddWiring,
18
- ExportedHTTPRouteConfigMeta,
19
- InspectorState,
20
- } from '../types.js'
21
- import { resolveHTTPMiddlewareFromObject } from '../utils/middleware.js'
22
- import { resolvePermissions } from '../utils/permissions.js'
23
- import { extractWireNames } from '../utils/post-process.js'
24
- import { ensureFunctionMetadata } from '../utils/ensure-function-metadata.js'
25
- import { resolveFunctionMeta } from '../utils/resolve-function-meta.js'
26
- import { ErrorCode } from '../error-codes.js'
27
- import { validateAuthSessionless } from '../utils/validate-auth-sessionless.js'
28
- import { detectSchemaVendorOrError } from '../utils/detect-schema-vendor.js'
29
- import { resolveAddonName } from '../utils/resolve-addon-package.js'
30
-
31
- import type { InspectorLogger } from '../types.js'
32
-
33
- /**
34
- * Parameters for registering an HTTP route
35
- */
36
- export interface RegisterHTTPRouteParams {
37
- obj: ts.ObjectLiteralExpression
38
- state: InspectorState
39
- checker: ts.TypeChecker
40
- logger: InspectorLogger
41
- sourceFile: ts.SourceFile
42
- basePath?: string
43
- inheritedTags?: string[]
44
- inheritedAuth?: boolean
45
- }
46
-
47
- export interface RegisterHTTPRouteMetaParams {
48
- route: ExportedHTTPRouteConfigMeta
49
- state: InspectorState
50
- logger: InspectorLogger
51
- sourceFile: ts.SourceFile
52
- basePath?: string
53
- inheritedTags?: string[]
54
- inheritedAuth?: boolean
55
- }
56
-
57
- /**
58
- * Extract header schema reference from headers property
59
- */
60
- const extractHeadersSchema = (
61
- obj: ts.ObjectLiteralExpression,
62
- routeName: string,
63
- method: string,
64
- state: InspectorState,
65
- checker: ts.TypeChecker,
66
- logger: InspectorLogger
67
- ): string | undefined => {
68
- const headersNode = getPropertyAssignmentInitializer(
69
- obj,
70
- 'headers',
71
- true,
72
- checker
73
- )
74
- if (!headersNode || !ts.isIdentifier(headersNode)) return undefined
75
-
76
- // Resolve the schema reference
77
- const symbol = checker.getSymbolAtLocation(headersNode)
78
- if (!symbol) return undefined
79
-
80
- const decl = symbol.valueDeclaration || symbol.declarations?.[0]
81
- if (!decl) return undefined
82
-
83
- let sourceFile: string
84
- if (ts.isImportSpecifier(decl)) {
85
- const aliasedSymbol = checker.getAliasedSymbol(symbol)
86
- if (aliasedSymbol) {
87
- const aliasedDecl =
88
- aliasedSymbol.valueDeclaration || aliasedSymbol.declarations?.[0]
89
- if (aliasedDecl) {
90
- sourceFile = aliasedDecl.getSourceFile().fileName
91
- } else {
92
- return undefined
93
- }
94
- } else {
95
- return undefined
96
- }
97
- } else {
98
- sourceFile = decl.getSourceFile().fileName
99
- }
100
-
101
- const vendor = detectSchemaVendorOrError(
102
- headersNode,
103
- checker,
104
- logger,
105
- `Route '${routeName}' header`,
106
- sourceFile
107
- )
108
- if (!vendor) return undefined
109
-
110
- // Create a sanitized schema name from route and method to avoid collisions
111
- const sanitizedRoute = routeName
112
- .replace(/[^a-zA-Z0-9]/g, '_')
113
- .replace(/^_+|_+$/g, '')
114
- const schemaName = `${method.toUpperCase()}_${sanitizedRoute}_Headers`
115
-
116
- state.schemaLookup.set(schemaName, {
117
- variableName: headersNode.text,
118
- sourceFile,
119
- vendor,
120
- })
121
-
122
- return schemaName
123
- }
124
-
125
- /**
126
- * Populate metaInputTypes for a given route based on method, input type,
127
- * query and params.
128
- */
129
- const computeInputTypes = (
130
- metaTypes: Map<
131
- string,
132
- { query?: string[]; params?: string[]; body?: string[] }
133
- >,
134
- methodType: string,
135
- inputType: string | null,
136
- queryValues: string[],
137
- paramsValues: string[]
138
- ): void => {
139
- if (!inputType) return
140
- metaTypes.set(inputType, {
141
- query: queryValues,
142
- params: paramsValues,
143
- body: ['post', 'put', 'patch'].includes(methodType)
144
- ? [...new Set([...queryValues, ...paramsValues])]
145
- : [],
146
- })
147
- }
148
-
149
- /**
150
- * Shared function to register an HTTP route in the inspector state.
151
- * Used by both wireHTTP and wireHTTPRoutes.
152
- */
153
- export function registerHTTPRoute({
154
- obj,
155
- state,
156
- checker,
157
- logger,
158
- sourceFile,
159
- basePath = '',
160
- inheritedTags = [],
161
- inheritedAuth,
162
- }: RegisterHTTPRouteParams): void {
163
- // Extract route path
164
- const routePath = getPropertyValue(obj, 'route') as string | null
165
- if (!routePath) return
166
-
167
- const method = (
168
- (getPropertyValue(obj, 'method') as string) || 'get'
169
- ).toLowerCase()
170
- const fullRoute = basePath + routePath
171
-
172
- // Extract params from route path
173
- let params: string[] = []
174
- try {
175
- const keys = pathToRegexp(fullRoute).keys
176
- params = keys.filter((k) => k.type === 'param').map((k) => k.name)
177
- } catch (e) {
178
- logger.error(
179
- `Failed to parse route '${fullRoute}': ${e instanceof Error ? e.message : e}`
180
- )
181
- return
182
- }
183
-
184
- // Get common metadata
185
- const {
186
- disabled,
187
- title,
188
- tags: routeTags,
189
- summary,
190
- description,
191
- errors,
192
- } = getCommonWireMetaData(obj, 'HTTP route', fullRoute, logger, checker)
193
-
194
- if (disabled) return
195
-
196
- // Merge inherited tags with route tags
197
- const tags = [...inheritedTags, ...(routeTags || [])]
198
-
199
- const query = (getPropertyValue(obj, 'query') as string[]) || []
200
-
201
- // Get function reference
202
- const funcInitializer = getPropertyAssignmentInitializer(
203
- obj,
204
- 'func',
205
- true,
206
- checker
207
- )
208
- if (!funcInitializer) {
209
- logger.critical(
210
- ErrorCode.MISSING_FUNC,
211
- `No valid 'func' property for route '${fullRoute}'.`
212
- )
213
- return
214
- }
215
-
216
- const extracted = extractFunctionName(funcInitializer, checker, state.rootDir)
217
- let funcName = extracted.pikkuFuncId
218
- if (funcName.startsWith('__temp_')) {
219
- funcName = makeContextBasedId('http', method, fullRoute)
220
- }
221
-
222
- let refAddonTarget: string | null = null
223
- if (
224
- ts.isCallExpression(funcInitializer) &&
225
- ts.isIdentifier(funcInitializer.expression) &&
226
- funcInitializer.expression.text === 'ref'
227
- ) {
228
- const [firstArg] = funcInitializer.arguments
229
- if (
230
- firstArg &&
231
- ts.isStringLiteral(firstArg) &&
232
- firstArg.text.includes(':')
233
- ) {
234
- refAddonTarget = firstArg.text
235
- }
236
- }
237
-
238
- const packageName = ts.isIdentifier(funcInitializer)
239
- ? resolveAddonName(
240
- funcInitializer,
241
- checker,
242
- state.rpc.wireAddonDeclarations
243
- )
244
- : null
245
-
246
- // A ref()-wired route points straight at the addon function, the same way the
247
- // CLI and channel adders record one. The addon's own metadata is the contract
248
- // — and it is authoritative where the checker is not: `ref('ns:fn')` only
249
- // types precisely once the consumer's own rpc map already lists the addon's
250
- // functions, so a cold run inferred the whole `FlattenedRPCMap` and a warm one
251
- // inferred the real input. The addon's metadata says which it is either way.
252
- //
253
- // The route stays the consuming app's all the same, so it records no
254
- // packageName: that names the package a wire *runs in*, and running this one
255
- // inside the addon would hand it the addon's middleware and services instead
256
- // of the app's. `ref` reaches the addon over RPC, which enters it properly.
257
- if (refAddonTarget) {
258
- const targetMeta = resolveFunctionMeta(state, refAddonTarget)
259
- if (!targetMeta) {
260
- logger.warn(
261
- `Skipping route '${fullRoute}': addon function metadata for '${refAddonTarget}' is not available yet.`
262
- )
263
- return
264
- }
265
- funcName = refAddonTarget
266
- } else {
267
- ensureFunctionMetadata(
268
- state,
269
- funcName,
270
- fullRoute,
271
- funcInitializer,
272
- checker,
273
- extracted.isHelper
274
- )
275
- }
276
-
277
- // The route's own `auth`, falling back to the group's. Recorded on the meta
278
- // below so an audit can answer "is this route open?" without re-reading the
279
- // source: the route can tighten a sessionless function, and until this was
280
- // written down that tightening existed only in the wiring.
281
- const routeAuthProp = getPropertyValue(obj, 'auth')
282
- const resolvedAuth =
283
- routeAuthProp === true || routeAuthProp === false
284
- ? routeAuthProp
285
- : inheritedAuth
286
-
287
- // For inline functions (e.g. oauth2 handlers), propagate sessionless: true
288
- // when auth is explicitly disabled at the route or group level — the
289
- // developer opted out of auth so no session is required.
290
- {
291
- const inlineMeta = state.functions.meta[funcName]
292
- if (
293
- inlineMeta &&
294
- inlineMeta.sessionless === undefined &&
295
- resolvedAuth === false
296
- ) {
297
- inlineMeta.sessionless = true
298
- }
299
- }
300
-
301
- // Lookup existing function metadata
302
- const fnMeta = resolveFunctionMeta(state, funcName)
303
- if (!fnMeta) {
304
- logger.critical(
305
- ErrorCode.FUNCTION_METADATA_NOT_FOUND,
306
- `No function metadata found for '${funcName}'.`
307
- )
308
- return
309
- }
310
-
311
- if (
312
- !validateAuthSessionless(
313
- logger,
314
- obj,
315
- state,
316
- funcName,
317
- `Route '${fullRoute}'`,
318
- inheritedAuth
319
- )
320
- ) {
321
- return
322
- }
323
-
324
- const input = fnMeta.inputs?.[0] || null
325
-
326
- const getRouteInputKeys = (): string[] | null => {
327
- const inputTypes = state.typesLookup.get(funcName)
328
- if (inputTypes && inputTypes.length > 0) {
329
- return extractTypeKeys(inputTypes[0])
330
- }
331
-
332
- const targetMeta = resolveFunctionMeta(state, funcName)
333
- if (targetMeta?.inputSchemaName) {
334
- const schema = state.schemas[targetMeta.inputSchemaName] as any
335
- const properties = schema?.properties
336
- if (properties && typeof properties === 'object') {
337
- return Object.keys(properties)
338
- }
339
- }
340
-
341
- return null
342
- }
343
-
344
- // Validate that route params and query params exist in function input type
345
- if (params.length > 0 || query.length > 0) {
346
- const inputKeys = getRouteInputKeys()
347
- if (!inputKeys) {
348
- // Input shape isn't inspectable at this phase (e.g. addon ref or opaque handler).
349
- // Skip param/query validation rather than emitting a false positive.
350
- } else {
351
- // Check path params
352
- if (params.length > 0) {
353
- const missingParams = params.filter((p) => !inputKeys.includes(p))
354
- if (missingParams.length > 0) {
355
- logger.critical(
356
- ErrorCode.ROUTE_PARAM_MISMATCH,
357
- `Route '${fullRoute}' has path parameter(s) [${missingParams.join(', ')}] ` +
358
- `not found in function '${funcName}' input type. ` +
359
- `Input type has: [${inputKeys.join(', ')}]`
360
- )
361
- return
362
- }
363
- }
364
-
365
- // Check query params
366
- if (query.length > 0) {
367
- const missingQuery = query.filter((q) => !inputKeys.includes(q))
368
- if (missingQuery.length > 0) {
369
- logger.critical(
370
- ErrorCode.ROUTE_QUERY_MISMATCH,
371
- `Route '${fullRoute}' has query parameter(s) [${missingQuery.join(', ')}] ` +
372
- `not found in function '${funcName}' input type. ` +
373
- `Input type has: [${inputKeys.join(', ')}]`
374
- )
375
- return
376
- }
377
- }
378
- }
379
- }
380
-
381
- // Compute inputTypes (body/query/params)
382
- computeInputTypes(state.http.metaInputTypes, method, input, query, params)
383
-
384
- // Resolve middleware
385
- const middleware = resolveHTTPMiddlewareFromObject(
386
- state,
387
- fullRoute,
388
- obj,
389
- tags,
390
- checker
391
- )
392
-
393
- // Resolve permissions
394
- const permissions = resolvePermissions(state, obj, tags, checker)
395
-
396
- state.serviceAggregation.usedFunctions.add(funcName)
397
- extractWireNames(middleware).forEach((name) =>
398
- state.serviceAggregation.usedMiddleware.add(name)
399
- )
400
- extractWireNames(permissions).forEach((name) =>
401
- state.serviceAggregation.usedPermissions.add(name)
402
- )
403
-
404
- // Check for SSE
405
- const sse = getPropertyValue(obj, 'sse') === true
406
-
407
- // Extract header schema
408
- const headersSchemaName = extractHeadersSchema(
409
- obj,
410
- fullRoute,
411
- method,
412
- state,
413
- checker,
414
- logger
415
- )
416
-
417
- // Record route
418
- state.http.files.add(sourceFile.fileName)
419
- state.http.meta[method][fullRoute] = {
420
- pikkuFuncId: funcName,
421
- ...(packageName && { packageName }),
422
- route: fullRoute,
423
- sourceFile: sourceFile.fileName,
424
- method: method as HTTPMethod,
425
- ...(resolvedAuth !== undefined && { auth: resolvedAuth }),
426
- params: params.length > 0 ? params : undefined,
427
- query: query.length > 0 ? query : undefined,
428
- inputTypes: undefined,
429
- title,
430
- summary,
431
- description,
432
- errors,
433
- tags: tags.length > 0 ? tags : undefined,
434
- middleware,
435
- permissions,
436
- sse: sse ? true : undefined,
437
- headersSchemaName,
438
- groupBasePath: basePath || undefined,
439
- }
440
- }
441
-
442
- export function registerHTTPRouteMeta({
443
- route,
444
- state,
445
- logger,
446
- sourceFile,
447
- basePath = '',
448
- inheritedTags = [],
449
- inheritedAuth,
450
- }: RegisterHTTPRouteMetaParams): void {
451
- const method = route.method.toLowerCase()
452
- const fullRoute = basePath + route.route
453
- const tags = [...inheritedTags, ...(route.tags || [])]
454
- const funcName = route.func.pikkuFuncId
455
- const fnMeta = resolveFunctionMeta(state, funcName)
456
-
457
- if (!fnMeta) {
458
- logger.critical(
459
- ErrorCode.FUNCTION_METADATA_NOT_FOUND,
460
- `No function metadata found for '${funcName}'.`
461
- )
462
- return
463
- }
464
-
465
- let params: string[] = []
466
- try {
467
- const keys = pathToRegexp(fullRoute).keys
468
- params = keys.filter((k) => k.type === 'param').map((k) => k.name)
469
- } catch (error) {
470
- logger.error(
471
- `Failed to parse route '${fullRoute}': ${error instanceof Error ? error.message : error}`
472
- )
473
- return
474
- }
475
-
476
- if (!route.func.packageName) {
477
- computeInputTypes(
478
- state.http.metaInputTypes,
479
- method,
480
- fnMeta.inputs?.[0] || null,
481
- [],
482
- params
483
- )
484
- }
485
-
486
- state.serviceAggregation.usedFunctions.add(funcName)
487
- state.http.files.add(sourceFile.fileName)
488
- state.http.meta[method][fullRoute] = {
489
- pikkuFuncId: funcName,
490
- ...(route.func.packageName && { packageName: route.func.packageName }),
491
- route: fullRoute,
492
- sourceFile: sourceFile.fileName,
493
- method: method as HTTPMethod,
494
- ...((route.auth ?? inheritedAuth) !== undefined && {
495
- auth: route.auth ?? inheritedAuth,
496
- }),
497
- params: params.length > 0 ? params : undefined,
498
- inputTypes: undefined,
499
- tags: tags.length > 0 ? tags : undefined,
500
- sse: route.sse ? true : undefined,
501
- groupBasePath: basePath || undefined,
502
- }
503
- }
504
-
505
- /**
506
- * Process wireHTTP calls
507
- */
508
- export const addHTTPRoute: AddWiring = (
509
- logger,
510
- node,
511
- checker,
512
- state,
513
- _options
514
- ) => {
515
- if (!ts.isCallExpression(node)) return
516
-
517
- const { expression, arguments: args } = node
518
- if (!ts.isIdentifier(expression) || expression.text !== 'wireHTTP') return
519
-
520
- const firstArg = args[0]
521
- if (!firstArg || !ts.isObjectLiteralExpression(firstArg)) return
522
-
523
- registerHTTPRoute({
524
- obj: firstArg,
525
- state,
526
- checker,
527
- logger,
528
- sourceFile: node.getSourceFile(),
529
- })
530
- }