# define _(no submodules)_ ## Purpose The `define` module exports a single function — `definePlugin(descriptor)` — that is the canonical entry point for authoring a plugin. The function returns its input unchanged at runtime; the value is entirely in its type signature, which threads the `TConfig` generic through every place the descriptor references it: `configSchema?: ZodType`, `defaults?: Partial`, and the four lifecycle hooks (`onRegister/onInit/onReady/onClose`). Inside each hook, `ctx.getOwnConfig()` returns `TConfig` with no cast required. Using `definePlugin` is preferred over building a raw `PluginDescriptor` literal because it pins the generic at the call site. TypeScript will then flag mismatches at the source of the error (the hook body), not at the registration site one or two files away. ## Features - Zero runtime overhead — the function body is `return descriptor`. - Full `TConfig` inference flows into hooks via `PluginContext`. - Compatible with descriptor field defaults (`description`, `dependencies`, `optionalDependencies`, `priority`, `enabledByDefault`, `tags`). - Plays nicely with `as const` literals — readers preserve `readonly` arrays for `dependencies` etc. ## Usage: Basic ```ts import { definePlugin } from "@suaveplan/api-plugin/define"; import z from "zod"; export const auth = definePlugin({ name: "auth", version: "0.1.0", configSchema: z.object({ sessionTtlSeconds: z.number().int().positive() }), defaults: { sessionTtlSeconds: 3600 }, onInit(ctx) { const { sessionTtlSeconds } = ctx.getOwnConfig(); ctx.logger.info("auth ready", { sessionTtlSeconds }); }, }); ``` ## Usage: Advanced Multiple hooks with `await` and the abort signal: ```ts export const queue = definePlugin<{ concurrency: number }>({ name: "queue", version: "0.1.0", dependencies: ["db"], defaults: { concurrency: 4 }, async onInit(ctx) { const { concurrency } = ctx.getOwnConfig(); ctx.logger.info("starting queue", { concurrency }); }, async onReady(ctx) { if (ctx.signal.aborted) return; ctx.logger.info("queue ready"); }, async onClose(ctx) { ctx.logger.info("queue draining"); }, }); ``` ## API Reference | Export | Signature | |---|---| | `definePlugin(descriptor)` | `(PluginDescriptor) => PluginDescriptor` | ## Implementation Notes The function is intentionally an identity at runtime so it can be constant-folded by bundlers — the dependency graph rewards leaf helpers that the optimiser can drop. Because the `descriptor` parameter is typed as `PluginDescriptor`, TypeScript will not narrow `TConfig` away if the call site supplies an explicit generic (`definePlugin({...})`). Implicit inference also works when `configSchema` is provided as a Zod schema, because the descriptor field is typed `ZodType` and Zod's schema generic is contravariant in this position. Calling `definePlugin` is preferred over a bare object literal even though both are runtime-equivalent: the call site is the right place for an editor to surface "Quick Info" on the generic, and it keeps the public author surface consistent across the 40+ in-flight `@suaveplan/api-plugin-*` packages.