@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 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,2 @@
1
+ export * from './express-server-adapter.js';
2
+ //# sourceMappingURL=index.js.map
@@ -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
@@ -0,0 +1,2 @@
1
+ export * from './modules/index.js';
2
+ export * from './http/index.js';
package/lib/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export * from './modules/index.js';
2
+ export * from './http/index.js';
3
+ //# sourceMappingURL=index.js.map
@@ -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,2 @@
1
+ export * from './express-platform-module.js';
2
+ //# sourceMappingURL=index.js.map
@@ -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
+ }