diff --git a/package-lock.json b/package-lock.json index dc5dc7e..00da733 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "Apache-2.0", "dependencies": { "@humanwhocodes/env": "^2.2.2", - "@krutoo/fetch-tools": "^0.0.11", + "@krutoo/fetch-tools": "^0.0.12", "@opentelemetry/api": "^1.4.1", "@opentelemetry/exporter-prometheus": "^0.38.0", "@opentelemetry/exporter-trace-otlp-http": "^0.39.1", @@ -3671,9 +3671,9 @@ } }, "node_modules/@krutoo/fetch-tools": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@krutoo/fetch-tools/-/fetch-tools-0.0.11.tgz", - "integrity": "sha512-AnXjfbhcVCq1n3gcb2oIaxjppEhmFy4FA94U3wOUT/Hgq44XCA5jS6MyTdNwKskn0y8vJTQAeUC2unW++bgR7A==" + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@krutoo/fetch-tools/-/fetch-tools-0.0.12.tgz", + "integrity": "sha512-qooqX0k7DoJF49j/9X6WnveUPpjSwlvBdko2LIrV2BcUhezZZ+a4etBs8gKMmaPZytZ7xF/JuFVlk4O7f8zjxA==" }, "node_modules/@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", @@ -18477,9 +18477,9 @@ } }, "@krutoo/fetch-tools": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@krutoo/fetch-tools/-/fetch-tools-0.0.11.tgz", - "integrity": "sha512-AnXjfbhcVCq1n3gcb2oIaxjppEhmFy4FA94U3wOUT/Hgq44XCA5jS6MyTdNwKskn0y8vJTQAeUC2unW++bgR7A==" + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@krutoo/fetch-tools/-/fetch-tools-0.0.12.tgz", + "integrity": "sha512-qooqX0k7DoJF49j/9X6WnveUPpjSwlvBdko2LIrV2BcUhezZZ+a4etBs8gKMmaPZytZ7xF/JuFVlk4O7f8zjxA==" }, "@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", diff --git a/package.json b/package.json index 90a6d0e..5044de9 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ }, "dependencies": { "@humanwhocodes/env": "^2.2.2", - "@krutoo/fetch-tools": "^0.0.11", + "@krutoo/fetch-tools": "^0.0.12", "@opentelemetry/api": "^1.4.1", "@opentelemetry/exporter-prometheus": "^0.38.0", "@opentelemetry/exporter-trace-otlp-http": "^0.39.1", @@ -147,6 +147,12 @@ "import": "./dist/esm/preset/web/providers/index.js", "default": "./dist/esm/preset/web/providers/index.js" }, + "./preset/server": { + "types": "./dist/types/preset/server/index.d.ts", + "require": "./dist/cjs/preset/server/index.js", + "import": "./dist/esm/preset/server/index.js", + "default": "./dist/esm/preset/server/index.js" + }, "./preset/node": { "types": "./dist/types/preset/node/index.d.ts", "require": "./dist/cjs/preset/node/index.js", @@ -279,6 +285,9 @@ "preset/web/providers": [ "./dist/types/preset/web/providers/index.d.ts" ], + "preset/server": [ + "./dist/types/preset/server/index.d.ts" + ], "preset/node": [ "./dist/types/preset/node/index.d.ts" ], diff --git a/src/preset/bun/bun/index.ts b/src/preset/bun/bun/index.ts index dc67cd4..5c6a732 100644 --- a/src/preset/bun/bun/index.ts +++ b/src/preset/bun/bun/index.ts @@ -29,6 +29,7 @@ export function PresetBun(customize?: PresetTuner) { // http serve preset.set(KnownToken.Http.serve, BunProviders.serve); + preset.set(KnownToken.Http.Serve.serviceRoutes, BunProviders.serviceRoutes); preset.set(KnownToken.Http.Serve.middleware, BunProviders.serveMiddleware); // http api diff --git a/src/preset/bun/bun/providers/index.ts b/src/preset/bun/bun/providers/index.ts index 78ce57c..a25452a 100644 --- a/src/preset/bun/bun/providers/index.ts +++ b/src/preset/bun/bun/providers/index.ts @@ -12,7 +12,7 @@ import { createSentryHandler } from '../../../../log/handler/sentry'; import { healthCheck } from '../../../isomorphic/utils'; import { provideFetch } from '../../../isomorphic/providers'; import { toMilliseconds } from '../../../../utils'; -import { ServerMiddleware } from '../../../server/types'; +import { ServerHandler, ServerMiddleware } from '../../../server/types'; import { applyServerMiddleware } from '../../../server/utils'; import PromClient from 'prom-client'; import { RESPONSE_EVENT_TYPE } from '../../../isomorphic/constants'; @@ -58,24 +58,37 @@ export const BunProviders = { serve(resolve: Resolve): Handler { const middleware = resolve(KnownToken.Http.Serve.middleware); const routes = resolve(KnownToken.Http.Serve.routes); + const serviceRoutes = resolve(KnownToken.Http.Serve.serviceRoutes); const enhance = applyServerMiddleware(...middleware); return router( // маршруты с промежуточными слоями - ...routes.map(([pathname, handler]) => { + ...routes.map(([pattern, handler]) => { const enhancedHandler = enhance(handler); - return route(pathname, request => enhancedHandler(request, { events: new EventTarget() })); + + return route.get(pattern, request => + enhancedHandler(request, { events: new EventTarget() }), + ); }), // @todo вместо routes обрабатывать pageRoutes с помощью route.get() из новой версии fetch-tools (для явности) // @todo также добавить apiRoutes и обрабатывать их с помощью с помощью route()? // служебные маршруты (без промежуточных слоев) - route('/healthcheck', healthCheck()), + ...serviceRoutes.map(([pattern, handler]) => + route(pattern, request => handler(request, { events: new EventTarget() })), + ), ); }, + serviceRoutes(): Array<[string, ServerHandler]> { + return [ + // служебные маршруты (без промежуточных слоев) + ['/healthcheck', healthCheck()], + ]; + }, + serveMiddleware(resolve: Resolve): ServerMiddleware[] { const config = resolve(KnownToken.Config.base); const logger = resolve(KnownToken.logger); @@ -184,14 +197,15 @@ export const BunProviders = { // @todo задействовать когда Bun реализует pref_hooks.monitorEventLoopDelay (https://github.com/siimon/prom-client/issues/570) // PromClient.collectDefaultMetrics(); - // @todo здесь или в другом компоненте надо проверять путь и метод запроса - return async () => { - const metrics = await PromClient.register.metrics(); - const headers = new Headers(); + return router( + route.get('/', async () => { + const metrics = await PromClient.register.metrics(); + const headers = new Headers(); - headers.set('Content-Type', PromClient.register.contentType); + headers.set('Content-Type', PromClient.register.contentType); - return new Response(metrics, { headers }); - }; + return new Response(metrics, { headers }); + }), + ); }, } as const; diff --git a/src/preset/bun/handler/providers/index.tsx b/src/preset/bun/handler/providers/index.tsx index 1b07d00..d021ba7 100644 --- a/src/preset/bun/handler/providers/index.tsx +++ b/src/preset/bun/handler/providers/index.tsx @@ -193,13 +193,21 @@ export const HandlerProviders = { (request, next) => { const innerController = new AbortController(); - request.signal?.addEventListener('abort', () => { - innerController.abort(); - }); + request.signal?.addEventListener( + 'abort', + () => { + innerController.abort(); + }, + { once: true }, + ); - abortController.signal.addEventListener('abort', () => { - innerController.abort(); - }); + abortController.signal.addEventListener( + 'abort', + () => { + innerController.abort(); + }, + { once: true }, + ); return next(new Request(request, { signal: innerController.signal })); }, diff --git a/src/preset/bun/handler/utils/index.ts b/src/preset/bun/handler/utils/index.ts index 45c3348..4dc18ff 100644 --- a/src/preset/bun/handler/utils/index.ts +++ b/src/preset/bun/handler/utils/index.ts @@ -1,9 +1,9 @@ /* eslint-disable require-jsdoc, jsdoc/require-jsdoc */ import type { ServerHandler } from '../../../server/types'; import { KnownToken } from '../../../../tokens'; -import { CURRENT_APP, type Application, type Resolve } from '../../../../di'; +import { CURRENT_APP, type Application, type Resolve, Provider } from '../../../../di'; -export function HandlerProvider(getApp: () => Application) { +export function HandlerProvider(getApp: () => Application): Provider { return (resolve: Resolve): ServerHandler => { const parent = resolve(CURRENT_APP); diff --git a/src/preset/node/handler/providers/index.tsx b/src/preset/node/handler/providers/index.tsx index 0767c1c..049278b 100644 --- a/src/preset/node/handler/providers/index.tsx +++ b/src/preset/node/handler/providers/index.tsx @@ -188,13 +188,21 @@ export function provideFetchMiddleware(resolve: Resolve): Middleware[] { (request, next) => { const innerController = new AbortController(); - request.signal?.addEventListener('abort', () => { - innerController.abort(); - }); + request.signal?.addEventListener( + 'abort', + () => { + innerController.abort(); + }, + { once: true }, + ); - abortController.signal.addEventListener('abort', () => { - innerController.abort(); - }); + abortController.signal.addEventListener( + 'abort', + () => { + innerController.abort(); + }, + { once: true }, + ); return next(new Request(request, { signal: innerController.signal })); }, @@ -268,13 +276,21 @@ export function provideAxiosMiddleware(resolve: Resolve): AxiosMiddleware[] async (config, next) => { const innerController = new AbortController(); - abortController.signal.addEventListener('abort', () => { - innerController.abort(); - }); + abortController.signal.addEventListener( + 'abort', + () => { + innerController.abort(); + }, + { once: true }, + ); - config.signal?.addEventListener?.('abort', () => { - innerController.abort(); - }); + config.signal?.addEventListener?.( + 'abort', + () => { + innerController.abort(); + }, + { once: true }, + ); await next({ ...config, signal: innerController.signal }); }, diff --git a/src/preset/server/index.ts b/src/preset/server/index.ts new file mode 100644 index 0000000..85b6ee5 --- /dev/null +++ b/src/preset/server/index.ts @@ -0,0 +1,2 @@ +export type { ServerHandler, ServerMiddleware, ServerHandlerContext } from './types'; +export { getClientIp, getForwardedHeaders, getPageResponseFormat } from './utils'; diff --git a/src/tokens.ts b/src/tokens.ts index 45e3731..62394ba 100644 --- a/src/tokens.ts +++ b/src/tokens.ts @@ -71,6 +71,7 @@ export const KnownToken = { serve: createToken('serve'), Serve: { routes: createToken>('serve/routes'), + serviceRoutes: createToken>('serve/service-routes'), middleware: createToken('serve/middleware'), },