@cobeo2004/proof-sub
v0.0.5
Published
A production-ready, real-time, type-safe publish-subscribe system with dynamic schema loading, automatic client code generation, and **full Node.js compatibility**.
Maintainers
Readme
🚀 ProofSub - A real-time, type-safe, dynamic pubsub system with auto-generated client code
A production-ready, real-time, type-safe publish-subscribe system with dynamic schema loading, automatic client code generation, and full Node.js compatibility.
✨ Features
- 🔄 Dynamic Schema Loading: Automatically watches for changes in your schema definitions
- 📋 Auto Code Generation: Generates complete TypeScript client code with types and interfaces
- 🔗 Real-time Updates: Broadcasts schema changes to all connected clients instantly
- 🛡️ Type Safety: Full TypeScript support with Zod validation
- ⚡ Hot Reload: No server restart needed when schemas change
- 🏗️ Auto-Setup: Creates schema files and directories automatically
- 🎯 Auto-Emit: Server automatically emits events based on defined schemas
- 📦 Easy SDK: Simple SDK that generates client code for you
- 🔧 Robust Error Handling: Comprehensive error messages and validation
- 📊 Health Monitoring: Built-in health checks and statistics
- 🖥️ CLI Tool: Command-line interface for easy client generation
- 🟢 Node.js Compatible: Works seamlessly in Node.js, Bun, and Browser environments
🚀 Quick Start (2 steps!)
1. Start the Server (Bun)
bun run start:example-serverThe server will automatically:
- ✅ Create
./proofsub/schema.ts(or path that you specify) if it doesn't exist - ✅ Start watching for schema changes
- ✅ Set up type-safe event emitters
2. Generate & Use Client (Node.js or Bun)
For Node.js:
# Install Node.js dependencies
npm run install:node
# Generate client for Node.js
npm run generate:example-client
# Use in your Node.js project// Node.js JavaScript
const { PubSubClient } = require("./generated.js");
const client = new PubSubClient("ws://localhost:3000");
await client.connect();
await client.subscribe("example.event", (data) => {
console.log("Event:", data.name);
});
await client.publish("example.event", {
id: "test-123",
name: "Hello from Node.js!",
createdAt: new Date(),
});For TypeScript (Node.js):
// Node.js TypeScript
import { PubSubClient } from "./generated";
const client = new PubSubClient("ws://localhost:3000", {
debug: true,
maxReconnectAttempts: 5,
});
await client.connect();
// Full type safety!
await client.subscribe("example.event", (data) => {
console.log("Event:", data.name); // TypeScript knows data.name exists!
});🟢 Node.js Setup
Install Dependencies
# For Node.js users
npm run install:node
# Or manually
npm install ws @types/ws tsx esbuild-registerGenerate Client for Node.js
# Generate JavaScript client
npm run generate -- -o ./generated.js
# Generate TypeScript client
npm run generate -- -o ./generated.ts
# Watch for changes (Node.js)
npm run generate:node -- --watch🎯 SDK Usage
The SDK works identically in both Node.js and Bun environments:
Generate Once
# Bun
bun run generate
# Node.js
npm run generate:node
# Custom output for Node.js
npm run generate:node -- -o ./src/pubsub-client.jsWatch for Changes
# Bun
bun run generate:watch
# Node.js
npm run generate:node -- --watch --debugProgrammatic Usage (Node.js)
import { generatePubSubClientOnce } from "./sdk/pubsub-sdk";
// Works in Node.js with 'ws' package
await generatePubSubClientOnce("ws://localhost:3000", "./my-client.ts");🎮 Examples
Node.js Examples
# Terminal 1: Start server (Bun)
bun run start
# Terminal 2: Run Node.js JavaScript example
npm run example:node
# Terminal 3: Run Node.js TypeScript example
npm run example:node-tsCross-Platform Workflow
# Server (Bun)
bun run start
# Client Generation (Node.js)
npm run generate:node -- --watch
# Your Node.js Application
node your-app.js # Uses ./generated.js🔧 Environment Compatibility
| Environment | Server | SDK | Generated Client |
| ----------- | ---------- | ------------------- | ---------------- |
| Bun | ✅ Primary | ✅ Native | ✅ Full Support |
| Node.js | ✅ | ✅ With ws | ✅ Full Support |
| Deno | ✅ | ✅ With ws | ✅ Full Support |
| Browser | ❌ | ✅ Native WebSocket | ✅ Full Support |
WebSocket Dependencies
The system automatically detects your environment:
- Browser: Uses native
WebSocket - Bun: Uses native WebSocket support
- Node.js: Uses
wspackage (install withnpm install ws)
🛠️ Generated Client Features
The generated client works identically across all environments:
// Generated client features (same API everywhere)
export class PubSubClient {
constructor(serverUrl: string, config?: PubSubClientConfig);
// Connection management
async connect(): Promise<void>;
disconnect(): void;
isConnected(): boolean;
// Type-safe pub/sub
async subscribe<T>(
event: T,
callback: (data: EventTypes[T]) => void
): Promise<PubSubSubscription>;
async publish<T>(event: T, data: EventTypes[T]): Promise<void>;
async unsubscribe(subscriptionId: string): Promise<void>;
// Utilities
getStatus(): ClientStatus;
getActiveSubscriptions(): string[];
// Auto-generated typed methods (based on your schemas)
async subscribeExampleEvent(
callback: (data: ExampleEventEvent) => void
): Promise<PubSubSubscription>;
async publishExampleEvent(data: ExampleEventEvent): Promise<void>;
}🖥️ CLI Commands
Works with both Bun and Node.js:
# Bun
bun run generate # Basic generation
bun run generate:watch # Watch for schema changes
bun run generate:debug # Watch with debug logging
# Node.js
npm run generate:node # Basic generation
npm run generate:node -- --watch # Watch for schema changes
npm run generate:node -- --debug # Debug logging
# CLI options (same for both)
--server <url> # WebSocket server URL
--output <path> # Output path for generated client
--watch # Watch for schema changes
--debug # Enable debug logging🏗️ How It Works
1. Server (Bun Only)
📁 Created directory: ./proofsub
📄 Created default schema file: ./proofsub/schema.ts
✅ Schemas loaded successfully: example.event
👀 Watching schema file: ./proofsub/schema.ts
🚀 PubSub server running on http://localhost:30002. Client Generation (Node.js or Bun)
🚀 PubSub Client Generator
📡 Server: ws://localhost:3000
📁 Output: ./generated.js
🔧 Generating client code...
✅ Client code generated successfully!3. Universal Client Usage
The generated client works the same everywhere:
// Works in Node.js, Bun, and Browser
const client = new PubSubClient("ws://localhost:3000");
await client.connect();
// ... same API everywhere📊 Monitoring & Health Checks
Health Endpoint
curl http://localhost:3000/healthResponse:
{
"connectedClients": 3,
"availableEvents": ["example.event"],
"totalEvents": 1,
"uptime": 1234.56
}🔧 Message Types
| Type | Direction | Description |
| --------------- | --------------- | -------------------------- |
| get_schema | SDK → Server | Request latest schema |
| schema_update | Server → SDK | Schema/code update |
| subscribe | Client → Server | Subscribe to an event |
| unsubscribe | Client → Server | Unsubscribe from an event |
| publish | Client → Server | Publish an event with data |
| event | Server → Client | Subscribed event data |
| error | Server → Client | Error with details |
📁 File Structure
├── server/ # Bun server
│ ├── index.ts # Main server entry point
│ ├── pubsub-server.ts # Robust PubSub server class
│ ├── schema-loader.ts # Dynamic schema loading & watching
│ ├── code-generator.ts # Client code generation
│ └── event-emitter-2.ts # Type-safe event emitter
├── sdk/ # Universal SDK (Node.js + Bun)
│ └── pubsub-sdk.ts # Code generator SDK
├── cli/ # Universal CLI
│ └── generate-client.ts # CLI tool for client generation
├── examples/ # Platform-specific examples
│ ├── node-simple-client.js # Node.js JavaScript example
│ └── node-typescript-client.ts # Node.js TypeScript example
├── proofsub/
│ └── schema.ts # Your event schemas (auto-created)
├── generated.ts # Auto-generated TypeScript client
├── generated.js # Auto-generated JavaScript client
└── README.md # This file🎮 Complete Examples
Node.js JavaScript Example
// examples/node-simple-client.js
const { generatePubSubClientOnce } = require("../sdk/pubsub-sdk.ts");
async function main() {
// Generate client
await generatePubSubClientOnce("ws://localhost:3000", "./generated.js");
// Use generated client
const { PubSubClient } = require("../generated.js");
const client = new PubSubClient("ws://localhost:3000");
await client.connect();
await client.subscribe("example.event", (data) => {
console.log("Received:", data);
});
await client.publish("example.event", {
id: "test",
name: "Hello Node.js!",
createdAt: new Date(),
});
}Node.js TypeScript Example
// examples/node-typescript-client.ts
import { generatePubSubClientOnce } from "../sdk/pubsub-sdk";
async function main() {
await generatePubSubClientOnce("ws://localhost:3000", "./generated.ts");
const { PubSubClient } = await import("../generated.ts");
const client = new PubSubClient("ws://localhost:3000", {
debug: true,
maxReconnectAttempts: 5,
});
await client.connect();
// ... full type safety!
}🚨 Error Handling
Node.js Specific Errors
❌ WebSocket not available. In Node.js, please install the "ws" package: npm install ws @types/ws
💡 Solution:
npm run install:nodeSchema Validation Errors
// Same error format across all environments
{
"type": "error",
"message": "Validation error for event 'example.event'",
"details": {
"errors": [...],
"receivedData": {...}
}
}🔒 Production Ready
Cross-Platform Deployment
# Server (Bun)
bun run build
bun run dist/index.js
# Client Generation (Node.js CI/CD)
npm run generate:node -- --output ./dist/pubsub-client.js
# Your Node.js Application
node dist/your-app.jsResource Cleanup
- Automatic client cleanup on disconnect
- Memory leak prevention
- File watcher cleanup
- Event listener cleanup
- Cross-platform compatibility
📈 Performance
- Minimal Memory Footprint: Efficient event handling
- Fast Schema Reloading: < 100ms schema updates
- Concurrent Connections: Handles hundreds of clients
- Type-Safe: Zero runtime type checking overhead
- Fast Generation: Client code generated in milliseconds
- Universal: Same performance across Node.js, Bun, and Browser
🤝 Contributing
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Test on both Node.js and Bun
- Submit a pull request
📝 Roadmap
- [ ] Add authentication string for both client and server
- [ ] Add support for multi-server instances
- [x] Add further support for different environments (e.g. Deno, Cloudflare Workers, etc.)
- [x] Add more Zod types, especially for
zod-form-data(deprecated, instead make compatible withzod-v4), - [ ] Ping every 10 seconds to keep the connection alive
- [ ] Generate Python Client Code
📄 License
MIT License - see LICENSE file for details
Ready to build real-time, type-safe applications across all JavaScript environments? 🚀
# Server (Bun)
bun run start
# Client (Node.js)
npm run install:node
npm run generate:node
node your-app.js
# Client (Bun)
bun run generate
bun run your-app.ts