import type { AppLifecycleService, AppLifecycleServiceDependencies } from "@lib/services/base/AppLifecycleService"; import { ServiceContext } from "@lib/services/base/ServiceBase"; import * as nodePath from "node:path"; import { ConfigServiceBrowserCompat } from "@lib/services/implements/browser/ConfigServiceBrowserCompat"; import { SvelteDialogManagerBase, type ComponentHasResult } from "@lib/services/implements/base/SvelteDialog"; import { UIService } from "@lib/services/implements/base/UIService"; import { InjectableServiceHub } from "@lib/services/implements/injectable/InjectableServiceHub"; import { InjectableAppLifecycleService } from "@lib/services/implements/injectable/InjectableAppLifecycleService"; import { InjectableConflictService } from "@lib/services/implements/injectable/InjectableConflictService"; import { InjectableDatabaseEventService } from "@lib/services/implements/injectable/InjectableDatabaseEventService"; import { InjectableFileProcessingService } from "@lib/services/implements/injectable/InjectableFileProcessingService"; import { PathServiceCompat } from "@lib/services/implements/injectable/InjectablePathService"; import { InjectableRemoteService } from "@lib/services/implements/injectable/InjectableRemoteService"; import { InjectableReplicationService } from "@lib/services/implements/injectable/InjectableReplicationService"; import { InjectableReplicatorService } from "@lib/services/implements/injectable/InjectableReplicatorService"; import { InjectableTestService } from "@lib/services/implements/injectable/InjectableTestService"; import { InjectableTweakValueService } from "@lib/services/implements/injectable/InjectableTweakValueService"; import { InjectableVaultServiceCompat } from "@lib/services/implements/injectable/InjectableVaultService"; import { ControlService } from "@lib/services/base/ControlService"; import type { IControlService } from "@lib/services/base/IService"; import { HeadlessAPIService } from "@lib/services/implements/headless/HeadlessAPIService"; // import { HeadlessDatabaseService } from "@lib/services/implements/headless/HeadlessDatabaseService"; import type { ServiceInstances } from "@lib/services/ServiceHub"; import { NodeKeyValueDBService } from "./NodeKeyValueDBService"; import { NodeSettingService } from "./NodeSettingService"; import { DatabaseService } from "@lib/services/base/DatabaseService"; import type { ObsidianLiveSyncSettings } from "@/lib/src/common/types"; export class NodeServiceContext extends ServiceContext { vaultPath: string; constructor(vaultPath: string) { super(); this.vaultPath = vaultPath; } } class NodeAppLifecycleService extends InjectableAppLifecycleService { constructor(context: T, dependencies: AppLifecycleServiceDependencies) { super(context, dependencies); } } class NodeSvelteDialogManager extends SvelteDialogManagerBase { openSvelteDialog( component: ComponentHasResult, initialData?: UInitial ): Promise { throw new Error("Method not implemented."); } } type NodeUIServiceDependencies = { appLifecycle: AppLifecycleService; config: ConfigServiceBrowserCompat; replicator: InjectableReplicatorService; APIService: HeadlessAPIService; control: IControlService; }; class NodeDatabaseService extends DatabaseService { protected override modifyDatabaseOptions( settings: ObsidianLiveSyncSettings, name: string, options: PouchDB.Configuration.DatabaseConfiguration ): { name: string; options: PouchDB.Configuration.DatabaseConfiguration } { const optionPass = { ...options, prefix: this.context.vaultPath + nodePath.sep, }; const passSettings = { ...settings, useIndexedDBAdapter: false }; return super.modifyDatabaseOptions(passSettings, name, optionPass); } } class NodeUIService extends UIService { override get dialogToCopy(): never { throw new Error("Method not implemented."); } constructor(context: T, dependencies: NodeUIServiceDependencies) { const headlessConfirm = dependencies.APIService.confirm; const dialogManager = new NodeSvelteDialogManager(context, { confirm: headlessConfirm, appLifecycle: dependencies.appLifecycle, config: dependencies.config, replicator: dependencies.replicator, control: dependencies.control, }); super(context, { appLifecycle: dependencies.appLifecycle, dialogManager, APIService: dependencies.APIService, }); } } export class NodeServiceHub extends InjectableServiceHub { constructor(basePath: string, context: T = new NodeServiceContext(basePath) as T) { const runtimeDir = nodePath.join(basePath, ".livesync", "runtime"); const localStoragePath = nodePath.join(runtimeDir, "local-storage.json"); const keyValueDBPath = nodePath.join(runtimeDir, "keyvalue-db.json"); const API = new HeadlessAPIService(context); const conflict = new InjectableConflictService(context); const fileProcessing = new InjectableFileProcessingService(context); const setting = new NodeSettingService(context, { APIService: API }, localStoragePath); const appLifecycle = new NodeAppLifecycleService(context, { settingService: setting, }); const remote = new InjectableRemoteService(context, { APIService: API, appLifecycle, setting, }); const tweakValue = new InjectableTweakValueService(context); const vault = new InjectableVaultServiceCompat(context, { settingService: setting, APIService: API, }); const test = new InjectableTestService(context); const databaseEvents = new InjectableDatabaseEventService(context); const path = new PathServiceCompat(context, { settingService: setting, }); const database = new NodeDatabaseService(context, { API: API, path, vault, setting, }); const config = new ConfigServiceBrowserCompat(context, { settingService: setting, APIService: API, }); const replicator = new InjectableReplicatorService(context, { settingService: setting, appLifecycleService: appLifecycle, databaseEventService: databaseEvents, }); const replication = new InjectableReplicationService(context, { APIService: API, appLifecycleService: appLifecycle, replicatorService: replicator, settingService: setting, fileProcessingService: fileProcessing, databaseService: database, }); const keyValueDB = new NodeKeyValueDBService( context, { appLifecycle, databaseEvents, vault, }, keyValueDBPath ); const control = new ControlService(context, { appLifecycleService: appLifecycle, settingService: setting, databaseService: database, fileProcessingService: fileProcessing, APIService: API, replicatorService: replicator, }); const ui = new NodeUIService(context, { appLifecycle, config, replicator, APIService: API, control, }); const serviceInstancesToInit: Required> = { appLifecycle, conflict, database, databaseEvents, fileProcessing, replication, replicator, remote, setting, tweakValue, vault, test, ui, path, API, config, keyValueDB: keyValueDB as any, control, }; super(context, serviceInstancesToInit as any); } }