@vielzeug/codex 3.1.1 → 26.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +1 -1
  2. package/data/catalog.json +166 -84
  3. package/data/llms-full.txt +3492 -1583
  4. package/data/llms.txt +9 -7
  5. package/data/manifest.json +1 -1
  6. package/data/packages/arsenal.json +40 -16
  7. package/data/packages/assay.json +12 -20
  8. package/data/packages/clockwork.json +31 -28
  9. package/data/packages/codex.json +5 -5
  10. package/data/packages/coins.json +4 -4
  11. package/data/packages/conduit.json +33 -34
  12. package/data/packages/courier.json +18 -17
  13. package/data/packages/dnd.json +11 -11
  14. package/data/packages/familiar.json +27 -6
  15. package/data/packages/flux.json +11 -8
  16. package/data/packages/focus.json +17 -7
  17. package/data/packages/forge.json +4 -4
  18. package/data/packages/gesture.json +11 -5
  19. package/data/packages/herald.json +16 -17
  20. package/data/packages/illusionist.json +5 -5
  21. package/data/packages/keymap.json +16 -12
  22. package/data/packages/ledger.json +26 -26
  23. package/data/packages/lingua.json +4 -4
  24. package/data/packages/mesh.json +30 -32
  25. package/data/packages/necromancer.json +7 -6
  26. package/data/packages/orbit.json +11 -10
  27. package/data/packages/ore.json +6 -5
  28. package/data/packages/postmaster.json +26 -26
  29. package/data/packages/prism.json +50 -42
  30. package/data/packages/pulse.json +34 -34
  31. package/data/packages/refine.json +7 -5
  32. package/data/packages/ripple.json +4 -4
  33. package/data/packages/rune.json +9 -9
  34. package/data/packages/sandbox.json +4 -4
  35. package/data/packages/scout.json +17 -11
  36. package/data/packages/scroll.json +14 -14
  37. package/data/packages/sentinel.json +26 -15
  38. package/data/packages/sigil.json +6 -6
  39. package/data/packages/sourcerer.json +4 -4
  40. package/data/packages/spell.json +31 -36
  41. package/data/packages/tandem.json +29 -0
  42. package/data/packages/tavern.json +23 -0
  43. package/data/packages/tempo.json +45 -43
  44. package/data/packages/vault.json +15 -25
  45. package/data/packages/ward.json +27 -30
  46. package/data/packages/wayfinder.json +34 -27
  47. package/data/refine.json +987 -134
  48. package/data/search.json +341 -306
  49. package/dist/http.js +2 -2
  50. package/dist/http.js.map +1 -1
  51. package/dist/index.d.ts +3 -4
  52. package/dist/index.js +3 -4
  53. package/dist/index.js.map +1 -1
  54. package/dist/refine.d.ts +1 -1
  55. package/dist/refine.js +1 -1
  56. package/dist/server.d.ts +1 -1
  57. package/dist/server.js +1 -1
  58. package/dist/tools/refine.js +1 -1
  59. package/package.json +5 -12
  60. package/skills/vielzeug/SKILL.md +57 -55
  61. package/dist/advanced.d.ts +0 -12
  62. package/dist/advanced.js +0 -13
  63. package/dist/advanced.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  {
2
- "apiSource": "export { createContainer } from './container.js';\nexport {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';\nexport type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';\nexport { disposalSignalToken, factoryProvider, scope, token, valueProvider } from './types.js';\n",
2
+ "apiSource": "export { createContainer } from './container.js';\nexport {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n} from './errors.js';\nexport type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';\nexport { disposalSignalToken, factoryProvider, token, valueProvider } from './types.js';\n",
3
3
  "docs": {
4
- "index": "---\ntitle: Conduit — Dependency Injection for TypeScript\ndescription: Dependency-first asynchronous dependency injection with typed tokens, lifecycle scopes, startup validation, and deterministic disposal.\npackage: conduit\ncategory: infrastructure\nkeywords: [dependency injection, container, token, lifecycle, scope]\nexports: [createContainer, valueProvider, factoryProvider, disposalSignalToken, token, scope]\nrelated: [courier, vault, rune]\nenvironments: [browser, node, ssr, deno]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"conduit\" />\n\n## Why Conduit?\n\nConduit makes service wiring explicit. Typed builders create immutable providers, static graphs are validated at construction, and dependency tuples drive creation and disposal. Resolve one root token or a typed composition map.\n\n```ts\n// Before\nconst service = createService(createApi(config), logger);\n\n// After\nconst container = createContainer([\n valueProvider(Config, config),\n factoryProvider(Api, [Config], (config) => createApi(config)),\n factoryProvider(Service, [Api, Logger], (api, logger) => createService(api, logger)),\n]);\nconst services = await container.resolve({ service: Service });\n```\n\n| Feature | Conduit | Inversify | tsyringe |\n| --- | --- | --- | --- |\n| Dependencies | Explicit token tuples | Decorators/runtime metadata | Decorators/runtime metadata |\n| Async factories | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Partial | Partial |\n| Lifecycle scopes | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> |\n| Runtime dependencies | 0 | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n\n<div class=\"decision-callout\">\n\n**Use Conduit when** application services need explicit wiring and owned lifecycle cleanup.\n\n**Consider direct imports when** dependencies are static, small, and need no replacement or disposal boundary.\n\n</div>\n\n## Installation\n\n::: code-group\n\n```sh [pnpm]\npnpm add @vielzeug/conduit\n```\n\n```sh [npm]\nnpm install @vielzeug/conduit\n```\n\n```sh [yarn]\nyarn add @vielzeug/conduit\n```\n\n:::\n\n## Quick Start\n\n```ts\nimport { createContainer, factoryProvider, token, valueProvider } from '@vielzeug/conduit';\n\nconst Config = token<{ baseUrl: string }>('Config');\nconst Client = token<{ url: string }>('Client');\n\nconst container = createContainer([\n valueProvider(Config, { baseUrl: '/api' }),\n factoryProvider(Client, [Config], (config) => ({ url: `${config.baseUrl}/users` })),\n]);\n\nconst services = await container.resolve({ client: Client });\nconsole.log(services.client);\nawait container.dispose();\n```\n\n## Features\n\n<div class=\"features-grid\">\n\n- **`token`**: typed dependency identity\n- **`valueProvider` / `factoryProvider`**: token-safe immutable registrations\n- **`createContainer`**: validated provider graph\n- **`resolve`**: direct service or typed composition map\n- **`scope`**: explicit request and job ownership\n- **`dispose`**: in-flight-safe resource cleanup\n\n</div>\n\n## Documentation\n\n<div class=\"doc-links\">\n\n- [Usage Guide](./usage.md)\n- [API Reference](./api.md)\n- [Examples](./examples.md)\n- [Migration Guide](./migration.md)\n\n</div>\n\n## See Also\n\n<div class=\"see-also\">\n\n- [Courier](/courier/) — inject HTTP clients into application services.\n- [Vault](/vault/) — inject persistence adapters with scoped ownership.\n- [Rune](/rune/) — provide application logging services.\n\n</div>\n\n<!-- markdownlint-enable MD025 MD033 MD060 -->\n",
5
- "api": "---\ntitle: Conduit — API Reference\ndescription: Reference for Conduit tokens, immutable provider arrays, dependency-first factories, scopes, composition-root resolution, and lifecycle disposal.\n---\n\n[[toc]]\n\n## API Overview\n\n| Symbol | Purpose | Mode | Common gotcha |\n| --- | --- | --- | --- |\n| `token` | Create typed dependency identity | Sync | Same description does not mean same token |\n| `scope` | Create named lifecycle identity | Sync | Must match factory lifetime |\n| `createContainer` | Build root container from an immutable provider array | Sync | Validates the full graph at construction |\n| `valueProvider` / `factoryProvider` | Build type-safe immutable registrations | Sync | Prefer over unannotated object literals |\n| `Provider` | Value or factory registration type | Sync | One local registration per token |\n| `has` | Check registration visibility | Sync | Walks parent containers |\n| `resolve` | Resolve one token or typed composition-root map | Async | Undeclared map tokens fail at resolution |\n| `createScope` | Create child owner | Sync | Named scope required for scoped factories |\n| `dispose` | Release owned resources | Async | May throw `ConduitDisposeError` after cleanup attempts |\n\n## Package Entry Point\n\n| Import | Purpose |\n| --- | --- |\n| `@vielzeug/conduit` | Complete Conduit API |\n\n## Tokens and Scopes\n\n```ts\ntoken<T>(description: string): Token<T>\nscope(name: string): ScopeToken\n```\n\nTokens and scopes are unique symbols. Descriptions exist only for diagnostics. `disposalSignalToken` is a built-in `Token<AbortSignal>` that resolves to the owning root, transient-requesting container, or named scope signal.\n\n## Container\n\n```ts\ncreateContainer(providers: readonly Provider[], options?: { name?: string }): Container\n```\n\n`providers` is an immutable array of value and factory providers. Construction validates the entire graph — duplicate tokens, missing dependencies, circular factory tuples, and singletons depending on scoped factories all fail fast.\n\n### Providers\n\n```ts\ntype Provider<T, Dependencies> = ValueProvider<T> | FactoryProvider<T, Dependencies>;\n\nvalueProvider<T>(token: Token<T>, value: T, options?: ValueOptions<T>): ValueProvider<T>;\nfactoryProvider<T, Dependencies>(\n token: Token<T>,\n dependencies: Dependencies,\n factory: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options?: FactoryOptions<T>,\n): FactoryProvider<T, Dependencies>;\n```\n\nUse builders for token-driven value and dependency inference:\n\n```ts\nvalueProvider(Config, { baseUrl: '/api' }, { dispose: (value) => value.close() });\nfactoryProvider(Service, [Api, Logger], (api, logger) => createService(api, logger), {\n lifetime: 'singleton',\n dispose: (value) => value.dispose(),\n});\n```\n\nExplicit `ValueProvider<T>` and `FactoryProvider<T, Dependencies>` annotations remain available for reusable provider declarations. Avoid unannotated provider object literals because TypeScript cannot contextually infer one factory parameter from another object property.\n\n`dependencies` is copied at construction and drives creation, validation, cycle detection, and teardown order. Factories may return a value or promise.\n\n`lifetime` accepts `'singleton'` (default), `'transient'`, or a `ScopeToken`. Singletons cannot capture transient or scoped factories. Named-scope factories may depend on singletons, transients, or factories in the same named scope.\n\n```ts\ntype FactoryProvider<T, Dependencies> = {\n token: Token<T>;\n dependencies: Dependencies;\n factory: (...values: InferTokens<Dependencies>) => Promise<T> | T;\n dispose?: (value: T) => void | Promise<void>;\n lifetime?: 'singleton' | 'transient' | ScopeToken;\n};\n```\n\n### has\n\n```ts\ncontainer.has(token): boolean\n```\n\nChecks local and parent registrations without creating a factory result.\n\n### resolve\n\n```ts\ncontainer.resolve(token: Token<T>): Promise<T>\ncontainer.resolve(map: ServiceMap): Promise<InferServices<typeof map>>\n```\n\nResolves one typed token or a service object at a composition root. Map keys are defined as own properties, including `__proto__`, without changing the result prototype. Missing top-level tokens fail during resolution.\n\n```ts\nconst services = await container.resolve({ client: Client, config: Config });\n```\n\nSingleton resolutions deduplicate concurrent callers and cache successful values. A rejected creation attempt is evicted so a later resolution can retry.\n\n### createScope\n\n```ts\ncontainer.createScope(\n scope?: ScopeToken,\n options?: { name?: string; providers?: readonly Provider[] },\n): Container\n```\n\nA matching scope owns resources registered with its `ScopeToken` lifetime. Immutable local providers may shadow parent registrations for request or test overrides. Disposing a parent also disposes active children.\n\n### dispose\n\n```ts\ncontainer.dispose(): Promise<void>\ncontainer.disposalSignal: AbortSignal\ncontainer.disposed: boolean\n```\n\nDisposal blocks new work, aborts `disposalSignal`, disposes active child scopes, waits for complete in-flight creation and late-result cleanup, then disposes owned resources in reverse creation order. Cleanup failures are aggregated in the readonly `ConduitDisposeError.errors` array.\n\n## Types\n\n```ts\ntype Token<T = unknown> = symbol;\ntype ScopeToken = symbol;\ntype Lifetime = 'singleton' | 'transient' | ScopeToken;\n\ntype InferTokens<T extends readonly Token<unknown>[]> = {\n [K in keyof T]: T[K] extends Token<infer Value> ? Value : never;\n};\n\ntype ServiceMap = { readonly [key: string]: Token<unknown> };\n\ntype InferServices<M extends ServiceMap> = {\n readonly [K in keyof M]: M[K] extends Token<infer Value> ? Value : never;\n};\n\ninterface Container {\n createScope(scope?: ScopeToken, options?: { name?: string; providers?: readonly Provider[] }): Container;\n readonly disposalSignal: AbortSignal;\n dispose(): Promise<void>;\n readonly disposed: boolean;\n has<T>(token: Token<T>): boolean;\n readonly name: string;\n resolve<T>(token: Token<T>): Promise<T>;\n resolve<M extends ServiceMap>(map: M): Promise<InferServices<M>>;\n [Symbol.asyncDispose](): Promise<void>;\n}\n```\n\n## Errors\n\n- `ConduitError` — base class; use `instanceof ConduitError` to narrow package errors.\n- `ConduitProviderNotFoundError` — dependency has no registration.\n- `ConduitCircularDependencyError` — static factory tuple graph contains a cycle.\n- `ConduitDuplicateRegistrationError` — token registered twice in one container.\n- `ConduitScopedResolutionError` — scoped factory resolved without matching scope, or a singleton depends on a scoped factory.\n- `ConduitDisposedError` — operation attempted after disposal began.\n- `ConduitDisposeError` — one or more cleanup hooks failed.\n",
6
- "usage": "---\ntitle: Conduit — Usage Guide\ndescription: Register an immutable provider array, resolve a typed service object at composition roots, create scopes, and dispose owned resources.\n---\n\n[[toc]]\n\n## Basic Usage\n\nCreate tokens once, build a container from an immutable provider array, then resolve a typed service object at your composition root.\n\n```ts\nimport { createContainer, factoryProvider, token, valueProvider } from '@vielzeug/conduit';\n\nconst Config = token<{ baseUrl: string }>('Config');\nconst Client = token<{ url: string }>('Client');\n\nconst container = createContainer([\n valueProvider(Config, { baseUrl: '/api' }),\n factoryProvider(Client, [Config], (config) => ({ url: `${config.baseUrl}/users` })),\n]);\n\nconst services = await container.resolve({ config: Config, client: Client });\nconsole.log(services.client);\nawait container.dispose();\n```\n\n## Define Dependencies\n\nFactory `dependencies` tuples are authoritative. Conduit resolves tuple values in order, validates every edge at construction, and disposes created services in reverse dependency order.\n\n```ts\nconst Logger = token<{ info(message: string): void }>('Logger');\nconst Api = token<{ get(path: string): Promise<unknown> }>('Api');\nconst Service = token<{ load(): Promise<unknown> }>('Service');\n\nconst container = createContainer([\n valueProvider(Logger, { info: (message) => console.log(message) }),\n factoryProvider(Api, [], () => ({ get: async (path: string) => fetch(path) })),\n factoryProvider(Service, [Api, Logger], (api, logger) => ({\n async load() {\n logger.info('Loading data');\n return api.get('/data');\n },\n })),\n]);\n```\n\n## Choose Lifetimes\n\nFactories are singletons by default and cached on the registering container. Concurrent singleton resolutions share one in-flight attempt; a rejected attempt is evicted for retry. Use `'transient'` for one value per resolution or a `ScopeToken` for request, job, or test ownership. Singletons cannot depend on transient or scoped factories, and one named scope cannot depend on another.\n\n```ts\nimport { createContainer, factoryProvider, scope, token } from '@vielzeug/conduit';\n\nconst Request = scope('request');\nconst Session = token<{ id: string }>('Session');\n\nconst root = createContainer([\n factoryProvider(Session, [], () => ({ id: crypto.randomUUID() }), { lifetime: Request }),\n]);\n```\n\nFactory dependency tuples are copied at construction, so later caller mutation cannot change Conduit's graph. Add `disposalSignalToken` to a factory tuple when work must observe its owning container or scope cancellation.\n\n## Create Named Scopes\n\nUse a scope token when a resource belongs to a request, job, or test lifecycle. Pass immutable local providers through `createScope()` options to override parent registrations.\n\n```ts\nconst TraceId = token<string>('TraceId');\nconst request = root.createScope(Request, {\n providers: [valueProvider(TraceId, 'request-trace')],\n});\nconst services = await request.resolve({ session: Session });\nawait request.dispose();\nawait root.dispose();\n```\n\nResolving `Session` from `root` throws `ConduitScopedResolutionError` because no matching scope owns it.\n\n## Resolve at Composition Roots\n\nResolve a map at composition roots to receive an explicitly typed service object. Direct `resolve(token)` remains available for one root service and focused tests; avoid scattering service-locator calls through application code.\n\n```ts\nconst client = await container.resolve(Client);\nconst services = await container.resolve({ client: Client, config: Config });\n// Both results are fully typed.\n```\n\n## Dispose Resources\n\n`dispose()` rejects new work, aborts `disposalSignal`, disposes child scopes, waits for in-flight creation, then releases services in reverse creation order. A factory that finishes after disposal starts is immediately cleaned up and its resolver receives `ConduitDisposedError`.\n\n```ts\nawait container.dispose();\n```\n\n`ConduitDisposeError.errors` contains every cleanup failure after Conduit attempts all hooks, including cleanup from in-flight factories and child scopes.\n\n## Testing\n\nBuild a container per test with explicit values for external dependencies. Because the provider array is immutable and validated at construction, a misconfigured test container fails immediately.\n\n```ts\nconst Clock = token<{ now(): number }>('Clock');\nconst Service = token<{ timestamp: number }>('Service');\n\nconst container = createContainer([\n valueProvider(Clock, { now: () => 123 }),\n factoryProvider(Service, [Clock], (clock) => ({ timestamp: clock.now() })),\n]);\n\nconst services = await container.resolve({ service: Service });\nexpect(services.service).toEqual({ timestamp: 123 });\nawait container.dispose();\n```\n\n## Best Practices\n\n- Create tokens at module scope.\n- Use `valueProvider()` and `factoryProvider()` so tokens, values, dependencies, and disposers remain type-safe.\n- Declare every factory dependency in its tuple.\n- Keep factories focused on one service.\n- Use scopes for request/job-owned resources.\n- Resolve once at a composition root; pass the typed service object downstream.\n- Dispose every scope and root container.\n- Keep optional application fallback policy outside Conduit.\n- Use `await using container = createContainer([...])` when lexical async disposal fits application lifetime.\n",
7
- "examples": "---\ntitle: Conduit — Examples\ndescription: Immutable provider array recipes.\n---\n\n## Examples\n\n- [Basic setup](./examples/basic-setup.md)\n- [Static async providers](./examples/async-providers.md)\n- [Singleton lifetime](./examples/lifetimes.md)\n- [Named scopes](./examples/named-scopes.md)\n- [Disposal lifecycle](./examples/dispose-lifecycle.md)\n- [Startup validation](./examples/startup-hardening.md)\n"
4
+ "index": "---\ntitle: 'Conduit: Dependency Injection for TypeScript'\ndescription: Dependency-first asynchronous dependency injection with typed tokens, child-container scoping, startup validation, and deterministic disposal.\npackage: conduit\ncategory: infrastructure\nkeywords: [dependency injection, container, token, lifecycle, scope]\nexports: [createContainer, valueProvider, factoryProvider, disposalSignalToken, token]\nrelated: [courier, vault, rune]\nenvironments: [browser, node, ssr, deno]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"conduit\" />\n\n## Why Conduit?\n\nConduit makes service wiring explicit. Typed builders create immutable providers, static graphs are validated at construction, and dependency tuples drive creation and disposal. Resolve one root token or a typed composition map.\n\n```ts\n// Before\nconst service = createService(createApi(config), logger);\n\n// After\nconst container = createContainer([\n valueProvider(Config, config),\n factoryProvider(Api, [Config], (config) => createApi(config)),\n factoryProvider(Service, [Api, Logger], (api, logger) => createService(api, logger)),\n]);\nconst services = await container.resolve({ service: Service });\n```\n\n| Feature | Conduit | Inversify | tsyringe |\n| --- | --- | --- | --- |\n| Dependencies | Explicit token tuples | Decorators/runtime metadata | Decorators/runtime metadata |\n| Async factories | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Partial | Partial |\n| Lifecycle scopes | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> |\n| Runtime dependencies | 0 | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n\n<div class=\"decision-callout\">\n\n**Use Conduit when** application services need explicit wiring and owned lifecycle cleanup.\n\n**Consider direct imports when** dependencies are static, small, and need no replacement or disposal boundary.\n\n</div>\n\n## Installation\n\n::: code-group\n\n```sh [pnpm]\npnpm add @vielzeug/conduit\n```\n\n```sh [npm]\nnpm install @vielzeug/conduit\n```\n\n```sh [yarn]\nyarn add @vielzeug/conduit\n```\n\n:::\n\n## Quick Start\n\n```ts\nimport { createContainer, factoryProvider, token, valueProvider } from '@vielzeug/conduit';\n\nconst Config = token<{ baseUrl: string }>('Config');\nconst Client = token<{ url: string }>('Client');\n\nconst container = createContainer([\n valueProvider(Config, { baseUrl: '/api' }),\n factoryProvider(Client, [Config], (config) => ({ url: `${config.baseUrl}/users` })),\n]);\n\nconst services = await container.resolve({ client: Client });\nconsole.log(services.client);\nawait container.dispose();\n```\n\n## Features\n\n<div class=\"features-grid\">\n\n- **`token`**: typed dependency identity\n- **`valueProvider` / `factoryProvider`**: token-safe immutable registrations\n- **`createContainer`**: validated provider graph\n- **`resolve`**: direct service or typed composition map\n- **`createScope`**: child containers for request and job ownership\n- **`dispose`**: in-flight-safe resource cleanup\n\n</div>\n\n## Documentation\n\n<div class=\"doc-links\">\n\n- [Usage Guide](./usage.md)\n- [API Reference](./api.md)\n- [Examples](./examples.md)\n- [Migration Guide](./migration.md)\n\n</div>\n\n## See Also\n\n<div class=\"see-also\">\n\n- [Courier](/courier/): inject HTTP clients into application services.\n- [Vault](/vault/): inject persistence adapters with scoped ownership.\n- [Rune](/rune/): provide application logging services.\n\n</div>\n\n<!-- markdownlint-enable MD025 MD033 MD060 -->\n",
5
+ "api": "---\ntitle: 'Conduit: API Reference'\ndescription: Reference for Conduit tokens, immutable provider arrays, dependency-first factories, child containers, composition-root resolution, and lifecycle disposal.\n---\n\n[[toc]]\n\n## API Overview\n\n| Symbol | Purpose | Mode | Common gotcha |\n| --- | --- | --- | --- |\n| `token` | Create typed dependency identity | Sync | Same description does not mean same token |\n| `createContainer` | Build root container from an immutable provider array | Sync | Validates the full graph at construction |\n| `valueProvider` / `factoryProvider` | Build type-safe immutable registrations | Sync | Prefer over unannotated object literals |\n| `Provider` | Value or factory registration type | Sync | One local registration per token |\n| `has` | Check registration visibility | Sync | Walks parent containers |\n| `resolve` | Resolve one token or typed composition-root map | Async | Undeclared map tokens fail at resolution |\n| `createScope` | Create child container | Sync | Child providers shadow parent registrations |\n| `dispose` | Release owned resources | Async | May throw `ConduitDisposeError` after cleanup attempts |\n\n## Package Entry Point\n\n| Import | Purpose |\n| --- | --- |\n| `@vielzeug/conduit` | Complete Conduit API |\n\n## Tokens\n\n```ts\ntoken<T>(description: string): Token<T>\n```\n\nTokens are unique symbols. Descriptions exist only for diagnostics. `disposalSignalToken` is a built-in `Token<AbortSignal>` that resolves to the owning container's cancellation signal.\n\n## Container\n\n```ts\ncreateContainer(providers: readonly Provider[], options?: { name?: string }): Container\n```\n\n`providers` is an immutable array of value and factory providers. Construction validates the entire graph: duplicate tokens, missing dependencies, circular factory tuples, and singletons depending on transient factories all fail fast.\n\n### Providers\n\n```ts\ntype Provider<T, Dependencies> = ValueProvider<T> | FactoryProvider<T, Dependencies>;\n\nvalueProvider<T>(token: Token<T>, value: T, options?: ValueOptions<T>): ValueProvider<T>;\nfactoryProvider<T, Dependencies>(\n token: Token<T>,\n dependencies: Dependencies,\n factory: (...values: InferTokens<Dependencies>) => Promise<T> | T,\n options?: FactoryOptions<T>,\n): FactoryProvider<T, Dependencies>;\n```\n\nUse builders for token-driven value and dependency inference:\n\n```ts\nvalueProvider(Config, { baseUrl: '/api' }, { dispose: (value) => value.close() });\nfactoryProvider(Service, [Api, Logger], (api, logger) => createService(api, logger), {\n lifetime: 'singleton',\n dispose: (value) => value.dispose(),\n});\n```\n\nExplicit `ValueProvider<T>` and `FactoryProvider<T, Dependencies>` annotations remain available for reusable provider declarations. Avoid unannotated provider object literals because TypeScript cannot contextually infer one factory parameter from another object property.\n\n`dependencies` is copied at construction and drives creation, validation, cycle detection, and teardown order. Factories may return a value or promise.\n\n`lifetime` accepts `'singleton'` (default) or `'transient'`. Singletons cannot capture transient factories.\n\n```ts\ntype FactoryProvider<T, Dependencies> = {\n token: Token<T>;\n dependencies: Dependencies;\n factory: (...values: InferTokens<Dependencies>) => Promise<T> | T;\n dispose?: (value: T) => void | Promise<void>;\n lifetime?: 'singleton' | 'transient';\n};\n```\n\n### has\n\n```ts\ncontainer.has(token): boolean\n```\n\nChecks local and parent registrations without creating a factory result.\n\n### resolve\n\n```ts\ncontainer.resolve(token: Token<T>): Promise<T>\ncontainer.resolve(map: ServiceMap): Promise<InferServices<typeof map>>\n```\n\nResolves one typed token or a service object at a composition root. Map keys are defined as own properties, including `__proto__`, without changing the result prototype. Missing top-level tokens fail during resolution.\n\n```ts\nconst services = await container.resolve({ client: Client, config: Config });\n```\n\nSingleton resolutions deduplicate concurrent callers and cache successful values. A rejected creation attempt is evicted so a later resolution can retry.\n\n### createScope\n\n```ts\ncontainer.createScope(options?: { name?: string; providers?: readonly AnyProvider[] }): Container\n```\n\nA child container inherits parent registrations. Immutable local providers may shadow parent registrations for request or test overrides: this is how request-scoped values are spelled: one child per request, disposed when the request ends. Disposing a parent also disposes active children.\n\n### dispose\n\n```ts\ncontainer.dispose(): Promise<void>\ncontainer.disposalSignal: AbortSignal\ncontainer.disposed: boolean\n```\n\nDisposal blocks new work, aborts `disposalSignal`, disposes active child containers, waits for complete in-flight creation and late-result cleanup, then disposes owned resources in reverse creation order. Cleanup failures are aggregated in the readonly `ConduitDisposeError.errors` array.\n\n## Types\n\n```ts\ntype Token<T = unknown> = symbol;\ntype Lifetime = 'singleton' | 'transient';\n\ntype InferTokens<T extends readonly Token<unknown>[]> = {\n [K in keyof T]: T[K] extends Token<infer Value> ? Value : never;\n};\n\ntype ServiceMap = { readonly [key: string]: Token<unknown> };\n\ntype InferServices<M extends ServiceMap> = {\n readonly [K in keyof M]: M[K] extends Token<infer Value> ? Value : never;\n};\n\ninterface Container {\n createScope(options?: { name?: string; providers?: readonly AnyProvider[] }): Container;\n readonly disposalSignal: AbortSignal;\n dispose(): Promise<void>;\n readonly disposed: boolean;\n has<T>(token: Token<T>): boolean;\n readonly name: string;\n resolve<T>(token: Token<T>): Promise<T>;\n resolve<M extends ServiceMap>(map: M): Promise<InferServices<M>>;\n [Symbol.asyncDispose](): Promise<void>;\n}\n```\n\n## Errors\n\n- `ConduitError`: base class; use `instanceof ConduitError` to narrow package errors.\n- `ConduitProviderNotFoundError`: dependency has no registration.\n- `ConduitCircularDependencyError`: static factory tuple graph contains a cycle.\n- `ConduitDuplicateRegistrationError`: token registered twice in one container.\n- `ConduitDisposedError`: operation attempted after disposal began.\n- `ConduitDisposeError`: one or more cleanup hooks failed.\n",
6
+ "usage": "---\ntitle: 'Conduit: Usage Guide'\ndescription: Register an immutable provider array, resolve a typed service object at composition roots, scope work to child containers, and dispose owned resources.\n---\n\n[[toc]]\n\n## Basic Usage\n\nCreate tokens once, build a container from an immutable provider array, then resolve a typed service object at your composition root.\n\n```ts\nimport { createContainer, factoryProvider, token, valueProvider } from '@vielzeug/conduit';\n\nconst Config = token<{ baseUrl: string }>('Config');\nconst Client = token<{ url: string }>('Client');\n\nconst container = createContainer([\n valueProvider(Config, { baseUrl: '/api' }),\n factoryProvider(Client, [Config], (config) => ({ url: `${config.baseUrl}/users` })),\n]);\n\nconst services = await container.resolve({ config: Config, client: Client });\nconsole.log(services.client);\nawait container.dispose();\n```\n\n## Define Dependencies\n\nFactory `dependencies` tuples are authoritative. Conduit resolves tuple values in order, validates every edge at construction, and disposes created services in reverse dependency order.\n\n```ts\nconst Logger = token<{ info(message: string): void }>('Logger');\nconst Api = token<{ get(path: string): Promise<unknown> }>('Api');\nconst Service = token<{ load(): Promise<unknown> }>('Service');\n\nconst container = createContainer([\n valueProvider(Logger, { info: (message) => console.log(message) }),\n factoryProvider(Api, [], () => ({ get: async (path: string) => fetch(path) })),\n factoryProvider(Service, [Api, Logger], (api, logger) => ({\n async load() {\n logger.info('Loading data');\n return api.get('/data');\n },\n })),\n]);\n```\n\n## Choose Lifetimes\n\nFactories are singletons by default and cached on the registering container. Concurrent singleton resolutions share one in-flight attempt; a rejected attempt is evicted for retry. Use `'transient'` for one value per resolution. Singletons cannot depend on transient factories.\n\n```ts\nimport { createContainer, factoryProvider, token } from '@vielzeug/conduit';\n\nconst Clock = token<{ now(): number }>('Clock');\n\nconst root = createContainer([\n factoryProvider(Clock, [], () => ({ now: () => Date.now() }), { lifetime: 'transient' }),\n]);\n```\n\nFactory dependency tuples are copied at construction, so later caller mutation cannot change Conduit's graph. Add `disposalSignalToken` to a factory tuple when work must observe its owning container's cancellation.\n\n## Scope Work to Child Containers\n\nUse a child container when a resource belongs to a request, job, or test lifecycle. Pass immutable local providers through `createScope()` options to shadow parent registrations; the child owns and disposes them.\n\n```ts\nconst Session = token<{ id: string }>('Session');\nconst TraceId = token<string>('TraceId');\n\nconst request = root.createScope({\n providers: [\n factoryProvider(Session, [], () => ({ id: crypto.randomUUID() })),\n valueProvider(TraceId, 'request-trace'),\n ],\n});\nconst services = await request.resolve({ session: Session, traceId: TraceId });\nawait request.dispose();\nawait root.dispose();\n```\n\nEach child caches its own singleton, so two request children resolve distinct `Session` values while the root never sees request-owned work unless it registers it.\n\n## Resolve at Composition Roots\n\nResolve a map at composition roots to receive an explicitly typed service object. Direct `resolve(token)` remains available for one root service and focused tests; avoid scattering service-locator calls through application code.\n\n```ts\nconst client = await container.resolve(Client);\nconst services = await container.resolve({ client: Client, config: Config });\n// Both results are fully typed.\n```\n\n## Dispose Resources\n\n`dispose()` rejects new work, aborts `disposalSignal`, disposes child containers, waits for in-flight creation, then releases services in reverse creation order. A factory that finishes after disposal starts is immediately cleaned up and its resolver receives `ConduitDisposedError`.\n\n```ts\nawait container.dispose();\n```\n\n`ConduitDisposeError.errors` contains every cleanup failure after Conduit attempts all hooks, including cleanup from in-flight factories and child containers.\n\n## Testing\n\nBuild a container per test with explicit values for external dependencies. Because the provider array is immutable and validated at construction, a misconfigured test container fails immediately.\n\n```ts\nconst Clock = token<{ now(): number }>('Clock');\nconst Service = token<{ timestamp: number }>('Service');\n\nconst container = createContainer([\n valueProvider(Clock, { now: () => 123 }),\n factoryProvider(Service, [Clock], (clock) => ({ timestamp: clock.now() })),\n]);\n\nconst services = await container.resolve({ service: Service });\nexpect(services.service).toEqual({ timestamp: 123 });\nawait container.dispose();\n```\n\n## Best Practices\n\n- Create tokens at module scope.\n- Use `valueProvider()` and `factoryProvider()` so tokens, values, dependencies, and disposers remain type-safe.\n- Declare every factory dependency in its tuple.\n- Keep factories focused on one service.\n- Use child containers for request/job-owned resources.\n- Resolve once at a composition root; pass the typed service object downstream.\n- Dispose every child container and root container.\n- Keep optional application fallback policy outside Conduit.\n- Use `await using container = createContainer([...])` when lexical async disposal fits application lifetime.\n",
7
+ "examples": "---\ntitle: 'Conduit: Examples'\ndescription: Immutable provider array recipes.\n---\n\n## Examples\n\n- [Basic setup](./examples/basic-setup.md)\n- [Static async providers](./examples/async-providers.md)\n- [Singleton lifetime](./examples/lifetimes.md)\n- [Child containers](./examples/child-containers.md)\n- [Disposal lifecycle](./examples/dispose-lifecycle.md)\n- [Startup validation](./examples/startup-hardening.md)\n"
8
8
  },
9
9
  "examples": [
10
10
  {
@@ -12,6 +12,11 @@
12
12
  "code": "import { createContainer, factoryProvider, token, valueProvider } from '@vielzeug/conduit'\n\nconst Config = token<{ baseUrl: string }>('Config')\nconst Client = token<{ url: string }>('Client')\n\nconst container = createContainer([\n valueProvider(Config, { baseUrl: '/api' }),\n factoryProvider(Client, [Config], config => ({ url: config.baseUrl + '/users' })),\n])\n\nconst services = await container.resolve({ client: Client })\nconsole.log(services.client)\nawait container.dispose()",
13
13
  "name": "Immutable provider array"
14
14
  },
15
+ {
16
+ "id": "child-containers",
17
+ "code": "import { createContainer, factoryProvider, token } from '@vielzeug/conduit'\n\nconst Session = token('Session')\n\nconst root = createContainer([])\n\nconst request = root.createScope({\n providers: [factoryProvider(Session, [], () => ({ id: crypto.randomUUID() }))],\n})\n\nconst services = await request.resolve({ session: Session })\nconsole.log(services.session)\nawait request.dispose()\nawait root.dispose()",
18
+ "name": "Child container ownership"
19
+ },
15
20
  {
16
21
  "id": "dispose-lifecycle",
17
22
  "code": "import { createContainer, factoryProvider, token } from '@vielzeug/conduit'\n\nconst Database = token('Database')\nconst Service = token('Service')\nconst order = []\n\nconst container = createContainer([\n factoryProvider(Database, [], () => ({ close() {} }), { dispose: () => { order.push('database') } }),\n factoryProvider(Service, [Database], database => ({ database }), { dispose: () => { order.push('service') } }),\n])\n\nawait container.resolve({ service: Service })\nawait container.dispose()\nconsole.log(order)",
@@ -22,11 +27,6 @@
22
27
  "code": "import { createContainer, factoryProvider, token } from '@vielzeug/conduit'\n\nconst Singleton = token('Singleton')\n\nconst container = createContainer([\n factoryProvider(Singleton, [], () => ({ id: crypto.randomUUID() })),\n])\n\nconst services = await container.resolve({ a: Singleton, b: Singleton })\nconsole.log(services.a === services.b)\nawait container.dispose()",
23
28
  "name": "Singleton lifetime caching"
24
29
  },
25
- {
26
- "id": "scoped-execution",
27
- "code": "import { createContainer, factoryProvider, scope, token } from '@vielzeug/conduit'\n\nconst Request = scope('request')\nconst Session = token('Session')\n\nconst root = createContainer([\n factoryProvider(Session, [], () => ({ id: crypto.randomUUID() }), { lifetime: Request }),\n])\n\nconst request = root.createScope(Request)\nconst services = await request.resolve({ session: Session })\nconsole.log(services.session)\nawait request.dispose()\nawait root.dispose()",
28
- "name": "Named scope ownership"
29
- },
30
30
  {
31
31
  "id": "testing",
32
32
  "code": "import { createContainer, factoryProvider, token, valueProvider } from '@vielzeug/conduit'\n\nconst Clock = token<{ now(): number }>('Clock')\nconst Service = token<{ timestamp: number }>('Service')\n\nconst container = createContainer([\n valueProvider(Clock, { now: () => 123 }),\n factoryProvider(Service, [Clock], clock => ({ timestamp: clock.now() })),\n])\n\nconst services = await container.resolve({ service: Service })\nconsole.log(services.service)\nawait container.dispose()",
@@ -40,29 +40,28 @@
40
40
  ],
41
41
  "typeSignatures": {
42
42
  "createContainer": "export { createContainer } from './container.js';",
43
- "ConduitCircularDependencyError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';",
44
- "ConduitDisposedError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';",
45
- "ConduitDisposeError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';",
46
- "ConduitDuplicateRegistrationError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';",
47
- "ConduitError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';",
48
- "ConduitProviderNotFoundError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';",
49
- "ConduitScopedResolutionError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n ConduitScopedResolutionError,\n} from './errors.js';",
50
- "Container": "export type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
51
- "FactoryOptions": "export type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
52
- "FactoryProvider": "export type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
53
- "InferServices": "export type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
54
- "InferTokens": "export type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
55
- "Lifetime": "export type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
56
- "Provider": "export type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
57
- "ScopeToken": "export type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
58
- "ServiceMap": "export type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
59
- "Token": "export type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
60
- "ValueOptions": "export type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
61
- "ValueProvider": "export type {\n Container,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ScopeToken,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
62
- "disposalSignalToken": "export { disposalSignalToken, factoryProvider, scope, token, valueProvider } from './types.js';",
63
- "factoryProvider": "export { disposalSignalToken, factoryProvider, scope, token, valueProvider } from './types.js';",
64
- "scope": "export { disposalSignalToken, factoryProvider, scope, token, valueProvider } from './types.js';",
65
- "token": "export { disposalSignalToken, factoryProvider, scope, token, valueProvider } from './types.js';",
66
- "valueProvider": "export { disposalSignalToken, factoryProvider, scope, token, valueProvider } from './types.js';"
43
+ "ConduitCircularDependencyError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n} from './errors.js';",
44
+ "ConduitDisposedError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n} from './errors.js';",
45
+ "ConduitDisposeError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n} from './errors.js';",
46
+ "ConduitDuplicateRegistrationError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n} from './errors.js';",
47
+ "ConduitError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n} from './errors.js';",
48
+ "ConduitProviderNotFoundError": "export {\n ConduitCircularDependencyError,\n ConduitDisposedError,\n ConduitDisposeError,\n ConduitDuplicateRegistrationError,\n ConduitError,\n ConduitProviderNotFoundError,\n} from './errors.js';",
49
+ "AnyProvider": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
50
+ "Container": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
51
+ "CreateScopeOptions": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
52
+ "FactoryOptions": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
53
+ "FactoryProvider": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
54
+ "InferServices": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
55
+ "InferTokens": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
56
+ "Lifetime": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
57
+ "Provider": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
58
+ "ServiceMap": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
59
+ "Token": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
60
+ "ValueOptions": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
61
+ "ValueProvider": "export type {\n AnyProvider,\n Container,\n CreateScopeOptions,\n FactoryOptions,\n FactoryProvider,\n InferServices,\n InferTokens,\n Lifetime,\n Provider,\n ServiceMap,\n Token,\n ValueOptions,\n ValueProvider,\n} from './types.js';",
62
+ "disposalSignalToken": "export { disposalSignalToken, factoryProvider, token, valueProvider } from './types.js';",
63
+ "factoryProvider": "export { disposalSignalToken, factoryProvider, token, valueProvider } from './types.js';",
64
+ "token": "export { disposalSignalToken, factoryProvider, token, valueProvider } from './types.js';",
65
+ "valueProvider": "export { disposalSignalToken, factoryProvider, token, valueProvider } from './types.js';"
67
66
  }
68
67
  }
@@ -1,10 +1,10 @@
1
1
  {
2
- "apiSource": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';\nexport { withBearerAuth, withLogging, withRequestId } from './interceptors.js';\nexport type { ResponseType } from './response.js';\nexport type { FetchContext, Middleware, TransportOptions } from './transport.js';\nexport type {\n CourierCacheKey,\n CourierCacheKeyAtom,\n CourierCacheOptions,\n CourierReadCache,\n GetRequestConfig,\n Params,\n PrefetchConfig,\n RequestConfig,\n} from './url.js';\n",
2
+ "apiSource": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';\nexport { withBearerAuth, withLogging, withRequestId } from './interceptors.js';\nexport type { ResponseType } from './response.js';\nexport type { FetchContext, Middleware, TransportOptions } from './transport.js';\nexport type {\n CourierCacheKey,\n CourierCacheKeyAtom,\n CourierCacheOptions,\n CourierReadCache,\n GetRequestConfig,\n Params,\n PrefetchConfig,\n RequestConfig,\n} from './url.js';\n",
3
3
  "docs": {
4
- "index": "---\ntitle: Courier — HTTP client\ndescription: A framework-neutral HTTP client with explicit cached reads, prefetching, immutable middleware, typed paths, and structured errors.\npackage: courier\ncategory: http\nkeywords: [http-client, fetch, cache, prefetch, middleware, interceptors, errors]\nrelated: [flux, spell, postmaster]\nexports:\n [\n createCourier,\n CourierError,\n CourierHttpError,\n CourierNetworkError,\n CourierTimeoutError,\n CourierAbortError,\n CourierSchemaValidationError,\n withBearerAuth,\n withRequestId,\n withLogging,\n ]\nenvironments: [browser, node, ssr, deno]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"courier\" />\n\n## Why Courier?\n\nNative `fetch` leaves request policy, error classification, middleware composition, and repeated-read coordination to each application. Courier keeps those concerns in one client, including explicit cached GETs and warm-cache prefetching, while observable query and mutation state remain consumer-owned.\n\n```ts\n// Before\nconst response = await fetch(`/api/users/${userId}`);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconst user = await response.json();\n\n// After\nconst user = await courier.get<User>('/users/{id}', { params: { id: userId } });\n```\n\n| Feature | Courier | ky | ofetch |\n| --- | --- | --- | --- |\n| Bundle size | <PackageInfo package=\"courier\" type=\"size\" /> | Separate package | Separate package |\n| Zero runtime dependencies | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Native fetch transport | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> |\n| Explicit parsed-value cache and prefetch | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Immutable middleware at construction | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Structured error taxonomy | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> |\n\n<div class=\"decision-callout\">\n\n**Use Courier when** one client should own typed HTTP, explicit cached GETs and prefetching, immutable middleware, and structured errors — while a separate state layer owns observable queries and mutations.\n\n**Consider ky when** you only need a compact fetch wrapper. **Consider ofetch when** you want a bundled fetch utility with its own retry and caching conventions.\n\n</div>\n\n## Installation\n\n::: code-group\n\n```sh [pnpm]\npnpm add @vielzeug/courier\n```\n\n```sh [npm]\nnpm install @vielzeug/courier\n```\n\n```sh [yarn]\nyarn add @vielzeug/courier\n```\n\n:::\n\n## Quick Start\n\nCreate one transport client for an application or request scope, then use method conveniences for standard HTTP methods and `request()` for custom methods.\n\n```ts\nimport { CourierHttpError, createCourier } from '@vielzeug/courier';\n\ntype User = { id: number; name: string };\n\nconst courier = createCourier({ baseUrl: 'https://api.example.com' });\n\ntry {\n const user = await courier.get<User>('/users/{id}', { params: { id: 42 } });\n console.log(user.name);\n} catch (error) {\n if (CourierHttpError.is(error, 404)) console.log('User not found');\n else throw error;\n} finally {\n courier.dispose();\n}\n```\n\n## Features\n\n<div class=\"features-grid\">\n\n- **`createCourier()`** — one lifecycle, immutable middleware pipeline, header defaults, and cancellation boundary.\n- **`request()`** — one contract for every HTTP method; pass `method` in the config.\n- **Cached `get()`** — opt in with a structured key and optional per-read TTL; successful parsed values share bounded storage and in-flight work.\n- **`prefetch()`** — await cache warming while request failures remain observable through `tap()`.\n- **`invalidateCache()` / `clearCache()`** — invalidate structured key prefixes without query state.\n- **`get()` / `post()` / `put()` / `patch()` / `delete()`** — conveniences for standard methods.\n- **`withBearerAuth()` / `withRequestId()` / `withLogging()`** — composable middleware configured at construction.\n- **`tap()`** — signal-owned structured transport observation.\n- **Error taxonomy** — HTTP, network, timeout, abort, parse, and schema failures are distinct, actionable classes.\n- **`cancelAll()` / `dispose()`** — abort active requests and tear down the transport.\n\n</div>\n\n## Documentation\n\n<div class=\"doc-links\">\n\n- [Usage Guide](./usage.md)\n- [API Reference](./api.md)\n- [Examples](./examples.md)\n- [Migration Guide](./migration.md)\n\n</div>\n\n## See Also\n\n<div class=\"see-also\">\n\n- [Flux](/flux/) — composes async streams; pair with Courier transport calls in the owning state layer.\n- [Spell](/spell/) — validates parsed HTTP payloads through Courier's `schema` option.\n- [Postmaster](/postmaster/) — coordinates durable delivery of Courier requests through a job outbox.\n\n</div>\n\n<!-- markdownlint-enable MD025 MD033 MD060 -->\n",
5
- "api": "---\ntitle: Courier — API Reference\ndescription: Reference for Courier HTTP, cached read, prefetch, middleware, and error APIs.\n---\n\n[[toc]]\n\n## API Overview\n\n| Symbol | Purpose | Execution mode | Common gotcha |\n| --- | --- | --- | --- |\n| `createCourier()` | Creates transport client | Sync | Dispose only when whole scope ends |\n| `request()` | Sends one HTTP request of any method | Async | Direct calls never deduplicate |\n| `get()` | Sends a GET, optionally through the explicit cache | Async | One key must identify one representation |\n| `prefetch()` | Warms a cached GET | Async | Request failures resolve after surfacing through `tap()` |\n| `invalidateCache()` / `clearCache()` | Removes cached values | Sync | Invalidation matches structured key prefixes |\n| `post()` / `put()` / `patch()` / `delete()` | Common write method conveniences | Async | Use `request()` for custom methods |\n| `withBearerAuth()` | Adds authorization middleware | Sync | Token provider runs per request |\n| `withRequestId()` | Adds request identifier middleware | Sync | Default generator uses `crypto.randomUUID()` |\n| `withLogging()` | Logs request result metadata | Sync | Requires explicit logger; URLs may contain sensitive query values |\n| `tap()` | Observe structured transport events | Sync | Observation only; optional signal owns lifetime |\n\n## Package Entry Point\n\n| Import | Purpose |\n| --- | --- |\n| `@vielzeug/courier` | Client factory, errors, middleware helpers, and public types |\n\n## Client\n\n### `createCourier()`\n\n```ts\ncreateCourier(options?: CourierOptions): Courier;\n```\n\nReturns an HTTP client sharing base URL, default headers, immutable middleware, optional parsed-value cache, timeout, and cancellation lifecycle.\n\n| `CourierOptions` field | Type | Default | Description |\n| --- | --- | --- | --- |\n| `baseUrl` | `string` | `''` | Prefix for relative request paths |\n| `cache.capacity` | `number` | `100` | Maximum cached entries; positive integer or `Infinity` |\n| `cache.ttlMs` | `number` | `30_000` | Default cache freshness; non-negative milliseconds or `Infinity` |\n| `fetch` | `typeof globalThis.fetch` | `globalThis.fetch` | Fetch implementation |\n| `headers` | `HeadersInit` | `{}` | Default request headers (immutable; merged lowercase) |\n| `middleware` | `readonly Middleware[]` | `[]` | Immutable middleware chain configured at construction |\n| `timeout` | `number` | `30_000` | Integer milliseconds from 1 to 2,147,483,647, or `Infinity` |\n\n**Returns:** `Courier`.\n\n```ts\nimport { createCourier, withBearerAuth } from '@vielzeug/courier';\n\nconst courier = createCourier({\n baseUrl: 'https://api.example.com',\n middleware: [withBearerAuth('token')],\n});\n```\n\n| `Courier` member | Signature | Description |\n| --- | --- | --- |\n| `request` | `<T, P>(path, config?) => Promise<T>` | Sends one HTTP request; `config.method` defaults to `GET` |\n| `get` | `<T, P>(path, config?) => Promise<T>` | Sends GET; `cache` opts parsed responses into bounded caching |\n| `prefetch` | `<T, P>(path, config) => Promise<void>` | Warms one required structured cache key; failures are tap-observed |\n| `invalidateCache` | `(prefix: CourierCacheKey) => void` | Invalidates matching settled and pending key prefixes |\n| `clearCache` | `() => void` | Removes every cached and pending entry |\n| `post` | `<T, P>(path, config?) => Promise<T>` | Sends POST |\n| `put` | `<T, P>(path, config?) => Promise<T>` | Sends PUT |\n| `patch` | `<T, P>(path, config?) => Promise<T>` | Sends PATCH |\n| `delete` | `<T, P>(path, config?) => Promise<T>` | Sends DELETE |\n| `tap` | `(handler, options?: { signal?: AbortSignal }) => () => void` | Observes structured request and disposal events |\n| `cancelAll` | `() => void` | Aborts active requests; client remains usable |\n| `dispose` | `() => void` | Final teardown; aborts work and marks client unusable |\n| `disposed` | `boolean` | Whether final disposal occurred |\n| `disposalSignal` | `AbortSignal` | Aborts on final disposal |\n\n---\n\n## Requests\n\n### `request()`\n\n```ts\nrequest<T, P extends string>(path: P, config?: RequestConfig<P, T> & { method?: string }): Promise<T>;\n```\n\nSends one HTTP request. `config.method` defaults to `GET`; pass any method (including custom verbs) to support it consistently.\n\n| `RequestConfig<P, T>` field | Type | Description |\n| --- | --- | --- |\n| `method` | `string` | HTTP method; defaults to `GET` |\n| `params` | `Record<string, string \\| number \\| boolean>` | Path parameters for `{param}` placeholders |\n| `query` | `Params` | Query string parameters |\n| `body` | `unknown` | BodyInit values pass through; streams use Node duplex; GET/HEAD reject bodies; other values encode as JSON |\n| `headers` | `HeadersInit` | Per-request headers merged with (and overriding) defaults |\n| `responseType` | `ResponseType` | Response parsing strategy |\n| `schema` | `{ parse(data: unknown): T }` | Optional parsed-response validator; incompatible with `responseType: 'raw'` |\n| `signal` | `AbortSignal` | External abort signal merged with internal cancellation |\n| `timeout` | `number` | Integer milliseconds from 1 to 2,147,483,647, or `Infinity`; overrides default |\n| `fetchInit` | `Omit<RequestInit, 'body' \\| 'headers' \\| 'method' \\| 'signal'>` | Raw fetch options for advanced use |\n\n**Returns:** Parsed response body (or `undefined` for empty bodies).\n\n```ts\nconst created = await courier.request<User>('/users', {\n method: 'POST',\n body: { name: 'Ada' },\n});\n```\n\n### `get()`\n\n```ts\nget<T, P extends string>(path: P, config?: GetRequestConfig<P, T>): Promise<T>;\n```\n\nConvenience for `request(path, { ...config, method: 'GET' })`. A `cache` descriptor opts a parsed response into the bounded cache. It requires a structured key and may override the default TTL. Raw responses cannot be cached.\n\n```ts\nconst user = await courier.get<User>('/users/{id}', {\n cache: { key: ['users', 1], ttlMs: 10_000 },\n params: { id: 1 },\n});\n```\n\n## Cache\n\n### `prefetch()`\n\n```ts\nprefetch<T, P extends string>(path: P, config: PrefetchConfig<P, T>): Promise<void>;\n```\n\nStarts the same cached GET used by `get()`. `config.cache` is required; `signal`, per-call `timeout`, and `responseType: 'raw'` are unavailable. Fresh values and pending loads are reused. The promise settles when the attempt finishes. Request failures emit `request-error` through `tap()` and resolve without caching data.\n\n### `invalidateCache()` and `clearCache()`\n\n```ts\ninvalidateCache(prefix: CourierCacheKey): void;\nclearCache(): void;\n```\n\n`invalidateCache()` removes every settled entry whose structured key starts with `prefix` and prevents matching pending loads from being stored. `clearCache()` applies that behavior to all entries. Existing waiters may still receive an invalidated in-flight result; `cancelAll()` or `dispose()` aborts physical work.\n\n---\n\n## Middleware\n\nMiddleware is an immutable chain configured at construction. Each middleware receives an immutable `FetchContext` and a `next` function.\n\n```ts\ntype Middleware = (ctx: FetchContext, next: (ctx: FetchContext) => Promise<Response>) => Promise<Response>;\n```\n\n### Middleware helpers\n\n```ts\nwithBearerAuth(token: string | (() => string | null | undefined | Promise<string | null | undefined>)): Middleware;\nwithRequestId(options?: { generate?: () => string; header?: string }): Middleware;\nwithLogging(options: {\n logger: (message: string, meta: { duration: number; method: string; status: number; url: string }) => void;\n}): Middleware;\n```\n\nEach helper returns a `Middleware` passed in the `middleware` option. `withLogging` requires an explicit `logger` function, isolates logger failures from requests, and has no default console output.\n\n```ts\nconst courier = createCourier({\n middleware: [\n withBearerAuth(() => tokenStore.getAccessToken()),\n withRequestId(),\n withLogging({ logger: (msg) => console.log(msg) }),\n ],\n});\n```\n\n## Types\n\n```ts\ntype TransportOptions = {\n baseUrl?: string;\n fetch?: typeof globalThis.fetch;\n headers?: HeadersInit;\n middleware?: readonly Middleware[];\n timeout?: number;\n};\n\ntype CourierCacheKeyAtom = string | number | boolean | null;\ntype CourierCacheKey = readonly [CourierCacheKeyAtom, ...CourierCacheKeyAtom[]];\n\ntype CourierCacheOptions = {\n capacity?: number;\n ttlMs?: number;\n};\n\ntype CourierReadCache = {\n key: CourierCacheKey;\n ttlMs?: number;\n};\n\ntype CourierOptions = TransportOptions & {\n cache?: CourierCacheOptions;\n};\n\ntype FetchContext = {\n readonly headers: Readonly<Record<string, string>>;\n readonly init: Readonly<Omit<RequestInit, 'headers'>>;\n readonly url: string;\n withHeaders(updates: Record<string, string | undefined>): FetchContext;\n withInit(updates: Partial<Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'>>): FetchContext;\n};\n\ntype Middleware = (ctx: FetchContext, next: (ctx: FetchContext) => Promise<Response>) => Promise<Response>;\n\ntype CourierEvent =\n | { type: 'request-start'; method: string; url: string }\n | { type: 'request-success'; method: string; url: string; status: number; duration: number }\n | { type: 'request-error'; method: string; url: string; error: unknown }\n | { type: 'dispose' };\n```\n\n```ts\ntype ParamValue = string | number | boolean | null | readonly (string | number | boolean | null)[] | undefined;\ntype Params = Record<string, ParamValue>;\ntype ResponseType = 'auto' | 'json' | 'text' | 'blob' | 'arrayBuffer' | 'raw';\ntype RequestConfig<P extends string = string, T = unknown> = {\n body?: unknown;\n method?: string;\n fetchInit?: Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'>;\n headers?: HeadersInit;\n params?: Record<string, string | number | boolean>;\n query?: Params;\n responseType?: ResponseType;\n schema?: { parse(data: unknown): T };\n signal?: AbortSignal;\n timeout?: number;\n};\n\ntype GetRequestConfig<P extends string = string, T = unknown> = Omit<\n RequestConfig<P, T>,\n 'body' | 'method' | 'responseType'\n> &\n ({ cache?: CourierReadCache; responseType?: Exclude<ResponseType, 'raw'> } | { cache?: never; responseType: 'raw' }) & {\n body?: never;\n };\n\ntype PrefetchConfig<P extends string = string, T = unknown> = Omit<\n GetRequestConfig<P, T>,\n 'cache' | 'responseType' | 'signal' | 'timeout'\n> & {\n cache: CourierReadCache;\n responseType?: Exclude<ResponseType, 'raw'>;\n signal?: never;\n timeout?: never;\n};\n```\n\n## Errors\n\n| Error | Trigger | Notable properties |\n| --- | --- | --- |\n| `CourierError` | Base class for all Courier errors | Use `instanceof` to narrow |\n| `CourierHttpError` | Non-2xx HTTP response | `status`, `data`, `headers`, `method`, `url`; `CourierHttpError.is(e, status?)` narrows by status |\n| `CourierNetworkError` | Request failure without response | `method`, `url`, `cause` |\n| `CourierTimeoutError` | Timeout signal aborts request | `method`, `url`, `cause` |\n| `CourierAbortError` | Caller or client cancellation | `method`, `url`, `cause` |\n| `CourierSchemaValidationError` | Response schema fails | `data`, `cause` |\n| `CourierParseError` | Response body cannot parse | — |\n| `CourierDisposedError` | Work starts after disposal | — |\n\nErrors thrown directly by custom middleware are preserved rather than reclassified.\n",
6
- "usage": "---\ntitle: Courier — Usage Guide\ndescription: Use one Courier client for typed HTTP, explicit cached reads, prefetching, immutable middleware, and structured errors.\n---\n\n[[toc]]\n\n## Basic Usage\n\nCreate one Courier client for an application or request scope. Its transport policy, middleware, and disposal lifecycle apply to every request.\n\n```ts\nimport { createCourier } from '@vielzeug/courier';\n\ntype User = { id: number; name: string };\n\nconst courier = createCourier({ baseUrl: 'https://api.example.com' });\nconst user = await courier.get<User>('/users/{id}', { params: { id: 1 } });\nconsole.log(user.name);\n```\n\n## HTTP Requests\n\nUse `get()`, `post()`, `put()`, `patch()`, and `delete()` for standard methods. Use `request()` when the method is custom or selected dynamically. Courier preserves root-relative paths, encodes path parameters, serializes JSON-compatible bodies, and parses successful responses.\n\n```ts\nconst posts = await courier.get<{ id: number; title: string }[]>('/users/{id}/posts', {\n params: { id: 1 },\n query: { limit: 20, status: 'published' },\n});\n\nawait courier.patch('/posts/{id}', {\n body: { title: 'Updated title' },\n params: { id: posts[0].id },\n});\n```\n\n`get()`, `post()`, `put()`, `patch()`, and `delete()` cover common methods. Use `request()` for custom verbs or when a method is selected dynamically.\n\n## Default Headers\n\nSet default headers at construction. They are merged (lowercased) into every request and cannot be mutated at runtime — middleware handles dynamic headers.\n\n```ts\nconst courier = createCourier({\n baseUrl: 'https://api.example.com',\n headers: { 'x-client': 'web' },\n});\n```\n\n## Middleware\n\nMiddleware is an immutable chain configured once at construction. Each middleware receives an immutable `FetchContext` and a `next` function. Use `ctx.withHeaders()` or `ctx.withInit()` to derive a new context — never mutate `ctx` directly.\n\n```ts\nimport { withBearerAuth, withRequestId, createCourier } from '@vielzeug/courier';\n\nconst courier = createCourier({\n baseUrl: 'https://api.example.com',\n middleware: [\n withBearerAuth(() => sessionStorage.getItem('access-token') ?? ''),\n withRequestId(),\n ],\n});\n```\n\nA bearer token provider may return `null`, `undefined`, or an empty string to omit a stale authorization header. Use `withLogging()` with an explicit `logger` function to log requests during local development. `withLogging()` includes full URLs, so sanitize query values before persistent logging.\n\n```ts\nimport { withLogging, createCourier } from '@vielzeug/courier';\n\nconst courier = createCourier({\n baseUrl: 'https://api.example.com',\n middleware: [withLogging({ logger: (msg) => console.log(msg) })],\n});\n```\n\nUse `tap()` for multiple structured transport observers. It emits request-start, request-success, request-error, and dispose events; observer failures cannot alter requests. Pass `{ signal }` to own listener lifetime.\n\n```ts\nconst stop = courier.tap((event) => metrics.record(event), { signal: routeSignal });\n```\n\nBecause middleware is immutable, a client's behavior is locally understandable from its construction call. To change policy, create a new client.\n\n## Cached Reads and Prefetching\n\nOpt parsed GETs into caching with a structured key. Courier uses a finite capacity of 100 entries and a 30-second TTL by default; client options change those defaults, and each read may override TTL. Successful parsed and schema-validated values are cached, while errors are not.\n\n```ts\nconst courier = createCourier({\n baseUrl: 'https://api.example.com',\n cache: { capacity: 200, ttlMs: 60_000 },\n});\nconst cache = { key: ['accounts', accountId, 'users', userId] as const, ttlMs: 10_000 };\n\nawait courier.prefetch<User>('/users/{id}', { cache, params: { id: userId } });\nconst user = await courier.get<User>('/users/{id}', { cache, params: { id: userId } });\n```\n\n`prefetch()` returns a promise that settles when warming finishes. Request failures are not cached or rejected from that promise; the physical request emits `request-error` through `tap()`. Cache, key, and URL configuration errors still throw before prefetch starts.\n\nInvalidate a structured prefix after writes. Every matching settled or pending key becomes ineligible for caching, while unrelated entries remain available.\n\n```ts\nawait courier.patch('/users/{id}', { body: update, params: { id: userId } });\ncourier.invalidateCache(['accounts', accountId, 'users']);\n```\n\nA cache key must identify one response representation, including a stable non-secret principal or tenant identifier, schema, and relevant request variants. Never place credentials in a key; call `clearCache()` when identity changes. Cached objects are shared by reference.\n\nConcurrent callers share physical work but own their own signal and timeout. One cancelled caller does not affect the others. When every caller cancels and no prefetch owns the load, Courier aborts the physical request. `cancelAll()` always aborts physical work; `dispose()` also clears settled cache data.\n\n## Response Parsing\n\nCourier parses successful 2xx response bodies automatically based on `content-type`, unless you set `responseType` explicitly (`'json'`, `'text'`, `'blob'`, `'arrayBuffer'`, or `'raw'` for the `Response` itself). Empty JSON bodies return `undefined` instead of throwing. Raw response bodies remain owned by Courier until consumed or cancelled, so `cancelAll()` and `dispose()` still abort them. Raw responses cannot be combined with `schema`. Always consume or cancel the body to release request ownership, and set `timeout: Infinity` for intentionally long-lived streams. Courier preserves URL, redirect, and type metadata on tracked responses and their clones.\n\n```ts\nconst buffer = await courier.request('/files/{id}', {\n method: 'GET',\n params: { id: 1 },\n responseType: 'arrayBuffer',\n});\n```\n\n## Schema Validation\n\nPass a `schema` with a `parse(data)` method to validate the parsed body. Any validator works — a `@vielzeug/spell` schema or a plain function wrapper. A failed parse throws `CourierSchemaValidationError`.\n\n```ts\nimport { s } from '@vielzeug/spell';\n\nconst user = await courier.get('/users/1', {\n schema: s.object({ id: s.number(), name: s.string() }),\n});\n```\n\n## Cancellation and Disposal\n\nPass a `signal` to cancel one request. `cancelAll()` aborts every active request without disposing the client. `dispose()` aborts active work and marks the client unusable — call it only at the final application or request boundary.\n\n```ts\nconst controller = new AbortController();\nvoid courier.get('/slow', { signal: controller.signal });\ncontroller.abort(); // cancels that request only\n\ncourier.cancelAll(); // cancels all active requests\ncourier.dispose(); // final teardown\n```\n\n## Timeouts\n\nSet a client-wide `timeout` (default 30,000 ms) or a per-request timeout. Finite values must be integer milliseconds from 1 through 2,147,483,647. A timed-out request rejects with `CourierTimeoutError`; use `Infinity` for intentionally long-lived work.\n\n```ts\nconst courier = createCourier({ timeout: 10_000 });\nawait courier.get('/health', { timeout: 2_000 });\n```\n\n## Error Handling\n\nCourier classifies URL, request-construction, fetch, cancellation, HTTP, response-parsing, and schema failures into distinct error classes. Errors thrown directly by custom middleware are preserved.\n\n```ts\nimport {\n CourierAbortError,\n CourierHttpError,\n CourierNetworkError,\n CourierParseError,\n CourierTimeoutError,\n createCourier,\n} from '@vielzeug/courier';\n\nconst courier = createCourier({ baseUrl: 'https://api.example.com' });\n\nasync function loadUser(): Promise<string> {\n try {\n return (await courier.get<{ name: string }>('/users/1', { timeout: 2_000 })).name;\n } catch (error) {\n if (error instanceof CourierAbortError) return 'Cancelled';\n if (error instanceof CourierTimeoutError) return 'Timed out; retry.';\n if (CourierHttpError.is(error, 404)) return 'User not found.';\n if (error instanceof CourierNetworkError) return 'Check your connection.';\n if (error instanceof CourierParseError) return 'The server returned an unreadable response.';\n throw error;\n }\n}\n```\n\n- A `CourierHttpError` has a response (`status`, `data`, `headers`); a `CourierNetworkError` does not.\n- Do not display cancellation as an application error during navigation.\n- `CourierSchemaValidationError` carries the raw pre-validation `data`.\n\n## Composing with a State Layer\n\nCourier owns HTTP transport and optional parsed GET caching. Observable query state, optimistic mutations, collection navigation, and stream state belong to the owning state layer (e.g. Sourcerer, TanStack Query, or consumer code). Compose Courier calls into that layer instead of nesting state machines.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst users = createPageSource<User>({\n load: async ({ page, pageSize, signal }) => {\n const result = await courier.get<{ data: User[]; total: number }>('/users', {\n query: { page, pageSize },\n signal,\n });\n return { items: result.data, totalItems: result.total };\n },\n});\n\nawait users.reload();\n```\n\n## Framework Integration\n\nCreate Courier at an application or route boundary. Inject the client where requests are issued; let the framework own rendering and cache state.\n\n::: code-group\n\n```tsx [React]\nimport { createContext, useContext } from 'react';\nimport { createCourier } from '@vielzeug/courier';\n\ntype User = { id: number; name: string };\n\ntype CourierClient = ReturnType<typeof createCourier>;\nconst CourierContext = createContext<CourierClient | null>(null);\n\nexport function CourierProvider({ children, courier }: { children: React.ReactNode; courier: CourierClient }) {\n return <CourierContext.Provider value={courier}>{children}</CourierContext.Provider>;\n}\n\nexport function useCourier() {\n const courier = useContext(CourierContext);\n if (!courier) throw new Error('CourierProvider missing');\n return courier;\n}\n\n// In a component:\n// const user = await useCourier().get<User>('/users/1');\n```\n\n```ts [Vue 3]\nimport { createCourier } from '@vielzeug/courier';\n\nconst courier = createCourier({ baseUrl: '/api' });\n// Provide via app.provide('courier', courier) and inject in setup().\n```\n\n```svelte [Svelte]\n<script lang=\"ts\">\n import { createCourier } from '@vielzeug/courier';\n export let courier: ReturnType<typeof createCourier>;\n</script>\n```\n\n:::\n\nCourier exposes no loading, error, or cache store. Construct the client at the application or SSR-request boundary, pass it into framework providers, and dispose it at that same boundary. Render state in the framework that owns the view.\n\n## Gotchas\n\n### Root-relative paths stay root-relative\n\nWith no `baseUrl`, `'/api/users'` is passed to fetch unchanged while `'api/users'` remains document-relative. With a `baseUrl`, Courier appends either spelling to that base.\n\n### `baseUrl` should not include query parameters\n\n`buildUrl` joins `baseUrl` and path with `/`. A base URL like `https://api.example.com?token=abc` produces broken URLs (`https://api.example.com?token=abc/users`). Pass query parameters per-request via `config.query` instead.\n\n### Query parameters precede fragments\n\nWhen a path already contains `#fragment`, Courier inserts `config.query` before the fragment so values remain part of the HTTP query.\n\n### GET and HEAD bodies are rejected\n\nFetch does not support bodies for GET or HEAD. Courier rejects them as request parse errors before dispatch.\n\n### Middleware is immutable\n\nThere is no `use()` method. To change middleware, create a new client. This keeps each client's behavior locally understandable and avoids runtime mutation of the request chain.\n\n### Keep credentials out of URLs when using logging middleware\n\n`withLogging()` logs the full URL, including query parameters. If URLs may contain sensitive data, provide a custom `logger` that sanitizes the URL first.\n\n## Best Practices\n\n- Create one Courier client per application or SSR request scope.\n- Configure middleware once at construction; never mutate it at runtime.\n- Use method conveniences for GET/POST/PUT/PATCH/DELETE and `request()` for custom verbs.\n- Use explicit cache keys only for parsed GETs that should share data and in-flight work.\n- Clear cached data when the authenticated principal or tenant changes.\n- Let the owning state layer own observable queries and mutations.\n- Dispose only at the final application or request boundary.\n- Keep credentials out of URLs when using logging middleware.\n",
7
- "examples": "---\ntitle: Courier — Examples\ndescription: Practical examples and recipes for courier.\n---\n\n## Examples\n\n- [Authentication](./examples/authentication.md)\n- [CRUD Operations](./examples/crud-operations.md)\n- [Disposal](./examples/disposal.md)\n- [Error Handling Patterns](./examples/error-handling-patterns.md)\n- [File Uploads](./examples/file-uploads.md)\n- [Optimistic Updates](./examples/optimistic-updates.md)\n- [SSE Events](./examples/sse-events.md)\n"
4
+ "index": "---\ntitle: 'Courier: HTTP client'\ndescription: A framework-neutral HTTP client with explicit cached reads, prefetching, immutable middleware, typed paths, and structured errors.\npackage: courier\ncategory: http\nkeywords: [http-client, fetch, cache, prefetch, middleware, interceptors, errors]\nrelated: [flux, spell, postmaster]\nexports:\n [\n createCourier,\n CourierError,\n CourierHttpError,\n CourierNetworkError,\n CourierTimeoutError,\n CourierAbortError,\n CourierSchemaValidationError,\n withBearerAuth,\n withRequestId,\n withLogging,\n ]\nenvironments: [browser, node, ssr, deno]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"courier\" />\n\n## Why Courier?\n\nNative `fetch` leaves request policy, error classification, middleware composition, and repeated-read coordination to each application. Courier keeps those concerns in one client, including explicit cached GETs and warm-cache prefetching, while observable query and mutation state remain consumer-owned.\n\n```ts\n// Before\nconst response = await fetch(`/api/users/${userId}`);\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\nconst user = await response.json();\n\n// After\nconst user = await courier.get<User>('/users/{id}', { params: { id: userId } });\n```\n\n| Feature | Courier | ky | ofetch |\n| --- | --- | --- | --- |\n| Bundle size | <PackageInfo package=\"courier\" type=\"size\" /> | Separate package | Separate package |\n| Zero runtime dependencies | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Native fetch transport | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> |\n| Explicit parsed-value cache and prefetch | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Immutable middleware at construction | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Structured error taxonomy | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> |\n\n<div class=\"decision-callout\">\n\n**Use Courier when** one client should own typed HTTP, explicit cached GETs and prefetching, immutable middleware, and structured errors, while a separate state layer owns observable queries and mutations.\n\n**Consider ky when** you only need a compact fetch wrapper. **Consider ofetch when** you want a bundled fetch utility with its own retry and caching conventions.\n\n</div>\n\n## Installation\n\n::: code-group\n\n```sh [pnpm]\npnpm add @vielzeug/courier\n```\n\n```sh [npm]\nnpm install @vielzeug/courier\n```\n\n```sh [yarn]\nyarn add @vielzeug/courier\n```\n\n:::\n\n## Quick Start\n\nCreate one transport client for an application or request scope, then use method conveniences for standard HTTP methods and `request()` for custom methods.\n\n```ts\nimport { CourierHttpError, createCourier } from '@vielzeug/courier';\n\ntype User = { id: number; name: string };\n\nconst courier = createCourier({ baseUrl: 'https://api.example.com' });\n\ntry {\n const user = await courier.get<User>('/users/{id}', { params: { id: 42 } });\n console.log(user.name);\n} catch (error) {\n if (CourierHttpError.is(error, 404)) console.log('User not found');\n else throw error;\n} finally {\n courier.dispose();\n}\n```\n\n## Features\n\n<div class=\"features-grid\">\n\n- **`createCourier()`**: one lifecycle, immutable middleware pipeline, header defaults, and cancellation boundary.\n- **`request()`**: one contract for every HTTP method; pass `method` in the config.\n- **Cached `get()`**: opt in with a structured key and optional per-read TTL; successful parsed values share bounded storage and in-flight work.\n- **`prefetch()`**: await cache warming while request failures remain observable through `tap()`.\n- **`invalidateCache()` / `clearCache()`**: invalidate structured key prefixes without query state.\n- **`get()` / `post()` / `put()` / `patch()` / `delete()`**: conveniences for standard methods.\n- **`withBearerAuth()` / `withRequestId()` / `withLogging()`**: composable middleware configured at construction.\n- **`tap()`**: signal-owned structured transport observation.\n- **Error taxonomy**: HTTP, network, timeout, abort, parse, and schema failures are distinct, actionable classes.\n- **`cancelAll()` / `dispose()`**: abort active requests and tear down the transport.\n\n</div>\n\n## Documentation\n\n<div class=\"doc-links\">\n\n- [Usage Guide](./usage.md)\n- [API Reference](./api.md)\n- [Examples](./examples.md)\n- [Migration Guide](./migration.md)\n\n</div>\n\n## See Also\n\n<div class=\"see-also\">\n\n- [Flux](/flux/): composes async streams; pair with Courier transport calls in the owning state layer.\n- [Spell](/spell/): validates parsed HTTP payloads through Courier's `schema` option.\n- [Postmaster](/postmaster/): coordinates durable delivery of Courier requests through a job outbox.\n\n</div>\n\n<!-- markdownlint-enable MD025 MD033 MD060 -->\n",
5
+ "api": "---\ntitle: 'Courier: API Reference'\ndescription: Reference for Courier HTTP, cached read, prefetch, middleware, and error APIs.\n---\n\n[[toc]]\n\n## API Overview\n\n| Symbol | Purpose | Execution mode | Common gotcha |\n| --- | --- | --- | --- |\n| `createCourier()` | Creates transport client | Sync | Dispose only when whole scope ends |\n| `request()` | Sends one HTTP request of any method | Async | Direct calls never deduplicate |\n| `get()` | Sends a GET, optionally through the explicit cache | Async | One key must identify one representation |\n| `prefetch()` | Warms a cached GET | Async | Request failures resolve after surfacing through `tap()` |\n| `invalidateCache()` / `clearCache()` | Removes cached values | Sync | Invalidation matches structured key prefixes |\n| `post()` / `put()` / `patch()` / `delete()` | Common write method conveniences | Async | Use `request()` for custom methods |\n| `withBearerAuth()` | Adds authorization middleware | Sync | Token provider runs per request |\n| `withRequestId()` | Adds request identifier middleware | Sync | Default generator uses `crypto.randomUUID()` |\n| `withLogging()` | Logs request result metadata | Sync | Requires explicit logger; URLs may contain sensitive query values |\n| `tap()` | Observe structured transport events | Sync | Observation only; optional signal owns lifetime |\n\n## Package Entry Point\n\n| Import | Purpose |\n| --- | --- |\n| `@vielzeug/courier` | Client factory, errors, middleware helpers, and public types |\n\n## Client\n\n### `createCourier()`\n\n```ts\ncreateCourier(options?: CourierOptions): Courier;\n```\n\nReturns an HTTP client sharing base URL, default headers, immutable middleware, optional parsed-value cache, timeout, and cancellation lifecycle.\n\n| `CourierOptions` field | Type | Default | Description |\n| --- | --- | --- | --- |\n| `baseUrl` | `string` | `''` | Prefix for relative request paths |\n| `cache.capacity` | `number` | `100` | Maximum cached entries; positive integer or `Infinity` |\n| `cache.ttlMs` | `number` | `30_000` | Default cache freshness; non-negative milliseconds or `Infinity` |\n| `fetch` | `typeof globalThis.fetch` | `globalThis.fetch` | Fetch implementation |\n| `headers` | `HeadersInit` | `{}` | Default request headers (immutable; merged lowercase) |\n| `middleware` | `readonly Middleware[]` | `[]` | Immutable middleware chain configured at construction |\n| `timeout` | `number` | `30_000` | Integer milliseconds from 1 to 2,147,483,647, or `Infinity` |\n\n**Returns:** `Courier`.\n\n```ts\nimport { createCourier, withBearerAuth } from '@vielzeug/courier';\n\nconst courier = createCourier({\n baseUrl: 'https://api.example.com',\n middleware: [withBearerAuth('token')],\n});\n```\n\n| `Courier` member | Signature | Description |\n| --- | --- | --- |\n| `request` | `<T, P>(path, config?) => Promise<T>` | Sends one HTTP request; `config.method` defaults to `GET` |\n| `get` | `<T, P>(path, config?) => Promise<T>` | Sends GET; `cache` opts parsed responses into bounded caching |\n| `prefetch` | `<T, P>(path, config) => Promise<void>` | Warms one required structured cache key; failures are tap-observed |\n| `invalidateCache` | `(prefix: CourierCacheKey) => void` | Invalidates matching settled and pending key prefixes |\n| `clearCache` | `() => void` | Removes every cached and pending entry |\n| `post` | `<T, P>(path, config?) => Promise<T>` | Sends POST |\n| `put` | `<T, P>(path, config?) => Promise<T>` | Sends PUT |\n| `patch` | `<T, P>(path, config?) => Promise<T>` | Sends PATCH |\n| `delete` | `<T, P>(path, config?) => Promise<T>` | Sends DELETE |\n| `tap` | `(handler, options?: { signal?: AbortSignal }) => () => void` | Observes structured request and disposal events |\n| `cancelAll` | `() => void` | Aborts active requests; client remains usable |\n| `dispose` | `() => void` | Final teardown; aborts work and marks client unusable |\n| `disposed` | `boolean` | Whether final disposal occurred |\n| `disposalSignal` | `AbortSignal` | Aborts on final disposal |\n\n---\n\n## Requests\n\n### `request()`\n\n```ts\nrequest<T, P extends string>(path: P, config?: RequestConfig<P, T> & { method?: string }): Promise<T>;\n```\n\nSends one HTTP request. `config.method` defaults to `GET`; pass any method (including custom verbs) to support it consistently.\n\n| `RequestConfig<P, T>` field | Type | Description |\n| --- | --- | --- |\n| `method` | `string` | HTTP method; defaults to `GET` |\n| `params` | `Record<string, string \\| number \\| boolean>` | Path parameters for `{param}` placeholders |\n| `query` | `Params` | Query string parameters |\n| `body` | `unknown` | BodyInit values pass through; streams use Node duplex; GET/HEAD reject bodies; other values encode as JSON |\n| `headers` | `HeadersInit` | Per-request headers merged with (and overriding) defaults |\n| `responseType` | `ResponseType` | Response parsing strategy |\n| `schema` | `{ parse(data: unknown): T }` | Optional parsed-response validator; incompatible with `responseType: 'raw'` |\n| `signal` | `AbortSignal` | External abort signal merged with internal cancellation |\n| `timeout` | `number` | Integer milliseconds from 1 to 2,147,483,647, or `Infinity`; overrides default |\n| `fetchInit` | `Omit<RequestInit, 'body' \\| 'headers' \\| 'method' \\| 'signal'>` | Raw fetch options for advanced use |\n\n**Returns:** Parsed response body (or `undefined` for empty bodies).\n\n```ts\nconst created = await courier.request<User>('/users', {\n method: 'POST',\n body: { name: 'Ada' },\n});\n```\n\n### `get()`\n\n```ts\nget<T, P extends string>(path: P, config?: GetRequestConfig<P, T>): Promise<T>;\n```\n\nConvenience for `request(path, { ...config, method: 'GET' })`. A `cache` descriptor opts a parsed response into the bounded cache. It requires a structured key and may override the default TTL. Raw responses cannot be cached.\n\n```ts\nconst user = await courier.get<User>('/users/{id}', {\n cache: { key: ['users', 1], ttlMs: 10_000 },\n params: { id: 1 },\n});\n```\n\n## Cache\n\n### `prefetch()`\n\n```ts\nprefetch<T, P extends string>(path: P, config: PrefetchConfig<P, T>): Promise<void>;\n```\n\nStarts the same cached GET used by `get()`. `config.cache` is required; `signal`, per-call `timeout`, and `responseType: 'raw'` are unavailable. Fresh values and pending loads are reused. The promise settles when the attempt finishes. Request failures emit `request-error` through `tap()` and resolve without caching data.\n\n### `invalidateCache()` and `clearCache()`\n\n```ts\ninvalidateCache(prefix: CourierCacheKey): void;\nclearCache(): void;\n```\n\n`invalidateCache()` removes every settled entry whose structured key starts with `prefix` and prevents matching pending loads from being stored. `clearCache()` applies that behavior to all entries. Existing waiters may still receive an invalidated in-flight result; `cancelAll()` or `dispose()` aborts physical work.\n\n---\n\n## Middleware\n\nMiddleware is an immutable chain configured at construction. Each middleware receives an immutable `FetchContext` and a `next` function.\n\n```ts\ntype Middleware = (ctx: FetchContext, next: (ctx: FetchContext) => Promise<Response>) => Promise<Response>;\n```\n\n### Middleware helpers\n\n```ts\nwithBearerAuth(token: string | (() => string | null | undefined | Promise<string | null | undefined>)): Middleware;\nwithRequestId(options?: { generate?: () => string; header?: string }): Middleware;\nwithLogging(options: {\n logger: (message: string, meta: { duration: number; method: string; status: number; url: string }) => void;\n}): Middleware;\n```\n\nEach helper returns a `Middleware` passed in the `middleware` option. `withLogging` requires an explicit `logger` function, isolates logger failures from requests, and has no default console output.\n\n```ts\nconst courier = createCourier({\n middleware: [\n withBearerAuth(() => tokenStore.getAccessToken()),\n withRequestId(),\n withLogging({ logger: (msg) => console.log(msg) }),\n ],\n});\n```\n\n## Types\n\n```ts\ntype TransportOptions = {\n baseUrl?: string;\n fetch?: typeof globalThis.fetch;\n headers?: HeadersInit;\n middleware?: readonly Middleware[];\n timeout?: number;\n};\n\ntype CourierCacheKeyAtom = string | number | boolean | null;\ntype CourierCacheKey = readonly [CourierCacheKeyAtom, ...CourierCacheKeyAtom[]];\n\ntype CourierCacheOptions = {\n capacity?: number;\n ttlMs?: number;\n};\n\ntype CourierReadCache = {\n key: CourierCacheKey;\n ttlMs?: number;\n};\n\ntype CourierOptions = TransportOptions & {\n cache?: CourierCacheOptions;\n};\n\ntype FetchContext = {\n readonly headers: Readonly<Record<string, string>>;\n readonly init: Readonly<Omit<RequestInit, 'headers'>>;\n readonly url: string;\n withHeaders(updates: Record<string, string | undefined>): FetchContext;\n withInit(updates: Partial<Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'>>): FetchContext;\n};\n\ntype Middleware = (ctx: FetchContext, next: (ctx: FetchContext) => Promise<Response>) => Promise<Response>;\n\ntype CourierEvent =\n | { type: 'request-start'; method: string; url: string }\n | { type: 'request-success'; method: string; url: string; status: number; duration: number }\n | { type: 'request-error'; method: string; url: string; error: unknown }\n | { type: 'dispose' };\n```\n\n```ts\ntype ParamValue = string | number | boolean | null | readonly (string | number | boolean | null)[] | undefined;\ntype Params = Record<string, ParamValue>;\ntype ResponseType = 'auto' | 'json' | 'text' | 'blob' | 'arrayBuffer' | 'raw';\ntype RequestConfig<P extends string = string, T = unknown> = {\n body?: unknown;\n method?: string;\n fetchInit?: Omit<RequestInit, 'body' | 'headers' | 'method' | 'signal'>;\n headers?: HeadersInit;\n params?: Record<string, string | number | boolean>;\n query?: Params;\n responseType?: ResponseType;\n schema?: { parse(data: unknown): T };\n signal?: AbortSignal;\n timeout?: number;\n};\n\ntype GetRequestConfig<P extends string = string, T = unknown> = Omit<\n RequestConfig<P, T>,\n 'body' | 'method' | 'responseType'\n> &\n ({ cache?: CourierReadCache; responseType?: Exclude<ResponseType, 'raw'> } | { cache?: never; responseType: 'raw' }) & {\n body?: never;\n };\n\ntype PrefetchConfig<P extends string = string, T = unknown> = Omit<\n GetRequestConfig<P, T>,\n 'cache' | 'responseType' | 'signal' | 'timeout'\n> & {\n cache: CourierReadCache;\n responseType?: Exclude<ResponseType, 'raw'>;\n signal?: never;\n timeout?: never;\n};\n```\n\n## Errors\n\n| Error | Trigger | Notable properties |\n| --- | --- | --- |\n| `CourierError` | Base class for all Courier errors | Use `instanceof` to narrow |\n| `CourierHttpError` | Non-2xx HTTP response | `status`, `data`, `headers`, `method`, `url`; `CourierHttpError.is(e, status?)` narrows by status |\n| `CourierNetworkError` | Request failure without response | `method`, `url`, `cause` |\n| `CourierTimeoutError` | Timeout signal aborts request | `method`, `url`, `cause` |\n| `CourierAbortError` | Caller or client cancellation | `method`, `url`, `cause` |\n| `CourierSchemaValidationError` | Response schema fails | `data`, `cause` |\n| `CourierParseError` | Response body cannot parse | N/A |\n| `CourierConfigError` | Invalid request config (GET/HEAD body, raw + schema) | N/A |\n| `CourierDisposedError` | Work starts after disposal | N/A |\n\nErrors thrown directly by custom middleware are preserved rather than reclassified.\n",
6
+ "usage": "---\ntitle: 'Courier: Usage Guide'\ndescription: Use one Courier client for typed HTTP, explicit cached reads, prefetching, immutable middleware, and structured errors.\n---\n\n[[toc]]\n\n## Basic Usage\n\nCreate one Courier client for an application or request scope. Its transport policy, middleware, and disposal lifecycle apply to every request.\n\n```ts\nimport { createCourier } from '@vielzeug/courier';\n\ntype User = { id: number; name: string };\n\nconst courier = createCourier({ baseUrl: 'https://api.example.com' });\nconst user = await courier.get<User>('/users/{id}', { params: { id: 1 } });\nconsole.log(user.name);\n```\n\n## HTTP Requests\n\nUse `get()`, `post()`, `put()`, `patch()`, and `delete()` for standard methods. Use `request()` when the method is custom or selected dynamically. Courier preserves root-relative paths, encodes path parameters, serializes JSON-compatible bodies, and parses successful responses.\n\n```ts\nconst posts = await courier.get<{ id: number; title: string }[]>('/users/{id}/posts', {\n params: { id: 1 },\n query: { limit: 20, status: 'published' },\n});\n\nawait courier.patch('/posts/{id}', {\n body: { title: 'Updated title' },\n params: { id: posts[0].id },\n});\n```\n\n`get()`, `post()`, `put()`, `patch()`, and `delete()` cover common methods. Use `request()` for custom verbs or when a method is selected dynamically.\n\n## Default Headers\n\nSet default headers at construction. They are merged (lowercased) into every request and cannot be mutated at runtime: middleware handles dynamic headers.\n\n```ts\nconst courier = createCourier({\n baseUrl: 'https://api.example.com',\n headers: { 'x-client': 'web' },\n});\n```\n\n## Middleware\n\nMiddleware is an immutable chain configured once at construction. Each middleware receives an immutable `FetchContext` and a `next` function. Use `ctx.withHeaders()` or `ctx.withInit()` to derive a new context: never mutate `ctx` directly.\n\n```ts\nimport { withBearerAuth, withRequestId, createCourier } from '@vielzeug/courier';\n\nconst courier = createCourier({\n baseUrl: 'https://api.example.com',\n middleware: [\n withBearerAuth(() => sessionStorage.getItem('access-token') ?? ''),\n withRequestId(),\n ],\n});\n```\n\nA bearer token provider may return `null`, `undefined`, or an empty string to omit a stale authorization header. Use `withLogging()` with an explicit `logger` function to log requests during local development. `withLogging()` includes full URLs, so sanitize query values before persistent logging.\n\n```ts\nimport { withLogging, createCourier } from '@vielzeug/courier';\n\nconst courier = createCourier({\n baseUrl: 'https://api.example.com',\n middleware: [withLogging({ logger: (msg) => console.log(msg) })],\n});\n```\n\nUse `tap()` for multiple structured transport observers. It emits request-start, request-success, request-error, and dispose events; observer failures cannot alter requests. Pass `{ signal }` to own listener lifetime.\n\n```ts\nconst stop = courier.tap((event) => metrics.record(event), { signal: routeSignal });\n```\n\nBecause middleware is immutable, a client's behavior is locally understandable from its construction call. To change policy, create a new client.\n\n## Cached Reads and Prefetching\n\nOpt parsed GETs into caching with a structured key. Courier uses a finite capacity of 100 entries and a 30-second TTL by default; client options change those defaults, and each read may override TTL. Successful parsed and schema-validated values are cached, while errors are not.\n\n```ts\nconst courier = createCourier({\n baseUrl: 'https://api.example.com',\n cache: { capacity: 200, ttlMs: 60_000 },\n});\nconst cache = { key: ['accounts', accountId, 'users', userId] as const, ttlMs: 10_000 };\n\nawait courier.prefetch<User>('/users/{id}', { cache, params: { id: userId } });\nconst user = await courier.get<User>('/users/{id}', { cache, params: { id: userId } });\n```\n\n`prefetch()` returns a promise that settles when warming finishes. Request failures are not cached or rejected from that promise; the physical request emits `request-error` through `tap()`. Cache, key, and URL configuration errors still throw before prefetch starts.\n\nInvalidate a structured prefix after writes. Every matching settled or pending key becomes ineligible for caching, while unrelated entries remain available.\n\n```ts\nawait courier.patch('/users/{id}', { body: update, params: { id: userId } });\ncourier.invalidateCache(['accounts', accountId, 'users']);\n```\n\nA cache key must identify one response representation, including a stable non-secret principal or tenant identifier, schema, and relevant request variants. Never place credentials in a key; call `clearCache()` when identity changes. Cached objects are shared by reference.\n\nConcurrent callers share physical work but own their own signal and timeout. One cancelled caller does not affect the others. When every caller cancels and no prefetch owns the load, Courier aborts the physical request. `cancelAll()` always aborts physical work; `dispose()` also clears settled cache data.\n\n## Response Parsing\n\nCourier parses successful 2xx response bodies automatically based on `content-type`, unless you set `responseType` explicitly (`'json'`, `'text'`, `'blob'`, `'arrayBuffer'`, or `'raw'` for the `Response` itself). Empty JSON bodies return `undefined` instead of throwing. Raw response bodies remain owned by Courier until consumed or cancelled, so `cancelAll()` and `dispose()` still abort them. Raw responses cannot be combined with `schema`. Always consume or cancel the body to release request ownership, and set `timeout: Infinity` for intentionally long-lived streams. Courier preserves URL, redirect, and type metadata on tracked responses and their clones.\n\n```ts\nconst buffer = await courier.request('/files/{id}', {\n method: 'GET',\n params: { id: 1 },\n responseType: 'arrayBuffer',\n});\n```\n\n## Schema Validation\n\nPass a `schema` with a `parse(data)` method to validate the parsed body. Any validator works: a `@vielzeug/spell` schema or a plain function wrapper. A failed parse throws `CourierSchemaValidationError`.\n\n```ts\nimport { s } from '@vielzeug/spell';\n\nconst user = await courier.get('/users/1', {\n schema: s.object({ id: s.number(), name: s.string() }),\n});\n```\n\n## Cancellation and Disposal\n\nPass a `signal` to cancel one request. `cancelAll()` aborts every active request without disposing the client. `dispose()` aborts active work and marks the client unusable: call it only at the final application or request boundary.\n\n```ts\nconst controller = new AbortController();\nvoid courier.get('/slow', { signal: controller.signal });\ncontroller.abort(); // cancels that request only\n\ncourier.cancelAll(); // cancels all active requests\ncourier.dispose(); // final teardown\n```\n\n## Timeouts\n\nSet a client-wide `timeout` (default 30,000 ms) or a per-request timeout. Finite values must be integer milliseconds from 1 through 2,147,483,647. A timed-out request rejects with `CourierTimeoutError`; use `Infinity` for intentionally long-lived work.\n\n```ts\nconst courier = createCourier({ timeout: 10_000 });\nawait courier.get('/health', { timeout: 2_000 });\n```\n\n## Error Handling\n\nCourier classifies URL, request-construction, fetch, cancellation, HTTP, response-parsing, and schema failures into distinct error classes. Errors thrown directly by custom middleware are preserved.\n\n```ts\nimport {\n CourierAbortError,\n CourierHttpError,\n CourierNetworkError,\n CourierParseError,\n CourierTimeoutError,\n createCourier,\n} from '@vielzeug/courier';\n\nconst courier = createCourier({ baseUrl: 'https://api.example.com' });\n\nasync function loadUser(): Promise<string> {\n try {\n return (await courier.get<{ name: string }>('/users/1', { timeout: 2_000 })).name;\n } catch (error) {\n if (error instanceof CourierAbortError) return 'Cancelled';\n if (error instanceof CourierTimeoutError) return 'Timed out; retry.';\n if (CourierHttpError.is(error, 404)) return 'User not found.';\n if (error instanceof CourierNetworkError) return 'Check your connection.';\n if (error instanceof CourierParseError) return 'The server returned an unreadable response.';\n throw error;\n }\n}\n```\n\n- A `CourierHttpError` has a response (`status`, `data`, `headers`); a `CourierNetworkError` does not.\n- Do not display cancellation as an application error during navigation.\n- `CourierSchemaValidationError` carries the raw pre-validation `data`.\n\n## Composing with a State Layer\n\nCourier owns HTTP transport and optional parsed GET caching. Observable query state, optimistic mutations, collection navigation, and stream state belong to the owning state layer (e.g. Sourcerer, TanStack Query, or consumer code). Compose Courier calls into that layer instead of nesting state machines.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\n\nconst users = createPageSource<User>({\n load: async ({ page, pageSize, signal }) => {\n const result = await courier.get<{ data: User[]; total: number }>('/users', {\n query: { page, pageSize },\n signal,\n });\n return { items: result.data, totalItems: result.total };\n },\n});\n\nawait users.reload();\n```\n\n## Framework Integration\n\nCreate Courier at an application or route boundary. Inject the client where requests are issued; let the framework own rendering and cache state.\n\n::: code-group\n\n```tsx [React]\nimport { createContext, useContext } from 'react';\nimport { createCourier } from '@vielzeug/courier';\n\ntype User = { id: number; name: string };\n\ntype CourierClient = ReturnType<typeof createCourier>;\nconst CourierContext = createContext<CourierClient | null>(null);\n\nexport function CourierProvider({ children, courier }: { children: React.ReactNode; courier: CourierClient }) {\n return <CourierContext.Provider value={courier}>{children}</CourierContext.Provider>;\n}\n\nexport function useCourier() {\n const courier = useContext(CourierContext);\n if (!courier) throw new Error('CourierProvider missing');\n return courier;\n}\n\n// In a component:\n// const user = await useCourier().get<User>('/users/1');\n```\n\n```ts [Vue 3]\nimport { createCourier } from '@vielzeug/courier';\n\nconst courier = createCourier({ baseUrl: '/api' });\n// Provide via app.provide('courier', courier) and inject in setup().\n```\n\n```svelte [Svelte]\n<script lang=\"ts\">\n import { createCourier } from '@vielzeug/courier';\n export let courier: ReturnType<typeof createCourier>;\n</script>\n```\n\n:::\n\nCourier exposes no loading, error, or cache store. Construct the client at the application or SSR-request boundary, pass it into framework providers, and dispose it at that same boundary. Render state in the framework that owns the view.\n\n## Gotchas\n\n### Root-relative paths stay root-relative\n\nWith no `baseUrl`, `'/api/users'` is passed to fetch unchanged while `'api/users'` remains document-relative. With a `baseUrl`, Courier appends either spelling to that base.\n\n### `baseUrl` should not include query parameters\n\n`buildUrl` joins `baseUrl` and path with `/`. A base URL like `https://api.example.com?token=abc` produces broken URLs (`https://api.example.com?token=abc/users`). Pass query parameters per-request via `config.query` instead.\n\n### Query parameters precede fragments\n\nWhen a path already contains `#fragment`, Courier inserts `config.query` before the fragment so values remain part of the HTTP query.\n\n### GET and HEAD bodies are rejected\n\nFetch does not support bodies for GET or HEAD. Courier rejects them as request parse errors before dispatch.\n\n### Middleware is immutable\n\nThere is no `use()` method. To change middleware, create a new client. This keeps each client's behavior locally understandable and avoids runtime mutation of the request chain.\n\n### Keep credentials out of URLs when using logging middleware\n\n`withLogging()` logs the full URL, including query parameters. If URLs may contain sensitive data, provide a custom `logger` that sanitizes the URL first.\n\n## Best Practices\n\n- Create one Courier client per application or SSR request scope.\n- Configure middleware once at construction; never mutate it at runtime.\n- Use method conveniences for GET/POST/PUT/PATCH/DELETE and `request()` for custom verbs.\n- Use explicit cache keys only for parsed GETs that should share data and in-flight work.\n- Clear cached data when the authenticated principal or tenant changes.\n- Let the owning state layer own observable queries and mutations.\n- Dispose only at the final application or request boundary.\n- Keep credentials out of URLs when using logging middleware.\n",
7
+ "examples": "---\ntitle: 'Courier: Examples'\ndescription: Practical examples and recipes for courier.\n---\n\n## Examples\n\n- [Authentication](./examples/authentication.md)\n- [CRUD Operations](./examples/crud-operations.md)\n- [Disposal](./examples/disposal.md)\n- [Error Handling Patterns](./examples/error-handling-patterns.md)\n- [File Uploads](./examples/file-uploads.md)\n- [Optimistic Updates](./examples/optimistic-updates.md)\n- [SSE Events](./examples/sse-events.md)\n"
8
8
  },
9
9
  "examples": [
10
10
  {
@@ -24,18 +24,19 @@
24
24
  }
25
25
  ],
26
26
  "typeSignatures": {
27
- "Courier": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
28
- "CourierAbortError": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
29
- "CourierDisposedError": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
30
- "CourierError": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
31
- "CourierEvent": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
32
- "CourierHttpError": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
33
- "CourierNetworkError": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
34
- "CourierOptions": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
35
- "CourierParseError": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
36
- "CourierSchemaValidationError": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
37
- "CourierTimeoutError": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
38
- "createCourier": "export {\n type Courier,\n CourierAbortError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
27
+ "Courier": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
28
+ "CourierAbortError": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
29
+ "CourierConfigError": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
30
+ "CourierDisposedError": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
31
+ "CourierError": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
32
+ "CourierEvent": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
33
+ "CourierHttpError": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
34
+ "CourierNetworkError": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
35
+ "CourierOptions": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
36
+ "CourierParseError": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
37
+ "CourierSchemaValidationError": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
38
+ "CourierTimeoutError": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
39
+ "createCourier": "export {\n type Courier,\n CourierAbortError,\n CourierConfigError,\n CourierDisposedError,\n CourierError,\n type CourierEvent,\n CourierHttpError,\n CourierNetworkError,\n type CourierOptions,\n CourierParseError,\n CourierSchemaValidationError,\n CourierTimeoutError,\n createCourier,\n} from './courier.js';",
39
40
  "withBearerAuth": "export { withBearerAuth, withLogging, withRequestId } from './interceptors.js';",
40
41
  "withLogging": "export { withBearerAuth, withLogging, withRequestId } from './interceptors.js';",
41
42
  "withRequestId": "export { withBearerAuth, withLogging, withRequestId } from './interceptors.js';",