@shaferllc/keel 0.66.0 → 0.68.0
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.
- package/AGENTS.md +167 -0
- package/README.md +30 -1
- package/bin/keel-mcp.mjs +9 -0
- package/dist/core/application.d.ts +5 -5
- package/dist/core/application.js +2 -2
- package/dist/core/cache.d.ts +82 -5
- package/dist/core/cache.js +181 -23
- package/dist/core/cli/stubs.d.ts +12 -0
- package/dist/core/cli/stubs.js +120 -0
- package/dist/core/events.d.ts +129 -5
- package/dist/core/events.js +165 -7
- package/dist/core/health.d.ts +141 -0
- package/dist/core/health.js +226 -0
- package/dist/core/helpers.d.ts +9 -3
- package/dist/core/helpers.js +11 -3
- package/dist/core/index.d.ts +15 -10
- package/dist/core/index.js +7 -4
- package/dist/core/lock.d.ts +139 -0
- package/dist/core/lock.js +215 -0
- package/dist/core/logger.d.ts +82 -4
- package/dist/core/logger.js +141 -23
- package/dist/core/mail.d.ts +128 -7
- package/dist/core/mail.js +264 -16
- package/dist/core/queue.d.ts +134 -9
- package/dist/core/queue.js +304 -14
- package/dist/core/storage.d.ts +159 -6
- package/dist/core/storage.js +287 -7
- package/dist/mcp/server.d.ts +19 -0
- package/dist/mcp/server.js +355 -0
- package/docs/ai-manifest.json +2472 -0
- package/docs/ai.md +128 -0
- package/docs/architecture.md +331 -0
- package/docs/authentication.md +453 -0
- package/docs/authorization.md +167 -0
- package/docs/broadcasting.md +137 -0
- package/docs/broker.md +500 -0
- package/docs/cache.md +558 -0
- package/docs/configuration.md +311 -0
- package/docs/console.md +356 -0
- package/docs/container.md +467 -0
- package/docs/controllers.md +265 -0
- package/docs/cors.md +51 -0
- package/docs/database.md +530 -0
- package/docs/debugging.md +129 -0
- package/docs/decorators.md +127 -0
- package/docs/errors.md +395 -0
- package/docs/events.md +496 -0
- package/docs/examples/architecture-app.ts +27 -0
- package/docs/examples/authentication.ts +61 -0
- package/docs/examples/authorization.ts +79 -0
- package/docs/examples/broadcasting.ts +60 -0
- package/docs/examples/broker-cache-validate.ts +34 -0
- package/docs/examples/broker-fault-tolerance.ts +29 -0
- package/docs/examples/broker-middleware.ts +27 -0
- package/docs/examples/broker.ts +203 -0
- package/docs/examples/cache.ts +222 -0
- package/docs/examples/configuration.ts +81 -0
- package/docs/examples/container.ts +134 -0
- package/docs/examples/controllers.ts +86 -0
- package/docs/examples/database.ts +118 -0
- package/docs/examples/debugging.ts +41 -0
- package/docs/examples/decorators.ts +40 -0
- package/docs/examples/errors.ts +121 -0
- package/docs/examples/events.ts +204 -0
- package/docs/examples/factories.ts +84 -0
- package/docs/examples/hashing.ts +71 -0
- package/docs/examples/health.ts +94 -0
- package/docs/examples/helpers.ts +171 -0
- package/docs/examples/hooks.ts +54 -0
- package/docs/examples/inertia.ts +81 -0
- package/docs/examples/locks.ts +120 -0
- package/docs/examples/logger.ts +92 -0
- package/docs/examples/mail.ts +160 -0
- package/docs/examples/middleware.ts +119 -0
- package/docs/examples/migrations.ts +126 -0
- package/docs/examples/models.ts +239 -0
- package/docs/examples/notification.ts +124 -0
- package/docs/examples/providers.ts +123 -0
- package/docs/examples/queues.ts +254 -0
- package/docs/examples/rate-limiting.ts +42 -0
- package/docs/examples/redis.ts +99 -0
- package/docs/examples/request-response.ts +197 -0
- package/docs/examples/routing.ts +186 -0
- package/docs/examples/scheduling.ts +62 -0
- package/docs/examples/sessions.ts +102 -0
- package/docs/examples/static-files.ts +63 -0
- package/docs/examples/storage.ts +132 -0
- package/docs/examples/templates.ts +58 -0
- package/docs/examples/testing.ts +66 -0
- package/docs/examples/transformer.ts +141 -0
- package/docs/examples/transformers.ts +49 -0
- package/docs/examples/url-builder.ts +86 -0
- package/docs/examples/validation.ts +102 -0
- package/docs/examples/views.tsx +62 -0
- package/docs/examples/vite.ts +106 -0
- package/docs/factories.md +166 -0
- package/docs/getting-started.md +290 -0
- package/docs/hashing.md +259 -0
- package/docs/health.md +225 -0
- package/docs/helpers.md +347 -0
- package/docs/hono.md +186 -0
- package/docs/hooks.md +118 -0
- package/docs/inertia.md +241 -0
- package/docs/locks.md +323 -0
- package/docs/logger.md +290 -0
- package/docs/mail.md +678 -0
- package/docs/middleware.md +425 -0
- package/docs/migrations.md +476 -0
- package/docs/models.md +810 -0
- package/docs/notifications.md +474 -0
- package/docs/providers.md +363 -0
- package/docs/queues.md +679 -0
- package/docs/rate-limiting.md +155 -0
- package/docs/redis.md +178 -0
- package/docs/request-response.md +953 -0
- package/docs/routing.md +804 -0
- package/docs/scheduling.md +110 -0
- package/docs/security.md +85 -0
- package/docs/sessions.md +354 -0
- package/docs/social-auth.md +174 -0
- package/docs/static-files.md +211 -0
- package/docs/storage.md +450 -0
- package/docs/templates.md +315 -0
- package/docs/testing.md +125 -0
- package/docs/transformers.md +381 -0
- package/docs/url-builder.md +295 -0
- package/docs/validation.md +288 -0
- package/docs/views.md +267 -0
- package/docs/vite.md +434 -0
- package/llms-full.txt +17694 -0
- package/llms.txt +116 -0
- package/package.json +26 -7
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
# The Service Container
|
|
2
|
+
|
|
3
|
+
The container is the backbone of Keel. Every service — config, the router,
|
|
4
|
+
controllers, and anything you write — is registered in it and resolved out of
|
|
5
|
+
it. It is the single registry every service resolves out of.
|
|
6
|
+
|
|
7
|
+
## Why a container?
|
|
8
|
+
|
|
9
|
+
Instead of `import`ing concrete classes everywhere and `new`ing them by hand,
|
|
10
|
+
you _bind_ how a service is built once, then _resolve_ it wherever you need it.
|
|
11
|
+
That gives you a single place to swap implementations (real vs. fake in tests),
|
|
12
|
+
share singletons, and inject dependencies.
|
|
13
|
+
|
|
14
|
+
## Binding
|
|
15
|
+
|
|
16
|
+
Bindings live in a service provider's `register()` method (see
|
|
17
|
+
[Providers](./providers.md)). A binding is keyed by a **token** — a string,
|
|
18
|
+
symbol, or class — and a **factory** that receives the container.
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { ServiceProvider } from "@shaferllc/keel/core";
|
|
22
|
+
|
|
23
|
+
export class AppServiceProvider extends ServiceProvider {
|
|
24
|
+
register(): void {
|
|
25
|
+
// Transient: a fresh value every time it is resolved.
|
|
26
|
+
this.app.bind("clock", () => new Date());
|
|
27
|
+
|
|
28
|
+
// Singleton: built once, then cached.
|
|
29
|
+
this.app.singleton(Mailer, (app) => new Mailer(app.make("config")));
|
|
30
|
+
|
|
31
|
+
// Instance: register an already-constructed value.
|
|
32
|
+
this.app.instance("version", "0.1.0");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## The short way: global helpers
|
|
38
|
+
|
|
39
|
+
You don't need `this.app` at all. The same operations exist as global helpers
|
|
40
|
+
that resolve against the active application — bind and resolve from anywhere:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { bind, singleton, instance, make, bound } from "@shaferllc/keel/core";
|
|
44
|
+
|
|
45
|
+
bind("clock", () => new Date()); // transient
|
|
46
|
+
singleton(Mailer, (app) => new Mailer(app)); // shared
|
|
47
|
+
instance("version", "0.6.0"); // pre-built value
|
|
48
|
+
|
|
49
|
+
const mailer = make(Mailer);
|
|
50
|
+
const version = make<string>("version");
|
|
51
|
+
if (bound("clock")) { /* … */ }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Both styles work everywhere; the helpers are just less to type.
|
|
55
|
+
|
|
56
|
+
## Aliases
|
|
57
|
+
|
|
58
|
+
Point a second token at an existing binding with `alias(name, target)`. The
|
|
59
|
+
target owns the binding (and its singleton, if any); the alias just resolves
|
|
60
|
+
through to it:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { alias, make } from "@shaferllc/keel/core";
|
|
64
|
+
|
|
65
|
+
alias("router", Router); // make("router") === make(Router)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Swapping bindings in tests
|
|
69
|
+
|
|
70
|
+
`swap(token, factory)` temporarily replaces a binding with a fake, and
|
|
71
|
+
`restore(token)` puts the original back — the container remembers the real one
|
|
72
|
+
(binding *and* any resolved instance) so your test doesn't have to. `restore()`
|
|
73
|
+
with no argument undoes every swap, which makes a tidy `afterEach`:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { swap, restore } from "@shaferllc/keel/core";
|
|
77
|
+
|
|
78
|
+
swap(Mailer, () => fakeMailer); // resolved once, shared for the test
|
|
79
|
+
// … exercise code that make()s Mailer …
|
|
80
|
+
restore(Mailer); // or restore() to undo all swaps
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This is Keel's answer to mocking a service without reaching into module
|
|
84
|
+
internals: the code under test resolves `Mailer` the same way it always does,
|
|
85
|
+
and gets the fake. (For request-scoped fakes, prefer plain
|
|
86
|
+
[dependency injection](#dependency-injection-in-controllers) — pass the collaborator
|
|
87
|
+
in — so there's no global to restore.)
|
|
88
|
+
|
|
89
|
+
## Resolving
|
|
90
|
+
|
|
91
|
+
Use `make()` (or `this.app.make()`) to pull something out:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const mailer = make(Mailer);
|
|
95
|
+
const version = make<string>("version");
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
If a token is bound, its factory runs (once, for singletons). If you pass an
|
|
99
|
+
**unbound class**, the container auto-constructs it, passing itself to the
|
|
100
|
+
constructor:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
class ReportService {
|
|
104
|
+
constructor(private app: Container) {}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const report = app.make(ReportService); // works with no explicit binding
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Auto-resolution is transient: an unbound class is rebuilt every `make()` — it is
|
|
111
|
+
never cached, because nothing marked it shared. Bind it with `singleton` if you
|
|
112
|
+
want one instance.
|
|
113
|
+
|
|
114
|
+
### When nothing is bound
|
|
115
|
+
|
|
116
|
+
`make()` only auto-constructs **class** tokens. A string or symbol that was never
|
|
117
|
+
bound has nothing to build, so it throws:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
make("nope"); // Error: Nothing bound in the container for [nope].
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Guard with `bound()` when a token might be missing:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
const clock = bound("clock") ? make<Date>("clock") : new Date();
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Dependency injection in controllers
|
|
130
|
+
|
|
131
|
+
Controllers are resolved through the container, so their constructor receives
|
|
132
|
+
it. Pull whatever you need:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import type { Ctx } from "@shaferllc/keel/core";
|
|
136
|
+
import { Application, type Container } from "@shaferllc/keel/core";
|
|
137
|
+
|
|
138
|
+
export class InvoiceController {
|
|
139
|
+
constructor(private app: Container) {}
|
|
140
|
+
|
|
141
|
+
index(c: Ctx) {
|
|
142
|
+
const config = this.app.make(Application).config();
|
|
143
|
+
return c.json({ currency: config.get("app.currency", "USD") });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## The API
|
|
149
|
+
|
|
150
|
+
| Method | Purpose |
|
|
151
|
+
|--------|---------|
|
|
152
|
+
| `bind(token, factory)` | Transient binding — fresh value each resolve |
|
|
153
|
+
| `singleton(token, factory)` | Shared binding — resolved once, then cached |
|
|
154
|
+
| `instance(token, value)` | Register a pre-built value as a shared instance |
|
|
155
|
+
| `make(token)` / `get(token)` | Resolve a token |
|
|
156
|
+
| `bound(token)` | Whether a token is bound or cached |
|
|
157
|
+
| `build(ctor)` | Instantiate a class, passing it the container |
|
|
158
|
+
|
|
159
|
+
## Tokens
|
|
160
|
+
|
|
161
|
+
- **Strings/symbols** — good for values and interfaces: `"config"`, `"clock"`.
|
|
162
|
+
- **Classes** — good for services; the class doubles as its own token and can be
|
|
163
|
+
auto-resolved when unbound.
|
|
164
|
+
|
|
165
|
+
## Under the hood
|
|
166
|
+
|
|
167
|
+
The whole container is about 90 lines in
|
|
168
|
+
[`src/core/container.ts`](../src/core/container.ts). Two maps — one for bindings,
|
|
169
|
+
one for cached instances — and a `make()` that checks the cache, runs the
|
|
170
|
+
factory, and caches shared results. Read it; there's no magic.
|
|
171
|
+
|
|
172
|
+
## Related
|
|
173
|
+
|
|
174
|
+
Bindings usually live in a [service provider](./providers.md)'s `register()`
|
|
175
|
+
method; the global helpers resolve against the active [`Application`](./application.md),
|
|
176
|
+
which registers itself on construction.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## API reference
|
|
181
|
+
|
|
182
|
+
### Container
|
|
183
|
+
|
|
184
|
+
The registry itself. You rarely construct it — the `Application` is a `Container`,
|
|
185
|
+
and you reach it as `this.app` inside providers/controllers or via the global
|
|
186
|
+
helpers below. Registration methods (`bind`, `singleton`) return `this` and so
|
|
187
|
+
chain; resolution methods return the value.
|
|
188
|
+
|
|
189
|
+
#### `bind(token, factory)`
|
|
190
|
+
|
|
191
|
+
`bind<T>(token: Token<T>, factory: Factory<T>): this`
|
|
192
|
+
|
|
193
|
+
Registers a transient binding — the factory runs on every resolve, yielding a
|
|
194
|
+
fresh value each time.
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
app.bind("clock", () => new Date());
|
|
198
|
+
app.bind(Mailer, (c) => new Mailer(c.make("config")));
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Notes:** returns `this`, so calls chain. Re-binding the same token overwrites
|
|
202
|
+
the prior binding. The factory receives the container, so it can resolve its own
|
|
203
|
+
dependencies.
|
|
204
|
+
|
|
205
|
+
#### `singleton(token, factory)`
|
|
206
|
+
|
|
207
|
+
`singleton<T>(token: Token<T>, factory: Factory<T>): this`
|
|
208
|
+
|
|
209
|
+
Registers a shared binding — the factory runs at most once; the result is cached
|
|
210
|
+
and returned on every later resolve.
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
app.singleton(Mailer, (c) => new Mailer(c.make("config")));
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Notes:** returns `this`. The factory is lazy — it doesn't run until the first
|
|
217
|
+
`make()`. The cached value lives in the instance map, so a later `bound()` is
|
|
218
|
+
`true` even before first resolve (the binding is registered immediately).
|
|
219
|
+
|
|
220
|
+
#### `instance(token, value)`
|
|
221
|
+
|
|
222
|
+
`instance<T>(token: Token<T>, value: T): T`
|
|
223
|
+
|
|
224
|
+
Registers an already-constructed value as a shared instance, skipping any factory.
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
const version = app.instance("version", "0.30.0"); // returns "0.30.0"
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Notes:** returns the value you passed (not `this`), so it reads well inline.
|
|
231
|
+
Overrides any cached instance for the token. Because it writes the instance map,
|
|
232
|
+
`make()` returns it directly without ever consulting a binding.
|
|
233
|
+
|
|
234
|
+
#### `make(token)`
|
|
235
|
+
|
|
236
|
+
`make<T>(token: Token<T>): T`
|
|
237
|
+
|
|
238
|
+
Resolves a token: returns a cached instance if present, else runs its binding
|
|
239
|
+
(caching the result for singletons), else auto-constructs an unbound class.
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
const mailer = app.make(Mailer);
|
|
243
|
+
const version = app.make<string>("version");
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
**Notes:** resolution order is instance cache → binding → class auto-build. An
|
|
247
|
+
unbound **class** token is built via `build()` and **not** cached. An unbound
|
|
248
|
+
string/symbol token throws `Nothing bound in the container for [token].`
|
|
249
|
+
|
|
250
|
+
#### `get(token)`
|
|
251
|
+
|
|
252
|
+
`get<T>(token: Token<T>): T`
|
|
253
|
+
|
|
254
|
+
Alias for `make()` — identical behavior, sugar for an `app(token)`-style read.
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
const mailer = app.get(Mailer);
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Notes:** delegates straight to `make()`; use whichever name reads better.
|
|
261
|
+
|
|
262
|
+
#### `build(ctor)`
|
|
263
|
+
|
|
264
|
+
`build<T>(ctor: Constructor<T>): T`
|
|
265
|
+
|
|
266
|
+
Instantiates a class directly, passing the container to its constructor. Bypasses
|
|
267
|
+
bindings and the instance cache entirely.
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
const report = app.build(ReportService); // new ReportService(app)
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Notes:** always constructs a new instance (never cached), and ignores any
|
|
274
|
+
binding registered for the class. `make()` calls this under the hood when it
|
|
275
|
+
auto-resolves an unbound class token.
|
|
276
|
+
|
|
277
|
+
#### `bound(token)`
|
|
278
|
+
|
|
279
|
+
`bound(token: Token): boolean`
|
|
280
|
+
|
|
281
|
+
Reports whether the token has a binding **or** a cached instance.
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
if (app.bound("clock")) app.make("clock");
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Notes:** `true` for singletons even before first resolve (the binding exists).
|
|
288
|
+
|
|
289
|
+
#### `alias(alias, target)`
|
|
290
|
+
|
|
291
|
+
`alias<T>(alias: Token<T>, target: Token<T>): this`
|
|
292
|
+
|
|
293
|
+
Registers a token that resolves through to another token.
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
app.singleton(Router, () => new Router(app));
|
|
297
|
+
app.alias("router", Router);
|
|
298
|
+
app.make("router") === app.make(Router); // true — same singleton
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**Notes:** returns `this` (chainable). The alias is a thin transient wrapper that
|
|
302
|
+
calls `make(target)`, so the target keeps ownership of its own sharing — aliasing
|
|
303
|
+
a singleton still yields the one shared instance.
|
|
304
|
+
|
|
305
|
+
#### `swap(token, factory)`
|
|
306
|
+
|
|
307
|
+
`swap<T>(token: Token<T>, factory: Factory<T>): this`
|
|
308
|
+
|
|
309
|
+
Temporarily replaces a binding with a fake, for tests. The replacement is shared
|
|
310
|
+
(resolved once), and the original binding **and** any resolved instance are
|
|
311
|
+
remembered for `restore()`.
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
app.swap(Mailer, () => fakeMailer);
|
|
315
|
+
app.make(Mailer); // fakeMailer
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**Notes:** returns `this`. Idempotent per token — the first `swap` saves the
|
|
319
|
+
original, later swaps just change the fake. Clears the cached instance so the
|
|
320
|
+
next `make()` goes through the fake.
|
|
321
|
+
|
|
322
|
+
#### `restore(token?)`
|
|
323
|
+
|
|
324
|
+
`restore(token?: Token): this`
|
|
325
|
+
|
|
326
|
+
Undoes a `swap()`, restoring the original binding (and instance). Called with no
|
|
327
|
+
token, it restores **every** swap — handy in an `afterEach`.
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
app.restore(Mailer); // one token
|
|
331
|
+
app.restore(); // all swaps
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**Notes:** returns `this`. A no-op for a token that wasn't swapped. If the token
|
|
335
|
+
had no binding before the swap, `restore` removes it, leaving `bound()` false
|
|
336
|
+
again.
|
|
337
|
+
Does not consider auto-resolvable classes — an unbound class is `bound() === false`
|
|
338
|
+
yet still `make()`-able.
|
|
339
|
+
|
|
340
|
+
### Global helpers
|
|
341
|
+
|
|
342
|
+
Free functions in [`src/core/helpers.ts`](../src/core/helpers.ts) that proxy to
|
|
343
|
+
the active application's container, so you can bind and resolve from anywhere
|
|
344
|
+
without threading `this.app` through. Each calls `app()` internally, which throws
|
|
345
|
+
if no `Application` has been bootstrapped.
|
|
346
|
+
|
|
347
|
+
#### `bind(token, factory)`
|
|
348
|
+
|
|
349
|
+
`bind<T>(token: Token<T>, factory: Factory<T>): void`
|
|
350
|
+
|
|
351
|
+
Transient binding on the active application.
|
|
352
|
+
|
|
353
|
+
```ts
|
|
354
|
+
import { bind } from "@shaferllc/keel/core";
|
|
355
|
+
bind("clock", () => new Date());
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Notes:** returns `void` — unlike `Container.bind`, it does **not** return the
|
|
359
|
+
container, so these helpers don't chain.
|
|
360
|
+
|
|
361
|
+
#### `singleton(token, factory)`
|
|
362
|
+
|
|
363
|
+
`singleton<T>(token: Token<T>, factory: Factory<T>): void`
|
|
364
|
+
|
|
365
|
+
Shared binding on the active application.
|
|
366
|
+
|
|
367
|
+
```ts
|
|
368
|
+
import { singleton } from "@shaferllc/keel/core";
|
|
369
|
+
singleton(Mailer, (app) => new Mailer(app));
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
**Notes:** returns `void`. Same lazy, resolve-once semantics as `Container.singleton`.
|
|
373
|
+
|
|
374
|
+
#### `instance(token, value)`
|
|
375
|
+
|
|
376
|
+
`instance<T>(token: Token<T>, value: T): T`
|
|
377
|
+
|
|
378
|
+
Registers a pre-built value on the active application; returns the value.
|
|
379
|
+
|
|
380
|
+
```ts
|
|
381
|
+
import { instance } from "@shaferllc/keel/core";
|
|
382
|
+
const version = instance("version", "0.30.0");
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
**Notes:** the one container helper that returns its value (mirrors
|
|
386
|
+
`Container.instance`), so it composes inline.
|
|
387
|
+
|
|
388
|
+
#### `make(token)`
|
|
389
|
+
|
|
390
|
+
`make<T>(token: Token<T>): T`
|
|
391
|
+
|
|
392
|
+
Resolves a token out of the active application's container.
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
import { make } from "@shaferllc/keel/core";
|
|
396
|
+
const mailer = make(Mailer);
|
|
397
|
+
const version = make<string>("version");
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Notes:** same resolution rules and throw-on-missing behavior as `Container.make`.
|
|
401
|
+
|
|
402
|
+
#### `bound(token)`
|
|
403
|
+
|
|
404
|
+
`bound(token: Token): boolean`
|
|
405
|
+
|
|
406
|
+
Whether the token is bound or cached on the active application.
|
|
407
|
+
|
|
408
|
+
```ts
|
|
409
|
+
import { bound } from "@shaferllc/keel/core";
|
|
410
|
+
if (bound("clock")) { /* … */ }
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
**Notes:** proxies `Container.bound`.
|
|
414
|
+
|
|
415
|
+
#### `alias(alias, target)` · `swap(token, factory)` · `restore(token?)`
|
|
416
|
+
|
|
417
|
+
Global-helper forms of the container methods, resolving against the active
|
|
418
|
+
application.
|
|
419
|
+
|
|
420
|
+
```ts
|
|
421
|
+
import { alias, swap, restore } from "@shaferllc/keel/core";
|
|
422
|
+
|
|
423
|
+
alias("router", Router);
|
|
424
|
+
swap(Mailer, () => fakeMailer);
|
|
425
|
+
restore(); // undo every swap
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
**Notes:** `alias`/`swap` proxy `Container.alias`/`Container.swap`; `restore`
|
|
429
|
+
proxies `Container.restore` (no token restores all). `swap`/`restore` are for
|
|
430
|
+
tests — see [Swapping bindings in tests](#swapping-bindings-in-tests).
|
|
431
|
+
|
|
432
|
+
### Interfaces & types
|
|
433
|
+
|
|
434
|
+
#### `Token`
|
|
435
|
+
|
|
436
|
+
`type Token<T = unknown> = string | symbol | Constructor<T>`
|
|
437
|
+
|
|
438
|
+
What every binding is keyed by. Use a string/symbol for values and interfaces, or
|
|
439
|
+
a class — which doubles as its own token and can be auto-resolved when unbound.
|
|
440
|
+
|
|
441
|
+
```ts
|
|
442
|
+
const nameKey: Token<string> = "app.name";
|
|
443
|
+
const svcKey: Token<Mailer> = Mailer; // the class is the token
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
#### `Constructor`
|
|
447
|
+
|
|
448
|
+
`type Constructor<T = unknown> = new (...args: any[]) => T`
|
|
449
|
+
|
|
450
|
+
Any newable class. A class token is a `Constructor`; `build()` and auto-resolution
|
|
451
|
+
call `new ctor(container)` on it, so the constructor's first parameter receives the
|
|
452
|
+
container.
|
|
453
|
+
|
|
454
|
+
```ts
|
|
455
|
+
const ctor: Constructor<ReportService> = ReportService;
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
#### `Factory`
|
|
459
|
+
|
|
460
|
+
`type Factory<T> = (app: Container) => T`
|
|
461
|
+
|
|
462
|
+
The builder function you hand to `bind`/`singleton`. It receives the container, so
|
|
463
|
+
it can resolve dependencies while constructing the value.
|
|
464
|
+
|
|
465
|
+
```ts
|
|
466
|
+
const mailerFactory: Factory<Mailer> = (app) => new Mailer(app.make("config"));
|
|
467
|
+
```
|