diff options
| author | Adam Malczewski <[email protected]> | 2026-06-26 22:03:19 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-26 22:23:39 +0900 |
| commit | 727c98c9dae516a2070eb950410314380a20c974 (patch) | |
| tree | 52aa1022c54f11770be7e4e2a324f0a8b8b8deec /packages/kernel/src/host/host.ts | |
| parent | e59dc11f63b1df51142259bb2c406af8c9c8c2bb (diff) | |
| download | dispatch-727c98c9dae516a2070eb950410314380a20c974.tar.gz dispatch-727c98c9dae516a2070eb950410314380a20c974.zip | |
style: switch from tabs to 2-space indentation
Diffstat (limited to 'packages/kernel/src/host/host.ts')
| -rw-r--r-- | packages/kernel/src/host/host.ts | 412 |
1 files changed, 206 insertions, 206 deletions
diff --git a/packages/kernel/src/host/host.ts b/packages/kernel/src/host/host.ts index 2a262be..f74881f 100644 --- a/packages/kernel/src/host/host.ts +++ b/packages/kernel/src/host/host.ts @@ -1,22 +1,22 @@ import type { Bus } from "../bus/bus.js"; import type { AuthContract } from "../contracts/auth.js"; import type { - ConfigAccess, - EventsEmitter, - Extension, - HostAPI, - Manifest, - PermissionGate, - ScheduledJob, - SecretsAccess, - StorageNamespace, + ConfigAccess, + EventsEmitter, + Extension, + HostAPI, + Manifest, + PermissionGate, + ScheduledJob, + SecretsAccess, + StorageNamespace, } from "../contracts/extension.js"; import type { - EventHandler, - EventHookDescriptor, - FilterDescriptor, - FilterHandler, - ServiceHandle, + EventHandler, + EventHookDescriptor, + FilterDescriptor, + FilterHandler, + ServiceHandle, } from "../contracts/hooks.js"; import type { LogDeps, Logger, LogSink } from "../contracts/logging.js"; import type { ProviderContract } from "../contracts/provider.js"; @@ -28,210 +28,210 @@ import { isApiVersionCompatible } from "./version.js"; export const KERNEL_API_VERSION = "0.1.0"; export interface DisabledExtension { - readonly manifest: Manifest; - readonly reason: string; + readonly manifest: Manifest; + readonly reason: string; } export interface HostDeps { - readonly logger: Logger; - readonly config: ConfigAccess; - readonly storageFactory: (namespace: string) => StorageNamespace; - readonly secrets: SecretsAccess; - readonly permissions: PermissionGate; - readonly scheduler: { readonly register: (job: ScheduledJob) => void }; - readonly bus: Bus; - readonly events: EventsEmitter; - readonly logSink: LogSink; - readonly logDeps: LogDeps; + readonly logger: Logger; + readonly config: ConfigAccess; + readonly storageFactory: (namespace: string) => StorageNamespace; + readonly secrets: SecretsAccess; + readonly permissions: PermissionGate; + readonly scheduler: { readonly register: (job: ScheduledJob) => void }; + readonly bus: Bus; + readonly events: EventsEmitter; + readonly logSink: LogSink; + readonly logDeps: LogDeps; } export interface Host { - readonly activate: () => Promise<void>; - readonly deactivate: () => Promise<void>; - readonly getTools: () => ReadonlyMap<string, ToolContract>; - readonly getTool: (name: string) => ToolContract | undefined; - readonly getProviders: () => ReadonlyMap<string, ProviderContract>; - readonly getProvider: (id: string) => ProviderContract | undefined; - readonly getAuthProviders: () => ReadonlyMap<string, AuthContract>; - readonly getAuthProvider: (id: string) => AuthContract | undefined; - readonly getScheduledJobs: () => readonly ScheduledJob[]; - readonly getMigrations: () => readonly string[]; - readonly getDisabled: () => readonly DisabledExtension[]; - readonly getExtensions: () => readonly Manifest[]; - readonly getHostAPI: () => HostAPI; + readonly activate: () => Promise<void>; + readonly deactivate: () => Promise<void>; + readonly getTools: () => ReadonlyMap<string, ToolContract>; + readonly getTool: (name: string) => ToolContract | undefined; + readonly getProviders: () => ReadonlyMap<string, ProviderContract>; + readonly getProvider: (id: string) => ProviderContract | undefined; + readonly getAuthProviders: () => ReadonlyMap<string, AuthContract>; + readonly getAuthProvider: (id: string) => AuthContract | undefined; + readonly getScheduledJobs: () => readonly ScheduledJob[]; + readonly getMigrations: () => readonly string[]; + readonly getDisabled: () => readonly DisabledExtension[]; + readonly getExtensions: () => readonly Manifest[]; + readonly getHostAPI: () => HostAPI; } export function createHost(extensions: readonly Extension[], deps: HostDeps): Host { - const tools = new Map<string, ToolContract>(); - const providers = new Map<string, ProviderContract>(); - const authProviders = new Map<string, AuthContract>(); - const scheduledJobs: ScheduledJob[] = []; - const migrations: string[] = []; - const disabled: DisabledExtension[] = []; - const activated: Extension[] = []; + const tools = new Map<string, ToolContract>(); + const providers = new Map<string, ProviderContract>(); + const authProviders = new Map<string, AuthContract>(); + const scheduledJobs: ScheduledJob[] = []; + const migrations: string[] = []; + const disabled: DisabledExtension[] = []; + const activated: Extension[] = []; - const ordered = resolveActivationOrder(extensions.map((e) => e.manifest)); - const extById = new Map<string, Extension>(); - for (const ext of extensions) { - extById.set(ext.manifest.id, ext); - } + const ordered = resolveActivationOrder(extensions.map((e) => e.manifest)); + const extById = new Map<string, Extension>(); + for (const ext of extensions) { + extById.set(ext.manifest.id, ext); + } - const compatible: Extension[] = []; - for (const m of ordered) { - const ext = extById.get(m.id); - if (ext === undefined) continue; - if (isApiVersionCompatible(m.apiVersion, KERNEL_API_VERSION)) { - compatible.push(ext); - } else { - disabled.push({ - manifest: m, - reason: `apiVersion "${m.apiVersion}" is incompatible with kernel API ${KERNEL_API_VERSION}`, - }); - deps.logger.warn(`Extension "${m.id}" disabled: apiVersion incompatible`); - } - } + const compatible: Extension[] = []; + for (const m of ordered) { + const ext = extById.get(m.id); + if (ext === undefined) continue; + if (isApiVersionCompatible(m.apiVersion, KERNEL_API_VERSION)) { + compatible.push(ext); + } else { + disabled.push({ + manifest: m, + reason: `apiVersion "${m.apiVersion}" is incompatible with kernel API ${KERNEL_API_VERSION}`, + }); + deps.logger.warn(`Extension "${m.id}" disabled: apiVersion incompatible`); + } + } - for (const ext of compatible) { - const extMigrations = ext.manifest.contributes?.migrations; - if (extMigrations) { - for (const migration of extMigrations) { - migrations.push(migration); - } - } - } + for (const ext of compatible) { + const extMigrations = ext.manifest.contributes?.migrations; + if (extMigrations) { + for (const migration of extMigrations) { + migrations.push(migration); + } + } + } - function buildHostAPI( - extensionId: string, - opts?: { readonly registrationClosed?: boolean }, - ): HostAPI { - const closed = opts?.registrationClosed ?? false; - const extLogger = createLogger({ extensionId }, deps.logSink, deps.logDeps); - return { - defineTool(tool: ToolContract) { - if (closed) throw new Error("Registration not available after activation"); - tools.set(tool.name, tool); - }, - defineProvider(provider: ProviderContract) { - if (closed) throw new Error("Registration not available after activation"); - providers.set(provider.id, provider); - }, - defineAuth(auth: AuthContract) { - if (closed) throw new Error("Registration not available after activation"); - authProviders.set(auth.id, auth); - }, - on<TPayload>(hook: EventHookDescriptor<TPayload>, handler: EventHandler<TPayload>) { - return deps.bus.on(hook, handler); - }, - emit<TPayload>(hook: EventHookDescriptor<TPayload>, payload: TPayload) { - deps.bus.emit(hook, payload); - }, - addFilter<TValue>(hook: FilterDescriptor<TValue>, fn: FilterHandler<TValue>) { - return deps.bus.addFilter(hook, fn); - }, - async applyFilters<TValue>( - hook: FilterDescriptor<TValue>, - value: TValue, - opts?: { readonly failClosed?: boolean }, - ): Promise<TValue> { - return deps.bus.applyFilters(hook, value, opts); - }, - provideService<T>(handle: ServiceHandle<T>, impl: T) { - deps.bus.provideService(handle, impl); - }, - getService<T>(handle: ServiceHandle<T>): T { - return deps.bus.getService(handle); - }, - storage(namespace: string): StorageNamespace { - return deps.storageFactory(namespace); - }, - config: deps.config, - secrets: deps.secrets, - permissions: deps.permissions, - events: deps.events, - logger: extLogger, - getProviders() { - return providers; - }, - getTools() { - return tools; - }, - getAuthProviders() { - return authProviders; - }, - getAuthProvider(id: string) { - return authProviders.get(id); - }, - getExtensions() { - return Object.freeze(activated.map((e) => e.manifest)); - }, - scheduler: { - register(job: ScheduledJob) { - scheduledJobs.push(job); - deps.scheduler.register(job); - }, - }, - }; - } + function buildHostAPI( + extensionId: string, + opts?: { readonly registrationClosed?: boolean }, + ): HostAPI { + const closed = opts?.registrationClosed ?? false; + const extLogger = createLogger({ extensionId }, deps.logSink, deps.logDeps); + return { + defineTool(tool: ToolContract) { + if (closed) throw new Error("Registration not available after activation"); + tools.set(tool.name, tool); + }, + defineProvider(provider: ProviderContract) { + if (closed) throw new Error("Registration not available after activation"); + providers.set(provider.id, provider); + }, + defineAuth(auth: AuthContract) { + if (closed) throw new Error("Registration not available after activation"); + authProviders.set(auth.id, auth); + }, + on<TPayload>(hook: EventHookDescriptor<TPayload>, handler: EventHandler<TPayload>) { + return deps.bus.on(hook, handler); + }, + emit<TPayload>(hook: EventHookDescriptor<TPayload>, payload: TPayload) { + deps.bus.emit(hook, payload); + }, + addFilter<TValue>(hook: FilterDescriptor<TValue>, fn: FilterHandler<TValue>) { + return deps.bus.addFilter(hook, fn); + }, + async applyFilters<TValue>( + hook: FilterDescriptor<TValue>, + value: TValue, + opts?: { readonly failClosed?: boolean }, + ): Promise<TValue> { + return deps.bus.applyFilters(hook, value, opts); + }, + provideService<T>(handle: ServiceHandle<T>, impl: T) { + deps.bus.provideService(handle, impl); + }, + getService<T>(handle: ServiceHandle<T>): T { + return deps.bus.getService(handle); + }, + storage(namespace: string): StorageNamespace { + return deps.storageFactory(namespace); + }, + config: deps.config, + secrets: deps.secrets, + permissions: deps.permissions, + events: deps.events, + logger: extLogger, + getProviders() { + return providers; + }, + getTools() { + return tools; + }, + getAuthProviders() { + return authProviders; + }, + getAuthProvider(id: string) { + return authProviders.get(id); + }, + getExtensions() { + return Object.freeze(activated.map((e) => e.manifest)); + }, + scheduler: { + register(job: ScheduledJob) { + scheduledJobs.push(job); + deps.scheduler.register(job); + }, + }, + }; + } - return { - async activate() { - for (const ext of compatible) { - try { - await ext.activate(buildHostAPI(ext.manifest.id)); - activated.push(ext); - deps.logger.info(`Extension "${ext.manifest.id}" activated`); - } catch (err) { - disabled.push({ - manifest: ext.manifest, - reason: `Activation failed: ${err instanceof Error ? err.message : String(err)}`, - }); - deps.logger.error(`Extension "${ext.manifest.id}" failed to activate`, { err }); - } - } - }, - async deactivate() { - for (let i = activated.length - 1; i >= 0; i--) { - const ext = activated[i]; - if (ext === undefined || ext.deactivate === undefined) continue; - try { - await ext.deactivate(); - } catch (err) { - deps.logger.error(`Extension "${ext.manifest.id}" failed to deactivate`, { err }); - } - } - }, - getTools() { - return tools; - }, - getTool(name: string) { - return tools.get(name); - }, - getProviders() { - return providers; - }, - getProvider(id: string) { - return providers.get(id); - }, - getAuthProviders() { - return authProviders; - }, - getAuthProvider(id: string) { - return authProviders.get(id); - }, - getScheduledJobs() { - return scheduledJobs; - }, - getMigrations() { - return migrations; - }, - getDisabled() { - return disabled; - }, - getExtensions() { - return Object.freeze(activated.map((e) => e.manifest)); - }, - getHostAPI() { - return buildHostAPI("__host__", { registrationClosed: true }); - }, - }; + return { + async activate() { + for (const ext of compatible) { + try { + await ext.activate(buildHostAPI(ext.manifest.id)); + activated.push(ext); + deps.logger.info(`Extension "${ext.manifest.id}" activated`); + } catch (err) { + disabled.push({ + manifest: ext.manifest, + reason: `Activation failed: ${err instanceof Error ? err.message : String(err)}`, + }); + deps.logger.error(`Extension "${ext.manifest.id}" failed to activate`, { err }); + } + } + }, + async deactivate() { + for (let i = activated.length - 1; i >= 0; i--) { + const ext = activated[i]; + if (ext === undefined || ext.deactivate === undefined) continue; + try { + await ext.deactivate(); + } catch (err) { + deps.logger.error(`Extension "${ext.manifest.id}" failed to deactivate`, { err }); + } + } + }, + getTools() { + return tools; + }, + getTool(name: string) { + return tools.get(name); + }, + getProviders() { + return providers; + }, + getProvider(id: string) { + return providers.get(id); + }, + getAuthProviders() { + return authProviders; + }, + getAuthProvider(id: string) { + return authProviders.get(id); + }, + getScheduledJobs() { + return scheduledJobs; + }, + getMigrations() { + return migrations; + }, + getDisabled() { + return disabled; + }, + getExtensions() { + return Object.freeze(activated.map((e) => e.manifest)); + }, + getHostAPI() { + return buildHostAPI("__host__", { registrationClosed: true }); + }, + }; } |
