From d9a984cbea887495944f9b7d7430650a040241dc Mon Sep 17 00:00:00 2001 From: "Max P." Date: Tue, 27 May 2025 13:32:27 +0200 Subject: [PATCH 01/14] chore(tasks): add benchmark, format, and lint commands - Introduces a benchmark task for running performance tests - Adds format and lint tasks to enforce code style and quality --- deno.jsonc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/deno.jsonc b/deno.jsonc index 99e1327..2707c45 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -6,7 +6,10 @@ }, "tasks": { "test": "deno test --allow-net --allow-env --unstable-kv --allow-read --allow-write --coverage **/__tests__/*.test.ts", - "test:watch": "deno test --watch --allow-net --allow-env --unstable-kv --allow-read --allow-write **/__tests__/*.test.ts" + "test:watch": "deno test --watch --allow-net --allow-env --unstable-kv --allow-read --allow-write **/__tests__/*.test.ts", + "benchmark": "deno bench --allow-net --allow-env --unstable-kv --allow-read --allow-write **/__bench__/*.bench.ts", + "fmt": "deno fmt --check", + "lint": "deno lint" }, "compilerOptions": { "lib": [ @@ -29,5 +32,4 @@ "main.ts" ] } - //"importMap": "./import_map.json" } \ No newline at end of file -- 2.49.1 From af32f3b9f4905469def8c22239ef3de4b5c3ea54 Mon Sep 17 00:00:00 2001 From: "Max P." Date: Tue, 27 May 2025 13:32:38 +0200 Subject: [PATCH 02/14] chore(ci): update deno tasks in CI workflow - Replace individual deno commands with `deno task` equivalents - Add benchmark task to the CI workflow for performance testing --- .gitea/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 12e33a5..a28dbd6 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -24,6 +24,7 @@ jobs: - name: Run CI Checks run: | - deno fmt --check - deno lint + deno task fmt + deno task lint deno task test + deno task benchmark -- 2.49.1 From 2d3dacc35802d2ffd6c6eda22df5761dd2d03f74 Mon Sep 17 00:00:00 2001 From: "Max P." Date: Tue, 27 May 2025 13:32:48 +0200 Subject: [PATCH 03/14] chore(gitignore): add .local directory to ignored files - Updates .gitignore to include the .local directory - Prevents accidental commits of local configuration files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f2d2248..456454a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ coverage/ logs/ .locale/ +.local/ cache/ out.py output.txt -- 2.49.1 From ba3d2e33f2a3bd690cbc1f291fea07466a94b7d5 Mon Sep 17 00:00:00 2001 From: "Max P." Date: Tue, 27 May 2025 14:48:05 +0200 Subject: [PATCH 04/14] test(bench): add parallel benchmarks for HTTP kernel - Introduce parallel benchmarks for simple and complex HTTP requests - Improve performance testing with higher concurrency (10,000 requests) - Comment out single-request benchmarks for future reference --- src/__bench__/HttpKernel.bench.ts | 87 +++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/__bench__/HttpKernel.bench.ts diff --git a/src/__bench__/HttpKernel.bench.ts b/src/__bench__/HttpKernel.bench.ts new file mode 100644 index 0000000..d08a4bf --- /dev/null +++ b/src/__bench__/HttpKernel.bench.ts @@ -0,0 +1,87 @@ +import type { IRouteDefinition } from '../Interfaces/mod.ts'; +import { HttpKernel } from '../mod.ts'; + +const CONCURRENT_REQUESTS = 10000; + +// Deno.bench('Simple request', async (b) => { +// const kernel = new HttpKernel(); + +// const def: IRouteDefinition = { method: 'GET', path: '/hello' }; +// kernel.route(def).handle((_ctx) => { +// return Promise.resolve(new Response('OK', { status: 200 })); +// }); +// b.start(); +// await kernel.handle( +// new Request('http://localhost/hello', { method: 'GET' }), +// ); +// b.end(); +// }); + +Deno.bench('Simple request (parallel)', async (b) => { + const kernel = new HttpKernel(); + + const def: IRouteDefinition = { method: 'GET', path: '/hello' }; + kernel.route(def).handle((_ctx) => { + return Promise.resolve(new Response('OK', { status: 200 })); + }); + + const requests = Array.from( + { length: CONCURRENT_REQUESTS }, + () => + kernel.handle( + new Request('http://localhost/hello', { method: 'GET' }), + ), + ); + + b.start(); + await Promise.all(requests); + b.end(); +}); + +// Deno.bench('Complex request', async (b) => { +// const kernel = new HttpKernel(); + +// kernel.route({ method: 'GET', path: '/test' }) +// .middleware(async (_ctx, next) => { +// return await next(); +// }) +// .middleware(async (_ctx, next) => { +// return await next(); +// }) +// .handle((_ctx) => { +// return Promise.resolve(new Response('done')); +// }); + +// b.start(); +// await kernel.handle( +// new Request('http://localhost/test', { method: 'GET' }), +// ); +// b.end(); +// }); + +Deno.bench('Complex request (parallel)', async (b) => { + const kernel = new HttpKernel(); + + kernel.route({ method: 'GET', path: '/test' }) + .middleware(async (_ctx, next) => { + return await next(); + }) + .middleware(async (_ctx, next) => { + return await next(); + }) + .handle((_ctx) => { + return Promise.resolve(new Response('done')); + }); + + const requests = Array.from( + { length: CONCURRENT_REQUESTS }, + () => + kernel.handle( + new Request('http://localhost/test', { method: 'GET' }), + ), + ); + + b.start(); + await Promise.all(requests); + b.end(); +}); -- 2.49.1 From beadcefc6af6c31e5f123ca7348acb224ac930aa Mon Sep 17 00:00:00 2001 From: "Max P." Date: Tue, 27 May 2025 14:49:15 +0200 Subject: [PATCH 05/14] feat(interfaces): add runRoute method to IInternalRoute - Introduces a statically compiled `runRoute` method to encapsulate the middleware chain and final handler execution for routes. - Ensures consistent pipeline execution with safeguards like single `next()` invocation and a guaranteed `Response` return type. --- src/Interfaces/IInternalRoute.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Interfaces/IInternalRoute.ts b/src/Interfaces/IInternalRoute.ts index 7fc7d66..fd3e33f 100644 --- a/src/Interfaces/IInternalRoute.ts +++ b/src/Interfaces/IInternalRoute.ts @@ -36,4 +36,29 @@ export interface IInternalRoute { * The final handler that generates the HTTP response after all middleware has run. */ handler: Handler; + + /** + * The fully compiled execution pipeline for this route. + * + * This function is generated at route registration time and encapsulates the + * entire middleware chain as well as the final handler. It is called by the + * HttpKernel during request dispatch when a route has been matched. + * + * Internally, `runRoute` ensures that each middleware is invoked in the correct order + * and receives a `next()` callback to pass control downstream. The final handler is + * invoked once all middleware has completed or short-circuited the pipeline. + * + * It is guaranteed that: + * - The function is statically compiled and does not perform dynamic dispatching. + * - Each middleware can only call `next()` once; repeated invocations will throw. + * - The return value is either a `Response` or a Promise resolving to one. + * + * @param ctx - The context object carrying route, request, response and other scoped data. + * @returns A `Response` object or a Promise resolving to a `Response`. + * + * @throws {Error} If a middleware calls `next()` more than once. + */ + runRoute: ( + ctx: TContext, + ) => Promise | Response; } -- 2.49.1 From 91708a0499a98dc9c3b43e423d66fc12abc1cc21 Mon Sep 17 00:00:00 2001 From: "Max P." Date: Tue, 27 May 2025 14:49:32 +0200 Subject: [PATCH 06/14] feat(route-builder): add middleware chain compilation - Introduces a `compile` method to compose middleware and handler into a single executable function. - Enhances runtime safety by ensuring `next()` is called only once per middleware and validating middleware/handler signatures. - Improves code structure and maintainability for route execution. --- src/RouteBuilder.ts | 79 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/RouteBuilder.ts b/src/RouteBuilder.ts index d09a11a..7635058 100644 --- a/src/RouteBuilder.ts +++ b/src/RouteBuilder.ts @@ -1,10 +1,17 @@ import type { IRouteMatcherFactory } from './Interfaces/IRouteMatcher.ts'; import type { IContext, + IInternalRoute, IRouteBuilder, IRouteDefinition, } from './Interfaces/mod.ts'; -import type { Handler, Middleware, RegisterRoute } from './Types/mod.ts'; +import { isHandler } from './Types/Handler.ts'; +import { + type Handler, + isMiddleware, + type Middleware, + type RegisterRoute, +} from './Types/mod.ts'; import { createRouteMatcher } from './Utils/createRouteMatcher.ts'; /** @@ -66,6 +73,76 @@ export class RouteBuilder matcher, middlewares: this.mws, handler: handler, + runRoute: this.compile({ + middlewares: this.mws, + handler: handler, + }), }); } + + /** + * Compiles the middleware chain and handler into a single executable function. + * + * This method constructs a statically linked function chain by reducing all middleware + * and the final handler into one composed `runRoute` function. Each middleware receives + * a `next()` callback that invokes the next function in the chain. + * + * Additionally, the returned function ensures that `next()` can only be called once + * per middleware. If `next()` is invoked multiple times within the same middleware, + * a runtime `Error` is thrown, preventing unintended double-processing. + * + * Type safety is enforced at compile time: + * - If the final handler does not match the expected signature, a `TypeError` is thrown. + * - If any middleware does not conform to the middleware interface, a `TypeError` is thrown. + * + * @param route - A partial route object containing middleware and handler, + * excluding `matcher`, `method`, and `runRoute`. + * @returns A composed route execution function that takes a context object + * and returns a `Promise`. + * + * @throws {TypeError} If the handler or any middleware function is invalid. + * @throws {Error} If a middleware calls `next()` more than once during execution. + */ + private compile( + route: Omit< + IInternalRoute, + 'runRoute' | 'matcher' | 'method' + >, + ): ( + ctx: TContext, + ) => Promise { + if (!isHandler(route.handler)) { + throw new TypeError( + 'Route handler must be a function returning a Promise.', + ); + } + let composed = route.handler; + + for (let i = route.middlewares.length - 1; i >= 0; i--) { + if (!isMiddleware(route.middlewares[i])) { + throw new TypeError( + `Middleware at index ${i} is not a valid function.`, + ); + } + + const current = route.middlewares[i]; + const next = composed; + + composed = async (ctx: TContext): Promise => { + let called = false; + + return await current(ctx, async () => { + if (called) { + throw new Error( + `next() called multiple times in middleware at index ${i}`, + ); + } + called = true; + return await next(ctx); + }); + }; + } + + return composed; + } } -- 2.49.1 From 8243b07a5af921c2c81f9b7d10765138aa274915 Mon Sep 17 00:00:00 2001 From: "Max P." Date: Tue, 27 May 2025 14:49:47 +0200 Subject: [PATCH 07/14] refactor(kernel): simplify middleware and handler execution - Replace middleware pipeline logic with route-specific execution - Remove redundant type checks and streamline error handling - Improve maintainability by delegating response decoration to routes --- src/HttpKernel.ts | 83 ++++++++--------------------------------------- 1 file changed, 14 insertions(+), 69 deletions(-) diff --git a/src/HttpKernel.ts b/src/HttpKernel.ts index 26aefb8..fa6c778 100644 --- a/src/HttpKernel.ts +++ b/src/HttpKernel.ts @@ -8,13 +8,9 @@ import type { } from './Interfaces/mod.ts'; import { type DeepPartial, - type Handler, HTTP_404_NOT_FOUND, HTTP_500_INTERNAL_SERVER_ERROR, HttpStatusTextMap, - isHandler, - isMiddleware, - type Middleware, } from './Types/mod.ts'; import { RouteBuilder } from './RouteBuilder.ts'; import { createEmptyContext, normalizeError } from './Utils/mod.ts'; @@ -108,11 +104,12 @@ export class HttpKernel query: match.query, state: {}, } as TContext; - return await this.executePipeline( - ctx, - route.middlewares, - route.handler, - ); + try { + const response = await route.runRoute(ctx); + return this.cfg.decorateResponse(response, ctx); + } catch (e) { + return await this.handleInternalError(ctx, e); + } } } @@ -135,65 +132,13 @@ export class HttpKernel this.routes.push(route as unknown as IInternalRoute); } - /** - * Executes the middleware and handler pipeline for a matched route. - * - * This function: - * - Enforces linear middleware execution with `next()` tracking - * - Validates middleware and handler types at runtime - * - Applies the optional response decorator post-processing - * - Handles all runtime errors via the configured 500 handler - * - * @param ctx - The active request context passed to middleware and handler. - * @param middleware - Ordered middleware functions for this route. - * @param handler - The final handler responsible for generating a response. - * @returns The final HTTP `Response`, possibly decorated. - */ - private async executePipeline( + private handleInternalError = ( ctx: TContext, - middleware: Middleware[], - handler: Handler, - ): Promise { - const handleInternalError = (ctx: TContext, err?: unknown) => - this.cfg.httpErrorHandlers[HTTP_500_INTERNAL_SERVER_ERROR]( - ctx, - normalizeError(err), - ); - - let lastIndex = -1; - - const dispatch = async (currentIndex: number): Promise => { - if (currentIndex <= lastIndex) { - throw new Error('Middleware called `next()` multiple times'); - } - lastIndex = currentIndex; - - const isWithinMiddleware = currentIndex < middleware.length; - const fn = isWithinMiddleware ? middleware[currentIndex] : handler; - - if (isWithinMiddleware) { - if (!isMiddleware(fn)) { - throw new Error( - 'Expected middleware function, but received invalid value', - ); - } - return await fn(ctx, () => dispatch(currentIndex + 1)); - } - - if (!isHandler(fn)) { - throw new Error( - 'Expected request handler, but received invalid value', - ); - } - - return await fn(ctx); - }; - - try { - const response = await dispatch(0); - return this.cfg.decorateResponse(response, ctx); - } catch (e) { - return handleInternalError(ctx, e); - } - } + err?: unknown, + ): Response | Promise => { + return this.cfg.httpErrorHandlers[HTTP_500_INTERNAL_SERVER_ERROR]( + ctx, + normalizeError(err), + ); + }; } -- 2.49.1 From b3ed8dd52c25a7c2653245749ce62ecb81001573 Mon Sep 17 00:00:00 2001 From: "Max P." Date: Tue, 27 May 2025 14:50:01 +0200 Subject: [PATCH 08/14] test(httpkernel): enforce compile-time validation for signatures - Replace runtime 500 errors with compile-time validation for invalid middleware and handler signatures using `assertThrows` - Improve test clarity by explicitly checking for expected exceptions and error messages --- src/__tests__/HttpKernel.test.ts | 47 ++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/__tests__/HttpKernel.test.ts b/src/__tests__/HttpKernel.test.ts index a9c32c3..2348046 100644 --- a/src/__tests__/HttpKernel.test.ts +++ b/src/__tests__/HttpKernel.test.ts @@ -1,4 +1,7 @@ -import { assertEquals } from 'https://deno.land/std@0.204.0/assert/mod.ts'; +import { + assertEquals, + assertThrows, +} from 'https://deno.land/std@0.204.0/assert/mod.ts'; import { HttpKernel } from '../HttpKernel.ts'; import type { IRouteDefinition } from '../Interfaces/mod.ts'; @@ -88,30 +91,32 @@ Deno.test('HttpKernel: middleware short-circuits pipeline', async () => { assertEquals(calls, ['mw1']); }); -Deno.test('HttpKernel: invalid middleware or handler signature triggers 500', async () => { +Deno.test('HttpKernel: invalid middleware or handler signature throws at compile time', () => { const kernel = new HttpKernel(); // Middleware with wrong signature (missing ctx, next) - kernel.route({ method: 'GET', path: '/bad-mw' }) - // @ts-expect-error invalid middleware - .middleware(() => new Response('invalid')) - .handle((_ctx) => Promise.resolve(new Response('ok'))); - - const res1 = await kernel.handle(new Request('http://localhost/bad-mw')); - assertEquals(res1.status, 500); - assertEquals(await res1.text(), 'Internal Server Error'); + assertThrows( + () => { + kernel.route({ method: 'GET', path: '/bad-mw' }) + // @ts-expect-error invalid middleware + .middleware(() => new Response('invalid')) + .handle((_ctx) => Promise.resolve(new Response('ok'))); + }, + TypeError, + 'Middleware at index 0 is not a valid function.', + ); // Handler with wrong signature (no ctx) - kernel.route({ method: 'GET', path: '/bad-handler' }) - .middleware(async (_ctx, next) => await next()) - // @ts-expect-error invalid handler - .handle(() => new Response('invalid')); - - const res2 = await kernel.handle( - new Request('http://localhost/bad-handler'), + assertThrows( + () => { + kernel.route({ method: 'GET', path: '/bad-handler' }) + .middleware(async (_ctx, next) => await next()) + // @ts-expect-error invalid handler + .handle(() => new Response('invalid')); + }, + TypeError, + 'Route handler must be a function returning a Promise.', ); - assertEquals(res2.status, 500); - assertEquals(await res2.text(), 'Internal Server Error'); }); Deno.test('HttpKernel: 404 for unmatched route', async () => { @@ -124,7 +129,7 @@ Deno.test('HttpKernel: skips route with wrong method', async () => { const kernel = new HttpKernel(); kernel.route({ method: 'POST', path: '/only-post' }) - .handle(() => Promise.resolve(new Response('nope'))); + .handle((_ctx) => Promise.resolve(new Response('nope'))); const res = await kernel.handle( new Request('http://localhost/only-post', { method: 'GET' }), @@ -152,7 +157,7 @@ Deno.test('HttpKernel: handler throws → error propagates', async () => { const kernel = new HttpKernel(); kernel.route({ method: 'GET', path: '/throw' }) - .handle(() => { + .handle((_ctx) => { throw new Error('fail!'); }); -- 2.49.1 From 801d06ebf8127e47919d96ce72da94fe528d1818 Mon Sep 17 00:00:00 2001 From: "Max P." Date: Tue, 27 May 2025 14:50:10 +0200 Subject: [PATCH 09/14] test(routebuilder): add validation tests for handler and middleware - Add tests to validate middleware and handler signatures - Ensure TypeError is thrown for invalid signatures --- src/__tests__/RouteBuilder.test.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/__tests__/RouteBuilder.test.ts b/src/__tests__/RouteBuilder.test.ts index afb5acd..d54fdbe 100644 --- a/src/__tests__/RouteBuilder.test.ts +++ b/src/__tests__/RouteBuilder.test.ts @@ -10,11 +10,24 @@ import type { Handler, Middleware } from '../Types/mod.ts'; // Dummy objects // deno-lint-ignore require-await -const dummyHandler: Handler = async () => new Response('ok'); +const dummyHandler: Handler = async (_) => new Response('ok'); +// deno-lint-ignore require-await +const wrongHandler: Handler = async () => new Response('ok'); // Wrong signature, no ctx const dummyMiddleware: Middleware = async (_, next) => await next(); +// deno-lint-ignore require-await +const wrongMiddleware: Middleware = async () => new Response('ok'); // Wrong signature, no ctx, next const dummyDef: IRouteDefinition = { method: 'GET', path: '/hello' }; const dummyMatcher = () => ({ params: {} }); +Deno.test('middleware: throws if middleware signature is wrong', () => { + const builder = new RouteBuilder(() => {}, dummyDef); + assertThrows( + () => builder.middleware(wrongMiddleware).handle(dummyHandler), + TypeError, + 'Middleware at index 0 is not a valid function.', + ); +}); + Deno.test('middleware: single middleware is registered correctly', () => { let registered: IInternalRoute | null = null as IInternalRoute | null; @@ -51,6 +64,15 @@ Deno.test('middleware: preserves order of middleware', () => { assertEquals(result!.middlewares, [mw1, mw2]); }); +Deno.test('handle: throws if handler signature is wrong', () => { + const builder = new RouteBuilder(() => {}, dummyDef); + assertThrows( + () => builder.handle(wrongHandler), + TypeError, + 'Route handler must be a function returning a Promise.', + ); +}); + Deno.test('handle: uppercases method', () => { let result: IInternalRoute | null = null as IInternalRoute | null; -- 2.49.1 From 39e39a9699982653f0d1df2e845d8098fd79dbd9 Mon Sep 17 00:00:00 2001 From: "Max P." Date: Tue, 27 May 2025 14:56:03 +0200 Subject: [PATCH 10/14] chore(config): add CI task for local checks - Introduces a new "ci" task to streamline local CI workflows - Combines formatting, linting, testing, and benchmarking for convenience --- deno.jsonc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deno.jsonc b/deno.jsonc index 2707c45..e13a592 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -9,7 +9,8 @@ "test:watch": "deno test --watch --allow-net --allow-env --unstable-kv --allow-read --allow-write **/__tests__/*.test.ts", "benchmark": "deno bench --allow-net --allow-env --unstable-kv --allow-read --allow-write **/__bench__/*.bench.ts", "fmt": "deno fmt --check", - "lint": "deno lint" + "lint": "deno lint", + "ci": "deno task fmt && deno task lint && deno task test && deno task benchmark" // For local CI checks }, "compilerOptions": { "lib": [ -- 2.49.1 From d8a768655713bbe84c3dfe337d62fe1cc6cba4e1 Mon Sep 17 00:00:00 2001 From: "Max P." Date: Tue, 27 May 2025 14:56:14 +0200 Subject: [PATCH 11/14] feat(ci): enhance CI workflow with granular steps and error handling - Add separate steps for formatting, linting, testing, and benchmarking - Introduce failure detection to halt workflow on step failure - Improve maintainability and visibility of CI process outcomes --- .gitea/workflows/ci.yml | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index a28dbd6..7dce726 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -17,14 +17,36 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up Deno - uses: denoland/setup-deno@v1 + - uses: denoland/setup-deno@v1 with: deno-version: v2.x - - name: Run CI Checks + - name: Format + id: format + continue-on-error: true + run: deno task fmt + + - name: Lint + id: lint + continue-on-error: true + run: deno task lint + + - name: Test + id: test + continue-on-error: true + run: deno task test + + - name: Benchmark + id: benchmark + continue-on-error: true + run: deno task benchmark + + - name: Fail if any step failed + if: | + steps.format.outcome != 'success' || + steps.lint.outcome != 'success' || + steps.test.outcome != 'success' || + steps.benchmark.outcome != 'success' run: | - deno task fmt - deno task lint - deno task test - deno task benchmark + echo "::error::One or more steps failed" + exit 1 -- 2.49.1 From ed79a17d7ae0e57815a7d7e42ff3723121425d26 Mon Sep 17 00:00:00 2001 From: ghost-bot Date: Tue, 27 May 2025 12:57:12 +0000 Subject: [PATCH 12/14] chore(changelog): update unreleased changelog --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d99bbe..254e1c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ All notable changes to this project will be documented in this file. ### 🚀 Features +- *(ci)* Enhance CI workflow with granular steps and error handling - ([d8a7686](https://git.0xmax42.io/maxp/http-kernel/commit/d8a768655713bbe84c3dfe337d62fe1cc6cba4e1)) +- *(route-builder)* Add middleware chain compilation - ([91708a0](https://git.0xmax42.io/maxp/http-kernel/commit/91708a0499a98dc9c3b43e423d66fc12abc1cc21)) +- *(interfaces)* Add runRoute method to IInternalRoute - ([beadcef](https://git.0xmax42.io/maxp/http-kernel/commit/beadcefc6af6c31e5f123ca7348acb224ac930aa)) - *(workflows)* Conditionally generate changelog - ([b44bb2d](https://git.0xmax42.io/maxp/http-kernel/commit/b44bb2ddafe99c85b25229d2c4a0dfeacf750052)) - *(workflows)* Add CI for Deno project tests - ([9d5db4f](https://git.0xmax42.io/maxp/http-kernel/commit/9d5db4f414cf961248f2b879f2b132b81a32cb92)) @@ -15,6 +18,7 @@ All notable changes to this project will be documented in this file. ### 🚜 Refactor +- *(kernel)* Simplify middleware and handler execution - ([8243b07](https://git.0xmax42.io/maxp/http-kernel/commit/8243b07a5af921c2c81f9b7d10765138aa274915)) - *(imports)* Use explicit type-only imports across codebase - ([b83aa33](https://git.0xmax42.io/maxp/http-kernel/commit/b83aa330b34523e5102ab98ee61dedbbd62d4656)) - *(workflows)* Rename changelog file for consistency - ([b9d25f2](https://git.0xmax42.io/maxp/http-kernel/commit/b9d25f23fc6ad7696deee319024aa5b1af4d98c0)) @@ -24,8 +28,19 @@ All notable changes to this project will be documented in this file. - Add README for HttpKernel project - ([a1ce306](https://git.0xmax42.io/maxp/http-kernel/commit/a1ce30627c68a3f869eb6a104308322af8596dc1)) - Add MIT license file - ([5118a19](https://git.0xmax42.io/maxp/http-kernel/commit/5118a19aeaa1102591aa7fe093fdec1aa19dc7f5)) +### 🧪 Testing + +- *(routebuilder)* Add validation tests for handler and middleware - ([801d06e](https://git.0xmax42.io/maxp/http-kernel/commit/801d06ebf8127e47919d96ce72da94fe528d1818)) +- *(httpkernel)* Enforce compile-time validation for signatures - ([b3ed8dd](https://git.0xmax42.io/maxp/http-kernel/commit/b3ed8dd52c25a7c2653245749ce62ecb81001573)) +- *(bench)* Add parallel benchmarks for HTTP kernel - ([ba3d2e3](https://git.0xmax42.io/maxp/http-kernel/commit/ba3d2e33f2a3bd690cbc1f291fea07466a94b7d5)) + ### ⚙️ Miscellaneous Tasks +- *(config)* Add CI task for local checks - ([39e39a9](https://git.0xmax42.io/maxp/http-kernel/commit/39e39a9699982653f0d1df2e845d8098fd79dbd9)) +- *(gitignore)* Add .local directory to ignored files - ([2d3dacc](https://git.0xmax42.io/maxp/http-kernel/commit/2d3dacc35802d2ffd6c6eda22df5761dd2d03f74)) +- *(ci)* Update deno tasks in CI workflow - ([af32f3b](https://git.0xmax42.io/maxp/http-kernel/commit/af32f3b9f4905469def8c22239ef3de4b5c3ea54)) +- *(tasks)* Add benchmark, format, and lint commands - ([d9a984c](https://git.0xmax42.io/maxp/http-kernel/commit/d9a984cbea887495944f9b7d7430650a040241dc)) +- *(workflows)* Consolidate and update CI configuration - ([ec1697d](https://git.0xmax42.io/maxp/http-kernel/commit/ec1697df94b5378f1766663e278a41d403a64336)) - *(config)* Add exports field to module metadata - ([c28eb7f](https://git.0xmax42.io/maxp/http-kernel/commit/c28eb7f28dfaa8d3fdc540c4bcc306a3a8b9d6f8)) - *(git)* Ignore merge conflicts for CHANGELOG.md - ([6399113](https://git.0xmax42.io/maxp/http-kernel/commit/6399113e122e1207ebf4113aebd250358e31f461)) - *(workflows)* Refine branch handling in release process - ([71ea424](https://git.0xmax42.io/maxp/http-kernel/commit/71ea4247b35dc4afe5090d3c6502bfa936b5a947)) -- 2.49.1 From 828fcd4ef090114d5412ad547af72387b5db393f Mon Sep 17 00:00:00 2001 From: "Max P." Date: Tue, 27 May 2025 14:59:40 +0200 Subject: [PATCH 13/14] feat(workflows): add GitHub release sync workflow - Add a workflow to synchronize Gitea releases with GitHub - Remove deprecated upload-assets workflow example --- .gitea/workflows/sync-release-to-github.yml | 27 ++++++++++++ .gitea/workflows/upload-assets.yml.example | 47 --------------------- 2 files changed, 27 insertions(+), 47 deletions(-) create mode 100644 .gitea/workflows/sync-release-to-github.yml delete mode 100644 .gitea/workflows/upload-assets.yml.example diff --git a/.gitea/workflows/sync-release-to-github.yml b/.gitea/workflows/sync-release-to-github.yml new file mode 100644 index 0000000..4daebad --- /dev/null +++ b/.gitea/workflows/sync-release-to-github.yml @@ -0,0 +1,27 @@ +name: Sync Release to GitHub + +on: + release: + types: [published] + +jobs: + build-and-publish: + runs-on: ubuntu-22.04 + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + ref: ${{ github.event.release.tag_name }} + + - name: Run Releases Sync Action + uses: https://git.0xmax42.io/actions/releases-sync@main + with: + gitea_token: $ACTIONS_RUNTIME_TOKEN + gitea_url: https://git.0xmax42.io + gitea_owner: maxp + gitea_repo: http-kernel + tag_name: ${{ inputs.tag || github.event.release.tag_name }} + github_token: ${{ secrets.SYNC_GITHUB_TOKEN }} + github_owner: 0xMax42 + github_repo: http-kernel diff --git a/.gitea/workflows/upload-assets.yml.example b/.gitea/workflows/upload-assets.yml.example deleted file mode 100644 index fcb4a5b..0000000 --- a/.gitea/workflows/upload-assets.yml.example +++ /dev/null @@ -1,47 +0,0 @@ -# ======================== -# 📦 Upload Assets Template -# ======================== -# Dieser Workflow wird automatisch ausgelöst, wenn ein Release -# in Gitea veröffentlicht wurde (event: release.published). -# -# Er dient dem Zweck, Release-Artefakte (wie z. B. Binary-Dateien, -# Changelogs oder Build-Zips) nachträglich mit dem Release zu verknüpfen. -# -# Voraussetzung: Zwei Shell-Skripte liegen im Projekt: -# - .gitea/scripts/get-release-id.sh → ermittelt Release-ID per Tag -# - .gitea/scripts/upload-asset.sh → lädt Datei als Release-Asset hoch -# -# -------------------------------------- - -name: Upload Assets - -on: - release: - types: [published] # Nur bei Veröffentlichung eines Releases (nicht bei Entwürfen) - -jobs: - upload-assets: - runs-on: ubuntu-latest - - steps: - # 📥 Checke den Stand des Repos aus, exakt auf dem veröffentlichten Tag - # So ist garantiert, dass die Artefakte dem Zustand des Releases entsprechen. - - uses: actions/checkout@v4 - with: - ref: ${{ github.event.release.tag_name }} # z. B. "v1.2.3" - fetch-depth: 0 # vollständige Git-Historie (für z. B. git-cliff, logs etc.) - - # 🆔 Hole die Release-ID basierend auf dem Tag - # Die ID wird als Umgebungsvariable RELEASE_ID über $GITHUB_ENV verfügbar gemacht. - - name: Get Release ID from tag - run: .gitea/scripts/get-release-id.sh "${{ github.event.release.tag_name }}" - - # 🔼 Upload eines Release-Assets - # Beispiel: Lade CHANGELOG.md als Datei mit abweichendem Namen "RELEASE-NOTES.md" hoch - # - # Du kannst beliebig viele Upload-Schritte hinzufügen oder in einer Schleife iterieren. - # - # Hinweis: RELEASE_ID wird automatisch verwendet, da get-release-id.sh sie exportiert. - # - # - name: Upload CHANGELOG.md as RELEASE-NOTES.md - # run: .gitea/scripts/upload-asset.sh ./CHANGELOG.md RELEASE-NOTES.md -- 2.49.1 From 8656682b28287e190c132d8774fc0b5ced6c3a8a Mon Sep 17 00:00:00 2001 From: ghost-bot Date: Tue, 27 May 2025 12:59:54 +0000 Subject: [PATCH 14/14] chore(changelog): update unreleased changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 254e1c1..bc6fc03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ### 🚀 Features +- *(workflows)* Add GitHub release sync workflow - ([828fcd4](https://git.0xmax42.io/maxp/http-kernel/commit/828fcd4ef090114d5412ad547af72387b5db393f)) - *(ci)* Enhance CI workflow with granular steps and error handling - ([d8a7686](https://git.0xmax42.io/maxp/http-kernel/commit/d8a768655713bbe84c3dfe337d62fe1cc6cba4e1)) - *(route-builder)* Add middleware chain compilation - ([91708a0](https://git.0xmax42.io/maxp/http-kernel/commit/91708a0499a98dc9c3b43e423d66fc12abc1cc21)) - *(interfaces)* Add runRoute method to IInternalRoute - ([beadcef](https://git.0xmax42.io/maxp/http-kernel/commit/beadcefc6af6c31e5f123ca7348acb224ac930aa)) -- 2.49.1