feat: precise --changed via stack-trace source file tracking; OTel sink docs
This commit is contained in:
+27
-3
@@ -13,6 +13,7 @@ interface CapturedRoute {
|
||||
url: string
|
||||
schema?: Record<string, unknown>
|
||||
prefix?: string
|
||||
sourceFile?: string
|
||||
}
|
||||
|
||||
export interface DiscoveryResult {
|
||||
@@ -24,6 +25,26 @@ export interface DiscoveryResult {
|
||||
|
||||
// WeakMap to store captured routes per Fastify instance (no memory leaks)
|
||||
const capturedRoutes = new WeakMap<object, CapturedRoute[]>()
|
||||
|
||||
/**
|
||||
* Extract the source file that registered a route from a stack trace.
|
||||
* Finds the first frame outside node_modules and APOPHIS internal directories.
|
||||
*/
|
||||
function extractSourceFile(stack: string): string | undefined {
|
||||
const lines = stack.split('\n')
|
||||
for (let i = 3; i < lines.length; i++) {
|
||||
const line = lines[i]
|
||||
if (!line) continue
|
||||
const match = line.match(/\((.*?):\d+:\d+\)/) ?? line.match(/at\s+(.*?):\d+:\d+/)
|
||||
if (!match || !match[1]) continue
|
||||
const filePath = match[1]
|
||||
if (!filePath.includes('node_modules') && !filePath.includes('/apophis/') && !filePath.includes('\\apophis\\')) {
|
||||
return filePath
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture a route for discovery.
|
||||
* Called from the plugin's `onRoute` hook.
|
||||
@@ -32,6 +53,7 @@ export const captureRoute = (
|
||||
instance: object,
|
||||
route: CapturedRoute
|
||||
): void => {
|
||||
route.sourceFile = extractSourceFile(new Error().stack ?? '')
|
||||
const existing = capturedRoutes.get(instance) ?? []
|
||||
existing.push(route)
|
||||
capturedRoutes.set(instance, existing)
|
||||
@@ -140,9 +162,11 @@ export const discoverRouteDetails = (instance: DiscoverRouteDetailsInput): Disco
|
||||
const captured = capturedRoutes.get(instance)
|
||||
if (captured && captured.length > 0) {
|
||||
return {
|
||||
routes: captured.map((route) =>
|
||||
extractContract(route.url, route.method, route.schema)
|
||||
),
|
||||
routes: captured.map((route) => {
|
||||
const contract = extractContract(route.url, route.method, route.schema)
|
||||
contract.sourceFile = route.sourceFile
|
||||
return contract
|
||||
}),
|
||||
source: 'captured',
|
||||
hasSchemaMetadata: true,
|
||||
warnings: [],
|
||||
|
||||
Reference in New Issue
Block a user