@@ -2,6 +2,8 @@ import {AppConfig} from './app/config';
22import type { CliArgs } from './cli/args' ;
33import { Log } from '@toreda/log' ;
44import { type ClientDelegate , ClientLifecycle , clientPhase } from '@toreda/lifecycle' ;
5+ import { Bool , boolMake } from '@toreda/strong-types' ;
6+ import { Defaults } from './defaults' ;
57
68/**
79 * Example app class called by the CLI.
@@ -10,21 +12,62 @@ export class App implements ClientDelegate {
1012 public readonly lifecycle : ClientLifecycle ;
1113 public readonly log : Log ;
1214 public readonly cfg : AppConfig ;
15+ private readonly loaded : Bool ;
16+ private readonly running : Bool ;
1317
1418 constructor ( args : CliArgs , log : Log ) {
1519 this . lifecycle = new ClientLifecycle ( ) ;
1620 this . log = log ;
1721
22+ this . loaded = boolMake ( Defaults . App . Loaded ) ;
23+ this . running = boolMake ( Defaults . App . Running ) ;
1824 this . cfg = new AppConfig ( args , log ) ;
25+
26+ this . bindListeners ( ) ;
1927 }
2028
21- public async start ( ) : Promise < App > {
22- this . log . info ( `CLI App starting..` ) ;
29+ private bindListeners ( ) : void {
30+ this . load = this . load . bind ( this ) ;
31+ this . start = this . start . bind ( this ) ;
32+ }
2333
34+ public async load ( ) : Promise < App > {
35+ // Ignore duplicate load calls after app finishes loading. Not strictly necessary
36+ // when `load` contains only Lifecycle phase calls as lifecycle methods set their own
37+ // flags to prevent dupe calls. Prevents problematic behavior if unprotected calls
38+ // are added in the future.
39+ if ( this . loaded ( ) ) {
40+ return this ;
41+ }
42+ await clientPhase ( 'clientWillInit' , this ) ;
2443 await clientPhase ( 'clientOnInit' , this ) ;
44+ await clientPhase ( 'clientDidInit' , this ) ;
45+
46+ await clientPhase ( 'clientWillLoad' , this ) ;
2547 await clientPhase ( 'clientOnLoad' , this ) ;
48+ await clientPhase ( 'clientDidLoad' , this ) ;
49+
50+ this . loaded ( true ) ;
51+ return this ;
52+
53+ }
54+
55+ public async start ( ) : Promise < App > {
56+ // Ignore dupe calls after app start. Lifecycle phases maintain their own flags
57+ // to prevent dupe calls, but other logic here isn't protected without the check.
58+ if ( this . running ( ) ) {
59+ return this ;
60+ }
61+
62+ this . log . info ( `CLI App starting..` ) ;
63+ await this . load ( ) ;
64+ await clientPhase ( 'clientWillStart' , this ) ;
2665 await clientPhase ( 'clientOnStart' , this ) ;
66+ await clientPhase ( 'clientDidStart' , this ) ;
67+
68+ await clientPhase ( 'clientWillBecomeReady' , this ) ;
2769 await clientPhase ( 'clientOnReady' , this ) ;
70+ await clientPhase ( 'clientDidBecomeReady' , this ) ;
2871
2972 return this ;
3073 }
@@ -42,7 +85,7 @@ export class App implements ClientDelegate {
4285
4386 this . log . debug ( `CLI app init complete.` ) ;
4487
45- return this . lifecycle . phase ( 'clientOnInit' ) ;
88+ return this . lifecycle . endPhase ( 'clientOnInit' ) ;
4689 }
4790
4891 public async clientOnLoad ( ) : Promise < boolean > {
@@ -53,7 +96,7 @@ export class App implements ClientDelegate {
5396 return false ;
5497 }
5598
56- return this . lifecycle . phase ( 'clientOnLoad' ) ;
99+ return this . lifecycle . endPhase ( 'clientOnLoad' ) ;
57100 }
58101
59102 public async clientOnStart ( ) : Promise < boolean > {
@@ -64,7 +107,7 @@ export class App implements ClientDelegate {
64107 return false ;
65108 }
66109
67- return this . lifecycle . phase ( 'clientOnStart' ) ;
110+ return this . lifecycle . endPhase ( 'clientOnStart' ) ;
68111 }
69112
70113 public async clientOnReady ( ) : Promise < boolean > {
@@ -75,7 +118,7 @@ export class App implements ClientDelegate {
75118 return false ;
76119 }
77120
78- return this . lifecycle . phase ( 'clientOnReady' ) ;
121+ return this . lifecycle . endPhase ( 'clientOnReady' ) ;
79122 }
80123
81124 public reset ( ) : void {
0 commit comments