@kurdel/runtime-express 0.1.0-beta.1
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/LICENSE +21 -0
- package/README.md +39 -0
- package/lib/http/express-req-res-adapters.d.ts +10 -0
- package/lib/http/express-req-res-adapters.js +73 -0
- package/lib/http/express-req-res-adapters.js.map +1 -0
- package/lib/http/express-server-adapter.d.ts +20 -0
- package/lib/http/express-server-adapter.js +62 -0
- package/lib/http/express-server-adapter.js.map +1 -0
- package/lib/http/index.d.ts +1 -0
- package/lib/http/index.js +2 -0
- package/lib/http/index.js.map +1 -0
- package/lib/http/render-express-action-result.d.ts +7 -0
- package/lib/http/render-express-action-result.js +45 -0
- package/lib/http/render-express-action-result.js.map +1 -0
- package/lib/http/render-express-result-adapter.d.ts +9 -0
- package/lib/http/render-express-result-adapter.js +11 -0
- package/lib/http/render-express-result-adapter.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -0
- package/lib/modules/express-platform-module.d.ts +25 -0
- package/lib/modules/express-platform-module.js +44 -0
- package/lib/modules/express-platform-module.js.map +1 -0
- package/lib/modules/index.d.ts +1 -0
- package/lib/modules/index.js +2 -0
- package/lib/modules/index.js.map +1 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Andrii Sorokin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @kurdel/runtime-express
|
|
2
|
+
|
|
3
|
+
**Express-based runtime adapter** for Kurdel.
|
|
4
|
+
Provides a drop-in replacement for the native Node runtime with Express middleware support.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 📦 Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @kurdel/runtime-express
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 🚀 Usage
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { createExpressApplication } from '@kurdel/facade';
|
|
20
|
+
|
|
21
|
+
const app = await createExpressApplication({
|
|
22
|
+
modules: [],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
app.listen(3000);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 💡 Notes
|
|
31
|
+
|
|
32
|
+
* Fully compatible with `express` middlewares
|
|
33
|
+
* Uses the same `Controller` and `ActionResult` abstractions as other runtimes
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 📄 License
|
|
38
|
+
|
|
39
|
+
MIT © Andrii Sorokin
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Request, Response } from 'express';
|
|
2
|
+
import { type HttpRequest, type HttpResponse } from '@kurdel/common';
|
|
3
|
+
/**
|
|
4
|
+
* Converts Express's Request into a framework-agnostic HttpRequest.
|
|
5
|
+
*/
|
|
6
|
+
export declare function adaptExpressRequest(req: Request): HttpRequest;
|
|
7
|
+
/**
|
|
8
|
+
* Wraps Express's Response into a platform-independent HttpResponse.
|
|
9
|
+
*/
|
|
10
|
+
export declare function adaptExpressResponse(res: Response): HttpResponse;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { DEFAULT_INTERNAL_BASE } from '@kurdel/common';
|
|
2
|
+
/**
|
|
3
|
+
* Converts Express's Request into a framework-agnostic HttpRequest.
|
|
4
|
+
*/
|
|
5
|
+
export function adaptExpressRequest(req) {
|
|
6
|
+
// Normalize headers
|
|
7
|
+
const headers = {};
|
|
8
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
9
|
+
if (value !== undefined)
|
|
10
|
+
headers[key] = value;
|
|
11
|
+
}
|
|
12
|
+
// Construct query object (Express provides it already normalized)
|
|
13
|
+
const query = {};
|
|
14
|
+
for (const [key, value] of Object.entries(req.query)) {
|
|
15
|
+
query[key] = Array.isArray(value) ? value : value != null ? String(value) : '';
|
|
16
|
+
}
|
|
17
|
+
// Parse body only if present
|
|
18
|
+
let body = req.body;
|
|
19
|
+
if (typeof body === 'string') {
|
|
20
|
+
try {
|
|
21
|
+
body = JSON.parse(body);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
/* keep as string */
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Express doesn't include full URL — reconstruct from base
|
|
28
|
+
const url = new URL(req.originalUrl || req.url, DEFAULT_INTERNAL_BASE);
|
|
29
|
+
return {
|
|
30
|
+
method: req.method,
|
|
31
|
+
url: url.pathname + url.search,
|
|
32
|
+
headers,
|
|
33
|
+
body,
|
|
34
|
+
query,
|
|
35
|
+
params: req.params ?? {},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Wraps Express's Response into a platform-independent HttpResponse.
|
|
40
|
+
*/
|
|
41
|
+
export function adaptExpressResponse(res) {
|
|
42
|
+
return {
|
|
43
|
+
status(code) {
|
|
44
|
+
res.status(code);
|
|
45
|
+
return this;
|
|
46
|
+
},
|
|
47
|
+
send(body) {
|
|
48
|
+
if (body == null) {
|
|
49
|
+
res.end();
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
if (typeof body === 'object') {
|
|
53
|
+
if (!res.getHeader('content-type')) {
|
|
54
|
+
res.type('application/json');
|
|
55
|
+
}
|
|
56
|
+
res.send(JSON.stringify(body));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
res.send(String(body));
|
|
60
|
+
}
|
|
61
|
+
return this;
|
|
62
|
+
},
|
|
63
|
+
json(data) {
|
|
64
|
+
res.json(data);
|
|
65
|
+
return this;
|
|
66
|
+
},
|
|
67
|
+
redirect(code, location) {
|
|
68
|
+
res.redirect(code, location);
|
|
69
|
+
return this;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=express-req-res-adapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express-req-res-adapters.js","sourceRoot":"","sources":["../../src/http/express-req-res-adapters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAuC,MAAM,gBAAgB,CAAC;AAE5F;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,oBAAoB;IACpB,MAAM,OAAO,GAAsC,EAAE,CAAC;IACtD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACvD,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAChD,CAAC;IAED,kEAAkE;IAClE,MAAM,KAAK,GAAsC,EAAE,CAAC;IACpD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACrD,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAE,KAAkB,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/F,CAAC;IAED,6BAA6B;IAC7B,IAAI,IAAI,GAAY,GAAG,CAAC,IAAI,CAAC;IAC7B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,oBAAoB;QACtB,CAAC;IACH,CAAC;IAED,2DAA2D;IAC3D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC;IAEvE,OAAO;QACL,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,GAAG,EAAE,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM;QAC9B,OAAO;QACP,IAAI;QACJ,KAAK;QACL,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE;KACzB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAa;IAChD,OAAO;QACL,MAAM,CAAC,IAAY;YACjB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC,IAAS;YACZ,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;gBACjB,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO,IAAI,CAAC;YACd,CAAC;YAED,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,EAAE,CAAC;oBACnC,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;gBAC/B,CAAC;gBACD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YACjC,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YACzB,CAAC;YAED,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC,IAAa;YAChB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACf,OAAO,IAAI,CAAC;QACd,CAAC;QACD,QAAQ,CAAC,IAAY,EAAE,QAAgB;YACrC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;KACyB,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Express } from 'express';
|
|
2
|
+
import type { HttpRequest, HttpResponse } from '@kurdel/common';
|
|
3
|
+
import type { ServerAdapter } from '@kurdel/core/http';
|
|
4
|
+
/**
|
|
5
|
+
* Express-based implementation of ServerAdapter.
|
|
6
|
+
*
|
|
7
|
+
* Provides a seamless bridge between Express's native API and
|
|
8
|
+
* the Kurdel runtime HTTP abstraction layer.
|
|
9
|
+
*/
|
|
10
|
+
export declare class ExpressServerAdapter implements ServerAdapter<HttpRequest, HttpResponse> {
|
|
11
|
+
private readonly app;
|
|
12
|
+
private server?;
|
|
13
|
+
private handler?;
|
|
14
|
+
constructor();
|
|
15
|
+
on(cb: (req: HttpRequest, res: HttpResponse) => void | Promise<void>): void;
|
|
16
|
+
listen(port: number, hostOrCb?: string | (() => void), cb?: () => void): void;
|
|
17
|
+
close(): Promise<void>;
|
|
18
|
+
raw<T = Express>(): T | undefined;
|
|
19
|
+
url(): string;
|
|
20
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { adaptExpressRequest, adaptExpressResponse } from './express-req-res-adapters.js';
|
|
3
|
+
/**
|
|
4
|
+
* Express-based implementation of ServerAdapter.
|
|
5
|
+
*
|
|
6
|
+
* Provides a seamless bridge between Express's native API and
|
|
7
|
+
* the Kurdel runtime HTTP abstraction layer.
|
|
8
|
+
*/
|
|
9
|
+
export class ExpressServerAdapter {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.app = express();
|
|
12
|
+
this.app.use(express.json());
|
|
13
|
+
this.app.use(express.urlencoded({ extended: true }));
|
|
14
|
+
// Delegate all requests to Kurdel runtime
|
|
15
|
+
this.app.all(/.*/, async (req, res) => {
|
|
16
|
+
if (!this.handler) {
|
|
17
|
+
res.status(404).send('No handler registered.');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const request = adaptExpressRequest(req);
|
|
22
|
+
const response = adaptExpressResponse(res);
|
|
23
|
+
await Promise.resolve(this.handler(request, response));
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
console.error('[ExpressServerAdapter] Unhandled request error:', err);
|
|
27
|
+
if (!res.headersSent) {
|
|
28
|
+
res.status(500).json({ error: 'Internal Server Error' });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
on(cb) {
|
|
34
|
+
this.handler = cb;
|
|
35
|
+
}
|
|
36
|
+
listen(port, hostOrCb, cb) {
|
|
37
|
+
const done = (typeof hostOrCb === 'function' ? hostOrCb : cb) ?? (() => { });
|
|
38
|
+
if (typeof hostOrCb === 'string') {
|
|
39
|
+
this.server = this.app.listen(port, hostOrCb, done);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this.server = this.app.listen(port, done);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async close() {
|
|
46
|
+
if (this.server) {
|
|
47
|
+
await new Promise((resolve, reject) => this.server.close(err => (err ? reject(err) : resolve())));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
raw() {
|
|
51
|
+
return this.app;
|
|
52
|
+
}
|
|
53
|
+
url() {
|
|
54
|
+
const addr = this.server?.address();
|
|
55
|
+
if (!addr)
|
|
56
|
+
return 'http://localhost';
|
|
57
|
+
if (typeof addr === 'string')
|
|
58
|
+
return addr;
|
|
59
|
+
return `http://localhost:${addr.port}`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=express-server-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express-server-adapter.js","sourceRoot":"","sources":["../../src/http/express-server-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './express-server-adapter.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/http/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Response } from 'express';
|
|
2
|
+
import type { ActionResult } from '@kurdel/core/http';
|
|
3
|
+
/**
|
|
4
|
+
* Express-specific renderer for ActionResult.
|
|
5
|
+
* Compatible with Express.Response and middleware chain.
|
|
6
|
+
*/
|
|
7
|
+
export declare function renderExpressActionResult(res: Response, r: ActionResult): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Express-specific renderer for ActionResult.
|
|
3
|
+
* Compatible with Express.Response and middleware chain.
|
|
4
|
+
*/
|
|
5
|
+
export function renderExpressActionResult(res, r) {
|
|
6
|
+
switch (r.kind) {
|
|
7
|
+
case 'json':
|
|
8
|
+
res.status(r.status).json(r.body);
|
|
9
|
+
break;
|
|
10
|
+
case 'text':
|
|
11
|
+
res.status(r.status).type('text/plain').send(r.body);
|
|
12
|
+
break;
|
|
13
|
+
case 'html':
|
|
14
|
+
res
|
|
15
|
+
.status(r.status)
|
|
16
|
+
.type(r.contentType ?? 'text/html; charset=utf-8')
|
|
17
|
+
.send(r.body);
|
|
18
|
+
break;
|
|
19
|
+
case 'redirect':
|
|
20
|
+
res.redirect(r.status, r.location);
|
|
21
|
+
break;
|
|
22
|
+
case 'empty':
|
|
23
|
+
res.status(r.status).end();
|
|
24
|
+
break;
|
|
25
|
+
case 'stream': {
|
|
26
|
+
const s = r;
|
|
27
|
+
if (s.contentType)
|
|
28
|
+
res.set('Content-Type', s.contentType);
|
|
29
|
+
if (s.contentLength)
|
|
30
|
+
res.set('Content-Length', String(s.contentLength));
|
|
31
|
+
res.status(s.status);
|
|
32
|
+
const stream = s.body;
|
|
33
|
+
if (stream && typeof stream.pipe === 'function') {
|
|
34
|
+
stream.pipe(res);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
res.status(500).send('Invalid stream body');
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
default:
|
|
42
|
+
res.status(500).send('Unsupported response type');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=render-express-action-result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-express-action-result.js","sourceRoot":"","sources":["../../src/http/render-express-action-result.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,GAAa,EAAE,CAAe;IACtE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,MAAM;YACT,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM;QAER,KAAK,MAAM;YACT,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACrD,MAAM;QAER,KAAK,MAAM;YACT,GAAG;iBACA,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;iBAChB,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,0BAA0B,CAAC;iBACjD,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChB,MAAM;QAER,KAAK,UAAU;YACb,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;YACnC,MAAM;QAER,KAAK,OAAO;YACV,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC;YAC3B,MAAM;QAER,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,CAAC,GAAG,CAAwC,CAAC;YACnD,IAAI,CAAC,CAAC,WAAW;gBAAE,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;YAC1D,IAAI,CAAC,CAAC,aAAa;gBAAE,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;YAExE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAErB,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC;YACtB,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAChD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAC9C,CAAC;YACD,MAAM;QACR,CAAC;QAED;YACE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACtD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HttpResponse } from '@kurdel/common';
|
|
2
|
+
import type { ActionResult } from '@kurdel/core/http';
|
|
3
|
+
/**
|
|
4
|
+
* Type bridge between platform-agnostic HttpResponse and Express.Response.
|
|
5
|
+
*
|
|
6
|
+
* Keeps RuntimeResponseRenderer generic while delegating to
|
|
7
|
+
* Express-specific rendering logic.
|
|
8
|
+
*/
|
|
9
|
+
export declare function renderExpressResultAdapter(res: HttpResponse, result: ActionResult): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { renderExpressActionResult } from './render-express-action-result.js';
|
|
2
|
+
/**
|
|
3
|
+
* Type bridge between platform-agnostic HttpResponse and Express.Response.
|
|
4
|
+
*
|
|
5
|
+
* Keeps RuntimeResponseRenderer generic while delegating to
|
|
6
|
+
* Express-specific rendering logic.
|
|
7
|
+
*/
|
|
8
|
+
export function renderExpressResultAdapter(res, result) {
|
|
9
|
+
renderExpressActionResult(res, result);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=render-express-result-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-express-result-adapter.js","sourceRoot":"","sources":["../../src/http/render-express-result-adapter.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,GAAiB,EAAE,MAAoB;IAChF,yBAAyB,CAAC,GAA0B,EAAE,MAAM,CAAC,CAAC;AAChE,CAAC"}
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { AppModule } from '@kurdel/core/app';
|
|
2
|
+
/**
|
|
3
|
+
* Platform module for the Express.js runtime environment.
|
|
4
|
+
*
|
|
5
|
+
* ## Responsibilities
|
|
6
|
+
* - Registers the Express-specific `ServerAdapter` and `ResponseRenderer`
|
|
7
|
+
* implementations required for running Kurdel on Express.
|
|
8
|
+
*
|
|
9
|
+
* ## Provided tokens
|
|
10
|
+
* - {@link TOKENS.ServerAdapter} → {@link ExpressServerAdapter}
|
|
11
|
+
* - {@link TOKENS.ResponseRenderer} → {@link RuntimeResponseRenderer} configured with `renderExpressResultAdapter`
|
|
12
|
+
*
|
|
13
|
+
* ## Priority
|
|
14
|
+
* `ModulePriority.Platform` — ensures that the platform bindings
|
|
15
|
+
* are applied before the generic runtime modules (e.g., `ServerModule`).
|
|
16
|
+
*
|
|
17
|
+
* ## Usage
|
|
18
|
+
* Typically added automatically by {@link createExpressApplication}:
|
|
19
|
+
* ```ts
|
|
20
|
+
* const app = await createExpressApplication({
|
|
21
|
+
* modules: [MyHttpModule],
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare const ExpressPlatformModule: AppModule;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ModulePriority } from '@kurdel/core/app';
|
|
2
|
+
import { TOKENS } from '@kurdel/core/tokens';
|
|
3
|
+
import { RuntimeResponseRenderer } from '@kurdel/runtime/http';
|
|
4
|
+
import { ExpressServerAdapter } from '../http/express-server-adapter.js';
|
|
5
|
+
import { renderExpressResultAdapter } from '../http/render-express-result-adapter.js';
|
|
6
|
+
/**
|
|
7
|
+
* Platform module for the Express.js runtime environment.
|
|
8
|
+
*
|
|
9
|
+
* ## Responsibilities
|
|
10
|
+
* - Registers the Express-specific `ServerAdapter` and `ResponseRenderer`
|
|
11
|
+
* implementations required for running Kurdel on Express.
|
|
12
|
+
*
|
|
13
|
+
* ## Provided tokens
|
|
14
|
+
* - {@link TOKENS.ServerAdapter} → {@link ExpressServerAdapter}
|
|
15
|
+
* - {@link TOKENS.ResponseRenderer} → {@link RuntimeResponseRenderer} configured with `renderExpressResultAdapter`
|
|
16
|
+
*
|
|
17
|
+
* ## Priority
|
|
18
|
+
* `ModulePriority.Platform` — ensures that the platform bindings
|
|
19
|
+
* are applied before the generic runtime modules (e.g., `ServerModule`).
|
|
20
|
+
*
|
|
21
|
+
* ## Usage
|
|
22
|
+
* Typically added automatically by {@link createExpressApplication}:
|
|
23
|
+
* ```ts
|
|
24
|
+
* const app = await createExpressApplication({
|
|
25
|
+
* modules: [MyHttpModule],
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export const ExpressPlatformModule = {
|
|
30
|
+
priority: ModulePriority.Platform,
|
|
31
|
+
providers: [
|
|
32
|
+
{
|
|
33
|
+
provide: TOKENS.ServerAdapter,
|
|
34
|
+
useFactory: () => new ExpressServerAdapter(),
|
|
35
|
+
singleton: true,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
provide: TOKENS.ResponseRenderer,
|
|
39
|
+
useFactory: () => new RuntimeResponseRenderer(renderExpressResultAdapter),
|
|
40
|
+
singleton: true,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=express-platform-module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express-platform-module.js","sourceRoot":"","sources":["../../src/modules/express-platform-module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AAEvF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAc;IAC9C,QAAQ,EAAE,cAAc,CAAC,QAAQ;IACjC,SAAS,EAAE;QACT;YACE,OAAO,EAAE,MAAM,CAAC,aAAa;YAC7B,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,oBAAoB,EAAE;YAC5C,SAAS,EAAE,IAAI;SAChB;QACD;YACE,OAAO,EAAE,MAAM,CAAC,gBAAgB;YAChC,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,uBAAuB,CAAC,0BAA0B,CAAC;YACzE,SAAS,EAAE,IAAI;SAChB;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './express-platform-module.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/modules/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kurdel/runtime-express",
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
|
+
"description": "Express runtime adapter for Kurdel",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./lib/index.js",
|
|
8
|
+
"./http": "./lib/http/index.js",
|
|
9
|
+
"./modules": "./lib/modules/index.js"
|
|
10
|
+
},
|
|
11
|
+
"main": "./lib/index.js",
|
|
12
|
+
"types": "./lib/index.d.ts",
|
|
13
|
+
"files": [
|
|
14
|
+
"lib"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"prepack": "npm run build",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"test:ui": "vitest",
|
|
20
|
+
"test:watch": "vitest --watch",
|
|
21
|
+
"coverage": "vitest run --coverage",
|
|
22
|
+
"clean": "rimraf lib ../../.cache/tsconfig.runtime-express.build.tsbuildinfo",
|
|
23
|
+
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
24
|
+
"build:force": "npm run clean && tsc -p tsconfig.build.json --force && tsc-alias -p tsconfig.build.json"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"kurdel",
|
|
28
|
+
"express",
|
|
29
|
+
"adapter",
|
|
30
|
+
"framework"
|
|
31
|
+
],
|
|
32
|
+
"author": "Andrii Sorokin",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": "^20.19.0 || ^22.12.0 || >=24.0.0"
|
|
36
|
+
},
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "git+https://github.com/ignorantic/kurdel.git",
|
|
40
|
+
"directory": "packages/runtime-express"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/ignorantic/kurdel/tree/main/packages/runtime-express#readme",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/ignorantic/kurdel/issues"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public",
|
|
48
|
+
"tag": "beta"
|
|
49
|
+
},
|
|
50
|
+
"peerDependencies": {
|
|
51
|
+
"express": "^4.18.0 || ^5.0.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/express": "^5.0.3",
|
|
55
|
+
"@types/node": "^20.9.0",
|
|
56
|
+
"@types/supertest": "^6.0.3",
|
|
57
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
58
|
+
"rimraf": "^6.0.1",
|
|
59
|
+
"supertest": "^7.1.4",
|
|
60
|
+
"tsc-alias": "^1.8.16"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"@kurdel/common": "0.1.0-beta.1",
|
|
64
|
+
"@kurdel/core": "0.1.0-beta.1",
|
|
65
|
+
"@kurdel/runtime": "0.1.0-beta.1"
|
|
66
|
+
}
|
|
67
|
+
}
|