1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-19 01:33:33 +00:00

Ps/pm 5965/better config polling (#8325)

* Create tracker that can await until expected observables are received.

* Test dates are almost equal

* Remove unused class method

* Allow for updating active account in accout service fake

* Correct observable tracker behavior

Clarify documentation

* Transition config service to state provider

Updates the config fetching behavior to be lazy and ensure that any emitted value has been updated if older than a configurable value (statically compiled).

If desired, config fetching can be ensured fresh through an async.

* Update calls to config service in DI and bootstrapping

* Migrate account server configs

* Fix global config fetching

* Test migration rollback

* Adhere to implementation naming convention

* Adhere to abstract class naming convention

* Complete config abstraction rename

* Remove unnecessary cli config service

* Fix builds

* Validate observable does not complete

* Use token service to determine authed or unauthed config pull

* Remove superfluous factory config

* Name describe blocks after the thing they test

* Remove implementation documentation

Unfortunately the experience when linking to external documentation is quite poor. Instead of following the link and retrieving docs, you get a link that can be clicked to take you out of context to the docs. No link _does_ retrieve docs, but lacks indication in the implementation that documentation exists at all.

On the balance, removing the link is the better experience.

* Fix storybook
This commit is contained in:
Matt Gibson
2024-03-27 12:03:09 -05:00
committed by GitHub
parent 64d6f6fef3
commit 62ad39e697
79 changed files with 946 additions and 609 deletions

View File

@@ -1,5 +1,9 @@
import { UserId } from "../../../types/guid";
import { ServerConfigResponse } from "../../models/response/server-config.response";
export abstract class ConfigApiServiceAbstraction {
get: () => Promise<ServerConfigResponse>;
/**
* Fetches the server configuration for the given user. If no user is provided, the configuration will not contain user-specific context.
*/
get: (userId: UserId | undefined) => Promise<ServerConfigResponse>;
}

View File

@@ -1,30 +0,0 @@
import { Observable } from "rxjs";
import { SemVer } from "semver";
import { FeatureFlag } from "../../../enums/feature-flag.enum";
import { Region } from "../environment.service";
import { ServerConfig } from "./server-config";
export abstract class ConfigServiceAbstraction {
serverConfig$: Observable<ServerConfig | null>;
cloudRegion$: Observable<Region>;
getFeatureFlag$: <T extends boolean | number | string>(
key: FeatureFlag,
defaultValue?: T,
) => Observable<T>;
getFeatureFlag: <T extends boolean | number | string>(
key: FeatureFlag,
defaultValue?: T,
) => Promise<T>;
checkServerMeetsVersionRequirement$: (
minimumRequiredServerVersion: SemVer,
) => Observable<boolean>;
/**
* Force ConfigService to fetch an updated config from the server and emit it from serverConfig$
* @deprecated The service implementation should subscribe to an observable and use that to trigger a new fetch from
* server instead
*/
triggerServerConfigFetch: () => void;
}

View File

@@ -0,0 +1,47 @@
import { Observable } from "rxjs";
import { SemVer } from "semver";
import { FeatureFlag } from "../../../enums/feature-flag.enum";
import { Region } from "../environment.service";
import { ServerConfig } from "./server-config";
export abstract class ConfigService {
/** The server config of the currently active user */
serverConfig$: Observable<ServerConfig | null>;
/** The cloud region of the currently active user */
cloudRegion$: Observable<Region>;
/**
* Retrieves the value of a feature flag for the currently active user
* @param key The feature flag to retrieve
* @param defaultValue The default value to return if the feature flag is not set or the server's config is irretrievable
* @returns An observable that emits the value of the feature flag, updates as the server config changes
*/
getFeatureFlag$: <T extends boolean | number | string>(
key: FeatureFlag,
defaultValue?: T,
) => Observable<T>;
/**
* Retrieves the value of a feature flag for the currently active user
* @param key The feature flag to retrieve
* @param defaultValue The default value to return if the feature flag is not set or the server's config is irretrievable
* @returns The value of the feature flag
*/
getFeatureFlag: <T extends boolean | number | string>(
key: FeatureFlag,
defaultValue?: T,
) => Promise<T>;
/**
* Verifies whether the server version meets the minimum required version
* @param minimumRequiredServerVersion The minimum version required
* @returns True if the server version is greater than or equal to the minimum required version
*/
checkServerMeetsVersionRequirement$: (
minimumRequiredServerVersion: SemVer,
) => Observable<boolean>;
/**
* Triggers a check that the config for the currently active user is up-to-date. If it is not, it will be fetched from the server and stored.
*/
abstract ensureConfigFetched(): Promise<void>;
}

View File

@@ -7,7 +7,6 @@ import {
} from "../../models/data/server-config.data";
const dayInMilliseconds = 24 * 3600 * 1000;
const eighteenHoursInMilliseconds = 18 * 3600 * 1000;
export class ServerConfig {
version: string;
@@ -38,10 +37,6 @@ export class ServerConfig {
return this.getAgeInMilliseconds() <= dayInMilliseconds;
}
expiresSoon(): boolean {
return this.getAgeInMilliseconds() >= eighteenHoursInMilliseconds;
}
static fromJSON(obj: Jsonify<ServerConfig>): ServerConfig {
if (obj == null) {
return null;

View File

@@ -16,7 +16,6 @@ import { LocalData } from "../../vault/models/data/local.data";
import { CipherView } from "../../vault/models/view/cipher.view";
import { AddEditCipherInfo } from "../../vault/types/add-edit-cipher-info";
import { KdfType } from "../enums";
import { ServerConfigData } from "../models/data/server-config.data";
import { Account } from "../models/domain/account";
import { EncString } from "../models/domain/enc-string";
import { StorageOptions } from "../models/domain/storage-options";
@@ -278,14 +277,6 @@ export abstract class StateService<T extends Account = Account> {
setVaultTimeoutAction: (value: string, options?: StorageOptions) => Promise<void>;
getApproveLoginRequests: (options?: StorageOptions) => Promise<boolean>;
setApproveLoginRequests: (value: boolean, options?: StorageOptions) => Promise<void>;
/**
* @deprecated Do not call this directly, use ConfigService
*/
getServerConfig: (options?: StorageOptions) => Promise<ServerConfigData>;
/**
* @deprecated Do not call this directly, use ConfigService
*/
setServerConfig: (value: ServerConfigData, options?: StorageOptions) => Promise<void>;
/**
* fetches string value of URL user tried to navigate to while unauthenticated.
* @param options Defines the storage options for the URL; Defaults to session Storage.