@@ -40,6 +40,7 @@ import { cn } from "~/utils/cn";
4040import { v3DeploymentParams , v3DeploymentsPath , v3RunsPath } from "~/utils/pathBuilder" ;
4141import { capitalizeWord } from "~/utils/string" ;
4242import { UserTag } from "../_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route" ;
43+ import { DeploymentEventFromString } from "@trigger.dev/core/v3/schemas" ;
4344
4445export const loader = async ( { request, params } : LoaderFunctionArgs ) => {
4546 const userId = await requireUserId ( request ) ;
@@ -48,15 +49,15 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
4849
4950 try {
5051 const presenter = new DeploymentPresenter ( ) ;
51- const { deployment, s2Logs } = await presenter . call ( {
52+ const { deployment, eventStream } = await presenter . call ( {
5253 userId,
5354 organizationSlug,
5455 projectSlug : projectParam ,
5556 environmentSlug : envParam ,
5657 deploymentShortCode : deploymentParam ,
5758 } ) ;
5859
59- return typedjson ( { deployment, s2Logs } ) ;
60+ return typedjson ( { deployment, eventStream } ) ;
6061 } catch ( error ) {
6162 console . error ( error ) ;
6263 throw new Response ( undefined , {
@@ -69,18 +70,18 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
6970type LogEntry = {
7071 message : string ;
7172 timestamp : Date ;
72- level : "info" | "error" | "warn" ;
73+ level : "info" | "error" | "warn" | "debug" ;
7374} ;
7475
7576export default function Page ( ) {
76- const { deployment, s2Logs } = useTypedLoaderData < typeof loader > ( ) ;
77+ const { deployment, eventStream } = useTypedLoaderData < typeof loader > ( ) ;
7778 const organization = useOrganization ( ) ;
7879 const project = useProject ( ) ;
7980 const environment = useEnvironment ( ) ;
8081 const location = useLocation ( ) ;
8182 const page = new URLSearchParams ( location . search ) . get ( "page" ) ;
8283
83- const logsDisabled = s2Logs === undefined ;
84+ const logsDisabled = eventStream === undefined ;
8485 const [ logs , setLogs ] = useState < LogEntry [ ] > ( [ ] ) ;
8586 const [ isStreaming , setIsStreaming ] = useState ( true ) ;
8687 const [ streamError , setStreamError ] = useState < string | null > ( null ) ;
@@ -97,9 +98,9 @@ export default function Page() {
9798
9899 const streamLogs = async ( ) => {
99100 try {
100- const s2 = new S2 ( { accessToken : s2Logs . accessToken } ) ;
101- const basin = s2 . basin ( s2Logs . basin ) ;
102- const stream = basin . stream ( s2Logs . stream ) ;
101+ const s2 = new S2 ( { accessToken : eventStream . s2 . accessToken } ) ;
102+ const basin = s2 . basin ( eventStream . s2 . basin ) ;
103+ const stream = basin . stream ( eventStream . s2 . stream ) ;
103104
104105 const readSession = await stream . readSession (
105106 {
@@ -113,27 +114,49 @@ export default function Page() {
113114 const decoder = new TextDecoder ( ) ;
114115
115116 for await ( const record of readSession ) {
116- try {
117- const headers : Record < string , string > = { } ;
118-
119- if ( record . headers ) {
120- for ( const [ nameBytes , valueBytes ] of record . headers ) {
121- headers [ decoder . decode ( nameBytes ) ] = decoder . decode ( valueBytes ) ;
117+ const decoded = decoder . decode ( record . body ) ;
118+ const result = DeploymentEventFromString . safeParse ( decoded ) ;
119+
120+ if ( ! result . success ) {
121+ // fallback to the previous format in s2 logs for compatibility
122+ try {
123+ const headers : Record < string , string > = { } ;
124+
125+ if ( record . headers ) {
126+ for ( const [ nameBytes , valueBytes ] of record . headers ) {
127+ headers [ decoder . decode ( nameBytes ) ] = decoder . decode ( valueBytes ) ;
128+ }
122129 }
130+ const level = ( headers [ "level" ] ?. toLowerCase ( ) as LogEntry [ "level" ] ) ?? "info" ;
131+
132+ setLogs ( ( prevLogs ) => [
133+ ...prevLogs ,
134+ {
135+ timestamp : new Date ( record . timestamp ) ,
136+ message : decoded ,
137+ level,
138+ } ,
139+ ] ) ;
140+ } catch ( err ) {
141+ console . error ( "Failed to parse log record:" , err ) ;
123142 }
124- const level = ( headers [ "level" ] ?. toLowerCase ( ) as LogEntry [ "level" ] ) ?? "info" ;
125-
126- setLogs ( ( prevLogs ) => [
127- ...prevLogs ,
128- {
129- timestamp : new Date ( record . timestamp ) ,
130- message : decoder . decode ( record . body ) ,
131- level,
132- } ,
133- ] ) ;
134- } catch ( err ) {
135- console . error ( "Failed to parse log record:" , err ) ;
143+
144+ continue ;
136145 }
146+
147+ const event = result . data ;
148+ if ( event . type !== "log" ) {
149+ continue ;
150+ }
151+
152+ setLogs ( ( prevLogs ) => [
153+ ...prevLogs ,
154+ {
155+ timestamp : new Date ( record . timestamp ) ,
156+ message : event . data . message ,
157+ level : event . data . level ,
158+ } ,
159+ ] ) ;
137160 }
138161 } catch ( error ) {
139162 if ( abortController . signal . aborted ) return ;
@@ -158,7 +181,7 @@ export default function Page() {
158181 return ( ) => {
159182 abortController . abort ( ) ;
160183 } ;
161- } , [ s2Logs ?. basin , s2Logs ?. stream , s2Logs ?. accessToken , isPending ] ) ;
184+ } , [ eventStream ?. s2 ?. basin , eventStream ?. s2 ?. stream , eventStream ?. s2 ?. accessToken , isPending ] ) ;
162185
163186 return (
164187 < div className = "grid h-full max-h-full grid-rows-[2.5rem_1fr] overflow-hidden bg-background-bright" >
0 commit comments