This document provides essential information for AI coding agents working in the PartyServer monorepo.
PartyServer is a monorepo using npm workspaces with multiple packages:
packages/partyserver- Core library for Durable Objects with WebSocket supportpackages/partysocket- Reconnecting WebSocket client librarypackages/y-partyserver- Yjs CRDT support for PartyServerpackages/partysub- Pub/sub at scalepackages/partysync- State synchronization (experimental)packages/partywhen- Task scheduling at scalepackages/hono-party- Hono middlewarefixtures/*- Self-contained examples
npm run build # Build all packages
npm run check # Run all checks (format, lint, type, test)
npm run format # Format code with Oxfmt
npm run check:format # Check code formatting with Oxfmt
npm run check:lint # Run Oxlint linter
npm run check:type # Type-check all packages
npm run check:test # Run all tests
npm run check:repo # Run sherif (monorepo consistency)npm run build # Build the package (uses tsdown)
npm run check:test # Run tests with vitest# Run all tests in a package
cd packages/partysocket && npm run check:test
# Run a single test file
npx vitest src/tests/reconnecting.test.ts
# Run tests in watch mode
npx vitest --watch
# Run tests with specific pattern
npx vitest reconnecting- Formatter: Oxfmt (configured in
.oxfmtrc.json) - Quote style: Double quotes (
") - Trailing commas: None
- Print width: 80
- Run
npm run formatbefore committing
- Linter: Oxlint (configured in
.oxlintrc.json) - Plugins:
react,jsx-a11y,typescript,react-hooks - Key rules:
no-explicit-any: offno-non-null-assertion: offno-redeclare: offno-unused-vars: error (with^_ignore patterns for args/vars/caught)react-hooks/exhaustive-deps: warn
- Run
npm run check:lintto verify
- Target: ESNext
- Module: ESNext with Bundler resolution
- Strict mode: Enabled
- JSX: react-jsx
- Use
noEmit: true(compilation handled by tsdown) - Use
verbatimModuleSyntax: true - Use
isolatedModules: true skipLibCheck: truefor performance
// 1. Import from relative modules first
import ReconnectingWebSocket from "./ws";
// 2. Then type imports (prefer `import type`)
import type * as RWS from "./ws";
import type { Connection } from "./types";
// 3. Use type-only imports when importing only types
// This helps with tree-shaking and clarity- Classes: PascalCase (e.g.,
PartySocket,ReconnectingWebSocket) - Functions/methods: camelCase (e.g.,
getPartyInfo,_handleOpen) - Private methods: Prefix with underscore (e.g.,
_connect,_debugLogger) - Constants: UPPER_SNAKE_CASE for true constants (e.g.,
PORT,DEFAULT) - Types/Interfaces: PascalCase (e.g.,
PartySocketOptions,EventHandlerOptions) - Type aliases: PascalCase for complex types, camelCase for simple utilities
// Use console.error for critical errors with helpful context
console.error(`‼️ No WebSocket implementation available...`);
// Use console.warn for warnings
console.warn(`PartySocket: party name "${name}" contains forward slash...`);
// For debug logging, use the debug flag pattern
private _debug(...args: unknown[]) {
if (this._options.debug) {
this._debugLogger("RWS>", ...args);
}
}
// Throw errors with descriptive messages
throw new Error("path must not start with a slash");
// Use assert for internal invariants
function assert(condition: unknown, msg?: string): asserts condition {
if (!condition) {
throw new Error(msg);
}
}- Use
// TODO:for action items - Use JSDoc for public API documentation
- Prefer descriptive names over comments
- Use
oxlint-disable-next-lineor@ts-expect-errorwith explanations when necessary:// oxlint-disable-next-line no-explicit-any // @ts-expect-error ws types are weird
- Group related functionality together
- Public methods before private methods
- Use
readonlyfor constructor parameters when appropriate - Prefer composition over inheritance
- Keep files focused (single responsibility)
- Use Vitest for all tests
- Place tests in
src/tests/directory - Use
@vitest-environment jsdomdirective when needed - Mock external dependencies appropriately
- Write descriptive test names
- Use
beforeAll,afterAll,beforeEach,afterEachfor setup/teardown
- Use Changesets for version management (
.changeset/) - Write clear, descriptive commit messages
- Keep commits focused on a single change
- Test before committing
- Dual format: ESM and CommonJS
- Generate both
.d.tsand.d.ctsdeclaration files - Run oxfmt on generated output files (handled by build scripts)
- Use
tsdownfor building packages - Verify exports with
scripts/check-exports.ts
- Avoid
forEachwhere performance matters (but allowed by linter) - Use optional chaining (
?.) and nullish coalescing (??) - Prefer
constoverletwhen possible - Be mindful of bundle size (tree-shaking friendly exports)
- Use EventTarget for event handling in browser/Node compatibility
- Clone events when re-dispatching them
- Use exponential backoff for reconnection logic
- Provide both callback and event listener APIs
- Support both string and function-based configuration