@asenajs/ergenecore 1.4.0 → 2.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/README.md +9 -3
- package/dist/lib/Ergenecore.d.ts +65 -63
- package/dist/lib/Ergenecore.js +320 -343
- package/dist/lib/Ergenecore.js.map +1 -1
- package/dist/lib/ErgenecoreContextWrapper.js +4 -1
- package/dist/lib/ErgenecoreContextWrapper.js.map +1 -1
- package/dist/lib/ErgenecoreWebsocketAdapter.js +4 -2
- package/dist/lib/ErgenecoreWebsocketAdapter.js.map +1 -1
- package/dist/lib/defaults/ConfigService.d.ts +19 -14
- package/dist/lib/defaults/ConfigService.js +5 -2
- package/dist/lib/defaults/ConfigService.js.map +1 -1
- package/dist/lib/defaults/MiddlewareService.d.ts +6 -2
- package/dist/lib/defaults/MiddlewareService.js.map +1 -1
- package/dist/lib/defaults/ValidationService.js.map +1 -1
- package/dist/lib/errors.d.ts +50 -1
- package/dist/lib/errors.js +68 -0
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/stream/SSEStreamWriter.js +6 -1
- package/dist/lib/stream/SSEStreamWriter.js.map +1 -1
- package/dist/lib/stream/StreamWriter.js +9 -2
- package/dist/lib/stream/StreamWriter.js.map +1 -1
- package/dist/lib/utils/factory.d.ts +10 -0
- package/dist/lib/utils/factory.js +2 -2
- package/dist/lib/utils/factory.js.map +1 -1
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Asena Ergenecore Adapter
|
|
2
2
|
|
|
3
|
+
[](https://asena.sh)
|
|
4
|
+
[](https://bun.sh)
|
|
5
|
+
|
|
3
6
|
**Blazing-fast** native Bun adapter for [Asena.js](https://github.com/asenajs/asena) - Built exclusively with Bun's native APIs for maximum performance.
|
|
4
7
|
|
|
5
8
|
Built on Bun runtime for exceptional performance:
|
|
@@ -604,11 +607,14 @@ export class ServerConfig extends ConfigService {
|
|
|
604
607
|
}
|
|
605
608
|
|
|
606
609
|
// With custom exception mapper
|
|
610
|
+
import { isValidationError } from '@asenajs/asena/adapter';
|
|
611
|
+
|
|
607
612
|
export class ExceptionMapper {
|
|
608
613
|
map(error: Error, context: Context): Response {
|
|
609
|
-
//
|
|
610
|
-
|
|
611
|
-
|
|
614
|
+
// Request validation failures arrive here like any other error.
|
|
615
|
+
// Check this before `instanceof HttpException` - ValidationError extends it
|
|
616
|
+
if (isValidationError(error)) {
|
|
617
|
+
return context.send({ error: 'Validation failed', details: error.issues }, 400);
|
|
612
618
|
}
|
|
613
619
|
|
|
614
620
|
return context.send({ error: 'Internal server error' }, 500);
|
package/dist/lib/Ergenecore.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { WebsocketRouteParams } from '@asenajs/asena/adapter';
|
|
2
|
-
import { AsenaAdapter, type AsenaServeOptions, type AsenaStartOptions, type BaseMiddleware, type ErrorHandler, type RouteParams } from '@asenajs/asena/adapter';
|
|
2
|
+
import { AsenaAdapter, type AsenaServeOptions, type AsenaStartOptions, type BaseMiddleware, type ErrorHandler, type NotFoundHandler, type RouteParams } from '@asenajs/asena/adapter';
|
|
3
3
|
import { type ServerLogger } from '@asenajs/asena/logger';
|
|
4
4
|
import type { GlobalMiddlewareConfig } from '@asenajs/asena/server/config';
|
|
5
5
|
import { ErgenecoreWebsocketAdapter } from './ErgenecoreWebsocketAdapter';
|
|
@@ -50,6 +50,15 @@ export declare class Ergenecore extends AsenaAdapter<Context, ValidationSchemaWi
|
|
|
50
50
|
* Error handler function
|
|
51
51
|
*/
|
|
52
52
|
private errorHandler?;
|
|
53
|
+
/**
|
|
54
|
+
* Handler for requests that matched no route
|
|
55
|
+
*/
|
|
56
|
+
private notFoundHandler?;
|
|
57
|
+
/**
|
|
58
|
+
* Whether the adapter logs errors before handing them to the application.
|
|
59
|
+
* Set false when your own handler already logs with a correlation id.
|
|
60
|
+
*/
|
|
61
|
+
private readonly logErrors;
|
|
53
62
|
/**
|
|
54
63
|
* Global middlewares with route configuration
|
|
55
64
|
* Structure: Array<{ middleware, config }>
|
|
@@ -72,7 +81,7 @@ export declare class Ergenecore extends AsenaAdapter<Context, ValidationSchemaWi
|
|
|
72
81
|
* @param logger - Server logger instance
|
|
73
82
|
* @param websocketAdapter - WebSocket adapter instance (optional)
|
|
74
83
|
*/
|
|
75
|
-
constructor(logger: ServerLogger, websocketAdapter?: ErgenecoreWebsocketAdapter);
|
|
84
|
+
constructor(logger: ServerLogger, websocketAdapter?: ErgenecoreWebsocketAdapter, logErrors?: boolean);
|
|
76
85
|
/**
|
|
77
86
|
* Registers a WebSocket route (deferred registration)
|
|
78
87
|
*
|
|
@@ -173,6 +182,12 @@ export declare class Ergenecore extends AsenaAdapter<Context, ValidationSchemaWi
|
|
|
173
182
|
* @param errorHandler - Error handler function
|
|
174
183
|
*/
|
|
175
184
|
onError(errorHandler: ErrorHandler<Context>): void;
|
|
185
|
+
/**
|
|
186
|
+
* Registers the handler for requests that match no route.
|
|
187
|
+
*
|
|
188
|
+
* Separate from {@link onError}: a missing route is a routing outcome, not a thrown error.
|
|
189
|
+
*/
|
|
190
|
+
onNotFound(notFoundHandler: NotFoundHandler<Context>): void;
|
|
176
191
|
/**
|
|
177
192
|
* Sets serve options
|
|
178
193
|
*
|
|
@@ -223,6 +238,54 @@ export declare class Ergenecore extends AsenaAdapter<Context, ValidationSchemaWi
|
|
|
223
238
|
* ```
|
|
224
239
|
*/
|
|
225
240
|
private buildWebSocketRoutes;
|
|
241
|
+
/**
|
|
242
|
+
* Answers a request nothing served: an unmatched route, or a static file that does not exist.
|
|
243
|
+
*
|
|
244
|
+
* Both go through the application's `onNotFound` so an app has one place to shape its 404,
|
|
245
|
+
* and both fall back to the same JSON envelope the hono adapter uses.
|
|
246
|
+
*
|
|
247
|
+
* Deliberately NOT routed to `onError` - that hook is for errors the application threw.
|
|
248
|
+
*/
|
|
249
|
+
private respondToUnmatched;
|
|
250
|
+
private resolveUnmatchedResponse;
|
|
251
|
+
/**
|
|
252
|
+
* Records a request the framework itself answered with a 404.
|
|
253
|
+
*
|
|
254
|
+
* Only reached when the application has no `onNotFound`, or when its hook declined or threw -
|
|
255
|
+
* an application that answered its own 404 already knows about the request. Without this an
|
|
256
|
+
* unmatched route was the one outcome that produced no output at any level, which is exactly
|
|
257
|
+
* the traffic (bots, probes, a typo in a deployed client) an operator needs to see.
|
|
258
|
+
*
|
|
259
|
+
* `info`, not `warn`: a scanner walking /wp-admin, /.env and /phpmyadmin must not be able to
|
|
260
|
+
* fill the warning stream. Not `debug` either - a 404 nobody can see is how a mistyped route
|
|
261
|
+
* survives to production.
|
|
262
|
+
*/
|
|
263
|
+
private logUnmatched;
|
|
264
|
+
/**
|
|
265
|
+
* Logs an error before the application's handler sees it, at a level that matches the
|
|
266
|
+
* response the caller will get.
|
|
267
|
+
*
|
|
268
|
+
* This adapter used to log only when NO error handler was registered - which is to say,
|
|
269
|
+
* never in a real application, since every app configures `onError`. A 500 answered
|
|
270
|
+
* nothing to stdout and the stack was gone. The level split mirrors the hono adapter:
|
|
271
|
+
* 5xx is ours to fix and gets a stack, 4xx is the caller's and would otherwise let a bot
|
|
272
|
+
* scanning for /wp-admin flood the error stream.
|
|
273
|
+
*/
|
|
274
|
+
private logHandledError;
|
|
275
|
+
/**
|
|
276
|
+
* Produces the response for a thrown error, in the same order the hono adapter uses.
|
|
277
|
+
*
|
|
278
|
+
* The application's handler gets first refusal on *every* error, `HttpException` included.
|
|
279
|
+
* Previously each catch block answered an `HttpException` straight from `getResponse()` and
|
|
280
|
+
* only consulted `errorHandler` for everything else, so an app could not reshape its own
|
|
281
|
+
* 401/403/404 envelopes. Worse, only one of the five catch blocks carried the
|
|
282
|
+
* `!isValidationError` exemption, so a `ValidationError` thrown on the fast path never
|
|
283
|
+
* reached `onError` at all - the exact opposite of why ValidationError exists.
|
|
284
|
+
*
|
|
285
|
+
* Falls back to the exception's own response (or a 500) when there is no handler, when the
|
|
286
|
+
* handler returns nothing, or when the handler itself throws.
|
|
287
|
+
*/
|
|
288
|
+
private respondToError;
|
|
226
289
|
/**
|
|
227
290
|
* Executes middleware chain with recursive next() pattern
|
|
228
291
|
*
|
|
@@ -342,7 +405,6 @@ export declare class Ergenecore extends AsenaAdapter<Context, ValidationSchemaWi
|
|
|
342
405
|
* - Error handling
|
|
343
406
|
*
|
|
344
407
|
* @param route - Route parameters
|
|
345
|
-
* @param _commonMiddlewares - Common middlewares for this route group (for future optimization)
|
|
346
408
|
* @returns Bun-compatible route handler
|
|
347
409
|
*/
|
|
348
410
|
private createRouteHandler;
|
|
@@ -438,66 +500,6 @@ export declare class Ergenecore extends AsenaAdapter<Context, ValidationSchemaWi
|
|
|
438
500
|
* ```
|
|
439
501
|
*/
|
|
440
502
|
private buildStaticFileHeaders;
|
|
441
|
-
/**
|
|
442
|
-
* Extracts base path from a route path
|
|
443
|
-
*
|
|
444
|
-
* Removes dynamic segments (parameters and wildcards) from the path
|
|
445
|
-
* to find the static base path for grouping routes.
|
|
446
|
-
*
|
|
447
|
-
* @param path - Route path (e.g., "/api/users/:id")
|
|
448
|
-
* @returns Base path without dynamic segments (e.g., "/api/users")
|
|
449
|
-
*
|
|
450
|
-
* @example
|
|
451
|
-
* ```typescript
|
|
452
|
-
* extractBasePath('/api/users/:id') // => '/api/users'
|
|
453
|
-
* extractBasePath('/api/users/:id/posts/:postId') // => '/api/users'
|
|
454
|
-
* extractBasePath('/static/*') // => '/static'
|
|
455
|
-
* extractBasePath('/') // => '/'
|
|
456
|
-
* ```
|
|
457
|
-
*/
|
|
458
|
-
private extractBasePath;
|
|
459
|
-
/**
|
|
460
|
-
* Extracts common middlewares across multiple routes
|
|
461
|
-
*
|
|
462
|
-
* Identifies middlewares that are present in ALL routes and can be
|
|
463
|
-
* moved to group level for optimization.
|
|
464
|
-
*
|
|
465
|
-
* @param routes - Array of routes to analyze
|
|
466
|
-
* @returns Array of common middleware instances
|
|
467
|
-
*
|
|
468
|
-
* @example
|
|
469
|
-
* ```typescript
|
|
470
|
-
* extractCommonMiddlewares([
|
|
471
|
-
* { middlewares: [auth, log, rate] },
|
|
472
|
-
* { middlewares: [auth, log] },
|
|
473
|
-
* { middlewares: [auth, log] }
|
|
474
|
-
* ]) // => [auth, log]
|
|
475
|
-
* ```
|
|
476
|
-
*/
|
|
477
|
-
private extractCommonMiddlewares;
|
|
478
|
-
/**
|
|
479
|
-
* Groups routes by their base path
|
|
480
|
-
*
|
|
481
|
-
* Creates a map of base paths to routes for optimization.
|
|
482
|
-
* Routes with the same base path will share common middlewares.
|
|
483
|
-
*
|
|
484
|
-
* @param routes - Array of routes to group
|
|
485
|
-
* @returns Map of base paths to route arrays
|
|
486
|
-
*
|
|
487
|
-
* @example
|
|
488
|
-
* ```typescript
|
|
489
|
-
* groupRoutesByBasePath([
|
|
490
|
-
* { path: '/api/users' },
|
|
491
|
-
* { path: '/api/users/:id' },
|
|
492
|
-
* { path: '/api/posts' }
|
|
493
|
-
* ])
|
|
494
|
-
* // => Map {
|
|
495
|
-
* // '/api/users' => [route1, route2],
|
|
496
|
-
* // '/api/posts' => [route3]
|
|
497
|
-
* // }
|
|
498
|
-
* ```
|
|
499
|
-
*/
|
|
500
|
-
private groupRoutesByBasePath;
|
|
501
503
|
get hostname(): any;
|
|
502
504
|
set hostname(value: any);
|
|
503
505
|
/**
|