# API index

Package entry points with container accessors for every service.

Battery interfaces live in `core/<b>` with the `Register`/`Open` registry, each adapter lives in its own module at `adapters/<b>/<a>` with a `Register()` call wiring it in, and SDK-free helpers live in `shared/*`. Import the `core` interface plus the adapter modules you need and resolve through `container`. The `dsl/*` packages are internal-only: runtime code must not import the compiler.

## Construct and resolve

Construction is always config plus container. Each service resolves on first use and caches the result; on error the cached state clears so the next call retries.

```go
import (
    "github.com/zenta-dev/zever/config"
    "github.com/zenta-dev/zever/container"
)

c := container.New(config.Default())
db, err := c.DB()
if err != nil {
    return err
}
q, err := c.Queue()
if err != nil {
    return err
}
d, err := c.Job() // d shares the resolved queue instance
if err != nil {
    return err
}
```

`container.New(nil)` is valid: an untouched container closes cleanly without opening anything. `Job()` has no registry of its own; it builds a `*job.Dispatcher` over the already-resolved `Queue`. `Scheduler()` injects that dispatcher, so the scheduler shares the same `Queue` connection instead of opening a redundant one. Resolving `Scheduler()` therefore resolves `Job()` and, transitively, `Queue` as a side effect.

`GRPCClient(target, opts...)` builds `*grpc.ClientConn` connections through the `shared/grpcclient` helper (round-robin LB, retry policy, TLS, static resolver) and caches one conn per target string; the conns close with the container.

## Close

```go
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := c.Close(ctx); err != nil {
    var te *container.CloseTimeoutError
    var pe *container.ClosePanicError
    _ = te
    _ = pe
    return err
}
```

Close shuts down only resolved services, dependents first, joining per-service close failures via `errors.Join`.

## Core packages

| Package | Role |
|---|---|
| `config` | layered typed config, defaults/file/env (own module) |
| `container` | sole resolver, lazy accessors, ordered close (own module) |
| `orm` | generics typed builder over `core/db` (own module) |
| `dsl` | `.zen` compiler frontend, compile time only (own module) |
| `core/middleware` | shared HTTP middleware (own module) |
| `cmd/zever` | flags-only toolkit shell (own module) |
| `shared/*` | SDK-free helpers (`codec`, `redisclient`, `redisopt`, `s3opts`, `retry`, `lrucache`, ...), one module each |
| `shared/grpcclient` | gRPC client constructor (`New(ctx, target, opts...)`: LB, retry, TLS, static resolver); no registry, resolved via `GRPCClient(target, opts...)` |

## Service packages and accessors

| Package | Accessor | Notes |
|---|---|---|
| `core/agent` | `Agent()` | `*agent.Loop` |
| `core/ai` | `AI()` | |
| `core/analytics` | `Analytics()` | |
| `core/auth` | `Auth()` | |
| `core/billing` | `Billing()` | |
| `core/cache` | `Cache()` | leaf dependency, closed last |
| `core/cdn` | `CDN()` | |
| `core/crypto` | `Crypto()` | |
| `core/db` | `DB()` | plus `Transactor()` helper |
| `core/document` | `Document()` | |
| `core/eventbus` | `EventBus()` (`Eventbus()` alias) | |
| `core/flag` | `Flag()` | |
| `core/geo` | `Geo()` | |
| `grpc` | `GRPC(opts...)` | lazy `*grpc.Server` singleton, no registry |
| `core/i18n` | `I18n()` | |
| `core/idempotency` | `Idempotency()` | |
| `core/job` | `Job()` | `*job.Dispatcher` over resolved `Queue` |
| `core/lock` | `Lock()` | |
| `core/log` | `Log()` | |
| `core/mailer` | `Mailer()` | |
| `core/media` | `Media()` | |
| `core/notification` | `Notification()` | |
| `core/observability` | `Observability()` | |
| `core/outbox` | `Outbox()` | |
| `core/password` | `Password()` | |
| `core/payment` | `Payment()` | |
| `core/permission` | `Permission()` | |
| `core/queue` | `Queue()` | leaf dependency, closed last |
| `core/rag` | `RAG()` | `*rag.Engine` |
| `core/ratelimit` | `RateLimit()` (`Ratelimit()` alias) | |
| `core/resilience` | `Resilience()` | |
| `core/router` | `Router()` | |
| `core/scheduler` | `Scheduler()` | shares `Queue` via `Job()`, closed first |
| `core/search` | `Search()` | |
| `core/secrets` | `Secrets()` | |
| `core/session` | `Session()` | |
| `core/storage` | `Storage()` | |
| `core/tenant` | `Tenant()` | |
| `core/vectorstore` | `VectorStore()` | |
| `core/webhook` | `Webhook()` | |
| `core/workflow` | `Workflow()` | |

