Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
# `loaders` — per-request DataLoader scope
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`loaders` defines the per-request DataLoader scope the engine creates
around every incoming GraphQL operation. Two concurrent requests
receive distinct loader instances; the cache never leaks across
request boundaries even though both requests draw from the same set of
loader factories registered on the abstract `GraphqlRegistry`.
The module is deliberately the thinnest possible wrapper around the
`LoaderFactory.create()` surface owned by `@suaveplan/api-types/graphql`.
The engine calls `createRequestLoaderScope()` once per request; resolvers
that need a loader call `scope.get(name, factory)`; the engine disposes
the scope at request end.
## Features
- One scope per request — distinct cache per request guaranteed.
- Loader lazily instantiated on first `get(name, factory)` call;
subsequent calls reuse the instance.
- `dispose()` blocks subsequent `get()` calls so a buggy late resolver
cannot resurrect a freed cache.
- Zero runtime dependencies — pure JS, fits in ~40 lines.
## Usage: Basic
```ts
import { createRequestLoaderScope } from "@suaveplan/api-graphql-apollo/loaders";
const scope = createRequestLoaderScope();
const userLoader = scope.get("users", userLoaderFactory);
const user = await userLoader.load("u_42");
scope.dispose();
```
## Usage: Advanced
Wire the scope into a resolver context object so resolvers consume
loaders by name through the request context:
```ts
import { createRequestLoaderScope } from "@suaveplan/api-graphql-apollo/loaders";
function makeContext(): RequestContext {
const scope = createRequestLoaderScope();
return {
loaders: {
users: () => scope.get("users", userLoaderFactory),
orders: () => scope.get("orders", orderLoaderFactory),
},
finalize: () => scope.dispose(),
} as unknown as RequestContext;
}
```
## API Reference
- `RequestLoaderScope`:
- `get<TKey, TValue>(name, factory): { load }`
- `dispose(): void`
- `size(): number`
- `createRequestLoaderScope(): RequestLoaderScope`.
## Implementation Notes
The scope is a closure over a `Map<string, LoaderInstance>` plus a
`disposed` boolean. Throwing on `get` after `dispose` surfaces the
late-resolver bug at the call site instead of silently producing
inconsistent reads. The size accessor is provided so OTel histograms
can record loader-fanout per request.