O que uma factory de plugin faz
Uma factory de plugin é uma função que aceita um objeto de configuração e retorna uma entrada { namespace, config } para o array plugins. Ao usar o helper definePlugin de @spraxium/core, você cria essa factory com inferência completa de TypeScript: a string de namespace fica presa a um tipo literal, a carga de configuração é validada em tempo de compilação e ConfigStore.getPluginConfig infere automaticamente o tipo de retorno quando você passa a factory como chave.
Escrever uma factory significa que quem consome o plugin nunca toca em strings cruas de namespace. A mesma referência, a função de factory exportada, serve tanto como entrada de registro em spraxium.config.ts quanto como chave de lookup dentro do código do seu serviço. Se o namespace mudar algum dia, só o arquivo de definição da factory precisa ser atualizado.
Defina a interface de configuração
Crie uma interface TypeScript que descreva todas as opções de que o plugin precisa em runtime. Mantenha-a plana e focada no que o plugin realmente consome. Adicione comentários JSDoc para que o editor mostre tooltips quando outras pessoas configurarem o plugin.
export interface MyPluginConfig {
enabled: boolean;
apiKey: string;
retries?: number;
}Crie a factory com definePlugin
Chame definePlugin com a string literal do namespace como primeiro
parâmetro de tipo e a interface de configuração como segundo. Exporte a
factory resultante para que quem usa o plugin possa importá-la em
spraxium.config.ts. O namespace precisa ser único entre todos os plugins
registrados no mesmo projeto.
import { definePlugin } from '@spraxium/core';
import type { MyPluginConfig } from './interfaces/my-plugin-config.interface';
export const defineMyPlugin = definePlugin<'my-plugin', MyPluginConfig>(
'my-plugin',
);Registre em spraxium.config.ts
Importe a factory e chame-a dentro do array plugins. O TypeScript impõe o formato do objeto de configuração e rejeita chaves inválidas ou tipos de valor incorretos em tempo de compilação, antes que qualquer código rode.
import { defineConfig } from '@spraxium/core';
import { defineMyPlugin } from './src/my-plugin.config';
export default defineConfig({
plugins: [
defineMyPlugin({
enabled: true,
apiKey: process.env.MY_PLUGIN_API_KEY ?? '',
retries: 3,
}),
],
});Leia a config em runtime
Dentro do serviço do plugin, chame ConfigStore.getPluginConfig com a
factory como argumento. O tipo de retorno é inferido automaticamente como
MyPluginConfig | undefined. Se o plugin não tiver sido registrado, o
método retorna undefined, então você sempre deve tratar esse caso antes
de acessar os campos.
import { Injectable } from '@spraxium/common';
import { ConfigStore } from '@spraxium/core';
import { defineMyPlugin } from './my-plugin.config';
@Injectable()
export class MyPluginService {
private readonly config = ConfigStore.getPluginConfig(defineMyPlugin);
initialize(): void {
if (!this.config?.enabled) return;
// Use this.config.apiKey, this.config.retries, etc.
}
}O namespace precisa ser único
Se dois plugins compartilharem a mesma string de namespace, a segunda entrada no array plugins vai sobrescrever a primeira. As duas continuarão presentes no array, mas somente a última com aquele namespace será retornada por getPluginConfig. Escolha namespaces que reflitam o nome do pacote para evitar colisões.
Lendo a config fora de um serviço
ConfigStore.getPluginConfig é um método estático que pode ser chamado em qualquer lugar depois que a config é carregada. Isso inclui guards, interceptors e código em nível de módulo. A função de factory é o único argumento necessário; não há lookup por string nem cast manual de tipo.
import { Guard } from '@spraxium/common';
import type { ExecutionContext, SpraxiumGuard } from '@spraxium/common';
import { ConfigStore } from '@spraxium/core';
import { defineMyPlugin } from '../my-plugin.config';
@Guard()
export class PluginEnabledGuard implements SpraxiumGuard {
canActivate(_ctx: ExecutionContext): boolean {
const config = ConfigStore.getPluginConfig(defineMyPlugin);
return config?.enabled === true;
}
}Organizando o arquivo da factory
Em pacotes publicados, a factory e a interface de configuração normalmente ficam lado a lado na raiz do pacote e são reexportadas pelo índice do pacote. Assim, quem consome importa tudo o que precisa em uma única linha.