{"id":50309342,"url":"https://github.com/cinderblock/ghostcom","last_synced_at":"2026-05-28T19:30:24.275Z","repository":{"id":352487323,"uuid":"1211272461","full_name":"cinderblock/ghostcom","owner":"cinderblock","description":"Virtual COM port creation for Node.js and Bun on Windows — high-performance native duplex streams with tappable serial control signals","archived":false,"fork":false,"pushed_at":"2026-04-19T19:32:41.000Z","size":274,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-04-19T21:28:15.951Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cinderblock.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-15T08:21:24.000Z","updated_at":"2026-04-19T19:32:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cinderblock/ghostcom","commit_stats":null,"previous_names":["cinderblock/ghostcom"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/cinderblock/ghostcom","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cinderblock%2Fghostcom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cinderblock%2Fghostcom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cinderblock%2Fghostcom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cinderblock%2Fghostcom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cinderblock","download_url":"https://codeload.github.com/cinderblock/ghostcom/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cinderblock%2Fghostcom/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33624202,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-28T19:30:23.666Z","updated_at":"2026-05-28T19:30:24.265Z","avatar_url":"https://github.com/cinderblock.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GhostCOM\n\nVirtual COM port creation for Node.js and Bun on Windows.\n\nCreate fake serial ports that appear as real COM ports to the operating system. External applications can open and use them as if they were physical serial devices, while your Node.js/Bun code controls the other end through a high-performance native duplex stream.\n\n## Features\n\n- **Real COM ports** — Ports appear in Device Manager and are discoverable by any Windows application\n- **High-performance native streams** — Zero-copy data path via overlapped I/O on a kernel driver, surfaced as a Node.js `Duplex` stream\n- **Byte-agnostic** — Data flows at native speed regardless of baud rate, parity, or other serial line settings\n- **Tappable control signals** — Observe every serial configuration change (baud rate, DTR/RTS, flow control, etc.) as events\n- **Null-modem crossover** — Companion-side DTR/RTS appear as DSR+DCD / CTS on the COM side\n- **Node.js \u0026 Bun** — Works with both runtimes via N-API\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│  Your Application (Node.js / Bun)                           │\n│                                                             │\n│  const port = await createPort({ portNumber: 10 });         │\n│  port.stream.pipe(port.stream);  // echo                    │\n│  port.on(\"signal\", (s) =\u003e console.log(s.baudRate));         │\n└──────────────┬──────────────────────────┬───────────────────┘\n               │ Duplex stream            │ Signal events\n               ▼                          ▼\n┌─────────────────────────────────────────────────────────────┐\n│  Rust Native Addon (napi-rs)                                │\n│  Overlapped I/O threads + ThreadsafeFunction callbacks      │\n└──────────────┬──────────────────────────┬───────────────────┘\n               │ ReadFile/WriteFile       │ DeviceIoControl\n               ▼                          ▼\n┌─────────────────────────────────────────────────────────────┐\n│  KMDF Kernel Driver                                         │\n│  \\\\.\\GCOM\u003cN\u003e           ←──ring buffers──→  \\\\.\\COM\u003cN\u003e       │\n│  (companion device)     (signal state)     (serial port)    │\n└──────────────────────────────────────────┬──────────────────┘\n                                           │\n                                           ▼\n                              External application\n                              (PuTTY, firmware tools, etc.)\n```\n\n## Quick Start\n\n```ts\nimport { createPort, SignalChanged } from \"ghostcom\";\n\n// Create a virtual COM port\nconst port = await createPort({ portNumber: 10 });\nconsole.log(`Created ${port.portName}`); // \"COM10\"\n\n// Respond to data from external applications\nport.stream.on(\"data\", (chunk) =\u003e {\n  console.log(\"Received:\", chunk);\n  port.stream.write(Buffer.from(\"ACK\\r\\n\"));\n});\n\n// Monitor serial configuration changes\nport.on(\"signal\", (state) =\u003e {\n  if (state.changedMask \u0026 SignalChanged.BAUD) {\n    console.log(`Baud rate changed to ${state.baudRate}`);\n  }\n});\n\n// Know when an app opens/closes the port\nport.on(\"com-open\", () =\u003e {\n  console.log(\"External application connected\");\n  port.setSignals({ dtr: true, rts: true }); // Assert DSR+CTS\n});\n\n// Clean up\nawait port.destroy();\n```\n\n## Prerequisites\n\n### Driver Installation\n\nGhostCOM requires a kernel-mode driver to create real COM port devices. The driver must be built with the Windows Driver Kit and installed with administrator privileges.\n\n**Requirements:**\n\n1. **Visual Studio 2022** with the \"Desktop development with C++\" workload\n2. **Windows SDK** (included with VS)\n3. **Windows Driver Kit (WDK)** — [Download](https://learn.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk)\n4. **Test signing enabled** (for development):\n   ```powershell\n   bcdedit /set testsigning on\n   # Reboot required\n   ```\n\n**Build and install the driver:**\n\n```powershell\n# Build\nbun run build:driver\n\n# Self-sign for testing\nbun run build:driver -- -Sign\n\n# Install (requires Administrator)\nbun run install:driver\n```\n\n### Native Addon\n\nThe Rust native addon requires:\n\n1. **Rust toolchain** — [Install via rustup](https://rustup.rs/)\n2. **MSVC target**: `rustup target add x86_64-pc-windows-msvc`\n\n```bash\nbun install\nbun run build:addon\nbun run build:ts\n```\n\n## API\n\n### `createPort(options?): Promise\u003cVirtualPort\u003e`\n\nCreate a new virtual COM port.\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `portNumber` | `number` | COM port number (e.g., 10 for COM10). Auto-assigned if omitted. |\n\n### `VirtualPort`\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `portName` | `string` | Port name, e.g. `\"COM10\"` |\n| `portNumber` | `number` | Port number |\n| `stream` | `Duplex` | Bidirectional byte stream |\n| `signals` | `SignalState` | Last known signal state snapshot |\n| `isComOpen` | `boolean` | Whether an external app has the port open |\n| `destroyed` | `boolean` | Whether the port has been destroyed |\n\n| Method | Description |\n|--------|-------------|\n| `setSignals({ dtr?, rts? })` | Set companion output signals (DTR→DSR+DCD, RTS→CTS) |\n| `destroy(): Promise\u003cvoid\u003e` | Tear down the port and remove it from the system |\n\n| Event | Payload | Description |\n|-------|---------|-------------|\n| `\"signal\"` | `SignalState` | Any serial configuration change |\n| `\"com-open\"` | — | External app opened the COM port |\n| `\"com-close\"` | — | External app closed the COM port |\n| `\"error\"` | `Error` | Unrecoverable error |\n\n### `SignalState`\n\n```ts\ninterface SignalState {\n  sequenceNumber: number;\n  changedMask: number;    // Use SignalChanged.* constants\n  baudRate: number;\n  dataBits: 5 | 6 | 7 | 8;\n  stopBits: \"one\" | \"one-five\" | \"two\";\n  parity: \"none\" | \"odd\" | \"even\" | \"mark\" | \"space\";\n  dtr: boolean;\n  rts: boolean;\n  breakState: boolean;\n  handflow: HandFlow;\n  specialChars: SpecialChars;\n  waitMask: number;\n}\n```\n\n### `SignalChanged` Constants\n\n```ts\nSignalChanged.BAUD         // Baud rate changed\nSignalChanged.LINE_CONTROL // Data bits, stop bits, or parity changed\nSignalChanged.DTR          // DTR asserted or cleared\nSignalChanged.RTS          // RTS asserted or cleared\nSignalChanged.BREAK        // Break state changed\nSignalChanged.HANDFLOW     // Flow control configuration changed\nSignalChanged.CHARS        // Special characters changed\nSignalChanged.WAIT_MASK    // WaitCommEvent mask changed\nSignalChanged.COM_OPEN     // External app opened the COM port\nSignalChanged.COM_CLOSE    // External app closed the COM port\n```\n\n### Utility Functions\n\n```ts\nlistPorts(): PortInfo[]          // List active virtual ports\nisDriverInstalled(): boolean     // Check if the driver is loaded\ndriverVersion(): string | null   // Get driver version\n```\n\n## Examples\n\n```bash\n# Echo server — echoes all data back to the sender\nbun run examples/echo.ts 10\n\n# Signal monitor — log all serial config changes\nbun run examples/signal-monitor.ts 20\n\n# Virtual null-modem pair — bridge two ports together\nbun run examples/pair.ts 10 11\n```\n\n## How It Works\n\n### Data Flow\n\n1. External app writes bytes to COM10 via `WriteFile`\n2. The kernel driver's COM-side write handler copies bytes into the **ComToCompanion** ring buffer (64KB, lock-free SPSC)\n3. If the companion has a pending read, the driver immediately satisfies it from the ring buffer\n4. The Rust addon's read thread (blocked on overlapped `ReadFile`) wakes up with the data\n5. The read thread invokes a `ThreadsafeFunction` to push the `Buffer` onto the JS event loop\n6. `VirtualPortStream.push(chunk)` delivers the data to your stream consumer\n\nThe reverse direction (your code → external app) follows the symmetric path through the **CompanionToCom** ring buffer.\n\n### Signal Flow\n\n1. External app calls `SetCommState` (or similar) to set baud rate to 115200\n2. Windows sends `IOCTL_SERIAL_SET_BAUD_RATE` to the COM device\n3. The driver updates `SignalState.BaudRate`, increments the sequence number, sets `ChangedMask |= GCOM_CHANGED_BAUD`\n4. The driver completes any pending `IOCTL_GCOM_WAIT_SIGNAL_CHANGE` on the companion device\n5. The addon's signal-watcher thread receives the `GcomSignalState` struct\n6. It invokes a `ThreadsafeFunction` to deliver the decoded `SignalState` to JS\n7. `VirtualPort` emits `\"signal\"` with the full state snapshot\n\n### Null-Modem Crossover\n\nThe driver implements standard null-modem signal crossover:\n\n| Your code sets | External app sees |\n|---------------|-------------------|\n| `dtr: true` | DSR + DCD asserted |\n| `rts: true` | CTS asserted |\n\n| External app sets | Your code sees |\n|-------------------|---------------|\n| DTR | `signal.dtr === true` |\n| RTS | `signal.rts === true` |\n\n## Driver Signing\n\nFor development, the driver can be self-signed with test signing enabled. For production distribution:\n\n1. Obtain an EV code signing certificate\n2. Run the driver through Microsoft's [Hardware Lab Kit (HLK)](https://learn.microsoft.com/en-us/windows-hardware/test/hlk/)\n3. Submit for [attestation signing](https://learn.microsoft.com/en-us/windows-hardware/drivers/dashboard/code-signing-attestation) via the Hardware Dev Center\n\nAlternatively, consider a UMDF v2 (User-Mode Driver Framework) port, which only requires standard Authenticode signing.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcinderblock%2Fghostcom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcinderblock%2Fghostcom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcinderblock%2Fghostcom/lists"}