mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
Resolve state <-> state-test-utils circular dependency (#16093)
* Resolve state <-> state-test-utils circular dependency * Fix type errors
This commit is contained in:
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -101,6 +101,7 @@ libs/guid @bitwarden/team-platform-dev
|
|||||||
libs/client-type @bitwarden/team-platform-dev
|
libs/client-type @bitwarden/team-platform-dev
|
||||||
libs/core-test-utils @bitwarden/team-platform-dev
|
libs/core-test-utils @bitwarden/team-platform-dev
|
||||||
libs/state @bitwarden/team-platform-dev
|
libs/state @bitwarden/team-platform-dev
|
||||||
|
libs/state-internal @bitwarden/team-platform-dev
|
||||||
libs/state-test-utils @bitwarden/team-platform-dev
|
libs/state-test-utils @bitwarden/team-platform-dev
|
||||||
# Web utils used across app and connectors
|
# Web utils used across app and connectors
|
||||||
apps/web/src/utils/ @bitwarden/team-platform-dev
|
apps/web/src/utils/ @bitwarden/team-platform-dev
|
||||||
|
|||||||
@@ -143,23 +143,6 @@ import { DefaultSdkService } from "@bitwarden/common/platform/services/sdk/defau
|
|||||||
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
|
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
|
||||||
import { SystemService } from "@bitwarden/common/platform/services/system.service";
|
import { SystemService } from "@bitwarden/common/platform/services/system.service";
|
||||||
import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service";
|
import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service";
|
||||||
import {
|
|
||||||
ActiveUserStateProvider,
|
|
||||||
DefaultStateService,
|
|
||||||
DerivedStateProvider,
|
|
||||||
GlobalStateProvider,
|
|
||||||
SingleUserStateProvider,
|
|
||||||
StateEventRunnerService,
|
|
||||||
StateProvider,
|
|
||||||
} from "@bitwarden/common/platform/state";
|
|
||||||
/* eslint-disable import/no-restricted-paths -- We need the implementation to inject, but generally these should not be accessed */
|
|
||||||
import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-active-user-state.provider";
|
|
||||||
import { DefaultGlobalStateProvider } from "@bitwarden/common/platform/state/implementations/default-global-state.provider";
|
|
||||||
import { DefaultSingleUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-single-user-state.provider";
|
|
||||||
import { DefaultStateProvider } from "@bitwarden/common/platform/state/implementations/default-state.provider";
|
|
||||||
import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/inline-derived-state";
|
|
||||||
import { StateEventRegistrarService } from "@bitwarden/common/platform/state/state-event-registrar.service";
|
|
||||||
/* eslint-enable import/no-restricted-paths */
|
|
||||||
import { PrimarySecondaryStorageService } from "@bitwarden/common/platform/storage/primary-secondary-storage.service";
|
import { PrimarySecondaryStorageService } from "@bitwarden/common/platform/storage/primary-secondary-storage.service";
|
||||||
import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service";
|
import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service";
|
||||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||||
@@ -232,6 +215,24 @@ import {
|
|||||||
KeyService as KeyServiceAbstraction,
|
KeyService as KeyServiceAbstraction,
|
||||||
} from "@bitwarden/key-management";
|
} from "@bitwarden/key-management";
|
||||||
import { BackgroundSyncService } from "@bitwarden/platform/background-sync";
|
import { BackgroundSyncService } from "@bitwarden/platform/background-sync";
|
||||||
|
import {
|
||||||
|
ActiveUserStateProvider,
|
||||||
|
DerivedStateProvider,
|
||||||
|
GlobalStateProvider,
|
||||||
|
SingleUserStateProvider,
|
||||||
|
StateEventRunnerService,
|
||||||
|
StateProvider,
|
||||||
|
} from "@bitwarden/state";
|
||||||
|
import {
|
||||||
|
DefaultActiveUserStateProvider,
|
||||||
|
DefaultGlobalStateProvider,
|
||||||
|
DefaultSingleUserStateProvider,
|
||||||
|
DefaultStateEventRegistrarService,
|
||||||
|
DefaultStateEventRunnerService,
|
||||||
|
DefaultStateProvider,
|
||||||
|
DefaultStateService,
|
||||||
|
InlineDerivedStateProvider,
|
||||||
|
} from "@bitwarden/state-internal";
|
||||||
import {
|
import {
|
||||||
IndividualVaultExportService,
|
IndividualVaultExportService,
|
||||||
IndividualVaultExportServiceAbstraction,
|
IndividualVaultExportServiceAbstraction,
|
||||||
@@ -569,12 +570,12 @@ export default class MainBackground {
|
|||||||
this.logService,
|
this.logService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const stateEventRegistrarService = new StateEventRegistrarService(
|
const stateEventRegistrarService = new DefaultStateEventRegistrarService(
|
||||||
this.globalStateProvider,
|
this.globalStateProvider,
|
||||||
storageServiceProvider,
|
storageServiceProvider,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.stateEventRunnerService = new StateEventRunnerService(
|
this.stateEventRunnerService = new DefaultStateEventRunnerService(
|
||||||
this.globalStateProvider,
|
this.globalStateProvider,
|
||||||
storageServiceProvider,
|
storageServiceProvider,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
// eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage specifically for browser backgrounds
|
|
||||||
import { MemoryStorageService } from "@bitwarden/common/platform/state/storage/memory-storage.service";
|
import { SerializedMemoryStorageService } from "@bitwarden/storage-core";
|
||||||
|
|
||||||
import { BrowserApi } from "../browser/browser-api";
|
import { BrowserApi } from "../browser/browser-api";
|
||||||
|
|
||||||
import { MemoryStoragePortMessage } from "./port-messages";
|
import { MemoryStoragePortMessage } from "./port-messages";
|
||||||
import { portName } from "./port-name";
|
import { portName } from "./port-name";
|
||||||
|
|
||||||
export class BackgroundMemoryStorageService extends MemoryStorageService {
|
export class BackgroundMemoryStorageService extends SerializedMemoryStorageService {
|
||||||
private _ports: chrome.runtime.Port[] = [];
|
private _ports: chrome.runtime.Port[] = [];
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
AbstractStorageService,
|
AbstractStorageService,
|
||||||
|
ClientLocations,
|
||||||
ObservableStorageService,
|
ObservableStorageService,
|
||||||
} from "@bitwarden/common/platform/abstractions/storage.service";
|
|
||||||
import {
|
|
||||||
PossibleLocation,
|
PossibleLocation,
|
||||||
StorageServiceProvider,
|
StorageServiceProvider,
|
||||||
} from "@bitwarden/common/platform/services/storage-service.provider";
|
} from "@bitwarden/storage-core";
|
||||||
// eslint-disable-next-line import/no-restricted-paths
|
|
||||||
import { ClientLocations } from "@bitwarden/common/platform/state/state-definition";
|
|
||||||
|
|
||||||
export class BrowserStorageServiceProvider extends StorageServiceProvider {
|
export class BrowserStorageServiceProvider extends StorageServiceProvider {
|
||||||
constructor(
|
constructor(
|
||||||
|
|||||||
@@ -104,13 +104,6 @@ import { ContainerService } from "@bitwarden/common/platform/services/container.
|
|||||||
import { DefaultSdkClientFactory } from "@bitwarden/common/platform/services/sdk/default-sdk-client-factory";
|
import { DefaultSdkClientFactory } from "@bitwarden/common/platform/services/sdk/default-sdk-client-factory";
|
||||||
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
|
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
|
||||||
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
|
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
|
||||||
import {
|
|
||||||
DerivedStateProvider,
|
|
||||||
GlobalStateProvider,
|
|
||||||
StateProvider,
|
|
||||||
} from "@bitwarden/common/platform/state";
|
|
||||||
// eslint-disable-next-line import/no-restricted-paths -- Used for dependency injection
|
|
||||||
import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/inline-derived-state";
|
|
||||||
import { PrimarySecondaryStorageService } from "@bitwarden/common/platform/storage/primary-secondary-storage.service";
|
import { PrimarySecondaryStorageService } from "@bitwarden/common/platform/storage/primary-secondary-storage.service";
|
||||||
import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service";
|
import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service";
|
||||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||||
@@ -140,6 +133,8 @@ import {
|
|||||||
KeyService,
|
KeyService,
|
||||||
} from "@bitwarden/key-management";
|
} from "@bitwarden/key-management";
|
||||||
import { LockComponentService } from "@bitwarden/key-management-ui";
|
import { LockComponentService } from "@bitwarden/key-management-ui";
|
||||||
|
import { DerivedStateProvider, GlobalStateProvider, StateProvider } from "@bitwarden/state";
|
||||||
|
import { InlineDerivedStateProvider } from "@bitwarden/state-internal";
|
||||||
import {
|
import {
|
||||||
DefaultSshImportPromptService,
|
DefaultSshImportPromptService,
|
||||||
PasswordRepromptService,
|
PasswordRepromptService,
|
||||||
|
|||||||
@@ -107,25 +107,6 @@ import { DefaultSdkService } from "@bitwarden/common/platform/services/sdk/defau
|
|||||||
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
|
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
|
||||||
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
|
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
|
||||||
import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service";
|
import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service";
|
||||||
import {
|
|
||||||
ActiveUserStateProvider,
|
|
||||||
DefaultStateService,
|
|
||||||
DerivedStateProvider,
|
|
||||||
GlobalStateProvider,
|
|
||||||
SingleUserStateProvider,
|
|
||||||
StateEventRunnerService,
|
|
||||||
StateProvider,
|
|
||||||
StateService,
|
|
||||||
} from "@bitwarden/common/platform/state";
|
|
||||||
/* eslint-disable import/no-restricted-paths -- We need the implementation to inject, but generally these should not be accessed */
|
|
||||||
import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-active-user-state.provider";
|
|
||||||
import { DefaultDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/default-derived-state.provider";
|
|
||||||
import { DefaultGlobalStateProvider } from "@bitwarden/common/platform/state/implementations/default-global-state.provider";
|
|
||||||
import { DefaultSingleUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-single-user-state.provider";
|
|
||||||
import { DefaultStateProvider } from "@bitwarden/common/platform/state/implementations/default-state.provider";
|
|
||||||
import { StateEventRegistrarService } from "@bitwarden/common/platform/state/state-event-registrar.service";
|
|
||||||
import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service";
|
|
||||||
/* eslint-enable import/no-restricted-paths */
|
|
||||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||||
// eslint-disable-next-line no-restricted-imports -- Needed for service construction
|
// eslint-disable-next-line no-restricted-imports -- Needed for service construction
|
||||||
import { DefaultSyncService } from "@bitwarden/common/platform/sync/internal";
|
import { DefaultSyncService } from "@bitwarden/common/platform/sync/internal";
|
||||||
@@ -172,6 +153,26 @@ import {
|
|||||||
DefaultBiometricStateService,
|
DefaultBiometricStateService,
|
||||||
} from "@bitwarden/key-management";
|
} from "@bitwarden/key-management";
|
||||||
import { NodeCryptoFunctionService } from "@bitwarden/node/services/node-crypto-function.service";
|
import { NodeCryptoFunctionService } from "@bitwarden/node/services/node-crypto-function.service";
|
||||||
|
import {
|
||||||
|
ActiveUserStateProvider,
|
||||||
|
DerivedStateProvider,
|
||||||
|
GlobalStateProvider,
|
||||||
|
SingleUserStateProvider,
|
||||||
|
StateEventRunnerService,
|
||||||
|
StateProvider,
|
||||||
|
StateService,
|
||||||
|
} from "@bitwarden/state";
|
||||||
|
import {
|
||||||
|
DefaultActiveUserStateProvider,
|
||||||
|
DefaultDerivedStateProvider,
|
||||||
|
DefaultGlobalStateProvider,
|
||||||
|
DefaultSingleUserStateProvider,
|
||||||
|
DefaultStateEventRegistrarService,
|
||||||
|
DefaultStateEventRunnerService,
|
||||||
|
DefaultStateProvider,
|
||||||
|
DefaultStateService,
|
||||||
|
} from "@bitwarden/state-internal";
|
||||||
|
import { SerializedMemoryStorageService } from "@bitwarden/storage-core";
|
||||||
import {
|
import {
|
||||||
IndividualVaultExportService,
|
IndividualVaultExportService,
|
||||||
IndividualVaultExportServiceAbstraction,
|
IndividualVaultExportServiceAbstraction,
|
||||||
@@ -209,7 +210,7 @@ export class ServiceContainer {
|
|||||||
storageService: LowdbStorageService;
|
storageService: LowdbStorageService;
|
||||||
secureStorageService: NodeEnvSecureStorageService;
|
secureStorageService: NodeEnvSecureStorageService;
|
||||||
memoryStorageService: MemoryStorageService;
|
memoryStorageService: MemoryStorageService;
|
||||||
memoryStorageForStateProviders: MemoryStorageServiceForStateProviders;
|
memoryStorageForStateProviders: SerializedMemoryStorageService;
|
||||||
migrationRunner: MigrationRunner;
|
migrationRunner: MigrationRunner;
|
||||||
i18nService: I18nService;
|
i18nService: I18nService;
|
||||||
platformUtilsService: CliPlatformUtilsService;
|
platformUtilsService: CliPlatformUtilsService;
|
||||||
@@ -339,7 +340,7 @@ export class ServiceContainer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.memoryStorageService = new MemoryStorageService();
|
this.memoryStorageService = new MemoryStorageService();
|
||||||
this.memoryStorageForStateProviders = new MemoryStorageServiceForStateProviders();
|
this.memoryStorageForStateProviders = new SerializedMemoryStorageService();
|
||||||
|
|
||||||
const storageServiceProvider = new StorageServiceProvider(
|
const storageServiceProvider = new StorageServiceProvider(
|
||||||
this.storageService,
|
this.storageService,
|
||||||
@@ -351,12 +352,12 @@ export class ServiceContainer {
|
|||||||
this.logService,
|
this.logService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const stateEventRegistrarService = new StateEventRegistrarService(
|
const stateEventRegistrarService = new DefaultStateEventRegistrarService(
|
||||||
this.globalStateProvider,
|
this.globalStateProvider,
|
||||||
storageServiceProvider,
|
storageServiceProvider,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.stateEventRunnerService = new StateEventRunnerService(
|
this.stateEventRunnerService = new DefaultStateEventRunnerService(
|
||||||
this.globalStateProvider,
|
this.globalStateProvider,
|
||||||
storageServiceProvider,
|
storageServiceProvider,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/no
|
|||||||
import { NoopSdkLoadService } from "@bitwarden/common/platform/services/sdk/noop-sdk-load.service";
|
import { NoopSdkLoadService } from "@bitwarden/common/platform/services/sdk/noop-sdk-load.service";
|
||||||
import { SystemService } from "@bitwarden/common/platform/services/system.service";
|
import { SystemService } from "@bitwarden/common/platform/services/system.service";
|
||||||
import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state";
|
import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state";
|
||||||
// eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage
|
|
||||||
import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service";
|
|
||||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||||
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
import { DialogService, ToastService } from "@bitwarden/components";
|
import { DialogService, ToastService } from "@bitwarden/components";
|
||||||
@@ -105,6 +103,7 @@ import {
|
|||||||
BiometricsService,
|
BiometricsService,
|
||||||
} from "@bitwarden/key-management";
|
} from "@bitwarden/key-management";
|
||||||
import { LockComponentService } from "@bitwarden/key-management-ui";
|
import { LockComponentService } from "@bitwarden/key-management-ui";
|
||||||
|
import { SerializedMemoryStorageService } from "@bitwarden/storage-core";
|
||||||
import { DefaultSshImportPromptService, SshImportPromptService } from "@bitwarden/vault";
|
import { DefaultSshImportPromptService, SshImportPromptService } from "@bitwarden/vault";
|
||||||
|
|
||||||
import { DesktopLoginApprovalDialogComponentService } from "../../auth/login/desktop-login-approval-dialog-component.service";
|
import { DesktopLoginApprovalDialogComponentService } from "../../auth/login/desktop-login-approval-dialog-component.service";
|
||||||
@@ -234,7 +233,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
safeProvider({ provide: MEMORY_STORAGE, useClass: MemoryStorageService, deps: [] }),
|
safeProvider({ provide: MEMORY_STORAGE, useClass: MemoryStorageService, deps: [] }),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: OBSERVABLE_MEMORY_STORAGE,
|
provide: OBSERVABLE_MEMORY_STORAGE,
|
||||||
useClass: MemoryStorageServiceForStateProviders,
|
useClass: SerializedMemoryStorageService,
|
||||||
deps: [],
|
deps: [],
|
||||||
}),
|
}),
|
||||||
safeProvider({ provide: OBSERVABLE_DISK_STORAGE, useExisting: AbstractStorageService }),
|
safeProvider({ provide: OBSERVABLE_DISK_STORAGE, useExisting: AbstractStorageService }),
|
||||||
|
|||||||
@@ -21,18 +21,17 @@ import { DefaultEnvironmentService } from "@bitwarden/common/platform/services/d
|
|||||||
import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service";
|
import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service";
|
||||||
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
|
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
|
||||||
import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner";
|
import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner";
|
||||||
/* eslint-disable import/no-restricted-paths -- We need the implementation to inject, but generally this should not be accessed */
|
|
||||||
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
|
|
||||||
import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-active-user-state.provider";
|
|
||||||
import { DefaultDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/default-derived-state.provider";
|
|
||||||
import { DefaultGlobalStateProvider } from "@bitwarden/common/platform/state/implementations/default-global-state.provider";
|
|
||||||
import { DefaultSingleUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-single-user-state.provider";
|
|
||||||
import { DefaultStateProvider } from "@bitwarden/common/platform/state/implementations/default-state.provider";
|
|
||||||
import { StateEventRegistrarService } from "@bitwarden/common/platform/state/state-event-registrar.service";
|
|
||||||
import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service";
|
|
||||||
/* eslint-enable import/no-restricted-paths */
|
|
||||||
import { DefaultBiometricStateService } from "@bitwarden/key-management";
|
import { DefaultBiometricStateService } from "@bitwarden/key-management";
|
||||||
import { NodeCryptoFunctionService } from "@bitwarden/node/services/node-crypto-function.service";
|
import { NodeCryptoFunctionService } from "@bitwarden/node/services/node-crypto-function.service";
|
||||||
|
import {
|
||||||
|
DefaultActiveUserStateProvider,
|
||||||
|
DefaultDerivedStateProvider,
|
||||||
|
DefaultGlobalStateProvider,
|
||||||
|
DefaultSingleUserStateProvider,
|
||||||
|
DefaultStateEventRegistrarService,
|
||||||
|
DefaultStateProvider,
|
||||||
|
} from "@bitwarden/state-internal";
|
||||||
|
import { SerializedMemoryStorageService, StorageServiceProvider } from "@bitwarden/storage-core";
|
||||||
|
|
||||||
import { MainDesktopAutotypeService } from "./autofill/main/main-desktop-autotype.service";
|
import { MainDesktopAutotypeService } from "./autofill/main/main-desktop-autotype.service";
|
||||||
import { MainSshAgentService } from "./autofill/main/main-ssh-agent.service";
|
import { MainSshAgentService } from "./autofill/main/main-ssh-agent.service";
|
||||||
@@ -66,7 +65,7 @@ export class Main {
|
|||||||
i18nService: I18nMainService;
|
i18nService: I18nMainService;
|
||||||
storageService: ElectronStorageService;
|
storageService: ElectronStorageService;
|
||||||
memoryStorageService: MemoryStorageService;
|
memoryStorageService: MemoryStorageService;
|
||||||
memoryStorageForStateProviders: MemoryStorageServiceForStateProviders;
|
memoryStorageForStateProviders: SerializedMemoryStorageService;
|
||||||
messagingService: MessageSender;
|
messagingService: MessageSender;
|
||||||
environmentService: DefaultEnvironmentService;
|
environmentService: DefaultEnvironmentService;
|
||||||
desktopCredentialStorageListener: DesktopCredentialStorageListener;
|
desktopCredentialStorageListener: DesktopCredentialStorageListener;
|
||||||
@@ -134,7 +133,7 @@ export class Main {
|
|||||||
const storageDefaults: any = {};
|
const storageDefaults: any = {};
|
||||||
this.storageService = new ElectronStorageService(app.getPath("userData"), storageDefaults);
|
this.storageService = new ElectronStorageService(app.getPath("userData"), storageDefaults);
|
||||||
this.memoryStorageService = new MemoryStorageService();
|
this.memoryStorageService = new MemoryStorageService();
|
||||||
this.memoryStorageForStateProviders = new MemoryStorageServiceForStateProviders();
|
this.memoryStorageForStateProviders = new SerializedMemoryStorageService();
|
||||||
const storageServiceProvider = new StorageServiceProvider(
|
const storageServiceProvider = new StorageServiceProvider(
|
||||||
this.storageService,
|
this.storageService,
|
||||||
this.memoryStorageForStateProviders,
|
this.memoryStorageForStateProviders,
|
||||||
@@ -150,7 +149,7 @@ export class Main {
|
|||||||
|
|
||||||
this.mainCryptoFunctionService = new NodeCryptoFunctionService();
|
this.mainCryptoFunctionService = new NodeCryptoFunctionService();
|
||||||
|
|
||||||
const stateEventRegistrarService = new StateEventRegistrarService(
|
const stateEventRegistrarService = new DefaultStateEventRegistrarService(
|
||||||
globalStateProvider,
|
globalStateProvider,
|
||||||
storageServiceProvider,
|
storageServiceProvider,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -93,10 +93,7 @@ import { DefaultSdkClientFactory } from "@bitwarden/common/platform/services/sdk
|
|||||||
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
|
import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory";
|
||||||
import { NoopSdkLoadService } from "@bitwarden/common/platform/services/sdk/noop-sdk-load.service";
|
import { NoopSdkLoadService } from "@bitwarden/common/platform/services/sdk/noop-sdk-load.service";
|
||||||
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
|
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
|
||||||
/* eslint-disable import/no-restricted-paths -- Implementation for memory storage */
|
|
||||||
import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state";
|
import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state";
|
||||||
import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service";
|
|
||||||
/* eslint-enable import/no-restricted-paths -- Implementation for memory storage */
|
|
||||||
import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service";
|
import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service";
|
||||||
import {
|
import {
|
||||||
DefaultThemeStateService,
|
DefaultThemeStateService,
|
||||||
@@ -110,6 +107,7 @@ import {
|
|||||||
BiometricsService,
|
BiometricsService,
|
||||||
} from "@bitwarden/key-management";
|
} from "@bitwarden/key-management";
|
||||||
import { LockComponentService } from "@bitwarden/key-management-ui";
|
import { LockComponentService } from "@bitwarden/key-management-ui";
|
||||||
|
import { SerializedMemoryStorageService } from "@bitwarden/storage-core";
|
||||||
import { DefaultSshImportPromptService, SshImportPromptService } from "@bitwarden/vault";
|
import { DefaultSshImportPromptService, SshImportPromptService } from "@bitwarden/vault";
|
||||||
import { WebOrganizationInviteService } from "@bitwarden/web-vault/app/auth/core/services/organization-invite/web-organization-invite.service";
|
import { WebOrganizationInviteService } from "@bitwarden/web-vault/app/auth/core/services/organization-invite/web-organization-invite.service";
|
||||||
|
|
||||||
@@ -186,7 +184,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: OBSERVABLE_MEMORY_STORAGE,
|
provide: OBSERVABLE_MEMORY_STORAGE,
|
||||||
useClass: MemoryStorageServiceForStateProviders,
|
useClass: SerializedMemoryStorageService,
|
||||||
deps: [],
|
deps: [],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
|
|||||||
@@ -2,14 +2,11 @@ import { mock } from "jest-mock-extended";
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
AbstractStorageService,
|
AbstractStorageService,
|
||||||
ObservableStorageService,
|
|
||||||
} from "@bitwarden/common/platform/abstractions/storage.service";
|
|
||||||
import { PossibleLocation } from "@bitwarden/common/platform/services/storage-service.provider";
|
|
||||||
import {
|
|
||||||
ClientLocations,
|
ClientLocations,
|
||||||
|
ObservableStorageService,
|
||||||
|
PossibleLocation,
|
||||||
StorageLocation,
|
StorageLocation,
|
||||||
// eslint-disable-next-line import/no-restricted-paths
|
} from "@bitwarden/storage-core";
|
||||||
} from "@bitwarden/common/platform/state/state-definition";
|
|
||||||
|
|
||||||
import { WebStorageServiceProvider } from "./web-storage-service.provider";
|
import { WebStorageServiceProvider } from "./web-storage-service.provider";
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
AbstractStorageService,
|
AbstractStorageService,
|
||||||
|
ClientLocations,
|
||||||
ObservableStorageService,
|
ObservableStorageService,
|
||||||
} from "@bitwarden/common/platform/abstractions/storage.service";
|
|
||||||
import {
|
|
||||||
PossibleLocation,
|
PossibleLocation,
|
||||||
StorageServiceProvider,
|
StorageServiceProvider,
|
||||||
} from "@bitwarden/common/platform/services/storage-service.provider";
|
} from "@bitwarden/storage-core";
|
||||||
import {
|
|
||||||
ClientLocations,
|
|
||||||
// eslint-disable-next-line import/no-restricted-paths
|
|
||||||
} from "@bitwarden/common/platform/state/state-definition";
|
|
||||||
|
|
||||||
export class WebStorageServiceProvider extends StorageServiceProvider {
|
export class WebStorageServiceProvider extends StorageServiceProvider {
|
||||||
constructor(
|
constructor(
|
||||||
|
|||||||
@@ -230,24 +230,6 @@ import { DefaultSdkService } from "@bitwarden/common/platform/services/sdk/defau
|
|||||||
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
|
import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider";
|
||||||
import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service";
|
import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service";
|
||||||
import { ValidationService } from "@bitwarden/common/platform/services/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/services/validation.service";
|
||||||
import {
|
|
||||||
ActiveUserAccessor,
|
|
||||||
ActiveUserStateProvider,
|
|
||||||
DefaultStateService,
|
|
||||||
DerivedStateProvider,
|
|
||||||
GlobalStateProvider,
|
|
||||||
SingleUserStateProvider,
|
|
||||||
StateProvider,
|
|
||||||
} from "@bitwarden/common/platform/state";
|
|
||||||
/* eslint-disable import/no-restricted-paths -- We need the implementations to inject, but generally these should not be accessed */
|
|
||||||
import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-active-user-state.provider";
|
|
||||||
import { DefaultDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/default-derived-state.provider";
|
|
||||||
import { DefaultGlobalStateProvider } from "@bitwarden/common/platform/state/implementations/default-global-state.provider";
|
|
||||||
import { DefaultSingleUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-single-user-state.provider";
|
|
||||||
import { DefaultStateProvider } from "@bitwarden/common/platform/state/implementations/default-state.provider";
|
|
||||||
import { StateEventRegistrarService } from "@bitwarden/common/platform/state/state-event-registrar.service";
|
|
||||||
import { StateEventRunnerService } from "@bitwarden/common/platform/state/state-event-runner.service";
|
|
||||||
/* eslint-enable import/no-restricted-paths */
|
|
||||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||||
// eslint-disable-next-line no-restricted-imports -- Needed for DI
|
// eslint-disable-next-line no-restricted-imports -- Needed for DI
|
||||||
import { DefaultSyncService } from "@bitwarden/common/platform/sync/internal";
|
import { DefaultSyncService } from "@bitwarden/common/platform/sync/internal";
|
||||||
@@ -329,6 +311,26 @@ import {
|
|||||||
UserAsymmetricKeysRegenerationApiService,
|
UserAsymmetricKeysRegenerationApiService,
|
||||||
UserAsymmetricKeysRegenerationService,
|
UserAsymmetricKeysRegenerationService,
|
||||||
} from "@bitwarden/key-management";
|
} from "@bitwarden/key-management";
|
||||||
|
import {
|
||||||
|
ActiveUserStateProvider,
|
||||||
|
DerivedStateProvider,
|
||||||
|
GlobalStateProvider,
|
||||||
|
SingleUserStateProvider,
|
||||||
|
StateEventRegistrarService,
|
||||||
|
StateEventRunnerService,
|
||||||
|
StateProvider,
|
||||||
|
} from "@bitwarden/state";
|
||||||
|
import {
|
||||||
|
ActiveUserAccessor,
|
||||||
|
DefaultActiveUserStateProvider,
|
||||||
|
DefaultDerivedStateProvider,
|
||||||
|
DefaultGlobalStateProvider,
|
||||||
|
DefaultSingleUserStateProvider,
|
||||||
|
DefaultStateEventRegistrarService,
|
||||||
|
DefaultStateEventRunnerService,
|
||||||
|
DefaultStateProvider,
|
||||||
|
DefaultStateService,
|
||||||
|
} from "@bitwarden/state-internal";
|
||||||
import { SafeInjectionToken } from "@bitwarden/ui-common";
|
import { SafeInjectionToken } from "@bitwarden/ui-common";
|
||||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||||
// eslint-disable-next-line no-restricted-imports
|
// eslint-disable-next-line no-restricted-imports
|
||||||
@@ -1246,12 +1248,12 @@ const safeProviders: SafeProvider[] = [
|
|||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: StateEventRegistrarService,
|
provide: StateEventRegistrarService,
|
||||||
useClass: StateEventRegistrarService,
|
useClass: DefaultStateEventRegistrarService,
|
||||||
deps: [GlobalStateProvider, StorageServiceProvider],
|
deps: [GlobalStateProvider, StorageServiceProvider],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: StateEventRunnerService,
|
provide: StateEventRunnerService,
|
||||||
useClass: StateEventRunnerService,
|
useClass: DefaultStateEventRunnerService,
|
||||||
deps: [GlobalStateProvider, StorageServiceProvider],
|
deps: [GlobalStateProvider, StorageServiceProvider],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export { DeriveDefinition } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { DerivedStateProvider } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { DerivedState } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { GlobalStateProvider } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { GlobalState } from "@bitwarden/state";
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { Observable, distinctUntilChanged } from "rxjs";
|
|
||||||
|
|
||||||
import { UserId } from "../../../types/guid";
|
|
||||||
import { ActiveUserAccessor } from "../active-user.accessor";
|
|
||||||
import { UserKeyDefinition } from "../user-key-definition";
|
|
||||||
import { ActiveUserState } from "../user-state";
|
|
||||||
import { ActiveUserStateProvider, SingleUserStateProvider } from "../user-state.provider";
|
|
||||||
|
|
||||||
import { DefaultActiveUserState } from "./default-active-user-state";
|
|
||||||
|
|
||||||
export class DefaultActiveUserStateProvider implements ActiveUserStateProvider {
|
|
||||||
activeUserId$: Observable<UserId | undefined>;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private readonly activeAccountAccessor: ActiveUserAccessor,
|
|
||||||
private readonly singleUserStateProvider: SingleUserStateProvider,
|
|
||||||
) {
|
|
||||||
this.activeUserId$ = this.activeAccountAccessor.activeUserId$.pipe(
|
|
||||||
// To avoid going to storage when we don't need to, only get updates when there is a true change.
|
|
||||||
distinctUntilChanged((a, b) => (a == null || b == null ? a == b : a === b)), // Treat null and undefined as equal
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
get<T>(keyDefinition: UserKeyDefinition<T>): ActiveUserState<T> {
|
|
||||||
// All other providers cache the creation of their corresponding `State` objects, this instance
|
|
||||||
// doesn't need to do that since it calls `SingleUserStateProvider` it will go through their caching
|
|
||||||
// layer, because of that, the creation of this instance is quite simple and not worth caching.
|
|
||||||
return new DefaultActiveUserState(
|
|
||||||
keyDefinition,
|
|
||||||
this.activeUserId$,
|
|
||||||
this.singleUserStateProvider,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { DefaultActiveUserState } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { DefaultDerivedStateProvider } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { DefaultDerivedState } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { DefaultGlobalStateProvider } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { DefaultGlobalState } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { DefaultSingleUserStateProvider } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { DefaultSingleUserState } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { DefaultStateProvider } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { InlineDerivedState, InlineDerivedStateProvider } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { StateBase } from "@bitwarden/state";
|
|
||||||
@@ -1 +1,6 @@
|
|||||||
|
import { StateUpdateOptions as RequiredStateUpdateOptions } from "@bitwarden/state";
|
||||||
|
|
||||||
export * from "@bitwarden/state";
|
export * from "@bitwarden/state";
|
||||||
|
export { ActiveUserAccessor } from "@bitwarden/state-internal";
|
||||||
|
|
||||||
|
export type StateUpdateOptions<T, TCombine> = Partial<RequiredStateUpdateOptions<T, TCombine>>;
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export { KeyDefinition, KeyDefinitionOptions } from "@bitwarden/state";
|
|
||||||
@@ -1,4 +1 @@
|
|||||||
export { StateDefinition } from "@bitwarden/state";
|
export { StateDefinition } from "@bitwarden/state";
|
||||||
|
|
||||||
// To be removed once references are updated to point to @bitwarden/storage-core
|
|
||||||
export { StorageLocation, ClientLocations } from "@bitwarden/storage-core";
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
export {
|
|
||||||
StateEventRegistrarService,
|
|
||||||
StateEventInfo,
|
|
||||||
STATE_LOCK_EVENT,
|
|
||||||
STATE_LOGOUT_EVENT,
|
|
||||||
} from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { StateEventRunnerService } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { StateProvider } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { SerializedMemoryStorageService as MemoryStorageService } from "@bitwarden/storage-core";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { UserKeyDefinition, UserKeyDefinitionOptions } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { ActiveUserStateProvider, SingleUserStateProvider } from "@bitwarden/state";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { ActiveUserState, SingleUserState, CombinedState } from "@bitwarden/state";
|
|
||||||
5
libs/state-internal/README.md
Normal file
5
libs/state-internal/README.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# state-internal
|
||||||
|
|
||||||
|
Owned by: platform
|
||||||
|
|
||||||
|
The internal parts of @bitwarden/state that should not be used by other teams.
|
||||||
3
libs/state-internal/eslint.config.mjs
Normal file
3
libs/state-internal/eslint.config.mjs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import baseConfig from "../../eslint.config.mjs";
|
||||||
|
|
||||||
|
export default [...baseConfig];
|
||||||
10
libs/state-internal/jest.config.js
Normal file
10
libs/state-internal/jest.config.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
module.exports = {
|
||||||
|
displayName: "state-internal",
|
||||||
|
preset: "../../jest.preset.js",
|
||||||
|
testEnvironment: "node",
|
||||||
|
transform: {
|
||||||
|
"^.+\\.[tj]s$": ["ts-jest", { tsconfig: "<rootDir>/tsconfig.spec.json" }],
|
||||||
|
},
|
||||||
|
moduleFileExtensions: ["ts", "js", "html"],
|
||||||
|
coverageDirectory: "../../coverage/libs/state-internal",
|
||||||
|
};
|
||||||
11
libs/state-internal/package.json
Normal file
11
libs/state-internal/package.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "@bitwarden/state-internal",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "The internal parts of @bitwarden/state that should not be used by other teams.",
|
||||||
|
"private": true,
|
||||||
|
"type": "commonjs",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"author": "platform"
|
||||||
|
}
|
||||||
33
libs/state-internal/project.json
Normal file
33
libs/state-internal/project.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "state-internal",
|
||||||
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||||
|
"sourceRoot": "libs/state-internal/src",
|
||||||
|
"projectType": "library",
|
||||||
|
"tags": [],
|
||||||
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"executor": "@nx/js:tsc",
|
||||||
|
"outputs": ["{options.outputPath}"],
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/libs/state-internal",
|
||||||
|
"main": "libs/state-internal/src/index.ts",
|
||||||
|
"tsConfig": "libs/state-internal/tsconfig.lib.json",
|
||||||
|
"assets": ["libs/state-internal/*.md"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"executor": "@nx/eslint:lint",
|
||||||
|
"outputs": ["{options.outputFile}"],
|
||||||
|
"options": {
|
||||||
|
"lintFilePatterns": ["libs/state-internal/**/*.ts"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"executor": "@nx/jest:jest",
|
||||||
|
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||||
|
"options": {
|
||||||
|
"jestConfig": "libs/state-internal/jest.config.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,12 @@
|
|||||||
import { Observable, of } from "rxjs";
|
import { Observable, of } from "rxjs";
|
||||||
|
|
||||||
import { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils";
|
import { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils";
|
||||||
|
import {
|
||||||
|
DeriveDefinition,
|
||||||
|
KeyDefinition,
|
||||||
|
StateDefinition,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "@bitwarden/state";
|
||||||
import {
|
import {
|
||||||
FakeActiveUserAccessor,
|
FakeActiveUserAccessor,
|
||||||
FakeActiveUserStateProvider,
|
FakeActiveUserStateProvider,
|
||||||
@@ -14,11 +20,6 @@ import {
|
|||||||
} from "@bitwarden/state-test-utils";
|
} from "@bitwarden/state-test-utils";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { DeriveDefinition } from "../derive-definition";
|
|
||||||
import { KeyDefinition } from "../key-definition";
|
|
||||||
import { StateDefinition } from "../state-definition";
|
|
||||||
import { UserKeyDefinition } from "../user-key-definition";
|
|
||||||
|
|
||||||
import { DefaultStateProvider } from "./default-state.provider";
|
import { DefaultStateProvider } from "./default-state.provider";
|
||||||
|
|
||||||
describe("DefaultStateProvider", () => {
|
describe("DefaultStateProvider", () => {
|
||||||
@@ -2,13 +2,15 @@
|
|||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { Observable, distinctUntilChanged } from "rxjs";
|
import { Observable, distinctUntilChanged } from "rxjs";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ActiveUserState,
|
||||||
|
ActiveUserStateProvider,
|
||||||
|
SingleUserStateProvider,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "@bitwarden/state";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { ActiveUserAccessor } from "../active-user.accessor";
|
import { ActiveUserAccessor } from "./active-user.accessor";
|
||||||
import { UserKeyDefinition } from "../user-key-definition";
|
|
||||||
import { ActiveUserState } from "../user-state";
|
|
||||||
import { ActiveUserStateProvider, SingleUserStateProvider } from "../user-state.provider";
|
|
||||||
|
|
||||||
import { DefaultActiveUserState } from "./default-active-user-state";
|
import { DefaultActiveUserState } from "./default-active-user-state";
|
||||||
|
|
||||||
export class DefaultActiveUserStateProvider implements ActiveUserStateProvider {
|
export class DefaultActiveUserStateProvider implements ActiveUserStateProvider {
|
||||||
@@ -8,14 +8,11 @@ import { Jsonify } from "type-fest";
|
|||||||
|
|
||||||
import { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils";
|
import { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils";
|
||||||
import { LogService } from "@bitwarden/logging";
|
import { LogService } from "@bitwarden/logging";
|
||||||
|
import { StateDefinition, StateEventRegistrarService, UserKeyDefinition } from "@bitwarden/state";
|
||||||
import { StorageServiceProvider } from "@bitwarden/storage-core";
|
import { StorageServiceProvider } from "@bitwarden/storage-core";
|
||||||
import { FakeStorageService } from "@bitwarden/storage-test-utils";
|
import { FakeStorageService } from "@bitwarden/storage-test-utils";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { StateDefinition } from "../state-definition";
|
|
||||||
import { StateEventRegistrarService } from "../state-event-registrar.service";
|
|
||||||
import { UserKeyDefinition } from "../user-key-definition";
|
|
||||||
|
|
||||||
import { DefaultActiveUserState } from "./default-active-user-state";
|
import { DefaultActiveUserState } from "./default-active-user-state";
|
||||||
import { DefaultSingleUserStateProvider } from "./default-single-user-state.provider";
|
import { DefaultSingleUserStateProvider } from "./default-single-user-state.provider";
|
||||||
|
|
||||||
@@ -2,13 +2,16 @@
|
|||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { Observable, map, switchMap, firstValueFrom, timeout, throwError, NEVER } from "rxjs";
|
import { Observable, map, switchMap, firstValueFrom, timeout, throwError, NEVER } from "rxjs";
|
||||||
|
|
||||||
|
import {
|
||||||
|
activeMarker,
|
||||||
|
ActiveUserState,
|
||||||
|
CombinedState,
|
||||||
|
SingleUserStateProvider,
|
||||||
|
StateUpdateOptions,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "@bitwarden/state";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { StateUpdateOptions } from "../state-update-options";
|
|
||||||
import { UserKeyDefinition } from "../user-key-definition";
|
|
||||||
import { ActiveUserState, CombinedState, activeMarker } from "../user-state";
|
|
||||||
import { SingleUserStateProvider } from "../user-state.provider";
|
|
||||||
|
|
||||||
export class DefaultActiveUserState<T> implements ActiveUserState<T> {
|
export class DefaultActiveUserState<T> implements ActiveUserState<T> {
|
||||||
[activeMarker]: true;
|
[activeMarker]: true;
|
||||||
combinedState$: Observable<CombinedState<T>>;
|
combinedState$: Observable<CombinedState<T>>;
|
||||||
@@ -33,7 +36,7 @@ export class DefaultActiveUserState<T> implements ActiveUserState<T> {
|
|||||||
|
|
||||||
async update<TCombine>(
|
async update<TCombine>(
|
||||||
configureState: (state: T, dependency: TCombine) => T,
|
configureState: (state: T, dependency: TCombine) => T,
|
||||||
options: StateUpdateOptions<T, TCombine> = {},
|
options: Partial<StateUpdateOptions<T, TCombine>> = {},
|
||||||
): Promise<[UserId, T]> {
|
): Promise<[UserId, T]> {
|
||||||
const userId = await firstValueFrom(
|
const userId = await firstValueFrom(
|
||||||
this.activeUserId$.pipe(
|
this.activeUserId$.pipe(
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
|
|
||||||
import { DerivedStateDependencies } from "../../types/state";
|
import {
|
||||||
import { DeriveDefinition } from "../derive-definition";
|
DeriveDefinition,
|
||||||
import { DerivedState } from "../derived-state";
|
DerivedState,
|
||||||
import { DerivedStateProvider } from "../derived-state.provider";
|
DerivedStateDependencies,
|
||||||
|
DerivedStateProvider,
|
||||||
|
} from "@bitwarden/state";
|
||||||
|
|
||||||
import { DefaultDerivedState } from "./default-derived-state";
|
import { DefaultDerivedState } from "./default-derived-state";
|
||||||
|
|
||||||
@@ -5,9 +5,7 @@
|
|||||||
import { Subject, firstValueFrom } from "rxjs";
|
import { Subject, firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils";
|
import { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils";
|
||||||
|
import { DeriveDefinition, StateDefinition } from "@bitwarden/state";
|
||||||
import { DeriveDefinition } from "../derive-definition";
|
|
||||||
import { StateDefinition } from "../state-definition";
|
|
||||||
|
|
||||||
import { DefaultDerivedState } from "./default-derived-state";
|
import { DefaultDerivedState } from "./default-derived-state";
|
||||||
import { DefaultDerivedStateProvider } from "./default-derived-state.provider";
|
import { DefaultDerivedStateProvider } from "./default-derived-state.provider";
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
import { Observable, ReplaySubject, Subject, concatMap, merge, share, timer } from "rxjs";
|
import { Observable, ReplaySubject, Subject, concatMap, merge, share, timer } from "rxjs";
|
||||||
|
|
||||||
import { DerivedStateDependencies } from "../../types/state";
|
import { DeriveDefinition, DerivedState, DerivedStateDependencies } from "@bitwarden/state";
|
||||||
import { DeriveDefinition } from "../derive-definition";
|
|
||||||
import { DerivedState } from "../derived-state";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default derived state
|
* Default derived state
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { LogService } from "@bitwarden/logging";
|
import { LogService } from "@bitwarden/logging";
|
||||||
|
import { GlobalState, GlobalStateProvider, KeyDefinition } from "@bitwarden/state";
|
||||||
import { StorageServiceProvider } from "@bitwarden/storage-core";
|
import { StorageServiceProvider } from "@bitwarden/storage-core";
|
||||||
|
|
||||||
import { GlobalState } from "../global-state";
|
|
||||||
import { GlobalStateProvider } from "../global-state.provider";
|
|
||||||
import { KeyDefinition } from "../key-definition";
|
|
||||||
|
|
||||||
import { DefaultGlobalState } from "./default-global-state";
|
import { DefaultGlobalState } from "./default-global-state";
|
||||||
|
|
||||||
export class DefaultGlobalStateProvider implements GlobalStateProvider {
|
export class DefaultGlobalStateProvider implements GlobalStateProvider {
|
||||||
@@ -9,12 +9,11 @@ import { Jsonify } from "type-fest";
|
|||||||
|
|
||||||
import { trackEmissions, awaitAsync } from "@bitwarden/core-test-utils";
|
import { trackEmissions, awaitAsync } from "@bitwarden/core-test-utils";
|
||||||
import { LogService } from "@bitwarden/logging";
|
import { LogService } from "@bitwarden/logging";
|
||||||
|
import { KeyDefinition, StateDefinition } from "@bitwarden/state";
|
||||||
import { FakeStorageService } from "@bitwarden/storage-test-utils";
|
import { FakeStorageService } from "@bitwarden/storage-test-utils";
|
||||||
|
|
||||||
import { KeyDefinition, globalKeyBuilder } from "../key-definition";
|
|
||||||
import { StateDefinition } from "../state-definition";
|
|
||||||
|
|
||||||
import { DefaultGlobalState } from "./default-global-state";
|
import { DefaultGlobalState } from "./default-global-state";
|
||||||
|
import { globalKeyBuilder } from "./util";
|
||||||
|
|
||||||
class TestState {
|
class TestState {
|
||||||
date: Date;
|
date: Date;
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
import { LogService } from "@bitwarden/logging";
|
import { LogService } from "@bitwarden/logging";
|
||||||
|
import { GlobalState, KeyDefinition } from "@bitwarden/state";
|
||||||
import { AbstractStorageService, ObservableStorageService } from "@bitwarden/storage-core";
|
import { AbstractStorageService, ObservableStorageService } from "@bitwarden/storage-core";
|
||||||
|
|
||||||
import { GlobalState } from "../global-state";
|
|
||||||
import { KeyDefinition, globalKeyBuilder } from "../key-definition";
|
|
||||||
|
|
||||||
import { StateBase } from "./state-base";
|
import { StateBase } from "./state-base";
|
||||||
|
import { globalKeyBuilder } from "./util";
|
||||||
|
|
||||||
export class DefaultGlobalState<T>
|
export class DefaultGlobalState<T>
|
||||||
extends StateBase<T, KeyDefinition<T>>
|
extends StateBase<T, KeyDefinition<T>>
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { LogService } from "@bitwarden/logging";
|
import { LogService } from "@bitwarden/logging";
|
||||||
|
import {
|
||||||
|
SingleUserState,
|
||||||
|
SingleUserStateProvider,
|
||||||
|
StateEventRegistrarService,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "@bitwarden/state";
|
||||||
import { StorageServiceProvider } from "@bitwarden/storage-core";
|
import { StorageServiceProvider } from "@bitwarden/storage-core";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { StateEventRegistrarService } from "../state-event-registrar.service";
|
|
||||||
import { UserKeyDefinition } from "../user-key-definition";
|
|
||||||
import { SingleUserState } from "../user-state";
|
|
||||||
import { SingleUserStateProvider } from "../user-state.provider";
|
|
||||||
|
|
||||||
import { DefaultSingleUserState } from "./default-single-user-state";
|
import { DefaultSingleUserState } from "./default-single-user-state";
|
||||||
|
|
||||||
export class DefaultSingleUserStateProvider implements SingleUserStateProvider {
|
export class DefaultSingleUserStateProvider implements SingleUserStateProvider {
|
||||||
@@ -10,13 +10,10 @@ import { Jsonify } from "type-fest";
|
|||||||
import { trackEmissions, awaitAsync } from "@bitwarden/core-test-utils";
|
import { trackEmissions, awaitAsync } from "@bitwarden/core-test-utils";
|
||||||
import { newGuid } from "@bitwarden/guid";
|
import { newGuid } from "@bitwarden/guid";
|
||||||
import { LogService } from "@bitwarden/logging";
|
import { LogService } from "@bitwarden/logging";
|
||||||
|
import { StateDefinition, StateEventRegistrarService, UserKeyDefinition } from "@bitwarden/state";
|
||||||
import { FakeStorageService } from "@bitwarden/storage-test-utils";
|
import { FakeStorageService } from "@bitwarden/storage-test-utils";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { StateDefinition } from "../state-definition";
|
|
||||||
import { StateEventRegistrarService } from "../state-event-registrar.service";
|
|
||||||
import { UserKeyDefinition } from "../user-key-definition";
|
|
||||||
|
|
||||||
import { DefaultSingleUserState } from "./default-single-user-state";
|
import { DefaultSingleUserState } from "./default-single-user-state";
|
||||||
|
|
||||||
class TestState {
|
class TestState {
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
import { Observable, combineLatest, of } from "rxjs";
|
import { Observable, combineLatest, of } from "rxjs";
|
||||||
|
|
||||||
import { LogService } from "@bitwarden/logging";
|
import { LogService } from "@bitwarden/logging";
|
||||||
|
import {
|
||||||
|
CombinedState,
|
||||||
|
SingleUserState,
|
||||||
|
StateEventRegistrarService,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "@bitwarden/state";
|
||||||
import { AbstractStorageService, ObservableStorageService } from "@bitwarden/storage-core";
|
import { AbstractStorageService, ObservableStorageService } from "@bitwarden/storage-core";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { StateEventRegistrarService } from "../state-event-registrar.service";
|
|
||||||
import { UserKeyDefinition } from "../user-key-definition";
|
|
||||||
import { CombinedState, SingleUserState } from "../user-state";
|
|
||||||
|
|
||||||
import { StateBase } from "./state-base";
|
import { StateBase } from "./state-base";
|
||||||
|
|
||||||
export class DefaultSingleUserState<T>
|
export class DefaultSingleUserState<T>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { mock } from "jest-mock-extended";
|
import { mock } from "jest-mock-extended";
|
||||||
|
|
||||||
|
import { StateDefinition, UserKeyDefinition } from "@bitwarden/state";
|
||||||
import { FakeGlobalStateProvider } from "@bitwarden/state-test-utils";
|
import { FakeGlobalStateProvider } from "@bitwarden/state-test-utils";
|
||||||
import {
|
import {
|
||||||
AbstractStorageService,
|
AbstractStorageService,
|
||||||
@@ -7,16 +8,17 @@ import {
|
|||||||
StorageServiceProvider,
|
StorageServiceProvider,
|
||||||
} from "@bitwarden/storage-core";
|
} from "@bitwarden/storage-core";
|
||||||
|
|
||||||
import { StateDefinition } from "./state-definition";
|
import {
|
||||||
import { STATE_LOCK_EVENT, StateEventRegistrarService } from "./state-event-registrar.service";
|
DefaultStateEventRegistrarService,
|
||||||
import { UserKeyDefinition } from "./user-key-definition";
|
STATE_LOCK_EVENT,
|
||||||
|
} from "./default-state-event-registrar.service";
|
||||||
|
|
||||||
describe("StateEventRegistrarService", () => {
|
describe("StateEventRegistrarService", () => {
|
||||||
const globalStateProvider = new FakeGlobalStateProvider();
|
const globalStateProvider = new FakeGlobalStateProvider();
|
||||||
const lockState = globalStateProvider.getFake(STATE_LOCK_EVENT);
|
const lockState = globalStateProvider.getFake(STATE_LOCK_EVENT);
|
||||||
const storageServiceProvider = mock<StorageServiceProvider>();
|
const storageServiceProvider = mock<StorageServiceProvider>();
|
||||||
|
|
||||||
const sut = new StateEventRegistrarService(globalStateProvider, storageServiceProvider);
|
const sut = new DefaultStateEventRegistrarService(globalStateProvider, storageServiceProvider);
|
||||||
|
|
||||||
describe("registerEvents", () => {
|
describe("registerEvents", () => {
|
||||||
const fakeKeyDefinition = new UserKeyDefinition<boolean>(
|
const fakeKeyDefinition = new UserKeyDefinition<boolean>(
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import {
|
||||||
|
CLEAR_EVENT_DISK,
|
||||||
|
ClearEvent,
|
||||||
|
GlobalState,
|
||||||
|
GlobalStateProvider,
|
||||||
|
KeyDefinition,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "@bitwarden/state";
|
||||||
|
import { PossibleLocation, StorageServiceProvider } from "@bitwarden/storage-core";
|
||||||
|
|
||||||
|
export type StateEventInfo = {
|
||||||
|
state: string;
|
||||||
|
key: string;
|
||||||
|
location: PossibleLocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const STATE_LOCK_EVENT = KeyDefinition.array<StateEventInfo>(CLEAR_EVENT_DISK, "lock", {
|
||||||
|
deserializer: (e) => e,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const STATE_LOGOUT_EVENT = KeyDefinition.array<StateEventInfo>(CLEAR_EVENT_DISK, "logout", {
|
||||||
|
deserializer: (e) => e,
|
||||||
|
});
|
||||||
|
|
||||||
|
export class DefaultStateEventRegistrarService {
|
||||||
|
private readonly stateEventStateMap: { [Prop in ClearEvent]: GlobalState<StateEventInfo[]> };
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
globalStateProvider: GlobalStateProvider,
|
||||||
|
private storageServiceProvider: StorageServiceProvider,
|
||||||
|
) {
|
||||||
|
this.stateEventStateMap = {
|
||||||
|
lock: globalStateProvider.get(STATE_LOCK_EVENT),
|
||||||
|
logout: globalStateProvider.get(STATE_LOGOUT_EVENT),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async registerEvents(keyDefinition: UserKeyDefinition<unknown>) {
|
||||||
|
for (const clearEvent of keyDefinition.clearOn) {
|
||||||
|
const eventState = this.stateEventStateMap[clearEvent];
|
||||||
|
// Determine the storage location for this
|
||||||
|
const [storageLocation] = this.storageServiceProvider.get(
|
||||||
|
keyDefinition.stateDefinition.defaultStorageLocation,
|
||||||
|
keyDefinition.stateDefinition.storageLocationOverrides,
|
||||||
|
);
|
||||||
|
|
||||||
|
const newEvent: StateEventInfo = {
|
||||||
|
state: keyDefinition.stateDefinition.name,
|
||||||
|
key: keyDefinition.key,
|
||||||
|
location: storageLocation,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only update the event state if the existing list doesn't have a matching entry
|
||||||
|
await eventState.update(
|
||||||
|
(existingTickets) => {
|
||||||
|
existingTickets ??= [];
|
||||||
|
existingTickets.push(newEvent);
|
||||||
|
return existingTickets;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
shouldUpdate: (currentTickets) => {
|
||||||
|
return (
|
||||||
|
// If the current tickets are null, then it will for sure be added
|
||||||
|
currentTickets == null ||
|
||||||
|
// If an existing match couldn't be found, we also need to add one
|
||||||
|
currentTickets.findIndex(
|
||||||
|
(e) =>
|
||||||
|
e.state === newEvent.state &&
|
||||||
|
e.key === newEvent.key &&
|
||||||
|
e.location === newEvent.location,
|
||||||
|
) === -1
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,16 +8,16 @@ import {
|
|||||||
} from "@bitwarden/storage-core";
|
} from "@bitwarden/storage-core";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { STATE_LOCK_EVENT } from "./state-event-registrar.service";
|
import { STATE_LOCK_EVENT } from "./default-state-event-registrar.service";
|
||||||
import { StateEventRunnerService } from "./state-event-runner.service";
|
import { DefaultStateEventRunnerService } from "./default-state-event-runner.service";
|
||||||
|
|
||||||
describe("EventRunnerService", () => {
|
describe("DefaultStateEventRunnerService", () => {
|
||||||
const fakeGlobalStateProvider = new FakeGlobalStateProvider();
|
const fakeGlobalStateProvider = new FakeGlobalStateProvider();
|
||||||
const lockState = fakeGlobalStateProvider.getFake(STATE_LOCK_EVENT);
|
const lockState = fakeGlobalStateProvider.getFake(STATE_LOCK_EVENT);
|
||||||
|
|
||||||
const storageServiceProvider = mock<StorageServiceProvider>();
|
const storageServiceProvider = mock<StorageServiceProvider>();
|
||||||
|
|
||||||
const sut = new StateEventRunnerService(fakeGlobalStateProvider, storageServiceProvider);
|
const sut = new DefaultStateEventRunnerService(fakeGlobalStateProvider, storageServiceProvider);
|
||||||
|
|
||||||
describe("handleEvent", () => {
|
describe("handleEvent", () => {
|
||||||
it("does nothing if there are no events in state", async () => {
|
it("does nothing if there are no events in state", async () => {
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ClearEvent,
|
||||||
|
GlobalState,
|
||||||
|
GlobalStateProvider,
|
||||||
|
StateDefinition,
|
||||||
|
StateEventRunnerService,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "@bitwarden/state";
|
||||||
|
import { StorageLocation, StorageServiceProvider } from "@bitwarden/storage-core";
|
||||||
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
|
import {
|
||||||
|
STATE_LOCK_EVENT,
|
||||||
|
STATE_LOGOUT_EVENT,
|
||||||
|
StateEventInfo,
|
||||||
|
} from "./default-state-event-registrar.service";
|
||||||
|
|
||||||
|
export class DefaultStateEventRunnerService implements StateEventRunnerService {
|
||||||
|
private readonly stateEventMap: { [Prop in ClearEvent]: GlobalState<StateEventInfo[]> };
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
globalStateProvider: GlobalStateProvider,
|
||||||
|
private storageServiceProvider: StorageServiceProvider,
|
||||||
|
) {
|
||||||
|
this.stateEventMap = {
|
||||||
|
lock: globalStateProvider.get(STATE_LOCK_EVENT),
|
||||||
|
logout: globalStateProvider.get(STATE_LOGOUT_EVENT),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleEvent(event: ClearEvent, userId: UserId) {
|
||||||
|
let tickets = await firstValueFrom(this.stateEventMap[event].state$);
|
||||||
|
tickets ??= [];
|
||||||
|
|
||||||
|
const failures: string[] = [];
|
||||||
|
|
||||||
|
for (const ticket of tickets) {
|
||||||
|
try {
|
||||||
|
const [, service] = this.storageServiceProvider.get(
|
||||||
|
ticket.location,
|
||||||
|
{}, // The storage location is already the computed storage location for this client
|
||||||
|
);
|
||||||
|
|
||||||
|
const ticketStorageKey = this.storageKeyFor(userId, ticket);
|
||||||
|
|
||||||
|
// Evaluate current value so we can avoid writing to state if we don't need to
|
||||||
|
const currentValue = await service.get(ticketStorageKey);
|
||||||
|
if (currentValue != null) {
|
||||||
|
await service.remove(ticketStorageKey);
|
||||||
|
}
|
||||||
|
} catch (err: unknown) {
|
||||||
|
let errorMessage = "Unknown Error";
|
||||||
|
if (
|
||||||
|
err != null &&
|
||||||
|
typeof err === "object" &&
|
||||||
|
"message" in err &&
|
||||||
|
typeof err.message === "string"
|
||||||
|
) {
|
||||||
|
errorMessage = err.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
failures.push(
|
||||||
|
`${errorMessage} in ${ticket.state} > ${ticket.key} located ${ticket.location}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failures.length > 0) {
|
||||||
|
// Throw aggregated error
|
||||||
|
throw new Error(
|
||||||
|
`One or more errors occurred while handling event '${event}' for user ${userId}.\n${failures.join("\n")}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private storageKeyFor(userId: UserId, ticket: StateEventInfo) {
|
||||||
|
const userKey = new UserKeyDefinition<unknown>(
|
||||||
|
new StateDefinition(ticket.state, ticket.location as unknown as StorageLocation),
|
||||||
|
ticket.key,
|
||||||
|
{
|
||||||
|
deserializer: (v) => v,
|
||||||
|
clearOn: [],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return userKey.buildKey(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,12 @@
|
|||||||
import { Observable, of } from "rxjs";
|
import { Observable, of } from "rxjs";
|
||||||
|
|
||||||
import { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils";
|
import { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils";
|
||||||
|
import {
|
||||||
|
DeriveDefinition,
|
||||||
|
KeyDefinition,
|
||||||
|
StateDefinition,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "@bitwarden/state";
|
||||||
import {
|
import {
|
||||||
FakeActiveUserAccessor,
|
FakeActiveUserAccessor,
|
||||||
FakeActiveUserStateProvider,
|
FakeActiveUserStateProvider,
|
||||||
@@ -14,11 +20,6 @@ import {
|
|||||||
} from "@bitwarden/state-test-utils";
|
} from "@bitwarden/state-test-utils";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { DeriveDefinition } from "../derive-definition";
|
|
||||||
import { KeyDefinition } from "../key-definition";
|
|
||||||
import { StateDefinition } from "../state-definition";
|
|
||||||
import { UserKeyDefinition } from "../user-key-definition";
|
|
||||||
|
|
||||||
import { DefaultStateProvider } from "./default-state.provider";
|
import { DefaultStateProvider } from "./default-state.provider";
|
||||||
|
|
||||||
describe("DefaultStateProvider", () => {
|
describe("DefaultStateProvider", () => {
|
||||||
@@ -2,17 +2,19 @@
|
|||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { Observable, filter, of, switchMap, take } from "rxjs";
|
import { Observable, filter, of, switchMap, take } from "rxjs";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ActiveUserStateProvider,
|
||||||
|
DeriveDefinition,
|
||||||
|
DerivedState,
|
||||||
|
DerivedStateDependencies,
|
||||||
|
DerivedStateProvider,
|
||||||
|
GlobalStateProvider,
|
||||||
|
SingleUserStateProvider,
|
||||||
|
StateProvider,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "@bitwarden/state";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { DerivedStateDependencies } from "../../types/state";
|
|
||||||
import { DeriveDefinition } from "../derive-definition";
|
|
||||||
import { DerivedState } from "../derived-state";
|
|
||||||
import { DerivedStateProvider } from "../derived-state.provider";
|
|
||||||
import { GlobalStateProvider } from "../global-state.provider";
|
|
||||||
import { StateProvider } from "../state.provider";
|
|
||||||
import { UserKeyDefinition } from "../user-key-definition";
|
|
||||||
import { ActiveUserStateProvider, SingleUserStateProvider } from "../user-state.provider";
|
|
||||||
|
|
||||||
export class DefaultStateProvider implements StateProvider {
|
export class DefaultStateProvider implements StateProvider {
|
||||||
activeUserId$: Observable<UserId>;
|
activeUserId$: Observable<UserId>;
|
||||||
constructor(
|
constructor(
|
||||||
@@ -10,3 +10,7 @@ export * from "./default-state.provider";
|
|||||||
export * from "./inline-derived-state";
|
export * from "./inline-derived-state";
|
||||||
export * from "./state-base";
|
export * from "./state-base";
|
||||||
export * from "./util";
|
export * from "./util";
|
||||||
|
export { ActiveUserAccessor } from "./active-user.accessor";
|
||||||
|
export { DefaultStateService } from "./legacy/default-state.service";
|
||||||
|
export { DefaultStateEventRegistrarService } from "./default-state-event-registrar.service";
|
||||||
|
export { DefaultStateEventRunnerService } from "./default-state-event-runner.service";
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Subject, firstValueFrom } from "rxjs";
|
import { Subject, firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { DeriveDefinition } from "../derive-definition";
|
import { DeriveDefinition, StateDefinition } from "@bitwarden/state";
|
||||||
import { StateDefinition } from "../state-definition";
|
|
||||||
|
|
||||||
import { InlineDerivedState } from "./inline-derived-state";
|
import { InlineDerivedState } from "./inline-derived-state";
|
||||||
|
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
import { Observable, concatMap } from "rxjs";
|
import { Observable, concatMap } from "rxjs";
|
||||||
|
|
||||||
import { DerivedStateDependencies } from "../../types/state";
|
import {
|
||||||
import { DeriveDefinition } from "../derive-definition";
|
DeriveDefinition,
|
||||||
import { DerivedState } from "../derived-state";
|
DerivedState,
|
||||||
import { DerivedStateProvider } from "../derived-state.provider";
|
DerivedStateDependencies,
|
||||||
|
DerivedStateProvider,
|
||||||
|
} from "@bitwarden/state";
|
||||||
|
|
||||||
export class InlineDerivedStateProvider implements DerivedStateProvider {
|
export class InlineDerivedStateProvider implements DerivedStateProvider {
|
||||||
get<TFrom, TTo, TDeps extends DerivedStateDependencies>(
|
get<TFrom, TTo, TDeps extends DerivedStateDependencies>(
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import { firstValueFrom } from "rxjs";
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
|
import { RequiredUserId, StateService } from "@bitwarden/state";
|
||||||
import { StorageService } from "@bitwarden/storage-core";
|
import { StorageService } from "@bitwarden/storage-core";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { ActiveUserAccessor } from "../core";
|
import { ActiveUserAccessor } from "../active-user.accessor";
|
||||||
|
|
||||||
import { GlobalState } from "./global-state";
|
import { GlobalState } from "./global-state";
|
||||||
import { RequiredUserId, StateService } from "./state.service";
|
|
||||||
|
|
||||||
const keys = {
|
const keys = {
|
||||||
global: "global",
|
global: "global",
|
||||||
@@ -1,16 +1,17 @@
|
|||||||
import { mock } from "jest-mock-extended";
|
import { mock } from "jest-mock-extended";
|
||||||
|
|
||||||
import { LogService } from "@bitwarden/logging";
|
import { LogService } from "@bitwarden/logging";
|
||||||
|
import {
|
||||||
|
KeyDefinition,
|
||||||
|
StateDefinition,
|
||||||
|
StateEventRegistrarService,
|
||||||
|
UserKeyDefinition,
|
||||||
|
} from "@bitwarden/state";
|
||||||
import { FakeActiveUserAccessor } from "@bitwarden/state-test-utils";
|
import { FakeActiveUserAccessor } from "@bitwarden/state-test-utils";
|
||||||
import { StorageServiceProvider } from "@bitwarden/storage-core";
|
import { StorageServiceProvider } from "@bitwarden/storage-core";
|
||||||
import { FakeStorageService } from "@bitwarden/storage-test-utils";
|
import { FakeStorageService } from "@bitwarden/storage-test-utils";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { KeyDefinition } from "../key-definition";
|
|
||||||
import { StateDefinition } from "../state-definition";
|
|
||||||
import { StateEventRegistrarService } from "../state-event-registrar.service";
|
|
||||||
import { UserKeyDefinition } from "../user-key-definition";
|
|
||||||
|
|
||||||
import { DefaultActiveUserState } from "./default-active-user-state";
|
import { DefaultActiveUserState } from "./default-active-user-state";
|
||||||
import { DefaultActiveUserStateProvider } from "./default-active-user-state.provider";
|
import { DefaultActiveUserStateProvider } from "./default-active-user-state.provider";
|
||||||
import { DefaultGlobalState } from "./default-global-state";
|
import { DefaultGlobalState } from "./default-global-state";
|
||||||
@@ -16,13 +16,10 @@ import {
|
|||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { LogService } from "@bitwarden/logging";
|
import { LogService } from "@bitwarden/logging";
|
||||||
|
import { DebugOptions, StateUpdateOptions, StorageKey } from "@bitwarden/state";
|
||||||
import { AbstractStorageService, ObservableStorageService } from "@bitwarden/storage-core";
|
import { AbstractStorageService, ObservableStorageService } from "@bitwarden/storage-core";
|
||||||
|
|
||||||
import { StorageKey } from "../../types/state";
|
import { getStoredValue, populateOptionsWithDefault } from "./util";
|
||||||
import { DebugOptions } from "../key-definition";
|
|
||||||
import { populateOptionsWithDefault, StateUpdateOptions } from "../state-update-options";
|
|
||||||
|
|
||||||
import { getStoredValue } from "./util";
|
|
||||||
|
|
||||||
// The parts of a KeyDefinition this class cares about to make it work
|
// The parts of a KeyDefinition this class cares about to make it work
|
||||||
type KeyDefinitionRequirements<T> = {
|
type KeyDefinitionRequirements<T> = {
|
||||||
@@ -85,15 +82,15 @@ export abstract class StateBase<T, KeyDef extends KeyDefinitionRequirements<T>>
|
|||||||
|
|
||||||
async update<TCombine>(
|
async update<TCombine>(
|
||||||
configureState: (state: T | null, dependency: TCombine) => T | null,
|
configureState: (state: T | null, dependency: TCombine) => T | null,
|
||||||
options: StateUpdateOptions<T, TCombine> = {},
|
options: Partial<StateUpdateOptions<T, TCombine>> = {},
|
||||||
): Promise<T | null> {
|
): Promise<T | null> {
|
||||||
options = populateOptionsWithDefault(options);
|
const normalizedOptions = populateOptionsWithDefault(options);
|
||||||
if (this.updatePromise != null) {
|
if (this.updatePromise != null) {
|
||||||
await this.updatePromise;
|
await this.updatePromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.updatePromise = this.internalUpdate(configureState, options);
|
this.updatePromise = this.internalUpdate(configureState, normalizedOptions);
|
||||||
return await this.updatePromise;
|
return await this.updatePromise;
|
||||||
} finally {
|
} finally {
|
||||||
this.updatePromise = null;
|
this.updatePromise = null;
|
||||||
8
libs/state-internal/src/state-internal.spec.ts
Normal file
8
libs/state-internal/src/state-internal.spec.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import * as lib from "./index";
|
||||||
|
|
||||||
|
describe("state-internal", () => {
|
||||||
|
// This test will fail until something is exported from index.ts
|
||||||
|
it("should work", () => {
|
||||||
|
expect(lib).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
38
libs/state-internal/src/util.ts
Normal file
38
libs/state-internal/src/util.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
|
import { KeyDefinition, StateUpdateOptions, StorageKey } from "@bitwarden/state";
|
||||||
|
import { AbstractStorageService } from "@bitwarden/storage-core";
|
||||||
|
|
||||||
|
export async function getStoredValue<T>(
|
||||||
|
key: string,
|
||||||
|
storage: AbstractStorageService,
|
||||||
|
deserializer: (jsonValue: Jsonify<T>) => T | null,
|
||||||
|
) {
|
||||||
|
if (storage.valuesRequireDeserialization) {
|
||||||
|
const jsonValue = await storage.get<Jsonify<T>>(key);
|
||||||
|
return deserializer(jsonValue);
|
||||||
|
} else {
|
||||||
|
const value = await storage.get<T>(key);
|
||||||
|
return value ?? null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link StorageKey}
|
||||||
|
* @param keyDefinition The key definition of which data the key should point to.
|
||||||
|
* @returns A key that is ready to be used in a storage service to get data.
|
||||||
|
*/
|
||||||
|
export function globalKeyBuilder(keyDefinition: KeyDefinition<unknown>): StorageKey {
|
||||||
|
return `global_${keyDefinition.stateDefinition.name}_${keyDefinition.key}` as StorageKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function populateOptionsWithDefault<T, TCombine>(
|
||||||
|
options: Partial<StateUpdateOptions<T, TCombine>>,
|
||||||
|
): StateUpdateOptions<T, TCombine> {
|
||||||
|
const { combineLatestWith = null, shouldUpdate = () => true, msTimeout = 1000 } = options;
|
||||||
|
return {
|
||||||
|
combineLatestWith: combineLatestWith,
|
||||||
|
shouldUpdate: shouldUpdate,
|
||||||
|
msTimeout: msTimeout,
|
||||||
|
};
|
||||||
|
}
|
||||||
6
libs/state-internal/tsconfig.eslint.json
Normal file
6
libs/state-internal/tsconfig.eslint.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": ["src/**/*.ts", "src/**/*.js"],
|
||||||
|
"exclude": ["**/build", "**/dist"]
|
||||||
|
}
|
||||||
13
libs/state-internal/tsconfig.json
Normal file
13
libs/state-internal/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.lib.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
10
libs/state-internal/tsconfig.lib.json
Normal file
10
libs/state-internal/tsconfig.lib.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"declaration": true,
|
||||||
|
"types": ["node"]
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts"],
|
||||||
|
"exclude": ["jest.config.js", "src/**/*.spec.ts"]
|
||||||
|
}
|
||||||
10
libs/state-internal/tsconfig.spec.json
Normal file
10
libs/state-internal/tsconfig.spec.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../dist/out-tsc",
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node10",
|
||||||
|
"types": ["jest", "node"]
|
||||||
|
},
|
||||||
|
"include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"]
|
||||||
|
}
|
||||||
@@ -17,22 +17,22 @@ import {
|
|||||||
DeriveDefinition,
|
DeriveDefinition,
|
||||||
DerivedStateProvider,
|
DerivedStateProvider,
|
||||||
UserKeyDefinition,
|
UserKeyDefinition,
|
||||||
ActiveUserAccessor,
|
|
||||||
} from "@bitwarden/state";
|
} from "@bitwarden/state";
|
||||||
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FakeActiveUserState,
|
FakeActiveUserState,
|
||||||
FakeDerivedState,
|
FakeDerivedState,
|
||||||
FakeGlobalState,
|
FakeGlobalState,
|
||||||
FakeSingleUserState,
|
FakeSingleUserState,
|
||||||
} from "@bitwarden/state-test-utils";
|
} from "./fake-state";
|
||||||
import { UserId } from "@bitwarden/user-core";
|
|
||||||
|
|
||||||
export interface MinimalAccountService {
|
export interface MinimalAccountService {
|
||||||
activeUserId: UserId | null;
|
activeUserId: UserId | null;
|
||||||
activeAccount$: Observable<{ id: UserId } | null>;
|
activeAccount$: Observable<{ id: UserId } | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FakeActiveUserAccessor implements MinimalAccountService, ActiveUserAccessor {
|
export class FakeActiveUserAccessor implements MinimalAccountService {
|
||||||
private _subject: BehaviorSubject<UserId | null>;
|
private _subject: BehaviorSubject<UserId | null>;
|
||||||
|
|
||||||
constructor(startingUser: UserId | null) {
|
constructor(startingUser: UserId | null) {
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import { Observable } from "rxjs";
|
|
||||||
|
|
||||||
import { UserId } from "@bitwarden/user-core";
|
|
||||||
|
|
||||||
export abstract class ActiveUserAccessor {
|
|
||||||
/**
|
|
||||||
* Returns a stream of the current active user for the application. The stream either emits the user id for that account
|
|
||||||
* or returns null if there is no current active user.
|
|
||||||
*/
|
|
||||||
abstract activeUserId$: Observable<UserId | null>;
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,7 @@ export interface GlobalState<T> {
|
|||||||
*/
|
*/
|
||||||
update: <TCombine>(
|
update: <TCombine>(
|
||||||
configureState: (state: T | null, dependency: TCombine) => T | null,
|
configureState: (state: T | null, dependency: TCombine) => T | null,
|
||||||
options?: StateUpdateOptions<T, TCombine>,
|
options?: Partial<StateUpdateOptions<T, TCombine>>,
|
||||||
) => Promise<T | null>;
|
) => Promise<T | null>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import { Jsonify } from "type-fest";
|
|
||||||
|
|
||||||
import { AbstractStorageService } from "@bitwarden/storage-core";
|
|
||||||
|
|
||||||
export async function getStoredValue<T>(
|
|
||||||
key: string,
|
|
||||||
storage: AbstractStorageService,
|
|
||||||
deserializer: (jsonValue: Jsonify<T>) => T | null,
|
|
||||||
) {
|
|
||||||
if (storage.valuesRequireDeserialization) {
|
|
||||||
const jsonValue = await storage.get<Jsonify<T>>(key);
|
|
||||||
return deserializer(jsonValue);
|
|
||||||
} else {
|
|
||||||
const value = await storage.get<T>(key);
|
|
||||||
return value ?? null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,14 +6,12 @@ export { StateProvider } from "./state.provider";
|
|||||||
export { GlobalStateProvider } from "./global-state.provider";
|
export { GlobalStateProvider } from "./global-state.provider";
|
||||||
export { ActiveUserState, SingleUserState, CombinedState } from "./user-state";
|
export { ActiveUserState, SingleUserState, CombinedState } from "./user-state";
|
||||||
export { ActiveUserStateProvider, SingleUserStateProvider } from "./user-state.provider";
|
export { ActiveUserStateProvider, SingleUserStateProvider } from "./user-state.provider";
|
||||||
export { KeyDefinition, KeyDefinitionOptions } from "./key-definition";
|
export { KeyDefinition, KeyDefinitionOptions, DebugOptions } from "./key-definition";
|
||||||
export { StateUpdateOptions } from "./state-update-options";
|
export { StateUpdateOptions } from "./state-update-options";
|
||||||
export { UserKeyDefinitionOptions, UserKeyDefinition } from "./user-key-definition";
|
export { UserKeyDefinitionOptions, UserKeyDefinition, ClearEvent } from "./user-key-definition";
|
||||||
export { StateEventRunnerService } from "./state-event-runner.service";
|
export { StateEventRunnerService } from "./state-event-runner.service";
|
||||||
export { activeMarker } from "./user-state";
|
export { activeMarker } from "./user-state";
|
||||||
export { StateDefinition } from "./state-definition";
|
export { StateDefinition } from "./state-definition";
|
||||||
export { ActiveUserAccessor } from "./active-user.accessor";
|
|
||||||
|
|
||||||
export * from "./state-definitions";
|
export * from "./state-definitions";
|
||||||
export * from "./implementations";
|
|
||||||
export * from "./state-event-registrar.service";
|
export * from "./state-event-registrar.service";
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import { Jsonify } from "type-fest";
|
|||||||
|
|
||||||
import { array, record } from "@bitwarden/serialization";
|
import { array, record } from "@bitwarden/serialization";
|
||||||
|
|
||||||
import { StorageKey } from "../types/state";
|
|
||||||
|
|
||||||
import { StateDefinition } from "./state-definition";
|
import { StateDefinition } from "./state-definition";
|
||||||
|
|
||||||
export type DebugOptions = {
|
export type DebugOptions = {
|
||||||
@@ -172,12 +170,3 @@ export class KeyDefinition<T> {
|
|||||||
return `${this.stateDefinition.name} > ${this.key}`;
|
return `${this.stateDefinition.name} > ${this.key}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a {@link StorageKey}
|
|
||||||
* @param keyDefinition The key definition of which data the key should point to.
|
|
||||||
* @returns A key that is ready to be used in a storage service to get data.
|
|
||||||
*/
|
|
||||||
export function globalKeyBuilder(keyDefinition: KeyDefinition<unknown>): StorageKey {
|
|
||||||
return `global_${keyDefinition.stateDefinition.name}_${keyDefinition.key}` as StorageKey;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,76 +1,5 @@
|
|||||||
import { PossibleLocation, StorageServiceProvider } from "@bitwarden/storage-core";
|
import { UserKeyDefinition } from "./user-key-definition";
|
||||||
|
|
||||||
import { GlobalState } from "./global-state";
|
export abstract class StateEventRegistrarService {
|
||||||
import { GlobalStateProvider } from "./global-state.provider";
|
abstract registerEvents(keyDefinition: UserKeyDefinition<unknown>): Promise<void>;
|
||||||
import { KeyDefinition } from "./key-definition";
|
|
||||||
import { CLEAR_EVENT_DISK } from "./state-definitions";
|
|
||||||
import { ClearEvent, UserKeyDefinition } from "./user-key-definition";
|
|
||||||
|
|
||||||
export type StateEventInfo = {
|
|
||||||
state: string;
|
|
||||||
key: string;
|
|
||||||
location: PossibleLocation;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const STATE_LOCK_EVENT = KeyDefinition.array<StateEventInfo>(CLEAR_EVENT_DISK, "lock", {
|
|
||||||
deserializer: (e) => e,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const STATE_LOGOUT_EVENT = KeyDefinition.array<StateEventInfo>(CLEAR_EVENT_DISK, "logout", {
|
|
||||||
deserializer: (e) => e,
|
|
||||||
});
|
|
||||||
|
|
||||||
export class StateEventRegistrarService {
|
|
||||||
private readonly stateEventStateMap: { [Prop in ClearEvent]: GlobalState<StateEventInfo[]> };
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
globalStateProvider: GlobalStateProvider,
|
|
||||||
private storageServiceProvider: StorageServiceProvider,
|
|
||||||
) {
|
|
||||||
this.stateEventStateMap = {
|
|
||||||
lock: globalStateProvider.get(STATE_LOCK_EVENT),
|
|
||||||
logout: globalStateProvider.get(STATE_LOGOUT_EVENT),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async registerEvents(keyDefinition: UserKeyDefinition<unknown>) {
|
|
||||||
for (const clearEvent of keyDefinition.clearOn) {
|
|
||||||
const eventState = this.stateEventStateMap[clearEvent];
|
|
||||||
// Determine the storage location for this
|
|
||||||
const [storageLocation] = this.storageServiceProvider.get(
|
|
||||||
keyDefinition.stateDefinition.defaultStorageLocation,
|
|
||||||
keyDefinition.stateDefinition.storageLocationOverrides,
|
|
||||||
);
|
|
||||||
|
|
||||||
const newEvent: StateEventInfo = {
|
|
||||||
state: keyDefinition.stateDefinition.name,
|
|
||||||
key: keyDefinition.key,
|
|
||||||
location: storageLocation,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Only update the event state if the existing list doesn't have a matching entry
|
|
||||||
await eventState.update(
|
|
||||||
(existingTickets) => {
|
|
||||||
existingTickets ??= [];
|
|
||||||
existingTickets.push(newEvent);
|
|
||||||
return existingTickets;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
shouldUpdate: (currentTickets) => {
|
|
||||||
return (
|
|
||||||
// If the current tickets are null, then it will for sure be added
|
|
||||||
currentTickets == null ||
|
|
||||||
// If an existing match couldn't be found, we also need to add one
|
|
||||||
currentTickets.findIndex(
|
|
||||||
(e) =>
|
|
||||||
e.state === newEvent.state &&
|
|
||||||
e.key === newEvent.key &&
|
|
||||||
e.location === newEvent.location,
|
|
||||||
) === -1
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,82 +1,7 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
|
||||||
// @ts-strict-ignore
|
|
||||||
import { firstValueFrom } from "rxjs";
|
|
||||||
|
|
||||||
import { StorageServiceProvider, StorageLocation } from "@bitwarden/storage-core";
|
|
||||||
import { UserId } from "@bitwarden/user-core";
|
import { UserId } from "@bitwarden/user-core";
|
||||||
|
|
||||||
import { GlobalState } from "./global-state";
|
import { ClearEvent } from "./user-key-definition";
|
||||||
import { GlobalStateProvider } from "./global-state.provider";
|
|
||||||
import { StateDefinition } from "./state-definition";
|
|
||||||
import {
|
|
||||||
STATE_LOCK_EVENT,
|
|
||||||
STATE_LOGOUT_EVENT,
|
|
||||||
StateEventInfo,
|
|
||||||
} from "./state-event-registrar.service";
|
|
||||||
import { ClearEvent, UserKeyDefinition } from "./user-key-definition";
|
|
||||||
|
|
||||||
export class StateEventRunnerService {
|
export abstract class StateEventRunnerService {
|
||||||
private readonly stateEventMap: { [Prop in ClearEvent]: GlobalState<StateEventInfo[]> };
|
abstract handleEvent(event: ClearEvent, userId: UserId): Promise<void>;
|
||||||
|
|
||||||
constructor(
|
|
||||||
globalStateProvider: GlobalStateProvider,
|
|
||||||
private storageServiceProvider: StorageServiceProvider,
|
|
||||||
) {
|
|
||||||
this.stateEventMap = {
|
|
||||||
lock: globalStateProvider.get(STATE_LOCK_EVENT),
|
|
||||||
logout: globalStateProvider.get(STATE_LOGOUT_EVENT),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleEvent(event: ClearEvent, userId: UserId) {
|
|
||||||
let tickets = await firstValueFrom(this.stateEventMap[event].state$);
|
|
||||||
tickets ??= [];
|
|
||||||
|
|
||||||
const failures: string[] = [];
|
|
||||||
|
|
||||||
for (const ticket of tickets) {
|
|
||||||
try {
|
|
||||||
const [, service] = this.storageServiceProvider.get(
|
|
||||||
ticket.location,
|
|
||||||
{}, // The storage location is already the computed storage location for this client
|
|
||||||
);
|
|
||||||
|
|
||||||
const ticketStorageKey = this.storageKeyFor(userId, ticket);
|
|
||||||
|
|
||||||
// Evaluate current value so we can avoid writing to state if we don't need to
|
|
||||||
const currentValue = await service.get(ticketStorageKey);
|
|
||||||
if (currentValue != null) {
|
|
||||||
await service.remove(ticketStorageKey);
|
|
||||||
}
|
|
||||||
} catch (err: unknown) {
|
|
||||||
let errorMessage = "Unknown Error";
|
|
||||||
if (typeof err === "object" && "message" in err && typeof err.message === "string") {
|
|
||||||
errorMessage = err.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
failures.push(
|
|
||||||
`${errorMessage} in ${ticket.state} > ${ticket.key} located ${ticket.location}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (failures.length > 0) {
|
|
||||||
// Throw aggregated error
|
|
||||||
throw new Error(
|
|
||||||
`One or more errors occurred while handling event '${event}' for user ${userId}.\n${failures.join("\n")}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private storageKeyFor(userId: UserId, ticket: StateEventInfo) {
|
|
||||||
const userKey = new UserKeyDefinition<unknown>(
|
|
||||||
new StateDefinition(ticket.state, ticket.location as unknown as StorageLocation),
|
|
||||||
ticket.key,
|
|
||||||
{
|
|
||||||
deserializer: (v) => v,
|
|
||||||
clearOn: [],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
return userKey.buildKey(userId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,27 +2,8 @@
|
|||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
|
|
||||||
export const DEFAULT_OPTIONS = {
|
export type StateUpdateOptions<T, TCombine> = {
|
||||||
shouldUpdate: () => true,
|
readonly shouldUpdate: (state: T, dependency: TCombine) => boolean;
|
||||||
combineLatestWith: null as Observable<unknown>,
|
readonly combineLatestWith: Observable<TCombine> | null;
|
||||||
msTimeout: 1000,
|
readonly msTimeout: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DefinitelyTypedDefault<T, TCombine> = Omit<
|
|
||||||
typeof DEFAULT_OPTIONS,
|
|
||||||
"shouldUpdate" | "combineLatestWith"
|
|
||||||
> & {
|
|
||||||
shouldUpdate: (state: T, dependency: TCombine) => boolean;
|
|
||||||
combineLatestWith?: Observable<TCombine>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type StateUpdateOptions<T, TCombine> = Partial<DefinitelyTypedDefault<T, TCombine>>;
|
|
||||||
|
|
||||||
export function populateOptionsWithDefault<T, TCombine>(
|
|
||||||
options: StateUpdateOptions<T, TCombine>,
|
|
||||||
): StateUpdateOptions<T, TCombine> {
|
|
||||||
return {
|
|
||||||
...(DEFAULT_OPTIONS as StateUpdateOptions<T, TCombine>),
|
|
||||||
...options,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export interface ActiveUserState<T> extends UserState<T> {
|
|||||||
*/
|
*/
|
||||||
readonly update: <TCombine>(
|
readonly update: <TCombine>(
|
||||||
configureState: (state: T | null, dependencies: TCombine) => T | null,
|
configureState: (state: T | null, dependencies: TCombine) => T | null,
|
||||||
options?: StateUpdateOptions<T, TCombine>,
|
options?: Partial<StateUpdateOptions<T, TCombine>>,
|
||||||
) => Promise<[UserId, T | null]>;
|
) => Promise<[UserId, T | null]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +59,6 @@ export interface SingleUserState<T> extends UserState<T> {
|
|||||||
*/
|
*/
|
||||||
readonly update: <TCombine>(
|
readonly update: <TCombine>(
|
||||||
configureState: (state: T | null, dependencies: TCombine) => T | null,
|
configureState: (state: T | null, dependencies: TCombine) => T | null,
|
||||||
options?: StateUpdateOptions<T, TCombine>,
|
options?: Partial<StateUpdateOptions<T, TCombine>>,
|
||||||
) => Promise<T | null>;
|
) => Promise<T | null>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
export { StateService } from "./state.service";
|
export { StateService, RequiredUserId } from "./state.service";
|
||||||
export { DefaultStateService } from "./default-state.service";
|
|
||||||
|
|||||||
8
package-lock.json
generated
8
package-lock.json
generated
@@ -402,6 +402,10 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "GPL-3.0"
|
"license": "GPL-3.0"
|
||||||
},
|
},
|
||||||
|
"libs/state-internal": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"license": "GPL-3.0"
|
||||||
|
},
|
||||||
"libs/state-test-utils": {
|
"libs/state-test-utils": {
|
||||||
"name": "@bitwarden/state-test-utils",
|
"name": "@bitwarden/state-test-utils",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
@@ -4709,6 +4713,10 @@
|
|||||||
"resolved": "libs/state",
|
"resolved": "libs/state",
|
||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@bitwarden/state-internal": {
|
||||||
|
"resolved": "libs/state-internal",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/@bitwarden/state-test-utils": {
|
"node_modules/@bitwarden/state-test-utils": {
|
||||||
"resolved": "libs/state-test-utils",
|
"resolved": "libs/state-test-utils",
|
||||||
"link": true
|
"link": true
|
||||||
|
|||||||
@@ -52,6 +52,7 @@
|
|||||||
"@bitwarden/send-ui": ["./libs/tools/send/send-ui/src"],
|
"@bitwarden/send-ui": ["./libs/tools/send/send-ui/src"],
|
||||||
"@bitwarden/serialization": ["libs/serialization/src/index.ts"],
|
"@bitwarden/serialization": ["libs/serialization/src/index.ts"],
|
||||||
"@bitwarden/state": ["libs/state/src/index.ts"],
|
"@bitwarden/state": ["libs/state/src/index.ts"],
|
||||||
|
"@bitwarden/state-internal": ["libs/state-internal/src/index.ts"],
|
||||||
"@bitwarden/state-test-utils": ["libs/state-test-utils/src/index.ts"],
|
"@bitwarden/state-test-utils": ["libs/state-test-utils/src/index.ts"],
|
||||||
"@bitwarden/storage-core": ["libs/storage-core/src/index.ts"],
|
"@bitwarden/storage-core": ["libs/storage-core/src/index.ts"],
|
||||||
"@bitwarden/storage-test-utils": ["libs/storage-test-utils/src/index.ts"],
|
"@bitwarden/storage-test-utils": ["libs/storage-test-utils/src/index.ts"],
|
||||||
|
|||||||
Reference in New Issue
Block a user