{"_id":"@dogsvr/dogsvr","_rev":"7-ab2e8a36b7f40f567790544dd54f21cc","name":"@dogsvr/dogsvr","dist-tags":{"latest":"0.4.2"},"versions":{"0.0.1":{"name":"@dogsvr/dogsvr","version":"0.0.1","author":{"name":"rowanzhu"},"license":"MIT","_id":"@dogsvr/dogsvr@0.0.1","maintainers":[{"name":"rowanzhu","email":"rowanzhu@gmail.com"}],"homepage":"https://github.com/dogsvr/dogsvr#readme","bugs":{"url":"https://github.com/dogsvr/dogsvr/issues"},"dist":{"shasum":"3096a07683d7a478e0e701799613dceb93ac0b40","tarball":"https://registry.npmjs.org/@dogsvr/dogsvr/-/dogsvr-0.0.1.tgz","fileCount":17,"integrity":"sha512-jlkkUXDL3xH3KGR4F1cj68rt/ExQeol8MfI+asq9c9YMyWTF6kkVZ+bEdaObSaNeJG2ulsrEmXFs2UY3s8xFng==","signatures":[{"sig":"MEUCIQDE3IM9zUiMJov1JRNZpqMgvLerieMhzrBGRyaaTWptRQIgU9jnaNbgtA24UzZ4mGRZF9tjFWXPrnrTkJTR1UBN4k8=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":14595},"main":"index.js","gitHead":"4899c25758b70283ad59e245ac0a72ea331ca132","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rm -rf dist && mkdir dist && cp package.json LICENSE README.md dist && npx tsc"},"_npmUser":{"name":"rowanzhu","email":"rowanzhu@gmail.com"},"repository":{"url":"git+https://github.com/dogsvr/dogsvr.git","type":"git"},"_npmVersion":"8.11.0","description":"dogsvr is a game server package based on nodejs, and makes writing game server easier for rapid development of small teams.","directories":{},"_nodeVersion":"16.15.1","dependencies":{"tx2":"^1.0.5"},"_hasShrinkwrap":false,"devDependencies":{"@types/tx2":"^1.0.3"},"_npmOperationalInternal":{"tmp":"tmp/dogsvr_0.0.1_1731828457086_0.38830605515236893","host":"s3://npm-registry-packages"}},"0.0.2":{"name":"@dogsvr/dogsvr","version":"0.0.2","author":{"name":"rowanzhu"},"license":"MIT","_id":"@dogsvr/dogsvr@0.0.2","maintainers":[{"name":"rowanzhu","email":"rowanzhu@gmail.com"}],"homepage":"https://github.com/dogsvr/dogsvr#readme","bugs":{"url":"https://github.com/dogsvr/dogsvr/issues"},"dist":{"shasum":"71ebefd2aa711310dfdcbe25b2a3e0db80dcd2ed","tarball":"https://registry.npmjs.org/@dogsvr/dogsvr/-/dogsvr-0.0.2.tgz","fileCount":17,"integrity":"sha512-wVKIl3aA/MUOkcqFR/jz/WhkGZqVw4g9NzXLTg+z3LJcUVNJINuEhwYUJVznwV0v1OpS6hxANjTtUjXGGEW5uA==","signatures":[{"sig":"MEUCIQDrR25nmHNyeVj/n+IC/QdBoHStk00ruWCWvFMgTBOOagIgHgTD4LzAHrHbWdkb5VPtg00F8BttgC/0vLwb3TW6gAU=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":17306},"main":"index.js","gitHead":"f92c0d1ec875cb9118d2873d12b3cfeff6d68bf6","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rm -rf dist && mkdir dist && cp package.json LICENSE README.md dist && npx tsc"},"_npmUser":{"name":"rowanzhu","email":"rowanzhu@gmail.com"},"repository":{"url":"git+https://github.com/dogsvr/dogsvr.git","type":"git"},"_npmVersion":"8.11.0","description":"dogsvr is a game server package based on nodejs, and makes writing game server easier for rapid development of small teams.","directories":{},"_nodeVersion":"16.15.1","dependencies":{"tx2":"^1.0.5"},"_hasShrinkwrap":false,"devDependencies":{"@types/tx2":"^1.0.3"},"_npmOperationalInternal":{"tmp":"tmp/dogsvr_0.0.2_1733651347418_0.09911394884922431","host":"s3://npm-registry-packages"}},"0.0.4":{"name":"@dogsvr/dogsvr","version":"0.0.4","author":{"name":"rowanzhu"},"license":"MIT","_id":"@dogsvr/dogsvr@0.0.4","maintainers":[{"name":"rowanzhu","email":"rowanzhu@gmail.com"}],"homepage":"https://github.com/dogsvr/dogsvr#readme","bugs":{"url":"https://github.com/dogsvr/dogsvr/issues"},"dist":{"shasum":"ffc2ca51b87b3d76408b516eb6406eb9b742f44d","tarball":"https://registry.npmjs.org/@dogsvr/dogsvr/-/dogsvr-0.0.4.tgz","fileCount":17,"integrity":"sha512-0fUbSwohYNdWLg+dl/tqHtIxbAK5qbMNH7fKbv75/BI3+D+ybOPD/eFUpRsqfEJG4a2N58sKKf23t49CK2p/rQ==","signatures":[{"sig":"MEUCIG1uWVwB2FZ/iXMTxfWNIWg2LXBo89hSs57EgosW9BfhAiEA5fuQ0A2qI2CtBLt43xiJM3a22Z6viT39NAS8Dtamh8o=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":17347},"main":"index.js","gitHead":"61756cf2dc63053314a9330478892cf30fedc50b","scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"rm -rf dist && mkdir dist && cp package.json LICENSE README.md dist && npx tsc"},"_npmUser":{"name":"rowanzhu","email":"rowanzhu@gmail.com"},"repository":{"url":"git+https://github.com/dogsvr/dogsvr.git","type":"git"},"_npmVersion":"8.11.0","description":"dogsvr is a game server package based on nodejs, and makes writing game server easier for rapid development of small teams.","directories":{},"_nodeVersion":"16.15.1","dependencies":{"tx2":"^1.0.5"},"_hasShrinkwrap":false,"devDependencies":{"@types/tx2":"^1.0.3"},"_npmOperationalInternal":{"tmp":"tmp/dogsvr_0.0.4_1734792632516_0.6880507936805671","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@dogsvr/dogsvr","version":"0.4.1","keywords":["game-server","worker-threads","hot-update","tsrpc","grpc","dogsvr"],"author":{"name":"rowanzhu"},"license":"MIT","_id":"@dogsvr/dogsvr@0.4.1","maintainers":[{"name":"rowanzhu","email":"rowanzhu@gmail.com"}],"homepage":"https://github.com/dogsvr/dogsvr#readme","bugs":{"url":"https://github.com/dogsvr/dogsvr/issues"},"dist":{"shasum":"35e6d3ebf682d2455f07f0ce34c63f6168fb84e8","tarball":"https://registry.npmjs.org/@dogsvr/dogsvr/-/dogsvr-0.4.1.tgz","fileCount":33,"integrity":"sha512-N4CCiiFF8HyQhh49ijcwO+cjm52eQ4p6H7B/EakhQVCs4RF1DHgh4c+jI+MgmmQZEUUjpk0ZcQmsad5gWdr+ow==","signatures":[{"sig":"MEYCIQDwX0NBjZVnPCBk4jzNUgjoaRShdBH5Noapf/g6/zaKpwIhAPiqncOWpVxrwv/yjyxtw+8Z/pD3it7R9YBrZ9Cy3Vqu","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":68966},"exports":{"./main_thread":{"types":"./dist/main_thread/index.d.ts","default":"./dist/main_thread/index.js"},"./package.json":"./package.json","./worker_thread":{"types":"./dist/worker_thread/index.d.ts","default":"./dist/worker_thread/index.js"}},"gitHead":"5a41740c74705798007d66afcc20a4dbecbfdc7a","scripts":{"build":"rm -rf dist && tsc"},"_npmUser":{"name":"rowanzhu","email":"rowanzhu@gmail.com"},"repository":{"url":"git+https://github.com/dogsvr/dogsvr.git","type":"git"},"_npmVersion":"11.6.2","description":"Game server framework with main/worker thread separation, hot-update, and pluggable connection layers.","directories":{},"_nodeVersion":"24.13.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^6.0.3","@types/node":"^24.12.2"},"_npmOperationalInternal":{"tmp":"tmp/dogsvr_0.4.1_1777809908253_0.3926226283721581","host":"s3://npm-registry-packages-npm-production"}},"0.4.2":{"name":"@dogsvr/dogsvr","version":"0.4.2","description":"Game server framework with main/worker thread separation, hot-update, and pluggable connection layers.","keywords":["game-server","worker-threads","hot-update","tsrpc","grpc","dogsvr"],"exports":{"./main_thread":{"types":"./dist/main_thread/index.d.ts","default":"./dist/main_thread/index.js"},"./worker_thread":{"types":"./dist/worker_thread/index.d.ts","default":"./dist/worker_thread/index.js"},"./common":{"types":"./dist/common/index.d.ts","default":"./dist/common/index.js"},"./package.json":"./package.json"},"scripts":{"build":"rm -rf dist && tsc"},"repository":{"type":"git","url":"git+https://github.com/dogsvr/dogsvr.git"},"author":{"name":"rowanzhu"},"license":"MIT","bugs":{"url":"https://github.com/dogsvr/dogsvr/issues"},"homepage":"https://github.com/dogsvr/dogsvr#readme","dependencies":{},"devDependencies":{"@types/node":"^24.12.2","typescript":"^6.0.3"},"gitHead":"32e70c588d1fa842a5927e40bf6f09ce5c7c1c2c","_id":"@dogsvr/dogsvr@0.4.2","_nodeVersion":"24.13.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-i5jaNSnMLWlXlZcOKeLnt8GNluyoN14TJgvgQFOgsPfnzdpzl3LbbMM8GbD5+VfOTOAMAtCe5EdA3v/IUwNozw==","shasum":"0f922d644897544a21934d897120f67ac44f7905","tarball":"https://registry.npmjs.org/@dogsvr/dogsvr/-/dogsvr-0.4.2.tgz","fileCount":76,"unpackedSize":132793,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICKtXVPGCeNhkb9x0DBQXU3WwauI/bB0fkQyd3st8HfaAiEAuIk53qPu8mX9Z0RsBAraq+ju1JWVc5X75dzyO9CMzuY="}]},"_npmUser":{"name":"rowanzhu","email":"rowanzhu@gmail.com"},"directories":{},"maintainers":[{"name":"rowanzhu","email":"rowanzhu@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dogsvr_0.4.2_1785065446346_0.37572336949251817"},"_hasShrinkwrap":false}},"time":{"created":"2024-11-17T07:27:36.989Z","modified":"2026-07-26T11:30:46.696Z","0.0.1":"2024-11-17T07:27:37.306Z","0.0.2":"2024-12-08T09:49:07.582Z","0.0.4":"2024-12-21T14:50:32.670Z","0.4.0":"2026-05-03T10:25:17.966Z","0.4.1":"2026-05-03T12:05:08.403Z","0.4.2":"2026-07-26T11:30:46.517Z"},"bugs":{"url":"https://github.com/dogsvr/dogsvr/issues"},"author":{"name":"rowanzhu"},"license":"MIT","homepage":"https://github.com/dogsvr/dogsvr#readme","keywords":["game-server","worker-threads","hot-update","tsrpc","grpc","dogsvr"],"repository":{"type":"git","url":"git+https://github.com/dogsvr/dogsvr.git"},"description":"Game server framework with main/worker thread separation, hot-update, and pluggable connection layers.","maintainers":[{"name":"rowanzhu","email":"rowanzhu@gmail.com"}],"readme":"# @dogsvr/dogsvr\n\nNode.js game server framework built around a **main thread + worker thread** model: the main thread owns connections and routes messages, worker threads run business logic in parallel. Worker code is **hot-updatable**; connection layers are **pluggable**; message serialization is whatever you want (`Uint8Array` or `string`).\n\nThis package is the **entry point of the dogsvr polyrepo** — if you're new here, start with this README for the framework, then walk through [`example-proj`](https://github.com/dogsvr/example-proj) for a runnable three-server reference.\n\n## Ecosystem — the dogsvr polyrepo\n\nThe dogsvr stack is intentionally split into small, independently versioned git repos. Each repo publishes at most one or two npm packages; no monorepo, no workspaces.\n\n| Repo / package | Role |\n|---|---|\n| [`@dogsvr/dogsvr`](https://github.com/dogsvr/dogsvr) | **Framework core** — main thread, worker threads, load balancer, hot update, txn mgr, logger interface |\n| [`@dogsvr/logger`](https://github.com/dogsvr/logger) | Default pino-based NDJSON logger plugin (inline / central modes); registers itself when imported |\n| [`@dogsvr/cl-tsrpc`](https://github.com/dogsvr/cl-tsrpc) | TSRPC connection layer (WebSocket / HTTP) with per-connection auth + identity binding (`openId` / `zoneId` / `gid`) |\n| [`@dogsvr/cl-grpc`](https://github.com/dogsvr/cl-grpc) | gRPC connection layer for server-to-server unary calls |\n| [`@dogsvr/cfg-luban`](https://github.com/dogsvr/cfg-luban) | Runtime for reading Luban-generated game config — data lives in LMDB (mmap'd, outside the V8 heap), so all worker threads in the process share one pagecache-resident copy, and multiple Node processes on the same host share it via the OS pagecache too. FlatBuffers provides offset-based random access, so no upfront parse and no GC pressure from config tables |\n| [`@dogsvr/cfg-luban-cli`](https://github.com/dogsvr/cfg-luban-cli) | Codegen CLI: Excel → FlatBuffers → LMDB pipeline |\n| [`example-proj`](https://github.com/dogsvr/example-proj) | **Reference integration** — three servers (dir / zonesvr / battlesvr), Redis + MongoDB, Colyseus rooms |\n| [`example-proj-cfg`](https://github.com/dogsvr/example-proj-cfg) | Reference business config repo that feeds `cfg-luban-cli` |\n| [`example-proj-client`](https://github.com/dogsvr/example-proj-client) | Reference Phaser 4 web client for `example-proj` |\n\nYou pick which `@dogsvr/cl-*` packages to install; you pick whether to use `@dogsvr/cfg-luban`; you pick `@dogsvr/logger` (or supply your own `LoggerImpl`). The framework core only requires that any chosen plugin be imported at startup to self-register. See [Architecture](#architecture) below for how they fit together at runtime.\n\n## Features\n\n- **Multi-thread via Node `worker_threads`** — main thread runs one event loop for connections; N worker threads run business handlers. Messages between them are routed by a pluggable load-balancer (round-robin, random, least-load, consistent-hash by `gid`).\n- **Pluggable connection layers (CL)** — import any `@dogsvr/cl-*` package to self-register a factory; main thread wires inbound/outbound connections from JSON config. Roll your own CL by extending `BaseCL` / `BaseCLC`.\n- **Pluggable logger** — `log`, `LoggerImpl`, `LoggerHub`, `Level` are defined here; the implementation registers itself via `registerLogger()` (main) / `registerWorkerLogger()` (worker). Default plugin is [`@dogsvr/logger`](https://github.com/dogsvr/logger) (pino-based NDJSON, two modes); without a plugin a built-in console fallback prints human-readable lines and warns once.\n- **No serialization opinions** — `Msg.body` is `Uint8Array | string`. Protobuf, JSON, MsgPack, FlatBuffers — it's your call.\n- **Hot update of worker logic** — drain in-flight txns and replace workers without dropping connections. Two strategies: `rolling` (one at a time, default) or `allAtOnce` (all new, then drain old). Triggered via `pm2 trigger <name> hotUpdate` over the native pm2 IPC channel (no `tx2` dependency).\n\n## Requirements\n\n**Node.js**: tested on **v24.13.0 on Linux (x86-64)**; other maintained LTS lines are expected to work but are not routinely exercised. File an issue if something breaks on your runtime.\n\n## Install\n\n```sh\nnpm install @dogsvr/dogsvr\nnpm install @dogsvr/logger     # NDJSON output via pino (recommended)\nnpm install @dogsvr/cl-tsrpc   # pick your connection layer(s)\nnpm install @dogsvr/cl-grpc    # or gRPC, or both\n```\n\n> The `@dogsvr/dogsvr` package exposes two **subpath** imports only — there is no root entry. See [import paths](#import-paths) below.\n\n## Quick start\n\nMinimum two files: one that boots the main thread, one that runs in each worker.\n\n### `server.ts` (main thread entry)\n\n```ts\nimport * as dogsvr from '@dogsvr/dogsvr/main_thread';\nimport { setupLogger } from '@dogsvr/logger/main_thread';\nimport '@dogsvr/cl-tsrpc';  // self-registers \"tsrpc\" CL factory\nimport * as path from 'node:path';\n\nconst cfg = dogsvr.loadMainThreadConfig(path.resolve(__dirname, 'main_thread_config.json'));\nsetupLogger({ mode: 'inline', level: 'info' });  // read from cfg.log in practice; see Logger section\ndogsvr.startServer(cfg);\n```\n\n`main_thread_config.json` shape (mirrors `SvrConfig` + any business fields you read via `getMainThreadConfig<MyTypedConfig>()`):\n\n```json\n{\n    \"workerThreadRunFile\": \"./worker.js\",\n    \"workerThreadNum\": 2,\n    \"log\": { \"mode\": \"inline\", \"level\": \"info\" },\n    \"cl\":  { \"tsrpc\": { \"type\": \"tsrpc\", \"svrType\": \"ws\", \"port\": 20000 } },\n    \"clc\": {}\n}\n```\n\nValues like `workerThreadNum`, `port`, `mode`, and `level` are illustrative — tune them for your deployment.\n\nOptional fields: `lbStrategy`, `hotUpdateStrategy`, `workerConfigPath`, `hotUpdateTimeout`.\n\nYou can also pass a `SvrConfig` object directly to `startServer()` if you prefer programmatic setup.\n\n### `worker.ts` (runs in each worker thread)\n\n```ts\nimport * as dogsvr from '@dogsvr/dogsvr/worker_thread';\n\ndogsvr.workerReady(async () => {\n    dogsvr.loadWorkerThreadConfig();\n    // one-time init: set up logger, open DBs, etc.\n    // See Logger section below for setupLoggerInWorker() wiring.\n});\n\ndogsvr.regCmdHandler(10001, async (reqMsg) => {\n    const req = JSON.parse(reqMsg.body as string);\n    if (!req.name) {\n        throw new dogsvr.HandlerError(1001, 'name is required');\n    }\n    return JSON.stringify({ res: `hello, ${req.name}` });\n\n    // other valid returns:\n    //   return { body: '...', head: { serverVersion: '1.2.3' } };   // with head patch\n    //   return;                                                      // undefined → silent drop\n});\n```\n\n`respondCmd` / `respondError` are still exported as escape hatches for responding from a different async context, but the return-value / throw form above is the canonical handler shape.\n\n### Run\n\n```sh\npm2 start dist/server.js\npm2 trigger dist/server hotUpdate    # redeploy worker.js without dropping conns\n```\n\nFor a complete, runnable example with three servers, Redis/MongoDB integration, and room-based battles, see [`example-proj`](https://github.com/dogsvr/example-proj).\n\n## Import paths\n\n`@dogsvr/dogsvr` exposes **three subpaths** and no root:\n\n```ts\nimport * as dogsvr from '@dogsvr/dogsvr/main_thread';    // main-thread APIs\nimport * as dogsvr from '@dogsvr/dogsvr/worker_thread';  // worker-thread APIs\nimport { SabLineWriter } from '@dogsvr/dogsvr/common';   // SAB line-stream transport (for external plugins)\n```\n\nAttempting `require('@dogsvr/dogsvr')` returns `ERR_PACKAGE_PATH_NOT_EXPORTED` — this is **intentional**, so that code running in a worker can never accidentally pull in `startServer` (which would recursively spawn more workers).\n\nFull surface lists live in the barrel files: [`src/main_thread/index.ts`](src/main_thread/index.ts), [`src/worker_thread/index.ts`](src/worker_thread/index.ts), [`src/common/index.ts`](src/common/index.ts). For the design rationale (why no root, the single-sided rule, resolver compatibility), see [`docs/explanation/subpaths.md`](docs/explanation/subpaths.md).\n\n## Architecture\n\n![architecture diagram](https://github.com/user-attachments/assets/8903ee30-36c6-4922-a5d9-5a0715c1ded4)\n\n- **Main thread** owns the event loop for connections and dispatches messages to workers by command ID + routing fields (`gid` for consistent-hash LB).\n- **Worker threads** run your registered handlers. Workers never talk directly — cross-worker comms go through CLC callbacks routed by main.\n- **Messages** (`Msg`): `head` carries `cmdId`, routing fields, txn id, direction flags (`clcOptions` / `clOptions`), and error info; `body` is raw bytes or string.\n\n## Logger\n\nThe framework defines the logger contract (`Log`, `LoggerImpl`, `LoggerHub`, `Level`) and exposes a `log` proxy from both subpaths, but ships only a console-based fallback. For NDJSON output install [`@dogsvr/logger`](https://github.com/dogsvr/logger) and wire it once at startup; to plug in a different backend call `registerLogger()` / `registerWorkerLogger()` with your own `LoggerImpl`.\n\nSee [`docs/how-to/setup_logger.md`](docs/how-to/setup_logger.md) for the full wiring.\n\n## More\n\n- [Set up the logger](docs/how-to/setup_logger.md) — NDJSON output, worker wiring, alternative backends\n- [Subpaths](docs/explanation/subpaths.md) — three-subpath design, resolver compatibility, the single-sided rule, why no root\n- [SAB transport layers](docs/explanation/sab_transport_layers.md) — three-layer split (ring / line / msg), subpath exposure rule, hot-path invariants, hot-update drain trap\n- [SAB ring design](docs/explanation/sab_ring_design.md) — drain-reset vs classic modulo ring, back-pressure timing, fallback-layer interaction\n- [`src/common/` directory discipline](docs/explanation/common_directory_discipline.md) — what belongs in `common/`, auditing recipe, paired-strategy reshaping\n\nRelated repos in the dogsvr ecosystem:\n\n- Logger plugin: [`@dogsvr/logger`](https://github.com/dogsvr/logger)\n- Connection layers: [`@dogsvr/cl-tsrpc`](https://github.com/dogsvr/cl-tsrpc) · [`@dogsvr/cl-grpc`](https://github.com/dogsvr/cl-grpc)\n- Config pipeline: [`@dogsvr/cfg-luban`](https://github.com/dogsvr/cfg-luban) · [`@dogsvr/cfg-luban-cli`](https://github.com/dogsvr/cfg-luban-cli)\n- Reference integration: [`example-proj`](https://github.com/dogsvr/example-proj) · [`example-proj-cfg`](https://github.com/dogsvr/example-proj-cfg) · [`example-proj-client`](https://github.com/dogsvr/example-proj-client)\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","readmeFilename":"README.md"}