/** * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { Runnable } from "@k8slens/run-many"; import type { DiContainerForInjection, Injectable, InjectionToken } from "@ogre-tools/injectable"; import { getInjectionToken, getInjectable } from "@ogre-tools/injectable"; import assert from "assert"; export interface Initializable { readonly rootId: string; readonly stateToken: InjectionToken; } export const getInitializable = (rootId: string): Initializable => ({ rootId, stateToken: getInjectionToken({ id: `${rootId}-state-token`, }), }); type InitState = { set: true; value: T } | { set: false }; export type ImplInitializableInjectionTokensArgs = { token: Initializable; init: (di: DiContainerForInjection) => T | Promise; } & ( { phase: InjectionToken, void>; runAfter?: Injectable, Runnable, void>[]; } | { runAfter: Injectable, Runnable, void>; phase?: undefined; } ); export const getInjectablesForInitializable = ({ init, token: { rootId, stateToken, }, ...rest }: ImplInitializableInjectionTokensArgs) => { let state: InitState = { set: false }; const stateInjectable = getInjectable({ id: `${rootId}-state`, instantiate: () => { assert(state.set, `Tried to inject "${rootId}" before initialization was complete`); return state.value; }, injectionToken: stateToken, }); const initializationInjectable = getInjectable({ id: `${rootId}-initialization`, instantiate: (di) => ({ run: async () => { state = { set: true, value: await init(di), }; }, runAfter: rest.runAfter, }), injectionToken: (() => { if (rest.runAfter && !Array.isArray(rest.runAfter)) { return rest.runAfter.injectionToken; } return rest.phase; })(), }); return { stateInjectable, initializationInjectable, }; };