@zyno-io/ts-server-foundation 26.712.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/devconsole/assets/index-BlWLbczn.css +1 -0
- package/dist/devconsole/assets/index-lSF6DUY3.js +3 -0
- package/dist/devconsole/index.html +13 -0
- package/dist/src/app/base.d.ts +66 -0
- package/dist/src/app/base.d.ts.map +1 -0
- package/dist/src/app/base.js +577 -0
- package/dist/src/app/base.js.map +1 -0
- package/dist/src/app/commands.d.ts +20 -0
- package/dist/src/app/commands.d.ts.map +1 -0
- package/dist/src/app/commands.js +17 -0
- package/dist/src/app/commands.js.map +1 -0
- package/dist/src/app/config-loader.d.ts +9 -0
- package/dist/src/app/config-loader.d.ts.map +1 -0
- package/dist/src/app/config-loader.js +91 -0
- package/dist/src/app/config-loader.js.map +1 -0
- package/dist/src/app/config.d.ts +96 -0
- package/dist/src/app/config.d.ts.map +1 -0
- package/dist/src/app/config.js +114 -0
- package/dist/src/app/config.js.map +1 -0
- package/dist/src/app/const.d.ts +5 -0
- package/dist/src/app/const.d.ts.map +1 -0
- package/dist/src/app/const.js +17 -0
- package/dist/src/app/const.js.map +1 -0
- package/dist/src/app/current.d.ts +5 -0
- package/dist/src/app/current.d.ts.map +1 -0
- package/dist/src/app/current.js +14 -0
- package/dist/src/app/current.js.map +1 -0
- package/dist/src/app/index.d.ts +8 -0
- package/dist/src/app/index.d.ts.map +1 -0
- package/dist/src/app/index.js +13 -0
- package/dist/src/app/index.js.map +1 -0
- package/dist/src/app/lifecycle.d.ts +9 -0
- package/dist/src/app/lifecycle.d.ts.map +1 -0
- package/dist/src/app/lifecycle.js +21 -0
- package/dist/src/app/lifecycle.js.map +1 -0
- package/dist/src/app/migrations-entrypoint.d.ts +3 -0
- package/dist/src/app/migrations-entrypoint.d.ts.map +1 -0
- package/dist/src/app/migrations-entrypoint.js +35 -0
- package/dist/src/app/migrations-entrypoint.js.map +1 -0
- package/dist/src/app/resolver.d.ts +6 -0
- package/dist/src/app/resolver.d.ts.map +1 -0
- package/dist/src/app/resolver.js +15 -0
- package/dist/src/app/resolver.js.map +1 -0
- package/dist/src/auth/index.d.ts +3 -0
- package/dist/src/auth/index.d.ts.map +1 -0
- package/dist/src/auth/index.js +15 -0
- package/dist/src/auth/index.js.map +1 -0
- package/dist/src/auth/jwt.d.ts +61 -0
- package/dist/src/auth/jwt.d.ts.map +1 -0
- package/dist/src/auth/jwt.js +379 -0
- package/dist/src/auth/jwt.js.map +1 -0
- package/dist/src/auth/provider.d.ts +21 -0
- package/dist/src/auth/provider.d.ts.map +1 -0
- package/dist/src/auth/provider.js +148 -0
- package/dist/src/auth/provider.js.map +1 -0
- package/dist/src/cli/common.d.ts +13 -0
- package/dist/src/cli/common.d.ts.map +1 -0
- package/dist/src/cli/common.js +99 -0
- package/dist/src/cli/common.js.map +1 -0
- package/dist/src/cli/tsf-create-app.d.ts +3 -0
- package/dist/src/cli/tsf-create-app.d.ts.map +1 -0
- package/dist/src/cli/tsf-create-app.js +89 -0
- package/dist/src/cli/tsf-create-app.js.map +1 -0
- package/dist/src/cli/tsf-dev.d.ts +3 -0
- package/dist/src/cli/tsf-dev.d.ts.map +1 -0
- package/dist/src/cli/tsf-dev.js +753 -0
- package/dist/src/cli/tsf-dev.js.map +1 -0
- package/dist/src/cli/tsf-gen-proto.d.ts +3 -0
- package/dist/src/cli/tsf-gen-proto.d.ts.map +1 -0
- package/dist/src/cli/tsf-gen-proto.js +134 -0
- package/dist/src/cli/tsf-gen-proto.js.map +1 -0
- package/dist/src/cli/tsf-install.d.ts +8 -0
- package/dist/src/cli/tsf-install.d.ts.map +1 -0
- package/dist/src/cli/tsf-install.js +424 -0
- package/dist/src/cli/tsf-install.js.map +1 -0
- package/dist/src/cli/tsf-migrate.d.ts +3 -0
- package/dist/src/cli/tsf-migrate.d.ts.map +1 -0
- package/dist/src/cli/tsf-migrate.js +271 -0
- package/dist/src/cli/tsf-migrate.js.map +1 -0
- package/dist/src/cli/tsf-test.d.ts +4 -0
- package/dist/src/cli/tsf-test.d.ts.map +1 -0
- package/dist/src/cli/tsf-test.js +350 -0
- package/dist/src/cli/tsf-test.js.map +1 -0
- package/dist/src/cli/tsf-update.d.ts +3 -0
- package/dist/src/cli/tsf-update.d.ts.map +1 -0
- package/dist/src/cli/tsf-update.js +12 -0
- package/dist/src/cli/tsf-update.js.map +1 -0
- package/dist/src/cli/tsf.d.ts +3 -0
- package/dist/src/cli/tsf.d.ts.map +1 -0
- package/dist/src/cli/tsf.js +29 -0
- package/dist/src/cli/tsf.js.map +1 -0
- package/dist/src/database/database.d.ts +54 -0
- package/dist/src/database/database.d.ts.map +1 -0
- package/dist/src/database/database.js +695 -0
- package/dist/src/database/database.js.map +1 -0
- package/dist/src/database/driver.d.ts +28 -0
- package/dist/src/database/driver.d.ts.map +1 -0
- package/dist/src/database/driver.js +5 -0
- package/dist/src/database/driver.js.map +1 -0
- package/dist/src/database/drivers/index.d.ts +4 -0
- package/dist/src/database/drivers/index.d.ts.map +1 -0
- package/dist/src/database/drivers/index.js +9 -0
- package/dist/src/database/drivers/index.js.map +1 -0
- package/dist/src/database/drivers/mysql-session-rpc.d.ts +40 -0
- package/dist/src/database/drivers/mysql-session-rpc.d.ts.map +1 -0
- package/dist/src/database/drivers/mysql-session-rpc.js +180 -0
- package/dist/src/database/drivers/mysql-session-rpc.js.map +1 -0
- package/dist/src/database/drivers/mysql-session.d.ts +25 -0
- package/dist/src/database/drivers/mysql-session.d.ts.map +1 -0
- package/dist/src/database/drivers/mysql-session.js +124 -0
- package/dist/src/database/drivers/mysql-session.js.map +1 -0
- package/dist/src/database/drivers/mysql.d.ts +20 -0
- package/dist/src/database/drivers/mysql.d.ts.map +1 -0
- package/dist/src/database/drivers/mysql.js +84 -0
- package/dist/src/database/drivers/mysql.js.map +1 -0
- package/dist/src/database/drivers/postgres.d.ts +22 -0
- package/dist/src/database/drivers/postgres.d.ts.map +1 -0
- package/dist/src/database/drivers/postgres.js +80 -0
- package/dist/src/database/drivers/postgres.js.map +1 -0
- package/dist/src/database/entity.d.ts +112 -0
- package/dist/src/database/entity.d.ts.map +1 -0
- package/dist/src/database/entity.js +333 -0
- package/dist/src/database/entity.js.map +1 -0
- package/dist/src/database/errors.d.ts +7 -0
- package/dist/src/database/errors.d.ts.map +1 -0
- package/dist/src/database/errors.js +34 -0
- package/dist/src/database/errors.js.map +1 -0
- package/dist/src/database/factory.d.ts +48 -0
- package/dist/src/database/factory.d.ts.map +1 -0
- package/dist/src/database/factory.js +139 -0
- package/dist/src/database/factory.js.map +1 -0
- package/dist/src/database/identifiers.d.ts +8 -0
- package/dist/src/database/identifiers.d.ts.map +1 -0
- package/dist/src/database/identifiers.js +46 -0
- package/dist/src/database/identifiers.js.map +1 -0
- package/dist/src/database/index.d.ts +14 -0
- package/dist/src/database/index.d.ts.map +1 -0
- package/dist/src/database/index.js +33 -0
- package/dist/src/database/index.js.map +1 -0
- package/dist/src/database/metadata.d.ts +27 -0
- package/dist/src/database/metadata.d.ts.map +1 -0
- package/dist/src/database/metadata.js +70 -0
- package/dist/src/database/metadata.js.map +1 -0
- package/dist/src/database/migration/create/comparator.d.ts +3 -0
- package/dist/src/database/migration/create/comparator.d.ts.map +1 -0
- package/dist/src/database/migration/create/comparator.js +302 -0
- package/dist/src/database/migration/create/comparator.js.map +1 -0
- package/dist/src/database/migration/create/db-reader.d.ts +9 -0
- package/dist/src/database/migration/create/db-reader.d.ts.map +1 -0
- package/dist/src/database/migration/create/db-reader.js +478 -0
- package/dist/src/database/migration/create/db-reader.js.map +1 -0
- package/dist/src/database/migration/create/ddl-generator.d.ts +4 -0
- package/dist/src/database/migration/create/ddl-generator.d.ts.map +1 -0
- package/dist/src/database/migration/create/ddl-generator.js +431 -0
- package/dist/src/database/migration/create/ddl-generator.js.map +1 -0
- package/dist/src/database/migration/create/entity-reader.d.ts +7 -0
- package/dist/src/database/migration/create/entity-reader.d.ts.map +1 -0
- package/dist/src/database/migration/create/entity-reader.js +169 -0
- package/dist/src/database/migration/create/entity-reader.js.map +1 -0
- package/dist/src/database/migration/create/file-generator.d.ts +7 -0
- package/dist/src/database/migration/create/file-generator.d.ts.map +1 -0
- package/dist/src/database/migration/create/file-generator.js +60 -0
- package/dist/src/database/migration/create/file-generator.js.map +1 -0
- package/dist/src/database/migration/create/index.d.ts +19 -0
- package/dist/src/database/migration/create/index.d.ts.map +1 -0
- package/dist/src/database/migration/create/index.js +102 -0
- package/dist/src/database/migration/create/index.js.map +1 -0
- package/dist/src/database/migration/create/schema-model.d.ts +99 -0
- package/dist/src/database/migration/create/schema-model.d.ts.map +1 -0
- package/dist/src/database/migration/create/schema-model.js +24 -0
- package/dist/src/database/migration/create/schema-model.js.map +1 -0
- package/dist/src/database/migration/create/type-mapper.d.ts +13 -0
- package/dist/src/database/migration/create/type-mapper.d.ts.map +1 -0
- package/dist/src/database/migration/create/type-mapper.js +293 -0
- package/dist/src/database/migration/create/type-mapper.js.map +1 -0
- package/dist/src/database/migration/index.d.ts +33 -0
- package/dist/src/database/migration/index.d.ts.map +1 -0
- package/dist/src/database/migration/index.js +165 -0
- package/dist/src/database/migration/index.js.map +1 -0
- package/dist/src/database/migration/maintenance.d.ts +26 -0
- package/dist/src/database/migration/maintenance.d.ts.map +1 -0
- package/dist/src/database/migration/maintenance.js +65 -0
- package/dist/src/database/migration/maintenance.js.map +1 -0
- package/dist/src/database/query.d.ts +79 -0
- package/dist/src/database/query.d.ts.map +1 -0
- package/dist/src/database/query.js +435 -0
- package/dist/src/database/query.js.map +1 -0
- package/dist/src/database/schema.d.ts +147 -0
- package/dist/src/database/schema.d.ts.map +1 -0
- package/dist/src/database/schema.js +709 -0
- package/dist/src/database/schema.js.map +1 -0
- package/dist/src/database/session.d.ts +63 -0
- package/dist/src/database/session.d.ts.map +1 -0
- package/dist/src/database/session.js +226 -0
- package/dist/src/database/session.js.map +1 -0
- package/dist/src/database/sql.d.ts +37 -0
- package/dist/src/database/sql.d.ts.map +1 -0
- package/dist/src/database/sql.js +143 -0
- package/dist/src/database/sql.js.map +1 -0
- package/dist/src/database/values.d.ts +6 -0
- package/dist/src/database/values.d.ts.map +1 -0
- package/dist/src/database/values.js +237 -0
- package/dist/src/database/values.js.map +1 -0
- package/dist/src/devconsole/controller.d.ts +11 -0
- package/dist/src/devconsole/controller.d.ts.map +1 -0
- package/dist/src/devconsole/controller.js +78 -0
- package/dist/src/devconsole/controller.js.map +1 -0
- package/dist/src/devconsole/generated/devconsole.d.ts +306 -0
- package/dist/src/devconsole/generated/devconsole.d.ts.map +1 -0
- package/dist/src/devconsole/generated/devconsole.js +4029 -0
- package/dist/src/devconsole/generated/devconsole.js.map +1 -0
- package/dist/src/devconsole/index.d.ts +10 -0
- package/dist/src/devconsole/index.d.ts.map +1 -0
- package/dist/src/devconsole/index.js +26 -0
- package/dist/src/devconsole/index.js.map +1 -0
- package/dist/src/devconsole/observers.d.ts +4 -0
- package/dist/src/devconsole/observers.d.ts.map +1 -0
- package/dist/src/devconsole/observers.js +170 -0
- package/dist/src/devconsole/observers.js.map +1 -0
- package/dist/src/devconsole/runtime.d.ts +16 -0
- package/dist/src/devconsole/runtime.d.ts.map +1 -0
- package/dist/src/devconsole/runtime.js +48 -0
- package/dist/src/devconsole/runtime.js.map +1 -0
- package/dist/src/devconsole/security.d.ts +8 -0
- package/dist/src/devconsole/security.d.ts.map +1 -0
- package/dist/src/devconsole/security.js +33 -0
- package/dist/src/devconsole/security.js.map +1 -0
- package/dist/src/devconsole/server.d.ts +25 -0
- package/dist/src/devconsole/server.d.ts.map +1 -0
- package/dist/src/devconsole/server.js +452 -0
- package/dist/src/devconsole/server.js.map +1 -0
- package/dist/src/devconsole/store.d.ts +111 -0
- package/dist/src/devconsole/store.d.ts.map +1 -0
- package/dist/src/devconsole/store.js +177 -0
- package/dist/src/devconsole/store.js.map +1 -0
- package/dist/src/di/container.d.ts +38 -0
- package/dist/src/di/container.d.ts.map +1 -0
- package/dist/src/di/container.js +252 -0
- package/dist/src/di/container.js.map +1 -0
- package/dist/src/di/errors.d.ts +18 -0
- package/dist/src/di/errors.d.ts.map +1 -0
- package/dist/src/di/errors.js +71 -0
- package/dist/src/di/errors.js.map +1 -0
- package/dist/src/di/index.d.ts +5 -0
- package/dist/src/di/index.d.ts.map +1 -0
- package/dist/src/di/index.js +10 -0
- package/dist/src/di/index.js.map +1 -0
- package/dist/src/di/module.d.ts +29 -0
- package/dist/src/di/module.d.ts.map +1 -0
- package/dist/src/di/module.js +42 -0
- package/dist/src/di/module.js.map +1 -0
- package/dist/src/di/provider.d.ts +34 -0
- package/dist/src/di/provider.d.ts.map +1 -0
- package/dist/src/di/provider.js +24 -0
- package/dist/src/di/provider.js.map +1 -0
- package/dist/src/env.d.ts +122 -0
- package/dist/src/env.d.ts.map +1 -0
- package/dist/src/env.js +61 -0
- package/dist/src/env.js.map +1 -0
- package/dist/src/events/event-bus.d.ts +26 -0
- package/dist/src/events/event-bus.d.ts.map +1 -0
- package/dist/src/events/event-bus.js +67 -0
- package/dist/src/events/event-bus.js.map +1 -0
- package/dist/src/events/index.d.ts +2 -0
- package/dist/src/events/index.d.ts.map +1 -0
- package/dist/src/events/index.js +7 -0
- package/dist/src/events/index.js.map +1 -0
- package/dist/src/health/healthcheck.controller.d.ts +9 -0
- package/dist/src/health/healthcheck.controller.d.ts.map +1 -0
- package/dist/src/health/healthcheck.controller.js +33 -0
- package/dist/src/health/healthcheck.controller.js.map +1 -0
- package/dist/src/health/healthcheck.service.d.ts +13 -0
- package/dist/src/health/healthcheck.service.d.ts.map +1 -0
- package/dist/src/health/healthcheck.service.js +37 -0
- package/dist/src/health/healthcheck.service.js.map +1 -0
- package/dist/src/health/index.d.ts +3 -0
- package/dist/src/health/index.d.ts.map +1 -0
- package/dist/src/health/index.js +8 -0
- package/dist/src/health/index.js.map +1 -0
- package/dist/src/helpers/async/context.d.ts +10 -0
- package/dist/src/helpers/async/context.d.ts.map +1 -0
- package/dist/src/helpers/async/context.js +52 -0
- package/dist/src/helpers/async/context.js.map +1 -0
- package/dist/src/helpers/async/process.d.ts +16 -0
- package/dist/src/helpers/async/process.d.ts.map +1 -0
- package/dist/src/helpers/async/process.js +62 -0
- package/dist/src/helpers/async/process.js.map +1 -0
- package/dist/src/helpers/async/promise.d.ts +11 -0
- package/dist/src/helpers/async/promise.d.ts.map +1 -0
- package/dist/src/helpers/async/promise.js +32 -0
- package/dist/src/helpers/async/promise.js.map +1 -0
- package/dist/src/helpers/data/array.d.ts +5 -0
- package/dist/src/helpers/data/array.d.ts.map +1 -0
- package/dist/src/helpers/data/array.js +27 -0
- package/dist/src/helpers/data/array.js.map +1 -0
- package/dist/src/helpers/data/objects.d.ts +13 -0
- package/dist/src/helpers/data/objects.d.ts.map +1 -0
- package/dist/src/helpers/data/objects.js +55 -0
- package/dist/src/helpers/data/objects.js.map +1 -0
- package/dist/src/helpers/data/serialization.d.ts +5 -0
- package/dist/src/helpers/data/serialization.d.ts.map +1 -0
- package/dist/src/helpers/data/serialization.js +25 -0
- package/dist/src/helpers/data/serialization.js.map +1 -0
- package/dist/src/helpers/data/transformer.d.ts +13 -0
- package/dist/src/helpers/data/transformer.d.ts.map +1 -0
- package/dist/src/helpers/data/transformer.js +50 -0
- package/dist/src/helpers/data/transformer.js.map +1 -0
- package/dist/src/helpers/index.d.ts +19 -0
- package/dist/src/helpers/index.d.ts.map +1 -0
- package/dist/src/helpers/index.js +30 -0
- package/dist/src/helpers/index.js.map +1 -0
- package/dist/src/helpers/io/package.d.ts +10 -0
- package/dist/src/helpers/io/package.d.ts.map +1 -0
- package/dist/src/helpers/io/package.js +35 -0
- package/dist/src/helpers/io/package.js.map +1 -0
- package/dist/src/helpers/io/stream.d.ts +18 -0
- package/dist/src/helpers/io/stream.d.ts.map +1 -0
- package/dist/src/helpers/io/stream.js +131 -0
- package/dist/src/helpers/io/stream.js.map +1 -0
- package/dist/src/helpers/redis/broadcast.d.ts +15 -0
- package/dist/src/helpers/redis/broadcast.d.ts.map +1 -0
- package/dist/src/helpers/redis/broadcast.js +93 -0
- package/dist/src/helpers/redis/broadcast.js.map +1 -0
- package/dist/src/helpers/redis/cache.d.ts +20 -0
- package/dist/src/helpers/redis/cache.d.ts.map +1 -0
- package/dist/src/helpers/redis/cache.js +57 -0
- package/dist/src/helpers/redis/cache.js.map +1 -0
- package/dist/src/helpers/redis/mutex.d.ts +45 -0
- package/dist/src/helpers/redis/mutex.d.ts.map +1 -0
- package/dist/src/helpers/redis/mutex.js +446 -0
- package/dist/src/helpers/redis/mutex.js.map +1 -0
- package/dist/src/helpers/redis/redis.d.ts +12 -0
- package/dist/src/helpers/redis/redis.d.ts.map +1 -0
- package/dist/src/helpers/redis/redis.js +62 -0
- package/dist/src/helpers/redis/redis.js.map +1 -0
- package/dist/src/helpers/security/crypto.d.ts +31 -0
- package/dist/src/helpers/security/crypto.d.ts.map +1 -0
- package/dist/src/helpers/security/crypto.js +108 -0
- package/dist/src/helpers/security/crypto.js.map +1 -0
- package/dist/src/helpers/security/validation.d.ts +3 -0
- package/dist/src/helpers/security/validation.d.ts.map +1 -0
- package/dist/src/helpers/security/validation.js +14 -0
- package/dist/src/helpers/security/validation.js.map +1 -0
- package/dist/src/helpers/utils/date.d.ts +4 -0
- package/dist/src/helpers/utils/date.d.ts.map +1 -0
- package/dist/src/helpers/utils/date.js +16 -0
- package/dist/src/helpers/utils/date.js.map +1 -0
- package/dist/src/helpers/utils/error.d.ts +20 -0
- package/dist/src/helpers/utils/error.d.ts.map +1 -0
- package/dist/src/helpers/utils/error.js +164 -0
- package/dist/src/helpers/utils/error.js.map +1 -0
- package/dist/src/helpers/utils/uuid.d.ts +5 -0
- package/dist/src/helpers/utils/uuid.d.ts.map +1 -0
- package/dist/src/helpers/utils/uuid.js +13 -0
- package/dist/src/helpers/utils/uuid.js.map +1 -0
- package/dist/src/http/auth.d.ts +20 -0
- package/dist/src/http/auth.d.ts.map +1 -0
- package/dist/src/http/auth.js +68 -0
- package/dist/src/http/auth.js.map +1 -0
- package/dist/src/http/base.d.ts +57 -0
- package/dist/src/http/base.d.ts.map +1 -0
- package/dist/src/http/base.js +331 -0
- package/dist/src/http/base.js.map +1 -0
- package/dist/src/http/context.d.ts +6 -0
- package/dist/src/http/context.d.ts.map +1 -0
- package/dist/src/http/context.js +26 -0
- package/dist/src/http/context.js.map +1 -0
- package/dist/src/http/cors.d.ts +25 -0
- package/dist/src/http/cors.d.ts.map +1 -0
- package/dist/src/http/cors.js +124 -0
- package/dist/src/http/cors.js.map +1 -0
- package/dist/src/http/decorators.d.ts +64 -0
- package/dist/src/http/decorators.d.ts.map +1 -0
- package/dist/src/http/decorators.js +102 -0
- package/dist/src/http/decorators.js.map +1 -0
- package/dist/src/http/errors.d.ts +50 -0
- package/dist/src/http/errors.d.ts.map +1 -0
- package/dist/src/http/errors.js +158 -0
- package/dist/src/http/errors.js.map +1 -0
- package/dist/src/http/index.d.ts +31 -0
- package/dist/src/http/index.d.ts.map +1 -0
- package/dist/src/http/index.js +33 -0
- package/dist/src/http/index.js.map +1 -0
- package/dist/src/http/middleware.d.ts +12 -0
- package/dist/src/http/middleware.d.ts.map +1 -0
- package/dist/src/http/middleware.js +31 -0
- package/dist/src/http/middleware.js.map +1 -0
- package/dist/src/http/parameter-resolvers.d.ts +3 -0
- package/dist/src/http/parameter-resolvers.d.ts.map +1 -0
- package/dist/src/http/parameter-resolvers.js +8 -0
- package/dist/src/http/parameter-resolvers.js.map +1 -0
- package/dist/src/http/request-logging.d.ts +34 -0
- package/dist/src/http/request-logging.d.ts.map +1 -0
- package/dist/src/http/request-logging.js +130 -0
- package/dist/src/http/request-logging.js.map +1 -0
- package/dist/src/http/request.d.ts +69 -0
- package/dist/src/http/request.d.ts.map +1 -0
- package/dist/src/http/request.js +366 -0
- package/dist/src/http/request.js.map +1 -0
- package/dist/src/http/response.d.ts +98 -0
- package/dist/src/http/response.d.ts.map +1 -0
- package/dist/src/http/response.js +292 -0
- package/dist/src/http/response.js.map +1 -0
- package/dist/src/http/router.d.ts +100 -0
- package/dist/src/http/router.d.ts.map +1 -0
- package/dist/src/http/router.js +1085 -0
- package/dist/src/http/router.js.map +1 -0
- package/dist/src/http/startup-logging.d.ts +8 -0
- package/dist/src/http/startup-logging.d.ts.map +1 -0
- package/dist/src/http/startup-logging.js +55 -0
- package/dist/src/http/startup-logging.js.map +1 -0
- package/dist/src/http/static-files.d.ts +15 -0
- package/dist/src/http/static-files.d.ts.map +1 -0
- package/dist/src/http/static-files.js +110 -0
- package/dist/src/http/static-files.js.map +1 -0
- package/dist/src/http/store.d.ts +8 -0
- package/dist/src/http/store.d.ts.map +1 -0
- package/dist/src/http/store.js +47 -0
- package/dist/src/http/store.js.map +1 -0
- package/dist/src/http/types.d.ts +23 -0
- package/dist/src/http/types.d.ts.map +1 -0
- package/dist/src/http/types.js +3 -0
- package/dist/src/http/types.js.map +1 -0
- package/dist/src/http/upgrade.d.ts +22 -0
- package/dist/src/http/upgrade.d.ts.map +1 -0
- package/dist/src/http/upgrade.js +164 -0
- package/dist/src/http/upgrade.js.map +1 -0
- package/dist/src/http/uploads.d.ts +36 -0
- package/dist/src/http/uploads.d.ts.map +1 -0
- package/dist/src/http/uploads.js +287 -0
- package/dist/src/http/uploads.js.map +1 -0
- package/dist/src/http/workflow.d.ts +34 -0
- package/dist/src/http/workflow.d.ts.map +1 -0
- package/dist/src/http/workflow.js +40 -0
- package/dist/src/http/workflow.js.map +1 -0
- package/dist/src/index.d.ts +21 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +88 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/openapi/controller.d.ts +9 -0
- package/dist/src/openapi/controller.d.ts.map +1 -0
- package/dist/src/openapi/controller.js +45 -0
- package/dist/src/openapi/controller.js.map +1 -0
- package/dist/src/openapi/index.d.ts +5 -0
- package/dist/src/openapi/index.d.ts.map +1 -0
- package/dist/src/openapi/index.js +21 -0
- package/dist/src/openapi/index.js.map +1 -0
- package/dist/src/openapi/schema.d.ts +26 -0
- package/dist/src/openapi/schema.d.ts.map +1 -0
- package/dist/src/openapi/schema.js +1128 -0
- package/dist/src/openapi/schema.js.map +1 -0
- package/dist/src/openapi/serializer.d.ts +16 -0
- package/dist/src/openapi/serializer.d.ts.map +1 -0
- package/dist/src/openapi/serializer.js +506 -0
- package/dist/src/openapi/serializer.js.map +1 -0
- package/dist/src/openapi/types.d.ts +84 -0
- package/dist/src/openapi/types.d.ts.map +1 -0
- package/dist/src/openapi/types.js +5 -0
- package/dist/src/openapi/types.js.map +1 -0
- package/dist/src/reflection/annotations.d.ts +15 -0
- package/dist/src/reflection/annotations.d.ts.map +1 -0
- package/dist/src/reflection/annotations.js +228 -0
- package/dist/src/reflection/annotations.js.map +1 -0
- package/dist/src/reflection/conversion.d.ts +15 -0
- package/dist/src/reflection/conversion.d.ts.map +1 -0
- package/dist/src/reflection/conversion.js +360 -0
- package/dist/src/reflection/conversion.js.map +1 -0
- package/dist/src/reflection/deserializer.d.ts +15 -0
- package/dist/src/reflection/deserializer.d.ts.map +1 -0
- package/dist/src/reflection/deserializer.js +42 -0
- package/dist/src/reflection/deserializer.js.map +1 -0
- package/dist/src/reflection/entity.d.ts +9 -0
- package/dist/src/reflection/entity.d.ts.map +1 -0
- package/dist/src/reflection/entity.js +74 -0
- package/dist/src/reflection/entity.js.map +1 -0
- package/dist/src/reflection/errors.d.ts +8 -0
- package/dist/src/reflection/errors.d.ts.map +1 -0
- package/dist/src/reflection/errors.js +21 -0
- package/dist/src/reflection/errors.js.map +1 -0
- package/dist/src/reflection/index.d.ts +8 -0
- package/dist/src/reflection/index.d.ts.map +1 -0
- package/dist/src/reflection/index.js +13 -0
- package/dist/src/reflection/index.js.map +1 -0
- package/dist/src/reflection/metadata-store.d.ts +14 -0
- package/dist/src/reflection/metadata-store.d.ts.map +1 -0
- package/dist/src/reflection/metadata-store.js +18 -0
- package/dist/src/reflection/metadata-store.js.map +1 -0
- package/dist/src/reflection/model.d.ts +271 -0
- package/dist/src/reflection/model.d.ts.map +1 -0
- package/dist/src/reflection/model.js +36 -0
- package/dist/src/reflection/model.js.map +1 -0
- package/dist/src/reflection/reflection-class.d.ts +60 -0
- package/dist/src/reflection/reflection-class.d.ts.map +1 -0
- package/dist/src/reflection/reflection-class.js +263 -0
- package/dist/src/reflection/reflection-class.js.map +1 -0
- package/dist/src/reflection/type-utils.d.ts +34 -0
- package/dist/src/reflection/type-utils.d.ts.map +1 -0
- package/dist/src/reflection/type-utils.js +485 -0
- package/dist/src/reflection/type-utils.js.map +1 -0
- package/dist/src/reflection.d.ts +2 -0
- package/dist/src/reflection.d.ts.map +1 -0
- package/dist/src/reflection.js +5 -0
- package/dist/src/reflection.js.map +1 -0
- package/dist/src/services/cli.d.ts +9 -0
- package/dist/src/services/cli.d.ts.map +1 -0
- package/dist/src/services/cli.js +47 -0
- package/dist/src/services/cli.js.map +1 -0
- package/dist/src/services/index.d.ts +8 -0
- package/dist/src/services/index.d.ts.map +1 -0
- package/dist/src/services/index.js +13 -0
- package/dist/src/services/index.js.map +1 -0
- package/dist/src/services/leader.d.ts +31 -0
- package/dist/src/services/leader.d.ts.map +1 -0
- package/dist/src/services/leader.js +176 -0
- package/dist/src/services/leader.js.map +1 -0
- package/dist/src/services/logger.d.ts +60 -0
- package/dist/src/services/logger.d.ts.map +1 -0
- package/dist/src/services/logger.js +349 -0
- package/dist/src/services/logger.js.map +1 -0
- package/dist/src/services/mail/index.d.ts +57 -0
- package/dist/src/services/mail/index.d.ts.map +1 -0
- package/dist/src/services/mail/index.js +89 -0
- package/dist/src/services/mail/index.js.map +1 -0
- package/dist/src/services/mail/postmark.d.ts +11 -0
- package/dist/src/services/mail/postmark.d.ts.map +1 -0
- package/dist/src/services/mail/postmark.js +41 -0
- package/dist/src/services/mail/postmark.js.map +1 -0
- package/dist/src/services/mail/smtp.d.ts +11 -0
- package/dist/src/services/mail/smtp.d.ts.map +1 -0
- package/dist/src/services/mail/smtp.js +50 -0
- package/dist/src/services/mail/smtp.js.map +1 -0
- package/dist/src/services/mesh-client/index.d.ts +9 -0
- package/dist/src/services/mesh-client/index.d.ts.map +1 -0
- package/dist/src/services/mesh-client/index.js +18 -0
- package/dist/src/services/mesh-client/index.js.map +1 -0
- package/dist/src/services/mesh-client/mesh-client-redis-registry.d.ts +23 -0
- package/dist/src/services/mesh-client/mesh-client-redis-registry.d.ts.map +1 -0
- package/dist/src/services/mesh-client/mesh-client-redis-registry.js +360 -0
- package/dist/src/services/mesh-client/mesh-client-redis-registry.js.map +1 -0
- package/dist/src/services/mesh-client/mesh-client-registry.d.ts +16 -0
- package/dist/src/services/mesh-client/mesh-client-registry.d.ts.map +1 -0
- package/dist/src/services/mesh-client/mesh-client-registry.js +44 -0
- package/dist/src/services/mesh-client/mesh-client-registry.js.map +1 -0
- package/dist/src/services/mesh-client/mesh-client-service.d.ts +88 -0
- package/dist/src/services/mesh-client/mesh-client-service.d.ts.map +1 -0
- package/dist/src/services/mesh-client/mesh-client-service.js +222 -0
- package/dist/src/services/mesh-client/mesh-client-service.js.map +1 -0
- package/dist/src/services/mesh-client/mesh-srpc-server.d.ts +95 -0
- package/dist/src/services/mesh-client/mesh-srpc-server.d.ts.map +1 -0
- package/dist/src/services/mesh-client/mesh-srpc-server.js +475 -0
- package/dist/src/services/mesh-client/mesh-srpc-server.js.map +1 -0
- package/dist/src/services/mesh-client/types.d.ts +36 -0
- package/dist/src/services/mesh-client/types.d.ts.map +1 -0
- package/dist/src/services/mesh-client/types.js +38 -0
- package/dist/src/services/mesh-client/types.js.map +1 -0
- package/dist/src/services/mesh.d.ts +73 -0
- package/dist/src/services/mesh.d.ts.map +1 -0
- package/dist/src/services/mesh.js +511 -0
- package/dist/src/services/mesh.js.map +1 -0
- package/dist/src/services/worker/entity.d.ts +26 -0
- package/dist/src/services/worker/entity.d.ts.map +1 -0
- package/dist/src/services/worker/entity.js +30 -0
- package/dist/src/services/worker/entity.js.map +1 -0
- package/dist/src/services/worker/index.d.ts +25 -0
- package/dist/src/services/worker/index.d.ts.map +1 -0
- package/dist/src/services/worker/index.js +52 -0
- package/dist/src/services/worker/index.js.map +1 -0
- package/dist/src/services/worker/observer.d.ts +13 -0
- package/dist/src/services/worker/observer.d.ts.map +1 -0
- package/dist/src/services/worker/observer.js +22 -0
- package/dist/src/services/worker/observer.js.map +1 -0
- package/dist/src/services/worker/queue.d.ts +38 -0
- package/dist/src/services/worker/queue.d.ts.map +1 -0
- package/dist/src/services/worker/queue.js +227 -0
- package/dist/src/services/worker/queue.js.map +1 -0
- package/dist/src/services/worker/recorder.d.ts +17 -0
- package/dist/src/services/worker/recorder.d.ts.map +1 -0
- package/dist/src/services/worker/recorder.js +88 -0
- package/dist/src/services/worker/recorder.js.map +1 -0
- package/dist/src/services/worker/runner.d.ts +37 -0
- package/dist/src/services/worker/runner.d.ts.map +1 -0
- package/dist/src/services/worker/runner.js +319 -0
- package/dist/src/services/worker/runner.js.map +1 -0
- package/dist/src/services/worker/types.d.ts +63 -0
- package/dist/src/services/worker/types.d.ts.map +1 -0
- package/dist/src/services/worker/types.js +38 -0
- package/dist/src/services/worker/types.js.map +1 -0
- package/dist/src/srpc/SrpcByteStream.d.ts +60 -0
- package/dist/src/srpc/SrpcByteStream.d.ts.map +1 -0
- package/dist/src/srpc/SrpcByteStream.js +237 -0
- package/dist/src/srpc/SrpcByteStream.js.map +1 -0
- package/dist/src/srpc/SrpcClient.d.ts +67 -0
- package/dist/src/srpc/SrpcClient.d.ts.map +1 -0
- package/dist/src/srpc/SrpcClient.js +406 -0
- package/dist/src/srpc/SrpcClient.js.map +1 -0
- package/dist/src/srpc/SrpcServer.d.ts +56 -0
- package/dist/src/srpc/SrpcServer.d.ts.map +1 -0
- package/dist/src/srpc/SrpcServer.js +519 -0
- package/dist/src/srpc/SrpcServer.js.map +1 -0
- package/dist/src/srpc/index.d.ts +9 -0
- package/dist/src/srpc/index.d.ts.map +1 -0
- package/dist/src/srpc/index.js +17 -0
- package/dist/src/srpc/index.js.map +1 -0
- package/dist/src/srpc/observer.d.ts +21 -0
- package/dist/src/srpc/observer.d.ts.map +1 -0
- package/dist/src/srpc/observer.js +22 -0
- package/dist/src/srpc/observer.js.map +1 -0
- package/dist/src/srpc/types.d.ts +92 -0
- package/dist/src/srpc/types.d.ts.map +1 -0
- package/dist/src/srpc/types.js +28 -0
- package/dist/src/srpc/types.js.map +1 -0
- package/dist/src/telemetry/index.d.ts +3 -0
- package/dist/src/telemetry/index.d.ts.map +1 -0
- package/dist/src/telemetry/index.js +22 -0
- package/dist/src/telemetry/index.js.map +1 -0
- package/dist/src/telemetry/otel/helpers.d.ts +45 -0
- package/dist/src/telemetry/otel/helpers.d.ts.map +1 -0
- package/dist/src/telemetry/otel/helpers.js +142 -0
- package/dist/src/telemetry/otel/helpers.js.map +1 -0
- package/dist/src/telemetry/otel/index.d.ts +22 -0
- package/dist/src/telemetry/otel/index.d.ts.map +1 -0
- package/dist/src/telemetry/otel/index.js +268 -0
- package/dist/src/telemetry/otel/index.js.map +1 -0
- package/dist/src/telemetry/otel/metrics.controller.d.ts +5 -0
- package/dist/src/telemetry/otel/metrics.controller.d.ts.map +1 -0
- package/dist/src/telemetry/otel/metrics.controller.js +82 -0
- package/dist/src/telemetry/otel/metrics.controller.js.map +1 -0
- package/dist/src/telemetry/otel/metrics.d.ts +2 -0
- package/dist/src/telemetry/otel/metrics.d.ts.map +1 -0
- package/dist/src/telemetry/otel/metrics.js +16 -0
- package/dist/src/telemetry/otel/metrics.js.map +1 -0
- package/dist/src/telemetry/sentry.d.ts +9 -0
- package/dist/src/telemetry/sentry.d.ts.map +1 -0
- package/dist/src/telemetry/sentry.js +63 -0
- package/dist/src/telemetry/sentry.js.map +1 -0
- package/dist/src/testing/database-readiness.d.ts +11 -0
- package/dist/src/testing/database-readiness.d.ts.map +1 -0
- package/dist/src/testing/database-readiness.js +102 -0
- package/dist/src/testing/database-readiness.js.map +1 -0
- package/dist/src/testing/expect.d.ts +21 -0
- package/dist/src/testing/expect.d.ts.map +1 -0
- package/dist/src/testing/expect.js +110 -0
- package/dist/src/testing/expect.js.map +1 -0
- package/dist/src/testing/fixtures.d.ts +18 -0
- package/dist/src/testing/fixtures.d.ts.map +1 -0
- package/dist/src/testing/fixtures.js +46 -0
- package/dist/src/testing/fixtures.js.map +1 -0
- package/dist/src/testing/index.d.ts +143 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +993 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/testing/mysql-session-manager-process.d.ts +3 -0
- package/dist/src/testing/mysql-session-manager-process.d.ts.map +1 -0
- package/dist/src/testing/mysql-session-manager-process.js +77 -0
- package/dist/src/testing/mysql-session-manager-process.js.map +1 -0
- package/dist/src/testing/mysql-session-manager.d.ts +59 -0
- package/dist/src/testing/mysql-session-manager.d.ts.map +1 -0
- package/dist/src/testing/mysql-session-manager.js +910 -0
- package/dist/src/testing/mysql-session-manager.js.map +1 -0
- package/dist/src/testing/sql.d.ts +47 -0
- package/dist/src/testing/sql.d.ts.map +1 -0
- package/dist/src/testing/sql.js +313 -0
- package/dist/src/testing/sql.js.map +1 -0
- package/dist/src/type-compiler/go/ast_expression.go +161 -0
- package/dist/src/type-compiler/go/ast_metadata.go +355 -0
- package/dist/src/type-compiler/go/collect.go +806 -0
- package/dist/src/type-compiler/go/emission_plan.go +205 -0
- package/dist/src/type-compiler/go/emit_ast.go +406 -0
- package/dist/src/type-compiler/go/emit_ast_test.go +248 -0
- package/dist/src/type-compiler/go/go.mod +10 -0
- package/dist/src/type-compiler/go/plugin.go +308 -0
- package/dist/src/type-compiler/go/plugin_test.go +752 -0
- package/dist/src/type-compiler/go/precompute.go +86 -0
- package/dist/src/type-compiler/go/receive_type.go +837 -0
- package/dist/src/type-compiler/go/resolve.go +265 -0
- package/dist/src/type-compiler/go/source_scan.go +51 -0
- package/dist/src/type-compiler/go/text_parse.go +671 -0
- package/dist/src/type-compiler/go/type_expr.go +1227 -0
- package/dist/src/type-compiler/go/typia_expr.go +2119 -0
- package/dist/src/type-compiler/index.cjs +6 -0
- package/dist/src/types/index.d.ts +7 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +14 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/types/phone.d.ts +6 -0
- package/dist/src/types/phone.d.ts.map +1 -0
- package/dist/src/types/phone.js +64 -0
- package/dist/src/types/phone.js.map +1 -0
- package/dist/src/types/primitives.d.ts +33 -0
- package/dist/src/types/primitives.d.ts.map +1 -0
- package/dist/src/types/primitives.js +5 -0
- package/dist/src/types/primitives.js.map +1 -0
- package/dist/src/types/runtime.d.ts +5 -0
- package/dist/src/types/runtime.d.ts.map +1 -0
- package/dist/src/types/runtime.js +20 -0
- package/dist/src/types/runtime.js.map +1 -0
- package/dist/src/types/type-annotations.d.ts +28 -0
- package/dist/src/types/type-annotations.d.ts.map +1 -0
- package/dist/src/types/type-annotations.js +33 -0
- package/dist/src/types/type-annotations.js.map +1 -0
- package/dist/src/types.d.ts +2 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +7 -0
- package/dist/src/types.js.map +1 -0
- package/docs/.vitepress/config.mts +85 -0
- package/docs/content/CONTRIBUTING.md +53 -0
- package/docs/content/README-DEV.md +59 -0
- package/docs/content/README.md +52 -0
- package/docs/content/authentication.md +213 -0
- package/docs/content/cli.md +214 -0
- package/docs/content/configuration.md +191 -0
- package/docs/content/database.md +476 -0
- package/docs/content/devconsole.md +148 -0
- package/docs/content/di.md +212 -0
- package/docs/content/documentation-plan.md +182 -0
- package/docs/content/env.md +120 -0
- package/docs/content/getting-started.md +324 -0
- package/docs/content/health.md +64 -0
- package/docs/content/helpers.md +294 -0
- package/docs/content/http.md +402 -0
- package/docs/content/index.md +109 -0
- package/docs/content/leader-service.md +98 -0
- package/docs/content/logging.md +225 -0
- package/docs/content/mail.md +171 -0
- package/docs/content/mesh-client.md +333 -0
- package/docs/content/mesh-service.md +255 -0
- package/docs/content/migrations.md +190 -0
- package/docs/content/openapi.md +134 -0
- package/docs/content/overview.md +98 -0
- package/docs/content/public/images/devconsole/01-dashboard.png +0 -0
- package/docs/content/public/images/devconsole/02-routes.png +0 -0
- package/docs/content/public/images/devconsole/03-openapi.png +0 -0
- package/docs/content/public/images/devconsole/04-requests.png +0 -0
- package/docs/content/public/images/devconsole/05-srpc.png +0 -0
- package/docs/content/public/images/devconsole/06-database.png +0 -0
- package/docs/content/public/images/devconsole/06b-database-log.png +0 -0
- package/docs/content/public/images/devconsole/07-health.png +0 -0
- package/docs/content/public/images/devconsole/08-mutex.png +0 -0
- package/docs/content/public/images/devconsole/09-repl.png +0 -0
- package/docs/content/public/images/devconsole/10-workers.png +0 -0
- package/docs/content/public-api.md +84 -0
- package/docs/content/redis.md +174 -0
- package/docs/content/reflection.md +180 -0
- package/docs/content/release.md +100 -0
- package/docs/content/sql.md +121 -0
- package/docs/content/srpc.md +292 -0
- package/docs/content/telemetry.md +173 -0
- package/docs/content/testing.md +327 -0
- package/docs/content/type-reflection-architecture.md +149 -0
- package/docs/content/types.md +286 -0
- package/docs/content/uploads.md +145 -0
- package/docs/content/worker.md +182 -0
- package/docs/openapi.md +3 -0
- package/package.json +124 -0
- package/resources/proto/devconsole.proto +286 -0
- package/template-app/.env.development +10 -0
- package/template-app/gitignore.tmpl +11 -0
- package/template-app/package.json.tmpl +25 -0
- package/template-app/src/app.ts +13 -0
- package/template-app/src/config.ts +5 -0
- package/template-app/src/controllers/Example.controller.ts +19 -0
- package/template-app/src/database.ts +5 -0
- package/template-app/src/entities/Example.entity.ts +9 -0
- package/template-app/src/index.ts +7 -0
- package/template-app/src/migrations/.gitkeep +2 -0
- package/template-app/src/services/Example.service.ts +20 -0
- package/template-app/tests/app.spec.ts +8 -0
- package/template-app/tsconfig.json +26 -0
- package/template-app/tsconfig.test.json +5 -0
- package/types.d.ts +4 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# Mesh Client Tracking
|
|
2
|
+
|
|
3
|
+
Track clients connected across multiple backend nodes and invoke operations on any client regardless of which node it's connected to. Built on top of [MeshService](./mesh-service.md).
|
|
4
|
+
|
|
5
|
+
Three layers, each building on the previous:
|
|
6
|
+
|
|
7
|
+
1. **MeshClientRegistry** — tracks which clients are connected where, with metadata
|
|
8
|
+
2. **MeshClientService** — adds transparent cross-node client invocation
|
|
9
|
+
3. **MeshSrpcServer** — extends SrpcServer with auto-registration, lifecycle callbacks, and distributed invoke
|
|
10
|
+
|
|
11
|
+
## MeshClientRegistry
|
|
12
|
+
|
|
13
|
+
Track which clients are connected to which node, with arbitrary metadata.
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { MeshClientRegistry, MeshClientRedisRegistry } from '@zyno-io/ts-server-foundation';
|
|
17
|
+
|
|
18
|
+
interface ClientMeta {
|
|
19
|
+
userId: string;
|
|
20
|
+
role: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Usually you don't construct this manually — MeshClientService and MeshSrpcServer create it for you.
|
|
24
|
+
// But if you need standalone tracking:
|
|
25
|
+
const backend = new MeshClientRedisRegistry<ClientMeta>('my-app');
|
|
26
|
+
const registry = new MeshClientRegistry<ClientMeta>(mesh.instanceId, backend);
|
|
27
|
+
|
|
28
|
+
await registry.register('client-123', { userId: 'user-1', role: 'admin' });
|
|
29
|
+
|
|
30
|
+
const client = await registry.getClient('client-123');
|
|
31
|
+
// { clientId: 'client-123', nodeId: 1, connectedAt: 1710000000000, metadata: { userId: 'user-1', role: 'admin' } }
|
|
32
|
+
|
|
33
|
+
const all = await registry.listClients();
|
|
34
|
+
const local = await registry.listClientsForNode(mesh.instanceId);
|
|
35
|
+
|
|
36
|
+
// Update metadata (ownership-safe: only updates if this node owns the registration)
|
|
37
|
+
const updated = await registry.updateMetadata('client-123', {
|
|
38
|
+
userId: 'user-1',
|
|
39
|
+
role: 'superadmin'
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Ownership-safe: only removes if this node owns the registration
|
|
43
|
+
const removed = await registry.unregister('client-123'); // true if removed, false if client moved
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The `MeshClientRegistryBackend` interface is pluggable — implement your own for database-backed tracking:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import type { MeshClientRegistryBackend, RegisteredClient, RegisterResult } from '@zyno-io/ts-server-foundation';
|
|
50
|
+
|
|
51
|
+
class DatabaseClientRegistry<TMeta> implements MeshClientRegistryBackend<TMeta> {
|
|
52
|
+
async register(clientId: string, nodeId: number, metadata: TMeta, allowSupersede = true): Promise<RegisterResult> {
|
|
53
|
+
// Atomically create an active registration, return a conflict when another
|
|
54
|
+
// node owns it and supersession is disabled, or report the superseded node.
|
|
55
|
+
throw new Error('Implement active registration');
|
|
56
|
+
}
|
|
57
|
+
async reserve(clientId: string, nodeId: number, metadata: TMeta, allowSupersede = true): Promise<RegisterResult> {
|
|
58
|
+
// Pending reservations must remain hidden from lookup/list operations.
|
|
59
|
+
throw new Error('Implement pending reservation');
|
|
60
|
+
}
|
|
61
|
+
async activate(clientId: string, nodeId: number, metadata: TMeta): Promise<boolean> {
|
|
62
|
+
// Promote this node's pending reservation to active without changing ownership.
|
|
63
|
+
throw new Error('Implement reservation activation');
|
|
64
|
+
}
|
|
65
|
+
async unregister(clientId: string, nodeId: number): Promise<boolean> {
|
|
66
|
+
throw new Error('Implement ownership-safe removal');
|
|
67
|
+
}
|
|
68
|
+
async updateMetadata(clientId: string, nodeId: number, metadata: TMeta): Promise<boolean> {
|
|
69
|
+
throw new Error('Implement ownership-safe metadata update');
|
|
70
|
+
}
|
|
71
|
+
async getClient(clientId: string): Promise<RegisteredClient<TMeta> | undefined> {
|
|
72
|
+
throw new Error('Implement active lookup');
|
|
73
|
+
}
|
|
74
|
+
async listClients(): Promise<RegisteredClient<TMeta>[]> {
|
|
75
|
+
throw new Error('Implement active listing');
|
|
76
|
+
}
|
|
77
|
+
async listClientsForNode(nodeId: number): Promise<RegisteredClient<TMeta>[]> {
|
|
78
|
+
throw new Error('Implement active listing by node');
|
|
79
|
+
}
|
|
80
|
+
async cleanupNode(nodeId: number): Promise<RegisteredClient<TMeta>[]> {
|
|
81
|
+
throw new Error('Implement ownership-safe node cleanup');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### API
|
|
87
|
+
|
|
88
|
+
#### `new MeshClientRegistry<TMeta>(nodeId: number, backend: MeshClientRegistryBackend<TMeta>)`
|
|
89
|
+
|
|
90
|
+
Creates a registry bound to a specific mesh node ID.
|
|
91
|
+
|
|
92
|
+
#### `register(clientId, metadata, allowSupersede?)` → `Promise<RegisterResult>`
|
|
93
|
+
|
|
94
|
+
Register an active client on this node. A `connectedAt` timestamp (epoch ms) is automatically recorded. The result is `{ status: 'ok', supersededNodeId }` when registration succeeds or `{ status: 'conflict', ownerNodeId }` when another node owns the client and supersession is disabled. `ownerNodeId` can be `null` if the owner disappears during the conflict/readback race. The built-in Redis backend allows supersession by default.
|
|
95
|
+
|
|
96
|
+
#### `reserve(clientId, metadata, allowSupersede?)` → `Promise<RegisterResult>`
|
|
97
|
+
|
|
98
|
+
Atomically reserve ownership without making the client visible to `getClient()`, list operations, or invocation. The result has the same conflict/supersession shape as `register()`.
|
|
99
|
+
|
|
100
|
+
#### `activate(clientId, metadata)` → `Promise<boolean>`
|
|
101
|
+
|
|
102
|
+
Promote a pending reservation owned by this node to an active registration and store its final metadata. It returns `false` if the reservation disappeared or ownership moved to another node.
|
|
103
|
+
|
|
104
|
+
#### `unregister(clientId)` → `Promise<boolean>`
|
|
105
|
+
|
|
106
|
+
Remove a client registration. Returns `true` if the client was owned by this node and was removed. Returns `false` if the client had already reconnected to a different node (ownership-safe).
|
|
107
|
+
|
|
108
|
+
#### `updateMetadata(clientId, metadata)` → `Promise<boolean>`
|
|
109
|
+
|
|
110
|
+
Update metadata for a registered client. Returns `true` if the client was owned by this node and was updated. Returns `false` if the client is not registered or has moved to a different node (ownership-safe).
|
|
111
|
+
|
|
112
|
+
#### `getClient(clientId)` → `Promise<RegisteredClient<TMeta> | undefined>`
|
|
113
|
+
|
|
114
|
+
Look up a client by ID across all nodes. The returned `RegisteredClient` includes `clientId`, `nodeId`, `connectedAt` (epoch ms), and `metadata`.
|
|
115
|
+
|
|
116
|
+
#### `listClients()` → `Promise<RegisteredClient<TMeta>[]>`
|
|
117
|
+
|
|
118
|
+
List all registered clients across all nodes.
|
|
119
|
+
|
|
120
|
+
#### `listClientsForNode(nodeId?)` → `Promise<RegisteredClient<TMeta>[]>`
|
|
121
|
+
|
|
122
|
+
List clients for a specific node. Defaults to this registry's node.
|
|
123
|
+
|
|
124
|
+
#### `cleanupNode(nodeId?)` → `Promise<RegisteredClient<TMeta>[]>`
|
|
125
|
+
|
|
126
|
+
Remove all clients for a node, returning the orphaned clients (with metadata). Only removes clients still owned by that node — clients that reconnected elsewhere are left intact.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## MeshClientService
|
|
131
|
+
|
|
132
|
+
Combines MeshClientRegistry with MeshService for transparent cross-node client invocation. You provide a `clientInvokeFn` for delivery to a client connected to this node; it is called for both local invocations and requests forwarded from another node.
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { MeshClientService } from '@zyno-io/ts-server-foundation';
|
|
136
|
+
|
|
137
|
+
// Define broadcast types for type-safe broadcasting
|
|
138
|
+
interface MyBroadcasts {
|
|
139
|
+
configUpdated: { keys: string[] };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const clientService = new MeshClientService<ClientMeta, MyBroadcasts>({
|
|
143
|
+
key: 'my-app',
|
|
144
|
+
clientInvokeFn: async (clientId, type, data, timeoutMs) => {
|
|
145
|
+
// Deliver to a client connected to this node, whether the caller is local or remote.
|
|
146
|
+
return localDelivery(clientId, type, data);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
await clientService.start();
|
|
151
|
+
|
|
152
|
+
await clientService.registerClient('client-123', { userId: 'user-1', role: 'admin' });
|
|
153
|
+
|
|
154
|
+
// Update metadata after registration (ownership-safe)
|
|
155
|
+
await clientService.updateClientMetadata('client-123', { userId: 'user-1', role: 'superadmin' });
|
|
156
|
+
|
|
157
|
+
// Invoke on any client — routes through mesh if on a different node
|
|
158
|
+
const result = await clientService.invoke('client-123', 'notify', { text: 'hello' });
|
|
159
|
+
|
|
160
|
+
// Broadcast to all nodes
|
|
161
|
+
clientService.registerBroadcastHandler('configUpdated', (data, senderInstanceId) => {
|
|
162
|
+
console.log(`Config updated by node ${senderInstanceId}:`, data.keys);
|
|
163
|
+
});
|
|
164
|
+
await clientService.broadcast('configUpdated', { keys: ['feature-flag-x'] });
|
|
165
|
+
|
|
166
|
+
const clients = await clientService.clientRegistry.listClients();
|
|
167
|
+
|
|
168
|
+
await clientService.stop();
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### API
|
|
172
|
+
|
|
173
|
+
#### `new MeshClientService<TMeta, TBroadcasts>(options)`
|
|
174
|
+
|
|
175
|
+
| Option | Type | Description |
|
|
176
|
+
| -------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
177
|
+
| `key` | `string` | Mesh key (internally namespaced as `_mc:{key}`) |
|
|
178
|
+
| `meshOptions` | `MeshServiceOptions` | Optional tuning for the internal mesh node |
|
|
179
|
+
| `registryBackend` | `MeshClientRegistryBackend` | Optional custom backend (defaults to `MeshClientRedisRegistry`) |
|
|
180
|
+
| `clientInvokeFn` | `(clientId, type, data, timeoutMs?) => Promise<unknown>` | Delivers local clients for both local and forwarded invocations |
|
|
181
|
+
| `clientUpdateMetaFn` | `(clientId, metadata) => boolean` | Optional owning-node hook that applies a cross-node metadata update to the live local client. |
|
|
182
|
+
|
|
183
|
+
#### Properties
|
|
184
|
+
|
|
185
|
+
| Property | Type | Description |
|
|
186
|
+
| ---------------- | --------------------------- | ----------------------------- |
|
|
187
|
+
| `instanceId` | `number` | This node's mesh instance ID |
|
|
188
|
+
| `clientRegistry` | `MeshClientRegistry<TMeta>` | Direct access to the registry |
|
|
189
|
+
|
|
190
|
+
#### Methods
|
|
191
|
+
|
|
192
|
+
| Method | Description |
|
|
193
|
+
| -------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
|
|
194
|
+
| `start()` | Start the internal mesh and initialize the registry |
|
|
195
|
+
| `stop()` | Clean up own clients, stop the mesh |
|
|
196
|
+
| `registerClient(clientId, metadata, allowSupersede?)` → `Promise<boolean>` | Register on this node; false means a non-superseded ownership conflict |
|
|
197
|
+
| `reserveClient(clientId, metadata, allowSupersede?)` → `Promise<boolean>` | Reserve ownership without exposing the client until activation |
|
|
198
|
+
| `activateClient(clientId, metadata)` → `Promise<boolean>` | Promote this node's reservation to active |
|
|
199
|
+
| `unregisterClient(clientId)` → `Promise<boolean>` | Unregister (returns false if client moved elsewhere) |
|
|
200
|
+
| `updateClientMetadata(clientId, metadata)` → `Promise<boolean>` | Update metadata (returns false if client moved) |
|
|
201
|
+
| `invoke(clientId, type, data, timeoutMs?)` | Invoke on any client, routes automatically |
|
|
202
|
+
| `registerBroadcastHandler(type, handler)` | Register a handler for a broadcast type |
|
|
203
|
+
| `broadcast(type, data, options?)` | Broadcast to all nodes in the mesh |
|
|
204
|
+
|
|
205
|
+
Before `start()`, registration and reservation are accepted as no-op compatibility calls, activation/update/unregister return `false`, and `invoke()` throws `ClientNotFoundError`. Callers that need discoverable state must await `start()` first. Local invocation calls `clientInvokeFn` directly. Remote invocation forwards to the owning node and preserves `ClientDisconnectedError`; other delivery failures become `ClientInvocationError`. Remote metadata updates run `clientUpdateMetaFn` on the owner and persist the accepted metadata in the registry.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## MeshSrpcServer
|
|
210
|
+
|
|
211
|
+
Extends `SrpcServer` with mesh client tracking. Single class — no need to create an SrpcServer separately.
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import { MeshSrpcServer } from '@zyno-io/ts-server-foundation';
|
|
215
|
+
import { ClientMessage, ServerMessage } from './generated/proto';
|
|
216
|
+
|
|
217
|
+
const server = new MeshSrpcServer({
|
|
218
|
+
// SrpcServer options
|
|
219
|
+
logger,
|
|
220
|
+
clientMessage: ClientMessage,
|
|
221
|
+
serverMessage: ServerMessage,
|
|
222
|
+
wsPath: '/srpc',
|
|
223
|
+
|
|
224
|
+
// Mesh options
|
|
225
|
+
meshKey: 'my-app'
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Register SRPC handlers as usual
|
|
229
|
+
server.registerMessageHandler('uEcho', async (stream, data) => {
|
|
230
|
+
return { message: `Echo: ${data.message}` };
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Lifecycle callbacks
|
|
234
|
+
server.onClientConnected((clientId, metadata) => {
|
|
235
|
+
console.log(`Client ${clientId} connected`);
|
|
236
|
+
db.updatePresence(clientId, 'online');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
server.onClientDisconnected((clientId, metadata) => {
|
|
240
|
+
// Only fires if the client actually left — NOT if it reconnected to another node
|
|
241
|
+
console.log(`Client ${clientId} disconnected`);
|
|
242
|
+
db.updatePresence(clientId, 'offline');
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
server.onNodeClientsOrphaned((nodeId, clients) => {
|
|
246
|
+
// Fires on the leader when a dead node is cleaned up
|
|
247
|
+
// Only includes clients that didn't reconnect elsewhere
|
|
248
|
+
console.log(`Node ${nodeId} died, ${clients.length} orphaned clients`);
|
|
249
|
+
for (const client of clients) {
|
|
250
|
+
db.updatePresence(client.clientId, 'offline');
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
await server.meshStart();
|
|
255
|
+
|
|
256
|
+
// Update client metadata at any time (ownership-safe)
|
|
257
|
+
await server.updateClientMetadata('client-123', { ...metadata, role: 'superadmin' });
|
|
258
|
+
|
|
259
|
+
// Type-safe invoke on any client, regardless of which node
|
|
260
|
+
await server.invoke('client-123', 'dNotify', { text: 'hello' });
|
|
261
|
+
|
|
262
|
+
// Broadcast to all nodes (uses MeshService broadcast under the hood)
|
|
263
|
+
// Add a TBroadcasts generic to the server for type-safe broadcasts:
|
|
264
|
+
// new MeshSrpcServer<Meta, ClientMsg, ServerMsg, RegistryMeta, MyBroadcasts>(...)
|
|
265
|
+
server.registerBroadcastHandler('configUpdated', (data, senderInstanceId) => {
|
|
266
|
+
console.log(`Config updated by node ${senderInstanceId}:`, data);
|
|
267
|
+
});
|
|
268
|
+
await server.broadcast('configUpdated', { keys: ['feature-flag-x'] });
|
|
269
|
+
|
|
270
|
+
// Access the registry
|
|
271
|
+
const allClients = await server.clientRegistry.listClients();
|
|
272
|
+
|
|
273
|
+
// Shutdown
|
|
274
|
+
await server.meshStop();
|
|
275
|
+
server.close();
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### API
|
|
279
|
+
|
|
280
|
+
#### Constructor
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
new MeshSrpcServer(options: ISrpcServerOptions & MeshSrpcServerOptions)
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
`MeshSrpcServerOptions`:
|
|
287
|
+
|
|
288
|
+
| Option | Type | Description |
|
|
289
|
+
| ----------------- | --------------------------- | ---------------------------------------------- |
|
|
290
|
+
| `meshKey` | `string` | Mesh key |
|
|
291
|
+
| `meshOptions` | `MeshServiceOptions` | Optional mesh tuning |
|
|
292
|
+
| `registryBackend` | `MeshClientRegistryBackend` | Optional custom backend |
|
|
293
|
+
| `extractMetadata` | `(stream) => TRegistryMeta` | Optional metadata extraction from SRPC streams |
|
|
294
|
+
|
|
295
|
+
#### Properties
|
|
296
|
+
|
|
297
|
+
| Property | Type | Description |
|
|
298
|
+
| ---------------- | ----------------------------------- | ----------------------------- |
|
|
299
|
+
| `meshInstanceId` | `number` | This node's mesh instance ID |
|
|
300
|
+
| `clientRegistry` | `MeshClientRegistry<TRegistryMeta>` | Direct access to the registry |
|
|
301
|
+
|
|
302
|
+
#### Methods
|
|
303
|
+
|
|
304
|
+
| Method | Description |
|
|
305
|
+
| -------------------------------------------- | ----------------------------------------------------------------------------------------- |
|
|
306
|
+
| `meshStart()` | Start mesh client tracking |
|
|
307
|
+
| `meshStop()` | Stop mesh client tracking (call before `close()`) |
|
|
308
|
+
| `updateClientMetadata(clientId, metadata)` | Update metadata (returns false if client moved); also updates local cache |
|
|
309
|
+
| `invoke(clientId, prefix, data, timeoutMs?)` | Type-safe invoke on any client across any node |
|
|
310
|
+
| `registerBroadcastHandler(type, handler)` | Register a handler for a broadcast type (see [MeshService broadcasts](./mesh-service.md)) |
|
|
311
|
+
| `broadcast(type, data, options?)` | Broadcast to all nodes in the mesh |
|
|
312
|
+
| `onClientConnected(handler)` | Fires on the node the client connected to |
|
|
313
|
+
| `onClientDisconnected(handler)` | Fires on the node the client disconnected from |
|
|
314
|
+
| `onNodeClientsOrphaned(handler)` | Fires on the **leader node** when a dead node's clients are cleaned up |
|
|
315
|
+
|
|
316
|
+
Plus all `SrpcServer` methods: `registerMessageHandler`, `registerConnectionHandler`, `registerDisconnectHandler`, `setClientAuthorizer`, etc.
|
|
317
|
+
|
|
318
|
+
`MeshSrpcServer` reserves client ownership before SRPC activation, so pending connections never appear in active registry lookups. After activation, top-level assignments and deletions on `stream.meta` are batched in a microtask and synchronized to the registry. Nested mutations are not observable through the proxy; replace the top-level value or call `updateClientMetadata()`. Explicit metadata updates currently merge supplied keys into the live `stream.meta` object while replacing the registry metadata value, so callers that need deletion parity should delete top-level stream keys directly. Calls for a remote client route through the mesh to the owning SRPC stream. Connected/disconnected callbacks are serialized per client, and a stale disconnect from a same-node replacement does not unregister the replacement or publish an offline callback.
|
|
319
|
+
|
|
320
|
+
## Current Limits
|
|
321
|
+
|
|
322
|
+
- The built-in Redis registry applies a 24-hour safety TTL to its client hash and per-node sets. Registry writes refresh those keys, but mesh heartbeats currently do not; registrations in a completely quiet mesh can therefore expire while clients remain connected.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## Error Classes
|
|
327
|
+
|
|
328
|
+
| Error | When |
|
|
329
|
+
| ------------------------- | --------------------------------------------------------------------- |
|
|
330
|
+
| `ClientNotFoundError` | `invoke()` called with a clientId not in the registry |
|
|
331
|
+
| `ClientDisconnectedError` | Client was in the registry but no longer connected on the target node |
|
|
332
|
+
| `ClientInvocationError` | Remote delivery failed (wraps the original error message) |
|
|
333
|
+
| `MeshRequestTimeoutError` | The remote node didn't respond to the mesh forwarding request |
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# MeshService
|
|
2
|
+
|
|
3
|
+
Typed RPC between distributed application instances. Each node gets a unique integer ID and can invoke handlers on any other node (or itself) with full type safety. Uses Redis pub/sub for messaging and sorted sets for node tracking.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
### Define a message map
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { MeshService, MeshMessageMap } from '@zyno-io/ts-server-foundation';
|
|
11
|
+
|
|
12
|
+
type MyMessages = {
|
|
13
|
+
getStatus: { request: { verbose: boolean }; response: { status: string; uptime: number } };
|
|
14
|
+
invalidateCache: { request: { keys: string[] }; response: { cleared: number } };
|
|
15
|
+
};
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Create and start a node
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
const mesh = new MeshService<MyMessages>('my-app');
|
|
22
|
+
|
|
23
|
+
mesh.registerHandler('getStatus', async data => {
|
|
24
|
+
return { status: 'ok', uptime: process.uptime() };
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
mesh.registerHandler('invalidateCache', async data => {
|
|
28
|
+
const cleared = await cache.delete(data.keys);
|
|
29
|
+
return { cleared };
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
await mesh.start();
|
|
33
|
+
console.log(`Node started with instance ID: ${mesh.instanceId}`);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Invoke a handler on another node
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// Call a specific node by its instance ID
|
|
40
|
+
const result = await mesh.invoke(targetInstanceId, 'getStatus', { verbose: true });
|
|
41
|
+
console.log(result.status); // fully typed
|
|
42
|
+
|
|
43
|
+
// Calling your own instance ID routes directly to the local handler (no pub/sub)
|
|
44
|
+
const local = await mesh.invoke(mesh.instanceId, 'getStatus', { verbose: false });
|
|
45
|
+
|
|
46
|
+
// Per-request timeout (overrides the service-level default)
|
|
47
|
+
const fast = await mesh.invoke(targetInstanceId, 'getStatus', { verbose: false }, 2000);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### List nodes in the mesh
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
const nodes = await mesh.getNodes();
|
|
54
|
+
for (const node of nodes) {
|
|
55
|
+
console.log(`${node.instanceId} @ ${node.hostname}${node.self ? ' (self)' : ''}`);
|
|
56
|
+
}
|
|
57
|
+
// 1 @ web-server-01
|
|
58
|
+
// 2 @ web-server-02 (self)
|
|
59
|
+
// 3 @ web-server-03
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Track node departures
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
mesh.setNodeCleanedUpCallback(async instanceId => {
|
|
66
|
+
console.log(`Node ${instanceId} left the mesh`);
|
|
67
|
+
// Clean up resources associated with that node
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Broadcast to all nodes
|
|
72
|
+
|
|
73
|
+
Fire-and-forget messages to every node in the mesh. Unlike `invoke`, broadcasts have no response.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { MeshService, MeshBroadcastMap } from '@zyno-io/ts-server-foundation';
|
|
77
|
+
|
|
78
|
+
type MyBroadcasts = {
|
|
79
|
+
configUpdated: { keys: string[] };
|
|
80
|
+
userLoggedOut: { userId: string };
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const mesh = new MeshService<MyMessages, MyBroadcasts>('my-app');
|
|
84
|
+
|
|
85
|
+
// Register handlers for broadcast types
|
|
86
|
+
mesh.registerBroadcastHandler('configUpdated', (data, senderInstanceId) => {
|
|
87
|
+
console.log(`Config update from node ${senderInstanceId}:`, data.keys);
|
|
88
|
+
reloadConfig(data.keys);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
await mesh.start();
|
|
92
|
+
|
|
93
|
+
// Broadcast to all nodes (including self)
|
|
94
|
+
await mesh.broadcast('configUpdated', { keys: ['feature-flags'] });
|
|
95
|
+
|
|
96
|
+
// Skip self-delivery
|
|
97
|
+
await mesh.broadcast('userLoggedOut', { userId: '123' }, { skipSelf: true });
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Graceful shutdown
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
await mesh.stop();
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## API
|
|
107
|
+
|
|
108
|
+
### `new MeshService<T extends MeshMessageMap, B extends MeshBroadcastMap>(key: string, options?: MeshServiceOptions)`
|
|
109
|
+
|
|
110
|
+
Creates a new mesh node.
|
|
111
|
+
|
|
112
|
+
- **`key`** -- Logical mesh name. All nodes using the same key form one mesh. Different keys are fully independent.
|
|
113
|
+
- **`options`** -- Optional tuning parameters (see below).
|
|
114
|
+
|
|
115
|
+
### `MeshServiceOptions`
|
|
116
|
+
|
|
117
|
+
| Option | Type | Default | Description |
|
|
118
|
+
| --------------------- | ---------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
119
|
+
| `heartbeatIntervalMs` | `number` | `5000` | How often this node refreshes its heartbeat in the registry. |
|
|
120
|
+
| `nodeTtlMs` | `number` | `15000` | How long a node can go without a heartbeat before the leader removes it. |
|
|
121
|
+
| `requestTimeoutMs` | `number` | `10000` | Default timeout for remote invocations. Reset on each heartbeat from the handler, so long-running handlers won't time out. |
|
|
122
|
+
| `leaderOptions` | `LeaderServiceOptions` | — | Options passed to the internal `LeaderService` used for cleanup leader election. |
|
|
123
|
+
|
|
124
|
+
### Properties
|
|
125
|
+
|
|
126
|
+
| Property | Type | Description |
|
|
127
|
+
| ------------ | -------- | ----------------------------------------------------------------------- |
|
|
128
|
+
| `instanceId` | `number` | Unique integer ID assigned to this node on `start()`. `0` before start. |
|
|
129
|
+
|
|
130
|
+
### Methods
|
|
131
|
+
|
|
132
|
+
#### `registerHandler<K>(type: K, handler: (data: T[K]['request']) => T[K]['response'] | Promise<T[K]['response']>): void`
|
|
133
|
+
|
|
134
|
+
Register a handler for a message type. Handlers can be registered before or after `start()`. Registering a handler for a type that already has one replaces it.
|
|
135
|
+
|
|
136
|
+
#### `invoke<K>(instanceId: number, type: K, data: T[K]['request'], timeoutMs?: number): Promise<T[K]['response']>`
|
|
137
|
+
|
|
138
|
+
Send a typed request to a specific node and wait for the response.
|
|
139
|
+
|
|
140
|
+
- **`timeoutMs`** -- Optional per-request timeout. Falls back to the service-level `requestTimeoutMs` if not provided. The handler-side heartbeat interval automatically adjusts to the caller's timeout.
|
|
141
|
+
- If `instanceId` matches the local node, the handler is called directly (no pub/sub, no timeout).
|
|
142
|
+
- If the target node doesn't exist or doesn't respond, the promise rejects with `MeshRequestTimeoutError`.
|
|
143
|
+
- If the target has no handler for the type, rejects with `MeshNoHandlerError`.
|
|
144
|
+
- If the handler throws, rejects with `MeshHandlerError` containing the error message.
|
|
145
|
+
|
|
146
|
+
#### `registerBroadcastHandler<K>(type: K, handler: (data: B[K], senderInstanceId: number) => void | Promise<void>): void`
|
|
147
|
+
|
|
148
|
+
Register a handler for a broadcast message type. Broadcast handlers receive the message data and the sender's instance ID. Errors thrown in handlers are logged but do not propagate.
|
|
149
|
+
|
|
150
|
+
#### `broadcast<K>(type: K, data: B[K], options?: MeshBroadcastOptions): Promise<void>`
|
|
151
|
+
|
|
152
|
+
Send a fire-and-forget message to all nodes in the mesh (including self, unless `skipSelf: true`).
|
|
153
|
+
|
|
154
|
+
| Option | Type | Default | Description |
|
|
155
|
+
| ---------- | --------- | ------- | ----------------------------------- |
|
|
156
|
+
| `skipSelf` | `boolean` | `false` | Don't deliver the broadcast to self |
|
|
157
|
+
|
|
158
|
+
#### `getNodes(): Promise<MeshNode[]>`
|
|
159
|
+
|
|
160
|
+
Returns all live nodes in the mesh. Each `MeshNode` contains:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
interface MeshNode {
|
|
164
|
+
instanceId: number; // The node's unique integer ID
|
|
165
|
+
hostname: string; // The OS hostname of the machine running the node
|
|
166
|
+
self: boolean; // true if this is the calling node
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The method returns the current heartbeat registry members. Gracefully stopped nodes remove themselves immediately; expired nodes can remain visible until the leader's cleanup pass removes them.
|
|
171
|
+
|
|
172
|
+
#### `setNodeCleanedUpCallback(cb: (instanceId: number) => void | Promise<void>): void`
|
|
173
|
+
|
|
174
|
+
Register a callback invoked when the leader detects and removes an expired node. Only fires on the current leader instance. Errors in the callback are logged but don't affect cleanup of other nodes.
|
|
175
|
+
|
|
176
|
+
#### `start(): Promise<void>`
|
|
177
|
+
|
|
178
|
+
Join the mesh. Acquires a unique instance ID, subscribes to its pub/sub channel and broadcast channel, registers in the heartbeat set, and starts leader election. Throws if already running.
|
|
179
|
+
|
|
180
|
+
#### `stop(): Promise<void>`
|
|
181
|
+
|
|
182
|
+
Leave the mesh. Stops heartbeats, rejects all pending outbound requests with `Error('MeshService stopped')`, unsubscribes from pub/sub, and removes itself from the heartbeat registry. Safe to call before `start()` or multiple times.
|
|
183
|
+
|
|
184
|
+
## Error Classes
|
|
185
|
+
|
|
186
|
+
### `MeshRequestTimeoutError`
|
|
187
|
+
|
|
188
|
+
The target node did not respond within the timeout period. This can happen if the target has crashed, is unreachable, or the Redis pub/sub connection is disrupted.
|
|
189
|
+
|
|
190
|
+
### `MeshHandlerError`
|
|
191
|
+
|
|
192
|
+
The target node's handler threw an error. The `message` property contains the original error message from the remote handler.
|
|
193
|
+
|
|
194
|
+
### `MeshNoHandlerError`
|
|
195
|
+
|
|
196
|
+
No handler is registered for the requested message type -- either locally (direct invocation) or on the remote node.
|
|
197
|
+
|
|
198
|
+
## Architecture
|
|
199
|
+
|
|
200
|
+
### Node Registry
|
|
201
|
+
|
|
202
|
+
Nodes are tracked in a Redis sorted set (`{prefix}:mesh:{key}:heartbeats`) where the score is the last heartbeat timestamp (from Redis server time, avoiding clock skew) and the member is the instance ID. Node metadata (hostname) is stored in a Redis hash (`{prefix}:mesh:{key}:nodes`).
|
|
203
|
+
|
|
204
|
+
Unique instance IDs are assigned via `INCR` on `{prefix}:mesh:{key}:next_id`. Both the heartbeat entry and the nodes hash entry are removed on graceful stop or leader-driven cleanup of expired nodes.
|
|
205
|
+
|
|
206
|
+
### Messaging
|
|
207
|
+
|
|
208
|
+
Each node subscribes to its own pub/sub channel: `{prefix}:mesh:{key}:node:{instanceId}`.
|
|
209
|
+
|
|
210
|
+
Three message types flow over these channels:
|
|
211
|
+
|
|
212
|
+
| Type | Direction | Purpose |
|
|
213
|
+
| ------------- | ----------------- | -------------------------------------------------------- |
|
|
214
|
+
| **Request** | Caller -> Handler | `{ requestId, senderInstanceId, type, data, timeoutMs }` |
|
|
215
|
+
| **Response** | Handler -> Caller | `{ requestId, reply: true, data?, error? }` |
|
|
216
|
+
| **Heartbeat** | Handler -> Caller | `{ requestId, heartbeat: true }` |
|
|
217
|
+
|
|
218
|
+
### Broadcast
|
|
219
|
+
|
|
220
|
+
All nodes also subscribe to a shared broadcast channel: `{prefix}:mesh:{key}:broadcast`. Broadcasts are fire-and-forget — the sender publishes once and all subscribers receive the message. No response is collected.
|
|
221
|
+
|
|
222
|
+
Channel routing: the subscriber's `message` handler inspects the channel name to distinguish broadcast messages from point-to-point messages on the instance channel.
|
|
223
|
+
|
|
224
|
+
### Request Heartbeats
|
|
225
|
+
|
|
226
|
+
While a handler is executing, the handling node sends periodic heartbeat messages back to the caller (every `requestTimeoutMs * 0.75`). The caller resets its timeout timer on each heartbeat. This allows short absolute timeouts while supporting arbitrarily long handler execution.
|
|
227
|
+
|
|
228
|
+
The handler uses the **caller's** `requestTimeoutMs` (sent in the request message) for its heartbeat interval, so mixed-timeout configurations work correctly.
|
|
229
|
+
|
|
230
|
+
### Leader Election
|
|
231
|
+
|
|
232
|
+
Each mesh uses an internal `LeaderService` (key: `mesh:{key}`) for leader election. The leader is responsible for:
|
|
233
|
+
|
|
234
|
+
1. Running the cleanup Lua script on each heartbeat cycle
|
|
235
|
+
2. Removing expired nodes from the sorted set
|
|
236
|
+
3. Invoking the `nodeCleanedUpCallback` for each removed node
|
|
237
|
+
|
|
238
|
+
Only one node (the leader) performs cleanup at any time.
|
|
239
|
+
|
|
240
|
+
### Local Invocation
|
|
241
|
+
|
|
242
|
+
When `invoke` is called with the node's own instance ID, the handler is called directly as a function call -- no serialization, no pub/sub, no timeout. Errors propagate as-is.
|
|
243
|
+
|
|
244
|
+
## Configuration
|
|
245
|
+
|
|
246
|
+
The Redis connection is configured via environment variables with the `MESH_REDIS_` prefix (falls back to `REDIS_`):
|
|
247
|
+
|
|
248
|
+
| Variable | Description |
|
|
249
|
+
| -------------------------- | ------------------------------------------------------------ |
|
|
250
|
+
| `MESH_REDIS_HOST` | Redis host |
|
|
251
|
+
| `MESH_REDIS_PORT` | Redis port |
|
|
252
|
+
| `MESH_REDIS_PREFIX` | Key prefix (falls back to `REDIS_PREFIX`, then package name) |
|
|
253
|
+
| `MESH_REDIS_SENTINEL_HOST` | Sentinel host (optional) |
|
|
254
|
+
| `MESH_REDIS_SENTINEL_PORT` | Sentinel port (optional) |
|
|
255
|
+
| `MESH_REDIS_SENTINEL_NAME` | Sentinel master name (optional) |
|