@@ -51,12 +51,14 @@ import type {
5151 PageError ,
5252 IntervalRouteDefinitions ,
5353 IntervalPageHandler ,
54+ IntervalErrorHandler ,
5455} from '../types'
5556import type { DataChannelConnection } from './DataChannelConnection'
5657import type { IceServer } from './DataChannelConnection'
5758import TransactionLoadingState from './TransactionLoadingState'
5859import { Interval , InternalConfig , IntervalError } from '..'
5960import Page from './Page'
61+ import Action from './Action'
6062import {
6163 Layout ,
6264 BasicLayout ,
@@ -122,6 +124,7 @@ export default class IntervalClient {
122124 #resolveShutdown: ( ( ) => void ) | undefined
123125 #config: InternalConfig
124126
127+ #routes: Map < string , Action | Page > = new Map ( )
125128 #actionDefinitions: ActionDefinition [ ] = [ ]
126129 #pageDefinitions: PageDefinition [ ] = [ ]
127130 #actionHandlers: Map < string , IntervalActionHandler > = new Map ( )
@@ -136,6 +139,8 @@ export default class IntervalClient {
136139 environment : ActionEnvironment | undefined
137140 #forcePeerMessages = false
138141
142+ #onError: IntervalErrorHandler | undefined
143+
139144 constructor ( interval : Interval , config : InternalConfig ) {
140145 this . #interval = interval
141146 this . #apiKey = config . apiKey
@@ -185,43 +190,55 @@ export default class IntervalClient {
185190 if ( config . setHostHandlers ) {
186191 config . setHostHandlers ( this . #createRPCHandlers( ) )
187192 }
193+
194+ if ( config . onError ) {
195+ this . #onError = config . onError
196+ }
188197 }
189198
190199 async #walkRoutes( ) {
200+ const routes = new Map < string , Action | Page > ( )
201+
191202 const pageDefinitions : PageDefinition [ ] = [ ]
192203 const actionDefinitions : ( ActionDefinition & { handler : undefined } ) [ ] = [ ]
193204 const actionHandlers = new Map < string , IntervalActionHandler > ( )
194205 const pageHandlers = new Map < string , IntervalPageHandler > ( )
195206
196- function walkRouter ( groupSlug : string , router : Page ) {
207+ function walkRouter ( groupSlug : string , page : Page ) {
208+ routes . set ( groupSlug , page )
209+
197210 pageDefinitions . push ( {
198211 slug : groupSlug ,
199- name : router . name ,
200- description : router . description ,
201- hasHandler : ! ! router . handler ,
202- unlisted : router . unlisted ,
203- access : router . access ,
212+ name : page . name ,
213+ description : page . description ,
214+ hasHandler : ! ! page . handler ,
215+ unlisted : page . unlisted ,
216+ access : page . access ,
204217 } )
205218
206- if ( router . handler ) {
207- pageHandlers . set ( groupSlug , router . handler )
219+ if ( page . handler ) {
220+ pageHandlers . set ( groupSlug , page . handler )
208221 }
209222
210- for ( const [ slug , def ] of Object . entries ( router . routes ) ) {
223+ for ( let [ slug , def ] of Object . entries ( page . routes ) ) {
211224 if ( def instanceof Page ) {
212225 walkRouter ( `${ groupSlug } /${ slug } ` , def )
213226 } else {
227+ const fullSlug = `${ groupSlug } /${ slug } `
228+
229+ if ( ! ( def instanceof Action ) ) {
230+ def = new Action ( def )
231+ routes . set ( fullSlug , def )
232+ }
233+
214234 actionDefinitions . push ( {
215235 groupSlug,
216236 slug,
217- ...( 'handler' in def ? def : { } ) ,
237+ ...def ,
218238 handler : undefined ,
219239 } )
220240
221- actionHandlers . set (
222- `${ groupSlug } /${ slug } ` ,
223- 'handler' in def ? def . handler : def
224- )
241+ actionHandlers . set ( fullSlug , def . handler )
225242 }
226243 }
227244 }
@@ -247,28 +264,33 @@ export default class IntervalClient {
247264 }
248265 }
249266
250- const routes = {
267+ const allRoutes = {
251268 ...this . #config. actions ,
252269 ...this . #config. groups ,
253270 ...fileSystemRoutes ,
254271 ...this . #config. routes ,
255272 }
256273
257- if ( routes ) {
258- for ( const [ slug , def ] of Object . entries ( routes ) ) {
259- if ( def instanceof Page ) {
260- walkRouter ( slug , def )
261- } else {
262- actionDefinitions . push ( {
263- slug,
264- ...( 'handler' in def ? def : { } ) ,
265- handler : undefined ,
266- } )
267- actionHandlers . set ( slug , 'handler' in def ? def . handler : def )
274+ for ( let [ slug , def ] of Object . entries ( allRoutes ) ) {
275+ if ( def instanceof Page ) {
276+ walkRouter ( slug , def )
277+ } else {
278+ if ( ! ( def instanceof Action ) ) {
279+ def = new Action ( def )
268280 }
281+
282+ actionDefinitions . push ( {
283+ slug,
284+ ...def ,
285+ handler : undefined ,
286+ } )
287+
288+ routes . set ( slug , def )
289+ actionHandlers . set ( slug , def . handler )
269290 }
270291 }
271292
293+ this . #routes = routes
272294 this . #pageDefinitions = pageDefinitions
273295 this . #actionDefinitions = actionDefinitions
274296 this . #actionHandlers = actionHandlers
@@ -1148,6 +1170,16 @@ export default class IntervalClient {
11481170 }
11491171 }
11501172
1173+ this . #onError?.( {
1174+ error : err ,
1175+ route : action . slug ,
1176+ routeDefinition : this . #routes. get ( action . slug ) ,
1177+ params : ctx . params ,
1178+ environment : ctx . environment ,
1179+ user : ctx . user ,
1180+ organization : ctx . organization ,
1181+ } )
1182+
11511183 const result : ActionResultSchema = {
11521184 schemaVersion : TRANSACTION_RESULT_SCHEMA_VERSION ,
11531185 status : 'FAILURE' ,
@@ -1545,6 +1577,15 @@ export default class IntervalClient {
15451577 page . title = page . title ( )
15461578 } catch ( err ) {
15471579 this . #logger. error ( err )
1580+ this . #onError?.( {
1581+ error : err ,
1582+ route : ctx . page . slug ,
1583+ routeDefinition : this . #routes. get ( ctx . page . slug ) ,
1584+ params : ctx . params ,
1585+ environment : ctx . environment ,
1586+ user : ctx . user ,
1587+ organization : ctx . organization ,
1588+ } )
15481589 errors . push ( pageError ( err , 'title' ) )
15491590 }
15501591 }
@@ -1559,6 +1600,15 @@ export default class IntervalClient {
15591600 } )
15601601 . catch ( err => {
15611602 this . #logger. error ( err )
1603+ this . #onError?.( {
1604+ error : err ,
1605+ route : ctx . page . slug ,
1606+ routeDefinition : this . #routes. get ( ctx . page . slug ) ,
1607+ params : ctx . params ,
1608+ environment : ctx . environment ,
1609+ user : ctx . user ,
1610+ organization : ctx . organization ,
1611+ } )
15621612 errors . push ( pageError ( err , 'title' ) )
15631613 scheduleSendPage ( )
15641614 } )
@@ -1570,6 +1620,15 @@ export default class IntervalClient {
15701620 page . description = page . description ( )
15711621 } catch ( err ) {
15721622 this . #logger. error ( err )
1623+ this . #onError?.( {
1624+ error : err ,
1625+ route : ctx . page . slug ,
1626+ routeDefinition : this . #routes. get ( ctx . page . slug ) ,
1627+ params : ctx . params ,
1628+ environment : ctx . environment ,
1629+ user : ctx . user ,
1630+ organization : ctx . organization ,
1631+ } )
15731632 errors . push ( pageError ( err , 'description' ) )
15741633 }
15751634 }
@@ -1584,6 +1643,15 @@ export default class IntervalClient {
15841643 } )
15851644 . catch ( err => {
15861645 this . #logger. error ( err )
1646+ this . #onError?.( {
1647+ error : err ,
1648+ route : ctx . page . slug ,
1649+ routeDefinition : this . #routes. get ( ctx . page . slug ) ,
1650+ params : ctx . params ,
1651+ environment : ctx . environment ,
1652+ user : ctx . user ,
1653+ organization : ctx . organization ,
1654+ } )
15871655 errors . push ( pageError ( err , 'description' ) )
15881656 scheduleSendPage ( )
15891657 } )
@@ -1628,6 +1696,16 @@ export default class IntervalClient {
16281696 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#thenables
16291697 err => {
16301698 this . #logger. error ( err )
1699+ this . #onError?.( {
1700+ error : err ,
1701+ route : ctx . page . slug ,
1702+ routeDefinition : this . #routes. get ( ctx . page . slug ) ,
1703+ params : ctx . params ,
1704+ environment : ctx . environment ,
1705+ user : ctx . user ,
1706+ organization : ctx . organization ,
1707+ } )
1708+
16311709 if ( err instanceof IOError && err . cause ) {
16321710 errors . push ( pageError ( err . cause , 'children' ) )
16331711 } else {
@@ -1644,6 +1722,17 @@ export default class IntervalClient {
16441722 . catch ( async err => {
16451723 this . #logger. error ( 'Error in page:' , err )
16461724 errors . push ( pageError ( err ) )
1725+
1726+ this . #onError?.( {
1727+ error : err ,
1728+ route : ctx . page . slug ,
1729+ routeDefinition : this . #routes. get ( ctx . page . slug ) ,
1730+ params : ctx . params ,
1731+ environment : ctx . environment ,
1732+ user : ctx . user ,
1733+ organization : ctx . organization ,
1734+ } )
1735+
16471736 const pageLayout : LayoutSchemaInput = {
16481737 kind : 'BASIC' ,
16491738 errors,
0 commit comments