@rhythmjs/rhythm 0.0.12 → 0.0.13
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/README.md +20 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ The composition kernel at the core of Rhythm, the Bun-native backend framework,
|
|
|
7
7
|
- **Onion middleware**: `use()` wraps downstream steps, running code before _and_ after `next()`.
|
|
8
8
|
- **Providers**: `provide()` registers a value or async factory that resolves once and joins the context at its position in the chain: only middleware (and mounted controllers) added after it see the value. A returned key prefixed with `#` (e.g. `"#close"`) stays out of context but is still passed in full to `dispose()`.
|
|
9
9
|
- **Encapsulated modules**: `register()` mounts a child `Rhythm`; its context stays sealed unless you explicitly export fields from it.
|
|
10
|
-
- **Readonly context**: the context passed to middleware is deeply readonly at the type level; state only changes via `
|
|
10
|
+
- **Readonly context**: the context passed to middleware is deeply readonly at the type level; `next()` takes no arguments (pure Koa style), so state only changes via `derive()` (or `provide()`), or through a value branded with the `RhythmMutable` symbol (how `RhythmRouter`/`RhythmCli`'s response objects stay mutable).
|
|
11
11
|
|
|
12
12
|
## Example
|
|
13
13
|
|
|
@@ -34,17 +34,31 @@ await app.teardown();
|
|
|
34
34
|
|
|
35
35
|
`provide()` factories run once, in declaration order, each receiving everything resolved so far via `deps`. On each `run()`, the whole chain, middleware and provider injections alike, executes in registration order, onion-style: everything only applies to what was chained after it.
|
|
36
36
|
|
|
37
|
+
### Extending the context
|
|
38
|
+
|
|
39
|
+
`next()` accepts no parameters: middleware cannot pass values downstream through it. To add fields to the context, use `derive()`, which runs your function, merges the returned fields into the context, then calls `next()` for you. The new fields are inferred and visible to everything chained after it.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { Rhythm, derive } from "@rhythmjs/rhythm";
|
|
43
|
+
|
|
44
|
+
const app = new Rhythm<{ userId: string }>()
|
|
45
|
+
.use(derive((ctx) => ({ user: { id: ctx.userId, name: "Ada" } })))
|
|
46
|
+
.use((ctx) => console.log(ctx.user.name));
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Keys prefixed with `#` are dropped from the context. For long-lived resources with teardown, use `provide()` instead.
|
|
50
|
+
|
|
37
51
|
### Module registration
|
|
38
52
|
|
|
39
53
|
```ts
|
|
54
|
+
import { Rhythm, derive } from "@rhythmjs/rhythm";
|
|
55
|
+
|
|
40
56
|
const authModule = new Rhythm<{ userId: string }>({ name: "auth" })
|
|
41
57
|
.provide(
|
|
42
58
|
() => ({ db: connectToUserDb() }),
|
|
43
59
|
(db) => db.close(),
|
|
44
60
|
)
|
|
45
|
-
.use(
|
|
46
|
-
await next({ user: ctx.db.findUser(ctx.userId) });
|
|
47
|
-
});
|
|
61
|
+
.use(derive((ctx) => ({ user: ctx.db.findUser(ctx.userId) })));
|
|
48
62
|
|
|
49
63
|
const app = new Rhythm<{ userId: string }>()
|
|
50
64
|
.register(authModule, (result) => ({ user: result.user })) // only `user` crosses back
|
|
@@ -56,7 +70,8 @@ const app = new Rhythm<{ userId: string }>()
|
|
|
56
70
|
## API
|
|
57
71
|
|
|
58
72
|
- `new Rhythm<TInput>(options?)`: creates a pipeline; `options.name`/`options.type` label errors from `register()`.
|
|
59
|
-
- `.use(fn: (ctx, next) => Promise<void> | void)`: add an onion middleware step.
|
|
73
|
+
- `.use(fn: (ctx, next) => Promise<void> | void)`: add an onion middleware step. `next()` takes no arguments; to extend the context pass a `derive()` middleware.
|
|
74
|
+
- `derive(fn: (ctx) => TExtra | Promise<TExtra>)`: middleware that merges `fn`'s result into the context and continues; the typed way to add fields.
|
|
60
75
|
- `.provide(factory: (deps) => TValue | Promise<TValue>, dispose?)`: register a provider; resolved once, injected at its chain position, disposed in reverse order on `teardown()`.
|
|
61
76
|
- `.register(other: Rhythm, exportValue?)`: mount a child `Rhythm` module; sealed by default, opt in via `exportValue`. Controllers (`RhythmRouter`, `RhythmCli`) are not modules; they mount via `.use()` instead.
|
|
62
77
|
- `.run(input)`: runs `setup()` if needed, dispatches `input` through the middleware chain.
|