> ## Documentation Index
> Fetch the complete documentation index at: https://pulian.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# @hile/context

> Propagate request/work-unit context through async calls, models, micro messages, queues, and logger bindings.

# @hile/context

Propagate request/work-unit context through async calls, models, micro messages, queues, and logger bindings.

## Choose This Package When

| User asks for                                                      | Use             | Also read                   |
| ------------------------------------------------------------------ | --------------- | --------------------------- |
| Propagate request id, tenant id, logger bindings, or micro context | `@hile/context` | `packages/model-context.md` |

## Use When

Use `@hile/model` for reusable business logic and `@hile/context` for request/work-unit context that should flow through async calls, micro messages, and queue jobs.

## Do Not Use When

* Do not put business logic only in controllers when it will be reused by jobs, pages, or message handlers.
* Do not add fixed business fields to `@hile/context`; each app owns its context shape.

## Install

```bash theme={null}
pnpm add @hile/model @hile/context
```

## Imports

```ts theme={null}
import { defineModel, loadModel } from '@hile/model'
import { contextHttp, contextModel, getContext, requireContext, runWithContext } from '@hile/context'
```

## Copy-Paste Example

```ts theme={null}
import { defineModel } from '@hile/model'

export default defineModel(async (input: { name: string }) => {
  return { greeting: `Hello ${input.name}` }
})
```

Use it:

```ts theme={null}
const result = await loadModel(greetModel, { name: 'Ada' })
```

## More Examples

```ts theme={null}
import { defineModel } from '@hile/model'
import typeormService from '@hile/typeorm'

export const findUser = defineModel({
  services: [typeormService] as const,
  pipelines: [
    async (ctx, next) => {
      if (!ctx.args.userId) throw new Error('userId is required')
      await next()
    },
  ],
  async main([ds], input: { userId: string }) {
    return ds.getRepository(User).findOneBy({ id: input.userId })
  },
})
```

Context in HTTP:

```ts theme={null}
http.use(contextHttp({
  read: (ctx) => ({ requestId: String(ctx.headers['x-request-id'] ?? crypto.randomUUID()) }),
  write: (context, ctx) => ctx.set('x-request-id', String(context.requestId ?? '')),
}))
```

Context in model pipeline:

```ts theme={null}
const withTenant = contextModel<{ tenantId: string }>({
  read: (input) => ({ tenantId: input.tenantId }),
})
```

## Runtime And Lifecycle Notes

* `loadModel(model, input)` rejects if the first argument was not created by `defineModel()`.
* Model input must be an object.
* Services are loaded in the order of the `services` tuple.
* Pipeline middleware follows Koa-style `await next()`.
* The terminal model result is stored in `ctx.state.result` and returned by `loadModel()`.
* `runWithContext()` merges with parent context by default; pass `{ merge: false }` to replace.
* `getContext()` returns a frozen shallow snapshot.
* `requireContext(keys)` throws when selected keys are missing.

## Anti-Patterns

* Passing primitives to `loadModel()`.
* Mutating context snapshots.
* Logging whole context objects by default.
* Assuming context propagation changes business payloads; it should stay in metadata or async storage.

## Verification Checklist

* Models export `defineModel(...)` results.
* Controllers and pages call `loadModel(model, objectInput)`.
* Pipeline middleware writes derived state to `ctx.state`.
* Context keys are app-defined and JSON-serializable when crossing process boundaries.

## Package-Local AI Guide

This package also ships `AI.md` in npm so agents can read accurate examples after installation.
