feat(api): complete phase 2.4 control plane
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import type Database from 'better-sqlite3';
|
||||
import type { SessionMetadata } from '@multi-simadmin/contracts';
|
||||
import { CredentialResolverError } from './instance-credential-resolver.js';
|
||||
import { UpstreamSessionClient } from './upstream-session-client.js';
|
||||
|
||||
export interface CredentialResolver {
|
||||
resolve(instanceId: string): Promise<string>;
|
||||
}
|
||||
export class InstanceLoginServiceError extends Error {
|
||||
constructor(readonly code: 'NOT_FOUND' | 'CREDENTIAL_UNAVAILABLE') {
|
||||
super(code);
|
||||
}
|
||||
}
|
||||
export interface InstanceLoginServiceOptions {
|
||||
readonly db: Database.Database;
|
||||
readonly client: UpstreamSessionClient;
|
||||
readonly resolver: CredentialResolver;
|
||||
readonly now?: () => Date;
|
||||
}
|
||||
export class InstanceLoginService {
|
||||
private readonly now: () => Date;
|
||||
constructor(private readonly options: InstanceLoginServiceOptions) {
|
||||
this.now = options.now ?? (() => new Date());
|
||||
}
|
||||
async login(instanceId: string, password?: string): Promise<SessionMetadata> {
|
||||
const origin = this.origin(instanceId);
|
||||
let resolved: string;
|
||||
try {
|
||||
resolved = password ?? (await this.options.resolver.resolve(instanceId));
|
||||
} catch (error) {
|
||||
if (error instanceof CredentialResolverError) throw new InstanceLoginServiceError(error.code);
|
||||
throw error;
|
||||
}
|
||||
const result = await this.options.client.login(instanceId, origin, resolved);
|
||||
return { instanceId, authenticated: result.authenticated, checkedAt: this.now().toISOString() };
|
||||
}
|
||||
async logout(instanceId: string): Promise<SessionMetadata> {
|
||||
await this.options.client.logout(instanceId, this.origin(instanceId));
|
||||
return { instanceId, authenticated: false, checkedAt: this.now().toISOString() };
|
||||
}
|
||||
private origin(instanceId: string): string {
|
||||
const row = this.options.db
|
||||
.prepare('SELECT base_url FROM instances WHERE id=?')
|
||||
.get(instanceId) as { base_url: string } | undefined;
|
||||
if (!row) throw new InstanceLoginServiceError('NOT_FOUND');
|
||||
return row.base_url;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user