65 lines
2.8 KiB
TypeScript
65 lines
2.8 KiB
TypeScript
import type Database from 'better-sqlite3';
|
|
import type { FastifyInstance } from 'fastify';
|
|
import { buildApp, type BuildAppOptions } from './app.js';
|
|
import {
|
|
ConnectionProbe,
|
|
type ConnectionTransport,
|
|
} from './application/connections/connection-probe.js';
|
|
import { InstanceCredentialResolver } from './application/connections/instance-credential-resolver.js';
|
|
import { InstanceLoginService } from './application/connections/instance-login-service.js';
|
|
import {
|
|
InstanceSessionStore,
|
|
UpstreamSessionClient,
|
|
type UpstreamSessionClientOptions,
|
|
} from './application/connections/upstream-session-client.js';
|
|
import { InstanceService } from './application/instances/instance-service.js';
|
|
import { DeleteInstanceOperation } from './application/operations/delete-instance-operation.js';
|
|
import type { SecretStore } from './infrastructure/secrets/secret-store.js';
|
|
import { registerInstanceRoutes } from './interface/http/instance-routes.js';
|
|
|
|
export interface SafeControlPlaneUpstream extends ConnectionTransport {
|
|
request: UpstreamSessionClientOptions['request'];
|
|
}
|
|
export interface ControlPlaneOptions {
|
|
readonly db: Database.Database;
|
|
readonly store: SecretStore;
|
|
readonly upstream: SafeControlPlaneUpstream;
|
|
readonly now?: () => Date;
|
|
readonly app?: Omit<BuildAppOptions, 'registerRoutes'>;
|
|
}
|
|
export interface ControlPlaneApp extends FastifyInstance {
|
|
retryPendingSecretCleanup(): Promise<unknown>;
|
|
}
|
|
export function buildControlPlaneApp(options: ControlPlaneOptions): ControlPlaneApp {
|
|
const instances = options.now
|
|
? new InstanceService({ db: options.db, store: options.store, now: options.now })
|
|
: new InstanceService({ db: options.db, store: options.store });
|
|
const connections = options.now
|
|
? new ConnectionProbe({
|
|
db: options.db,
|
|
instances,
|
|
transport: options.upstream,
|
|
now: options.now,
|
|
})
|
|
: new ConnectionProbe({ db: options.db, instances, transport: options.upstream });
|
|
const sessions = new InstanceSessionStore();
|
|
const client = new UpstreamSessionClient({ sessions, request: options.upstream.request });
|
|
const resolver = new InstanceCredentialResolver({ db: options.db, store: options.store });
|
|
const login = options.now
|
|
? new InstanceLoginService({ db: options.db, client, resolver, now: options.now })
|
|
: new InstanceLoginService({ db: options.db, client, resolver });
|
|
const deletion = options.now
|
|
? new DeleteInstanceOperation({ db: options.db, instances, now: options.now })
|
|
: new DeleteInstanceOperation({ db: options.db, instances });
|
|
deletion.reconcileInterruptedJobs();
|
|
const app = buildApp({
|
|
...options.app,
|
|
registerRoutes: (app) =>
|
|
registerInstanceRoutes(app, { instances, connections, login, deletion }),
|
|
});
|
|
Object.assign(app, {
|
|
retryPendingSecretCleanup: () => instances.retryPendingSecretCleanup(),
|
|
});
|
|
return app as ControlPlaneApp;
|
|
}
|