@c9up/ream 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +70 -0
- package/dist/Application.d.ts +71 -0
- package/dist/Application.d.ts.map +1 -0
- package/dist/Application.js +151 -0
- package/dist/Application.js.map +1 -0
- package/dist/Codemods.d.ts +16 -0
- package/dist/Codemods.d.ts.map +1 -0
- package/dist/Codemods.js +277 -0
- package/dist/Codemods.js.map +1 -0
- package/dist/ConfigLoader.d.ts +29 -0
- package/dist/ConfigLoader.d.ts.map +1 -0
- package/dist/ConfigLoader.js +43 -0
- package/dist/ConfigLoader.js.map +1 -0
- package/dist/ErrorBoundary.d.ts +51 -0
- package/dist/ErrorBoundary.d.ts.map +1 -0
- package/dist/ErrorBoundary.js +122 -0
- package/dist/ErrorBoundary.js.map +1 -0
- package/dist/GracefulShutdown.d.ts +28 -0
- package/dist/GracefulShutdown.d.ts.map +1 -0
- package/dist/GracefulShutdown.js +55 -0
- package/dist/GracefulShutdown.js.map +1 -0
- package/dist/HealthCheck.d.ts +42 -0
- package/dist/HealthCheck.d.ts.map +1 -0
- package/dist/HealthCheck.js +65 -0
- package/dist/HealthCheck.js.map +1 -0
- package/dist/HotReload.d.ts +28 -0
- package/dist/HotReload.d.ts.map +1 -0
- package/dist/HotReload.js +60 -0
- package/dist/HotReload.js.map +1 -0
- package/dist/HttpKernel.d.ts +62 -0
- package/dist/HttpKernel.d.ts.map +1 -0
- package/dist/HttpKernel.js +210 -0
- package/dist/HttpKernel.js.map +1 -0
- package/dist/Ignitor.d.ts +195 -0
- package/dist/Ignitor.d.ts.map +1 -0
- package/dist/Ignitor.js +505 -0
- package/dist/Ignitor.js.map +1 -0
- package/dist/Provider.d.ts +54 -0
- package/dist/Provider.d.ts.map +1 -0
- package/dist/Provider.js +37 -0
- package/dist/Provider.js.map +1 -0
- package/dist/bodyparser/BodyParserMiddleware.d.ts +38 -0
- package/dist/bodyparser/BodyParserMiddleware.d.ts.map +1 -0
- package/dist/bodyparser/BodyParserMiddleware.js +143 -0
- package/dist/bodyparser/BodyParserMiddleware.js.map +1 -0
- package/dist/bodyparser/MultipartFile.d.ts +77 -0
- package/dist/bodyparser/MultipartFile.d.ts.map +1 -0
- package/dist/bodyparser/MultipartFile.js +138 -0
- package/dist/bodyparser/MultipartFile.js.map +1 -0
- package/dist/bodyparser/parseSize.d.ts +6 -0
- package/dist/bodyparser/parseSize.d.ts.map +1 -0
- package/dist/bodyparser/parseSize.js +21 -0
- package/dist/bodyparser/parseSize.js.map +1 -0
- package/dist/bootstrap/hyper-server.d.ts +27 -0
- package/dist/bootstrap/hyper-server.d.ts.map +1 -0
- package/dist/bootstrap/hyper-server.js +63 -0
- package/dist/bootstrap/hyper-server.js.map +1 -0
- package/dist/console/CommandRunner.d.ts +18 -0
- package/dist/console/CommandRunner.d.ts.map +1 -0
- package/dist/console/CommandRunner.js +65 -0
- package/dist/console/CommandRunner.js.map +1 -0
- package/dist/container/Container.d.ts +60 -0
- package/dist/container/Container.d.ts.map +1 -0
- package/dist/container/Container.js +329 -0
- package/dist/container/Container.js.map +1 -0
- package/dist/container/types.d.ts +25 -0
- package/dist/container/types.d.ts.map +1 -0
- package/dist/container/types.js +6 -0
- package/dist/container/types.js.map +1 -0
- package/dist/decorators/Lazy.d.ts +19 -0
- package/dist/decorators/Lazy.d.ts.map +1 -0
- package/dist/decorators/Lazy.js +53 -0
- package/dist/decorators/Lazy.js.map +1 -0
- package/dist/decorators/Service.d.ts +48 -0
- package/dist/decorators/Service.d.ts.map +1 -0
- package/dist/decorators/Service.js +70 -0
- package/dist/decorators/Service.js.map +1 -0
- package/dist/errors/FuzzyMatcher.d.ts +41 -0
- package/dist/errors/FuzzyMatcher.d.ts.map +1 -0
- package/dist/errors/FuzzyMatcher.js +81 -0
- package/dist/errors/FuzzyMatcher.js.map +1 -0
- package/dist/errors/ModuleErrors.d.ts +41 -0
- package/dist/errors/ModuleErrors.d.ts.map +1 -0
- package/dist/errors/ModuleErrors.js +65 -0
- package/dist/errors/ModuleErrors.js.map +1 -0
- package/dist/errors/PipelineStageError.d.ts +31 -0
- package/dist/errors/PipelineStageError.d.ts.map +1 -0
- package/dist/errors/PipelineStageError.js +77 -0
- package/dist/errors/PipelineStageError.js.map +1 -0
- package/dist/errors/ReamError.d.ts +50 -0
- package/dist/errors/ReamError.d.ts.map +1 -0
- package/dist/errors/ReamError.js +108 -0
- package/dist/errors/ReamError.js.map +1 -0
- package/dist/events/Emitter.d.ts +124 -0
- package/dist/events/Emitter.d.ts.map +1 -0
- package/dist/events/Emitter.js +271 -0
- package/dist/events/Emitter.js.map +1 -0
- package/dist/events/EventsProvider.d.ts +28 -0
- package/dist/events/EventsProvider.d.ts.map +1 -0
- package/dist/events/EventsProvider.js +36 -0
- package/dist/events/EventsProvider.js.map +1 -0
- package/dist/events/config.d.ts +8 -0
- package/dist/events/config.d.ts.map +1 -0
- package/dist/events/config.js +4 -0
- package/dist/events/config.js.map +1 -0
- package/dist/events/configure.d.ts +10 -0
- package/dist/events/configure.d.ts.map +1 -0
- package/dist/events/configure.js +11 -0
- package/dist/events/configure.js.map +1 -0
- package/dist/events/helix/helpers.d.ts +62 -0
- package/dist/events/helix/helpers.d.ts.map +1 -0
- package/dist/events/helix/helpers.js +187 -0
- package/dist/events/helix/helpers.js.map +1 -0
- package/dist/events/index.d.ts +17 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +15 -0
- package/dist/events/index.js.map +1 -0
- package/dist/events/native.d.ts +21 -0
- package/dist/events/native.d.ts.map +1 -0
- package/dist/events/native.js +17 -0
- package/dist/events/native.js.map +1 -0
- package/dist/events/services/main.d.ts +18 -0
- package/dist/events/services/main.d.ts.map +1 -0
- package/dist/events/services/main.js +31 -0
- package/dist/events/services/main.js.map +1 -0
- package/dist/events/testing/FakeBus.d.ts +66 -0
- package/dist/events/testing/FakeBus.d.ts.map +1 -0
- package/dist/events/testing/FakeBus.js +356 -0
- package/dist/events/testing/FakeBus.js.map +1 -0
- package/dist/graphql/GraphQLEngine.d.ts +69 -0
- package/dist/graphql/GraphQLEngine.d.ts.map +1 -0
- package/dist/graphql/GraphQLEngine.js +309 -0
- package/dist/graphql/GraphQLEngine.js.map +1 -0
- package/dist/graphql/GraphQLProvider.d.ts +32 -0
- package/dist/graphql/GraphQLProvider.d.ts.map +1 -0
- package/dist/graphql/GraphQLProvider.js +49 -0
- package/dist/graphql/GraphQLProvider.js.map +1 -0
- package/dist/helpers/base64.d.ts +40 -0
- package/dist/helpers/base64.d.ts.map +1 -0
- package/dist/helpers/base64.js +70 -0
- package/dist/helpers/base64.js.map +1 -0
- package/dist/helpers/index.d.ts +7 -0
- package/dist/helpers/index.d.ts.map +1 -0
- package/dist/helpers/index.js +5 -0
- package/dist/helpers/index.js.map +1 -0
- package/dist/helpers/is.d.ts +101 -0
- package/dist/helpers/is.d.ts.map +1 -0
- package/dist/helpers/is.js +151 -0
- package/dist/helpers/is.js.map +1 -0
- package/dist/helpers/napi-loader.d.ts +46 -0
- package/dist/helpers/napi-loader.d.ts.map +1 -0
- package/dist/helpers/napi-loader.js +69 -0
- package/dist/helpers/napi-loader.js.map +1 -0
- package/dist/helpers/safeEqual.d.ts +9 -0
- package/dist/helpers/safeEqual.d.ts.map +1 -0
- package/dist/helpers/safeEqual.js +16 -0
- package/dist/helpers/safeEqual.js.map +1 -0
- package/dist/helpers/string.d.ts +161 -0
- package/dist/helpers/string.d.ts.map +1 -0
- package/dist/helpers/string.js +429 -0
- package/dist/helpers/string.js.map +1 -0
- package/dist/helpers/types.d.ts +83 -0
- package/dist/helpers/types.d.ts.map +1 -0
- package/dist/helpers/types.js +6 -0
- package/dist/helpers/types.js.map +1 -0
- package/dist/http/Exception.d.ts +103 -0
- package/dist/http/Exception.d.ts.map +1 -0
- package/dist/http/Exception.js +228 -0
- package/dist/http/Exception.js.map +1 -0
- package/dist/http/HttpContext.d.ts +69 -0
- package/dist/http/HttpContext.d.ts.map +1 -0
- package/dist/http/HttpContext.js +55 -0
- package/dist/http/HttpContext.js.map +1 -0
- package/dist/http/RedirectBuilder.d.ts +31 -0
- package/dist/http/RedirectBuilder.d.ts.map +1 -0
- package/dist/http/RedirectBuilder.js +75 -0
- package/dist/http/RedirectBuilder.js.map +1 -0
- package/dist/http/Request.d.ts +160 -0
- package/dist/http/Request.d.ts.map +1 -0
- package/dist/http/Request.js +484 -0
- package/dist/http/Request.js.map +1 -0
- package/dist/http/Response.d.ts +114 -0
- package/dist/http/Response.d.ts.map +1 -0
- package/dist/http/Response.js +303 -0
- package/dist/http/Response.js.map +1 -0
- package/dist/http/SseStream.d.ts +89 -0
- package/dist/http/SseStream.d.ts.map +1 -0
- package/dist/http/SseStream.js +228 -0
- package/dist/http/SseStream.js.map +1 -0
- package/dist/http/urlDecode.d.ts +8 -0
- package/dist/http/urlDecode.d.ts.map +1 -0
- package/dist/http/urlDecode.js +18 -0
- package/dist/http/urlDecode.js.map +1 -0
- package/dist/index.d.ts +92 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +67 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/Pipeline.d.ts +36 -0
- package/dist/middleware/Pipeline.d.ts.map +1 -0
- package/dist/middleware/Pipeline.js +104 -0
- package/dist/middleware/Pipeline.js.map +1 -0
- package/dist/openapi/OpenApiGenerator.d.ts +58 -0
- package/dist/openapi/OpenApiGenerator.d.ts.map +1 -0
- package/dist/openapi/OpenApiGenerator.js +192 -0
- package/dist/openapi/OpenApiGenerator.js.map +1 -0
- package/dist/openapi/OpenApiMiddleware.d.ts +24 -0
- package/dist/openapi/OpenApiMiddleware.d.ts.map +1 -0
- package/dist/openapi/OpenApiMiddleware.js +78 -0
- package/dist/openapi/OpenApiMiddleware.js.map +1 -0
- package/dist/openapi/OpenApiProvider.d.ts +36 -0
- package/dist/openapi/OpenApiProvider.d.ts.map +1 -0
- package/dist/openapi/OpenApiProvider.js +42 -0
- package/dist/openapi/OpenApiProvider.js.map +1 -0
- package/dist/resources/ApiResource.d.ts +45 -0
- package/dist/resources/ApiResource.d.ts.map +1 -0
- package/dist/resources/ApiResource.js +58 -0
- package/dist/resources/ApiResource.js.map +1 -0
- package/dist/router/Router.d.ts +205 -0
- package/dist/router/Router.d.ts.map +1 -0
- package/dist/router/Router.js +552 -0
- package/dist/router/Router.js.map +1 -0
- package/dist/rpc/RpcProvider.d.ts +34 -0
- package/dist/rpc/RpcProvider.d.ts.map +1 -0
- package/dist/rpc/RpcProvider.js +37 -0
- package/dist/rpc/RpcProvider.js.map +1 -0
- package/dist/rpc/RpcRouter.d.ts +61 -0
- package/dist/rpc/RpcRouter.d.ts.map +1 -0
- package/dist/rpc/RpcRouter.js +187 -0
- package/dist/rpc/RpcRouter.js.map +1 -0
- package/dist/scheduler/Schedule.d.ts +53 -0
- package/dist/scheduler/Schedule.d.ts.map +1 -0
- package/dist/scheduler/Schedule.js +76 -0
- package/dist/scheduler/Schedule.js.map +1 -0
- package/dist/scheduler/ScheduleProvider.d.ts +56 -0
- package/dist/scheduler/ScheduleProvider.d.ts.map +1 -0
- package/dist/scheduler/ScheduleProvider.js +145 -0
- package/dist/scheduler/ScheduleProvider.js.map +1 -0
- package/dist/scheduler/Scheduler.d.ts +209 -0
- package/dist/scheduler/Scheduler.d.ts.map +1 -0
- package/dist/scheduler/Scheduler.js +432 -0
- package/dist/scheduler/Scheduler.js.map +1 -0
- package/dist/scheduler/index.d.ts +14 -0
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/scheduler/index.js +6 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/locks/LockBackend.d.ts +37 -0
- package/dist/scheduler/locks/LockBackend.d.ts.map +1 -0
- package/dist/scheduler/locks/LockBackend.js +13 -0
- package/dist/scheduler/locks/LockBackend.js.map +1 -0
- package/dist/scheduler/locks/MemoryLockBackend.d.ts +39 -0
- package/dist/scheduler/locks/MemoryLockBackend.d.ts.map +1 -0
- package/dist/scheduler/locks/MemoryLockBackend.js +71 -0
- package/dist/scheduler/locks/MemoryLockBackend.js.map +1 -0
- package/dist/scheduler/observability/ErrorReporter.d.ts +15 -0
- package/dist/scheduler/observability/ErrorReporter.d.ts.map +1 -0
- package/dist/scheduler/observability/ErrorReporter.js +13 -0
- package/dist/scheduler/observability/ErrorReporter.js.map +1 -0
- package/dist/scheduler/observability/ScheduleEvent.d.ts +57 -0
- package/dist/scheduler/observability/ScheduleEvent.d.ts.map +1 -0
- package/dist/scheduler/observability/ScheduleEvent.js +12 -0
- package/dist/scheduler/observability/ScheduleEvent.js.map +1 -0
- package/dist/scheduler/observability/ScheduleEventSink.d.ts +20 -0
- package/dist/scheduler/observability/ScheduleEventSink.d.ts.map +1 -0
- package/dist/scheduler/observability/ScheduleEventSink.js +17 -0
- package/dist/scheduler/observability/ScheduleEventSink.js.map +1 -0
- package/dist/scheduler/observability/StatsTracker.d.ts +50 -0
- package/dist/scheduler/observability/StatsTracker.d.ts.map +1 -0
- package/dist/scheduler/observability/StatsTracker.js +96 -0
- package/dist/scheduler/observability/StatsTracker.js.map +1 -0
- package/dist/security/CookieSigner.d.ts +13 -0
- package/dist/security/CookieSigner.d.ts.map +1 -0
- package/dist/security/CookieSigner.js +51 -0
- package/dist/security/CookieSigner.js.map +1 -0
- package/dist/security/SignedUrl.d.ts +17 -0
- package/dist/security/SignedUrl.d.ts.map +1 -0
- package/dist/security/SignedUrl.js +63 -0
- package/dist/security/SignedUrl.js.map +1 -0
- package/dist/security/crypto.d.ts +25 -0
- package/dist/security/crypto.d.ts.map +1 -0
- package/dist/security/crypto.js +82 -0
- package/dist/security/crypto.js.map +1 -0
- package/dist/server/HyperServer.d.ts +64 -0
- package/dist/server/HyperServer.d.ts.map +1 -0
- package/dist/server/HyperServer.js +54 -0
- package/dist/server/HyperServer.js.map +1 -0
- package/dist/server/Server.d.ts +68 -0
- package/dist/server/Server.d.ts.map +1 -0
- package/dist/server/Server.js +113 -0
- package/dist/server/Server.js.map +1 -0
- package/dist/services/app.d.ts +14 -0
- package/dist/services/app.d.ts.map +1 -0
- package/dist/services/app.js +27 -0
- package/dist/services/app.js.map +1 -0
- package/dist/services/router.d.ts +21 -0
- package/dist/services/router.d.ts.map +1 -0
- package/dist/services/router.js +36 -0
- package/dist/services/router.js.map +1 -0
- package/dist/services/server.d.ts +16 -0
- package/dist/services/server.d.ts.map +1 -0
- package/dist/services/server.js +32 -0
- package/dist/services/server.js.map +1 -0
- package/dist/session/Session.d.ts +88 -0
- package/dist/session/Session.d.ts.map +1 -0
- package/dist/session/Session.js +186 -0
- package/dist/session/Session.js.map +1 -0
- package/dist/session/SessionMiddleware.d.ts +16 -0
- package/dist/session/SessionMiddleware.d.ts.map +1 -0
- package/dist/session/SessionMiddleware.js +132 -0
- package/dist/session/SessionMiddleware.js.map +1 -0
- package/dist/session/drivers/CookieDriver.d.ts +17 -0
- package/dist/session/drivers/CookieDriver.d.ts.map +1 -0
- package/dist/session/drivers/CookieDriver.js +42 -0
- package/dist/session/drivers/CookieDriver.js.map +1 -0
- package/dist/session/drivers/MemoryDriver.d.ts +9 -0
- package/dist/session/drivers/MemoryDriver.d.ts.map +1 -0
- package/dist/session/drivers/MemoryDriver.js +24 -0
- package/dist/session/drivers/MemoryDriver.js.map +1 -0
- package/dist/storage/S3Driver.d.ts +27 -0
- package/dist/storage/S3Driver.d.ts.map +1 -0
- package/dist/storage/S3Driver.js +135 -0
- package/dist/storage/S3Driver.js.map +1 -0
- package/dist/storage/StaticMiddleware.d.ts +27 -0
- package/dist/storage/StaticMiddleware.d.ts.map +1 -0
- package/dist/storage/StaticMiddleware.js +153 -0
- package/dist/storage/StaticMiddleware.js.map +1 -0
- package/dist/storage/StaticProvider.d.ts +26 -0
- package/dist/storage/StaticProvider.d.ts.map +1 -0
- package/dist/storage/StaticProvider.js +31 -0
- package/dist/storage/StaticProvider.js.map +1 -0
- package/dist/storage/StorageManager.d.ts +31 -0
- package/dist/storage/StorageManager.d.ts.map +1 -0
- package/dist/storage/StorageManager.js +120 -0
- package/dist/storage/StorageManager.js.map +1 -0
- package/dist/testing/RequestBuilder.d.ts +67 -0
- package/dist/testing/RequestBuilder.d.ts.map +1 -0
- package/dist/testing/RequestBuilder.js +202 -0
- package/dist/testing/RequestBuilder.js.map +1 -0
- package/dist/testing/TestClient.d.ts +96 -0
- package/dist/testing/TestClient.d.ts.map +1 -0
- package/dist/testing/TestClient.js +263 -0
- package/dist/testing/TestClient.js.map +1 -0
- package/dist/types/helpers.d.ts +47 -0
- package/dist/types/helpers.d.ts.map +1 -0
- package/dist/types/helpers.js +5 -0
- package/dist/types/helpers.js.map +1 -0
- package/events.darwin-arm64.node +0 -0
- package/events.darwin-x64.node +0 -0
- package/events.linux-arm64-gnu.node +0 -0
- package/events.linux-x64-gnu.node +0 -0
- package/events.win32-x64-msvc.node +0 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +106 -0
- package/scheduler.darwin-arm64.node +0 -0
- package/scheduler.darwin-x64.node +0 -0
- package/scheduler.linux-arm64-gnu.node +0 -0
- package/scheduler.linux-x64-gnu.node +0 -0
- package/scheduler.win32-x64-msvc.node +0 -0
- package/scripts/copy-napi.mjs +113 -0
- package/src/Application.ts +177 -0
- package/src/Codemods.ts +343 -0
- package/src/ConfigLoader.ts +49 -0
- package/src/ErrorBoundary.ts +157 -0
- package/src/GracefulShutdown.ts +80 -0
- package/src/HealthCheck.ts +96 -0
- package/src/HotReload.ts +78 -0
- package/src/HttpKernel.ts +305 -0
- package/src/Ignitor.ts +656 -0
- package/src/Provider.ts +74 -0
- package/src/bodyparser/BodyParserMiddleware.ts +183 -0
- package/src/bodyparser/MultipartFile.ts +181 -0
- package/src/bodyparser/parseSize.ts +19 -0
- package/src/bootstrap/hyper-server.ts +78 -0
- package/src/console/CommandRunner.ts +82 -0
- package/src/container/Container.ts +383 -0
- package/src/container/types.ts +30 -0
- package/src/decorators/Lazy.ts +57 -0
- package/src/decorators/Service.ts +85 -0
- package/src/errors/FuzzyMatcher.ts +93 -0
- package/src/errors/ModuleErrors.ts +73 -0
- package/src/errors/PipelineStageError.ts +97 -0
- package/src/errors/ReamError.ts +138 -0
- package/src/events/Emitter.ts +333 -0
- package/src/events/EventsProvider.ts +58 -0
- package/src/events/config.ts +10 -0
- package/src/events/configure.ts +19 -0
- package/src/events/helix/helpers.ts +260 -0
- package/src/events/index.ts +22 -0
- package/src/events/native.ts +37 -0
- package/src/events/services/main.ts +39 -0
- package/src/events/testing/FakeBus.ts +420 -0
- package/src/graphql/GraphQLEngine.ts +421 -0
- package/src/graphql/GraphQLProvider.ts +59 -0
- package/src/helpers/base64.ts +72 -0
- package/src/helpers/index.ts +6 -0
- package/src/helpers/is.ts +162 -0
- package/src/helpers/napi-loader.ts +106 -0
- package/src/helpers/safeEqual.ts +15 -0
- package/src/helpers/string.ts +469 -0
- package/src/helpers/types.ts +100 -0
- package/src/http/Exception.ts +272 -0
- package/src/http/HttpContext.ts +108 -0
- package/src/http/RedirectBuilder.ts +89 -0
- package/src/http/Request.ts +540 -0
- package/src/http/Response.ts +351 -0
- package/src/http/SseStream.ts +250 -0
- package/src/http/urlDecode.ts +18 -0
- package/src/index.ts +263 -0
- package/src/middleware/Pipeline.ts +136 -0
- package/src/openapi/OpenApiGenerator.ts +254 -0
- package/src/openapi/OpenApiMiddleware.ts +101 -0
- package/src/openapi/OpenApiProvider.ts +67 -0
- package/src/resources/ApiResource.ts +79 -0
- package/src/router/Router.ts +733 -0
- package/src/rpc/RpcProvider.ts +54 -0
- package/src/rpc/RpcRouter.ts +243 -0
- package/src/scheduler/Schedule.ts +96 -0
- package/src/scheduler/ScheduleProvider.ts +177 -0
- package/src/scheduler/Scheduler.ts +601 -0
- package/src/scheduler/index.ts +24 -0
- package/src/scheduler/locks/LockBackend.ts +38 -0
- package/src/scheduler/locks/MemoryLockBackend.ts +85 -0
- package/src/scheduler/observability/ErrorReporter.ts +13 -0
- package/src/scheduler/observability/ScheduleEvent.ts +61 -0
- package/src/scheduler/observability/ScheduleEventSink.ts +21 -0
- package/src/scheduler/observability/StatsTracker.ts +134 -0
- package/src/security/CookieSigner.ts +54 -0
- package/src/security/SignedUrl.ts +71 -0
- package/src/security/crypto.ts +98 -0
- package/src/server/HyperServer.ts +121 -0
- package/src/server/Server.ts +147 -0
- package/src/services/app.ts +34 -0
- package/src/services/router.ts +44 -0
- package/src/services/server.ts +40 -0
- package/src/session/Session.ts +231 -0
- package/src/session/SessionMiddleware.ts +153 -0
- package/src/session/drivers/CookieDriver.ts +48 -0
- package/src/session/drivers/MemoryDriver.ts +29 -0
- package/src/storage/S3Driver.ts +171 -0
- package/src/storage/StaticMiddleware.ts +182 -0
- package/src/storage/StaticProvider.ts +40 -0
- package/src/storage/StorageManager.ts +142 -0
- package/src/testing/RequestBuilder.ts +275 -0
- package/src/testing/TestClient.ts +344 -0
- package/src/types/helpers.ts +52 -0
- package/swcrc.app.json +17 -0
- package/tsconfig.app.json +21 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 Router — dispatches RPC method calls to handlers.
|
|
3
|
+
*
|
|
4
|
+
* Same middleware/guard/validate pipeline as REST routes.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* rpc.method('task.validate', handler).guard('jwt').role('cs_member')
|
|
8
|
+
* rpc.namespace('task', TaskController) // every public method, DI-resolved per call
|
|
9
|
+
* rpc.group({ guard: 'jwt' }, (r) => { r.method('user.find', handler) })
|
|
10
|
+
*
|
|
11
|
+
* @implements MISS-27
|
|
12
|
+
*/
|
|
13
|
+
import type { HttpContext } from '../http/HttpContext.js';
|
|
14
|
+
export type RpcHandler = (ctx: HttpContext, params: unknown) => Promise<unknown> | unknown;
|
|
15
|
+
export interface RpcMethodDefinition {
|
|
16
|
+
name: string;
|
|
17
|
+
handler: RpcHandler;
|
|
18
|
+
guards: string[];
|
|
19
|
+
roles: string[];
|
|
20
|
+
permissions: string[];
|
|
21
|
+
middleware: string[];
|
|
22
|
+
validator?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare class RpcMethodBuilder {
|
|
25
|
+
#private;
|
|
26
|
+
constructor(def: RpcMethodDefinition);
|
|
27
|
+
guard(...guards: string[]): this;
|
|
28
|
+
role(...roles: string[]): this;
|
|
29
|
+
permission(...permissions: string[]): this;
|
|
30
|
+
validate(validator: string): this;
|
|
31
|
+
middleware(...names: string[]): this;
|
|
32
|
+
}
|
|
33
|
+
export declare class RpcRouter {
|
|
34
|
+
#private;
|
|
35
|
+
/**
|
|
36
|
+
* Set the IoC container used to resolve `namespace()` controllers — mirrors
|
|
37
|
+
* `GraphQLEngine.useContainer()` so RPC and GraphQL resolve class handlers the
|
|
38
|
+
* same way (fresh DI per call). Without a container, controllers fall back to
|
|
39
|
+
* `new Controller()`.
|
|
40
|
+
*/
|
|
41
|
+
useContainer(container: {
|
|
42
|
+
make<T>(target: new (...args: unknown[]) => T): T;
|
|
43
|
+
}): void;
|
|
44
|
+
/** Register an RPC method. */
|
|
45
|
+
method(name: string, handler: RpcHandler): RpcMethodBuilder;
|
|
46
|
+
/** Register methods from a controller — auto-registers all public methods. */
|
|
47
|
+
namespace(prefix: string, controller: new (...args: unknown[]) => Record<string, (...args: unknown[]) => unknown>): void;
|
|
48
|
+
/** Group methods with shared guards/middleware. */
|
|
49
|
+
group(config: {
|
|
50
|
+
guard?: string;
|
|
51
|
+
guards?: string[];
|
|
52
|
+
middleware?: string[];
|
|
53
|
+
}, callback: (rpc: RpcRouter) => void): void;
|
|
54
|
+
/** Handle an incoming JSON-RPC request. */
|
|
55
|
+
handle(ctx: HttpContext): Promise<void>;
|
|
56
|
+
/** Get all registered method names. */
|
|
57
|
+
getMethods(): string[];
|
|
58
|
+
/** Get method definition for introspection. */
|
|
59
|
+
getMethod(name: string): RpcMethodDefinition | undefined;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=RpcRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RpcRouter.d.ts","sourceRoot":"","sources":["../../src/rpc/RpcRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEzD,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;AAE1F,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,UAAU,CAAA;IACnB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,qBAAa,gBAAgB;;gBAGf,GAAG,EAAE,mBAAmB;IAIpC,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAKhC,IAAI,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAK9B,UAAU,CAAC,GAAG,WAAW,EAAE,MAAM,EAAE,GAAG,IAAI;IAK1C,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKjC,UAAU,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;CAIrC;AA+DD,qBAAa,SAAS;;IAKpB;;;;;OAKG;IACH,YAAY,CAAC,SAAS,EAAE;QAAE,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAA;KAAE,GAAG,IAAI;IAIpF,8BAA8B;IAC9B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,gBAAgB;IAa3D,8EAA8E;IAC9E,SAAS,CACP,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,GACtF,IAAI;IAeP,mDAAmD;IACnD,KAAK,CACH,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,EACpE,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,IAAI,GACjC,IAAI;IAWP,2CAA2C;IACrC,MAAM,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAgD7C,uCAAuC;IACvC,UAAU,IAAI,MAAM,EAAE;IAItB,+CAA+C;IAC/C,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;CAGzD"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 Router — dispatches RPC method calls to handlers.
|
|
3
|
+
*
|
|
4
|
+
* Same middleware/guard/validate pipeline as REST routes.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* rpc.method('task.validate', handler).guard('jwt').role('cs_member')
|
|
8
|
+
* rpc.namespace('task', TaskController) // every public method, DI-resolved per call
|
|
9
|
+
* rpc.group({ guard: 'jwt' }, (r) => { r.method('user.find', handler) })
|
|
10
|
+
*
|
|
11
|
+
* @implements MISS-27
|
|
12
|
+
*/
|
|
13
|
+
export class RpcMethodBuilder {
|
|
14
|
+
#def;
|
|
15
|
+
constructor(def) {
|
|
16
|
+
this.#def = def;
|
|
17
|
+
}
|
|
18
|
+
guard(...guards) {
|
|
19
|
+
this.#def.guards.push(...guards);
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
22
|
+
role(...roles) {
|
|
23
|
+
this.#def.roles.push(...roles);
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
permission(...permissions) {
|
|
27
|
+
this.#def.permissions.push(...permissions);
|
|
28
|
+
return this;
|
|
29
|
+
}
|
|
30
|
+
validate(validator) {
|
|
31
|
+
this.#def.validator = validator;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
middleware(...names) {
|
|
35
|
+
this.#def.middleware.push(...names);
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Build a JSON-RPC 2.0 error envelope. */
|
|
40
|
+
function rpcError(code, message, id) {
|
|
41
|
+
return { jsonrpc: '2.0', error: { code, message }, id };
|
|
42
|
+
}
|
|
43
|
+
/** Validate the JSON-RPC envelope and extract method/params/id. */
|
|
44
|
+
function parseRpcRequest(request) {
|
|
45
|
+
if (!request || typeof request !== 'object') {
|
|
46
|
+
return { ok: false, response: rpcError(-32600, 'Invalid Request', null) };
|
|
47
|
+
}
|
|
48
|
+
// request is narrowed to a non-null object by the typeof check above.
|
|
49
|
+
const jsonrpc = 'jsonrpc' in request && typeof request.jsonrpc === 'string' ? request.jsonrpc : undefined;
|
|
50
|
+
const method = 'method' in request && typeof request.method === 'string' ? request.method : undefined;
|
|
51
|
+
const params = 'params' in request ? request.params : undefined;
|
|
52
|
+
const id = 'id' in request ? request.id : undefined;
|
|
53
|
+
if (jsonrpc !== '2.0' || !method) {
|
|
54
|
+
return { ok: false, response: rpcError(-32600, 'Invalid Request', id ?? null) };
|
|
55
|
+
}
|
|
56
|
+
return { ok: true, method, params, id };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Enforce the method's guards/roles/permissions against the request auth state.
|
|
60
|
+
* Returns the JSON-RPC error code+message to reject with, or undefined when the
|
|
61
|
+
* caller is authorized.
|
|
62
|
+
*/
|
|
63
|
+
function checkRpcAuthorization(ctx, def) {
|
|
64
|
+
const needsAuth = def.guards.length > 0 || def.roles.length > 0 || def.permissions.length > 0;
|
|
65
|
+
if (needsAuth && !ctx.auth?.authenticated) {
|
|
66
|
+
return { code: -32003, message: 'Unauthorized' };
|
|
67
|
+
}
|
|
68
|
+
if (def.roles.length > 0) {
|
|
69
|
+
const userRoles = ctx.auth?.roles ?? [];
|
|
70
|
+
if (!def.roles.some((r) => userRoles.includes(r))) {
|
|
71
|
+
return { code: -32003, message: 'Insufficient role' };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (def.permissions.length > 0) {
|
|
75
|
+
const userPerms = ctx.auth?.permissions ?? [];
|
|
76
|
+
if (!def.permissions.every((p) => userPerms.includes(p))) {
|
|
77
|
+
return { code: -32003, message: 'Insufficient permissions' };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
export class RpcRouter {
|
|
83
|
+
#methods = new Map();
|
|
84
|
+
#groupConfig = null;
|
|
85
|
+
#container;
|
|
86
|
+
/**
|
|
87
|
+
* Set the IoC container used to resolve `namespace()` controllers — mirrors
|
|
88
|
+
* `GraphQLEngine.useContainer()` so RPC and GraphQL resolve class handlers the
|
|
89
|
+
* same way (fresh DI per call). Without a container, controllers fall back to
|
|
90
|
+
* `new Controller()`.
|
|
91
|
+
*/
|
|
92
|
+
useContainer(container) {
|
|
93
|
+
this.#container = container;
|
|
94
|
+
}
|
|
95
|
+
/** Register an RPC method. */
|
|
96
|
+
method(name, handler) {
|
|
97
|
+
const def = {
|
|
98
|
+
name,
|
|
99
|
+
handler,
|
|
100
|
+
guards: [...(this.#groupConfig?.guards ?? [])],
|
|
101
|
+
roles: [...(this.#groupConfig?.roles ?? [])],
|
|
102
|
+
permissions: [],
|
|
103
|
+
middleware: [...(this.#groupConfig?.middleware ?? [])],
|
|
104
|
+
};
|
|
105
|
+
this.#methods.set(name, def);
|
|
106
|
+
return new RpcMethodBuilder(def);
|
|
107
|
+
}
|
|
108
|
+
/** Register methods from a controller — auto-registers all public methods. */
|
|
109
|
+
namespace(prefix, controller) {
|
|
110
|
+
const proto = controller.prototype;
|
|
111
|
+
const methods = Object.getOwnPropertyNames(proto).filter((m) => m !== 'constructor' && typeof proto[m] === 'function');
|
|
112
|
+
for (const methodName of methods) {
|
|
113
|
+
this.method(`${prefix}.${methodName}`, async (ctx, params) => {
|
|
114
|
+
// Resolve through the container on every call (fresh DI per request,
|
|
115
|
+
// like GraphQLEngine), falling back to a bare `new` when unset.
|
|
116
|
+
const instance = this.#container ? this.#container.make(controller) : new controller();
|
|
117
|
+
return instance[methodName](ctx, params);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** Group methods with shared guards/middleware. */
|
|
122
|
+
group(config, callback) {
|
|
123
|
+
const prevConfig = this.#groupConfig;
|
|
124
|
+
this.#groupConfig = {
|
|
125
|
+
guards: [...(config.guards ?? []), ...(config.guard ? [config.guard] : [])],
|
|
126
|
+
roles: [],
|
|
127
|
+
middleware: config.middleware ?? [],
|
|
128
|
+
};
|
|
129
|
+
callback(this);
|
|
130
|
+
this.#groupConfig = prevConfig;
|
|
131
|
+
}
|
|
132
|
+
/** Handle an incoming JSON-RPC request. */
|
|
133
|
+
async handle(ctx) {
|
|
134
|
+
const body = ctx.request.body();
|
|
135
|
+
// Batch support (max 50 to prevent DoS)
|
|
136
|
+
if (Array.isArray(body)) {
|
|
137
|
+
if (body.length > 50) {
|
|
138
|
+
ctx.response.status(400).json({
|
|
139
|
+
jsonrpc: '2.0',
|
|
140
|
+
error: { code: -32600, message: 'Batch too large (max 50)' },
|
|
141
|
+
id: null,
|
|
142
|
+
});
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// Note: batch items share the same ctx (auth state). Each is processed sequentially.
|
|
146
|
+
const results = [];
|
|
147
|
+
for (const req of body) {
|
|
148
|
+
results.push(await this.#processOne(ctx, req));
|
|
149
|
+
}
|
|
150
|
+
ctx.response.status(200).json(results);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const result = await this.#processOne(ctx, body);
|
|
154
|
+
ctx.response.status(200).json(result);
|
|
155
|
+
}
|
|
156
|
+
async #processOne(ctx, request) {
|
|
157
|
+
const parsed = parseRpcRequest(request);
|
|
158
|
+
if (!parsed.ok)
|
|
159
|
+
return parsed.response;
|
|
160
|
+
const { method, params, id } = parsed;
|
|
161
|
+
const def = this.#methods.get(method);
|
|
162
|
+
if (!def)
|
|
163
|
+
return rpcError(-32601, 'Method not found', id);
|
|
164
|
+
try {
|
|
165
|
+
const denied = checkRpcAuthorization(ctx, def);
|
|
166
|
+
if (denied)
|
|
167
|
+
return rpcError(denied.code, denied.message, id);
|
|
168
|
+
const result = await def.handler(ctx, params);
|
|
169
|
+
return { jsonrpc: '2.0', result, id };
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
// Don't leak internal error details to caller
|
|
173
|
+
const isDev = process.env.NODE_ENV !== 'production';
|
|
174
|
+
const message = isDev && err instanceof Error ? err.message : 'Internal error';
|
|
175
|
+
return rpcError(-32603, message, id);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/** Get all registered method names. */
|
|
179
|
+
getMethods() {
|
|
180
|
+
return [...this.#methods.keys()];
|
|
181
|
+
}
|
|
182
|
+
/** Get method definition for introspection. */
|
|
183
|
+
getMethod(name) {
|
|
184
|
+
return this.#methods.get(name);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=RpcRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RpcRouter.js","sourceRoot":"","sources":["../../src/rpc/RpcRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAgBH,MAAM,OAAO,gBAAgB;IAC3B,IAAI,CAAqB;IAEzB,YAAY,GAAwB;QAClC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAA;IACjB,CAAC;IAED,KAAK,CAAC,GAAG,MAAgB;QACvB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAA;QAChC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,CAAC,GAAG,KAAe;QACrB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAA;QAC9B,OAAO,IAAI,CAAA;IACb,CAAC;IAED,UAAU,CAAC,GAAG,WAAqB;QACjC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAA;QAC1C,OAAO,IAAI,CAAA;IACb,CAAC;IAED,QAAQ,CAAC,SAAiB;QACxB,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC/B,OAAO,IAAI,CAAA;IACb,CAAC;IAED,UAAU,CAAC,GAAG,KAAe;QAC3B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAA;QACnC,OAAO,IAAI,CAAA;IACb,CAAC;CACF;AAQD,2CAA2C;AAC3C,SAAS,QAAQ,CAAC,IAAY,EAAE,OAAe,EAAE,EAAW;IAC1D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAAA;AACzD,CAAC;AAMD,mEAAmE;AACnE,SAAS,eAAe,CAAC,OAAgB;IACvC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,KAAK,EAAE,iBAAiB,EAAE,IAAI,CAAC,EAAE,CAAA;IAC3E,CAAC;IACD,sEAAsE;IACtE,MAAM,OAAO,GACX,SAAS,IAAI,OAAO,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAA;IAC3F,MAAM,MAAM,GACV,QAAQ,IAAI,OAAO,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;IACxF,MAAM,MAAM,GAAG,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;IAC/D,MAAM,EAAE,GAAG,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IACnD,IAAI,OAAO,KAAK,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;QACjC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,KAAK,EAAE,iBAAiB,EAAE,EAAE,IAAI,IAAI,CAAC,EAAE,CAAA;IACjF,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAA;AACzC,CAAC;AAED;;;;GAIG;AACH,SAAS,qBAAqB,CAC5B,GAAgB,EAChB,GAAwB;IAExB,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAA;IAC7F,IAAI,SAAS,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,CAAA;IAClD,CAAC;IACD,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAA;QACvC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,OAAO,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAA;QACvD,CAAC;IACH,CAAC;IACD,IAAI,GAAG,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,CAAA;QAC7C,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACjE,OAAO,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAA;QAC9D,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,OAAO,SAAS;IACpB,QAAQ,GAAqC,IAAI,GAAG,EAAE,CAAA;IACtD,YAAY,GAAuE,IAAI,CAAA;IACvF,UAAU,CAAwD;IAElE;;;;;OAKG;IACH,YAAY,CAAC,SAAgE;QAC3E,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;IAC7B,CAAC;IAED,8BAA8B;IAC9B,MAAM,CAAC,IAAY,EAAE,OAAmB;QACtC,MAAM,GAAG,GAAwB;YAC/B,IAAI;YACJ,OAAO;YACP,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;YAC9C,KAAK,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;YAC5C,WAAW,EAAE,EAAE;YACf,UAAU,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;SACvD,CAAA;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;QAC5B,OAAO,IAAI,gBAAgB,CAAC,GAAG,CAAC,CAAA;IAClC,CAAC;IAED,8EAA8E;IAC9E,SAAS,CACP,MAAc,EACd,UAAuF;QAEvF,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAA;QAClC,MAAM,OAAO,GAAG,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,MAAM,CACtD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,aAAa,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,UAAU,CAC7D,CAAA;QACD,KAAK,MAAM,UAAU,IAAI,OAAO,EAAE,CAAC;YACjC,IAAI,CAAC,MAAM,CAAC,GAAG,MAAM,IAAI,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;gBAC3D,qEAAqE;gBACrE,gEAAgE;gBAChE,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU,EAAE,CAAA;gBACtF,OAAO,QAAQ,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YAC1C,CAAC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,mDAAmD;IACnD,KAAK,CACH,MAAoE,EACpE,QAAkC;QAElC,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAA;QACpC,IAAI,CAAC,YAAY,GAAG;YAClB,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC3E,KAAK,EAAE,EAAE;YACT,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,EAAE;SACpC,CAAA;QACD,QAAQ,CAAC,IAAI,CAAC,CAAA;QACd,IAAI,CAAC,YAAY,GAAG,UAAU,CAAA;IAChC,CAAC;IAED,2CAA2C;IAC3C,KAAK,CAAC,MAAM,CAAC,GAAgB;QAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;QAE/B,wCAAwC;QACxC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;gBACrB,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBAC5B,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,0BAA0B,EAAE;oBAC5D,EAAE,EAAE,IAAI;iBACT,CAAC,CAAA;gBACF,OAAM;YACR,CAAC;YACD,qFAAqF;YACrF,MAAM,OAAO,GAAc,EAAE,CAAA;YAC7B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;YAChD,CAAC;YACD,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACtC,OAAM;QACR,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QAChD,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACvC,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,GAAgB,EAAE,OAAgB;QAClD,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAA;QACvC,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,MAAM,CAAC,QAAQ,CAAA;QACtC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,MAAM,CAAA;QAErC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACrC,IAAI,CAAC,GAAG;YAAE,OAAO,QAAQ,CAAC,CAAC,KAAK,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAA;QAEzD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,qBAAqB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;YAC9C,IAAI,MAAM;gBAAE,OAAO,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;YAE5D,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YAC7C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAA;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,8CAA8C;YAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAA;YACnD,MAAM,OAAO,GAAG,KAAK,IAAI,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAA;YAC9E,OAAO,QAAQ,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAA;QACtC,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,UAAU;QACR,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAClC,CAAC;IAED,+CAA+C;IAC/C,SAAS,CAAC,IAAY;QACpB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAChC,CAAC;CACF"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@Schedule('cron-expr')` method decorator — declares a recurring task.
|
|
3
|
+
*
|
|
4
|
+
* Tasks are discovered at boot by `ScheduleProvider` iterating the IoC
|
|
5
|
+
* service registry, reading this metadata, and registering each entry
|
|
6
|
+
* with the Rust-backed `Scheduler` (Story 28.1). The Rust ticker owns
|
|
7
|
+
* the loop; TypeScript only declares *what* runs and *when*.
|
|
8
|
+
*
|
|
9
|
+
* @implements Story 28.2
|
|
10
|
+
*/
|
|
11
|
+
import 'reflect-metadata';
|
|
12
|
+
import type { Constructor } from '../helpers/types.js';
|
|
13
|
+
export declare const SCHEDULE_METADATA_KEY: unique symbol;
|
|
14
|
+
export interface ScheduleMetadata {
|
|
15
|
+
cronExpr: string;
|
|
16
|
+
methodName: string | symbol;
|
|
17
|
+
target: Constructor;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Declares that a method should run on a cron schedule.
|
|
21
|
+
*
|
|
22
|
+
* Expressions are standard 5-field cron (minute hour day-of-month month
|
|
23
|
+
* day-of-week), evaluated in **UTC** by the Rust core — callers that
|
|
24
|
+
* want local-time semantics must pre-translate.
|
|
25
|
+
*
|
|
26
|
+
* Multiple `@Schedule` decorators on different methods of the same class
|
|
27
|
+
* accumulate into an array rather than overwriting each other. Metadata
|
|
28
|
+
* is stored with `Reflect.defineMetadata` under a stable symbol key on
|
|
29
|
+
* the class constructor; inherited metadata is NOT shared (each class
|
|
30
|
+
* owns its own array — subclasses that add schedules do not mutate the
|
|
31
|
+
* base class's array).
|
|
32
|
+
*
|
|
33
|
+
* Getters, setters, and static methods are rejected at decoration time
|
|
34
|
+
* with a clear `ReamError` so that misuse surfaces early rather than at
|
|
35
|
+
* first fire.
|
|
36
|
+
*
|
|
37
|
+
* Usage:
|
|
38
|
+
* ```ts
|
|
39
|
+
* @Service()
|
|
40
|
+
* class Cleanup {
|
|
41
|
+
* @Schedule('0 *\/5 * * *')
|
|
42
|
+
* async runCleanup() { ... }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function Schedule(cronExpr: string): MethodDecorator;
|
|
47
|
+
/**
|
|
48
|
+
* Return every `@Schedule` entry declared on `target` (empty array if
|
|
49
|
+
* none). Returns a shallow copy so callers cannot mutate the stored
|
|
50
|
+
* metadata by accident.
|
|
51
|
+
*/
|
|
52
|
+
export declare function getScheduleMetadata(target: Constructor): ScheduleMetadata[];
|
|
53
|
+
//# sourceMappingURL=Schedule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Schedule.d.ts","sourceRoot":"","sources":["../../src/scheduler/Schedule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,kBAAkB,CAAA;AAEzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEtD,eAAO,MAAM,qBAAqB,eAA0B,CAAA;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,GAAG,MAAM,CAAA;IAC3B,MAAM,EAAE,WAAW,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAmC1D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,gBAAgB,EAAE,CAG3E"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@Schedule('cron-expr')` method decorator — declares a recurring task.
|
|
3
|
+
*
|
|
4
|
+
* Tasks are discovered at boot by `ScheduleProvider` iterating the IoC
|
|
5
|
+
* service registry, reading this metadata, and registering each entry
|
|
6
|
+
* with the Rust-backed `Scheduler` (Story 28.1). The Rust ticker owns
|
|
7
|
+
* the loop; TypeScript only declares *what* runs and *when*.
|
|
8
|
+
*
|
|
9
|
+
* @implements Story 28.2
|
|
10
|
+
*/
|
|
11
|
+
import 'reflect-metadata';
|
|
12
|
+
import { ReamError } from '../errors/ReamError.js';
|
|
13
|
+
export const SCHEDULE_METADATA_KEY = Symbol('ream:schedule');
|
|
14
|
+
/**
|
|
15
|
+
* Declares that a method should run on a cron schedule.
|
|
16
|
+
*
|
|
17
|
+
* Expressions are standard 5-field cron (minute hour day-of-month month
|
|
18
|
+
* day-of-week), evaluated in **UTC** by the Rust core — callers that
|
|
19
|
+
* want local-time semantics must pre-translate.
|
|
20
|
+
*
|
|
21
|
+
* Multiple `@Schedule` decorators on different methods of the same class
|
|
22
|
+
* accumulate into an array rather than overwriting each other. Metadata
|
|
23
|
+
* is stored with `Reflect.defineMetadata` under a stable symbol key on
|
|
24
|
+
* the class constructor; inherited metadata is NOT shared (each class
|
|
25
|
+
* owns its own array — subclasses that add schedules do not mutate the
|
|
26
|
+
* base class's array).
|
|
27
|
+
*
|
|
28
|
+
* Getters, setters, and static methods are rejected at decoration time
|
|
29
|
+
* with a clear `ReamError` so that misuse surfaces early rather than at
|
|
30
|
+
* first fire.
|
|
31
|
+
*
|
|
32
|
+
* Usage:
|
|
33
|
+
* ```ts
|
|
34
|
+
* @Service()
|
|
35
|
+
* class Cleanup {
|
|
36
|
+
* @Schedule('0 *\/5 * * *')
|
|
37
|
+
* async runCleanup() { ... }
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function Schedule(cronExpr) {
|
|
42
|
+
return (target, propertyKey, descriptor) => {
|
|
43
|
+
// Reject static methods. For a static, `target` IS the constructor
|
|
44
|
+
// (callable function); for an instance method, `target` is the
|
|
45
|
+
// prototype. We need the real class either way.
|
|
46
|
+
if (typeof target === 'function') {
|
|
47
|
+
throw new ReamError('SCHEDULE_INVALID_TARGET', `@Schedule cannot be applied to static method '${String(propertyKey)}'`, {
|
|
48
|
+
hint: 'Move the scheduled logic to an instance method, or register the task manually via Scheduler.register().',
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// Reject getters/setters — `descriptor.value` is `undefined` for
|
|
52
|
+
// accessors, and the ticker needs a callable method.
|
|
53
|
+
if (descriptor && typeof descriptor.value !== 'function') {
|
|
54
|
+
throw new ReamError('SCHEDULE_INVALID_TARGET', `@Schedule cannot be applied to non-method '${String(propertyKey)}' (getters and setters are not supported)`, {
|
|
55
|
+
hint: 'Apply @Schedule to a regular method, not to an accessor.',
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
const ctor = target.constructor;
|
|
59
|
+
// getOwnMetadata — do NOT walk the prototype chain. A subclass must
|
|
60
|
+
// not mutate the base class's shared array; each class owns its own
|
|
61
|
+
// schedule list. Matches the convention in decorators/Service.ts.
|
|
62
|
+
const existing = Reflect.getOwnMetadata(SCHEDULE_METADATA_KEY, ctor) ?? [];
|
|
63
|
+
existing.push({ cronExpr, methodName: propertyKey, target: ctor });
|
|
64
|
+
Reflect.defineMetadata(SCHEDULE_METADATA_KEY, existing, ctor);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Return every `@Schedule` entry declared on `target` (empty array if
|
|
69
|
+
* none). Returns a shallow copy so callers cannot mutate the stored
|
|
70
|
+
* metadata by accident.
|
|
71
|
+
*/
|
|
72
|
+
export function getScheduleMetadata(target) {
|
|
73
|
+
const stored = Reflect.getOwnMetadata(SCHEDULE_METADATA_KEY, target) ?? [];
|
|
74
|
+
return [...stored];
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=Schedule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Schedule.js","sourceRoot":"","sources":["../../src/scheduler/Schedule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,kBAAkB,CAAA;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAGlD,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC,eAAe,CAAC,CAAA;AAQ5D;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAgB;IACvC,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE;QACzC,mEAAmE;QACnE,+DAA+D;QAC/D,gDAAgD;QAChD,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;YACjC,MAAM,IAAI,SAAS,CACjB,yBAAyB,EACzB,iDAAiD,MAAM,CAAC,WAAW,CAAC,GAAG,EACvE;gBACE,IAAI,EAAE,yGAAyG;aAChH,CACF,CAAA;QACH,CAAC;QAED,iEAAiE;QACjE,qDAAqD;QACrD,IAAI,UAAU,IAAI,OAAO,UAAU,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YACzD,MAAM,IAAI,SAAS,CACjB,yBAAyB,EACzB,8CAA8C,MAAM,CAAC,WAAW,CAAC,2CAA2C,EAC5G;gBACE,IAAI,EAAE,0DAA0D;aACjE,CACF,CAAA;QACH,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,WAA0B,CAAA;QAC9C,oEAAoE;QACpE,oEAAoE;QACpE,kEAAkE;QAClE,MAAM,QAAQ,GAAuB,OAAO,CAAC,cAAc,CAAC,qBAAqB,EAAE,IAAI,CAAC,IAAI,EAAE,CAAA;QAC9F,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;QAClE,OAAO,CAAC,cAAc,CAAC,qBAAqB,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAA;IAC/D,CAAC,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAmB;IACrD,MAAM,MAAM,GAAuB,OAAO,CAAC,cAAc,CAAC,qBAAqB,EAAE,MAAM,CAAC,IAAI,EAAE,CAAA;IAC9F,OAAO,CAAC,GAAG,MAAM,CAAC,CAAA;AACpB,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ScheduleProvider` — wires `@Schedule`-decorated methods into the
|
|
3
|
+
* Rust-backed [`Scheduler`].
|
|
4
|
+
*
|
|
5
|
+
* Lifecycle:
|
|
6
|
+
* - `boot()` — walks the IoC service registry, reads each class's
|
|
7
|
+
* `@Schedule` metadata, and registers a callback per entry.
|
|
8
|
+
* Idempotent: calling `boot()` twice is a no-op on the second call.
|
|
9
|
+
* Partial failures are rolled back — if the Nth task's registration
|
|
10
|
+
* throws, tasks 1..N-1 registered in the same boot are unregistered
|
|
11
|
+
* before the error propagates, so the scheduler is never left in a
|
|
12
|
+
* half-registered state.
|
|
13
|
+
* - `start()` — launches the Rust tick loop.
|
|
14
|
+
* - `shutdown()` — cancels the Rust tick loop.
|
|
15
|
+
*
|
|
16
|
+
* The registered callback resolves the service **at invocation time**
|
|
17
|
+
* (not registration time) via `container.make(target)`, so every run
|
|
18
|
+
* receives freshly-DI'd dependencies for transient-scoped services.
|
|
19
|
+
*
|
|
20
|
+
* @implements Story 28.2
|
|
21
|
+
*/
|
|
22
|
+
import type { AppContext } from '../Provider.js';
|
|
23
|
+
import { Provider } from '../Provider.js';
|
|
24
|
+
import { Scheduler } from './Scheduler.js';
|
|
25
|
+
export interface ScheduleProviderOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Override the `Scheduler` instance — used by tests to inject a
|
|
28
|
+
* mock. Production code relies on the default (`new Scheduler()`).
|
|
29
|
+
*/
|
|
30
|
+
scheduler?: Scheduler;
|
|
31
|
+
}
|
|
32
|
+
export declare class ScheduleProvider extends Provider {
|
|
33
|
+
#private;
|
|
34
|
+
readonly scheduler: Scheduler;
|
|
35
|
+
constructor(app: AppContext, options?: ScheduleProviderOptions);
|
|
36
|
+
/**
|
|
37
|
+
* Phase 1 — bind the scheduler into the IoC container under the
|
|
38
|
+
* stable token `'scheduler'`. CLI entrypoints
|
|
39
|
+
* (`ream schedule:list` / `ream schedule:run <name>`) retrieve the
|
|
40
|
+
* scheduler via `container.resolve('scheduler')` once the app has
|
|
41
|
+
* been booted through `Ignitor`. Consumers that import the
|
|
42
|
+
* provider directly still read the `readonly scheduler` field.
|
|
43
|
+
*
|
|
44
|
+
* Idempotent: re-registering the same provider instance (hot
|
|
45
|
+
* reload, repeated `app.start()` in tests) re-binds the same
|
|
46
|
+
* scheduler without error. A DIFFERENT `ScheduleProvider` trying
|
|
47
|
+
* to claim the `'scheduler'` token throws
|
|
48
|
+
* `SCHEDULE_PROVIDER_ALREADY_REGISTERED` so dueling providers do
|
|
49
|
+
* not silently overwrite each other.
|
|
50
|
+
*/
|
|
51
|
+
register(): void;
|
|
52
|
+
boot(): Promise<void>;
|
|
53
|
+
start(): Promise<void>;
|
|
54
|
+
shutdown(): Promise<void>;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=ScheduleProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScheduleProvider.d.ts","sourceRoot":"","sources":["../../src/scheduler/ScheduleProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB;AAED,qBAAa,gBAAiB,SAAQ,QAAQ;;IAC5C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;gBAGjB,GAAG,EAAE,UAAU,EAAE,OAAO,GAAE,uBAA4B;IAKlE;;;;;;;;;;;;;;OAcG;IACM,QAAQ,IAAI,IAAI;IA4BV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgFrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGzC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ScheduleProvider` — wires `@Schedule`-decorated methods into the
|
|
3
|
+
* Rust-backed [`Scheduler`].
|
|
4
|
+
*
|
|
5
|
+
* Lifecycle:
|
|
6
|
+
* - `boot()` — walks the IoC service registry, reads each class's
|
|
7
|
+
* `@Schedule` metadata, and registers a callback per entry.
|
|
8
|
+
* Idempotent: calling `boot()` twice is a no-op on the second call.
|
|
9
|
+
* Partial failures are rolled back — if the Nth task's registration
|
|
10
|
+
* throws, tasks 1..N-1 registered in the same boot are unregistered
|
|
11
|
+
* before the error propagates, so the scheduler is never left in a
|
|
12
|
+
* half-registered state.
|
|
13
|
+
* - `start()` — launches the Rust tick loop.
|
|
14
|
+
* - `shutdown()` — cancels the Rust tick loop.
|
|
15
|
+
*
|
|
16
|
+
* The registered callback resolves the service **at invocation time**
|
|
17
|
+
* (not registration time) via `container.make(target)`, so every run
|
|
18
|
+
* receives freshly-DI'd dependencies for transient-scoped services.
|
|
19
|
+
*
|
|
20
|
+
* @implements Story 28.2
|
|
21
|
+
*/
|
|
22
|
+
import { getServiceRegistry } from '../decorators/Service.js';
|
|
23
|
+
import { ReamError } from '../errors/ReamError.js';
|
|
24
|
+
import { Provider } from '../Provider.js';
|
|
25
|
+
import { getScheduleMetadata } from './Schedule.js';
|
|
26
|
+
import { Scheduler } from './Scheduler.js';
|
|
27
|
+
export class ScheduleProvider extends Provider {
|
|
28
|
+
scheduler;
|
|
29
|
+
#booted = false;
|
|
30
|
+
constructor(app, options = {}) {
|
|
31
|
+
super(app);
|
|
32
|
+
this.scheduler = options.scheduler ?? new Scheduler();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Phase 1 — bind the scheduler into the IoC container under the
|
|
36
|
+
* stable token `'scheduler'`. CLI entrypoints
|
|
37
|
+
* (`ream schedule:list` / `ream schedule:run <name>`) retrieve the
|
|
38
|
+
* scheduler via `container.resolve('scheduler')` once the app has
|
|
39
|
+
* been booted through `Ignitor`. Consumers that import the
|
|
40
|
+
* provider directly still read the `readonly scheduler` field.
|
|
41
|
+
*
|
|
42
|
+
* Idempotent: re-registering the same provider instance (hot
|
|
43
|
+
* reload, repeated `app.start()` in tests) re-binds the same
|
|
44
|
+
* scheduler without error. A DIFFERENT `ScheduleProvider` trying
|
|
45
|
+
* to claim the `'scheduler'` token throws
|
|
46
|
+
* `SCHEDULE_PROVIDER_ALREADY_REGISTERED` so dueling providers do
|
|
47
|
+
* not silently overwrite each other.
|
|
48
|
+
*/
|
|
49
|
+
register() {
|
|
50
|
+
const scheduler = this.scheduler;
|
|
51
|
+
const container = this.app.container;
|
|
52
|
+
// Probe for an existing binding. The `make` / `resolve` API
|
|
53
|
+
// throws when unbound; use it to distinguish "same instance"
|
|
54
|
+
// from "another provider already claimed the token".
|
|
55
|
+
let existing;
|
|
56
|
+
try {
|
|
57
|
+
existing = container.resolve('scheduler');
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
existing = undefined;
|
|
61
|
+
}
|
|
62
|
+
if (existing !== undefined) {
|
|
63
|
+
if (existing === scheduler) {
|
|
64
|
+
// Same provider re-running its register phase — no-op.
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
throw new ReamError('SCHEDULE_PROVIDER_ALREADY_REGISTERED', "Container token 'scheduler' is already bound to a different instance", {
|
|
68
|
+
hint: 'Only one ScheduleProvider can own the scheduler binding. Remove the duplicate provider from your reamrc.ts.',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
container.singleton('scheduler', () => scheduler);
|
|
72
|
+
}
|
|
73
|
+
async boot() {
|
|
74
|
+
if (this.#booted)
|
|
75
|
+
return;
|
|
76
|
+
const registry = getServiceRegistry();
|
|
77
|
+
const registered = [];
|
|
78
|
+
try {
|
|
79
|
+
for (const [target] of registry) {
|
|
80
|
+
const schedules = getScheduleMetadata(target);
|
|
81
|
+
if (schedules.length === 0)
|
|
82
|
+
continue;
|
|
83
|
+
if (!target.name) {
|
|
84
|
+
throw new ReamError('SCHEDULE_ANONYMOUS_CLASS', 'Anonymous classes cannot declare @Schedule — task names would collide', {
|
|
85
|
+
hint: 'Name the class explicitly (e.g. `export class Jobs { ... }`) so task names are unique and debuggable.',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
for (const { cronExpr, methodName } of schedules) {
|
|
89
|
+
// Reject symbol method keys — `String(Symbol('x'))` yields
|
|
90
|
+
// `Symbol(x)` which collides across distinct symbol instances
|
|
91
|
+
// sharing the same description. String keys are the
|
|
92
|
+
// documented contract.
|
|
93
|
+
if (typeof methodName === 'symbol') {
|
|
94
|
+
throw new ReamError('SCHEDULE_SYMBOL_METHOD', `@Schedule on symbol-keyed method is not supported on class '${target.name}'`, {
|
|
95
|
+
hint: 'Use a regular named method so the task can be addressed uniquely.',
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const taskName = `${target.name}.${methodName}`;
|
|
99
|
+
try {
|
|
100
|
+
this.scheduler.register(taskName, cronExpr, async () => {
|
|
101
|
+
// Resolve from the container on every fire so transient
|
|
102
|
+
// services get a fresh instance each run.
|
|
103
|
+
const instance = this.app.container.make(target);
|
|
104
|
+
const method = instance[methodName];
|
|
105
|
+
if (typeof method !== 'function') {
|
|
106
|
+
throw new ReamError('SCHEDULE_METHOD_NOT_FOUND', `Scheduled method ${taskName} is not callable on resolved instance`);
|
|
107
|
+
}
|
|
108
|
+
await method.call(instance);
|
|
109
|
+
});
|
|
110
|
+
registered.push(taskName);
|
|
111
|
+
}
|
|
112
|
+
catch (cause) {
|
|
113
|
+
const inner = cause;
|
|
114
|
+
throw new ReamError('SCHEDULE_INVALID_CRON', `Failed to register scheduled task '${taskName}': ${inner.message ?? String(cause)}`, {
|
|
115
|
+
context: { task: taskName, cronExpr },
|
|
116
|
+
hint: inner.hint,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
this.#booted = true;
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
// Roll back any partial registrations so a retry does not hit
|
|
125
|
+
// DUPLICATE_TASK and the scheduler is never half-initialized.
|
|
126
|
+
for (const name of registered) {
|
|
127
|
+
try {
|
|
128
|
+
this.scheduler.unregister(name);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Best-effort rollback; swallow secondary failures so the
|
|
132
|
+
// original error reaches the caller unchanged.
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
throw err;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async start() {
|
|
139
|
+
this.scheduler.start();
|
|
140
|
+
}
|
|
141
|
+
async shutdown() {
|
|
142
|
+
this.scheduler.stop();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=ScheduleProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScheduleProvider.js","sourceRoot":"","sources":["../../src/scheduler/ScheduleProvider.ts"],"names":[],"mappings":"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"}
|