Elysia アダプター
@inferdi/elysia は Elysia v1 のプラグインです。スコープドモードでは、1 つのリクエストスコープを作成し、それを Elysia コンテキスト上で公開し、ユーザーのエラーハンドラーが利用できるように保持し、onAfterResponse から破棄します。
インストール
pnpm add @inferdi/inferdi @inferdi/elysia elysiaimport { Elysia } from 'elysia'
import { Container } from '@inferdi/inferdi'
import { inferdiElysia } from '@inferdi/elysia'リクエストスコープ
type RequestContext = {
requestId: string
userId?: string
}
class Users {
constructor(readonly request: RequestContext) {}
profile(id: string) {
return { id, userId: this.request.userId }
}
}
const root = new Container()
.declareScopeInputs<{ request: RequestContext }>()
.registerClass('users', Users, ['request'], 'scoped')
const app = new Elysia()
.use(inferdiElysia({
container: root,
createScope: (_root, { request }) => root.createScope({
request: {
requestId: crypto.randomUUID(),
userId: request.headers.get('x-user-id') ?? undefined
}
})
}))
.get('/users/:id', ({ di, params }) =>
di.get('users').profile(params.id),
)カスタムのコンテキストキーの場合:
const app = new Elysia()
.use(inferdiElysia({
container: root,
key: 'container',
createScope: (_root, { request }) => root.createScope({
request: {
requestId: crypto.randomUUID(),
userId: request.headers.get('x-user-id') ?? undefined
}
})
}))
.get('/users/:id', ({ container, params }) =>
container.get('users').profile(params.id),
)ルートは、型付けされた Elysia チェーン内で .use(inferdiElysia(...)) の後に登録する必要があります。
オプション
| オプション | デフォルト | 説明 |
|---|---|---|
container | 必須 | ルートコンテナ。 |
key | 'di' | Elysia のコンテキストキー。 |
scopePerRequest | true | ルート専用モードにするには false を設定します。 |
createScope | root.createScope() | カスタムのリクエストスコープ作成。 |
setupScope | なし | スコープ作成後に追加の初期化を行います。 |
setupValidatedScope | なし | Elysia のバリデーション後に追加の初期化を行います。 |
disposeScope | scope.dispose() | カスタムの破棄。 |
autoDispose | true | false または false を返す述語は所有権を移譲します。 |
onDisposeError | console.error | クリーンアップ失敗のシンク。 |
ルート専用モード
const app = new Elysia()
.use(inferdiElysia({
container: root,
scopePerRequest: false,
}))
.get('/health', ({ di }) => di.get('health').check())ルート専用モードはルートコンテナを公開し、リクエストスコープのライフサイクルフックをインストールしません。スコープド専用のオプションは静的に拒否されます。
ライフサイクルに関する注意
クリーンアップはライフサイクル上 onAfterResponse にバインドされています。Elysia がそのフックに到達しなかった場合、アダプターはリクエストスコープが保持するリソースを解放できません。リクエストごとの記録は弱参照で保持されますが、リソースの破棄にはライフサイクルフックの実行が必要です。
バリデーション前に必要な値には setupScope を使用してください。バリデーション済みのボディ、クエリ、パラメータ、ヘッダー、または Cookie から導出される値には setupValidatedScope を使用してください。
ストリーミング
Elysia は、ストリームがドレインする前にストリーミングの Response を生成することがあります。スコープドサービスがルートの戻りの後に使用される場合は、skipInferdiDispose(context) を呼び出し、スコープを自分で破棄してください。
import { skipInferdiDispose } from '@inferdi/elysia'
app.get('/events', (context) => {
skipInferdiDispose(context)
const scope = context.di
const events = scope.get('events')
return new Response(new ReadableStream({
async start(controller) {
const encoder = new TextEncoder()
try {
for await (const event of events.subscribe()) {
controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`))
}
} finally {
await scope.dispose()
}
},
}))
})skipInferdiDispose は成功したクリーンアップのみを抑制します。エラーパスでは、それでも破棄します。
