mirror of
https://github.com/bitwarden/browser
synced 2026-02-11 14:04:03 +00:00
feat-wip: migrate sdk and ssh services
This commit is contained in:
@@ -45,11 +45,11 @@ import { SearchCiphersPipe } from "./pipes/search-ciphers.pipe";
|
||||
import { SearchPipe } from "./pipes/search.pipe";
|
||||
import { UserNamePipe } from "./pipes/user-name.pipe";
|
||||
import { UserTypePipe } from "./pipes/user-type.pipe";
|
||||
import { DecentralizedInitService as DecentralizedInitServiceAbstraction } from "./platform/abstractions/decentralized-init.service";
|
||||
import { DecentralizedInitService } from "./platform/abstractions/decentralized-init.service";
|
||||
import { EllipsisPipe } from "./platform/pipes/ellipsis.pipe";
|
||||
import { FingerprintPipe } from "./platform/pipes/fingerprint.pipe";
|
||||
import { I18nPipe } from "./platform/pipes/i18n.pipe";
|
||||
import { DecentralizedInitService } from "./platform/services/decentralized-init.service";
|
||||
import { DefaultDecentralizedInitService } from "./platform/services/default-decentralized-init.service";
|
||||
import { safeProvider } from "./platform/utils/safe-provider";
|
||||
import { IconComponent } from "./vault/components/icon.component";
|
||||
|
||||
@@ -149,8 +149,8 @@ import { IconComponent } from "./vault/components/icon.component";
|
||||
FingerprintPipe,
|
||||
PluralizePipe,
|
||||
safeProvider({
|
||||
provide: DecentralizedInitServiceAbstraction,
|
||||
useClass: DecentralizedInitService,
|
||||
provide: DecentralizedInitService,
|
||||
useClass: DefaultDecentralizedInitService,
|
||||
useAngularDecorators: true,
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -1,26 +1,9 @@
|
||||
import { InjectionToken, Type } from "@angular/core";
|
||||
import { InjectionToken } from "@angular/core";
|
||||
|
||||
import { Dependency, Initializable } from "@bitwarden/common/platform/abstractions/initializable";
|
||||
|
||||
import { SafeProvider } from "../utils/safe-provider";
|
||||
|
||||
/**
|
||||
* Services that implement Initializable can participate in decentralized initialization.
|
||||
* Each service declares its dependencies, and the DecentralizedInitService will execute
|
||||
* them in the correct order using topological sort.
|
||||
*/
|
||||
export abstract class Initializable {
|
||||
/**
|
||||
* List of service classes that must be initialized before this service.
|
||||
* Use actual class references for type safety and refactoring support.
|
||||
*/
|
||||
abstract dependencies: Type<Initializable>[];
|
||||
|
||||
/**
|
||||
* Initialize this service. Called after all dependencies have been initialized.
|
||||
* Can be async or sync.
|
||||
*/
|
||||
abstract init(): Promise<void> | void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multi-provider token for registering services that need initialization.
|
||||
* Services register themselves by adding to their library's provider bundle:
|
||||
@@ -40,7 +23,7 @@ export const INIT_SERVICES = new InjectionToken<Initializable[]>("INIT_SERVICES"
|
||||
*
|
||||
* @param type The Initializable service class
|
||||
*/
|
||||
export function initializableProvider<T extends Type<Initializable>>(ctor: T) {
|
||||
export function initializableProvider<T extends Dependency>(ctor: T) {
|
||||
return {
|
||||
provide: INIT_SERVICES,
|
||||
useExisting: ctor,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/**
|
||||
* Example usage of DecentralizedInitService
|
||||
* Example usage of DefaultDecentralizedInitService
|
||||
*
|
||||
* This file demonstrates how to:
|
||||
* 1. Make services implement Initializable
|
||||
* 2. Register services with INIT_SERVICES
|
||||
* 3. Use DecentralizedInitService in your app
|
||||
* 3. Use DefaultDecentralizedInitService in your app
|
||||
*
|
||||
* This is NOT production code - it's a reference example.
|
||||
*/
|
||||
@@ -90,17 +90,17 @@ export const EXAMPLE_LIBRARY_PROVIDERS = [
|
||||
/**
|
||||
* In your app's main config (e.g., app.config.ts or main.ts):
|
||||
*
|
||||
* import { DecentralizedInitService } from '@bitwarden/angular/platform/services/decentralized-init.service';
|
||||
* import { DefaultDecentralizedInitService } from '@bitwarden/angular/platform/services/default-decentralized-init.service';
|
||||
* import { EXAMPLE_LIBRARY_PROVIDERS } from '@bitwarden/angular/platform/services/decentralized-init.service.example';
|
||||
*
|
||||
* export const appConfig: ApplicationConfig = {
|
||||
* providers: [
|
||||
* ...EXAMPLE_LIBRARY_PROVIDERS,
|
||||
* DecentralizedInitService,
|
||||
* DefaultDecentralizedInitService,
|
||||
* {
|
||||
* provide: APP_INITIALIZER,
|
||||
* useFactory: (initService: DecentralizedInitService) => () => initService.init(),
|
||||
* deps: [DecentralizedInitService],
|
||||
* useFactory: (initService: DefaultDecentralizedInitService) => () => initService.init(),
|
||||
* deps: [DefaultDecentralizedInitService],
|
||||
* multi: true,
|
||||
* },
|
||||
* ]
|
||||
@@ -110,7 +110,7 @@ export const EXAMPLE_LIBRARY_PROVIDERS = [
|
||||
*
|
||||
* @Component({ ... })
|
||||
* export class AppComponent {
|
||||
* constructor(private initService: DecentralizedInitService) {}
|
||||
* constructor(private initService: DefaultDecentralizedInitService) {}
|
||||
*
|
||||
* ngOnInit() {
|
||||
* await this.initService.init();
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Type } from "@angular/core";
|
||||
|
||||
import { Initializable } from "../abstractions/decentralized-init.service";
|
||||
|
||||
import { DecentralizedInitService } from "./decentralized-init.service";
|
||||
import { DefaultDecentralizedInitService } from "./default-decentralized-init.service";
|
||||
|
||||
// Test service implementations
|
||||
class TestService implements Initializable {
|
||||
@@ -23,7 +23,7 @@ function createTrackingService(name: string, executionOrder: string[]) {
|
||||
};
|
||||
}
|
||||
|
||||
describe("DecentralizedInitService", () => {
|
||||
describe("DefaultDecentralizedInitService", () => {
|
||||
let executionOrder: string[];
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -34,7 +34,7 @@ describe("DecentralizedInitService", () => {
|
||||
describe("given no registered services", () => {
|
||||
it("completes without error when called", async () => {
|
||||
// Arrange
|
||||
const sut = new DecentralizedInitService([]);
|
||||
const sut = new DefaultDecentralizedInitService([]);
|
||||
|
||||
// Act & Assert
|
||||
await expect(sut.init()).resolves.not.toThrow();
|
||||
@@ -45,7 +45,7 @@ describe("DecentralizedInitService", () => {
|
||||
it("initializes a single service when called", async () => {
|
||||
// Arrange
|
||||
const service = new TestService();
|
||||
const sut = new DecentralizedInitService([service]);
|
||||
const sut = new DefaultDecentralizedInitService([service]);
|
||||
|
||||
// Act
|
||||
await sut.init();
|
||||
@@ -59,7 +59,7 @@ describe("DecentralizedInitService", () => {
|
||||
const service1 = new TestService();
|
||||
const service2 = new TestService();
|
||||
const service3 = new TestService();
|
||||
const sut = new DecentralizedInitService([service1, service2, service3]);
|
||||
const sut = new DefaultDecentralizedInitService([service1, service2, service3]);
|
||||
|
||||
// Act
|
||||
await sut.init();
|
||||
@@ -81,7 +81,7 @@ describe("DecentralizedInitService", () => {
|
||||
const serviceB = new ServiceB();
|
||||
serviceB.dependencies = [ServiceA];
|
||||
|
||||
const sut = new DecentralizedInitService([serviceB, serviceA]);
|
||||
const sut = new DefaultDecentralizedInitService([serviceB, serviceA]);
|
||||
|
||||
// Act
|
||||
await sut.init();
|
||||
@@ -107,7 +107,7 @@ describe("DecentralizedInitService", () => {
|
||||
serviceC.dependencies = [ServiceA, ServiceB];
|
||||
serviceD.dependencies = [ServiceC];
|
||||
|
||||
const sut = new DecentralizedInitService([serviceD, serviceB, serviceC, serviceA]);
|
||||
const sut = new DefaultDecentralizedInitService([serviceD, serviceB, serviceC, serviceA]);
|
||||
|
||||
// Act
|
||||
await sut.init();
|
||||
@@ -139,7 +139,7 @@ describe("DecentralizedInitService", () => {
|
||||
serviceC.dependencies = [ServiceA];
|
||||
serviceD.dependencies = [ServiceB, ServiceC];
|
||||
|
||||
const sut = new DecentralizedInitService([serviceD, serviceC, serviceB, serviceA]);
|
||||
const sut = new DefaultDecentralizedInitService([serviceD, serviceC, serviceB, serviceA]);
|
||||
|
||||
// Act
|
||||
await sut.init();
|
||||
@@ -166,7 +166,7 @@ describe("DecentralizedInitService", () => {
|
||||
}
|
||||
|
||||
const service = new CountingService();
|
||||
const sut = new DecentralizedInitService([service]);
|
||||
const sut = new DefaultDecentralizedInitService([service]);
|
||||
|
||||
// Act
|
||||
await sut.init();
|
||||
@@ -188,7 +188,7 @@ describe("DecentralizedInitService", () => {
|
||||
serviceA.dependencies = [ServiceB as Type<Initializable>];
|
||||
serviceB.dependencies = [ServiceA as Type<Initializable>];
|
||||
|
||||
const sut = new DecentralizedInitService([serviceA, serviceB]);
|
||||
const sut = new DefaultDecentralizedInitService([serviceA, serviceB]);
|
||||
|
||||
// Act & Assert
|
||||
await expect(sut.init()).rejects.toThrow(/Circular dependency detected/);
|
||||
@@ -208,7 +208,7 @@ describe("DecentralizedInitService", () => {
|
||||
serviceB.dependencies = [ServiceC as Type<Initializable>];
|
||||
serviceC.dependencies = [ServiceA as Type<Initializable>];
|
||||
|
||||
const sut = new DecentralizedInitService([serviceA, serviceB, serviceC]);
|
||||
const sut = new DefaultDecentralizedInitService([serviceA, serviceB, serviceC]);
|
||||
|
||||
// Act & Assert
|
||||
await expect(sut.init()).rejects.toThrow(/Circular dependency detected/);
|
||||
@@ -224,7 +224,7 @@ describe("DecentralizedInitService", () => {
|
||||
}
|
||||
|
||||
const serviceB = new ServiceB();
|
||||
const sut = new DecentralizedInitService([serviceB]);
|
||||
const sut = new DefaultDecentralizedInitService([serviceB]);
|
||||
|
||||
// Act & Assert
|
||||
await expect(sut.init()).rejects.toThrow(/not registered in INIT_SERVICES/);
|
||||
@@ -238,7 +238,7 @@ describe("DecentralizedInitService", () => {
|
||||
}
|
||||
|
||||
const myService = new MyService();
|
||||
const sut = new DecentralizedInitService([myService]);
|
||||
const sut = new DefaultDecentralizedInitService([myService]);
|
||||
|
||||
// Act & Assert
|
||||
await expect(sut.init()).rejects.toThrow("MyService depends on MyDependency");
|
||||
@@ -256,7 +256,7 @@ describe("DecentralizedInitService", () => {
|
||||
}
|
||||
|
||||
const service = new FailingService();
|
||||
const sut = new DecentralizedInitService([service]);
|
||||
const sut = new DefaultDecentralizedInitService([service]);
|
||||
|
||||
// Act & Assert
|
||||
await expect(sut.init()).rejects.toThrow(/Failed to initialize FailingService/);
|
||||
@@ -275,7 +275,7 @@ describe("DecentralizedInitService", () => {
|
||||
}
|
||||
|
||||
const service = new SyncService();
|
||||
const sut = new DecentralizedInitService([service]);
|
||||
const sut = new DefaultDecentralizedInitService([service]);
|
||||
|
||||
// Act
|
||||
await sut.init();
|
||||
@@ -305,7 +305,7 @@ describe("DecentralizedInitService", () => {
|
||||
|
||||
const syncService = new SyncService();
|
||||
const asyncService = new AsyncService();
|
||||
const sut = new DecentralizedInitService([asyncService, syncService]);
|
||||
const sut = new DefaultDecentralizedInitService([asyncService, syncService]);
|
||||
|
||||
// Act
|
||||
await sut.init();
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Inject, Injectable, Type } from "@angular/core";
|
||||
import { Inject, Injectable } from "@angular/core";
|
||||
|
||||
import { Dependency, Initializable } from "@bitwarden/common/platform/abstractions/initializable";
|
||||
|
||||
import {
|
||||
DecentralizedInitService as DecentralizedInitServiceAbstraction,
|
||||
Initializable,
|
||||
DecentralizedInitService,
|
||||
INIT_SERVICES,
|
||||
} from "../abstractions/decentralized-init.service";
|
||||
|
||||
@@ -18,7 +19,7 @@ import {
|
||||
* - Executes init() methods sequentially in dependency order
|
||||
*/
|
||||
@Injectable()
|
||||
export class DecentralizedInitService implements DecentralizedInitServiceAbstraction {
|
||||
export class DefaultDecentralizedInitService implements DecentralizedInitService {
|
||||
constructor(@Inject(INIT_SERVICES) private initServices: Initializable[]) {}
|
||||
|
||||
async init(): Promise<void> {
|
||||
@@ -46,9 +47,9 @@ export class DecentralizedInitService implements DecentralizedInitServiceAbstrac
|
||||
*/
|
||||
private topologicalSort(services: Initializable[]): Initializable[] {
|
||||
// Build a map from constructor to instance for quick lookup
|
||||
const instanceMap = new Map<Type<Initializable>, Initializable>();
|
||||
const instanceMap = new Map<Dependency, Initializable>();
|
||||
for (const service of services) {
|
||||
instanceMap.set(service.constructor as Type<Initializable>, service);
|
||||
instanceMap.set(service.constructor as Dependency, service);
|
||||
}
|
||||
|
||||
const sorted: Initializable[] = [];
|
||||
@@ -70,7 +71,7 @@ export class DecentralizedInitService implements DecentralizedInitServiceAbstrac
|
||||
const currentPath = [...path, service.constructor.name];
|
||||
|
||||
// Visit all dependencies first
|
||||
for (const depClass of service.dependencies) {
|
||||
for (const depClass of service.dependencies ?? []) {
|
||||
const depInstance = instanceMap.get(depClass);
|
||||
|
||||
if (!depInstance) {
|
||||
Reference in New Issue
Block a user