@velajs/vela 1.19.0 → 1.19.1
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/CHANGELOG.md +22 -14
- package/dist/configurable-module.builder-5FGMaXG6.js +91 -0
- package/dist/configurable-module.builder-5FGMaXG6.js.map +1 -0
- package/dist/container-BqUHID4l.js +645 -0
- package/dist/container-BqUHID4l.js.map +1 -0
- package/dist/cron-matcher-C9qv5OUA.js +113 -0
- package/dist/cron-matcher-C9qv5OUA.js.map +1 -0
- package/dist/decorate-GcSMAbKn.js +528 -0
- package/dist/decorate-GcSMAbKn.js.map +1 -0
- package/dist/decorators-C8YBFCIk.js +53 -0
- package/dist/decorators-C8YBFCIk.js.map +1 -0
- package/dist/define-module-NOyOZNXD.js +235 -0
- package/dist/define-module-NOyOZNXD.js.map +1 -0
- package/dist/discovery.service-BYm95SSD.js +368 -0
- package/dist/discovery.service-BYm95SSD.js.map +1 -0
- package/dist/discovery.service-Cpf1QcZ5.d.ts +648 -0
- package/dist/i18n/index.d.ts +138 -10
- package/dist/i18n/index.js +270 -8
- package/dist/i18n/index.js.map +1 -0
- package/dist/index-D72EQfcC.d.ts +430 -0
- package/dist/index-DhShDLCM.d.ts +2310 -0
- package/dist/index.d.ts +6 -70
- package/dist/index.js +14 -76
- package/dist/internal.d.ts +13 -17
- package/dist/internal.js +6 -19
- package/dist/live/index.d.ts +2 -12
- package/dist/live/index.js +826 -16
- package/dist/live/index.js.map +1 -0
- package/dist/metadata.registry-D1od8ZBt.d.ts +842 -0
- package/dist/plugin-ByBlVOve.js +1387 -0
- package/dist/plugin-ByBlVOve.js.map +1 -0
- package/dist/queue/index.d.ts +247 -10
- package/dist/queue/index.js +384 -12
- package/dist/queue/index.js.map +1 -0
- package/dist/request-context-C3nCGJNd.js +26 -0
- package/dist/request-context-C3nCGJNd.js.map +1 -0
- package/dist/route.manager-DRAZ5X04.js +991 -0
- package/dist/route.manager-DRAZ5X04.js.map +1 -0
- package/dist/schedule-node/index.d.ts +32 -3
- package/dist/schedule-node/index.js +97 -3
- package/dist/schedule-node/index.js.map +1 -0
- package/dist/schedule.registry-DVm7Jp5w.d.ts +55 -0
- package/dist/seeder/index.d.ts +75 -5
- package/dist/seeder/index.js +105 -4
- package/dist/seeder/index.js.map +1 -0
- package/dist/signed-url-CMmi0SIb.js +56 -0
- package/dist/signed-url-CMmi0SIb.js.map +1 -0
- package/dist/signed-url-DKhgja4U.d.ts +16 -0
- package/dist/src-eb5CI6Xn.js +2151 -0
- package/dist/src-eb5CI6Xn.js.map +1 -0
- package/dist/storage/index.d.ts +57 -4
- package/dist/storage/index.js +22 -5
- package/dist/storage/index.js.map +1 -0
- package/dist/streaming/index.d.ts +2 -2
- package/dist/streaming/index.js +2 -1
- package/dist/websocket/index.d.ts +3 -12
- package/dist/websocket/index.js +2 -16
- package/dist/websocket-DXmB-MWJ.js +697 -0
- package/dist/websocket-DXmB-MWJ.js.map +1 -0
- package/dist/websocket-node/index.d.ts +108 -6
- package/dist/websocket-node/index.js +228 -6
- package/dist/websocket-node/index.js.map +1 -0
- package/package.json +66 -53
- package/dist/__tests__/workers/entry.d.ts +0 -9
- package/dist/__tests__/workers-als/entry-als.d.ts +0 -9
- package/dist/application.d.ts +0 -104
- package/dist/application.js +0 -364
- package/dist/cache/cache.decorators.d.ts +0 -2
- package/dist/cache/cache.decorators.js +0 -4
- package/dist/cache/cache.interceptor.d.ts +0 -9
- package/dist/cache/cache.interceptor.js +0 -60
- package/dist/cache/cache.module.d.ts +0 -7
- package/dist/cache/cache.module.js +0 -58
- package/dist/cache/cache.service.d.ts +0 -9
- package/dist/cache/cache.service.js +0 -42
- package/dist/cache/cache.store.d.ts +0 -12
- package/dist/cache/cache.store.js +0 -51
- package/dist/cache/cache.tokens.d.ts +0 -6
- package/dist/cache/cache.tokens.js +0 -5
- package/dist/cache/cache.types.d.ts +0 -41
- package/dist/cache/cache.types.js +0 -1
- package/dist/cache/index.d.ts +0 -8
- package/dist/cache/index.js +0 -7
- package/dist/cache/tiered-cache.store.d.ts +0 -19
- package/dist/cache/tiered-cache.store.js +0 -40
- package/dist/config/config.module.d.ts +0 -19
- package/dist/config/config.module.js +0 -98
- package/dist/config/config.service.d.ts +0 -20
- package/dist/config/config.service.js +0 -43
- package/dist/config/config.store.d.ts +0 -46
- package/dist/config/config.store.js +0 -119
- package/dist/config/config.tokens.d.ts +0 -13
- package/dist/config/config.tokens.js +0 -14
- package/dist/config/config.types.d.ts +0 -41
- package/dist/config/config.types.js +0 -4
- package/dist/config/index.d.ts +0 -7
- package/dist/config/index.js +0 -5
- package/dist/config/register-as.d.ts +0 -52
- package/dist/config/register-as.js +0 -39
- package/dist/constants.d.ts +0 -44
- package/dist/constants.js +0 -46
- package/dist/container/container.d.ts +0 -154
- package/dist/container/container.js +0 -849
- package/dist/container/decorators.d.ts +0 -17
- package/dist/container/decorators.js +0 -57
- package/dist/container/disposable.d.ts +0 -5
- package/dist/container/disposable.js +0 -33
- package/dist/container/index.d.ts +0 -6
- package/dist/container/index.js +0 -5
- package/dist/container/mixin.d.ts +0 -24
- package/dist/container/mixin.js +0 -26
- package/dist/container/module-ref.d.ts +0 -21
- package/dist/container/module-ref.js +0 -48
- package/dist/container/types.d.ts +0 -154
- package/dist/container/types.js +0 -49
- package/dist/cors/cors.module.d.ts +0 -7
- package/dist/cors/cors.module.js +0 -37
- package/dist/cors/cors.tokens.d.ts +0 -3
- package/dist/cors/cors.tokens.js +0 -2
- package/dist/cors/cors.types.d.ts +0 -8
- package/dist/cors/cors.types.js +0 -1
- package/dist/cors/index.d.ts +0 -3
- package/dist/cors/index.js +0 -2
- package/dist/crypto/signed-url.d.ts +0 -12
- package/dist/crypto/signed-url.js +0 -60
- package/dist/discovery/discoverable.decorator.d.ts +0 -38
- package/dist/discovery/discoverable.decorator.js +0 -42
- package/dist/discovery/discovery.service.d.ts +0 -102
- package/dist/discovery/discovery.service.js +0 -177
- package/dist/discovery/index.d.ts +0 -2
- package/dist/discovery/index.js +0 -2
- package/dist/entrypoint/entrypoint.registry.d.ts +0 -42
- package/dist/entrypoint/entrypoint.registry.js +0 -112
- package/dist/entrypoint/entrypoint.types.d.ts +0 -41
- package/dist/entrypoint/entrypoint.types.js +0 -3
- package/dist/entrypoint/execution-context.d.ts +0 -15
- package/dist/entrypoint/execution-context.js +0 -21
- package/dist/entrypoint/execution-scope.d.ts +0 -21
- package/dist/entrypoint/execution-scope.js +0 -28
- package/dist/entrypoint/index.d.ts +0 -4
- package/dist/entrypoint/index.js +0 -4
- package/dist/errors/http-exception.d.ts +0 -63
- package/dist/errors/http-exception.js +0 -142
- package/dist/errors/index.d.ts +0 -1
- package/dist/errors/index.js +0 -1
- package/dist/event-emitter/event-emitter.decorators.d.ts +0 -1
- package/dist/event-emitter/event-emitter.decorators.js +0 -10
- package/dist/event-emitter/event-emitter.module.d.ts +0 -2
- package/dist/event-emitter/event-emitter.module.js +0 -23
- package/dist/event-emitter/event-emitter.service.d.ts +0 -13
- package/dist/event-emitter/event-emitter.service.js +0 -127
- package/dist/event-emitter/event-emitter.subscriber.d.ts +0 -9
- package/dist/event-emitter/event-emitter.subscriber.js +0 -45
- package/dist/event-emitter/event-emitter.tokens.d.ts +0 -1
- package/dist/event-emitter/event-emitter.tokens.js +0 -1
- package/dist/event-emitter/event-emitter.types.d.ts +0 -5
- package/dist/event-emitter/event-emitter.types.js +0 -1
- package/dist/event-emitter/index.d.ts +0 -6
- package/dist/event-emitter/index.js +0 -5
- package/dist/exceptions/errors.module.d.ts +0 -40
- package/dist/exceptions/errors.module.js +0 -46
- package/dist/exceptions/exception-handler.d.ts +0 -56
- package/dist/exceptions/exception-handler.js +0 -17
- package/dist/exceptions/index.d.ts +0 -6
- package/dist/exceptions/index.js +0 -3
- package/dist/exceptions/reporter.d.ts +0 -21
- package/dist/exceptions/reporter.js +0 -70
- package/dist/factory/adapter.d.ts +0 -36
- package/dist/factory/adapter.js +0 -18
- package/dist/factory/bootstrap.d.ts +0 -23
- package/dist/factory/bootstrap.js +0 -110
- package/dist/factory.d.ts +0 -16
- package/dist/factory.js +0 -36
- package/dist/fetch/fetch.module.d.ts +0 -7
- package/dist/fetch/fetch.module.js +0 -31
- package/dist/fetch/fetch.service.d.ts +0 -24
- package/dist/fetch/fetch.service.js +0 -145
- package/dist/fetch/fetch.types.d.ts +0 -24
- package/dist/fetch/fetch.types.js +0 -1
- package/dist/fetch/index.d.ts +0 -3
- package/dist/fetch/index.js +0 -2
- package/dist/health/health.http.d.ts +0 -14
- package/dist/health/health.http.js +0 -75
- package/dist/health/health.indicator.d.ts +0 -9
- package/dist/health/health.indicator.js +0 -32
- package/dist/health/health.module.d.ts +0 -2
- package/dist/health/health.module.js +0 -26
- package/dist/health/health.service.d.ts +0 -7
- package/dist/health/health.service.js +0 -69
- package/dist/health/health.types.d.ts +0 -15
- package/dist/health/health.types.js +0 -1
- package/dist/health/index.d.ts +0 -6
- package/dist/health/index.js +0 -4
- package/dist/http/ambient.d.ts +0 -17
- package/dist/http/ambient.js +0 -44
- package/dist/http/argument-resolver.d.ts +0 -10
- package/dist/http/argument-resolver.js +0 -89
- package/dist/http/decorators.d.ts +0 -198
- package/dist/http/decorators.js +0 -321
- package/dist/http/execution-context.d.ts +0 -8
- package/dist/http/execution-context.js +0 -35
- package/dist/http/handler-executor.d.ts +0 -20
- package/dist/http/handler-executor.js +0 -133
- package/dist/http/index.d.ts +0 -12
- package/dist/http/index.js +0 -7
- package/dist/http/instantiate.d.ts +0 -4
- package/dist/http/instantiate.js +0 -45
- package/dist/http/lazy-param.decorator.d.ts +0 -37
- package/dist/http/lazy-param.decorator.js +0 -117
- package/dist/http/request-container.d.ts +0 -16
- package/dist/http/request-container.js +0 -19
- package/dist/http/request-context.d.ts +0 -13
- package/dist/http/request-context.js +0 -22
- package/dist/http/response-mapper.d.ts +0 -8
- package/dist/http/response-mapper.js +0 -42
- package/dist/http/route-contributor.d.ts +0 -68
- package/dist/http/route-contributor.js +0 -22
- package/dist/http/route-map.d.ts +0 -30
- package/dist/http/route-map.js +0 -27
- package/dist/http/route.manager.d.ts +0 -92
- package/dist/http/route.manager.js +0 -481
- package/dist/http/types.d.ts +0 -37
- package/dist/http/types.js +0 -1
- package/dist/http/url/index.d.ts +0 -4
- package/dist/http/url/index.js +0 -3
- package/dist/http/url/signed-url.guard.d.ts +0 -27
- package/dist/http/url/signed-url.guard.js +0 -62
- package/dist/http/url/signing-secret.d.ts +0 -20
- package/dist/http/url/signing-secret.js +0 -24
- package/dist/http/url/url-generator.service.d.ts +0 -52
- package/dist/http/url/url-generator.service.js +0 -104
- package/dist/i18n/deep-merge.d.ts +0 -2
- package/dist/i18n/deep-merge.js +0 -15
- package/dist/i18n/i18n.middleware.d.ts +0 -15
- package/dist/i18n/i18n.middleware.js +0 -94
- package/dist/i18n/i18n.module.d.ts +0 -13
- package/dist/i18n/i18n.module.js +0 -69
- package/dist/i18n/i18n.options.d.ts +0 -30
- package/dist/i18n/i18n.options.js +0 -16
- package/dist/i18n/i18n.service.d.ts +0 -20
- package/dist/i18n/i18n.service.js +0 -49
- package/dist/i18n/i18n.tokens.d.ts +0 -6
- package/dist/i18n/i18n.tokens.js +0 -3
- package/dist/i18n/i18n.types.d.ts +0 -6
- package/dist/i18n/i18n.types.js +0 -1
- package/dist/i18n/message-loader.service.d.ts +0 -21
- package/dist/i18n/message-loader.service.js +0 -90
- package/dist/i18n/message-registry.d.ts +0 -16
- package/dist/i18n/message-registry.js +0 -49
- package/dist/lifecycle/index.d.ts +0 -20
- package/dist/lifecycle/index.js +0 -15
- package/dist/live/live.cursor.d.ts +0 -22
- package/dist/live/live.cursor.js +0 -56
- package/dist/live/live.decorators.d.ts +0 -32
- package/dist/live/live.decorators.js +0 -46
- package/dist/live/live.delta.d.ts +0 -15
- package/dist/live/live.delta.js +0 -51
- package/dist/live/live.engine.d.ts +0 -88
- package/dist/live/live.engine.js +0 -471
- package/dist/live/live.invalidation.d.ts +0 -45
- package/dist/live/live.invalidation.js +0 -99
- package/dist/live/live.module.d.ts +0 -28
- package/dist/live/live.module.js +0 -87
- package/dist/live/live.tokens.d.ts +0 -9
- package/dist/live/live.tokens.js +0 -8
- package/dist/live/live.types.d.ts +0 -138
- package/dist/live/live.types.js +0 -1
- package/dist/live/presence.d.ts +0 -44
- package/dist/live/presence.js +0 -130
- package/dist/metadata.d.ts +0 -10
- package/dist/metadata.js +0 -20
- package/dist/module/configurable-module.builder.d.ts +0 -56
- package/dist/module/configurable-module.builder.js +0 -84
- package/dist/module/configurable-module.types.d.ts +0 -93
- package/dist/module/configurable-module.types.js +0 -5
- package/dist/module/decorators.d.ts +0 -10
- package/dist/module/decorators.js +0 -47
- package/dist/module/define-module.d.ts +0 -112
- package/dist/module/define-module.js +0 -232
- package/dist/module/graph.d.ts +0 -10
- package/dist/module/graph.js +0 -35
- package/dist/module/index.d.ts +0 -10
- package/dist/module/index.js +0 -7
- package/dist/module/lazy-modules.d.ts +0 -82
- package/dist/module/lazy-modules.js +0 -231
- package/dist/module/lazy-provider.d.ts +0 -65
- package/dist/module/lazy-provider.js +0 -111
- package/dist/module/middleware.d.ts +0 -30
- package/dist/module/middleware.js +0 -67
- package/dist/module/module-loader.d.ts +0 -58
- package/dist/module/module-loader.js +0 -484
- package/dist/module/stable-hash.d.ts +0 -15
- package/dist/module/stable-hash.js +0 -52
- package/dist/module/types.d.ts +0 -1
- package/dist/module/types.js +0 -1
- package/dist/openapi/decorators.d.ts +0 -34
- package/dist/openapi/decorators.js +0 -66
- package/dist/openapi/document.d.ts +0 -3
- package/dist/openapi/document.js +0 -316
- package/dist/openapi/index.d.ts +0 -7
- package/dist/openapi/index.js +0 -6
- package/dist/openapi/redoc-ui.d.ts +0 -1
- package/dist/openapi/redoc-ui.js +0 -19
- package/dist/openapi/scalar-ui.d.ts +0 -1
- package/dist/openapi/scalar-ui.js +0 -19
- package/dist/openapi/swagger-ui.d.ts +0 -1
- package/dist/openapi/swagger-ui.js +0 -23
- package/dist/openapi/types.d.ts +0 -182
- package/dist/openapi/types.js +0 -4
- package/dist/openapi/zod-to-json-schema.d.ts +0 -4
- package/dist/openapi/zod-to-json-schema.js +0 -57
- package/dist/pipeline/app-providers.d.ts +0 -10
- package/dist/pipeline/app-providers.js +0 -43
- package/dist/pipeline/component.manager.d.ts +0 -25
- package/dist/pipeline/component.manager.js +0 -66
- package/dist/pipeline/decorators.d.ts +0 -10
- package/dist/pipeline/decorators.js +0 -42
- package/dist/pipeline/index.d.ts +0 -12
- package/dist/pipeline/index.js +0 -7
- package/dist/pipeline/pipeline-runner.d.ts +0 -31
- package/dist/pipeline/pipeline-runner.js +0 -40
- package/dist/pipeline/pipes.d.ts +0 -48
- package/dist/pipeline/pipes.js +0 -104
- package/dist/pipeline/reflector.d.ts +0 -86
- package/dist/pipeline/reflector.js +0 -121
- package/dist/pipeline/scoped-components.d.ts +0 -26
- package/dist/pipeline/scoped-components.js +0 -27
- package/dist/pipeline/tokens.d.ts +0 -57
- package/dist/pipeline/tokens.js +0 -47
- package/dist/pipeline/types.d.ts +0 -64
- package/dist/pipeline/types.js +0 -1
- package/dist/plugin/plugin.d.ts +0 -31
- package/dist/plugin/plugin.js +0 -111
- package/dist/queue/inline.driver.d.ts +0 -30
- package/dist/queue/inline.driver.js +0 -58
- package/dist/queue/queue.binding.d.ts +0 -23
- package/dist/queue/queue.binding.js +0 -60
- package/dist/queue/queue.client.d.ts +0 -20
- package/dist/queue/queue.client.js +0 -33
- package/dist/queue/queue.decorators.d.ts +0 -23
- package/dist/queue/queue.decorators.js +0 -46
- package/dist/queue/queue.dispatch.d.ts +0 -36
- package/dist/queue/queue.dispatch.js +0 -109
- package/dist/queue/queue.module.d.ts +0 -32
- package/dist/queue/queue.module.js +0 -80
- package/dist/queue/queue.tokens.d.ts +0 -21
- package/dist/queue/queue.tokens.js +0 -34
- package/dist/queue/queue.types.d.ts +0 -61
- package/dist/queue/queue.types.js +0 -4
- package/dist/registry/index.d.ts +0 -2
- package/dist/registry/index.js +0 -1
- package/dist/registry/metadata.registry.d.ts +0 -73
- package/dist/registry/metadata.registry.js +0 -357
- package/dist/registry/paths.d.ts +0 -3
- package/dist/registry/paths.js +0 -15
- package/dist/registry/types.d.ts +0 -116
- package/dist/registry/types.js +0 -1
- package/dist/registry/util.d.ts +0 -3
- package/dist/registry/util.js +0 -8
- package/dist/schedule/cron-matcher.d.ts +0 -2
- package/dist/schedule/cron-matcher.js +0 -62
- package/dist/schedule/index.d.ts +0 -8
- package/dist/schedule/index.js +0 -5
- package/dist/schedule/schedule.decorators.d.ts +0 -2
- package/dist/schedule/schedule.decorators.js +0 -18
- package/dist/schedule/schedule.module.d.ts +0 -9
- package/dist/schedule/schedule.module.js +0 -28
- package/dist/schedule/schedule.registry.d.ts +0 -23
- package/dist/schedule/schedule.registry.js +0 -63
- package/dist/schedule/schedule.tokens.d.ts +0 -2
- package/dist/schedule/schedule.tokens.js +0 -2
- package/dist/schedule/schedule.types.d.ts +0 -8
- package/dist/schedule/schedule.types.js +0 -1
- package/dist/schedule-node/schedule-node.module.d.ts +0 -9
- package/dist/schedule-node/schedule-node.module.js +0 -28
- package/dist/schedule-node/schedule.executor.d.ts +0 -19
- package/dist/schedule-node/schedule.executor.js +0 -112
- package/dist/seeder/seeder.decorator.d.ts +0 -7
- package/dist/seeder/seeder.decorator.js +0 -15
- package/dist/seeder/seeder.module.d.ts +0 -16
- package/dist/seeder/seeder.module.js +0 -44
- package/dist/seeder/seeder.registry.d.ts +0 -23
- package/dist/seeder/seeder.registry.js +0 -83
- package/dist/seeder/seeder.tokens.d.ts +0 -2
- package/dist/seeder/seeder.tokens.js +0 -1
- package/dist/seeder/seeder.types.d.ts +0 -20
- package/dist/seeder/seeder.types.js +0 -1
- package/dist/serialization/index.d.ts +0 -2
- package/dist/serialization/index.js +0 -2
- package/dist/serialization/serialize.decorator.d.ts +0 -6
- package/dist/serialization/serialize.decorator.js +0 -7
- package/dist/serialization/serializer.interceptor.d.ts +0 -4
- package/dist/serialization/serializer.interceptor.js +0 -16
- package/dist/services/index.d.ts +0 -2
- package/dist/services/index.js +0 -1
- package/dist/services/logger.d.ts +0 -59
- package/dist/services/logger.js +0 -159
- package/dist/storage/path-template.d.ts +0 -9
- package/dist/storage/path-template.js +0 -20
- package/dist/storage/storage.types.d.ts +0 -41
- package/dist/storage/storage.types.js +0 -5
- package/dist/throttler/index.d.ts +0 -6
- package/dist/throttler/index.js +0 -5
- package/dist/throttler/throttler.decorators.d.ts +0 -3
- package/dist/throttler/throttler.decorators.js +0 -4
- package/dist/throttler/throttler.guard.d.ts +0 -9
- package/dist/throttler/throttler.guard.js +0 -72
- package/dist/throttler/throttler.module.d.ts +0 -7
- package/dist/throttler/throttler.module.js +0 -41
- package/dist/throttler/throttler.storage.d.ts +0 -10
- package/dist/throttler/throttler.storage.js +0 -44
- package/dist/throttler/throttler.tokens.d.ts +0 -6
- package/dist/throttler/throttler.tokens.js +0 -5
- package/dist/throttler/throttler.types.d.ts +0 -25
- package/dist/throttler/throttler.types.js +0 -1
- package/dist/validation/create-zod-dto.d.ts +0 -13
- package/dist/validation/create-zod-dto.js +0 -18
- package/dist/validation/index.d.ts +0 -3
- package/dist/validation/index.js +0 -2
- package/dist/validation/validation.pipe.d.ts +0 -4
- package/dist/validation/validation.pipe.js +0 -19
- package/dist/websocket/websocket.decorators.d.ts +0 -47
- package/dist/websocket/websocket.decorators.js +0 -80
- package/dist/websocket/websocket.module.d.ts +0 -35
- package/dist/websocket/websocket.module.js +0 -63
- package/dist/websocket/websocket.tokens.d.ts +0 -30
- package/dist/websocket/websocket.tokens.js +0 -27
- package/dist/websocket/websocket.types.d.ts +0 -102
- package/dist/websocket/websocket.types.js +0 -4
- package/dist/websocket/ws-argument-resolver.d.ts +0 -13
- package/dist/websocket/ws-argument-resolver.js +0 -40
- package/dist/websocket/ws-dispatcher.d.ts +0 -54
- package/dist/websocket/ws-dispatcher.js +0 -343
- package/dist/websocket/ws-exception.d.ts +0 -25
- package/dist/websocket/ws-exception.js +0 -42
- package/dist/websocket/ws-execution-context.d.ts +0 -9
- package/dist/websocket/ws-execution-context.js +0 -24
- package/dist/websocket/ws-server.d.ts +0 -31
- package/dist/websocket/ws-server.js +0 -74
- package/dist/websocket/ws-sync.d.ts +0 -47
- package/dist/websocket/ws-sync.js +0 -74
- package/dist/websocket-node/node-ws-client.d.ts +0 -24
- package/dist/websocket-node/node-ws-client.js +0 -49
- package/dist/websocket-node/redis-live.d.ts +0 -24
- package/dist/websocket-node/redis-live.js +0 -57
- package/dist/websocket-node/redis-sync.d.ts +0 -33
- package/dist/websocket-node/redis-sync.js +0 -56
- package/dist/websocket-node/register-gateways.d.ts +0 -20
- package/dist/websocket-node/register-gateways.js +0 -61
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocket-DXmB-MWJ.js","names":[],"sources":["../src/discovery/discoverable.decorator.ts","../src/websocket/websocket.tokens.ts","../src/websocket/websocket.decorators.ts","../src/websocket/ws-argument-resolver.ts","../src/websocket/ws-execution-context.ts","../src/websocket/ws-exception.ts","../src/websocket/ws-dispatcher.ts","../src/websocket/ws-server.ts","../src/websocket/ws-sync.ts","../src/websocket/websocket.module.ts"],"sourcesContent":["import { MetadataRegistry } from '../registry/metadata.registry';\nimport type { Constructor } from '../registry/types';\n\n/**\n * A decorator whose annotated classes/methods are findable through\n * `DiscoveryService` by the decorator itself (no string key at the call site).\n */\nexport interface DiscoverableDecorator<T> {\n (value: T): ClassDecorator & MethodDecorator;\n /** The metadata key backing this decorator — stable across HMR re-evals. */\n KEY: string;\n}\n\nexport interface CreateDiscoverableDecoratorOptions {\n /**\n * Append to a class-level list instead of overwriting a single slot —\n * for stackable method decorators (`@Cron`-style: each application pushes\n * `{ methodName, ...value }` onto the class's list, which\n * `DiscoveryService.methodsWithMeta` flattens back to per-method entries).\n */\n append?: boolean;\n}\n\n/**\n * Mint a discoverable decorator for a module's extension surface:\n *\n * ```ts\n * export interface QueueConsumerMeta { queue: string }\n * export const QueueConsumer = createDiscoverableDecorator<QueueConsumerMeta>('vela:queue:consumer');\n *\n * @QueueConsumer({ queue: 'emails' })\n * @Injectable()\n * class EmailConsumer { ... }\n *\n * // At bootstrap, anywhere:\n * discovery.providersWithMeta(QueueConsumer) // typed { meta: QueueConsumerMeta }\n * ```\n *\n * Unlike `Reflector.createDecorator`, the key is required and caller-chosen:\n * a random key would mint a fresh identity on every HMR re-eval and orphan\n * previously-decorated classes. Namespace it (`'<pkg>:<area>:<thing>'`).\n */\nexport function createDiscoverableDecorator<T>(\n key: string,\n options: CreateDiscoverableDecoratorOptions = {},\n): DiscoverableDecorator<T> {\n const decorator = (value: T) => {\n return (target: object, propertyKey?: string | symbol): void => {\n const ctor =\n propertyKey !== undefined ? (target.constructor as Constructor) : (target as Constructor);\n if (options.append) {\n if (propertyKey !== undefined) {\n MetadataRegistry.appendCustomClassMeta(ctor, key, {\n methodName: propertyKey,\n ...(value as object),\n });\n } else {\n MetadataRegistry.appendCustomClassMeta(ctor, key, value);\n }\n } else if (propertyKey !== undefined) {\n MetadataRegistry.setCustomHandlerMeta(ctor, propertyKey, key, value);\n } else {\n MetadataRegistry.setCustomClassMeta(ctor, key, value);\n }\n };\n };\n (decorator as DiscoverableDecorator<T>).KEY = key;\n return decorator as DiscoverableDecorator<T>;\n}\n","import { InjectionToken } from '../container/types';\nimport type { WebSocketModuleOptions } from './websocket.module';\nimport type { RoomRegistry, SyncDriver } from './ws-sync';\nimport type { WsServer } from './websocket.types';\n\n// Free-form metadata keys — same string-token convention as ON_EVENT_METADATA / CRON_METADATA.\nexport const WS_GATEWAY_METADATA = 'vela:ws-gateway';\nexport const WS_SUBSCRIBE_METADATA = 'vela:ws-subscribe';\nexport const WS_RESERVED_METADATA = 'vela:ws-reserved';\n\n/**\n * Event names starting with this prefix are RESERVED for framework modules\n * (`$live`, …): app gateways may not subscribe to them, and inbound frames\n * carrying them route to `@ReservedWsEvent` handlers instead of gateways.\n */\nexport const RESERVED_WS_EVENT_PREFIX = '$';\n\n// WebSocket parameter-decorator kinds — parallel to `ParamType` for HTTP, keyed\n// by the WS argument resolver rather than the Hono-bound HTTP one.\nexport const WsParamType = {\n SOCKET: 'ws_socket',\n BODY: 'ws_body',\n SERVER: 'ws_server',\n} as const;\nexport type WsParamType = (typeof WsParamType)[keyof typeof WsParamType];\n\n/**\n * The connected gateway server handle. Injected into gateways/controllers via\n * `@WebSocketServer()` (constructor injection only — the container has no\n * property-injection pass) or `@Inject(WS_SERVER)`.\n */\nexport const WS_SERVER = new InjectionToken<WsServer>('WS_SERVER');\n\n/** The active cross-instance sync driver (`local()` by default). */\nexport const WS_SYNC_DRIVER = new InjectionToken<SyncDriver>('WS_SYNC_DRIVER');\n\n/** The local room-membership registry a transport reads/writes. */\nexport const WS_ROOM_REGISTRY = new InjectionToken<RoomRegistry>('WS_ROOM_REGISTRY');\n\n// forRoot() options carrier — a typed InjectionToken like every other module\n// options token (the raw-string form was the odd one out).\nexport const WS_MODULE_OPTIONS = new InjectionToken<WebSocketModuleOptions>('WS_MODULE_OPTIONS');\n","import { Scope } from '../constants';\nimport { Inject } from '../container/decorators';\nimport { createDiscoverableDecorator } from '../discovery/index';\nimport { MetadataRegistry } from '../registry/metadata.registry';\nimport type { Constructor } from '../registry/types';\nimport {\n RESERVED_WS_EVENT_PREFIX,\n WS_GATEWAY_METADATA,\n WS_RESERVED_METADATA,\n WS_SERVER,\n WS_SUBSCRIBE_METADATA,\n WsParamType,\n} from './websocket.tokens';\nimport type {\n ReservedWsEventMetadata,\n SubscribeMessageMetadata,\n WebSocketGatewayOptions,\n} from './websocket.types';\n\n/**\n * Marks a class as a WebSocket gateway. Mirrors `@Controller` for the socket\n * transport: registers the class as an injectable singleton and stores its\n * routing options (`path`, Cloudflare `binding`).\n *\n * @example\n * ```ts\n * @WebSocketGateway({ path: '/rooms/:id/ws', binding: 'CHAT_ROOM' })\n * class ChatGateway {}\n * ```\n */\nexport function WebSocketGateway(options: WebSocketGatewayOptions = {}): ClassDecorator {\n return (target) => {\n const ctor = target as unknown as Constructor;\n MetadataRegistry.setCustomClassMeta(ctor, WS_GATEWAY_METADATA, options);\n MetadataRegistry.markInjectable(ctor);\n MetadataRegistry.setScope(ctor, Scope.SINGLETON);\n };\n}\n\n/**\n * Binds a gateway method to an inbound event. Stackable — one class-level list,\n * exactly like `@OnEvent` (`event-emitter.decorators.ts`).\n */\nexport function SubscribeMessage(event: string): MethodDecorator {\n return (target: object, propertyKey: string | symbol) => {\n MetadataRegistry.appendCustomClassMeta<SubscribeMessageMetadata>(\n target.constructor as Constructor,\n WS_SUBSCRIBE_METADATA,\n { event, methodName: String(propertyKey) },\n );\n };\n}\n\nconst ReservedWsEventMeta =\n createDiscoverableDecorator<ReservedWsEventMetadata>(WS_RESERVED_METADATA);\n\n/**\n * Claims a reserved (`$`-prefixed) envelope event for a framework-module\n * provider (see `ReservedWsEventHandler`). Reserved frames route to the\n * decorated provider across every gateway path — gateways themselves may not\n * subscribe to `$…` events. Stack with `@Injectable()` like `@Processor`.\n *\n * @example\n * ```ts\n * @ReservedWsEvent('$live')\n * @Injectable()\n * class LiveEngine implements ReservedWsEventHandler { … }\n * ```\n */\nexport function ReservedWsEvent(event: string): ClassDecorator {\n if (!event.startsWith(RESERVED_WS_EVENT_PREFIX)) {\n throw new Error(\n `@ReservedWsEvent('${event}') must claim a '${RESERVED_WS_EVENT_PREFIX}'-prefixed event — ` +\n 'unprefixed events belong to app gateways (@SubscribeMessage).',\n );\n }\n return ReservedWsEventMeta({ event }) as ClassDecorator;\n}\n\nfunction wsParamDecorator(type: WsParamType): () => ParameterDecorator {\n return () =>\n (target: object, propertyKey: string | symbol | undefined, parameterIndex: number) => {\n if (propertyKey === undefined) {\n throw new Error('WebSocket parameter decorators can only be used on method parameters');\n }\n MetadataRegistry.addParameter(target.constructor as Constructor, propertyKey, {\n index: parameterIndex,\n type,\n });\n };\n}\n\n/** Injects the inbound message payload (the envelope's `data`) into a handler parameter. */\nexport const MessageBody = wsParamDecorator(WsParamType.BODY);\n\n/** Injects the connected socket (`WsClient`) into a handler parameter. */\nexport const ConnectedSocket = wsParamDecorator(WsParamType.SOCKET);\n\n/**\n * Injects the gateway server handle (`WsServer`). Constructor injection only —\n * the container has no property-injection pass, so this is sugar for\n * `@Inject(WS_SERVER)` on a constructor parameter.\n *\n * @example\n * ```ts\n * constructor(@WebSocketServer() private server: WsServer) {}\n * ```\n */\nexport function WebSocketServer(): ParameterDecorator {\n return Inject(WS_SERVER);\n}\n","import type { Type } from '../container/types';\nimport type { ArgumentMetadata, PipeTransform } from '../pipeline/types';\nimport type { ParameterMetadata } from '../registry/types';\nimport { WsParamType } from './websocket.tokens';\nimport type { WsClient } from './websocket.types';\n\n/**\n * Builds handler arguments for a gateway message. WS sibling of the HTTP\n * `ArgumentResolver`, but sourced from the envelope (`data`) and the socket\n * (`client`) instead of the Hono `Context`.\n *\n * With no parameter decorators the handler receives `(client, data)` — the\n * NestJS gateway convention. Pipes run only over `@MessageBody()` values, where\n * validation/transformation is meaningful.\n */\nexport async function resolveWsArgs(\n paramMeta: ParameterMetadata[],\n client: WsClient,\n data: unknown,\n pipes: PipeTransform[],\n paramTypes?: unknown[],\n): Promise<unknown[]> {\n if (paramMeta.length === 0) {\n return [client, data];\n }\n\n const maxIndex = paramMeta[paramMeta.length - 1]!.index;\n const args: unknown[] = new Array(maxIndex + 1).fill(undefined);\n\n for (const param of paramMeta) {\n if (param.type === WsParamType.SOCKET) {\n args[param.index] = client;\n continue;\n }\n\n if (param.type === WsParamType.BODY) {\n let value: unknown = data;\n const metadata: ArgumentMetadata = {\n type: param.type,\n data: param.name,\n metatype: paramTypes?.[param.index] as Type | undefined,\n };\n for (const pipe of pipes) {\n value = await pipe.transform(value, metadata);\n }\n args[param.index] = value;\n continue;\n }\n\n args[param.index] = undefined;\n }\n\n return args;\n}\n","import type { Type } from '../container/types';\nimport type { WsArgumentsHost } from '../pipeline/types';\nimport type { WsClient, WsExecutionContext } from './websocket.types';\n\nconst HTTP_ON_WS = (accessor: string) => () => {\n throw new Error(\n `${accessor} called on a WebSocket ExecutionContext. This handler runs over a gateway message, not HTTP — use switchToWs().`,\n );\n};\n\n/**\n * WebSocket sibling of `buildExecutionContext` (`http/execution-context.ts`).\n * Guards/pipes/interceptors/filters that read `getClass()`/`getHandler()` or\n * call `switchToWs()` reuse unchanged; the HTTP-only accessors throw rather\n * than fabricate a fake `Request`.\n */\nexport function buildWsExecutionContext(\n client: WsClient,\n data: unknown,\n controller: Type,\n handlerName: string | symbol,\n pattern: string,\n): WsExecutionContext {\n const host: WsArgumentsHost = {\n getClient: <T = unknown>() => client as T,\n getData: <T = unknown>() => data as T,\n getPattern: <T = string>() => pattern as T,\n };\n\n return {\n getType: <T extends string = 'ws'>() => 'ws' as T,\n getClass: () => controller,\n getHandler: () => handlerName,\n getContext: HTTP_ON_WS('getContext()') as never,\n getRequest: HTTP_ON_WS('getRequest()') as never,\n switchToHttp: HTTP_ON_WS('switchToHttp()') as never,\n switchToWs: () => host,\n };\n}\n","import { toErrorBody, type Catalog } from '@velajs/errors';\n\n/**\n * WebSocket analogue of `HttpException`. Thrown from guards/pipes/handlers to\n * signal a client-facing error; the dispatcher serializes it to an\n * `{ event: 'exception', data }` frame unless a matching exception filter\n * handles it first.\n */\nexport class WsException extends Error {\n constructor(private readonly err: string | Record<string, unknown>) {\n super(\n typeof err === 'string'\n ? err\n : String((err as Record<string, unknown>).message ?? 'WsException'),\n );\n this.name = 'WsException';\n }\n\n getError(): string | Record<string, unknown> {\n return this.err;\n }\n}\n\n/**\n * Default serialization of an uncaught error into the outbound exception frame.\n *\n * A `WsException` ships its own payload verbatim (string → `{ message }`,\n * object → as-is). Every other error routes through `toErrorBody` — the single\n * wire-redaction seam shared with the HTTP edge — so unbranded/internal errors\n * are redacted to their catalog title and only branded `VelaError`s echo a\n * client-safe `{ code, message, ... }`.\n */\nexport function toErrorFrame(\n error: unknown,\n catalog?: Catalog<string>,\n): { event: 'exception'; data: unknown } {\n if (error instanceof WsException) {\n const e = error.getError();\n return { event: 'exception', data: typeof e === 'string' ? { message: e } : e };\n }\n const { body } = toErrorBody(error, { catalog });\n return { event: 'exception', data: body.error };\n}\n","import { Container } from '../container/container';\nimport { Inject, Injectable, Optional } from '../container/decorators';\nimport type { Type } from '../container/types';\nimport { DiscoveryService } from '../discovery/discovery.service';\nimport type { ContributesEntrypoints, Entrypoint } from '../entrypoint/entrypoint.types';\nimport { resolveErrorReporter, type ErrorReporter } from '../exceptions/reporter';\nimport { instantiateMany } from '../http/instantiate';\nimport { RouteManager } from '../http/route.manager';\nimport type { OnApplicationBootstrap } from '../lifecycle/index';\nimport { ComponentManager } from '../pipeline/component.manager';\nimport { shouldFilterCatch } from '../pipeline/decorators';\nimport { PipelineRunner } from '../pipeline/pipeline-runner';\nimport type {\n CanActivate,\n ExceptionFilter,\n NestInterceptor,\n PipeTransform,\n} from '../pipeline/types';\nimport { MetadataRegistry } from '../registry/metadata.registry';\nimport type {\n Constructor,\n FilterType,\n GuardType,\n InterceptorType,\n ParameterMetadata,\n PipeType,\n} from '../registry/types';\nimport { resolveWsArgs } from './ws-argument-resolver';\nimport { buildWsExecutionContext } from './ws-execution-context';\nimport { toErrorFrame, WsException } from './ws-exception';\nimport {\n RESERVED_WS_EVENT_PREFIX,\n WS_GATEWAY_METADATA,\n WS_RESERVED_METADATA,\n WS_SERVER,\n WS_SUBSCRIBE_METADATA,\n} from './websocket.tokens';\nimport type {\n OnGatewayConnection,\n OnGatewayDisconnect,\n OnGatewayInit,\n ReservedWsEventHandler,\n ReservedWsEventMetadata,\n SubscribeMessageMetadata,\n WebSocketGatewayOptions,\n WsClient,\n WsExecutionContext,\n WsMessage,\n WsResponse,\n WsServer,\n} from './websocket.types';\n\ninterface HandlerEntry {\n methodName: string;\n paramMeta: ParameterMetadata[];\n paramTypes?: unknown[];\n guards: GuardType[];\n pipes: PipeType[];\n interceptors: InterceptorType[];\n filters: FilterType[];\n}\n\ninterface GatewayEntry {\n path: string;\n instance: Record<string, unknown>;\n gatewayClass: Type;\n handlers: Map<string, HandlerEntry>;\n}\n\nfunction hasAfterInit(x: unknown): x is OnGatewayInit {\n return typeof (x as OnGatewayInit)?.afterInit === 'function';\n}\nfunction hasHandleConnection(x: unknown): x is OnGatewayConnection {\n return typeof (x as OnGatewayConnection)?.handleConnection === 'function';\n}\nfunction hasHandleDisconnect(x: unknown): x is OnGatewayDisconnect {\n return typeof (x as OnGatewayDisconnect)?.handleDisconnect === 'function';\n}\nfunction isWsResponse(x: unknown): x is WsResponse {\n return typeof x === 'object' && x !== null && typeof (x as WsResponse).event === 'string';\n}\n\n/** Metadata carried by each `'websocket'` entrypoint a transport consumes. */\nexport interface WsEntrypointMeta {\n /** The gateway's route path (from `@WebSocketGateway({ path })`). */\n path: string;\n /** The dispatcher that routes frames for this gateway. */\n dispatcher: WsDispatcher;\n}\n\n/**\n * Discovers `@WebSocketGateway` classes at bootstrap (via `DiscoveryService`)\n * and routes inbound messages to `@SubscribeMessage` handlers. Transports read\n * the gateways from `app.entrypoints.ofKind('websocket')` (this dispatcher\n * contributes them) and call `handleOpen`, `dispatchMessage`, `handleClose`,\n * and `handleError`; the guard → pipe → interceptor → filter pipeline\n * (including `APP_*` global components) runs through the shared\n * `PipelineRunner`.\n */\n@Injectable()\nexport class WsDispatcher implements OnApplicationBootstrap, ContributesEntrypoints {\n private readonly gateways = new Map<string, GatewayEntry>();\n private readonly reserved = new Map<string, ReservedWsEventHandler>();\n\n constructor(\n @Inject(Container) private readonly container: Container,\n @Inject(DiscoveryService) private readonly discovery: DiscoveryService,\n @Optional() @Inject(WS_SERVER) private readonly server?: WsServer,\n @Optional() @Inject(RouteManager) private readonly routeManager?: RouteManager,\n ) {}\n\n /** Paths of every discovered `@WebSocketGateway` — used by transports to register routes. */\n get gatewayPaths(): string[] {\n return [...this.gateways.keys()];\n }\n\n async onApplicationBootstrap(): Promise<void> {\n // Reserved-event handlers first: modules claiming a `$…` event\n // (@ReservedWsEvent) receive those frames across every gateway path.\n for (const found of this.discovery.providersWithMeta<ReservedWsEventMetadata>(\n WS_RESERVED_METADATA,\n )) {\n if (!found.instance) continue;\n const event = found.meta.event;\n if (this.reserved.has(event)) {\n const msg =\n `[vela] duplicate @ReservedWsEvent('${event}') ` +\n `(${found.metatype.name}); keeping the first.`;\n if (this.container.getDiagnostics() === 'throw') throw new Error(msg);\n console.warn(msg);\n continue;\n }\n this.reserved.set(event, found.instance as unknown as ReservedWsEventHandler);\n }\n\n for (const found of this.discovery.providersWithMeta<WebSocketGatewayOptions>(\n WS_GATEWAY_METADATA,\n )) {\n if (!found.instance) continue;\n const gatewayClass = found.metatype;\n const instance = found.instance as Record<string, unknown>;\n\n const entry = this.buildGatewayEntry(gatewayClass, found.meta, instance);\n\n // Two gateways on the same path (or both defaulting to '') would silently\n // overwrite each other in the routing Map — surface it instead.\n if (this.gateways.has(entry.path)) {\n const msg =\n `[vela] duplicate @WebSocketGateway path '${entry.path}' ` +\n `(${gatewayClass.name}); keeping the first. Give each gateway a distinct path.`;\n if (this.container.getDiagnostics() === 'throw') throw new Error(msg);\n console.warn(msg);\n continue;\n }\n this.gateways.set(entry.path, entry);\n\n if (this.server && hasAfterInit(instance)) {\n try {\n await instance.afterInit(this.server);\n } catch (err) {\n this.reportBootstrapError(gatewayClass.name, err);\n }\n }\n }\n }\n\n /** One `'websocket'` entrypoint per discovered gateway (authoritative). */\n collectEntrypoints(): Entrypoint<WsEntrypointMeta>[] {\n return [...this.gateways.values()].map((entry) => ({\n kind: 'websocket',\n token: entry.gatewayClass,\n instance: entry.instance,\n meta: { path: entry.path, dispatcher: this },\n }));\n }\n\n async handleOpen(path: string, client: WsClient): Promise<void> {\n const entry = this.gateways.get(path);\n if (entry && hasHandleConnection(entry.instance)) {\n await entry.instance.handleConnection(client);\n }\n }\n\n async handleClose(path: string, client: WsClient, _code: number, _reason: string): Promise<void> {\n // Reserved handlers drop per-connection state first (isolated per handler)\n // so a throwing gateway handleDisconnect can't leak live subscriptions.\n for (const handler of this.reserved.values()) {\n try {\n await handler.handleSocketClose?.(path, client);\n } catch (err) {\n await this.handleError(path, client, err);\n }\n }\n const entry = this.gateways.get(path);\n if (entry && hasHandleDisconnect(entry.instance)) {\n await entry.instance.handleDisconnect(client);\n }\n }\n\n async handleError(path: string, _client: WsClient, err: unknown): Promise<void> {\n // Connection-level and reserved-frame (`$…`) throws land here. Route them\n // through the shared reporter so a custom APP_EXCEPTION_HANDLER observes\n // them too — the default reporter console.errors and honors `'silent'`.\n // No client frame is sent for this path, by design: reserved frames own\n // their own client-facing responses, and there is no envelope id to reply to.\n resolveErrorReporter(this.container).report(err, {\n edge: 'ws',\n source: path ? `reserved-frame ${path}` : 'reserved-frame',\n });\n }\n\n async dispatchMessage(path: string, client: WsClient, raw: string | ArrayBuffer): Promise<void> {\n const entry = this.gateways.get(path);\n if (!entry) return;\n\n let message: WsMessage;\n try {\n message = this.parse(raw);\n } catch {\n this.trySend(client, 'exception', { message: 'Invalid message' });\n return;\n }\n\n // Reserved namespace: `$…` frames route to @ReservedWsEvent handlers\n // (after app-wide guards) and NEVER reach gateway handlers; an unclaimed\n // reserved event is dropped like any unknown event.\n if (message.event.startsWith(RESERVED_WS_EVENT_PREFIX)) {\n await this.dispatchReserved(path, client, message);\n return;\n }\n\n const handler = entry.handlers.get(message.event);\n if (!handler) return; // unknown event — ignored (NestJS parity)\n\n const ctx = buildWsExecutionContext(\n client,\n message.data,\n entry.gatewayClass,\n handler.methodName,\n message.event,\n );\n\n // App-wide global components (APP_* provider tokens + imperative\n // app.useGlobalX()) run first, then controller/handler-tier — mirroring the\n // HTTP HandlerExecutor so global guards/pipes/interceptors/filters protect\n // gateway messages too. Read live so late registrations propagate.\n const globals = this.routeManager?.getGlobalComponents();\n const guards = [\n ...instantiateMany<CanActivate>(globals?.guards ?? [], this.container),\n ...instantiateMany<CanActivate>(handler.guards, this.container),\n ];\n const pipes = [\n ...instantiateMany<PipeTransform>(globals?.pipes ?? [], this.container),\n ...instantiateMany<PipeTransform>(handler.pipes, this.container),\n ];\n const interceptors = [\n ...instantiateMany<NestInterceptor>(globals?.interceptors ?? [], this.container),\n ...instantiateMany<NestInterceptor>(handler.interceptors, this.container),\n ];\n // Handler/controller filters first (closest), then global filters last.\n const filters = [\n ...instantiateMany<ExceptionFilter>(handler.filters, this.container),\n ...instantiateMany<ExceptionFilter>(globals?.filters ?? [], this.container),\n ];\n\n try {\n const method = entry.instance[handler.methodName] as (...a: unknown[]) => unknown;\n\n // Guards → args + pipes → interceptor chain → handler, via the shared\n // runner (WS keeps guards-first, unlike HTTP's args-before-guards).\n const result = await PipelineRunner.run({\n context: ctx,\n guards,\n interceptors,\n resolveArgs: () =>\n resolveWsArgs(handler.paramMeta, client, message.data, pipes, handler.paramTypes),\n invoke: async (args) => method.apply(entry.instance, args),\n onGuardReject: () => new WsException('Forbidden'),\n });\n\n this.reply(client, message, result);\n } catch (error) {\n const reporter = resolveErrorReporter(this.container);\n const source = `${entry.gatewayClass.name}.${handler.methodName}`;\n // Report FIRST, always — before any exception filter can claim (and thus\n // hide) the error. Rendering is a separate concern (mirrors HandlerExecutor).\n reporter.report(error, { edge: 'ws', source });\n await this.runFilters(client, message, error, filters, ctx, reporter, source);\n }\n }\n\n /**\n * Route a reserved (`$…`) frame to its claiming handler. App-wide (`APP_*` /\n * `useGlobalGuards`) guards protect reserved frames exactly like gateway\n * messages — guards-first, WS convention; handler/class-tier components are\n * the claiming module's own concern (e.g. live resolvers run their scoped\n * guards at subscribe).\n */\n private async dispatchReserved(\n path: string,\n client: WsClient,\n message: WsMessage,\n ): Promise<void> {\n const handler = this.reserved.get(message.event);\n if (!handler) return;\n\n const ctx = buildWsExecutionContext(\n client,\n message.data,\n handler.constructor as Type,\n 'handleReservedEvent',\n message.event,\n );\n const globals = this.routeManager?.getGlobalComponents();\n const guards = instantiateMany<CanActivate>(globals?.guards ?? [], this.container);\n try {\n for (const guard of guards) {\n if (!(await guard.canActivate(ctx))) {\n const frame = toErrorFrame(\n new WsException('Forbidden'),\n resolveErrorReporter(this.container).catalog,\n );\n this.trySend(client, frame.event, frame.data, message.id);\n return;\n }\n }\n await handler.handleReservedEvent(path, client, message);\n } catch (err) {\n await this.handleError(path, client, err);\n }\n }\n\n private reply(client: WsClient, message: WsMessage, result: unknown): void {\n if (result === undefined || result === null) return;\n if (isWsResponse(result)) {\n this.trySend(client, result.event, result.data, message.id);\n } else {\n this.trySend(client, message.event, result, message.id);\n }\n }\n\n private async runFilters(\n client: WsClient,\n message: WsMessage,\n error: unknown,\n filters: ExceptionFilter[],\n ctx: WsExecutionContext,\n reporter: ErrorReporter,\n source: string,\n ): Promise<void> {\n for (const filter of filters) {\n if (shouldFilterCatch(filter, error)) {\n try {\n const handled = await filter.catch(error, ctx);\n if (isWsResponse(handled)) {\n this.trySend(client, handled.event, handled.data, message.id);\n }\n } catch (filterError) {\n // A throwing filter is itself a bug worth reporting — then fall back\n // to the default redacted frame (mirrors HandlerExecutor).\n reporter.report(filterError, { edge: 'ws', source, note: 'exception filter threw' });\n const frame = toErrorFrame(error, reporter.catalog);\n this.trySend(client, frame.event, frame.data, message.id);\n }\n return;\n }\n }\n const errorFrame = toErrorFrame(error, reporter.catalog);\n this.trySend(client, errorFrame.event, errorFrame.data, message.id);\n }\n\n // Outbound sends are best-effort: the socket may have closed mid-dispatch.\n private trySend(client: WsClient, event: string, data: unknown, id?: string): void {\n try {\n client.send(event, data, id);\n } catch {\n // socket closed — nothing to do\n }\n }\n\n private reportBootstrapError(name: string, err: unknown): void {\n const mode = this.container.getDiagnostics();\n if (mode === 'throw') throw err;\n if (mode === 'log') console.warn(`[vela] websocket gateway ${name} afterInit failed:`, err);\n }\n\n private parse(raw: string | ArrayBuffer): WsMessage {\n const text = typeof raw === 'string' ? raw : new TextDecoder().decode(raw);\n const parsed = JSON.parse(text) as WsMessage;\n if (!parsed || typeof parsed !== 'object' || typeof parsed.event !== 'string') {\n throw new Error('Invalid WebSocket message envelope');\n }\n return parsed;\n }\n\n private buildGatewayEntry(\n gatewayClass: Type,\n options: WebSocketGatewayOptions,\n instance: Record<string, unknown>,\n ): GatewayEntry {\n const ctor = gatewayClass as unknown as Constructor;\n const subs =\n (MetadataRegistry.getCustomClassMeta(ctor, WS_SUBSCRIBE_METADATA) as\n | SubscribeMessageMetadata[]\n | undefined) ?? [];\n const allParams = MetadataRegistry.getParameters(ctor);\n\n const handlers = new Map<string, HandlerEntry>();\n for (const { event, methodName } of subs) {\n // The `$` namespace belongs to framework modules (@ReservedWsEvent) — an\n // app gateway subscribing to it would never receive the frames anyway.\n if (event.startsWith(RESERVED_WS_EVENT_PREFIX)) {\n const msg =\n `[vela] @SubscribeMessage('${event}') on ${gatewayClass.name}: the ` +\n `'${RESERVED_WS_EVENT_PREFIX}' event prefix is reserved for framework modules — skipped.`;\n if (this.container.getDiagnostics() === 'throw') throw new Error(msg);\n console.warn(msg);\n continue;\n }\n const paramMeta = [...(allParams.get(methodName) ?? [])].sort((a, b) => a.index - b.index);\n const paramTypes = Reflect.getMetadata(\n 'design:paramtypes',\n gatewayClass.prototype,\n methodName,\n ) as unknown[] | undefined;\n\n handlers.set(event, {\n methodName,\n paramMeta,\n paramTypes,\n guards: ComponentManager.getScopedComponents('guard', ctor, methodName),\n pipes: ComponentManager.getScopedComponents('pipe', ctor, methodName),\n interceptors: ComponentManager.getScopedComponents('interceptor', ctor, methodName),\n // Handler → controller → global, so the closest filter runs first (mirrors HandlerExecutor).\n filters: [...ComponentManager.getScopedComponents('filter', ctor, methodName)].reverse(),\n });\n }\n\n return { path: options.path ?? '', instance, gatewayClass, handlers };\n }\n}\n","import type { SyncDriver } from './ws-sync';\nimport type { BroadcastCommand, BroadcastOperator, WsServer } from './websocket.types';\n\n/**\n * Accumulates `{ rooms, exceptRooms, exceptIds }` across a fluent chain and, on\n * `.emit()`, produces a serializable `BroadcastCommand` handed to the active\n * `SyncDriver`. The driver decides local-vs-remote delivery.\n */\nexport class BroadcastOperatorImpl implements BroadcastOperator {\n constructor(\n private readonly driver: SyncDriver,\n private readonly rooms = new Set<string>(),\n private readonly exceptRooms = new Set<string>(),\n private readonly exceptIds = new Set<string>(),\n ) {}\n\n to(room: string): this {\n this.rooms.add(room);\n return this;\n }\n\n in(room: string): this {\n return this.to(room);\n }\n\n except(room: string): this {\n this.exceptRooms.add(room);\n return this;\n }\n\n emit(event: string, data?: unknown): void | Promise<void> {\n const cmd: BroadcastCommand = {\n rooms: [...this.rooms],\n exceptRooms: this.exceptRooms.size ? [...this.exceptRooms] : undefined,\n exceptIds: this.exceptIds.size ? [...this.exceptIds] : undefined,\n frame: JSON.stringify({ event, data }),\n };\n return this.driver.dispatch(cmd);\n }\n}\n\n/**\n * The `@WebSocketServer()`-injected handle. Server-origin broadcasts never\n * pre-exclude anyone (a client-origin `client.to()` seeds `exceptIds` with the\n * sender — that lives in the transport's client, not here).\n */\nexport class WsServerImpl implements WsServer {\n constructor(private readonly driver: SyncDriver) {}\n\n emit(event: string, data?: unknown): void | Promise<void> {\n // Empty `rooms` means GLOBAL.\n return this.driver.dispatch({ rooms: [], frame: JSON.stringify({ event, data }) });\n }\n\n to(room: string): BroadcastOperator {\n return new BroadcastOperatorImpl(this.driver).to(room);\n }\n\n in(room: string): BroadcastOperator {\n return this.to(room);\n }\n\n except(room: string): BroadcastOperator {\n return new BroadcastOperatorImpl(this.driver).except(room);\n }\n}\n","import type { BroadcastCommand, WsClient } from './websocket.types';\n\n/**\n * Owns LOCAL room membership and local fan-out for the connections a single\n * node/isolate holds. The Cloudflare transport backs this with hibernation\n * tags + attachment; node/bun/deno back it with the in-memory implementation\n * below. Always edge-safe (no `node:*`).\n */\nexport interface RoomRegistry {\n /** Register a connection (called on connect) so global broadcasts can reach it. */\n register(client: WsClient): void;\n join(client: WsClient, room: string): void | Promise<void>;\n leave(client: WsClient, room: string): void | Promise<void>;\n /** Remove a connection and all its room memberships (called on disconnect). */\n leaveAll(client: WsClient): void | Promise<void>;\n /** Deliver a command to the sockets THIS node holds, applying every exclusion. */\n deliverLocal(cmd: BroadcastCommand): void | Promise<void>;\n localIdsInRoom(room: string): string[];\n}\n\n/**\n * Pluggable cross-instance transport for broadcast commands. `local()` is the\n * zero-config single-instance default; `durableObject()` (Cloudflare) and\n * `redis()` (node) are additive and chosen at the composition root.\n */\nexport interface SyncDriver {\n readonly kind: string;\n /** Wire the local registry so the driver can deliver to locally-held sockets. */\n bind(registry: RoomRegistry): void;\n /** Route a command so every node that may hold a matching socket delivers it. */\n dispatch(cmd: BroadcastCommand): void | Promise<void>;\n countRoom?(room: string): Promise<number>;\n start?(): void | Promise<void>;\n stop?(): void | Promise<void>;\n}\n\n/** Single-instance default: deliver straight to the local registry, no cross-node hop. */\nexport function local(): SyncDriver {\n let registry: RoomRegistry | undefined;\n return {\n kind: 'local',\n bind(r) {\n registry = r;\n },\n dispatch(cmd) {\n return registry?.deliverLocal(cmd);\n },\n };\n}\n\n/** In-memory `RoomRegistry` for node/bun/deno and tests. Edge-safe (plain Maps). */\nexport class InMemoryRoomRegistry implements RoomRegistry {\n private readonly rooms = new Map<string, Set<WsClient>>();\n private readonly clientRooms = new Map<string, Set<string>>();\n private readonly clients = new Map<string, WsClient>();\n\n register(client: WsClient): void {\n this.clients.set(client.id, client);\n }\n\n join(client: WsClient, room: string): void {\n this.register(client);\n let members = this.rooms.get(room);\n if (!members) {\n members = new Set();\n this.rooms.set(room, members);\n }\n members.add(client);\n\n let joined = this.clientRooms.get(client.id);\n if (!joined) {\n joined = new Set();\n this.clientRooms.set(client.id, joined);\n }\n joined.add(room);\n }\n\n leave(client: WsClient, room: string): void {\n const members = this.rooms.get(room);\n members?.delete(client);\n if (members && members.size === 0) this.rooms.delete(room);\n this.clientRooms.get(client.id)?.delete(room);\n }\n\n leaveAll(client: WsClient): void {\n for (const room of this.clientRooms.get(client.id) ?? []) {\n const members = this.rooms.get(room);\n members?.delete(client);\n if (members && members.size === 0) this.rooms.delete(room);\n }\n this.clientRooms.delete(client.id);\n this.clients.delete(client.id);\n }\n\n localIdsInRoom(room: string): string[] {\n return [...(this.rooms.get(room) ?? [])].map((c) => c.id);\n }\n\n deliverLocal(cmd: BroadcastCommand): void {\n const excludeIds = new Set(cmd.exceptIds ?? []);\n const excludeRooms = cmd.exceptRooms ?? [];\n\n // Empty `rooms` => GLOBAL: every registered connection. Otherwise the union\n // of the targeted rooms' members (deduped per connection).\n const candidates =\n cmd.rooms.length === 0\n ? new Set(this.clients.values())\n : (() => {\n const set = new Set<WsClient>();\n for (const room of cmd.rooms) {\n for (const client of this.rooms.get(room) ?? []) set.add(client);\n }\n return set;\n })();\n\n for (const client of candidates) {\n if (excludeIds.has(client.id)) continue;\n const joined = this.clientRooms.get(client.id);\n if (excludeRooms.some((room) => joined?.has(room))) continue;\n client.sendRaw(cmd.frame);\n }\n }\n}\n","import { defineModule } from '../module/define-module';\nimport { WsDispatcher } from './ws-dispatcher';\nimport { WsServerImpl } from './ws-server';\nimport { InMemoryRoomRegistry, local, type RoomRegistry, type SyncDriver } from './ws-sync';\nimport { WS_MODULE_OPTIONS, WS_ROOM_REGISTRY, WS_SERVER, WS_SYNC_DRIVER } from './websocket.tokens';\n\nexport interface WebSocketModuleOptions {\n /**\n * Cross-instance sync driver. Defaults to `local()` (single instance). Use\n * `durableObject()` from `@velajs/cloudflare` or `redis()` from\n * `@velajs/vela/websocket-node` for horizontal scale.\n */\n sync?: SyncDriver;\n /**\n * Local room registry the transport reads/writes. Defaults to the in-memory\n * implementation (node/bun/deno); the Cloudflare transport supplies its own.\n */\n registry?: RoomRegistry;\n}\n\n/**\n * Registers the WebSocket gateway machinery: the message dispatcher (discovers\n * `@WebSocketGateway` classes via DiscoveryService at bootstrap), the room\n * registry, the sync driver, and the `@WebSocketServer()`-injected server\n * handle.\n *\n * Construction lives in chained provider factories — registry → driver\n * (bound to THAT registry) → server — so the single shared registry instance\n * is preserved and everything materializes at bootstrap's eager\n * instantiation, before any lifecycle hook or message dispatch.\n *\n * The instance key derives from the sync driver kind: two `forRoot()` calls\n * with the same driver kind dedup (HMR-idempotent); pass an explicit `key`\n * to run multiple same-kind instances side by side.\n */\nconst { ConfigurableModuleClass } = defineModule<WebSocketModuleOptions>({\n name: 'WebSocket',\n optionsToken: WS_MODULE_OPTIONS,\n key: (options) => `ws#${options.sync?.kind ?? 'local'}`,\n setup: ({ OPTIONS }) => ({\n providers: [\n {\n provide: WS_ROOM_REGISTRY,\n useFactory: (o: WebSocketModuleOptions) => o.registry ?? new InMemoryRoomRegistry(),\n inject: [OPTIONS],\n },\n {\n provide: WS_SYNC_DRIVER,\n useFactory: (o: WebSocketModuleOptions, registry: RoomRegistry) => {\n const driver = o.sync ?? local();\n driver.bind(registry);\n return driver;\n },\n inject: [OPTIONS, WS_ROOM_REGISTRY],\n },\n {\n provide: WS_SERVER,\n useFactory: (driver: SyncDriver) => new WsServerImpl(driver),\n inject: [WS_SYNC_DRIVER],\n },\n WsDispatcher,\n ],\n exports: [WS_SERVER, WS_SYNC_DRIVER, WS_ROOM_REGISTRY, WsDispatcher],\n }),\n});\n\nexport class WebSocketModule extends ConfigurableModuleClass {}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,108 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { E as VelaApplication } from "../metadata.registry-D1od8ZBt.js";
|
|
2
|
+
import { In as RoomRegistry, Ln as SyncDriver, er as WsClient } from "../index-DhShDLCM.js";
|
|
3
|
+
import { W as LiveDriver } from "../index-D72EQfcC.js";
|
|
4
|
+
import { UpgradeWebSocket, WSContext } from "hono/ws";
|
|
5
|
+
//#region src/websocket-node/node-ws-client.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* Core `WsClient` over Hono's `WSContext` (node/bun/deno — no hibernation).
|
|
8
|
+
* Room membership is mirrored into the shared `RoomRegistry` so broadcasts from
|
|
9
|
+
* the `WsServer` reach this connection.
|
|
10
|
+
*/
|
|
11
|
+
declare class NodeWsClient<TData extends Record<string, unknown> = Record<string, unknown>> implements WsClient<TData> {
|
|
12
|
+
private readonly ws;
|
|
13
|
+
private readonly registry;
|
|
14
|
+
readonly path: string;
|
|
15
|
+
readonly id: string;
|
|
16
|
+
data: TData;
|
|
17
|
+
private readonly _rooms;
|
|
18
|
+
constructor(ws: WSContext, registry: RoomRegistry, path: string);
|
|
19
|
+
get rooms(): ReadonlySet<string>;
|
|
20
|
+
get raw(): unknown;
|
|
21
|
+
send(event: string, data?: unknown, id?: string): void;
|
|
22
|
+
sendRaw(payload: string): void;
|
|
23
|
+
join(room: string): void | Promise<void>;
|
|
24
|
+
leave(room: string): void | Promise<void>;
|
|
25
|
+
commit(): void;
|
|
26
|
+
close(code?: number, reason?: string): void;
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/websocket-node/register-gateways.d.ts
|
|
30
|
+
/**
|
|
31
|
+
* Registers every `@WebSocketGateway` on the app's Hono instance using the
|
|
32
|
+
* runtime's Hono `upgradeWebSocket` factory — the same call works on node
|
|
33
|
+
* (`@hono/node-ws` / `@hono/node-server` v2), Bun (`hono/bun`), and Deno
|
|
34
|
+
* (`hono/deno`). Each connection auto-joins the room from a `:id` route param
|
|
35
|
+
* (or the route path), mirroring the Cloudflare DO-per-room model.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* // Node
|
|
40
|
+
* const app = await VelaFactory.create(AppModule);
|
|
41
|
+
* const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: app.getHonoApp() });
|
|
42
|
+
* registerWebSocketGateways(app, upgradeWebSocket);
|
|
43
|
+
* const server = serve({ fetch: app.fetch, port: 3000 });
|
|
44
|
+
* injectWebSocket(server);
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare function registerWebSocketGateways(app: VelaApplication, upgradeWebSocket: UpgradeWebSocket): void;
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/websocket-node/redis-sync.d.ts
|
|
50
|
+
/**
|
|
51
|
+
* Minimal Redis pub/sub surface (satisfied by `ioredis` / `node-redis`). Pub and
|
|
52
|
+
* sub MUST be separate connections — a subscribed Redis connection cannot publish.
|
|
53
|
+
* `off`/`removeListener`/`unsubscribe` are optional and used only by `stop()`.
|
|
54
|
+
*/
|
|
55
|
+
interface RedisPubSubClient {
|
|
56
|
+
publish(channel: string, message: string): unknown;
|
|
57
|
+
subscribe(channel: string): unknown;
|
|
58
|
+
on(event: 'message', listener: (channel: string, message: string) => void): unknown;
|
|
59
|
+
off?(event: 'message', listener: (channel: string, message: string) => void): unknown;
|
|
60
|
+
removeListener?(event: 'message', listener: (channel: string, message: string) => void): unknown;
|
|
61
|
+
unsubscribe?(channel: string): unknown;
|
|
62
|
+
}
|
|
63
|
+
interface RedisSyncOptions {
|
|
64
|
+
/** Connection used to publish broadcast commands. */
|
|
65
|
+
pub: RedisPubSubClient;
|
|
66
|
+
/** Separate connection used to subscribe (kept in subscriber mode). */
|
|
67
|
+
sub: RedisPubSubClient;
|
|
68
|
+
/** Channel prefix. Default `vela:ws`. */
|
|
69
|
+
prefix?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Cross-instance sync driver for node/bun via Redis pub/sub. Local-first: every
|
|
73
|
+
* `dispatch` delivers to this instance's sockets immediately, then fans the
|
|
74
|
+
* command out to peers on a single broadcast channel; each peer's registry
|
|
75
|
+
* filters delivery to its own local room members. The publishing instance drops
|
|
76
|
+
* its own echo via an `origin` stamp.
|
|
77
|
+
*
|
|
78
|
+
* Guarantees: at-most-once, no ordering across publishers, no replay — a fan-out
|
|
79
|
+
* bus, not a log. Pass it to `WebSocketModule.forRoot({ sync: redis({ pub, sub }) })`.
|
|
80
|
+
*/
|
|
81
|
+
declare function redis(options: RedisSyncOptions): SyncDriver;
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/websocket-node/redis-live.d.ts
|
|
84
|
+
interface RedisLiveOptions {
|
|
85
|
+
/** Connection used to publish invalidations. */
|
|
86
|
+
pub: RedisPubSubClient;
|
|
87
|
+
/** Separate connection kept in subscriber mode. */
|
|
88
|
+
sub: RedisPubSubClient;
|
|
89
|
+
/** Channel prefix. Default `vela:live`. */
|
|
90
|
+
prefix?: string;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Cross-instance live-invalidation driver for node/bun via Redis pub/sub —
|
|
94
|
+
* the live sibling of the WebSocket `redis()` sync driver, carrying TAGS
|
|
95
|
+
* instead of frames. Local-first: `dispatch` applies to this instance's
|
|
96
|
+
* engine immediately (its log stamps the returned commit cursor), then fans
|
|
97
|
+
* the command out so every peer re-runs ITS local subscriptions.
|
|
98
|
+
*
|
|
99
|
+
* Guarantees (same honesty as `redis()`): at-most-once, no cross-publisher
|
|
100
|
+
* ordering, no replay. Each instance keeps its own per-process epoch, so a
|
|
101
|
+
* client reconnecting onto a different instance always receives a full
|
|
102
|
+
* snapshot — exactly the protocol's multi-instance-node rule. Real cursor
|
|
103
|
+
* resume needs a shared ordered log (the Cloudflare DO transport).
|
|
104
|
+
*/
|
|
105
|
+
declare function redisLive(options: RedisLiveOptions): LiveDriver;
|
|
106
|
+
//#endregion
|
|
107
|
+
export { NodeWsClient, type RedisLiveOptions, type RedisPubSubClient, type RedisSyncOptions, redis, redisLive, registerWebSocketGateways };
|
|
108
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,6 +1,228 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { x as WS_ROOM_REGISTRY } from "../websocket-DXmB-MWJ.js";
|
|
2
|
+
//#region src/websocket-node/node-ws-client.ts
|
|
3
|
+
/**
|
|
4
|
+
* Core `WsClient` over Hono's `WSContext` (node/bun/deno — no hibernation).
|
|
5
|
+
* Room membership is mirrored into the shared `RoomRegistry` so broadcasts from
|
|
6
|
+
* the `WsServer` reach this connection.
|
|
7
|
+
*/
|
|
8
|
+
var NodeWsClient = class {
|
|
9
|
+
ws;
|
|
10
|
+
registry;
|
|
11
|
+
path;
|
|
12
|
+
id = crypto.randomUUID();
|
|
13
|
+
data = {};
|
|
14
|
+
_rooms = /* @__PURE__ */ new Set();
|
|
15
|
+
constructor(ws, registry, path) {
|
|
16
|
+
this.ws = ws;
|
|
17
|
+
this.registry = registry;
|
|
18
|
+
this.path = path;
|
|
19
|
+
}
|
|
20
|
+
get rooms() {
|
|
21
|
+
return this._rooms;
|
|
22
|
+
}
|
|
23
|
+
get raw() {
|
|
24
|
+
return this.ws;
|
|
25
|
+
}
|
|
26
|
+
send(event, data, id) {
|
|
27
|
+
this.ws.send(JSON.stringify(id !== void 0 ? {
|
|
28
|
+
id,
|
|
29
|
+
event,
|
|
30
|
+
data
|
|
31
|
+
} : {
|
|
32
|
+
event,
|
|
33
|
+
data
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
sendRaw(payload) {
|
|
37
|
+
this.ws.send(payload);
|
|
38
|
+
}
|
|
39
|
+
join(room) {
|
|
40
|
+
this._rooms.add(room);
|
|
41
|
+
return this.registry.join(this, room);
|
|
42
|
+
}
|
|
43
|
+
leave(room) {
|
|
44
|
+
this._rooms.delete(room);
|
|
45
|
+
return this.registry.leave(this, room);
|
|
46
|
+
}
|
|
47
|
+
commit() {}
|
|
48
|
+
close(code, reason) {
|
|
49
|
+
this.ws.close(code, reason);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/websocket-node/register-gateways.ts
|
|
54
|
+
function toText(data) {
|
|
55
|
+
if (typeof data === "string") return data;
|
|
56
|
+
if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Registers every `@WebSocketGateway` on the app's Hono instance using the
|
|
60
|
+
* runtime's Hono `upgradeWebSocket` factory — the same call works on node
|
|
61
|
+
* (`@hono/node-ws` / `@hono/node-server` v2), Bun (`hono/bun`), and Deno
|
|
62
|
+
* (`hono/deno`). Each connection auto-joins the room from a `:id` route param
|
|
63
|
+
* (or the route path), mirroring the Cloudflare DO-per-room model.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* // Node
|
|
68
|
+
* const app = await VelaFactory.create(AppModule);
|
|
69
|
+
* const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: app.getHonoApp() });
|
|
70
|
+
* registerWebSocketGateways(app, upgradeWebSocket);
|
|
71
|
+
* const server = serve({ fetch: app.fetch, port: 3000 });
|
|
72
|
+
* injectWebSocket(server);
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
function registerWebSocketGateways(app, upgradeWebSocket) {
|
|
76
|
+
const hono = app.getHonoApp();
|
|
77
|
+
const registry = app.get(WS_ROOM_REGISTRY);
|
|
78
|
+
for (const { meta } of app.entrypoints.ofKind("websocket")) {
|
|
79
|
+
const { path, dispatcher } = meta;
|
|
80
|
+
hono.get(path, upgradeWebSocket((c) => {
|
|
81
|
+
const roomId = c.req.param("id") ?? path;
|
|
82
|
+
let client;
|
|
83
|
+
let ready = Promise.resolve();
|
|
84
|
+
const onSetupError = (err) => {
|
|
85
|
+
dispatcher.handleError(path, client, err);
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
onOpen: (_evt, ws) => {
|
|
89
|
+
client = new NodeWsClient(ws, registry, path);
|
|
90
|
+
registry.register(client);
|
|
91
|
+
ready = Promise.resolve(client.join(roomId)).then(() => dispatcher.handleOpen(path, client)).catch(onSetupError);
|
|
92
|
+
},
|
|
93
|
+
onMessage: (evt) => {
|
|
94
|
+
const text = toText(evt.data);
|
|
95
|
+
if (text === void 0) return;
|
|
96
|
+
ready.then(() => dispatcher.dispatchMessage(path, client, text)).catch(onSetupError);
|
|
97
|
+
},
|
|
98
|
+
onClose: (evt) => {
|
|
99
|
+
const code = evt.code || 1e3;
|
|
100
|
+
const reason = evt.reason || "";
|
|
101
|
+
Promise.resolve(dispatcher.handleClose(path, client, code, reason)).catch(onSetupError).finally(() => registry.leaveAll(client));
|
|
102
|
+
},
|
|
103
|
+
onError: (evt) => {
|
|
104
|
+
dispatcher.handleError(path, client, evt);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/websocket-node/redis-sync.ts
|
|
112
|
+
const swallow$1 = (op) => {
|
|
113
|
+
Promise.resolve(op).catch(() => {});
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Cross-instance sync driver for node/bun via Redis pub/sub. Local-first: every
|
|
117
|
+
* `dispatch` delivers to this instance's sockets immediately, then fans the
|
|
118
|
+
* command out to peers on a single broadcast channel; each peer's registry
|
|
119
|
+
* filters delivery to its own local room members. The publishing instance drops
|
|
120
|
+
* its own echo via an `origin` stamp.
|
|
121
|
+
*
|
|
122
|
+
* Guarantees: at-most-once, no ordering across publishers, no replay — a fan-out
|
|
123
|
+
* bus, not a log. Pass it to `WebSocketModule.forRoot({ sync: redis({ pub, sub }) })`.
|
|
124
|
+
*/
|
|
125
|
+
function redis(options) {
|
|
126
|
+
const channel = `${options.prefix ?? "vela:ws"}:broadcast`;
|
|
127
|
+
const origin = crypto.randomUUID();
|
|
128
|
+
let registry;
|
|
129
|
+
let bound = false;
|
|
130
|
+
const onMessage = (ch, message) => {
|
|
131
|
+
if (ch !== channel) return;
|
|
132
|
+
let cmd;
|
|
133
|
+
try {
|
|
134
|
+
cmd = JSON.parse(message);
|
|
135
|
+
} catch {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (cmd.origin === origin) return;
|
|
139
|
+
swallow$1(registry?.deliverLocal(cmd));
|
|
140
|
+
};
|
|
141
|
+
return {
|
|
142
|
+
kind: "redis",
|
|
143
|
+
bind(reg) {
|
|
144
|
+
registry = reg;
|
|
145
|
+
if (bound) return;
|
|
146
|
+
bound = true;
|
|
147
|
+
swallow$1(options.sub.subscribe(channel));
|
|
148
|
+
options.sub.on("message", onMessage);
|
|
149
|
+
},
|
|
150
|
+
dispatch(cmd) {
|
|
151
|
+
swallow$1(registry?.deliverLocal(cmd));
|
|
152
|
+
swallow$1(options.pub.publish(channel, JSON.stringify({
|
|
153
|
+
...cmd,
|
|
154
|
+
origin
|
|
155
|
+
})));
|
|
156
|
+
},
|
|
157
|
+
stop() {
|
|
158
|
+
if (!bound) return;
|
|
159
|
+
bound = false;
|
|
160
|
+
options.sub.off?.("message", onMessage);
|
|
161
|
+
options.sub.removeListener?.("message", onMessage);
|
|
162
|
+
swallow$1(options.sub.unsubscribe?.(channel));
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/websocket-node/redis-live.ts
|
|
168
|
+
const swallow = (op) => {
|
|
169
|
+
Promise.resolve(op).catch(() => {});
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Cross-instance live-invalidation driver for node/bun via Redis pub/sub —
|
|
173
|
+
* the live sibling of the WebSocket `redis()` sync driver, carrying TAGS
|
|
174
|
+
* instead of frames. Local-first: `dispatch` applies to this instance's
|
|
175
|
+
* engine immediately (its log stamps the returned commit cursor), then fans
|
|
176
|
+
* the command out so every peer re-runs ITS local subscriptions.
|
|
177
|
+
*
|
|
178
|
+
* Guarantees (same honesty as `redis()`): at-most-once, no cross-publisher
|
|
179
|
+
* ordering, no replay. Each instance keeps its own per-process epoch, so a
|
|
180
|
+
* client reconnecting onto a different instance always receives a full
|
|
181
|
+
* snapshot — exactly the protocol's multi-instance-node rule. Real cursor
|
|
182
|
+
* resume needs a shared ordered log (the Cloudflare DO transport).
|
|
183
|
+
*/
|
|
184
|
+
function redisLive(options) {
|
|
185
|
+
const channel = `${options.prefix ?? "vela:live"}:invalidate`;
|
|
186
|
+
const origin = crypto.randomUUID();
|
|
187
|
+
let sink;
|
|
188
|
+
let bound = false;
|
|
189
|
+
const onMessage = (ch, message) => {
|
|
190
|
+
if (ch !== channel) return;
|
|
191
|
+
let cmd;
|
|
192
|
+
try {
|
|
193
|
+
cmd = JSON.parse(message);
|
|
194
|
+
} catch {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (cmd.origin === origin) return;
|
|
198
|
+
if (sink) swallow(sink.applyInvalidation(cmd));
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
kind: "redis",
|
|
202
|
+
bind(boundSink) {
|
|
203
|
+
sink = boundSink;
|
|
204
|
+
if (bound) return;
|
|
205
|
+
bound = true;
|
|
206
|
+
swallow(options.sub.subscribe(channel));
|
|
207
|
+
options.sub.on("message", onMessage);
|
|
208
|
+
},
|
|
209
|
+
async dispatch(cmd) {
|
|
210
|
+
swallow(options.pub.publish(channel, JSON.stringify({
|
|
211
|
+
...cmd,
|
|
212
|
+
origin
|
|
213
|
+
})));
|
|
214
|
+
return sink?.applyInvalidation(cmd);
|
|
215
|
+
},
|
|
216
|
+
stop() {
|
|
217
|
+
if (!bound) return;
|
|
218
|
+
bound = false;
|
|
219
|
+
options.sub.off?.("message", onMessage);
|
|
220
|
+
options.sub.removeListener?.("message", onMessage);
|
|
221
|
+
swallow(options.sub.unsubscribe?.(channel));
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
//#endregion
|
|
226
|
+
export { NodeWsClient, redis, redisLive, registerWebSocketGateways };
|
|
227
|
+
|
|
228
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["swallow"],"sources":["../../src/websocket-node/node-ws-client.ts","../../src/websocket-node/register-gateways.ts","../../src/websocket-node/redis-sync.ts","../../src/websocket-node/redis-live.ts"],"sourcesContent":["import type { WSContext } from 'hono/ws';\nimport type { RoomRegistry, WsClient } from '../websocket/index';\n\n/**\n * Core `WsClient` over Hono's `WSContext` (node/bun/deno — no hibernation).\n * Room membership is mirrored into the shared `RoomRegistry` so broadcasts from\n * the `WsServer` reach this connection.\n */\nexport class NodeWsClient<\n TData extends Record<string, unknown> = Record<string, unknown>,\n> implements WsClient<TData> {\n readonly id: string = crypto.randomUUID();\n data: TData = {} as TData;\n private readonly _rooms = new Set<string>();\n\n constructor(\n private readonly ws: WSContext,\n private readonly registry: RoomRegistry,\n readonly path: string,\n ) {}\n\n get rooms(): ReadonlySet<string> {\n return this._rooms;\n }\n\n get raw(): unknown {\n return this.ws;\n }\n\n send(event: string, data?: unknown, id?: string): void {\n this.ws.send(JSON.stringify(id !== undefined ? { id, event, data } : { event, data }));\n }\n\n sendRaw(payload: string): void {\n this.ws.send(payload);\n }\n\n join(room: string): void | Promise<void> {\n this._rooms.add(room);\n return this.registry.join(this, room);\n }\n\n leave(room: string): void | Promise<void> {\n this._rooms.delete(room);\n return this.registry.leave(this, room);\n }\n\n // In-memory registry mutates eagerly; nothing deferred to persist.\n commit(): void {}\n\n close(code?: number, reason?: string): void {\n this.ws.close(code, reason);\n }\n}\n","import type { Context } from 'hono';\nimport type { UpgradeWebSocket, WSMessageReceive } from 'hono/ws';\nimport type { VelaApplication } from '../application';\nimport { WS_ROOM_REGISTRY } from '../websocket/index';\nimport type { RoomRegistry, WsEntrypointMeta } from '../websocket/index';\nimport { NodeWsClient } from './node-ws-client';\n\nfunction toText(data: WSMessageReceive): string | undefined {\n if (typeof data === 'string') return data;\n if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);\n // Blob / SharedArrayBuffer — binary is out of scope for the JSON envelope protocol.\n return undefined;\n}\n\n/**\n * Registers every `@WebSocketGateway` on the app's Hono instance using the\n * runtime's Hono `upgradeWebSocket` factory — the same call works on node\n * (`@hono/node-ws` / `@hono/node-server` v2), Bun (`hono/bun`), and Deno\n * (`hono/deno`). Each connection auto-joins the room from a `:id` route param\n * (or the route path), mirroring the Cloudflare DO-per-room model.\n *\n * @example\n * ```ts\n * // Node\n * const app = await VelaFactory.create(AppModule);\n * const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app: app.getHonoApp() });\n * registerWebSocketGateways(app, upgradeWebSocket);\n * const server = serve({ fetch: app.fetch, port: 3000 });\n * injectWebSocket(server);\n * ```\n */\nexport function registerWebSocketGateways(\n app: VelaApplication,\n upgradeWebSocket: UpgradeWebSocket,\n): void {\n const hono = app.getHonoApp();\n const registry = app.get(WS_ROOM_REGISTRY) as RoomRegistry;\n\n for (const { meta } of app.entrypoints.ofKind<WsEntrypointMeta>('websocket')) {\n const { path, dispatcher } = meta;\n hono.get(\n path,\n upgradeWebSocket((c: Context) => {\n const roomId = c.req.param('id') ?? path;\n let client: NodeWsClient;\n // Connection-setup barrier: messages queue behind join + handleConnection\n // so an auth check in handleConnection runs before any message dispatches.\n let ready: Promise<unknown> = Promise.resolve();\n const onSetupError = (err: unknown) => {\n void dispatcher.handleError(path, client, err);\n };\n return {\n onOpen: (_evt, ws) => {\n client = new NodeWsClient(ws, registry, path);\n registry.register(client);\n ready = Promise.resolve(client.join(roomId))\n .then(() => dispatcher.handleOpen(path, client))\n .catch(onSetupError);\n },\n onMessage: (evt) => {\n const text = toText(evt.data);\n if (text === undefined) return;\n void ready\n .then(() => dispatcher.dispatchMessage(path, client, text))\n .catch(onSetupError);\n },\n onClose: (evt) => {\n const code = (evt as CloseEvent).code || 1000;\n const reason = (evt as CloseEvent).reason || '';\n void Promise.resolve(dispatcher.handleClose(path, client, code, reason))\n .catch(onSetupError)\n .finally(() => registry.leaveAll(client));\n },\n onError: (evt) => {\n void dispatcher.handleError(path, client, evt);\n },\n };\n }),\n );\n }\n}\n","import type { BroadcastCommand, RoomRegistry, SyncDriver } from '../websocket/index';\n\n/**\n * Minimal Redis pub/sub surface (satisfied by `ioredis` / `node-redis`). Pub and\n * sub MUST be separate connections — a subscribed Redis connection cannot publish.\n * `off`/`removeListener`/`unsubscribe` are optional and used only by `stop()`.\n */\nexport interface RedisPubSubClient {\n publish(channel: string, message: string): unknown;\n subscribe(channel: string): unknown;\n on(event: 'message', listener: (channel: string, message: string) => void): unknown;\n off?(event: 'message', listener: (channel: string, message: string) => void): unknown;\n removeListener?(event: 'message', listener: (channel: string, message: string) => void): unknown;\n unsubscribe?(channel: string): unknown;\n}\n\nexport interface RedisSyncOptions {\n /** Connection used to publish broadcast commands. */\n pub: RedisPubSubClient;\n /** Separate connection used to subscribe (kept in subscriber mode). */\n sub: RedisPubSubClient;\n /** Channel prefix. Default `vela:ws`. */\n prefix?: string;\n}\n\nconst swallow = (op: unknown): void => {\n // Redis client calls return promises that reject on transport failure; a\n // fan-out miss must never become an unhandled rejection that crashes the app.\n void Promise.resolve(op).catch(() => {});\n};\n\n/**\n * Cross-instance sync driver for node/bun via Redis pub/sub. Local-first: every\n * `dispatch` delivers to this instance's sockets immediately, then fans the\n * command out to peers on a single broadcast channel; each peer's registry\n * filters delivery to its own local room members. The publishing instance drops\n * its own echo via an `origin` stamp.\n *\n * Guarantees: at-most-once, no ordering across publishers, no replay — a fan-out\n * bus, not a log. Pass it to `WebSocketModule.forRoot({ sync: redis({ pub, sub }) })`.\n */\nexport function redis(options: RedisSyncOptions): SyncDriver {\n const prefix = options.prefix ?? 'vela:ws';\n const channel = `${prefix}:broadcast`;\n const origin = crypto.randomUUID();\n let registry: RoomRegistry | undefined;\n let bound = false;\n\n const onMessage = (ch: string, message: string): void => {\n if (ch !== channel) return;\n let cmd: BroadcastCommand & { origin?: string };\n try {\n cmd = JSON.parse(message);\n } catch {\n return;\n }\n if (cmd.origin === origin) return; // our own publish — already delivered locally\n swallow(registry?.deliverLocal(cmd));\n };\n\n return {\n kind: 'redis',\n bind(reg) {\n registry = reg;\n if (bound) return; // idempotent — never stack duplicate 'message' listeners on re-bind\n bound = true;\n swallow(options.sub.subscribe(channel));\n options.sub.on('message', onMessage);\n },\n dispatch(cmd) {\n swallow(registry?.deliverLocal(cmd));\n swallow(options.pub.publish(channel, JSON.stringify({ ...cmd, origin })));\n },\n stop() {\n if (!bound) return;\n bound = false;\n options.sub.off?.('message', onMessage);\n options.sub.removeListener?.('message', onMessage);\n swallow(options.sub.unsubscribe?.(channel));\n },\n };\n}\n","import type {\n CommitStamp,\n InvalidationCommand,\n LiveDriver,\n LiveInvalidationSink,\n} from '../live/index';\nimport type { RedisPubSubClient } from './redis-sync';\n\nexport interface RedisLiveOptions {\n /** Connection used to publish invalidations. */\n pub: RedisPubSubClient;\n /** Separate connection kept in subscriber mode. */\n sub: RedisPubSubClient;\n /** Channel prefix. Default `vela:live`. */\n prefix?: string;\n}\n\nconst swallow = (op: unknown): void => {\n void Promise.resolve(op).catch(() => {});\n};\n\n/**\n * Cross-instance live-invalidation driver for node/bun via Redis pub/sub —\n * the live sibling of the WebSocket `redis()` sync driver, carrying TAGS\n * instead of frames. Local-first: `dispatch` applies to this instance's\n * engine immediately (its log stamps the returned commit cursor), then fans\n * the command out so every peer re-runs ITS local subscriptions.\n *\n * Guarantees (same honesty as `redis()`): at-most-once, no cross-publisher\n * ordering, no replay. Each instance keeps its own per-process epoch, so a\n * client reconnecting onto a different instance always receives a full\n * snapshot — exactly the protocol's multi-instance-node rule. Real cursor\n * resume needs a shared ordered log (the Cloudflare DO transport).\n */\nexport function redisLive(options: RedisLiveOptions): LiveDriver {\n const prefix = options.prefix ?? 'vela:live';\n const channel = `${prefix}:invalidate`;\n const origin = crypto.randomUUID();\n let sink: LiveInvalidationSink | undefined;\n let bound = false;\n\n const onMessage = (ch: string, message: string): void => {\n if (ch !== channel) return;\n let cmd: InvalidationCommand;\n try {\n cmd = JSON.parse(message) as InvalidationCommand;\n } catch {\n return;\n }\n if (cmd.origin === origin) return; // our own publish — already applied locally\n if (sink) swallow(sink.applyInvalidation(cmd));\n };\n\n return {\n kind: 'redis',\n bind(boundSink) {\n sink = boundSink;\n if (bound) return; // idempotent — never stack duplicate 'message' listeners\n bound = true;\n swallow(options.sub.subscribe(channel));\n options.sub.on('message', onMessage);\n },\n async dispatch(cmd): Promise<CommitStamp | undefined> {\n swallow(options.pub.publish(channel, JSON.stringify({ ...cmd, origin })));\n return sink?.applyInvalidation(cmd);\n },\n stop() {\n if (!bound) return;\n bound = false;\n options.sub.off?.('message', onMessage);\n options.sub.removeListener?.('message', onMessage);\n swallow(options.sub.unsubscribe?.(channel));\n },\n };\n}\n"],"mappings":"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"}
|