@rhythmjs/rhythm 0.0.9 → 0.0.11

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/dist/compose.d.ts CHANGED
@@ -1,11 +1,10 @@
1
- import { DeriveMiddleware, Middleware, NextFn } from "./types.js";
2
- //#region src/compose.d.ts
3
- type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never;
1
+ import type { DeriveMiddleware, Middleware, NextFn } from "./types";
2
+ type UnionToIntersection<U> = (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
4
3
  type ContextOf<M> = M extends Middleware<infer C> ? C : never;
5
4
  type ExtraOf<M> = M extends DeriveMiddleware<any, infer E> ? E : {};
6
5
  export type ComposedMiddleware<TContext extends object, TExtra extends object> = ((context: TContext, next?: NextFn<TContext>) => Promise<TContext>) & Middleware<TContext> & {
7
- readonly "~derive": TExtra;
6
+ readonly "~derive": TExtra;
8
7
  };
9
8
  export declare function compose<const TMiddleware extends readonly Middleware<any>[]>(middleware: TMiddleware): ComposedMiddleware<UnionToIntersection<ContextOf<TMiddleware[number]>> & {}, UnionToIntersection<ExtraOf<TMiddleware[number]>> & {}>;
10
9
  export declare function compose<TContext extends object>(middleware: Middleware<TContext>[]): (context: TContext, next?: NextFn<TContext>) => Promise<TContext>;
11
- //#endregion
10
+ export {};
package/dist/compose.js CHANGED
@@ -1,24 +1,7 @@
1
- //#region src/compose.ts
2
- function compose(middleware) {
3
- if (!Array.isArray(middleware)) throw new TypeError("Middleware stack must be an array!");
4
- for (const fn of middleware) if (typeof fn !== "function") throw new TypeError("Middleware must be composed of functions!");
5
- return function(context, next) {
6
- let index = -1;
7
- return dispatch(0);
8
- function dispatch(i) {
9
- if (i <= index) return Promise.reject(/* @__PURE__ */ new Error("next() called multiple times"));
10
- index = i;
11
- const fn = i === middleware.length ? next : middleware[i];
12
- if (!fn) return Promise.resolve(context);
13
- const dispatchNext = () => dispatch(i + 1);
14
- try {
15
- const call = fn;
16
- return Promise.resolve(call(context, dispatchNext)).then(() => context);
17
- } catch (err) {
18
- return Promise.reject(err);
19
- }
20
- }
21
- };
22
- }
23
- //#endregion
24
- export { compose };
1
+ // @bun
2
+ import {
3
+ compose2
4
+ } from "./rhythm-d9ycs7zz.js";
5
+ export {
6
+ compose2 as compose
7
+ };
@@ -0,0 +1,31 @@
1
+ // @bun
2
+ // src/compose.ts
3
+ function compose2(middleware) {
4
+ if (!Array.isArray(middleware))
5
+ throw new TypeError("Middleware stack must be an array!");
6
+ for (const fn of middleware) {
7
+ if (typeof fn !== "function")
8
+ throw new TypeError("Middleware must be composed of functions!");
9
+ }
10
+ return function(context, next) {
11
+ let index = -1;
12
+ return dispatch(0);
13
+ function dispatch(i) {
14
+ if (i <= index)
15
+ return Promise.reject(new Error("next() called multiple times"));
16
+ index = i;
17
+ const fn = i === middleware.length ? next : middleware[i];
18
+ if (!fn)
19
+ return Promise.resolve(context);
20
+ const dispatchNext = () => dispatch(i + 1);
21
+ try {
22
+ const call = fn;
23
+ return Promise.resolve(call(context, dispatchNext)).then(() => context);
24
+ } catch (err) {
25
+ return Promise.reject(err);
26
+ }
27
+ }
28
+ };
29
+ }
30
+
31
+ export { compose2 };
package/dist/rhythm.d.ts CHANGED
@@ -1,22 +1,20 @@
1
- import { DeriveMiddleware, Middleware, OmitHashKeys } from "./types.js";
2
- //#region src/rhythm.d.ts
1
+ import type { DeriveMiddleware, Middleware, OmitHashKeys } from "./types";
3
2
  export interface RhythmOptions {
4
- name?: string;
5
- type?: string;
6
- [key: string]: unknown;
3
+ name?: string;
4
+ type?: string;
5
+ [key: string]: unknown;
7
6
  }
8
7
  export declare function derive<TContext extends object, TExtra extends object>(fn: (ctx: TContext) => TExtra | Promise<TExtra>): DeriveMiddleware<TContext, OmitHashKeys<TExtra>>;
9
8
  export declare class Rhythm<TInput extends object = {}, TContext extends object = TInput, TProviders extends object = {}> {
10
- #private;
11
- constructor(options?: RhythmOptions);
12
- use<TExtra extends object>(fn: DeriveMiddleware<TContext, TExtra>): Rhythm<TInput, TContext & TExtra, TProviders>;
13
- use(fn: Middleware<TContext>): this;
14
- provide<TValue extends object>(factory: (deps: TProviders) => TValue | Promise<TValue>, dispose?: (value: TValue) => void | Promise<void>): Rhythm<TInput, TContext & OmitHashKeys<TValue>, TProviders & OmitHashKeys<TValue>>;
15
- register<TRegInput extends object, TRegContext extends object, TExported extends object = {}>(other: Rhythm<TRegInput, TRegContext, any> & (TContext extends TRegInput ? unknown : never), exportValue?: (result: TRegContext) => TExported): Rhythm<TInput, TContext & TExported, TProviders>;
16
- setup(): Promise<void>;
17
- teardown(): Promise<void>;
18
- callback(): (input: TInput) => Promise<TContext>;
19
- run(input: TInput): Promise<TContext>;
20
- middleware(): Middleware<TContext>;
9
+ #private;
10
+ constructor(options?: RhythmOptions);
11
+ use<TExtra extends object>(fn: DeriveMiddleware<TContext, TExtra>): Rhythm<TInput, TContext & TExtra, TProviders>;
12
+ use(fn: Middleware<TContext>): this;
13
+ provide<TValue extends object>(factory: (deps: TProviders) => TValue | Promise<TValue>, dispose?: (value: TValue) => void | Promise<void>): Rhythm<TInput, TContext & OmitHashKeys<TValue>, TProviders & OmitHashKeys<TValue>>;
14
+ register<TRegInput extends object, TRegContext extends object, TExported extends object = {}>(other: Rhythm<TRegInput, TRegContext, any> & (TContext extends TRegInput ? unknown : never), exportValue?: (result: TRegContext) => TExported): Rhythm<TInput, TContext & TExported, TProviders>;
15
+ setup(): Promise<void>;
16
+ teardown(): Promise<void>;
17
+ callback(): (input: TInput) => Promise<TContext>;
18
+ run(input: TInput): Promise<TContext>;
19
+ middleware(): Middleware<TContext>;
21
20
  }
22
- //#endregion
package/dist/rhythm.js CHANGED
@@ -1,105 +1,118 @@
1
- import { compose } from "./compose.js";
2
- //#region src/rhythm.ts
1
+ // @bun
2
+ import {
3
+ compose2
4
+ } from "./rhythm-d9ycs7zz.js";
5
+
6
+ // src/rhythm.ts
3
7
  function publicEntries(value) {
4
- const exported = {};
5
- for (const [key, val] of Object.entries(value)) if (!key.startsWith("#")) exported[key] = val;
6
- return exported;
8
+ const exported = {};
9
+ for (const [key, val] of Object.entries(value)) {
10
+ if (!key.startsWith("#"))
11
+ exported[key] = val;
12
+ }
13
+ return exported;
7
14
  }
8
15
  function derive(fn) {
9
- if (typeof fn !== "function") throw new TypeError("derive factory must be a function!");
10
- const middleware = async (ctx, next) => {
11
- const value = await fn(ctx);
12
- Object.assign(ctx, publicEntries(value));
13
- await next();
14
- };
15
- return middleware;
16
+ if (typeof fn !== "function")
17
+ throw new TypeError("derive factory must be a function!");
18
+ const middleware = async (ctx, next) => {
19
+ const value = await fn(ctx);
20
+ Object.assign(ctx, publicEntries(value));
21
+ await next();
22
+ };
23
+ return middleware;
16
24
  }
17
- var Rhythm = class {
18
- #middleware = [];
19
- #options;
20
- #providers = [];
21
- #setupPromise = null;
22
- constructor(options = {}) {
23
- this.#options = options;
24
- }
25
- use(fn) {
26
- if (typeof fn !== "function") throw new TypeError("middleware must be a function!");
27
- this.#middleware.push(fn);
28
- return this;
29
- }
30
- provide(factory, dispose) {
31
- const entry = {
32
- factory,
33
- dispose
34
- };
35
- this.#providers.push(entry);
36
- this.#middleware.push(async (ctx, next) => {
37
- Object.assign(ctx, publicEntries(entry.resolved));
38
- await next();
39
- });
40
- return this;
41
- }
42
- register(other, exportValue) {
43
- const module = other;
44
- this.#providers.push({
45
- factory: async () => {
46
- await module.setup();
47
- return {};
48
- },
49
- dispose: () => module.teardown()
50
- });
51
- this.#middleware.push(async (ctx, next) => {
52
- let result;
53
- try {
54
- result = await module.run(ctx);
55
- } catch (cause) {
56
- const { type = "module", name = "anonymous" } = module.#options;
57
- throw new Error(`registered ${type} "${name}" failed`, { cause });
58
- }
59
- if (exportValue) Object.assign(ctx, exportValue(result));
60
- await next();
61
- });
62
- return this;
63
- }
64
- setup() {
65
- if (!this.#setupPromise) this.#setupPromise = this.#resolveProviders().catch((err) => {
66
- this.#setupPromise = null;
67
- throw err;
68
- });
69
- return this.#setupPromise;
70
- }
71
- async #resolveProviders() {
72
- const resolved = {};
73
- for (const entry of this.#providers) {
74
- entry.resolved = await entry.factory(resolved);
75
- Object.assign(resolved, publicEntries(entry.resolved));
76
- }
77
- }
78
- async teardown() {
79
- for (const entry of [...this.#providers].reverse()) {
80
- if (entry.resolved === void 0) continue;
81
- await entry.dispose?.(entry.resolved);
82
- entry.resolved = void 0;
83
- }
84
- this.#setupPromise = null;
85
- }
86
- callback() {
87
- const fn = compose([...this.#middleware]);
88
- return async (input) => {
89
- await this.setup();
90
- return fn({ ...input });
91
- };
92
- }
93
- run(input) {
94
- return this.callback()(input);
95
- }
96
- middleware() {
97
- const fn = compose([...this.#middleware]);
98
- return async (ctx, next) => {
99
- await this.setup();
100
- await fn(ctx, next);
101
- };
102
- }
25
+
26
+ class Rhythm {
27
+ #middleware = [];
28
+ #options;
29
+ #providers = [];
30
+ #setupPromise = null;
31
+ constructor(options = {}) {
32
+ this.#options = options;
33
+ }
34
+ use(fn) {
35
+ if (typeof fn !== "function")
36
+ throw new TypeError("middleware must be a function!");
37
+ this.#middleware.push(fn);
38
+ return this;
39
+ }
40
+ provide(factory, dispose) {
41
+ const entry = { factory, dispose };
42
+ this.#providers.push(entry);
43
+ this.#middleware.push(async (ctx, next) => {
44
+ Object.assign(ctx, publicEntries(entry.resolved));
45
+ await next();
46
+ });
47
+ return this;
48
+ }
49
+ register(other, exportValue) {
50
+ const module = other;
51
+ this.#providers.push({
52
+ factory: async () => {
53
+ await module.setup();
54
+ return {};
55
+ },
56
+ dispose: () => module.teardown()
57
+ });
58
+ this.#middleware.push(async (ctx, next) => {
59
+ let result;
60
+ try {
61
+ result = await module.run(ctx);
62
+ } catch (cause) {
63
+ const { type = "module", name = "anonymous" } = module.#options;
64
+ throw new Error(`registered ${type} "${name}" failed`, { cause });
65
+ }
66
+ if (exportValue)
67
+ Object.assign(ctx, exportValue(result));
68
+ await next();
69
+ });
70
+ return this;
71
+ }
72
+ setup() {
73
+ if (!this.#setupPromise) {
74
+ this.#setupPromise = this.#resolveProviders().catch((err) => {
75
+ this.#setupPromise = null;
76
+ throw err;
77
+ });
78
+ }
79
+ return this.#setupPromise;
80
+ }
81
+ async#resolveProviders() {
82
+ const resolved = {};
83
+ for (const entry of this.#providers) {
84
+ entry.resolved = await entry.factory(resolved);
85
+ Object.assign(resolved, publicEntries(entry.resolved));
86
+ }
87
+ }
88
+ async teardown() {
89
+ for (const entry of [...this.#providers].reverse()) {
90
+ if (entry.resolved === undefined)
91
+ continue;
92
+ await entry.dispose?.(entry.resolved);
93
+ entry.resolved = undefined;
94
+ }
95
+ this.#setupPromise = null;
96
+ }
97
+ callback() {
98
+ const fn = compose2([...this.#middleware]);
99
+ return async (input) => {
100
+ await this.setup();
101
+ return fn({ ...input });
102
+ };
103
+ }
104
+ run(input) {
105
+ return this.callback()(input);
106
+ }
107
+ middleware() {
108
+ const fn = compose2([...this.#middleware]);
109
+ return async (ctx, next) => {
110
+ await this.setup();
111
+ await fn(ctx, next);
112
+ };
113
+ }
114
+ }
115
+ export {
116
+ Rhythm,
117
+ derive
103
118
  };
104
- //#endregion
105
- export { Rhythm, derive };
package/dist/types.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- //#region src/types.d.ts
2
- export type OmitHashKeys<T> = { [K in keyof T as K extends `#${string}` ? never : K]: T[K]; };
1
+ export type OmitHashKeys<T> = {
2
+ [K in keyof T as K extends `#${string}` ? never : K]: T[K];
3
+ };
3
4
  export type NextFn<TContext extends object> = () => Promise<TContext>;
4
5
  export type Middleware<TContext extends object> = (ctx: TContext, next: NextFn<TContext>) => Promise<void> | void;
5
6
  export type DeriveMiddleware<TContext extends object, TExtra extends object> = Middleware<TContext> & {
6
- readonly "~derive": TExtra;
7
+ readonly "~derive": TExtra;
7
8
  };
8
- //#endregion
package/dist/types.js CHANGED
@@ -1 +1 @@
1
- export {};
1
+ // @bun
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhythmjs/rhythm",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "A minimal, type-safe onion-middleware and provider composition kernel.",
5
5
  "homepage": "https://rhythm.js.org/rhythm",
6
6
  "license": "ISC",
@@ -33,11 +33,16 @@
33
33
  "access": "public"
34
34
  },
35
35
  "devDependencies": {
36
+ "@types/bun": "^1.4.2",
36
37
  "@types/node": "^26.6.3",
37
- "typescript": "^7.0.2",
38
- "vite-plus": "^1.0.0"
38
+ "typescript": "^7.0.2"
39
39
  },
40
40
  "engines": {
41
- "node": ">=20.19.0"
41
+ "bun": ">=1.2.0"
42
+ },
43
+ "scripts": {
44
+ "build": "bun build src/rhythm.ts src/compose.ts src/types.ts --outdir dist --root src --format esm --target bun --packages external --splitting && tsc -p tsconfig.build.json",
45
+ "typecheck": "tsc --noEmit",
46
+ "test": "bun test"
42
47
  }
43
48
  }