@martel/calyx 0.1.0 â 1.0.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/.github/workflows/release.yml +6 -2
- package/CHANGELOG.md +6 -0
- package/README.md +130 -0
- package/benchmarks/di-benchmark.ts +15 -15
- package/benchmarks/run-calyx-lifecycle.ts +2 -2
- package/benchmarks/run-calyx.ts +2 -2
- package/bun.lock +1261 -0
- package/docs/controllers.md +2 -2
- package/docs/dependency-injection.md +1 -1
- package/docs/lifecycle.md +2 -2
- package/docs/migration.md +5 -5
- package/package.json +6 -5
- package/src/core/container.ts +252 -27
- package/src/core/decorators.ts +34 -10
- package/src/core/metadata.ts +13 -0
- package/src/core/module-ref.ts +3 -1
- package/src/http/application.ts +316 -150
- package/src/http/decorators.ts +29 -8
- package/src/http/factory.ts +4 -4
- package/src/http/router.ts +12 -0
- package/src/lifecycle/context.ts +2 -2
- package/src/lifecycle/interfaces.ts +20 -0
- package/tests/di.test.ts +11 -11
- package/tests/dynamic-module.test.ts +2 -2
- package/tests/lifecycle.test.ts +4 -4
- package/tests/phase1.test.ts +143 -0
- package/tests/phase2.test.ts +107 -0
- package/tests/phase3.test.ts +203 -0
- package/tests/routing.test.ts +4 -4
|
@@ -21,6 +21,11 @@ jobs:
|
|
|
21
21
|
with:
|
|
22
22
|
persist-credentials: false
|
|
23
23
|
|
|
24
|
+
- name: Setup Node
|
|
25
|
+
uses: actions/setup-node@v4
|
|
26
|
+
with:
|
|
27
|
+
node-version: 22
|
|
28
|
+
|
|
24
29
|
- name: Setup Bun
|
|
25
30
|
uses: oven-sh/setup-bun@v2
|
|
26
31
|
with:
|
|
@@ -35,5 +40,4 @@ jobs:
|
|
|
35
40
|
- name: Run semantic-release
|
|
36
41
|
env:
|
|
37
42
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
38
|
-
|
|
39
|
-
run: bunx semantic-release
|
|
43
|
+
run: npx semantic-release
|
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Calyx
|
|
2
|
+
|
|
3
|
+
Calyx is a high-performance, compile-ready, Bun-native TypeScript API framework modeled after the modular architecture and design patterns of **NestJS**.
|
|
4
|
+
|
|
5
|
+
It provides 100% conceptual and syntax compatibility, letting developers easily migrate NestJS applications to a native Bun runtime for **~2.5x higher throughput** and **3.5x lower latency**, with the option to compile the server directly into a single self-contained binary file.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Key Features
|
|
10
|
+
|
|
11
|
+
* **⥠Blazing Fast**: Engineered natively on `Bun.serve`, utilizing a fast radix routing engine and optimized request lifecycle executions.
|
|
12
|
+
* **ð§Đ NestJS Decorators Compatibility**: Direct mappings of `@Module()`, `@Injectable()`, `@Controller()`, `@UseGuards()`, `@UseInterceptors()`, `@UsePipes()`, and `@UseFilters()`.
|
|
13
|
+
* **ðĶ High Performance DI**: Fully featured Dependency Injection container with circular dependency protection, supporting custom (`useValue`/`useClass`/`useFactory`) and dynamic modules with **29x lower bootstrapping overhead**.
|
|
14
|
+
* **ðĄïļ Complete Request Lifecycle**: Clean request pipelines with Guards, Interceptors, Pipe transforms (with metadata), and target exception Filters.
|
|
15
|
+
* **ð Binary Compilation**: Compiles down to a single standalone executable binary with zero external runtime dependencies using `bun build --compile`.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
Initialize your project and install Calyx with your package manager:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bun add @martel/calyx reflect-metadata
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Ensure your `tsconfig.json` has legacy decorators enabled:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"compilerOptions": {
|
|
32
|
+
"experimentalDecorators": true,
|
|
33
|
+
"emitDecoratorMetadata": true
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import 'reflect-metadata';
|
|
44
|
+
import { Module, Injectable, Controller, Get, Query, UseGuards, CanActivate, ExecutionContext, VerdantFactory } from '@martel/calyx';
|
|
45
|
+
|
|
46
|
+
// 1. Define a Guard
|
|
47
|
+
@Injectable()
|
|
48
|
+
class AuthGuard implements CanActivate {
|
|
49
|
+
canActivate(context: ExecutionContext): boolean {
|
|
50
|
+
const req = context.switchToHttp().getRequest<Request>();
|
|
51
|
+
return req.headers.get('Authorization') === 'secret-token';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 2. Define a Controller
|
|
56
|
+
@Controller('items')
|
|
57
|
+
class ItemsController {
|
|
58
|
+
@Get()
|
|
59
|
+
@UseGuards(AuthGuard)
|
|
60
|
+
getItems(@Query('limit') limit?: string) {
|
|
61
|
+
return { data: ['item1', 'item2'], limit: limit ? Number(limit) : 10 };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 3. Define a Module
|
|
66
|
+
@Module({
|
|
67
|
+
controllers: [ItemsController],
|
|
68
|
+
})
|
|
69
|
+
class AppModule {}
|
|
70
|
+
|
|
71
|
+
// 4. Bootstrap Server
|
|
72
|
+
async function bootstrap() {
|
|
73
|
+
const app = await CalyxFactory.create(AppModule);
|
|
74
|
+
await app.listen(3000);
|
|
75
|
+
console.log('Calyx application is running on port 3000');
|
|
76
|
+
}
|
|
77
|
+
bootstrap();
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Performance Comparison (Benchmarks)
|
|
83
|
+
|
|
84
|
+
Measured using process-isolated `autocannon` benchmarks (100 connections, 8s, no pipelining) comparing Calyx vs NestJS (Express adapter under Bun):
|
|
85
|
+
|
|
86
|
+
| Benchmark | Calyx (Bun Native) | NestJS (Express on Bun) | Speedup | Latency Improvement |
|
|
87
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
88
|
+
| **DI Bootstrapping** | **7.81 Ξs** | 227.56 Ξs | **~29x faster** | N/A |
|
|
89
|
+
| **Raw Route Throughput** | **59,408 req/sec** | 23,148 req/sec | **2.57x faster** | **3.5x lower** (1.10ms vs 3.88ms) |
|
|
90
|
+
| **Lifecycle Pipeline (Guards/Pipes)** | **25,152 req/sec** | 10,274 req/sec | **2.45x faster** | **2.8x lower** (3.25ms vs 9.28ms) |
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Comprehensive Documentation
|
|
95
|
+
|
|
96
|
+
For detailed guides, API reference, and examples, refer to the documentation in the repository:
|
|
97
|
+
|
|
98
|
+
* ð **[Dependency Injection & Module System](file:///e:/code/verdant/docs/dependency-injection.md)**: Custom providers, modular structures, and resolution visibility.
|
|
99
|
+
* ð **[Controllers & Routing](file:///e:/code/verdant/docs/controllers.md)**: HTTP request handlers, parameters, redirects, and manual response wrappers.
|
|
100
|
+
* ð **[Request Lifecycle Pipeline](file:///e:/code/verdant/docs/lifecycle.md)**: How Guards, Interceptors, Pipes, and Exception Filters interact.
|
|
101
|
+
* ð **[Migration & Standalone Binary Compilation Guide](file:///e:/code/verdant/docs/migration.md)**: A complete handbook on moving from NestJS to Calyx and compiling to a single executable.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Commands
|
|
106
|
+
|
|
107
|
+
### Run Unit Tests
|
|
108
|
+
```bash
|
|
109
|
+
bun test
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Run Performance Benchmarks
|
|
113
|
+
```bash
|
|
114
|
+
# DI container benchmark
|
|
115
|
+
bun benchmarks/di-benchmark.ts
|
|
116
|
+
|
|
117
|
+
# HTTP server benchmark (compares Calyx vs NestJS)
|
|
118
|
+
bun benchmarks/http-benchmark.ts
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Build Binary
|
|
122
|
+
```bash
|
|
123
|
+
bun build --compile src/index.ts --outfile build/server
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
MIT
|
|
@@ -4,7 +4,7 @@ import { performance } from 'perf_hooks';
|
|
|
4
4
|
import { Module as NestModule, Injectable as NestInjectable } from '@nestjs/common';
|
|
5
5
|
import { NestFactory } from '@nestjs/core';
|
|
6
6
|
// Import calyx
|
|
7
|
-
import { Module as calyxModule, Injectable as calyxInjectable,
|
|
7
|
+
import { Module as calyxModule, Injectable as calyxInjectable, CalyxContainer } from '../src/index.ts';
|
|
8
8
|
|
|
9
9
|
// ----------------------------------------------------
|
|
10
10
|
// Setup Dependency Tree classes
|
|
@@ -12,32 +12,32 @@ import { Module as calyxModule, Injectable as calyxInjectable, calyxContainer }
|
|
|
12
12
|
|
|
13
13
|
// calyx classes
|
|
14
14
|
@calyxInjectable()
|
|
15
|
-
class
|
|
15
|
+
class CalyxService5 {}
|
|
16
16
|
|
|
17
17
|
@calyxInjectable()
|
|
18
|
-
class
|
|
19
|
-
constructor(public s5:
|
|
18
|
+
class CalyxService4 {
|
|
19
|
+
constructor(public s5: CalyxService5) {}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
@calyxInjectable()
|
|
23
|
-
class
|
|
24
|
-
constructor(public s4:
|
|
23
|
+
class CalyxService3 {
|
|
24
|
+
constructor(public s4: CalyxService4) {}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
@calyxInjectable()
|
|
28
|
-
class
|
|
29
|
-
constructor(public s3:
|
|
28
|
+
class CalyxService2 {
|
|
29
|
+
constructor(public s3: CalyxService3) {}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
@calyxInjectable()
|
|
33
|
-
class
|
|
34
|
-
constructor(public s2:
|
|
33
|
+
class CalyxService1 {
|
|
34
|
+
constructor(public s2: CalyxService2) {}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
@calyxModule({
|
|
38
|
-
providers: [
|
|
38
|
+
providers: [CalyxService1, CalyxService2, CalyxService3, CalyxService4, CalyxService5],
|
|
39
39
|
})
|
|
40
|
-
class
|
|
40
|
+
class CalyxAppModule {}
|
|
41
41
|
|
|
42
42
|
// NestJS classes
|
|
43
43
|
@NestInjectable()
|
|
@@ -83,10 +83,10 @@ async function runBenchmark() {
|
|
|
83
83
|
console.log(`Bootstrapping calyx container ${iterations} times...`);
|
|
84
84
|
const calyxStart = performance.now();
|
|
85
85
|
for (let i = 0; i < iterations; i++) {
|
|
86
|
-
const container = new
|
|
87
|
-
container.bootstrap(
|
|
86
|
+
const container = new CalyxContainer();
|
|
87
|
+
container.bootstrap(CalyxAppModule);
|
|
88
88
|
// Resolve one
|
|
89
|
-
container.getGlobalOrAnyInstance(
|
|
89
|
+
container.getGlobalOrAnyInstance(CalyxService1);
|
|
90
90
|
}
|
|
91
91
|
const calyxEnd = performance.now();
|
|
92
92
|
const calyxTime = calyxEnd - calyxStart;
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
CallHandler,
|
|
13
13
|
PipeTransform,
|
|
14
14
|
ExecutionContext,
|
|
15
|
-
|
|
15
|
+
CalyxFactory,
|
|
16
16
|
} from '../src/index.ts';
|
|
17
17
|
|
|
18
18
|
class AuthGuard implements CanActivate {
|
|
@@ -50,7 +50,7 @@ class HelloController {
|
|
|
50
50
|
class AppModule {}
|
|
51
51
|
|
|
52
52
|
async function main() {
|
|
53
|
-
const app = await
|
|
53
|
+
const app = await CalyxFactory.create(AppModule);
|
|
54
54
|
await app.listen(4003);
|
|
55
55
|
console.log('calyx lifecycle listening on 4003');
|
|
56
56
|
}
|
package/benchmarks/run-calyx.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
|
-
import { Module, Controller, Get,
|
|
2
|
+
import { Module, Controller, Get, CalyxFactory } from '../src/index.ts';
|
|
3
3
|
|
|
4
4
|
@Controller('hello')
|
|
5
5
|
class HelloController {
|
|
@@ -15,7 +15,7 @@ class HelloController {
|
|
|
15
15
|
class AppModule {}
|
|
16
16
|
|
|
17
17
|
async function main() {
|
|
18
|
-
const app = await
|
|
18
|
+
const app = await CalyxFactory.create(AppModule);
|
|
19
19
|
await app.listen(4001);
|
|
20
20
|
console.log('calyx listening on 4001');
|
|
21
21
|
}
|