github.com/grafana/pyroscope@v1.18.0/public/app/services/render.ts (about) 1 import { Result } from '@pyroscope/util/fp'; 2 import { 3 Profile, 4 Groups, 5 FlamebearerProfileSchema, 6 } from '@pyroscope/legacy/models'; 7 import { z } from 'zod'; 8 import type { ZodError } from 'zod'; 9 import { buildRenderURL } from '@pyroscope/util/updateRequests'; 10 import { Timeline, TimelineSchema } from '@pyroscope/models/timeline'; 11 import type { RequestError } from '@pyroscope/services/base'; 12 import { request } from '@pyroscope/services/base'; 13 14 export interface RenderOutput { 15 profile: Profile; 16 timeline: Timeline; 17 groups?: Groups; 18 } 19 20 interface RenderSingleProps { 21 from: string; 22 until: string; 23 query: string; 24 refreshToken?: string; 25 maxNodes: string | number; 26 } 27 export async function renderSingle( 28 props: RenderSingleProps, 29 controller?: { 30 signal?: AbortSignal; 31 } 32 ): Promise<Result<RenderOutput, RequestError | ZodError>> { 33 const url = buildRenderURL(props); 34 // TODO 35 const response = await request(`/pyroscope${url}&format=json`, { 36 signal: controller?.signal, 37 }); 38 39 if (response.isErr) { 40 return Result.err<RenderOutput, RequestError>(response.error); 41 } 42 43 const parsed = FlamebearerProfileSchema.merge( 44 z.object({ 45 timeline: TimelineSchema, 46 }) 47 ) 48 .merge(z.object({ telemetry: z.object({}).passthrough().optional() })) 49 .safeParse(response.value); 50 51 if (parsed.success) { 52 // TODO: strip timeline 53 const profile = parsed.data; 54 const { timeline } = parsed.data; 55 56 return Result.ok({ 57 profile, 58 timeline, 59 }); 60 } 61 62 return Result.err(parsed.error); 63 }