first commit
This commit is contained in:
66
docs/api-stack/api/api-plugin-site/src/plugin/plugin.md
Normal file
66
docs/api-stack/api/api-plugin-site/src/plugin/plugin.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# `plugin/plugin.ts`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Owns `createSitePlugin`, the canonical factory that produces the `PluginDescriptor` consumed by `@suaveplan/api-plugin`'s `PluginRegistry`. The factory composes every other module in this package — `SitePluginOptionsSchema` validates options at the boundary, the `SiteService` + `DomainResolverService` are constructed once, the Hono middleware is built and exposed through `ServiceRegistry`, the public + private route trees are mounted under the configured `routePrefix`, and the optional `organization:created` listener is wired when `autoCreateDefaultSite` is on. This file is the single integration point — every consumer of the package builds its descriptor through this one function.
|
||||
|
||||
The lifecycle is the canonical 4-phase shape: validate-at-construction, build-services in `onInit`, mount-routes in `onReady`, drop-listener in `onClose`. Each phase fails fast with a typed `SiteError` carrying a `SITE.*` code so misconfigurations are visible at registry intake rather than deferred to the first request.
|
||||
|
||||
## Features
|
||||
|
||||
- Zod-validated option boundary — `SITE.INVALID_OPTIONS` on bad config.
|
||||
- Resolves `db` from `ServiceRegistry`; throws `SITE.SERVICE_NOT_AVAILABLE` when missing.
|
||||
- Constructs and registers `siteService`, `domainResolver`, `domainResolverMiddleware`.
|
||||
- Optional `organization:created` listener for default-site auto-bootstrap, with `SITE.BOOTSTRAP_FAILED` event emission on error and the `site.bootstrap_failed_total` counter incremented on each failure.
|
||||
- Route mounting under `config.routePrefix` (defaults to `/api`) with prefix-collision detection via `SITE.ROUTE_PREFIX_COLLISION`.
|
||||
- `optionalDependencies: ["database", "auth", "events"]` so orchestrators topo-sort the site plugin after siblings without making them mandatory.
|
||||
- Emits `site:initialized` and `site:ready` lifecycle events.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { createSitePlugin } from "@suaveplan/api-plugin-site";
|
||||
|
||||
registry.register(createSitePlugin({ maxSitesPerOrg: 25 }));
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { createSitePlugin } from "@suaveplan/api-plugin-site";
|
||||
|
||||
const plugin = createSitePlugin({
|
||||
routePrefix: "/v1",
|
||||
autoCreateDefaultSite: true,
|
||||
defaultDomainPattern: "{slug}.acme.com",
|
||||
enableDomainResolution: true,
|
||||
});
|
||||
|
||||
await registry.register(plugin, { db: surrealAdapter, app: openApiHono });
|
||||
await registry.start();
|
||||
|
||||
// Downstream plugin can now resolve the service:
|
||||
const siteService = ctx.getService("siteService")!;
|
||||
await siteService.create({
|
||||
organization_id: "organization:abc",
|
||||
name: "Customer Site",
|
||||
domains: ["customer.acme.com"],
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `createSitePlugin(options?: CreateSitePluginOptions): PluginDescriptor<SitePluginConfig>`
|
||||
- `type CreateSitePluginOptions = SitePluginOptionsInput`
|
||||
- The descriptor name is `"site"`, version `"0.1.0"`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Service handles are stored in closure-scoped variables and bound via a private `bind` helper so the `onReady` hook can reuse the same instances constructed in `onInit`. The `mustService` / `mustResolver` guards trip when an orchestrator runs `onReady` before `onInit` (which the canonical registry never does, but tests / misuse can).
|
||||
- The plugin treats the host event bus as `EventBusLike<SiteEventMap>` so the cumulative event typing is enforced inside the plugin without bleeding into the global `EventBusLike` declaration on the host.
|
||||
- Route mounting is keyed by detecting any existing path starting with `${prefix}/sites/`; a collision raises `SITE.ROUTE_PREFIX_COLLISION` so two plugins can't silently overwrite each other.
|
||||
- `enableDomainResolution: false` suppresses ONLY the public router (which contains the resolve endpoint); the private router always mounts so CRUD remains usable even when public lookup is disabled.
|
||||
Reference in New Issue
Block a user