@engjts/nexus 0.1.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 +164 -0
- package/dist/advanced/cache/InMemoryCacheStore.d.ts +18 -0
- package/dist/advanced/cache/InMemoryCacheStore.d.ts.map +1 -0
- package/dist/advanced/cache/InMemoryCacheStore.js +60 -0
- package/dist/advanced/cache/InMemoryCacheStore.js.map +1 -0
- package/dist/advanced/cache/MultiTierCache.d.ts +55 -0
- package/dist/advanced/cache/MultiTierCache.d.ts.map +1 -0
- package/dist/advanced/cache/MultiTierCache.js +159 -0
- package/dist/advanced/cache/MultiTierCache.js.map +1 -0
- package/dist/advanced/cache/RedisCacheStore.d.ts +153 -0
- package/dist/advanced/cache/RedisCacheStore.d.ts.map +1 -0
- package/dist/advanced/cache/RedisCacheStore.js +247 -0
- package/dist/advanced/cache/RedisCacheStore.js.map +1 -0
- package/dist/advanced/cache/index.d.ts +6 -0
- package/dist/advanced/cache/index.d.ts.map +1 -0
- package/dist/advanced/cache/index.js +26 -0
- package/dist/advanced/cache/index.js.map +1 -0
- package/dist/advanced/cache/types.d.ts +35 -0
- package/dist/advanced/cache/types.d.ts.map +1 -0
- package/dist/advanced/cache/types.js +3 -0
- package/dist/advanced/cache/types.js.map +1 -0
- package/dist/advanced/graphql/SimpleDataLoader.d.ts +8 -0
- package/dist/advanced/graphql/SimpleDataLoader.d.ts.map +1 -0
- package/dist/advanced/graphql/SimpleDataLoader.js +43 -0
- package/dist/advanced/graphql/SimpleDataLoader.js.map +1 -0
- package/dist/advanced/graphql/index.d.ts +15 -0
- package/dist/advanced/graphql/index.d.ts.map +1 -0
- package/dist/advanced/graphql/index.js +19 -0
- package/dist/advanced/graphql/index.js.map +1 -0
- package/dist/advanced/graphql/server.d.ts +23 -0
- package/dist/advanced/graphql/server.d.ts.map +1 -0
- package/dist/advanced/graphql/server.js +208 -0
- package/dist/advanced/graphql/server.js.map +1 -0
- package/dist/advanced/graphql/types.d.ts +45 -0
- package/dist/advanced/graphql/types.d.ts.map +1 -0
- package/dist/advanced/graphql/types.js +3 -0
- package/dist/advanced/graphql/types.js.map +1 -0
- package/dist/advanced/jobs/InMemoryQueueStore.d.ts +14 -0
- package/dist/advanced/jobs/InMemoryQueueStore.d.ts.map +1 -0
- package/dist/advanced/jobs/InMemoryQueueStore.js +59 -0
- package/dist/advanced/jobs/InMemoryQueueStore.js.map +1 -0
- package/dist/advanced/jobs/JobQueue.d.ts +178 -0
- package/dist/advanced/jobs/JobQueue.d.ts.map +1 -0
- package/dist/advanced/jobs/JobQueue.js +440 -0
- package/dist/advanced/jobs/JobQueue.js.map +1 -0
- package/dist/advanced/jobs/RedisQueueStore.d.ts +157 -0
- package/dist/advanced/jobs/RedisQueueStore.d.ts.map +1 -0
- package/dist/advanced/jobs/RedisQueueStore.js +264 -0
- package/dist/advanced/jobs/RedisQueueStore.js.map +1 -0
- package/dist/advanced/jobs/index.d.ts +6 -0
- package/dist/advanced/jobs/index.d.ts.map +1 -0
- package/dist/advanced/jobs/index.js +26 -0
- package/dist/advanced/jobs/index.js.map +1 -0
- package/dist/advanced/jobs/types.d.ts +64 -0
- package/dist/advanced/jobs/types.d.ts.map +1 -0
- package/dist/advanced/jobs/types.js +3 -0
- package/dist/advanced/jobs/types.js.map +1 -0
- package/dist/advanced/observability/APMManager.d.ts +64 -0
- package/dist/advanced/observability/APMManager.d.ts.map +1 -0
- package/dist/advanced/observability/APMManager.js +150 -0
- package/dist/advanced/observability/APMManager.js.map +1 -0
- package/dist/advanced/observability/AlertManager.d.ts +30 -0
- package/dist/advanced/observability/AlertManager.d.ts.map +1 -0
- package/dist/advanced/observability/AlertManager.js +98 -0
- package/dist/advanced/observability/AlertManager.js.map +1 -0
- package/dist/advanced/observability/MetricRegistry.d.ts +37 -0
- package/dist/advanced/observability/MetricRegistry.d.ts.map +1 -0
- package/dist/advanced/observability/MetricRegistry.js +129 -0
- package/dist/advanced/observability/MetricRegistry.js.map +1 -0
- package/dist/advanced/observability/ObservabilityCenter.d.ts +113 -0
- package/dist/advanced/observability/ObservabilityCenter.d.ts.map +1 -0
- package/dist/advanced/observability/ObservabilityCenter.js +266 -0
- package/dist/advanced/observability/ObservabilityCenter.js.map +1 -0
- package/dist/advanced/observability/StructuredLogger.d.ts +25 -0
- package/dist/advanced/observability/StructuredLogger.d.ts.map +1 -0
- package/dist/advanced/observability/StructuredLogger.js +137 -0
- package/dist/advanced/observability/StructuredLogger.js.map +1 -0
- package/dist/advanced/observability/TracingManager.d.ts +31 -0
- package/dist/advanced/observability/TracingManager.d.ts.map +1 -0
- package/dist/advanced/observability/TracingManager.js +105 -0
- package/dist/advanced/observability/TracingManager.js.map +1 -0
- package/dist/advanced/observability/adapters.d.ts +134 -0
- package/dist/advanced/observability/adapters.d.ts.map +1 -0
- package/dist/advanced/observability/adapters.js +257 -0
- package/dist/advanced/observability/adapters.js.map +1 -0
- package/dist/advanced/observability/createObservabilityMiddleware.d.ts +8 -0
- package/dist/advanced/observability/createObservabilityMiddleware.d.ts.map +1 -0
- package/dist/advanced/observability/createObservabilityMiddleware.js +46 -0
- package/dist/advanced/observability/createObservabilityMiddleware.js.map +1 -0
- package/dist/advanced/observability/index.d.ts +2 -0
- package/dist/advanced/observability/index.d.ts.map +1 -0
- package/dist/advanced/observability/index.js +13 -0
- package/dist/advanced/observability/index.js.map +1 -0
- package/dist/advanced/observability/types.d.ts +182 -0
- package/dist/advanced/observability/types.d.ts.map +1 -0
- package/dist/advanced/observability/types.js +3 -0
- package/dist/advanced/observability/types.js.map +1 -0
- package/dist/advanced/playground/extractPathParams.d.ts +4 -0
- package/dist/advanced/playground/extractPathParams.d.ts.map +1 -0
- package/dist/advanced/playground/extractPathParams.js +8 -0
- package/dist/advanced/playground/extractPathParams.js.map +1 -0
- package/dist/advanced/playground/generateFieldExample.d.ts +2 -0
- package/dist/advanced/playground/generateFieldExample.d.ts.map +1 -0
- package/dist/advanced/playground/generateFieldExample.js +40 -0
- package/dist/advanced/playground/generateFieldExample.js.map +1 -0
- package/dist/advanced/playground/generatePlaygroundHTML.d.ts +3 -0
- package/dist/advanced/playground/generatePlaygroundHTML.d.ts.map +1 -0
- package/dist/advanced/playground/generatePlaygroundHTML.js +1848 -0
- package/dist/advanced/playground/generatePlaygroundHTML.js.map +1 -0
- package/dist/advanced/playground/generateSummary.d.ts +3 -0
- package/dist/advanced/playground/generateSummary.d.ts.map +1 -0
- package/dist/advanced/playground/generateSummary.js +19 -0
- package/dist/advanced/playground/generateSummary.js.map +1 -0
- package/dist/advanced/playground/getTagFromPath.d.ts +2 -0
- package/dist/advanced/playground/getTagFromPath.d.ts.map +1 -0
- package/dist/advanced/playground/getTagFromPath.js +11 -0
- package/dist/advanced/playground/getTagFromPath.js.map +1 -0
- package/dist/advanced/playground/index.d.ts +7 -0
- package/dist/advanced/playground/index.d.ts.map +1 -0
- package/dist/advanced/playground/index.js +10 -0
- package/dist/advanced/playground/index.js.map +1 -0
- package/dist/advanced/playground/playground.d.ts +4 -0
- package/dist/advanced/playground/playground.d.ts.map +1 -0
- package/dist/advanced/playground/playground.js +139 -0
- package/dist/advanced/playground/playground.js.map +1 -0
- package/dist/advanced/playground/types.d.ts +18 -0
- package/dist/advanced/playground/types.d.ts.map +1 -0
- package/dist/advanced/playground/types.js +3 -0
- package/dist/advanced/playground/types.js.map +1 -0
- package/dist/advanced/playground/zodToExample.d.ts +2 -0
- package/dist/advanced/playground/zodToExample.d.ts.map +1 -0
- package/dist/advanced/playground/zodToExample.js +22 -0
- package/dist/advanced/playground/zodToExample.js.map +1 -0
- package/dist/advanced/playground/zodToParams.d.ts +5 -0
- package/dist/advanced/playground/zodToParams.d.ts.map +1 -0
- package/dist/advanced/playground/zodToParams.js +18 -0
- package/dist/advanced/playground/zodToParams.js.map +1 -0
- package/dist/advanced/postman/buildAuth.d.ts +3 -0
- package/dist/advanced/postman/buildAuth.d.ts.map +1 -0
- package/dist/advanced/postman/buildAuth.js +32 -0
- package/dist/advanced/postman/buildAuth.js.map +1 -0
- package/dist/advanced/postman/buildBody.d.ts +3 -0
- package/dist/advanced/postman/buildBody.d.ts.map +1 -0
- package/dist/advanced/postman/buildBody.js +15 -0
- package/dist/advanced/postman/buildBody.js.map +1 -0
- package/dist/advanced/postman/buildQueryParams.d.ts +3 -0
- package/dist/advanced/postman/buildQueryParams.d.ts.map +1 -0
- package/dist/advanced/postman/buildQueryParams.js +26 -0
- package/dist/advanced/postman/buildQueryParams.js.map +1 -0
- package/dist/advanced/postman/buildRequestItem.d.ts +3 -0
- package/dist/advanced/postman/buildRequestItem.d.ts.map +1 -0
- package/dist/advanced/postman/buildRequestItem.js +33 -0
- package/dist/advanced/postman/buildRequestItem.js.map +1 -0
- package/dist/advanced/postman/buildResponses.d.ts +3 -0
- package/dist/advanced/postman/buildResponses.d.ts.map +1 -0
- package/dist/advanced/postman/buildResponses.js +12 -0
- package/dist/advanced/postman/buildResponses.js.map +1 -0
- package/dist/advanced/postman/buildUrl.d.ts +3 -0
- package/dist/advanced/postman/buildUrl.d.ts.map +1 -0
- package/dist/advanced/postman/buildUrl.js +30 -0
- package/dist/advanced/postman/buildUrl.js.map +1 -0
- package/dist/advanced/postman/capitalize.d.ts +2 -0
- package/dist/advanced/postman/capitalize.d.ts.map +1 -0
- package/dist/advanced/postman/capitalize.js +7 -0
- package/dist/advanced/postman/capitalize.js.map +1 -0
- package/dist/advanced/postman/generateCollection.d.ts +3 -0
- package/dist/advanced/postman/generateCollection.d.ts.map +1 -0
- package/dist/advanced/postman/generateCollection.js +50 -0
- package/dist/advanced/postman/generateCollection.js.map +1 -0
- package/dist/advanced/postman/generateEnvironment.d.ts +3 -0
- package/dist/advanced/postman/generateEnvironment.d.ts.map +1 -0
- package/dist/advanced/postman/generateEnvironment.js +33 -0
- package/dist/advanced/postman/generateEnvironment.js.map +1 -0
- package/dist/advanced/postman/generateExampleFromZod.d.ts +2 -0
- package/dist/advanced/postman/generateExampleFromZod.d.ts.map +1 -0
- package/dist/advanced/postman/generateExampleFromZod.js +22 -0
- package/dist/advanced/postman/generateExampleFromZod.js.map +1 -0
- package/dist/advanced/postman/generateFieldExample.d.ts +2 -0
- package/dist/advanced/postman/generateFieldExample.d.ts.map +1 -0
- package/dist/advanced/postman/generateFieldExample.js +55 -0
- package/dist/advanced/postman/generateFieldExample.js.map +1 -0
- package/dist/advanced/postman/generateName.d.ts +3 -0
- package/dist/advanced/postman/generateName.d.ts.map +1 -0
- package/dist/advanced/postman/generateName.js +19 -0
- package/dist/advanced/postman/generateName.js.map +1 -0
- package/dist/advanced/postman/generateUUID.d.ts +2 -0
- package/dist/advanced/postman/generateUUID.d.ts.map +1 -0
- package/dist/advanced/postman/generateUUID.js +14 -0
- package/dist/advanced/postman/generateUUID.js.map +1 -0
- package/dist/advanced/postman/getTagFromPath.d.ts +2 -0
- package/dist/advanced/postman/getTagFromPath.d.ts.map +1 -0
- package/dist/advanced/postman/getTagFromPath.js +12 -0
- package/dist/advanced/postman/getTagFromPath.js.map +1 -0
- package/dist/advanced/postman/index.d.ts +28 -0
- package/dist/advanced/postman/index.d.ts.map +1 -0
- package/dist/advanced/postman/index.js +30 -0
- package/dist/advanced/postman/index.js.map +1 -0
- package/dist/advanced/postman/postman.d.ts +7 -0
- package/dist/advanced/postman/postman.d.ts.map +1 -0
- package/dist/advanced/postman/postman.js +138 -0
- package/dist/advanced/postman/postman.js.map +1 -0
- package/dist/advanced/postman/slugify.d.ts +2 -0
- package/dist/advanced/postman/slugify.d.ts.map +1 -0
- package/dist/advanced/postman/slugify.js +10 -0
- package/dist/advanced/postman/slugify.js.map +1 -0
- package/dist/advanced/postman/types.d.ts +133 -0
- package/dist/advanced/postman/types.d.ts.map +1 -0
- package/dist/advanced/postman/types.js +3 -0
- package/dist/advanced/postman/types.js.map +1 -0
- package/dist/advanced/realtime/index.d.ts +13 -0
- package/dist/advanced/realtime/index.d.ts.map +1 -0
- package/dist/advanced/realtime/index.js +17 -0
- package/dist/advanced/realtime/index.js.map +1 -0
- package/dist/advanced/realtime/websocket.d.ts +60 -0
- package/dist/advanced/realtime/websocket.d.ts.map +1 -0
- package/dist/advanced/realtime/websocket.js +197 -0
- package/dist/advanced/realtime/websocket.js.map +1 -0
- package/dist/advanced/sentry/index.d.ts +287 -0
- package/dist/advanced/sentry/index.d.ts.map +1 -0
- package/dist/advanced/sentry/index.js +1002 -0
- package/dist/advanced/sentry/index.js.map +1 -0
- package/dist/advanced/sentry/types.d.ts +298 -0
- package/dist/advanced/sentry/types.d.ts.map +1 -0
- package/dist/advanced/sentry/types.js +6 -0
- package/dist/advanced/sentry/types.js.map +1 -0
- package/dist/advanced/static/generateDirectoryListing.d.ts +5 -0
- package/dist/advanced/static/generateDirectoryListing.d.ts.map +1 -0
- package/dist/advanced/static/generateDirectoryListing.js +44 -0
- package/dist/advanced/static/generateDirectoryListing.js.map +1 -0
- package/dist/advanced/static/generateETag.d.ts +8 -0
- package/dist/advanced/static/generateETag.d.ts.map +1 -0
- package/dist/advanced/static/generateETag.js +10 -0
- package/dist/advanced/static/generateETag.js.map +1 -0
- package/dist/advanced/static/getMimeType.d.ts +5 -0
- package/dist/advanced/static/getMimeType.d.ts.map +1 -0
- package/dist/advanced/static/getMimeType.js +11 -0
- package/dist/advanced/static/getMimeType.js.map +1 -0
- package/dist/advanced/static/index.d.ts +30 -0
- package/dist/advanced/static/index.d.ts.map +1 -0
- package/dist/advanced/static/index.js +33 -0
- package/dist/advanced/static/index.js.map +1 -0
- package/dist/advanced/static/isSafePath.d.ts +5 -0
- package/dist/advanced/static/isSafePath.d.ts.map +1 -0
- package/dist/advanced/static/isSafePath.js +14 -0
- package/dist/advanced/static/isSafePath.js.map +1 -0
- package/dist/advanced/static/publicDir.d.ts +12 -0
- package/dist/advanced/static/publicDir.d.ts.map +1 -0
- package/dist/advanced/static/publicDir.js +22 -0
- package/dist/advanced/static/publicDir.js.map +1 -0
- package/dist/advanced/static/serveStatic.d.ts +7 -0
- package/dist/advanced/static/serveStatic.d.ts.map +1 -0
- package/dist/advanced/static/serveStatic.js +198 -0
- package/dist/advanced/static/serveStatic.js.map +1 -0
- package/dist/advanced/static/spa.d.ts +14 -0
- package/dist/advanced/static/spa.d.ts.map +1 -0
- package/dist/advanced/static/spa.js +23 -0
- package/dist/advanced/static/spa.js.map +1 -0
- package/dist/advanced/static/types.d.ts +78 -0
- package/dist/advanced/static/types.d.ts.map +1 -0
- package/dist/advanced/static/types.js +67 -0
- package/dist/advanced/static/types.js.map +1 -0
- package/dist/advanced/swagger/SwaggerGenerator.d.ts +19 -0
- package/dist/advanced/swagger/SwaggerGenerator.d.ts.map +1 -0
- package/dist/advanced/swagger/SwaggerGenerator.js +59 -0
- package/dist/advanced/swagger/SwaggerGenerator.js.map +1 -0
- package/dist/advanced/swagger/buildOperation.d.ts +6 -0
- package/dist/advanced/swagger/buildOperation.d.ts.map +1 -0
- package/dist/advanced/swagger/buildOperation.js +54 -0
- package/dist/advanced/swagger/buildOperation.js.map +1 -0
- package/dist/advanced/swagger/buildParameters.d.ts +6 -0
- package/dist/advanced/swagger/buildParameters.d.ts.map +1 -0
- package/dist/advanced/swagger/buildParameters.js +57 -0
- package/dist/advanced/swagger/buildParameters.js.map +1 -0
- package/dist/advanced/swagger/buildRequestBody.d.ts +7 -0
- package/dist/advanced/swagger/buildRequestBody.d.ts.map +1 -0
- package/dist/advanced/swagger/buildRequestBody.js +19 -0
- package/dist/advanced/swagger/buildRequestBody.js.map +1 -0
- package/dist/advanced/swagger/buildResponses.d.ts +7 -0
- package/dist/advanced/swagger/buildResponses.d.ts.map +1 -0
- package/dist/advanced/swagger/buildResponses.js +48 -0
- package/dist/advanced/swagger/buildResponses.js.map +1 -0
- package/dist/advanced/swagger/capitalize.d.ts +2 -0
- package/dist/advanced/swagger/capitalize.d.ts.map +1 -0
- package/dist/advanced/swagger/capitalize.js +7 -0
- package/dist/advanced/swagger/capitalize.js.map +1 -0
- package/dist/advanced/swagger/convertPath.d.ts +6 -0
- package/dist/advanced/swagger/convertPath.d.ts.map +1 -0
- package/dist/advanced/swagger/convertPath.js +11 -0
- package/dist/advanced/swagger/convertPath.js.map +1 -0
- package/dist/advanced/swagger/createSwagger.d.ts +8 -0
- package/dist/advanced/swagger/createSwagger.d.ts.map +1 -0
- package/dist/advanced/swagger/createSwagger.js +12 -0
- package/dist/advanced/swagger/createSwagger.js.map +1 -0
- package/dist/advanced/swagger/generateOperationId.d.ts +6 -0
- package/dist/advanced/swagger/generateOperationId.d.ts.map +1 -0
- package/dist/advanced/swagger/generateOperationId.js +20 -0
- package/dist/advanced/swagger/generateOperationId.js.map +1 -0
- package/dist/advanced/swagger/generateSpec.d.ts +6 -0
- package/dist/advanced/swagger/generateSpec.d.ts.map +1 -0
- package/dist/advanced/swagger/generateSpec.js +85 -0
- package/dist/advanced/swagger/generateSpec.js.map +1 -0
- package/dist/advanced/swagger/generateSummary.d.ts +6 -0
- package/dist/advanced/swagger/generateSummary.d.ts.map +1 -0
- package/dist/advanced/swagger/generateSummary.js +22 -0
- package/dist/advanced/swagger/generateSummary.js.map +1 -0
- package/dist/advanced/swagger/generateSwaggerUI.d.ts +6 -0
- package/dist/advanced/swagger/generateSwaggerUI.d.ts.map +1 -0
- package/dist/advanced/swagger/generateSwaggerUI.js +69 -0
- package/dist/advanced/swagger/generateSwaggerUI.js.map +1 -0
- package/dist/advanced/swagger/generateThemeCss.d.ts +6 -0
- package/dist/advanced/swagger/generateThemeCss.d.ts.map +1 -0
- package/dist/advanced/swagger/generateThemeCss.js +53 -0
- package/dist/advanced/swagger/generateThemeCss.js.map +1 -0
- package/dist/advanced/swagger/index.d.ts +23 -0
- package/dist/advanced/swagger/index.d.ts.map +1 -0
- package/dist/advanced/swagger/index.js +26 -0
- package/dist/advanced/swagger/index.js.map +1 -0
- package/dist/advanced/swagger/swagger.d.ts +36 -0
- package/dist/advanced/swagger/swagger.d.ts.map +1 -0
- package/dist/advanced/swagger/swagger.js +198 -0
- package/dist/advanced/swagger/swagger.js.map +1 -0
- package/dist/advanced/swagger/types.d.ts +210 -0
- package/dist/advanced/swagger/types.d.ts.map +1 -0
- package/dist/advanced/swagger/types.js +3 -0
- package/dist/advanced/swagger/types.js.map +1 -0
- package/dist/advanced/swagger/zodFieldToOpenAPI.d.ts +6 -0
- package/dist/advanced/swagger/zodFieldToOpenAPI.d.ts.map +1 -0
- package/dist/advanced/swagger/zodFieldToOpenAPI.js +86 -0
- package/dist/advanced/swagger/zodFieldToOpenAPI.js.map +1 -0
- package/dist/advanced/swagger/zodSchemaToOpenAPI.d.ts +6 -0
- package/dist/advanced/swagger/zodSchemaToOpenAPI.d.ts.map +1 -0
- package/dist/advanced/swagger/zodSchemaToOpenAPI.js +44 -0
- package/dist/advanced/swagger/zodSchemaToOpenAPI.js.map +1 -0
- package/dist/advanced/swagger/zodToOpenAPI.d.ts +6 -0
- package/dist/advanced/swagger/zodToOpenAPI.d.ts.map +1 -0
- package/dist/advanced/swagger/zodToOpenAPI.js +22 -0
- package/dist/advanced/swagger/zodToOpenAPI.js.map +1 -0
- package/dist/advanced/testing/factory.d.ts +206 -0
- package/dist/advanced/testing/factory.d.ts.map +1 -0
- package/dist/advanced/testing/factory.js +433 -0
- package/dist/advanced/testing/factory.js.map +1 -0
- package/dist/advanced/testing/harness.d.ts +181 -0
- package/dist/advanced/testing/harness.d.ts.map +1 -0
- package/dist/advanced/testing/harness.js +481 -0
- package/dist/advanced/testing/harness.js.map +1 -0
- package/dist/advanced/testing/index.d.ts +235 -0
- package/dist/advanced/testing/index.d.ts.map +1 -0
- package/dist/advanced/testing/index.js +306 -0
- package/dist/advanced/testing/index.js.map +1 -0
- package/dist/advanced/testing/load-test.d.ts +148 -0
- package/dist/advanced/testing/load-test.d.ts.map +1 -0
- package/dist/advanced/testing/load-test.js +490 -0
- package/dist/advanced/testing/load-test.js.map +1 -0
- package/dist/advanced/testing/mock-server.d.ts +166 -0
- package/dist/advanced/testing/mock-server.d.ts.map +1 -0
- package/dist/advanced/testing/mock-server.js +424 -0
- package/dist/advanced/testing/mock-server.js.map +1 -0
- package/dist/advanced/testing/mock.d.ts +248 -0
- package/dist/advanced/testing/mock.d.ts.map +1 -0
- package/dist/advanced/testing/mock.js +549 -0
- package/dist/advanced/testing/mock.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +10 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/cli.d.ts +24 -0
- package/dist/cli/cli.d.ts.map +1 -0
- package/dist/cli/cli.js +131 -0
- package/dist/cli/cli.js.map +1 -0
- package/dist/cli/commands/build.d.ts +20 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +63 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/create.d.ts +13 -0
- package/dist/cli/commands/create.d.ts.map +1 -0
- package/dist/cli/commands/create.js +142 -0
- package/dist/cli/commands/create.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +15 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +77 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +13 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +80 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/help.d.ts +13 -0
- package/dist/cli/commands/help.d.ts.map +1 -0
- package/dist/cli/commands/help.js +83 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/init.d.ts +11 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +76 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/version.d.ts +9 -0
- package/dist/cli/commands/version.d.ts.map +1 -0
- package/dist/cli/commands/version.js +35 -0
- package/dist/cli/commands/version.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +7 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/templates/generators.d.ts +22 -0
- package/dist/cli/templates/generators.d.ts.map +1 -0
- package/dist/cli/templates/generators.js +282 -0
- package/dist/cli/templates/generators.js.map +1 -0
- package/dist/cli/templates/index.d.ts +27 -0
- package/dist/cli/templates/index.d.ts.map +1 -0
- package/dist/cli/templates/index.js +651 -0
- package/dist/cli/templates/index.js.map +1 -0
- package/dist/cli/utils/exec.d.ts +12 -0
- package/dist/cli/utils/exec.d.ts.map +1 -0
- package/dist/cli/utils/exec.js +37 -0
- package/dist/cli/utils/exec.js.map +1 -0
- package/dist/cli/utils/file-system.d.ts +15 -0
- package/dist/cli/utils/file-system.d.ts.map +1 -0
- package/dist/cli/utils/file-system.js +105 -0
- package/dist/cli/utils/file-system.js.map +1 -0
- package/dist/cli/utils/logger.d.ts +40 -0
- package/dist/cli/utils/logger.d.ts.map +1 -0
- package/dist/cli/utils/logger.js +100 -0
- package/dist/cli/utils/logger.js.map +1 -0
- package/dist/core/adapter.d.ts +73 -0
- package/dist/core/adapter.d.ts.map +1 -0
- package/dist/core/adapter.js +27 -0
- package/dist/core/adapter.js.map +1 -0
- package/dist/core/application.d.ts +540 -0
- package/dist/core/application.d.ts.map +1 -0
- package/dist/core/application.js +1111 -0
- package/dist/core/application.js.map +1 -0
- package/dist/core/context-pool.d.ts +52 -0
- package/dist/core/context-pool.d.ts.map +1 -0
- package/dist/core/context-pool.js +111 -0
- package/dist/core/context-pool.js.map +1 -0
- package/dist/core/context.d.ts +148 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +367 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/index.d.ts +23 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +77 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/middleware.d.ts +49 -0
- package/dist/core/middleware.d.ts.map +1 -0
- package/dist/core/middleware.js +215 -0
- package/dist/core/middleware.js.map +1 -0
- package/dist/core/performance/buffer-pool.d.ts +47 -0
- package/dist/core/performance/buffer-pool.d.ts.map +1 -0
- package/dist/core/performance/buffer-pool.js +97 -0
- package/dist/core/performance/buffer-pool.js.map +1 -0
- package/dist/core/performance/jit-compiler.d.ts +73 -0
- package/dist/core/performance/jit-compiler.d.ts.map +1 -0
- package/dist/core/performance/jit-compiler.js +145 -0
- package/dist/core/performance/jit-compiler.js.map +1 -0
- package/dist/core/performance/middleware-optimizer.d.ts +73 -0
- package/dist/core/performance/middleware-optimizer.d.ts.map +1 -0
- package/dist/core/performance/middleware-optimizer.js +138 -0
- package/dist/core/performance/middleware-optimizer.js.map +1 -0
- package/dist/core/plugin/PluginManager.d.ts +93 -0
- package/dist/core/plugin/PluginManager.d.ts.map +1 -0
- package/dist/core/plugin/PluginManager.js +351 -0
- package/dist/core/plugin/PluginManager.js.map +1 -0
- package/dist/core/plugin/builder.d.ts +192 -0
- package/dist/core/plugin/builder.d.ts.map +1 -0
- package/dist/core/plugin/builder.js +319 -0
- package/dist/core/plugin/builder.js.map +1 -0
- package/dist/core/plugin/index.d.ts +31 -0
- package/dist/core/plugin/index.d.ts.map +1 -0
- package/dist/core/plugin/index.js +41 -0
- package/dist/core/plugin/index.js.map +1 -0
- package/dist/core/plugin/types.d.ts +184 -0
- package/dist/core/plugin/types.d.ts.map +1 -0
- package/dist/core/plugin/types.js +17 -0
- package/dist/core/plugin/types.js.map +1 -0
- package/dist/core/router/file-router.d.ts +173 -0
- package/dist/core/router/file-router.d.ts.map +1 -0
- package/dist/core/router/file-router.js +498 -0
- package/dist/core/router/file-router.js.map +1 -0
- package/dist/core/router/index.d.ts +44 -0
- package/dist/core/router/index.d.ts.map +1 -0
- package/dist/core/router/index.js +145 -0
- package/dist/core/router/index.js.map +1 -0
- package/dist/core/router/radix-tree.d.ts +69 -0
- package/dist/core/router/radix-tree.d.ts.map +1 -0
- package/dist/core/router/radix-tree.js +196 -0
- package/dist/core/router/radix-tree.js.map +1 -0
- package/dist/core/store/index.d.ts +15 -0
- package/dist/core/store/index.d.ts.map +1 -0
- package/dist/core/store/index.js +23 -0
- package/dist/core/store/index.js.map +1 -0
- package/dist/core/store/registry.d.ts +80 -0
- package/dist/core/store/registry.d.ts.map +1 -0
- package/dist/core/store/registry.js +156 -0
- package/dist/core/store/registry.js.map +1 -0
- package/dist/core/store/request-store.d.ts +138 -0
- package/dist/core/store/request-store.d.ts.map +1 -0
- package/dist/core/store/request-store.js +209 -0
- package/dist/core/store/request-store.js.map +1 -0
- package/dist/core/store/types.d.ts +140 -0
- package/dist/core/store/types.d.ts.map +1 -0
- package/dist/core/store/types.js +176 -0
- package/dist/core/store/types.js.map +1 -0
- package/dist/core/types.d.ts +470 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +106 -0
- package/dist/core/types.js.map +1 -0
- package/dist/database/adapter.d.ts +32 -0
- package/dist/database/adapter.d.ts.map +1 -0
- package/dist/database/adapter.js +3 -0
- package/dist/database/adapter.js.map +1 -0
- package/dist/database/adapters/index.d.ts +2 -0
- package/dist/database/adapters/index.d.ts.map +1 -0
- package/dist/database/adapters/index.js +18 -0
- package/dist/database/adapters/index.js.map +1 -0
- package/dist/database/adapters/mysql.d.ts +160 -0
- package/dist/database/adapters/mysql.d.ts.map +1 -0
- package/dist/database/adapters/mysql.js +501 -0
- package/dist/database/adapters/mysql.js.map +1 -0
- package/dist/database/database.d.ts +27 -0
- package/dist/database/database.d.ts.map +1 -0
- package/dist/database/database.js +59 -0
- package/dist/database/database.js.map +1 -0
- package/dist/database/dialect.d.ts +110 -0
- package/dist/database/dialect.d.ts.map +1 -0
- package/dist/database/dialect.js +269 -0
- package/dist/database/dialect.js.map +1 -0
- package/dist/database/index.d.ts +12 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +28 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/migrations.d.ts +22 -0
- package/dist/database/migrations.d.ts.map +1 -0
- package/dist/database/migrations.js +73 -0
- package/dist/database/migrations.js.map +1 -0
- package/dist/database/optimizer.d.ts +25 -0
- package/dist/database/optimizer.d.ts.map +1 -0
- package/dist/database/optimizer.js +97 -0
- package/dist/database/optimizer.js.map +1 -0
- package/dist/database/query-builder.d.ts +49 -0
- package/dist/database/query-builder.d.ts.map +1 -0
- package/dist/database/query-builder.js +319 -0
- package/dist/database/query-builder.js.map +1 -0
- package/dist/database/realtime.d.ts +24 -0
- package/dist/database/realtime.d.ts.map +1 -0
- package/dist/database/realtime.js +38 -0
- package/dist/database/realtime.js.map +1 -0
- package/dist/database/schema.d.ts +27 -0
- package/dist/database/schema.d.ts.map +1 -0
- package/dist/database/schema.js +47 -0
- package/dist/database/schema.js.map +1 -0
- package/dist/database/transactions.d.ts +13 -0
- package/dist/database/transactions.d.ts.map +1 -0
- package/dist/database/transactions.js +51 -0
- package/dist/database/transactions.js.map +1 -0
- package/dist/database/types.d.ts +68 -0
- package/dist/database/types.d.ts.map +1 -0
- package/dist/database/types.js +3 -0
- package/dist/database/types.js.map +1 -0
- package/dist/deployment/cluster.d.ts +161 -0
- package/dist/deployment/cluster.d.ts.map +1 -0
- package/dist/deployment/cluster.js +336 -0
- package/dist/deployment/cluster.js.map +1 -0
- package/dist/deployment/config.d.ts +209 -0
- package/dist/deployment/config.d.ts.map +1 -0
- package/dist/deployment/config.js +263 -0
- package/dist/deployment/config.js.map +1 -0
- package/dist/deployment/docker.d.ts +168 -0
- package/dist/deployment/docker.d.ts.map +1 -0
- package/dist/deployment/docker.js +437 -0
- package/dist/deployment/docker.js.map +1 -0
- package/dist/deployment/graceful-shutdown.d.ts +130 -0
- package/dist/deployment/graceful-shutdown.d.ts.map +1 -0
- package/dist/deployment/graceful-shutdown.js +271 -0
- package/dist/deployment/graceful-shutdown.js.map +1 -0
- package/dist/deployment/index.d.ts +14 -0
- package/dist/deployment/index.d.ts.map +1 -0
- package/dist/deployment/index.js +33 -0
- package/dist/deployment/index.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +174 -0
- package/dist/index.js.map +1 -0
- package/dist/security/adapter.d.ts +144 -0
- package/dist/security/adapter.d.ts.map +1 -0
- package/dist/security/adapter.js +159 -0
- package/dist/security/adapter.js.map +1 -0
- package/dist/security/auth/JWTPlugin.d.ts +105 -0
- package/dist/security/auth/JWTPlugin.d.ts.map +1 -0
- package/dist/security/auth/JWTPlugin.js +146 -0
- package/dist/security/auth/JWTPlugin.js.map +1 -0
- package/dist/security/auth/JWTProvider.d.ts +104 -0
- package/dist/security/auth/JWTProvider.d.ts.map +1 -0
- package/dist/security/auth/JWTProvider.js +288 -0
- package/dist/security/auth/JWTProvider.js.map +1 -0
- package/dist/security/auth/adapter.d.ts +8 -0
- package/dist/security/auth/adapter.d.ts.map +1 -0
- package/dist/security/auth/adapter.js +29 -0
- package/dist/security/auth/adapter.js.map +1 -0
- package/dist/security/auth/jwt.d.ts +55 -0
- package/dist/security/auth/jwt.d.ts.map +1 -0
- package/dist/security/auth/jwt.js +198 -0
- package/dist/security/auth/jwt.js.map +1 -0
- package/dist/security/auth/middleware.d.ts +64 -0
- package/dist/security/auth/middleware.d.ts.map +1 -0
- package/dist/security/auth/middleware.js +161 -0
- package/dist/security/auth/middleware.js.map +1 -0
- package/dist/security/csrf.d.ts +41 -0
- package/dist/security/csrf.d.ts.map +1 -0
- package/dist/security/csrf.js +185 -0
- package/dist/security/csrf.js.map +1 -0
- package/dist/security/headers.d.ts +34 -0
- package/dist/security/headers.d.ts.map +1 -0
- package/dist/security/headers.js +95 -0
- package/dist/security/headers.js.map +1 -0
- package/dist/security/index.d.ts +19 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +65 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/rate-limit/adapter.d.ts +7 -0
- package/dist/security/rate-limit/adapter.d.ts.map +1 -0
- package/dist/security/rate-limit/adapter.js +8 -0
- package/dist/security/rate-limit/adapter.js.map +1 -0
- package/dist/security/rate-limit/memory.d.ts +28 -0
- package/dist/security/rate-limit/memory.d.ts.map +1 -0
- package/dist/security/rate-limit/memory.js +85 -0
- package/dist/security/rate-limit/memory.js.map +1 -0
- package/dist/security/rate-limit/middleware.d.ts +32 -0
- package/dist/security/rate-limit/middleware.d.ts.map +1 -0
- package/dist/security/rate-limit/middleware.js +159 -0
- package/dist/security/rate-limit/middleware.js.map +1 -0
- package/dist/security/sanitization.d.ts +29 -0
- package/dist/security/sanitization.d.ts.map +1 -0
- package/dist/security/sanitization.js +66 -0
- package/dist/security/sanitization.js.map +1 -0
- package/dist/security/types.d.ts +205 -0
- package/dist/security/types.d.ts.map +1 -0
- package/dist/security/types.js +8 -0
- package/dist/security/types.js.map +1 -0
- package/dist/security/utils.d.ts +19 -0
- package/dist/security/utils.d.ts.map +1 -0
- package/dist/security/utils.js +43 -0
- package/dist/security/utils.js.map +1 -0
- package/documentation/01-getting-started.md +240 -0
- package/documentation/02-context.md +335 -0
- package/documentation/03-routing.md +397 -0
- package/documentation/04-middleware.md +483 -0
- package/documentation/05-validation.md +514 -0
- package/documentation/06-error-handling.md +465 -0
- package/documentation/07-performance.md +364 -0
- package/documentation/08-adapters.md +470 -0
- package/documentation/09-api-reference.md +548 -0
- package/documentation/10-examples.md +582 -0
- package/documentation/11-deployment.md +477 -0
- package/documentation/12-sentry.md +620 -0
- package/documentation/13-sentry-data-storage.md +996 -0
- package/documentation/14-sentry-data-reference.md +457 -0
- package/documentation/15-sentry-summary.md +409 -0
- package/documentation/16-alerts-system.md +745 -0
- package/documentation/17-alert-adapters.md +696 -0
- package/documentation/18-alerts-implementation-summary.md +385 -0
- package/documentation/19-class-based-routing.md +840 -0
- package/documentation/20-websocket-realtime.md +813 -0
- package/documentation/21-cache-system.md +510 -0
- package/documentation/22-job-queue.md +772 -0
- package/documentation/23-sentry-plugin.md +551 -0
- package/documentation/24-testing-utilities.md +1287 -0
- package/documentation/25-api-versioning.md +533 -0
- package/documentation/26-context-store.md +607 -0
- package/documentation/27-dependency-injection.md +329 -0
- package/documentation/28-lifecycle-hooks.md +521 -0
- package/documentation/29-package-structure.md +196 -0
- package/documentation/30-plugin-system.md +414 -0
- package/documentation/31-jwt-authentication.md +597 -0
- package/documentation/32-cli.md +268 -0
- package/documentation/ALERTS-COMPLETE-SUMMARY.md +429 -0
- package/documentation/ALERTS-INDEX.md +330 -0
- package/documentation/ALERTS-QUICK-REFERENCE.md +286 -0
- package/documentation/README.md +178 -0
- package/documentation/index.html +34 -0
- package/modern_framework_paper.md +1870 -0
- package/package.json +178 -0
- package/public/css/style.css +87 -0
- package/public/index.html +34 -0
- package/public/js/app.js +27 -0
- package/src/advanced/cache/InMemoryCacheStore.ts +68 -0
- package/src/advanced/cache/MultiTierCache.ts +194 -0
- package/src/advanced/cache/RedisCacheStore.ts +341 -0
- package/src/advanced/cache/index.ts +5 -0
- package/src/advanced/cache/types.ts +40 -0
- package/src/advanced/graphql/SimpleDataLoader.ts +42 -0
- package/src/advanced/graphql/index.ts +22 -0
- package/src/advanced/graphql/server.ts +252 -0
- package/src/advanced/graphql/types.ts +42 -0
- package/src/advanced/jobs/InMemoryQueueStore.ts +68 -0
- package/src/advanced/jobs/JobQueue.ts +556 -0
- package/src/advanced/jobs/RedisQueueStore.ts +367 -0
- package/src/advanced/jobs/index.ts +5 -0
- package/src/advanced/jobs/types.ts +70 -0
- package/src/advanced/observability/APMManager.ts +163 -0
- package/src/advanced/observability/AlertManager.ts +109 -0
- package/src/advanced/observability/MetricRegistry.ts +151 -0
- package/src/advanced/observability/ObservabilityCenter.ts +304 -0
- package/src/advanced/observability/StructuredLogger.ts +154 -0
- package/src/advanced/observability/TracingManager.ts +117 -0
- package/src/advanced/observability/adapters.ts +304 -0
- package/src/advanced/observability/createObservabilityMiddleware.ts +63 -0
- package/src/advanced/observability/index.ts +11 -0
- package/src/advanced/observability/types.ts +174 -0
- package/src/advanced/playground/extractPathParams.ts +6 -0
- package/src/advanced/playground/generateFieldExample.ts +31 -0
- package/src/advanced/playground/generatePlaygroundHTML.ts +1849 -0
- package/src/advanced/playground/generateSummary.ts +19 -0
- package/src/advanced/playground/getTagFromPath.ts +9 -0
- package/src/advanced/playground/index.ts +8 -0
- package/src/advanced/playground/playground.ts +170 -0
- package/src/advanced/playground/types.ts +20 -0
- package/src/advanced/playground/zodToExample.ts +16 -0
- package/src/advanced/playground/zodToParams.ts +15 -0
- package/src/advanced/postman/buildAuth.ts +31 -0
- package/src/advanced/postman/buildBody.ts +15 -0
- package/src/advanced/postman/buildQueryParams.ts +27 -0
- package/src/advanced/postman/buildRequestItem.ts +36 -0
- package/src/advanced/postman/buildResponses.ts +11 -0
- package/src/advanced/postman/buildUrl.ts +33 -0
- package/src/advanced/postman/capitalize.ts +4 -0
- package/src/advanced/postman/generateCollection.ts +59 -0
- package/src/advanced/postman/generateEnvironment.ts +34 -0
- package/src/advanced/postman/generateExampleFromZod.ts +21 -0
- package/src/advanced/postman/generateFieldExample.ts +45 -0
- package/src/advanced/postman/generateName.ts +20 -0
- package/src/advanced/postman/generateUUID.ts +11 -0
- package/src/advanced/postman/getTagFromPath.ts +10 -0
- package/src/advanced/postman/index.ts +28 -0
- package/src/advanced/postman/postman.ts +156 -0
- package/src/advanced/postman/slugify.ts +7 -0
- package/src/advanced/postman/types.ts +140 -0
- package/src/advanced/realtime/index.ts +18 -0
- package/src/advanced/realtime/websocket.ts +211 -0
- package/src/advanced/sentry/index.ts +1236 -0
- package/src/advanced/sentry/types.ts +355 -0
- package/src/advanced/static/generateDirectoryListing.ts +47 -0
- package/src/advanced/static/generateETag.ts +7 -0
- package/src/advanced/static/getMimeType.ts +9 -0
- package/src/advanced/static/index.ts +32 -0
- package/src/advanced/static/isSafePath.ts +13 -0
- package/src/advanced/static/publicDir.ts +21 -0
- package/src/advanced/static/serveStatic.ts +225 -0
- package/src/advanced/static/spa.ts +24 -0
- package/src/advanced/static/types.ts +159 -0
- package/src/advanced/swagger/SwaggerGenerator.ts +66 -0
- package/src/advanced/swagger/buildOperation.ts +61 -0
- package/src/advanced/swagger/buildParameters.ts +61 -0
- package/src/advanced/swagger/buildRequestBody.ts +21 -0
- package/src/advanced/swagger/buildResponses.ts +54 -0
- package/src/advanced/swagger/capitalize.ts +5 -0
- package/src/advanced/swagger/convertPath.ts +9 -0
- package/src/advanced/swagger/createSwagger.ts +12 -0
- package/src/advanced/swagger/generateOperationId.ts +21 -0
- package/src/advanced/swagger/generateSpec.ts +105 -0
- package/src/advanced/swagger/generateSummary.ts +24 -0
- package/src/advanced/swagger/generateSwaggerUI.ts +70 -0
- package/src/advanced/swagger/generateThemeCss.ts +53 -0
- package/src/advanced/swagger/index.ts +25 -0
- package/src/advanced/swagger/swagger.ts +237 -0
- package/src/advanced/swagger/types.ts +206 -0
- package/src/advanced/swagger/zodFieldToOpenAPI.ts +94 -0
- package/src/advanced/swagger/zodSchemaToOpenAPI.ts +50 -0
- package/src/advanced/swagger/zodToOpenAPI.ts +22 -0
- package/src/advanced/testing/factory.ts +509 -0
- package/src/advanced/testing/harness.ts +612 -0
- package/src/advanced/testing/index.ts +430 -0
- package/src/advanced/testing/load-test.ts +618 -0
- package/src/advanced/testing/mock-server.ts +498 -0
- package/src/advanced/testing/mock.ts +670 -0
- package/src/cli/bin.ts +9 -0
- package/src/cli/cli.ts +155 -0
- package/src/cli/commands/build.ts +73 -0
- package/src/cli/commands/create.ts +166 -0
- package/src/cli/commands/dev.ts +85 -0
- package/src/cli/commands/generate.ts +97 -0
- package/src/cli/commands/help.ts +95 -0
- package/src/cli/commands/init.ts +91 -0
- package/src/cli/commands/version.ts +38 -0
- package/src/cli/index.ts +6 -0
- package/src/cli/templates/generators.ts +309 -0
- package/src/cli/templates/index.ts +679 -0
- package/src/cli/utils/exec.ts +52 -0
- package/src/cli/utils/file-system.ts +78 -0
- package/src/cli/utils/logger.ts +111 -0
- package/src/core/adapter.ts +88 -0
- package/src/core/application.ts +1283 -0
- package/src/core/context-pool.ts +127 -0
- package/src/core/context.ts +412 -0
- package/src/core/index.ts +80 -0
- package/src/core/middleware.ts +262 -0
- package/src/core/performance/buffer-pool.ts +108 -0
- package/src/core/performance/middleware-optimizer.ts +162 -0
- package/src/core/plugin/PluginManager.ts +435 -0
- package/src/core/plugin/builder.ts +358 -0
- package/src/core/plugin/index.ts +50 -0
- package/src/core/plugin/types.ts +214 -0
- package/src/core/router/file-router.ts +594 -0
- package/src/core/router/index.ts +182 -0
- package/src/core/router/radix-tree.ts +226 -0
- package/src/core/store/index.ts +30 -0
- package/src/core/store/registry.ts +178 -0
- package/src/core/store/request-store.ts +240 -0
- package/src/core/store/types.ts +233 -0
- package/src/core/types.ts +574 -0
- package/src/database/adapter.ts +35 -0
- package/src/database/adapters/index.ts +1 -0
- package/src/database/adapters/mysql.ts +669 -0
- package/src/database/database.ts +70 -0
- package/src/database/dialect.ts +388 -0
- package/src/database/index.ts +12 -0
- package/src/database/migrations.ts +86 -0
- package/src/database/optimizer.ts +125 -0
- package/src/database/query-builder.ts +404 -0
- package/src/database/realtime.ts +53 -0
- package/src/database/schema.ts +71 -0
- package/src/database/transactions.ts +56 -0
- package/src/database/types.ts +87 -0
- package/src/deployment/cluster.ts +471 -0
- package/src/deployment/config.ts +454 -0
- package/src/deployment/docker.ts +599 -0
- package/src/deployment/graceful-shutdown.ts +373 -0
- package/src/deployment/index.ts +56 -0
- package/src/index.ts +264 -0
- package/src/security/adapter.ts +318 -0
- package/src/security/auth/JWTPlugin.ts +234 -0
- package/src/security/auth/JWTProvider.ts +316 -0
- package/src/security/auth/adapter.ts +12 -0
- package/src/security/auth/jwt.ts +234 -0
- package/src/security/auth/middleware.ts +188 -0
- package/src/security/csrf.ts +220 -0
- package/src/security/headers.ts +108 -0
- package/src/security/index.ts +60 -0
- package/src/security/rate-limit/adapter.ts +7 -0
- package/src/security/rate-limit/memory.ts +108 -0
- package/src/security/rate-limit/middleware.ts +181 -0
- package/src/security/sanitization.ts +75 -0
- package/src/security/types.ts +240 -0
- package/src/security/utils.ts +52 -0
- package/tsconfig.json +39 -0
|
@@ -0,0 +1,1283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main application class
|
|
3
|
+
* Orchestrates all framework components
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createServer, Server as HTTPServer, IncomingMessage, ServerResponse } from 'http';
|
|
7
|
+
import { Router } from './router';
|
|
8
|
+
import { ContextPool } from './context-pool';
|
|
9
|
+
import { MiddlewareExecutor } from './middleware';
|
|
10
|
+
import {
|
|
11
|
+
Context,
|
|
12
|
+
Handler,
|
|
13
|
+
Middleware,
|
|
14
|
+
Response,
|
|
15
|
+
AppConfig,
|
|
16
|
+
ErrorHandler,
|
|
17
|
+
RouteConfig,
|
|
18
|
+
Plugin,
|
|
19
|
+
HTTPMethod,
|
|
20
|
+
RouteBase,
|
|
21
|
+
Route,
|
|
22
|
+
VersioningConfig,
|
|
23
|
+
VersioningStrategy,
|
|
24
|
+
DependencyContainer,
|
|
25
|
+
InjectedRouteConfig,
|
|
26
|
+
LifecycleHooks
|
|
27
|
+
} from './types';
|
|
28
|
+
import { AdapterRegistry } from './adapter';
|
|
29
|
+
import { PluginManager, NexusPlugin, SimplePlugin } from './plugin';
|
|
30
|
+
import { FileRouter, FileRouterOptions } from './router/file-router';
|
|
31
|
+
import { createObservabilityMiddleware } from '../advanced/observability/createObservabilityMiddleware';
|
|
32
|
+
import { ObservabilityCenter } from '../advanced/observability/ObservabilityCenter';
|
|
33
|
+
import {
|
|
34
|
+
GracefulShutdownManager,
|
|
35
|
+
GracefulShutdownOptions,
|
|
36
|
+
ClusterManager,
|
|
37
|
+
ClusterOptions
|
|
38
|
+
} from '../deployment';
|
|
39
|
+
import {
|
|
40
|
+
WebSocketGateway,
|
|
41
|
+
WebSocketRouteConfig
|
|
42
|
+
} from '../advanced/realtime/websocket';
|
|
43
|
+
import { ObservabilityOptions } from '../advanced/observability/types';
|
|
44
|
+
import { StoreRegistry, StoreConstructor, ContextStore } from './store';
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Default error handler
|
|
48
|
+
*/
|
|
49
|
+
const defaultErrorHandler: ErrorHandler = (error: Error, ctx: Context): Response => {
|
|
50
|
+
// Only log unexpected errors, not intentional ones (returned from handler)
|
|
51
|
+
if (!(error as any)._isIntentional) {
|
|
52
|
+
console.error('Unhandled error:', error);
|
|
53
|
+
console.error('Path:', ctx.path, 'Method:', ctx.method);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
statusCode: 500,
|
|
58
|
+
headers: { 'Content-Type': 'application/json' },
|
|
59
|
+
body: JSON.stringify({
|
|
60
|
+
error: error.message || 'Internal Server Error',
|
|
61
|
+
stack: process.env.NODE_ENV === 'development' && !(error as any)._isIntentional ? error.stack : undefined
|
|
62
|
+
})
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Application class
|
|
68
|
+
*/
|
|
69
|
+
export class Application<TDeps extends DependencyContainer = {}> {
|
|
70
|
+
private router: Router;
|
|
71
|
+
private contextPool: ContextPool;
|
|
72
|
+
private middlewareExecutor: MiddlewareExecutor;
|
|
73
|
+
private globalMiddlewares: Middleware[] = [];
|
|
74
|
+
private errorHandler: ErrorHandler;
|
|
75
|
+
private server?: HTTPServer;
|
|
76
|
+
private config: AppConfig;
|
|
77
|
+
private adapters: AdapterRegistry;
|
|
78
|
+
private shutdownManager?: GracefulShutdownManager;
|
|
79
|
+
private clusterManager?: ClusterManager;
|
|
80
|
+
private fallbackHandler?: Handler;
|
|
81
|
+
private wsGateway?: WebSocketGateway;
|
|
82
|
+
|
|
83
|
+
// Dependency injection container
|
|
84
|
+
private dependencies: TDeps = {} as TDeps;
|
|
85
|
+
|
|
86
|
+
// Versioning properties
|
|
87
|
+
private versioningConfig?: VersioningConfig;
|
|
88
|
+
private registeredVersions: Set<string> = new Set();
|
|
89
|
+
|
|
90
|
+
// Store registry for ContextStore system
|
|
91
|
+
private storeRegistry: StoreRegistry;
|
|
92
|
+
|
|
93
|
+
// Plugin manager for advanced plugins
|
|
94
|
+
private pluginManager: PluginManager;
|
|
95
|
+
|
|
96
|
+
// Lifecycle hooks
|
|
97
|
+
private lifecycleHooks: LifecycleHooks = {};
|
|
98
|
+
|
|
99
|
+
constructor(config: AppConfig = {}) {
|
|
100
|
+
this.config = {
|
|
101
|
+
contextPoolSize: 100,
|
|
102
|
+
enableJIT: true,
|
|
103
|
+
debug: false,
|
|
104
|
+
logRequests: true,
|
|
105
|
+
...config
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
this.router = new Router();
|
|
109
|
+
this.contextPool = new ContextPool(this.config.contextPoolSize);
|
|
110
|
+
this.middlewareExecutor = new MiddlewareExecutor();
|
|
111
|
+
this.errorHandler = config.onError || defaultErrorHandler;
|
|
112
|
+
this.adapters = new AdapterRegistry();
|
|
113
|
+
this.storeRegistry = new StoreRegistry({ debug: config.debug });
|
|
114
|
+
this.pluginManager = new PluginManager(this, { debug: config.debug });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Register lifecycle hooks for request processing
|
|
119
|
+
* Hooks are called at specific points during request lifecycle
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* app.hooks({
|
|
124
|
+
* onRequest: async (ctx) => {
|
|
125
|
+
* ctx.requestId = crypto.randomUUID();
|
|
126
|
+
* console.log(`[${ctx.requestId}] ${ctx.method} ${ctx.path}`);
|
|
127
|
+
* },
|
|
128
|
+
*
|
|
129
|
+
* beforeValidation: async (ctx) => {
|
|
130
|
+
* // Transform raw body before validation
|
|
131
|
+
* if (ctx.body?.data) {
|
|
132
|
+
* ctx.body = ctx.body.data;
|
|
133
|
+
* }
|
|
134
|
+
* },
|
|
135
|
+
*
|
|
136
|
+
* afterValidation: async (ctx) => {
|
|
137
|
+
* // Check authorization after body is validated
|
|
138
|
+
* if (!ctx.headers.authorization) {
|
|
139
|
+
* return ctx.response.status(401).json({ error: 'Unauthorized' });
|
|
140
|
+
* }
|
|
141
|
+
* },
|
|
142
|
+
*
|
|
143
|
+
* beforeHandler: async (ctx) => {
|
|
144
|
+
* // Load user from session
|
|
145
|
+
* ctx.user = await getUserFromToken(ctx.headers.authorization);
|
|
146
|
+
* },
|
|
147
|
+
*
|
|
148
|
+
* afterHandler: async (ctx, result) => {
|
|
149
|
+
* // Add metadata to all responses
|
|
150
|
+
* return { ...result, timestamp: Date.now(), requestId: ctx.requestId };
|
|
151
|
+
* },
|
|
152
|
+
*
|
|
153
|
+
* onError: async (ctx, error) => {
|
|
154
|
+
* // Log errors to external service
|
|
155
|
+
* await logToSentry(error, { requestId: ctx.requestId });
|
|
156
|
+
* },
|
|
157
|
+
*
|
|
158
|
+
* onResponse: async (ctx, response) => {
|
|
159
|
+
* console.log(`[${ctx.requestId}] Response: ${response.statusCode}`);
|
|
160
|
+
* }
|
|
161
|
+
* });
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
hooks(hooks: LifecycleHooks): this {
|
|
165
|
+
this.lifecycleHooks = { ...this.lifecycleHooks, ...hooks };
|
|
166
|
+
return this;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Set a fallback handler for unmatched routes (e.g., static files)
|
|
171
|
+
* Called before returning 404
|
|
172
|
+
*/
|
|
173
|
+
setFallbackHandler(handler: Handler): this {
|
|
174
|
+
this.fallbackHandler = handler;
|
|
175
|
+
return this;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Provide dependencies for injection into route handlers
|
|
180
|
+
* Dependencies are available via the second parameter in handlers
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const db = new Database();
|
|
185
|
+
* const cache = new Redis();
|
|
186
|
+
* const mailer = new Mailer();
|
|
187
|
+
*
|
|
188
|
+
* const app = createApp()
|
|
189
|
+
* .provide({ db, cache, mailer });
|
|
190
|
+
*
|
|
191
|
+
* // Use with inject option
|
|
192
|
+
* app.get('/users', {
|
|
193
|
+
* inject: ['db', 'cache'],
|
|
194
|
+
* handler: async (ctx, { db, cache }) => {
|
|
195
|
+
* // db and cache are fully typed!
|
|
196
|
+
* const users = await db.query('SELECT * FROM users');
|
|
197
|
+
* await cache.set('users', users);
|
|
198
|
+
* return { users };
|
|
199
|
+
* }
|
|
200
|
+
* });
|
|
201
|
+
*
|
|
202
|
+
* // Or access all dependencies
|
|
203
|
+
* app.get('/mail', async (ctx, deps) => {
|
|
204
|
+
* await deps.mailer.send({ to: 'user@example.com', subject: 'Hello' });
|
|
205
|
+
* return { sent: true };
|
|
206
|
+
* });
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
provide<T extends DependencyContainer>(deps: T): Application<TDeps & T> {
|
|
210
|
+
this.dependencies = { ...this.dependencies, ...deps } as TDeps & T;
|
|
211
|
+
return this as unknown as Application<TDeps & T>;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get a specific dependency by name
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```typescript
|
|
219
|
+
* const db = app.getDep('db');
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
getDep<K extends keyof TDeps>(name: K): TDeps[K] {
|
|
223
|
+
return this.dependencies[name];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Get all registered dependencies
|
|
228
|
+
*/
|
|
229
|
+
getDeps(): TDeps {
|
|
230
|
+
return this.dependencies;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Configure API versioning
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```typescript
|
|
238
|
+
* app.configVersions({
|
|
239
|
+
* strategies: ['header', 'query'],
|
|
240
|
+
* header: 'api-version',
|
|
241
|
+
* queryParam: 'v',
|
|
242
|
+
* defaultVersion: 'v1',
|
|
243
|
+
* register: ['v1', 'v2']
|
|
244
|
+
* });
|
|
245
|
+
*
|
|
246
|
+
* // Route tanpa prefix → otomatis jadi /{defaultVersion}/login
|
|
247
|
+
* app.post('/login', handler);
|
|
248
|
+
*
|
|
249
|
+
* // Route dengan prefix explicit
|
|
250
|
+
* app.post('/v2/login', handler);
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
configVersions(config: VersioningConfig): this {
|
|
254
|
+
this.versioningConfig = {
|
|
255
|
+
header: 'api-version',
|
|
256
|
+
queryParam: 'v',
|
|
257
|
+
...config
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// Register all versions
|
|
261
|
+
config.register.forEach(v => this.registeredVersions.add(v));
|
|
262
|
+
|
|
263
|
+
return this;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Check if a path starts with a registered version prefix
|
|
268
|
+
*/
|
|
269
|
+
private hasVersionPrefix(path: string): string | null {
|
|
270
|
+
const segment = path.split('/').filter(Boolean)[0];
|
|
271
|
+
if (segment && this.registeredVersions.has(segment)) {
|
|
272
|
+
return segment;
|
|
273
|
+
}
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Resolve version from request context
|
|
279
|
+
*/
|
|
280
|
+
private resolveVersion(ctx: Context): { version: string; basePath: string; source: VersioningStrategy | 'default' } {
|
|
281
|
+
if (!this.versioningConfig) {
|
|
282
|
+
return { version: '', basePath: ctx.path, source: 'default' };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const { strategies, header, queryParam, defaultVersion } = this.versioningConfig;
|
|
286
|
+
|
|
287
|
+
// 1. Check path strategy: /v1/login
|
|
288
|
+
if (strategies.includes('path')) {
|
|
289
|
+
const versionPrefix = this.hasVersionPrefix(ctx.path);
|
|
290
|
+
if (versionPrefix) {
|
|
291
|
+
const basePath = ctx.path.replace(new RegExp(`^/${versionPrefix}`), '') || '/';
|
|
292
|
+
return { version: versionPrefix, basePath, source: 'path' };
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 2. Check header strategy
|
|
297
|
+
if (strategies.includes('header') && header) {
|
|
298
|
+
const headerValue = ctx.headers[header] || ctx.headers[header.toLowerCase()];
|
|
299
|
+
const version = Array.isArray(headerValue) ? headerValue[0] : headerValue;
|
|
300
|
+
if (version && this.registeredVersions.has(version)) {
|
|
301
|
+
return { version, basePath: ctx.path, source: 'header' };
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// 3. Check query strategy
|
|
306
|
+
if (strategies.includes('query') && queryParam) {
|
|
307
|
+
const queryVersion = ctx.query?.[queryParam];
|
|
308
|
+
const version = Array.isArray(queryVersion) ? queryVersion[0] : queryVersion;
|
|
309
|
+
if (version && this.registeredVersions.has(version)) {
|
|
310
|
+
return { version, basePath: ctx.path, source: 'query' };
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// 4. Default version
|
|
315
|
+
return { version: defaultVersion, basePath: ctx.path, source: 'default' };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Build versioned path for route registration
|
|
320
|
+
*/
|
|
321
|
+
private buildVersionedPath(path: string): string {
|
|
322
|
+
if (!this.versioningConfig) return path;
|
|
323
|
+
|
|
324
|
+
// If path already has version prefix, return as-is
|
|
325
|
+
if (this.hasVersionPrefix(path)) {
|
|
326
|
+
return path;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Add default version prefix
|
|
330
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
331
|
+
return `/${this.versioningConfig.defaultVersion}${normalizedPath}`;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Add global middleware
|
|
336
|
+
*/
|
|
337
|
+
use(middleware: Middleware): this {
|
|
338
|
+
this.globalMiddlewares.push(middleware);
|
|
339
|
+
return this;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Register ContextStore classes
|
|
344
|
+
* Stores are singleton instances accessible via ctx.store(StoreClass)
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* ```typescript
|
|
348
|
+
* class UserStore extends ContextStore<UserState> {
|
|
349
|
+
* protected initial() { return { users: [], loading: false }; }
|
|
350
|
+
*
|
|
351
|
+
* async fetchUsers() {
|
|
352
|
+
* this.update({ loading: true });
|
|
353
|
+
* const users = await api.getUsers();
|
|
354
|
+
* this.set({ users, loading: false });
|
|
355
|
+
* }
|
|
356
|
+
* }
|
|
357
|
+
*
|
|
358
|
+
* const app = createApp();
|
|
359
|
+
* app.stores([UserStore, ProductStore]);
|
|
360
|
+
*
|
|
361
|
+
* app.get('/users', async (ctx) => {
|
|
362
|
+
* const userStore = ctx.store(UserStore);
|
|
363
|
+
* return { users: userStore.state.users };
|
|
364
|
+
* });
|
|
365
|
+
* ```
|
|
366
|
+
*/
|
|
367
|
+
stores(storeClasses: StoreConstructor<any>[]): this {
|
|
368
|
+
this.storeRegistry.registerAll(storeClasses);
|
|
369
|
+
return this;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Register a single ContextStore class
|
|
374
|
+
*
|
|
375
|
+
* @example
|
|
376
|
+
* ```typescript
|
|
377
|
+
* app.store(UserStore);
|
|
378
|
+
* ```
|
|
379
|
+
*/
|
|
380
|
+
store<T extends ContextStore<any>>(StoreClass: StoreConstructor<T>): this {
|
|
381
|
+
this.storeRegistry.register(StoreClass);
|
|
382
|
+
return this;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Get a store instance directly from application level
|
|
387
|
+
* Useful for accessing stores outside of request context
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* ```typescript
|
|
391
|
+
* const userStore = app.getStore(UserStore);
|
|
392
|
+
* userStore.listen((state) => console.log('Users updated:', state));
|
|
393
|
+
* ```
|
|
394
|
+
*/
|
|
395
|
+
getStore<T extends ContextStore<any>>(StoreClass: StoreConstructor<T>): T {
|
|
396
|
+
return this.storeRegistry.get(StoreClass);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Get the store registry for advanced usage
|
|
401
|
+
*/
|
|
402
|
+
getStoreRegistry(): StoreRegistry {
|
|
403
|
+
return this.storeRegistry;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Register a route
|
|
408
|
+
*/
|
|
409
|
+
route(config: RouteConfig): this {
|
|
410
|
+
this.router.addRoute(config);
|
|
411
|
+
return this;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Convenience: GET route
|
|
416
|
+
* Supports both function-style and class-based routing
|
|
417
|
+
*
|
|
418
|
+
* @example
|
|
419
|
+
* ```typescript
|
|
420
|
+
* // Function style (with dependencies)
|
|
421
|
+
* app.get('/users', async (ctx, { db }) => ({ users: await db.getUsers() }));
|
|
422
|
+
*
|
|
423
|
+
* // Config style with inject
|
|
424
|
+
* app.get('/users', {
|
|
425
|
+
* inject: ['db', 'cache'],
|
|
426
|
+
* handler: async (ctx, { db, cache }) => ({ users: [] }),
|
|
427
|
+
* meta: {...}
|
|
428
|
+
* });
|
|
429
|
+
*
|
|
430
|
+
* // Class-based style
|
|
431
|
+
* app.get(new UserListRoute());
|
|
432
|
+
* ```
|
|
433
|
+
*/
|
|
434
|
+
get<K extends keyof TDeps = keyof TDeps>(
|
|
435
|
+
pathOrRoute: string | Route,
|
|
436
|
+
handlerOrConfig?: Handler<Context, TDeps> | InjectedRouteConfig<Context, TDeps, K>
|
|
437
|
+
): this {
|
|
438
|
+
// Class-based routing
|
|
439
|
+
if (typeof pathOrRoute === 'object' && ('pathName' in pathOrRoute || 'handler' in pathOrRoute)) {
|
|
440
|
+
return this.registerClassRoute('GET', pathOrRoute as Route);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return this.registerVersionedRoute('GET', pathOrRoute as string, handlerOrConfig);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Convenience: POST route
|
|
448
|
+
* Supports both function-style and class-based routing
|
|
449
|
+
*/
|
|
450
|
+
post<K extends keyof TDeps = keyof TDeps>(
|
|
451
|
+
pathOrRoute: string | Route,
|
|
452
|
+
handlerOrConfig?: Handler<Context, TDeps> | InjectedRouteConfig<Context, TDeps, K>
|
|
453
|
+
): this {
|
|
454
|
+
// Class-based routing
|
|
455
|
+
if (typeof pathOrRoute === 'object' && ('pathName' in pathOrRoute || 'handler' in pathOrRoute)) {
|
|
456
|
+
return this.registerClassRoute('POST', pathOrRoute as Route);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
return this.registerVersionedRoute('POST', pathOrRoute as string, handlerOrConfig);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Convenience: PUT route
|
|
464
|
+
* Supports both function-style and class-based routing
|
|
465
|
+
*/
|
|
466
|
+
put<K extends keyof TDeps = keyof TDeps>(
|
|
467
|
+
pathOrRoute: string | Route,
|
|
468
|
+
handlerOrConfig?: Handler<Context, TDeps> | InjectedRouteConfig<Context, TDeps, K>
|
|
469
|
+
): this {
|
|
470
|
+
// Class-based routing
|
|
471
|
+
if (typeof pathOrRoute === 'object' && ('pathName' in pathOrRoute || 'handler' in pathOrRoute)) {
|
|
472
|
+
return this.registerClassRoute('PUT', pathOrRoute as Route);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
return this.registerVersionedRoute('PUT', pathOrRoute as string, handlerOrConfig);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Convenience: DELETE route
|
|
480
|
+
* Supports both function-style and class-based routing
|
|
481
|
+
*/
|
|
482
|
+
delete<K extends keyof TDeps = keyof TDeps>(
|
|
483
|
+
pathOrRoute: string | Route,
|
|
484
|
+
handlerOrConfig?: Handler<Context, TDeps> | InjectedRouteConfig<Context, TDeps, K>
|
|
485
|
+
): this {
|
|
486
|
+
// Class-based routing
|
|
487
|
+
if (typeof pathOrRoute === 'object' && ('pathName' in pathOrRoute || 'handler' in pathOrRoute)) {
|
|
488
|
+
return this.registerClassRoute('DELETE', pathOrRoute as Route);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return this.registerVersionedRoute('DELETE', pathOrRoute as string, handlerOrConfig);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Convenience: PATCH route
|
|
496
|
+
* Supports both function-style and class-based routing
|
|
497
|
+
*/
|
|
498
|
+
patch<K extends keyof TDeps = keyof TDeps>(
|
|
499
|
+
pathOrRoute: string | Route,
|
|
500
|
+
handlerOrConfig?: Handler<Context, TDeps> | InjectedRouteConfig<Context, TDeps, K>
|
|
501
|
+
): this {
|
|
502
|
+
// Class-based routing
|
|
503
|
+
if (typeof pathOrRoute === 'object' && ('pathName' in pathOrRoute || 'handler' in pathOrRoute)) {
|
|
504
|
+
return this.registerClassRoute('PATCH', pathOrRoute as Route);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return this.registerVersionedRoute('PATCH', pathOrRoute as string, handlerOrConfig);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Register a versioned route (internal)
|
|
512
|
+
*/
|
|
513
|
+
private registerVersionedRoute<K extends keyof TDeps>(
|
|
514
|
+
method: HTTPMethod,
|
|
515
|
+
path: string,
|
|
516
|
+
handlerOrConfig?: Handler<Context, TDeps> | InjectedRouteConfig<Context, TDeps, K>
|
|
517
|
+
): this {
|
|
518
|
+
// Build versioned path if versioning is configured
|
|
519
|
+
const versionedPath = this.buildVersionedPath(path);
|
|
520
|
+
|
|
521
|
+
if (typeof handlerOrConfig === 'function') {
|
|
522
|
+
// Function handler - wrap to inject all dependencies
|
|
523
|
+
const originalHandler = handlerOrConfig;
|
|
524
|
+
const deps = this.dependencies;
|
|
525
|
+
const wrappedHandler: Handler = async (ctx) => originalHandler(ctx, deps);
|
|
526
|
+
this.router.addRoute({ method, path: versionedPath, handler: wrappedHandler });
|
|
527
|
+
} else if (handlerOrConfig) {
|
|
528
|
+
// Config object with possible inject option
|
|
529
|
+
const config = handlerOrConfig as InjectedRouteConfig<Context, TDeps, K>;
|
|
530
|
+
const originalHandler = config.handler;
|
|
531
|
+
const allDeps = this.dependencies;
|
|
532
|
+
const injectKeys = config.inject;
|
|
533
|
+
|
|
534
|
+
// Create wrapped handler that injects dependencies
|
|
535
|
+
const wrappedHandler: Handler = async (ctx) => {
|
|
536
|
+
let injectedDeps: any;
|
|
537
|
+
if (injectKeys && injectKeys.length > 0) {
|
|
538
|
+
// Only inject specified dependencies
|
|
539
|
+
injectedDeps = {} as Pick<TDeps, K>;
|
|
540
|
+
for (const key of injectKeys) {
|
|
541
|
+
(injectedDeps as any)[key] = allDeps[key];
|
|
542
|
+
}
|
|
543
|
+
} else {
|
|
544
|
+
// Inject all dependencies
|
|
545
|
+
injectedDeps = allDeps;
|
|
546
|
+
}
|
|
547
|
+
return originalHandler(ctx, injectedDeps);
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
this.router.addRoute({
|
|
551
|
+
method,
|
|
552
|
+
path: versionedPath,
|
|
553
|
+
handler: wrappedHandler,
|
|
554
|
+
middlewares: config.middlewares,
|
|
555
|
+
schema: config.schema,
|
|
556
|
+
meta: config.meta
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
return this;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Register a class-based route with lifecycle hooks support and dependency injection
|
|
564
|
+
*/
|
|
565
|
+
private registerClassRoute(method: HTTPMethod, route: Route): this {
|
|
566
|
+
// ⚠️ ENFORCE: Route class MUST extend Route abstract class
|
|
567
|
+
if (!(route instanceof Route)) {
|
|
568
|
+
const className = (route as any).constructor?.name || 'Unknown';
|
|
569
|
+
throw new Error(
|
|
570
|
+
`Route class "${className}" must extend the Route abstract class.\n` +
|
|
571
|
+
`Example:\n` +
|
|
572
|
+
` import { Route } from 'nexus';\n` +
|
|
573
|
+
` class ${className} extends Route {\n` +
|
|
574
|
+
` pathName = '/your/path';\n` +
|
|
575
|
+
` async handler(ctx) { ... }\n` +
|
|
576
|
+
` }`
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (!route.pathName) {
|
|
581
|
+
throw new Error(
|
|
582
|
+
`Route class must have a pathName property when using manual registration. ` +
|
|
583
|
+
`Use app.useFileRoutes() for file-based routing without pathName.`
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Determine the handler - either the handler method or the method-specific handler
|
|
588
|
+
let originalHandler = route.handler;
|
|
589
|
+
if (!originalHandler && typeof (route as any)[method] === 'function') {
|
|
590
|
+
originalHandler = (route as any)[method].bind(route);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (!originalHandler) {
|
|
594
|
+
throw new Error(
|
|
595
|
+
`Route class must have a handler method or a ${method} method.`
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Wrap handler with lifecycle hooks if route extends Route class
|
|
600
|
+
const routeInstance = route as Route;
|
|
601
|
+
const hasHooks = typeof routeInstance.onBefore === 'function' ||
|
|
602
|
+
typeof routeInstance.onAfter === 'function' ||
|
|
603
|
+
typeof routeInstance.onError === 'function';
|
|
604
|
+
|
|
605
|
+
// Capture dependencies for injection
|
|
606
|
+
const deps = this.dependencies;
|
|
607
|
+
let finalHandler: Handler;
|
|
608
|
+
|
|
609
|
+
if (hasHooks) {
|
|
610
|
+
const boundOriginalHandler = originalHandler.bind(route);
|
|
611
|
+
const onBefore = routeInstance.onBefore?.bind(route);
|
|
612
|
+
const onAfter = routeInstance.onAfter?.bind(route);
|
|
613
|
+
const onError = routeInstance.onError?.bind(route);
|
|
614
|
+
|
|
615
|
+
finalHandler = async (ctx: Context) => {
|
|
616
|
+
try {
|
|
617
|
+
// Run onBefore hook (with deps)
|
|
618
|
+
if (onBefore) {
|
|
619
|
+
const beforeResult = await onBefore(ctx, deps);
|
|
620
|
+
// If onBefore returns a value (not undefined), skip handler
|
|
621
|
+
if (beforeResult !== undefined) {
|
|
622
|
+
return beforeResult;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Run the main handler with dependencies
|
|
627
|
+
let result = await boundOriginalHandler(ctx, deps);
|
|
628
|
+
|
|
629
|
+
// Run onAfter hook (with deps)
|
|
630
|
+
if (onAfter) {
|
|
631
|
+
result = await onAfter(ctx, result, deps);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
return result;
|
|
635
|
+
} catch (error) {
|
|
636
|
+
// Run onError hook if defined (with deps)
|
|
637
|
+
if (onError) {
|
|
638
|
+
return await onError(ctx, error as Error, deps);
|
|
639
|
+
}
|
|
640
|
+
// Re-throw if no onError handler
|
|
641
|
+
throw error;
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
} else {
|
|
645
|
+
// No hooks - just wrap with dependency injection
|
|
646
|
+
const boundHandler = originalHandler.bind(route);
|
|
647
|
+
finalHandler = async (ctx: Context) => boundHandler(ctx, deps);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
const config: RouteConfig = {
|
|
651
|
+
method,
|
|
652
|
+
path: route.pathName,
|
|
653
|
+
handler: finalHandler,
|
|
654
|
+
schema: route.schema?.(),
|
|
655
|
+
meta: route.meta?.(),
|
|
656
|
+
middlewares: route.middlewares?.()
|
|
657
|
+
};
|
|
658
|
+
this.router.addRoute(config);
|
|
659
|
+
return this;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Register a WebSocket route
|
|
664
|
+
*
|
|
665
|
+
* @example
|
|
666
|
+
* ```typescript
|
|
667
|
+
* app.ws('/ws/chat', {
|
|
668
|
+
* auth: async (ctx) => validateToken(ctx.query.token),
|
|
669
|
+
* onConnect: async (socket, ctx) => {
|
|
670
|
+
* console.log('User connected:', ctx.user);
|
|
671
|
+
* },
|
|
672
|
+
* onMessage: async (socket, message, ctx) => {
|
|
673
|
+
* socket.send(JSON.stringify({ echo: message }));
|
|
674
|
+
* },
|
|
675
|
+
* onClose: async (socket, ctx) => {
|
|
676
|
+
* console.log('User disconnected');
|
|
677
|
+
* }
|
|
678
|
+
* });
|
|
679
|
+
* ```
|
|
680
|
+
*/
|
|
681
|
+
ws(path: string, config: WebSocketRouteConfig): this {
|
|
682
|
+
if (!this.wsGateway) {
|
|
683
|
+
this.wsGateway = new WebSocketGateway();
|
|
684
|
+
}
|
|
685
|
+
this.wsGateway.register(path, config);
|
|
686
|
+
return this;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Get the WebSocket gateway for advanced usage (rooms, broadcast, etc.)
|
|
691
|
+
*
|
|
692
|
+
* @example
|
|
693
|
+
* ```typescript
|
|
694
|
+
* const ws = app.getWebSocket();
|
|
695
|
+
* ws.broadcast('room-name', { type: 'notification', message: 'Hello!' });
|
|
696
|
+
* ws.joinRoom('room-name', socket);
|
|
697
|
+
* ```
|
|
698
|
+
*/
|
|
699
|
+
getWebSocket(): WebSocketGateway | undefined {
|
|
700
|
+
return this.wsGateway;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Use file-based routing (Next.js style)
|
|
705
|
+
*
|
|
706
|
+
* Automatically scans a directory and registers routes based on file/folder structure.
|
|
707
|
+
* Supports dynamic parameters [id], catch-all [...slug], and nested routes.
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* ```typescript
|
|
711
|
+
* // Folder structure:
|
|
712
|
+
* // routes/
|
|
713
|
+
* // api/
|
|
714
|
+
* // users/
|
|
715
|
+
* // index.ts → GET/POST /api/users
|
|
716
|
+
* // [id]/
|
|
717
|
+
* // index.ts → GET/PUT/DELETE /api/users/:id
|
|
718
|
+
* // posts.ts → GET /api/users/:id/posts
|
|
719
|
+
*
|
|
720
|
+
* const app = createApp();
|
|
721
|
+
*
|
|
722
|
+
* await app.useFileRoutes({
|
|
723
|
+
* dir: './src/routes',
|
|
724
|
+
* prefix: '',
|
|
725
|
+
* debug: true
|
|
726
|
+
* });
|
|
727
|
+
*
|
|
728
|
+
* app.listen(3000);
|
|
729
|
+
* ```
|
|
730
|
+
*
|
|
731
|
+
* Route file format (function-style):
|
|
732
|
+
* ```typescript
|
|
733
|
+
* // routes/api/users/index.ts
|
|
734
|
+
* import { Context } from '@engjts/nexus';
|
|
735
|
+
*
|
|
736
|
+
* export async function GET(ctx: Context) {
|
|
737
|
+
* return ctx.json({ users: [] });
|
|
738
|
+
* }
|
|
739
|
+
*
|
|
740
|
+
* export async function POST(ctx: Context) {
|
|
741
|
+
* const body = ctx.body;
|
|
742
|
+
* return ctx.json({ created: body }, 201);
|
|
743
|
+
* }
|
|
744
|
+
*
|
|
745
|
+
* export const schema = { body: z.object({ name: z.string() }) };
|
|
746
|
+
* export const meta = { summary: 'User endpoints', tags: ['Users'] };
|
|
747
|
+
* ```
|
|
748
|
+
*
|
|
749
|
+
* Route file format (class-style):
|
|
750
|
+
* ```typescript
|
|
751
|
+
* // routes/api/users/[id]/index.ts
|
|
752
|
+
* import { RouteBase, Context } from '@engjts/nexus';
|
|
753
|
+
*
|
|
754
|
+
* export default class UserRoute implements RouteBase {
|
|
755
|
+
* method = ['GET', 'PUT', 'DELETE'] as const;
|
|
756
|
+
*
|
|
757
|
+
* async GET(ctx: Context) {
|
|
758
|
+
* return ctx.json({ user: { id: ctx.params.id } });
|
|
759
|
+
* }
|
|
760
|
+
*
|
|
761
|
+
* async PUT(ctx: Context) {
|
|
762
|
+
* return ctx.json({ updated: true });
|
|
763
|
+
* }
|
|
764
|
+
*
|
|
765
|
+
* async DELETE(ctx: Context) {
|
|
766
|
+
* return ctx.json({ deleted: true });
|
|
767
|
+
* }
|
|
768
|
+
* }
|
|
769
|
+
* ```
|
|
770
|
+
*/
|
|
771
|
+
async useFileRoutes(options: FileRouterOptions): Promise<this> {
|
|
772
|
+
const router = new FileRouter(options);
|
|
773
|
+
await router.register(this);
|
|
774
|
+
return this;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* Set custom error handler
|
|
779
|
+
*/
|
|
780
|
+
onError(handler: ErrorHandler): this {
|
|
781
|
+
this.errorHandler = handler;
|
|
782
|
+
return this;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Install a plugin (supports both legacy and new plugin formats)
|
|
787
|
+
*
|
|
788
|
+
* @example
|
|
789
|
+
* ```typescript
|
|
790
|
+
* // Legacy plugin
|
|
791
|
+
* app.plugin({ name: 'my-plugin', version: '1.0.0', install: (app) => {} });
|
|
792
|
+
*
|
|
793
|
+
* // New advanced plugin
|
|
794
|
+
* const authPlugin = definePlugin('auth')
|
|
795
|
+
* .version('1.0.0')
|
|
796
|
+
* .config<{ secret: string }>()
|
|
797
|
+
* .register(ctx => ctx.app.use(jwtMiddleware))
|
|
798
|
+
* .build();
|
|
799
|
+
*
|
|
800
|
+
* app.plugin(authPlugin, { secret: 'my-secret' });
|
|
801
|
+
* ```
|
|
802
|
+
*/
|
|
803
|
+
plugin<TConfig = any>(
|
|
804
|
+
plugin: Plugin | NexusPlugin<TConfig> | SimplePlugin,
|
|
805
|
+
config?: TConfig
|
|
806
|
+
): this {
|
|
807
|
+
// Check if it's a legacy Plugin with install method directly on app
|
|
808
|
+
if ('install' in plugin && !('meta' in plugin)) {
|
|
809
|
+
// Legacy format - call install directly
|
|
810
|
+
(plugin as Plugin).install(this);
|
|
811
|
+
} else {
|
|
812
|
+
// New plugin format - use PluginManager
|
|
813
|
+
this.pluginManager.add(plugin as NexusPlugin<TConfig>, config);
|
|
814
|
+
}
|
|
815
|
+
return this;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
/**
|
|
819
|
+
* Get the plugin manager for advanced plugin operations
|
|
820
|
+
*
|
|
821
|
+
* @example
|
|
822
|
+
* ```typescript
|
|
823
|
+
* const pm = app.getPluginManager();
|
|
824
|
+
*
|
|
825
|
+
* // Check if plugin exists
|
|
826
|
+
* if (pm.has('auth-plugin')) {
|
|
827
|
+
* const authApi = pm.getExports<AuthAPI>('auth-plugin');
|
|
828
|
+
* authApi.verify(token);
|
|
829
|
+
* }
|
|
830
|
+
*
|
|
831
|
+
* // Listen to plugin events
|
|
832
|
+
* pm.on('plugin:ready', (meta) => {
|
|
833
|
+
* console.log(`Plugin ${meta.name} is ready`);
|
|
834
|
+
* });
|
|
835
|
+
* ```
|
|
836
|
+
*/
|
|
837
|
+
getPluginManager(): PluginManager {
|
|
838
|
+
return this.pluginManager;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* Get exports from a specific plugin
|
|
843
|
+
* Shorthand for getPluginManager().getExports()
|
|
844
|
+
*/
|
|
845
|
+
getPluginExports<T = any>(pluginName: string): T | undefined {
|
|
846
|
+
return this.pluginManager.getExports<T>(pluginName);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* Check if a plugin is installed
|
|
851
|
+
*/
|
|
852
|
+
hasPlugin(name: string): boolean {
|
|
853
|
+
return this.pluginManager.has(name);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/**
|
|
857
|
+
* Register an adapter
|
|
858
|
+
*/
|
|
859
|
+
adapter<T>(name: string, adapter: T): this {
|
|
860
|
+
this.adapters.register(name, adapter);
|
|
861
|
+
return this;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Enable built-in observability (metrics, tracing, health checks)
|
|
866
|
+
* with safe, configurable endpoints.
|
|
867
|
+
*/
|
|
868
|
+
observe(options: ObservabilityOptions = {}): this {
|
|
869
|
+
const center = new ObservabilityCenter(options);
|
|
870
|
+
|
|
871
|
+
// Attach middleware for metrics/tracing/logging
|
|
872
|
+
this.use(createObservabilityMiddleware(center, options));
|
|
873
|
+
|
|
874
|
+
const existingRoutes = this.router.getRoutes();
|
|
875
|
+
|
|
876
|
+
// Metrics endpoint (default: /__nexus/metrics)
|
|
877
|
+
const metricsEnabled = options.metrics?.enabled ?? true;
|
|
878
|
+
if (metricsEnabled) {
|
|
879
|
+
const metricsPath = options.metrics?.endpoint ?? '/__nexus/metrics';
|
|
880
|
+
this.ensureNoRouteConflict('GET', metricsPath, existingRoutes);
|
|
881
|
+
this.get(metricsPath, async (ctx) => center.metricsHandler()(ctx));
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// Health endpoint (default: /__nexus/health)
|
|
885
|
+
if (options.health) {
|
|
886
|
+
const healthPath = options.health.endpoint ?? '/__nexus/health';
|
|
887
|
+
this.ensureNoRouteConflict('GET', healthPath, existingRoutes);
|
|
888
|
+
this.get(healthPath, async (ctx) => center.healthHandler()(ctx));
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
return this;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
private ensureNoRouteConflict(method: HTTPMethod, path: string, routes: Array<{ method: string; path: string }>) {
|
|
895
|
+
const conflict = routes.some(r => r.method === method && r.path === path);
|
|
896
|
+
if (conflict) {
|
|
897
|
+
throw new Error(
|
|
898
|
+
`Observability endpoint conflict for ${method} ${path}. ` +
|
|
899
|
+
'Silakan override endpoint melalui konfigurasi observability (metrics.endpoint / health.endpoint).'
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Get an adapter
|
|
906
|
+
*/
|
|
907
|
+
getAdapter<T>(name: string): T | undefined {
|
|
908
|
+
return this.adapters.get<T>(name);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
/**
|
|
912
|
+
* Initialize all plugins (must be called before listen/start)
|
|
913
|
+
* This runs: configure → register → boot lifecycle phases
|
|
914
|
+
*
|
|
915
|
+
* @example
|
|
916
|
+
* ```typescript
|
|
917
|
+
* const app = createApp()
|
|
918
|
+
* .plugin(authPlugin, { secret: 'xxx' })
|
|
919
|
+
* .plugin(dbPlugin, { url: 'postgres://...' });
|
|
920
|
+
*
|
|
921
|
+
* // Initialize all plugins
|
|
922
|
+
* await app.initialize();
|
|
923
|
+
*
|
|
924
|
+
* // Start the server
|
|
925
|
+
* app.listen(3000);
|
|
926
|
+
* ```
|
|
927
|
+
*/
|
|
928
|
+
async initialize(): Promise<this> {
|
|
929
|
+
await this.pluginManager.initialize();
|
|
930
|
+
return this;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* Start the HTTP server
|
|
935
|
+
*/
|
|
936
|
+
listen(port: number, callback?: () => void): HTTPServer {
|
|
937
|
+
this.server = createServer(async (req, res) => {
|
|
938
|
+
await this.handleRequest(req, res);
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
// Attach graceful shutdown if enabled
|
|
942
|
+
if (this.shutdownManager) {
|
|
943
|
+
this.shutdownManager.attach(this.server);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// Attach WebSocket gateway if any ws routes registered
|
|
947
|
+
if (this.wsGateway) {
|
|
948
|
+
this.wsGateway.attach(this.server);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
this.server.listen(port, () => {
|
|
952
|
+
// Notify plugins that server is ready
|
|
953
|
+
this.pluginManager.notifyReady().catch(err => {
|
|
954
|
+
console.error('[PluginManager] Error in ready phase:', err);
|
|
955
|
+
});
|
|
956
|
+
callback?.();
|
|
957
|
+
});
|
|
958
|
+
return this.server;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/**
|
|
962
|
+
* Start the server (alias for listen with modern options)
|
|
963
|
+
*/
|
|
964
|
+
start(options: { port: number; host?: string; callback?: () => void } | number): HTTPServer {
|
|
965
|
+
if (typeof options === 'number') {
|
|
966
|
+
return this.listen(options);
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
this.server = createServer(async (req, res) => {
|
|
970
|
+
await this.handleRequest(req, res);
|
|
971
|
+
});
|
|
972
|
+
|
|
973
|
+
// Attach graceful shutdown if enabled
|
|
974
|
+
if (this.shutdownManager) {
|
|
975
|
+
this.shutdownManager.attach(this.server);
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// Attach WebSocket gateway if any ws routes registered
|
|
979
|
+
if (this.wsGateway) {
|
|
980
|
+
this.wsGateway.attach(this.server);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
const { port, host = '0.0.0.0', callback } = options;
|
|
984
|
+
this.server.listen(port, host, () => {
|
|
985
|
+
// Notify plugins that server is ready
|
|
986
|
+
this.pluginManager.notifyReady().catch(err => {
|
|
987
|
+
console.error('[PluginManager] Error in ready phase:', err);
|
|
988
|
+
});
|
|
989
|
+
callback?.();
|
|
990
|
+
});
|
|
991
|
+
return this.server;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
/**
|
|
995
|
+
* Handle incoming HTTP request
|
|
996
|
+
*/
|
|
997
|
+
private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {
|
|
998
|
+
let ctx: Context | null = null;
|
|
999
|
+
let response: Response | null = null;
|
|
1000
|
+
|
|
1001
|
+
try {
|
|
1002
|
+
// Acquire context from pool
|
|
1003
|
+
ctx = await this.contextPool.acquire(req, res);
|
|
1004
|
+
|
|
1005
|
+
// Inject store registry into context
|
|
1006
|
+
if ('setStoreRegistry' in ctx && typeof ctx.setStoreRegistry === 'function') {
|
|
1007
|
+
(ctx as any).setStoreRegistry(this.storeRegistry);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// Set debug mode for request stores
|
|
1011
|
+
if ('setDebugMode' in ctx && typeof ctx.setDebugMode === 'function') {
|
|
1012
|
+
(ctx as any).setDebugMode(this.config.debug ?? false);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// === HOOK: onRequest ===
|
|
1016
|
+
if (this.lifecycleHooks.onRequest) {
|
|
1017
|
+
const hookResult = await this.lifecycleHooks.onRequest(ctx);
|
|
1018
|
+
if (this.isResponse(hookResult)) {
|
|
1019
|
+
await this.sendResponse(res, hookResult, ctx);
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// Apply versioning if configured
|
|
1025
|
+
let matchPath = ctx.path;
|
|
1026
|
+
if (this.versioningConfig) {
|
|
1027
|
+
const { version, basePath, source } = this.resolveVersion(ctx);
|
|
1028
|
+
ctx.version = version;
|
|
1029
|
+
ctx.versionSource = source;
|
|
1030
|
+
|
|
1031
|
+
// For header/query strategy, rewrite path to versioned path
|
|
1032
|
+
if (source === 'header' || source === 'query' || source === 'default') {
|
|
1033
|
+
matchPath = `/${version}${basePath.startsWith('/') ? basePath : '/' + basePath}`;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
if (this.config.debug) {
|
|
1037
|
+
console.log(`[Versioning] ${source} → ${version}, path: ${ctx.path} → ${matchPath}`);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// Find matching route
|
|
1042
|
+
const match = this.router.match(ctx.method, matchPath);
|
|
1043
|
+
|
|
1044
|
+
if (!match) {
|
|
1045
|
+
// Try fallback handler (e.g., static files)
|
|
1046
|
+
if (this.fallbackHandler) {
|
|
1047
|
+
const fallbackResponse = await this.fallbackHandler(ctx, this.dependencies);
|
|
1048
|
+
await this.sendResponse(res, fallbackResponse, ctx);
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
// 404 Not Found
|
|
1053
|
+
await this.sendResponse(res, {
|
|
1054
|
+
statusCode: 404,
|
|
1055
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1056
|
+
body: JSON.stringify({ error: 'Not Found' })
|
|
1057
|
+
}, ctx);
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// Set route params
|
|
1062
|
+
if ('setParams' in ctx && typeof ctx.setParams === 'function') {
|
|
1063
|
+
ctx.setParams(match.params);
|
|
1064
|
+
} else {
|
|
1065
|
+
ctx.params = match.params;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
// Combine global and route-specific middleware
|
|
1069
|
+
const allMiddlewares = [...this.globalMiddlewares, ...match.middlewares];
|
|
1070
|
+
|
|
1071
|
+
// Execute middleware chain and handler with hooks
|
|
1072
|
+
response = await this.middlewareExecutor.executeWithHooks(
|
|
1073
|
+
ctx,
|
|
1074
|
+
allMiddlewares,
|
|
1075
|
+
match.handler,
|
|
1076
|
+
this.lifecycleHooks,
|
|
1077
|
+
this.dependencies
|
|
1078
|
+
);
|
|
1079
|
+
|
|
1080
|
+
// === HOOK: onResponse ===
|
|
1081
|
+
if (this.lifecycleHooks.onResponse) {
|
|
1082
|
+
const hookResult = await this.lifecycleHooks.onResponse(ctx, response);
|
|
1083
|
+
if (this.isResponse(hookResult)) {
|
|
1084
|
+
response = hookResult;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// Send response
|
|
1089
|
+
await this.sendResponse(res, response, ctx);
|
|
1090
|
+
|
|
1091
|
+
} catch (error) {
|
|
1092
|
+
// === HOOK: onError ===
|
|
1093
|
+
if (ctx && this.lifecycleHooks.onError) {
|
|
1094
|
+
try {
|
|
1095
|
+
const hookResult = await this.lifecycleHooks.onError(ctx, error as Error);
|
|
1096
|
+
if (this.isResponse(hookResult)) {
|
|
1097
|
+
await this.sendResponse(res, hookResult, ctx);
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
} catch (hookError) {
|
|
1101
|
+
// Hook itself threw an error, continue to default error handler
|
|
1102
|
+
console.error('onError hook failed:', hookError);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
// Handle errors with default error handler
|
|
1107
|
+
try {
|
|
1108
|
+
const errorResponse = await this.errorHandler(error as Error, ctx!);
|
|
1109
|
+
|
|
1110
|
+
// === HOOK: onResponse (for error responses) ===
|
|
1111
|
+
if (ctx && this.lifecycleHooks.onResponse) {
|
|
1112
|
+
const hookResult = await this.lifecycleHooks.onResponse(ctx, errorResponse);
|
|
1113
|
+
if (this.isResponse(hookResult)) {
|
|
1114
|
+
await this.sendResponse(res, hookResult, ctx);
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
await this.sendResponse(res, errorResponse, ctx!);
|
|
1120
|
+
} catch (handlerError) {
|
|
1121
|
+
// Fallback error response
|
|
1122
|
+
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
1123
|
+
res.end('Internal Server Error');
|
|
1124
|
+
}
|
|
1125
|
+
} finally {
|
|
1126
|
+
// Dispose request-scoped stores
|
|
1127
|
+
if (ctx && 'disposeRequestStores' in ctx && typeof ctx.disposeRequestStores === 'function') {
|
|
1128
|
+
(ctx as any).disposeRequestStores();
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// Release context back to pool
|
|
1132
|
+
if (ctx) {
|
|
1133
|
+
this.contextPool.release(ctx);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* Check if value is a Response object
|
|
1140
|
+
*/
|
|
1141
|
+
private isResponse(value: any): value is Response {
|
|
1142
|
+
return (
|
|
1143
|
+
value &&
|
|
1144
|
+
typeof value === 'object' &&
|
|
1145
|
+
'statusCode' in value &&
|
|
1146
|
+
'headers' in value &&
|
|
1147
|
+
'body' in value
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/**
|
|
1152
|
+
* Send HTTP response
|
|
1153
|
+
*/
|
|
1154
|
+
private async sendResponse(res: ServerResponse, response: Response, ctx: Context): Promise<void> {
|
|
1155
|
+
// Set status code
|
|
1156
|
+
res.statusCode = response.statusCode;
|
|
1157
|
+
|
|
1158
|
+
// Set headers
|
|
1159
|
+
for (const [key, value] of Object.entries(response.headers)) {
|
|
1160
|
+
if (value !== undefined) {
|
|
1161
|
+
res.setHeader(key, value);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// Set cookies
|
|
1166
|
+
if ('getSetCookieHeaders' in ctx && typeof ctx.getSetCookieHeaders === 'function') {
|
|
1167
|
+
const setCookies = ctx.getSetCookieHeaders();
|
|
1168
|
+
if (setCookies.length > 0) {
|
|
1169
|
+
res.setHeader('Set-Cookie', setCookies);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
// Send body or stream
|
|
1174
|
+
if (response.stream) {
|
|
1175
|
+
response.stream.pipe(res);
|
|
1176
|
+
} else {
|
|
1177
|
+
res.end(response.body);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* Get all registered routes
|
|
1183
|
+
*/
|
|
1184
|
+
getRoutes() {
|
|
1185
|
+
return this.router.getRoutes();
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
/**
|
|
1189
|
+
* Get context pool statistics
|
|
1190
|
+
*/
|
|
1191
|
+
getPoolStats() {
|
|
1192
|
+
return this.contextPool.getStats();
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
/**
|
|
1196
|
+
* Close the server
|
|
1197
|
+
*/
|
|
1198
|
+
close(callback?: (err?: Error) => void): void {
|
|
1199
|
+
if (this.server) {
|
|
1200
|
+
this.server.close(callback);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
/**
|
|
1205
|
+
* Enable graceful shutdown for zero-downtime deployments
|
|
1206
|
+
*/
|
|
1207
|
+
gracefulShutdown(options: GracefulShutdownOptions = {}): this {
|
|
1208
|
+
this.shutdownManager = new GracefulShutdownManager({
|
|
1209
|
+
verbose: this.config.debug,
|
|
1210
|
+
...options
|
|
1211
|
+
});
|
|
1212
|
+
return this;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* Add a shutdown hook (e.g., closing database connections)
|
|
1217
|
+
*/
|
|
1218
|
+
onShutdown(name: string, handler: () => Promise<void>, priority?: number): this {
|
|
1219
|
+
if (!this.shutdownManager) {
|
|
1220
|
+
this.gracefulShutdown();
|
|
1221
|
+
}
|
|
1222
|
+
this.shutdownManager!.addHook({ name, handler, priority });
|
|
1223
|
+
return this;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
/**
|
|
1227
|
+
* Initiate graceful shutdown programmatically
|
|
1228
|
+
*/
|
|
1229
|
+
async shutdown(): Promise<void> {
|
|
1230
|
+
// Shutdown all plugins first
|
|
1231
|
+
await this.pluginManager.shutdown();
|
|
1232
|
+
|
|
1233
|
+
// Dispose all stores
|
|
1234
|
+
this.storeRegistry.dispose();
|
|
1235
|
+
|
|
1236
|
+
if (this.shutdownManager) {
|
|
1237
|
+
await this.shutdownManager.shutdown();
|
|
1238
|
+
} else {
|
|
1239
|
+
this.close();
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
/**
|
|
1244
|
+
* Check if shutdown is in progress
|
|
1245
|
+
*/
|
|
1246
|
+
isShuttingDown(): boolean {
|
|
1247
|
+
return this.shutdownManager?.isInShutdown() ?? false;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
/**
|
|
1251
|
+
* Get the shutdown manager for advanced usage
|
|
1252
|
+
*/
|
|
1253
|
+
getShutdownManager(): GracefulShutdownManager | undefined {
|
|
1254
|
+
return this.shutdownManager;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
/**
|
|
1258
|
+
* Start the application with clustering support
|
|
1259
|
+
* @param options Cluster options
|
|
1260
|
+
* @param startFn Function to start the server (called in each worker)
|
|
1261
|
+
*/
|
|
1262
|
+
cluster(options: ClusterOptions = {}): ClusterManager {
|
|
1263
|
+
this.clusterManager = new ClusterManager({
|
|
1264
|
+
verbose: this.config.debug,
|
|
1265
|
+
...options
|
|
1266
|
+
});
|
|
1267
|
+
return this.clusterManager;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/**
|
|
1271
|
+
* Get the cluster manager
|
|
1272
|
+
*/
|
|
1273
|
+
getClusterManager(): ClusterManager | undefined {
|
|
1274
|
+
return this.clusterManager;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
/**
|
|
1279
|
+
* Factory function to create an application
|
|
1280
|
+
*/
|
|
1281
|
+
export function createApp(config?: AppConfig): Application {
|
|
1282
|
+
return new Application(config);
|
|
1283
|
+
}
|