## Close shapes

| Shape | Used by | Semantics |
|---|---|---|
| `Close(ctx)` | pooled or network-backed services that may block (`db`, `cache`, `storage`, `lock`, `container` itself) | context-bounded shutdown |
| `Close()` | lightweight handles, iterators, statements, instant-close in-memory adapters (`auth`, `queue`, `session`, `payment`, `eventbus.Pusher`, `ratelimit.Limiter`, `db.Rows`, `db.Stmt`) | instant close |
| `Stop()` | scheduler only | cron lifecycle stop |

Probing (`closeAny`) tries `Close(context.Context) error`, then `Close() error`, then `Stop() error`, then `Shutdown(context.Context) error` (observability providers flush buffered spans/metrics), then no-op nil (`*job.Dispatcher` has no shutdown method). Crypto, log, password, permission, and router declare no Close/Stop/Shutdown and probe as no-op nil. Callers never guess: the probe picks the shape.

Close order:

```text
scheduler, job        dependents holding a queue ref, first
snapshots             everything without explicit ordering
cache, queue          leaf dependencies, last
db, registry pools    shared pools, after every borrower (no use-after-close)
grpcServer            independent GracefulStop/Stop, bounded by ctx
grpc clients          independent, one conn per target, closed with the container
```

Per-service bound is 5s only when the parent context carries no deadline; otherwise the parent deadline bounds each wait. Shared instances close once (pointer-identity dedup with a `keepAlive` set for the duration). Failures join via `errors.Join`; panics become `*ClosePanicError`, timeouts become `*CloseTimeoutError`. Error values name the service only, never resolved values. `Close` never opens anything: untouched services stay untouched.

## Production notes

- Start from `config.Default()` + `container.New`, then per-service accessors; no globals, no `init()` wiring.
- Keep to documented interfaces; new behavior means new interfaces, never new methods on public ones.
- Pass a parent deadline to `Close` in servers so shutdown is bounded end to end; inspect `CloseTimeoutError` / `ClosePanicError` with `errors.As`.
- Goroutine-safe types document their exit path; resolve the in-memory subset and `Close` it in tests so `goleak` stays clean.

## Troubleshooting

- **Close hangs**: parent context has no deadline and a service blocks; pass a timeout context (per-service bound is 5s only without one).
- **Close reports `CloseTimeoutError`**: a service outlived its bound. Check which service is named, then its backing store health.
- **Close reports `ClosePanicError`**: a service panicked during shutdown. Fix the service; the panic value is captured, not re-thrown.
- **Accessor keeps failing**: cached state clears on error, so each call retries fresh. Persistent failure means config or backend, not the container; check `Validate` and connectivity.

## Related

- [Adapters matrix](https://zenta-dev.github.io/zever/reference/adapters-matrix/) for adapter choice per service.
- [Config reference](https://zenta-dev.github.io/zever/reference/config/) for values behind accessors.
- [CLI reference](https://zenta-dev.github.io/zever/reference/cli/) for runtime commands over the container.
