Farmbot-Web-App/frontend/session.ts

70 lines
2.2 KiB
TypeScript
Raw Normal View History

2017-06-29 12:54:02 -06:00
import { AuthState } from "./auth/interfaces";
import { box } from "boxed_value";
import { BooleanSetting, NumericSetting } from "./session_keys";
2019-09-23 12:56:35 -06:00
import {
2020-02-28 09:35:32 -07:00
BooleanConfigKey, NumberConfigKey,
2019-09-23 12:56:35 -06:00
} from "farmbot/dist/resources/configs/web_app";
2017-06-29 12:54:02 -06:00
2017-08-27 09:19:23 -06:00
/** The `Session` namespace is a wrapper for `localStorage`.
* Use this to avoid direct access of `localStorage` where possible.
*
* Problems this namespace aims to solve:
* - Avoid duplication of localStorage key names.
* - Avoid duplication of de-serialization logic.
* - Avoid type errors by explicitly naming keys as (Boolean|Numeric)Setting
* - Create an upgrade path for the eventual server side storage
*/
2017-06-29 12:54:02 -06:00
export namespace Session {
2017-08-27 09:19:23 -06:00
/** Key that holds the user's JWT */
2017-06-29 12:54:02 -06:00
const KEY = "session";
/** Replace the contents of session storage. */
2017-10-12 14:28:19 -06:00
export function replaceToken(nextState: AuthState) {
2018-08-02 16:18:54 -06:00
localStorage.setItem(KEY, JSON.stringify(nextState));
2017-06-29 12:54:02 -06:00
}
/** Fetch the previous session. */
2017-10-12 14:28:19 -06:00
export function fetchStoredToken(): AuthState | undefined {
2017-06-29 12:54:02 -06:00
try {
2018-08-02 16:18:54 -06:00
const v: AuthState = JSON.parse(localStorage.getItem(KEY) || "");
2017-06-29 12:54:02 -06:00
if (box(v).kind === "object") {
return v;
} else {
2018-05-15 20:38:52 -06:00
throw new Error("Expected object or undefined"); // unreachable?
2017-06-29 12:54:02 -06:00
}
} catch (error) {
return undefined;
2017-08-02 09:14:08 -06:00
}
2017-06-29 12:54:02 -06:00
}
2018-12-18 11:25:17 -07:00
/** Clear localStorage and sessionStorage. */
2017-10-12 15:48:41 -06:00
export function clear(): never {
2019-02-04 09:31:52 -07:00
localStorage.clear();
sessionStorage.clear();
location.assign(window.location.origin || "/");
return undefined as never;
2017-06-29 12:54:02 -06:00
}
}
2017-08-30 15:18:44 -06:00
2017-12-27 09:24:50 -07:00
export const isBooleanSetting =
(k: unknown): k is BooleanConfigKey => !!BooleanSetting[k as BooleanConfigKey];
2017-08-30 15:18:44 -06:00
2020-02-28 09:34:28 -07:00
export function safeBooleanSetting(settingName: string): BooleanConfigKey {
if (isBooleanSetting(settingName)) {
return settingName;
2017-08-30 15:18:44 -06:00
} else {
2020-02-28 09:34:28 -07:00
throw new Error(`Expected BooleanConfigKey but got '${settingName}'`);
2017-08-30 15:18:44 -06:00
}
}
2017-12-11 04:50:41 -07:00
2017-12-27 09:24:50 -07:00
export const isNumericSetting =
(x: unknown): x is NumberConfigKey => !!NumericSetting[x as NumberConfigKey];
2017-12-11 04:50:41 -07:00
2020-02-28 09:34:28 -07:00
export function safeNumericSetting(settingName: string): NumberConfigKey {
if (isNumericSetting(settingName)) {
return settingName;
2017-12-11 04:50:41 -07:00
} else {
2020-02-28 09:34:28 -07:00
throw new Error(`Expected NumberConfigKey but got '${settingName}'`);
2017-12-11 04:50:41 -07:00
}
}