import { type Static, type TObject, type TSchema } from '@sinclair/typebox'; import { GROUP } from '../utils/consts.ts'; import type { Services } from '../utils/service.ts'; import { noopAsync } from '../utils/types.js'; import { customResourceStatusSchema, type CustomResourceRequest } from './custom-resource.request.ts'; type EnsureSecretOptions = { schema: T; name: string; namespace: string; generator: () => Promise>; }; type CustomResourceHandlerOptions = { request: CustomResourceRequest; ensureSecret: (options: EnsureSecretOptions) => Promise>; services: Services; }; type CustomResourceConstructor = { kind: string; spec: TSpec; names: { plural: string; singular: string; }; }; abstract class CustomResource { #options: CustomResourceConstructor; constructor(options: CustomResourceConstructor) { this.#options = options; } public readonly version = 'v1'; public get name() { return `${this.#options.names.plural}.${this.group}`; } public get group() { return GROUP; } public get path() { return `/apis/${this.group}/v1/${this.#options.names.plural}`; } public get kind() { return this.#options.kind; } public get spec() { return this.#options.spec; } public get names() { return this.#options.names; } public abstract update(options: CustomResourceHandlerOptions): Promise; public create?(options: CustomResourceHandlerOptions): Promise; public delete?(options: CustomResourceHandlerOptions): Promise; public toManifest = () => { return { apiVersion: 'apiextensions.k8s.io/v1', kind: 'CustomResourceDefinition', metadata: { name: this.name, }, spec: { group: this.group, names: { kind: this.kind, plural: this.#options.names.plural, singular: this.#options.names.singular, }, scope: 'Namespaced', versions: [ { name: this.version, served: true, storage: true, schema: { openAPIV3Schema: { type: 'object', properties: { spec: this.spec, status: customResourceStatusSchema as ExpectedAny, }, }, }, subresources: { status: {}, }, }, ], }, }; }; } const createCustomResource = ( options: CustomResourceConstructor & { update?: (options: CustomResourceHandlerOptions) => Promise; create?: (options: CustomResourceHandlerOptions) => Promise; delete?: (options: CustomResourceHandlerOptions) => Promise; }, ) => { return class extends CustomResource { constructor() { super(options); } public update = options.update ?? noopAsync; public create = options.create; public delete = options.delete; }; }; export { CustomResource, type CustomResourceConstructor, type CustomResourceHandlerOptions, type EnsureSecretOptions, createCustomResource, };