@rhythmjs/rhythm 0.0.19 → 0.0.21

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 CHANGED
@@ -6,7 +6,7 @@ The composition kernel at the core of Rhythm, the Bun-native backend framework,
6
6
 
7
7
  Rhythm separates **when** something happens:
8
8
 
9
- - **Startup time: `register()`.** Runs a callback once, immediately, against the app's shared startup context. Use it to create what lives for the whole process (a DB connection, config) and, optionally, how to close it. `stop()` runs the cleanups in reverse order.
9
+ - **Startup time: `register()`.** Runs a callback once against the app's shared startup context: immediately, or, if an earlier `register` is still pending, right after it settles, so a callback always sees what the ones before it added (a failed one skips the rest and fails the app). Use it to create what lives for the whole process (a DB connection, config) and, optionally, how to close it. `stop()` runs the cleanups in reverse order.
10
10
  - **Request time: `use()`.** Adds an onion middleware step that runs on every call of the handler, before _and_ after `next()`.
11
11
 
12
12
  Four small composable functions plug into those two methods, each for one purpose:
@@ -53,7 +53,7 @@ await app.stop(); // shut down
53
53
 
54
54
  ## Startup: `register()`
55
55
 
56
- `register(callback, cleanup?)` calls `callback(ctx, app)` right away with the shared startup context. Return a promise and the first request waits for it. `cleanup(ctx, app)` is optional and runs on `stop()`; if several cleanups throw, `stop()` still runs all of them and rejects with an `AggregateError`. `Rhythm` is also `AsyncDisposable`, so `await using app = ...` stops it for you.
56
+ `register(callback, cleanup?)` calls `callback(ctx, app)` with the shared startup context, right away unless an earlier `register` is still pending. Registrations run in order, so a callback sees everything the earlier ones added, even async ones (`include`, a database connection). Return a promise and the first request waits for it; if one fails, the later ones are skipped and the first request rejects. `cleanup(ctx, app)` is optional and runs on `stop()`; if several cleanups throw, `stop()` still runs all of them and rejects with an `AggregateError`. `Rhythm` is also `AsyncDisposable`, so `await using app = ...` stops it for you.
57
57
 
58
58
  ```ts
59
59
  const app = new Rhythm().register(
package/dist/mount.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import type { Middleware, MountMiddleware, Mountable } from "./types";
1
+ import type { Input, Middleware, MountMiddleware, Mountable } from "./types";
2
2
  export declare function mount<I extends object>(plugin: Mountable<I>): MountMiddleware<I>;
3
- export declare function mount<T extends object = {}, I extends object = any>(plugin: Mountable<I> & (T extends I ? unknown : never), condition: (ctx: T) => boolean): Middleware<T>;
3
+ export declare function mount<T extends object = {}, I extends object = any>(plugin: Mountable<I> & (T extends I ? unknown : never), condition: (ctx: T) => boolean): Middleware<T> & Input<T>;
package/dist/rhythm.js CHANGED
@@ -27,21 +27,33 @@ class Rhythm extends Pipeline2 {
27
27
  #ctx = {};
28
28
  #cleanups = [];
29
29
  #ready;
30
+ #tail;
30
31
  transparent = true;
31
32
  constructor(options) {
32
33
  super({ type: "module", ...options });
33
34
  }
34
35
  register(callback, cleanup) {
35
36
  this.adopt(sourceOf2(callback));
36
- const result = callback(this.#ctx, this);
37
- if (result instanceof Promise) {
38
- this.#ready = Promise.all([this.#ready, result]);
37
+ if (this.#tail) {
38
+ this.#track(this.#tail.then(() => callback(this.#ctx, this)));
39
+ } else {
40
+ const result = callback(this.#ctx, this);
41
+ if (result instanceof Promise)
42
+ this.#track(result);
39
43
  }
40
44
  if (cleanup) {
41
45
  this.#cleanups.push(() => cleanup(this.#ctx, this));
42
46
  }
43
47
  return this;
44
48
  }
49
+ #track(pending) {
50
+ this.#ready = this.#tail = pending;
51
+ const clear = () => {
52
+ if (this.#tail === pending)
53
+ this.#tail = undefined;
54
+ };
55
+ pending.then(clear, clear);
56
+ }
45
57
  async stop() {
46
58
  const errors = [];
47
59
  while (this.#cleanups.length) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhythmjs/rhythm",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "A minimal, type-safe middleware and startup-composition kernel: register() at startup, use() per request, with derive, decorate, mount and include.",
5
5
  "homepage": "https://rhythm.js.org/rhythm",
6
6
  "license": "ISC",