Developer guide

SnowLuma is a TypeScript + native-module hybrid. TypeScript handles runtime orchestration, the OneBot implementation, the protocol bridge, the SDK, and the WebUI; native modules cover the hook, injection, and the high-performance WebSocket implementation.

Monorepo layout

pnpm workspace with five packages:

SnowLuma/
├─ packages/
│  ├─ core/        @snowluma/core       Bridge / OneBot / Hook orchestration
│  ├─ websocket/   @snowluma/websocket  In-tree WS impl (uses native addon)
│  ├─ sdk/         @snowluma/sdk        Typed OneBot client for external use
│  ├─ webui/       webui                React + Vite console
│  └─ runtime/     distribution templates (launcher, package.json, scripts)
├─ native/         per-platform native artefacts (.node / .dll / .so)
├─ dist/           build output
├─ tools/          helper scripts (version bump, release, etc.)
├─ docs/           ADRs and developer notes
└─ package.json

Core startup chain

Entry point: packages/core/src/index.ts.

loadRuntimeConfig()           ← reads config/runtime.json / env
HookManager(autoLoadOnDiscovery)
BridgeManager
OneBotManager                 ← spins up OneBotInstance per UIN
initWebUI(port=webuiPort)     ← full builds only

What the runtime creates:

  • HookManager — discovers QQ main processes and injects the native addon. With hookAutoLoad: true, every new PID gets injected automatically.
  • BridgeManager — decodes hook messages from the named pipe into bridge events; caches rkey / contacts / group members.
  • OneBotManager — owns OneBotInstances keyed by UIN; each instance has its own MessageStore, MediaStore, and NetworkManager.
  • initWebUI — full builds boot the WebUI; default port 5099 (override via runtime.json.webuiPort).

Hook + native modules

The native hook module is loaded via process.dlopen(). Source lives in the separate dev/nnphook repo.

Filename convention:

snowluma-win32-x64.node    snowluma-win32-x64.dll
snowluma-linux-x64.node    snowluma-linux-x64.so
snowluma-linux-arm64.node  snowluma-linux-arm64.so

Load search paths:

native/
dist/native/
packages/runtime/native/

Native addon API:

  • getAllMainProcess — enumerate QQ main processes.
  • loadModuleManual — manually map the injection module into the target process.
  • unloadModuleManual — unload an injected module.

Default target process is QQ.exe on Windows, qq on Linux.

OneBot lifecycle

When the bridge detects a QQ session starting:

  1. Load config/onebot_<uin>.json (or copy from global if missing).
  2. Construct OneBotInstance.
  3. Boot HTTP / WS / reverse WS / HTTP-POST adapters per networks.* config.
  4. Asynchronously warm up the friend list, group list, and group members.
  5. Forward bridge events into OneBot events.

When the session closes the matching instance is released.

WebSocket package

@snowluma/websocket is the in-repo WebSocket implementation; its surface tracks ws closely while routing through a native fast path.

Exports:

  • WebSocket — client constructor.
  • WebSocketServer — server constructor.
  • Server — alias for WebSocketServer.
  • InternalWebSocket — internal connection implementation.

Loads its own platform-specific .node from the same native/ search paths.

SDK package

@snowluma/sdk is a typed OneBot client for downstream consumers — standalone-publishable to npm and independent of the SnowLuma runtime. It's built inside the monorepo (see pnpm build:sdk / build:all below); for consumer-side usage see the SDK docs.

Dev scripts

pnpm install
pnpm dev              # core dev mode
pnpm dev:web          # WebUI dev server
pnpm build            # core only
pnpm build:webui      # WebUI only
pnpm build:sdk        # SDK only
pnpm build:all        # core + SDK + WebUI
pnpm test             # core tests
pnpm typecheck        # workspace typecheck
pnpm lint             # workspace lint

Build order

Full distribution:

pnpm build:all

Runs, in order:

  1. @snowluma/core full build
  2. @snowluma/sdk
  3. webui

Output goes to the repo root dist/.

Docs site

The docs site lives in a separate repo: SnowLuma/SnowLumaDocs. Local development usually checks it out at dev/SnowLumaDocs/ alongside SnowLuma.

Stack: Rspress + React + TypeScript + MDX + KaTeX.

The OneBot API reference is generated by the docs repo's pnpm api:generate (also wired to prebuild) from docs/public/api/catalog.json — one page per action, plus a category overview and a searchable landing page. catalog.json is the action catalog produced by the main repo's collectActionDocs() (same shape as @snowluma/mcp's CatalogAction); the main repo's sync-docs-catalog workflow commits it here automatically via the SnowLuma bot on release — no manual upkeep.

Contribution notes

  • Don't bypass BridgeManager — every OneBot action should reach NTQQ through BridgeInterface. Keeps the OneBot layer decoupled and testable.
  • Keep configs auto-generatable — new fields must stay backwards-compatible; normalize them on load and write the result back.
  • Native modules are per-platform — when adding a platform, sync the .node and the injectable library.
  • Tests first — core OneBot behavior should be validated with vitest; see packages/core/tests/.
  • API docs automation — just add the action with defineAction (optionally returnsSchema to describe data); catalog.json is kept in sync by the sync-docs-catalog workflow, so the API reference never drifts. Run pnpm api:generate locally to preview.