All files / app/web-ui state.ts

100% Statements 98/98
100% Branches 13/13
100% Functions 4/4
100% Lines 98/98

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 981x 1x 1x 2x 2x 2x 2x 2x 2x 1x 2x 2x 2x 2x 1x 1x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 112x 112x 112x 14x 4x 4x 14x 10x 10x 14x 112x 112x 143x 143x 143x 143x 143x 143x 143x 23x 23x 23x 23x 23x 143x 143x 81x 81x 81x 14x 14x 14x 14x 14x 14x 14x 14x 14x 14x 1x 1x 14x 1x 1x 14x 3x 3x 14x 14x 81x 81x 81x 81x 81x 81x 81x 81x 81x 143x
import {iCPSError} from "../error/error.js";
import {MFA_ERR, AUTH_ERR, WEB_SERVER_ERR} from "../error/error-codes.js";
 
export enum StateType {
    READY = `ready`,
    AUTH = `authenticating`,
    MFA = `mfa_required`,
    SYNC = `syncing`,
}
 
export enum StateTrigger {
    SYNC = `sync`,
    AUTH = `auth`,
}
 
export class State {
    /**
     * Keeps track when the next scheduled sync should happen
     */
    nextSync?: number;
    /**
     * If error is present, previous state ended in error
     */
    prevError?: iCPSError
    /**
     * What triggered the current state initially (if applicable)
     */
    prevTrigger?: StateTrigger
    /**
     * The timestamp when the state was last changed
     */
    timestamp: number = Date.now();
 
    /**
     * Current state of the application
     */
    state: StateType = StateType.READY;
 
    updateState(newState: StateType, ctx? : {error?: iCPSError, nextSync?: number}) {
        this.timestamp = Date.now();
        this.state = newState;
        if(ctx) {
            if(ctx.nextSync) {
                this.nextSync = ctx.nextSync;
            }
            if(ctx.error) {
                this.prevError = iCPSError.toiCPSError(ctx.error);
            }
        }
        
    }
 
    /**
     * Indicates that the current state was changed due to a trigger (such as sync or auth).
     * This will clear any previous error.
     * @param trigger - The trigger that caused the state change
     */
    triggerSync(trigger: StateTrigger) {
        // First step is always to go to AUTH state
        this.updateState(StateType.AUTH);
        this.prevTrigger = trigger;
        this.prevError = undefined;
    }
 
    serialize() {
 
        let error = undefined
        if(this.prevError) {
            error = {
                message: this.prevError.getDescription(),
                code: this.prevError.getRootErrorCode(),
            }
 
            /**
             * If possible, this will try to convert known error codes into user-friendly messages
             */
            switch (error.code) {
            case MFA_ERR.FAIL_ON_MFA.code:
                error.message = `MFA code required. Use the 'Renew Authentication' button to request and enter a new code.`;
                break;
            case AUTH_ERR.UNAUTHORIZED.code:
                error.message = `Your credentials seem to be invalid. Please check your iCloud credentials and try again.`;
                break;
            case WEB_SERVER_ERR.MFA_CODE_NOT_PROVIDED.code:
                error.message = `MFA code not provided within timeout period. Use the 'Renew Authentication' button to request and enter a new code.`;
                break;
            }
        }
 
        return {
            state: this.state,
            nextSync: this.nextSync,
            prevError: error,
            prevTrigger: this.prevTrigger,
            timestamp: this.timestamp,
        };
    }
}