@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.
- package/CHANGELOG.md +330 -0
- package/dist/add/add-analytics.d.ts +9 -0
- package/dist/add/add-analytics.js +178 -0
- package/dist/add/add-auth.js +0 -54
- package/dist/add/add-feature-flag.d.ts +2 -0
- package/dist/add/add-feature-flag.js +162 -0
- package/dist/add/add-wire-addon.js +1 -0
- package/dist/add/add-wire-remote-addon.js +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/inspector.js +4 -0
- package/dist/surface/collect-surface.d.ts +58 -0
- package/dist/surface/collect-surface.js +613 -0
- package/dist/types.d.ts +20 -11
- package/dist/utils/filter-inspector-state.js +14 -0
- package/dist/utils/post-process.js +15 -0
- package/dist/utils/read-module-specifiers.d.ts +8 -0
- package/dist/utils/read-module-specifiers.js +23 -0
- package/dist/utils/read-tsconfig-out-dir.d.ts +5 -0
- package/dist/utils/read-tsconfig-out-dir.js +12 -0
- package/dist/utils/resolve-deploy-target.d.ts +7 -0
- package/dist/utils/resolve-deploy-target.js +15 -7
- package/dist/utils/serialize-inspector-state.d.ts +5 -0
- package/dist/utils/serialize-inspector-state.js +8 -0
- package/dist/visit.js +4 -0
- package/package.json +16 -6
- package/run-tests.sh +21 -6
- package/src/add/add-addon-bans.ts +0 -85
- package/src/add/add-agent-scorer.test.ts +0 -197
- package/src/add/add-agent-scorer.ts +0 -83
- package/src/add/add-agent.test.ts +0 -87
- package/src/add/add-agent.ts +0 -638
- package/src/add/add-approval-description.ts +0 -76
- package/src/add/add-auth.test.ts +0 -791
- package/src/add/add-auth.ts +0 -424
- package/src/add/add-channel.ts +0 -778
- package/src/add/add-cli-renderers.test.ts +0 -74
- package/src/add/add-cli.ts +0 -1006
- package/src/add/add-credential.ts +0 -186
- package/src/add/add-feature.test.ts +0 -306
- package/src/add/add-feature.ts +0 -253
- package/src/add/add-file-extends-core-type.ts +0 -66
- package/src/add/add-file-with-config.ts +0 -45
- package/src/add/add-file-with-factory.test.ts +0 -134
- package/src/add/add-file-with-factory.ts +0 -288
- package/src/add/add-functions.test.ts +0 -743
- package/src/add/add-functions.ts +0 -1548
- package/src/add/add-gateway.ts +0 -143
- package/src/add/add-http-route-ref.test.ts +0 -149
- package/src/add/add-http-route.ts +0 -530
- package/src/add/add-http-routes.ts +0 -471
- package/src/add/add-keyed-wiring.ts +0 -180
- package/src/add/add-mcp-prompt.ts +0 -157
- package/src/add/add-mcp-resource.ts +0 -175
- package/src/add/add-middleware.test.ts +0 -196
- package/src/add/add-middleware.ts +0 -879
- package/src/add/add-permission-auth.test.ts +0 -59
- package/src/add/add-permission.ts +0 -311
- package/src/add/add-personas.test.ts +0 -406
- package/src/add/add-personas.ts +0 -287
- package/src/add/add-queue-worker.ts +0 -117
- package/src/add/add-rpc-invocations.test.ts +0 -287
- package/src/add/add-rpc-invocations.ts +0 -221
- package/src/add/add-scenario-step.test.ts +0 -509
- package/src/add/add-schedule.ts +0 -120
- package/src/add/add-scope.test.ts +0 -419
- package/src/add/add-scope.ts +0 -221
- package/src/add/add-secret.ts +0 -10
- package/src/add/add-subject-scenario-steps.test.ts +0 -161
- package/src/add/add-system-role.test.ts +0 -297
- package/src/add/add-system-role.ts +0 -162
- package/src/add/add-trigger.ts +0 -165
- package/src/add/add-variable.ts +0 -10
- package/src/add/add-wire-addon.test.ts +0 -185
- package/src/add/add-wire-addon.ts +0 -146
- package/src/add/add-wire-remote-addon.ts +0 -80
- package/src/add/add-workflow-edge-cases.test.ts +0 -201
- package/src/add/add-workflow-fanout.test.ts +0 -166
- package/src/add/add-workflow-graph-foreach.test.ts +0 -174
- package/src/add/add-workflow-graph-input.test.ts +0 -94
- package/src/add/add-workflow-graph-notes.test.ts +0 -74
- package/src/add/add-workflow-graph.ts +0 -644
- package/src/add/add-workflow-on-error.test.ts +0 -118
- package/src/add/add-workflow-return-switch.test.ts +0 -121
- package/src/add/add-workflow-silent-drops.test.ts +0 -261
- package/src/add/add-workflow-sleep-expression.test.ts +0 -96
- package/src/add/add-workflow.test.ts +0 -155
- package/src/add/add-workflow.ts +0 -482
- package/src/add/addon-bans.test.ts +0 -121
- package/src/add/addon-contracts.test.ts +0 -221
- package/src/add/allow-escape-hatches.test.ts +0 -144
- package/src/add/audit-meta.test.ts +0 -75
- package/src/add/classified-sink-check.test.ts +0 -347
- package/src/add/config-value-metadata.test.ts +0 -263
- package/src/add/dynamic-import-check.test.ts +0 -119
- package/src/add/expect-eventually-scenario-only.test.ts +0 -108
- package/src/add/function-body-span.test.ts +0 -96
- package/src/add/inline-wiring-function.test.ts +0 -104
- package/src/add/pii-check.test.ts +0 -258
- package/src/add/rpc-type-cast.test.ts +0 -123
- package/src/add/scenario-instrumentation.test.ts +0 -89
- package/src/add/scenario-instrumentation.ts +0 -42
- package/src/add/scenario-marker.test.ts +0 -89
- package/src/add/scenario-not-extractable.test.ts +0 -159
- package/src/add/scenario-services.test.ts +0 -103
- package/src/add/scenario-skip.test.ts +0 -83
- package/src/add/validate-workflow-graph-addons.test.ts +0 -102
- package/src/add/wire-name-literal.test.ts +0 -117
- package/src/error-codes-emitted.test.ts +0 -76
- package/src/error-codes.ts +0 -145
- package/src/index.ts +0 -66
- package/src/inspector.ts +0 -575
- package/src/schema-generator.ts +0 -1
- package/src/source-file-cache.ts +0 -73
- package/src/tsconfig-paths.test.ts +0 -90
- package/src/types-map.ts +0 -141
- package/src/types.ts +0 -775
- package/src/utils/annotate-http-route-auth.test.ts +0 -161
- package/src/utils/annotate-http-route-auth.ts +0 -53
- package/src/utils/check-classified-sinks.ts +0 -215
- package/src/utils/check-pii-output.ts +0 -120
- package/src/utils/compute-diagnostics.test.ts +0 -106
- package/src/utils/compute-required-schemas.ts +0 -48
- package/src/utils/contract-hashes.test.ts +0 -553
- package/src/utils/contract-hashes.ts +0 -387
- package/src/utils/custom-types-generator.test.ts +0 -124
- package/src/utils/custom-types-generator.ts +0 -150
- package/src/utils/detect-schema-vendor.test.ts +0 -123
- package/src/utils/detect-schema-vendor.ts +0 -120
- package/src/utils/does-type-extend-core-type.ts +0 -53
- package/src/utils/ensure-function-metadata.ts +0 -385
- package/src/utils/extract-function-name.ts +0 -612
- package/src/utils/extract-function-node.ts +0 -70
- package/src/utils/extract-node-value.test.ts +0 -117
- package/src/utils/extract-node-value.ts +0 -172
- package/src/utils/extract-secret-usage.test.ts +0 -81
- package/src/utils/extract-secret-usage.ts +0 -73
- package/src/utils/extract-services.ts +0 -70
- package/src/utils/extract-surface-usage.test.ts +0 -147
- package/src/utils/extract-surface-usage.ts +0 -121
- package/src/utils/filter-inspector-state.test.ts +0 -2232
- package/src/utils/filter-inspector-state.ts +0 -1298
- package/src/utils/filter-utils.test.ts +0 -843
- package/src/utils/filter-utils.ts +0 -161
- package/src/utils/find-root-dir.ts +0 -68
- package/src/utils/find-zod-transform.test.ts +0 -70
- package/src/utils/find-zod-transform.ts +0 -103
- package/src/utils/get-exported-variable-name.ts +0 -48
- package/src/utils/get-files-and-methods.ts +0 -157
- package/src/utils/get-property-value.test.ts +0 -141
- package/src/utils/get-property-value.ts +0 -331
- package/src/utils/hash.ts +0 -26
- package/src/utils/literal-properties.ts +0 -97
- package/src/utils/load-addon-functions-meta.test.ts +0 -157
- package/src/utils/load-addon-functions-meta.ts +0 -508
- package/src/utils/load-addon-scopes.test.ts +0 -138
- package/src/utils/middleware.test.ts +0 -204
- package/src/utils/middleware.ts +0 -303
- package/src/utils/nested-project-filter.test.ts +0 -53
- package/src/utils/nested-project-filter.ts +0 -28
- package/src/utils/permissions-shorthand.test.ts +0 -79
- package/src/utils/permissions.test.ts +0 -125
- package/src/utils/permissions.ts +0 -129
- package/src/utils/post-process.test.ts +0 -1094
- package/src/utils/post-process.ts +0 -1604
- package/src/utils/resolve-addon-package.ts +0 -106
- package/src/utils/resolve-core-type.test.ts +0 -142
- package/src/utils/resolve-core-type.ts +0 -35
- package/src/utils/resolve-deploy-target.test.ts +0 -135
- package/src/utils/resolve-deploy-target.ts +0 -65
- package/src/utils/resolve-function-meta.ts +0 -25
- package/src/utils/resolve-function-types.ts +0 -42
- package/src/utils/resolve-identifier.ts +0 -46
- package/src/utils/resolve-ref-contract.ts +0 -71
- package/src/utils/resolve-versions.test.ts +0 -499
- package/src/utils/resolve-versions.ts +0 -228
- package/src/utils/schema-cache.test.ts +0 -124
- package/src/utils/schema-generator.test.ts +0 -272
- package/src/utils/schema-generator.ts +0 -780
- package/src/utils/secret-alias-services.test.ts +0 -146
- package/src/utils/secret-alias-services.ts +0 -58
- package/src/utils/serialize-inspector-state.ts +0 -742
- package/src/utils/serialize-mcp-json.ts +0 -150
- package/src/utils/serialize-middleware-groups-meta.ts +0 -36
- package/src/utils/serialize-openapi-json.ts +0 -277
- package/src/utils/serialize-permissions-groups-meta.ts +0 -7
- package/src/utils/single-declaration.ts +0 -57
- package/src/utils/type-utils.ts +0 -145
- package/src/utils/validate-auth-sessionless.ts +0 -30
- package/src/utils/validate-exposed-functions-gated.test.ts +0 -230
- package/src/utils/validate-exposed-functions-gated.ts +0 -103
- package/src/utils/validate-tags-resolve-to-middleware.test.ts +0 -108
- package/src/utils/validate-tags-resolve-to-middleware.ts +0 -48
- package/src/utils/workflow/derive-workflow-plan.test.ts +0 -178
- package/src/utils/workflow/derive-workflow-plan.ts +0 -117
- package/src/utils/workflow/dsl/deserialize-dsl-workflow.ts +0 -1465
- package/src/utils/workflow/dsl/deserialize-fanout-body.test.ts +0 -71
- package/src/utils/workflow/dsl/deserialize-fanout-fidelity.test.ts +0 -99
- package/src/utils/workflow/dsl/deserialize-graph-next.test.ts +0 -161
- package/src/utils/workflow/dsl/deserialize-roundtrip-bindings.test.ts +0 -121
- package/src/utils/workflow/dsl/deserialize-roundtrip-values.test.ts +0 -116
- package/src/utils/workflow/dsl/deserialize-roundtrip.test.ts +0 -145
- package/src/utils/workflow/dsl/extract-approval-policy.test.ts +0 -71
- package/src/utils/workflow/dsl/extract-dsl-workflow.ts +0 -2254
- package/src/utils/workflow/dsl/index.ts +0 -11
- package/src/utils/workflow/dsl/patterns.ts +0 -440
- package/src/utils/workflow/dsl/validation.ts +0 -203
- package/src/utils/workflow/graph/convert-dsl-to-graph-skip.test.ts +0 -35
- package/src/utils/workflow/graph/convert-dsl-to-graph.ts +0 -543
- package/src/utils/workflow/graph/fanout-node-identity.test.ts +0 -105
- package/src/utils/workflow/graph/finalize-workflow-wires.ts +0 -310
- package/src/utils/workflow/graph/finalize-workflows.test.ts +0 -50
- package/src/utils/workflow/graph/finalize-workflows.ts +0 -130
- package/src/utils/workflow/graph/index.ts +0 -28
- package/src/utils/workflow/graph/serialize-workflow-graph.ts +0 -240
- package/src/utils/workflow/graph/workflow-graph.types.ts +0 -281
- package/src/visit.ts +0 -181
- package/tsconfig.json +0 -19
- 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
|
-
}
|