@@ -15,9 +15,9 @@ export interface IBasemapSessionParams {
15
15
startSessionUrl : string ;
16
16
styleFamily : StyleFamily ;
17
17
authentication : IAuthenticationManager | string ;
18
- expires : Date | string ;
19
- startTime : Date | string ;
20
- endTime : Date | string ;
18
+ expires : Date ;
19
+ startTime : Date ;
20
+ endTime : Date ;
21
21
safetyMargin ?: number ;
22
22
duration ?: number ;
23
23
}
@@ -26,7 +26,14 @@ export interface IStartSessionParams {
26
26
styleFamily ?: StyleFamily ;
27
27
authentication : IAuthenticationManager | string ;
28
28
saftyMargin ?: number ;
29
- testSession ?: boolean ;
29
+ duration ?: number ;
30
+ autoRefresh ?: boolean ;
31
+
32
+ /**
33
+ * The URL to start the session. If not provided, it will use the default URL.
34
+ * @private
35
+ */
36
+ startSessionUrl ?: string ;
30
37
}
31
38
32
39
/**
@@ -37,6 +44,15 @@ export interface IStartSessionParams {
37
44
* @implements {IAuthenticationManager}
38
45
*/
39
46
export abstract class BaseSession implements IAuthenticationManager {
47
+ // the static methods for event handlers are used to provide doc via typedoc and do not need to be tested.
48
+ /* istanbul ignore next -- @preserve */
49
+ /**
50
+ * Event handler for when an error occurs during session management.
51
+ */
52
+ static readonly error = function error ( e : Error ) : void { } ; // eslint-disable-line @typescript-eslint/no-empty-function
53
+
54
+ // the static methods for event handlers are used to provide doc via typedoc and do not need to be tested.
55
+ /* istanbul ignore next -- @preserve */
40
56
/**
41
57
* Event handler for when a session expires and the `token` it no longer valid.
42
58
*
@@ -54,6 +70,8 @@ export abstract class BaseSession implements IAuthenticationManager {
54
70
expires : Date ;
55
71
} ) : void { } ; // eslint-disable-line @typescript-eslint/no-empty-function
56
72
73
+ // the static methods for event handlers are used to provide doc via typedoc and do not need to be tested.
74
+ /* istanbul ignore next -- @preserve */
57
75
/**
58
76
* Event handler for when a session refreshes and a new `token` is available.
59
77
*
@@ -146,6 +164,11 @@ export abstract class BaseSession implements IAuthenticationManager {
146
164
*/
147
165
private emitter : any ;
148
166
167
+ /**
168
+ * A handler that is used to automatically refresh the session when it expires.
169
+ */
170
+ private autoRefreshHandler : ( ( ) => void ) | null = null ;
171
+
149
172
/**
150
173
* Creates a new instance of the BaseSession class. Generally you should not create an instance of this class directly, but instead use the static methods to start a session or deserialize a session.
151
174
*
@@ -168,21 +191,11 @@ export abstract class BaseSession implements IAuthenticationManager {
168
191
this . styleFamily = params . styleFamily || "arcgis" ;
169
192
this . authentication = params . authentication ;
170
193
this . duration = params . duration || DEFAULT_DURATION ;
171
- this . startTime =
172
- typeof params . startTime === "string"
173
- ? new Date ( params . startTime )
174
- : params . startTime ;
175
- this . endTime =
176
- typeof params . endTime === "string"
177
- ? new Date ( params . endTime )
178
- : params . endTime ;
179
- this . expires =
180
- typeof params . expires === "string"
181
- ? new Date ( params . expires )
182
- : params . expires ;
194
+ this . startTime = params . startTime ;
195
+ this . endTime = params . endTime ;
196
+ this . expires = params . expires ;
183
197
this . saftyMargin = params . safetyMargin || DEFAULT_SAFETY_MARGIN ;
184
198
this . emitter = mitt ( ) ;
185
- this . startCheckingExpirationTime ( ) ;
186
199
}
187
200
188
201
/**
@@ -208,9 +221,6 @@ export abstract class BaseSession implements IAuthenticationManager {
208
221
*/
209
222
startCheckingExpirationTime ( ) {
210
223
const check = ( ) => {
211
- console . log (
212
- "BaremapStyleSession.startCheckingExpirationTime(): Checking session expiration time..."
213
- ) ;
214
224
this . isSessionExpired ( ) ;
215
225
} ;
216
226
@@ -224,6 +234,8 @@ export abstract class BaseSession implements IAuthenticationManager {
224
234
setTimeout ( ( ) => {
225
235
check ( ) ; // check immediately after starting the interval
226
236
} , 10 ) ;
237
+
238
+ return this . expirationTimerId ; // return the timer ID so it can be stopped later
227
239
}
228
240
229
241
/**
@@ -236,6 +248,15 @@ export abstract class BaseSession implements IAuthenticationManager {
236
248
}
237
249
}
238
250
251
+ /**
252
+ * Indicates if the session is currently checking for expiration time.
253
+ *
254
+ * @returns {boolean } - Returns true if the session is checking for expiration time, otherwise false.
255
+ */
256
+ get checkingExpirationTime ( ) : boolean {
257
+ return ! ! this . expirationTimerId ;
258
+ }
259
+
239
260
/**
240
261
* Starts a new session using the provided parameters and returns an instance of the session class.
241
262
*
@@ -249,13 +270,15 @@ export abstract class BaseSession implements IAuthenticationManager {
249
270
styleFamily = "arcgis" ,
250
271
authentication,
251
272
safetyMargin = DEFAULT_SAFETY_MARGIN ,
252
- duration = DEFAULT_DURATION
273
+ duration = DEFAULT_DURATION ,
274
+ autoRefresh = true
253
275
} : {
254
276
startSessionUrl ?: string ;
255
277
styleFamily ?: StyleFamily ;
256
278
authentication : IAuthenticationManager | string ;
257
279
safetyMargin ?: number ;
258
280
duration ?: number ;
281
+ autoRefresh ?: boolean ;
259
282
} ,
260
283
SessionClass : new ( params : IBasemapSessionParams ) => T
261
284
) : Promise < T > {
@@ -266,20 +289,24 @@ export abstract class BaseSession implements IAuthenticationManager {
266
289
duration
267
290
} ) ;
268
291
269
- const timeToSubtract = safetyMargin || DEFAULT_SAFETY_MARGIN ;
270
-
271
292
const session = new SessionClass ( {
272
293
startSessionUrl : startSessionUrl ,
273
294
token : sessionResponse . sessionToken ,
274
295
styleFamily,
275
296
authentication,
276
- safetyMargin : timeToSubtract ,
277
- expires : new Date ( sessionResponse . endTime - timeToSubtract ) ,
297
+ safetyMargin,
298
+ expires : new Date ( sessionResponse . endTime - safetyMargin ) ,
278
299
startTime : new Date ( sessionResponse . startTime ) ,
279
300
endTime : new Date ( sessionResponse . endTime ) ,
280
301
duration
281
302
} ) ;
282
303
304
+ session . startCheckingExpirationTime ( ) ;
305
+
306
+ if ( autoRefresh ) {
307
+ session . startAutoRefresh ( ) ;
308
+ }
309
+
283
310
return session as T ;
284
311
}
285
312
@@ -298,9 +325,6 @@ export abstract class BaseSession implements IAuthenticationManager {
298
325
*/
299
326
getToken ( ) : Promise < string > {
300
327
if ( this . isExpired ) {
301
- console . log (
302
- "BasmapStyleSession.getToken(): Session expired, refreshing credentials..."
303
- ) ;
304
328
return this . refreshCredentials ( ) . then ( ( ) => this . token ) ;
305
329
}
306
330
@@ -316,13 +340,23 @@ export abstract class BaseSession implements IAuthenticationManager {
316
340
return true ;
317
341
}
318
342
343
+ /**
344
+ * Indicates if the session is set to automatically refresh when it expires.
345
+ *
346
+ * @returns {boolean } - Returns true if auto-refresh is enabled, otherwise false.
347
+ */
348
+ get autoRefresh ( ) : boolean {
349
+ return ! ! this . autoRefreshHandler && ! ! this . expirationTimerId ;
350
+ }
351
+
319
352
/**
320
353
* Refreshes the session credentials by starting a new session.
321
354
* This will emit a "refreshed" event with the previous and current session details.
322
355
*
323
356
* @returns A promise that resolves to the current instance of the session.
324
357
*/
325
358
async refreshCredentials ( ) : Promise < this> {
359
+ // @TODO switch this to structured clone when we upgrade to Node 20+ types so we don't have to parse the dates later
326
360
const previous = JSON . parse (
327
361
JSON . stringify ( {
328
362
token : this . token ,
@@ -332,30 +366,69 @@ export abstract class BaseSession implements IAuthenticationManager {
332
366
} )
333
367
) ;
334
368
335
- const newSession = await startNewSession ( {
336
- startSessionUrl : this . startSessionUrl ,
337
- styleFamily : this . styleFamily ,
338
- authentication : this . authentication ,
339
- duration : this . duration
340
- } ) ;
341
-
342
- this . setToken ( newSession . sessionToken ) ;
343
- this . setStartTime ( new Date ( newSession . startTime ) ) ;
344
- this . setEndTime ( new Date ( newSession . endTime ) ) ;
345
- this . setExpires ( new Date ( newSession . endTime - this . saftyMargin ) ) ;
369
+ try {
370
+ const newSession = await startNewSession ( {
371
+ startSessionUrl : this . startSessionUrl ,
372
+ styleFamily : this . styleFamily ,
373
+ authentication : this . authentication ,
374
+ duration : this . duration
375
+ } ) ;
346
376
347
- this . emitter . emit ( "refreshed" , {
348
- previous,
349
- current : {
350
- token : this . token ,
351
- startTime : this . startTime ,
352
- endTime : this . endTime ,
353
- expires : this . expires
354
- }
355
- } ) ;
377
+ this . setToken ( newSession . sessionToken ) ;
378
+ this . setStartTime ( new Date ( newSession . startTime ) ) ;
379
+ this . setEndTime ( new Date ( newSession . endTime ) ) ;
380
+ this . setExpires ( new Date ( newSession . endTime - this . saftyMargin ) ) ;
381
+
382
+ this . emitter . emit ( "refreshed" , {
383
+ previous : {
384
+ token : previous . token ,
385
+ startTime : new Date ( previous . startTime ) ,
386
+ endTime : new Date ( previous . endTime ) ,
387
+ expires : new Date ( previous . expires )
388
+ } ,
389
+ current : {
390
+ token : this . token ,
391
+ startTime : this . startTime ,
392
+ endTime : this . endTime ,
393
+ expires : this . expires
394
+ }
395
+ } ) ;
396
+ } catch ( error ) {
397
+ this . emitter . emit ( "error" , error ) ;
398
+ throw error ;
399
+ }
356
400
357
401
return this ;
358
402
}
403
+ /**
404
+ * Enables auto-refresh for the session. This will automatically refresh the session when it expires.
405
+ * It will also start checking the expiration time of the session if it is not already started via {@linkcode BaseSession.startCheckingExpirationTime}.
406
+ */
407
+ startAutoRefresh ( ) {
408
+ if ( ! this . expirationTimerId ) {
409
+ this . startCheckingExpirationTime ( ) ;
410
+ }
411
+
412
+ this . autoRefreshHandler = ( ) => {
413
+ this . refreshCredentials ( ) . catch ( ( error : Error ) => {
414
+ this . emitter . emit ( "error" , error ) ;
415
+ } ) ;
416
+ } ;
417
+
418
+ this . on ( "expired" , this . autoRefreshHandler ) ;
419
+ }
420
+
421
+ /**
422
+ * Disables auto-refresh for the session. This will stop automatically refreshing the session when it expires.
423
+ * This will **not** stop checking the expiration time of the session. If you want to stop automated expiration
424
+ * checking, call {@linkcode BaseSession.stopCheckingExpirationTime} after calling this method.
425
+ */
426
+ stopAutoRefresh ( ) {
427
+ if ( this . autoRefreshHandler ) {
428
+ this . off ( "expired" , this . autoRefreshHandler ) ;
429
+ this . autoRefreshHandler = null ;
430
+ }
431
+ }
359
432
360
433
/**
361
434
* A handler that listens for an eventName and returns custom handler.
@@ -365,9 +438,13 @@ export abstract class BaseSession implements IAuthenticationManager {
365
438
*/
366
439
on ( event : "refreshed" , handler : typeof BaseSession . refreshed ) : void ;
367
440
on ( event : "expired" , handler : typeof BaseSession . expired ) : void ;
441
+ on ( event : "error" , handler : typeof BaseSession . error ) : void ;
368
442
on (
369
443
eventName : string ,
370
- handler : typeof BaseSession . refreshed | typeof BaseSession . expired
444
+ handler :
445
+ | typeof BaseSession . refreshed
446
+ | typeof BaseSession . expired
447
+ | typeof BaseSession . error
371
448
) {
372
449
this . emitter . on ( eventName , handler ) ;
373
450
this . isSessionExpired ( ) ; // check if the session is expired immediately after adding the handler
@@ -381,9 +458,14 @@ export abstract class BaseSession implements IAuthenticationManager {
381
458
*/
382
459
once ( event : "refreshed" , handler : typeof BaseSession . refreshed ) : void ;
383
460
once ( event : "expired" , handler : typeof BaseSession . expired ) : void ;
461
+ once ( event : "error" , handler : typeof BaseSession . error ) : void ;
462
+
384
463
once (
385
464
eventName : string ,
386
- handler : typeof BaseSession . refreshed | typeof BaseSession . expired
465
+ handler :
466
+ | typeof BaseSession . refreshed
467
+ | typeof BaseSession . expired
468
+ | typeof BaseSession . error
387
469
) {
388
470
const fn = ( e : any ) => {
389
471
this . emitter . off ( eventName , fn ) ;
@@ -401,9 +483,13 @@ export abstract class BaseSession implements IAuthenticationManager {
401
483
*/
402
484
off ( event : "refreshed" , handler : typeof BaseSession . refreshed ) : void ;
403
485
off ( event : "expired" , handler : typeof BaseSession . expired ) : void ;
486
+ off ( event : "error" , handler : typeof BaseSession . error ) : void ;
404
487
off (
405
488
eventName : string ,
406
- handler : typeof BaseSession . refreshed | typeof BaseSession . expired
489
+ handler :
490
+ | typeof BaseSession . refreshed
491
+ | typeof BaseSession . expired
492
+ | typeof BaseSession . error
407
493
) {
408
494
this . emitter . off ( eventName , handler ) ;
409
495
}
0 commit comments