Commit Graph
9 Commits
Author SHA1 Message Date
DrSmoothl 056188d63d chore: resolve async SQLite merge conflicts
Integrate the current development branch, preserve the album comment fixes, and align the changes with repository formatting and dependency tooling.
2026-10-13 09:55:16 +08:00
手瓜一十雪 e699351f90 feat: adopt async SQLite and improve messaging and runtime diagnostics 2026-10-12 15:44:55 +08:00
DrSmoothl 7c0519f75f lint 2026-10-12 15:43:34 +08:00
DrSmoothl e16fa78b55 fix(onebot): distinguish private poke conversations
Preserve the private conversation peer separately from the poke sender and target. Emit NapCat-compatible user_id and sender_id fields while keeping group notices unchanged.

Add MsgPush and event-converter regression coverage for self-pokes across multiple friend sessions.

Fixes #285.
2026-07-25 20:28:28 +08:00
DrSmoothl e9ae2ec751 feat(log): show ARK card title in JSON segment preview (#96)
The JSON segment preview was a fixed "[JSON]" placeholder, hiding both
real card titles and QQ's server-side fallback prompts (e.g. cardId
-896954183 "当前QQ版本不支持此应用,请升级", which is what #96 reported
seeing). Best-effort extract a title from the common ARK fields —
meta.{detail_1,detail,news,mannounce,music,video}.title, single-section
meta, then root.prompt / root.desc — and render as "[卡片:...]"; fall
back to "[JSON]" on parse failure or an unrecognised schema. Title is
truncated at 30 chars so a long prompt cannot blow up the log line.

OneBot segment shape is unchanged: downstream consumers still get the
full payload at data.data; this is purely a log-preview readability fix.
The helper is pure best-effort and never throws — every failure path
falls through to the existing "[JSON]" output.
2026-06-11 20:47:54 +08:00
游手好闲的言柒 d2a67cb560 fix(onebot): add canonical fields to file segment and fix log rendering (#94)
* fix(onebot): support inline file url/path in send_group/private_msg

* test(onebot): update file segment parser test for inline url/path support

* fix(onebot): add canonical fields to file segment and fix log rendering
2026-06-11 15:40:47 +08:00
DrSmoothl c16064d7e3 refactor(packages): rename @snowluma/bridge → @snowluma/protocol
The package previously named "bridge" houses the protocol-byte layer
(OIDB cmds, msg-push decoders, highway uploaders, element-builder,
event bus). The name "bridge" suggested transport/lifecycle, which it
isn't — that role lives in core/hook and core/bridge/manager. Rename
to match what's actually inside.

This is a pure rename: zero logic changes, all 73 import sites updated
mechanically and TS-verified. core/onebot dependencies key updated.
ESLint override path adjusted for the moved oidb-services directory.

Rename detection threshold: git log --find-renames=20% recommended
when following history across this commit — content-replacement
(@snowluma/bridge → @snowluma/protocol) dropped per-file similarity
below git's default 50% on import-heavy files.
2026-05-23 23:31:03 +08:00
DrSmoothl f7a03ca05a refactor(bridge): extract protocol layer into @snowluma/bridge package
Phase 2 of the 4-package split (RoadMap #3). Moves ~35 files —
events / event-bus / identity-service / packet-pipeline / element-
builder / bridge-oidb / qq-info / msg-push/* / highway/* / web/* +
the bridge-side formatters — out of `packages/core/src/bridge/`
into the new `@snowluma/bridge` workspace package. Everything that
translates QQ wire bytes ↔ typed events/elements now lives there.

Why
---
- `packages/core/src/bridge/` was actually two layers: a low-level
  "protocol decoder + I/O" set (msg-push, highway, packet-pipeline,
  identity, element-builder) AND the Api-class host (bridge.ts +
  apis/*). The Api layer can't move without the protocol layer
  moving first, but the two had grown into one directory.
- Bridge-internal consumers (highway uploaders, OIDB envelope
  helper, element-builder, msg-push parsers) only ever needed
  `bridge.identity` + `bridge.sendRawPacket` + the upload-metadata
  cache. Splitting them out lets that minimal surface live in the
  bridge package as `BridgeContext` while the api-layer's extended
  context (with `apis: ApiHub`) stays in @snowluma/core.

What stays in @snowluma/core (apis layer):
  - bridge.ts          ── the god-class that composes the protocol
                          building blocks + mounts apis
  - bridge-interface.ts ── public façade for OneBot consumers
  - manager.ts          ── per-uin BridgeManager hub
  - apis/*              ── the 13 typed Api classes
  - bridge-context.ts (NEW) ── extends @snowluma/bridge's slim
                              BridgeContext with `apis: ApiHub` so
                              the 13 Api classes keep their typed
                              `this.ctx.apis.X.method()` access.

Layout
------
Moved via `git mv` (history preserved):
  events / event-bus / identity-service / packet-pipeline /
  element-builder / bridge-oidb / qq-info / msg-push/* /
  highway/* / web/*           → @snowluma/bridge/<sub>
  utils/event-format.ts        → @snowluma/bridge/format.ts

  (the last one renamed because the destination directory only has
  bridge-related files; `format.ts` reads cleaner than `event-format`.
  Listed as a rename in git's `RM` output — content unchanged.)

Layering fixes (functionality preserved, just type signatures)
--------------------------------------------------------------
- `element-builder.SendContext.bridge` → typed as `BridgeContext`
  instead of `Bridge`. Reads only `bridge.identity` and the
  upload-cache (both on BridgeContext); the concrete `Bridge`
  instance still passes via free upcast.
- `bridge-oidb.runOidb` signature widened from `Bridge` to
  `BridgeContext` — same reason.
- `highway/{highway-client,pipeline,image-upload,ptt-upload,
  video-upload}.ts` — same.
- `format.ts::formatReply` parameter typed as a new local
  `ReplyEventLookup` structural type (`{ findEvent(id): JsonObject |
  null }`) instead of `MessageStore` from @snowluma/onebot. The
  OneBot `MessageStore` is a structural superset; consumers pass
  it through unchanged.
- JSON value types moved to a new `@snowluma/common/json` subpath
  (consumed by format.ts) — `onebot/types.ts` re-exports them so
  external `import { JsonValue } from '<…>/onebot/types'` paths
  keep working.
- `UploadedFileMeta` interface moved from `core/src/bridge/bridge.ts`
  into `@snowluma/bridge/bridge-context.ts` — element-builder + the
  forward-builder both read the upload cache through BridgeContext,
  so the type has to live in @snowluma/bridge. `bridge.ts` keeps
  its re-export for back-compat.

Changes
-------
- New package `packages/bridge/` (package.json with per-file subpath
  exports mirroring legacy `core/src/bridge/<x>` layout 1:1,
  tsconfig.json, typecheck script).
- 35 `.ts` files moved via `git mv` (3 files counted by git as
  RM — rename + modify because Bridge → BridgeContext type swap).
- 150+ import sites rewritten across `packages/core/src` and
  `packages/core/tests`: `'../bridge/<x>'`, `'../../bridge/<x>'`,
  `'../src/bridge/<x>'`, `'@/bridge/web/<x>'`, and vitest
  `vi.mock(...)` literals all collapse to `@snowluma/bridge/<x>`.
- `@snowluma/core` depends on `@snowluma/bridge` (workspace:*).
- `@snowluma/bridge` depends on `@snowluma/common`,
  `@snowluma/proto-defs`, `@snowluma/proton`.
- `packages/core/src/utils/` directory removed (empty).

Verification
------------
- Full workspace `pnpm -r typecheck`: all 10 projects clean.
- core test suite: 552 passed / 552 total (pre-existing
  websocket-darwin-arm64.node addon failure unchanged — same
  baseline as the previous refactor commits).
- Vite build (with stubbed native binary): clean — 143 modules,
  2.84 MB bundle / 224 KB gzip, identical envelope to the
  pre-split build.

Phase 3 (next): OneBot + WebUI move into @snowluma/onebot. The
runnable `index.ts` stays in @snowluma/core as the application
entry, importing `OneBotManager` from `@snowluma/onebot`.
2026-05-21 08:41:34 +08:00
DrSmoothl 257686eac6 feat(logger): identity-aware readable event rendering
Notice events (recall / join / leave / poke / admin / mute / essence
/ request / invite) and the received-message log now resolve group
IDs and user IDs against the Identity cache so output reads as
human names instead of raw QQ numbers.

Before:
  [Event] 群撤回 12345 | 67890 被 99999 撤回
  [Event] 群 12345 | NickName(67890): ID:42 你好 [图片]

After:
  [Event] 群撤回 [SnowLuma群(12345)] | [Alice(67890)] 被 [Bob(99999)] 撤回
  [Event] 群 [SnowLuma群(12345)] | [Alice(67890)]: ID:42 你好 [图片]

Reply segments now expand one level via messageStore.findEvent —
"[回复:42]" becomes "[回复 [Alice(100)]: 早安]" when the original
is still in the message store, falling back to the bare id when it
isn't.

New file utils/event-format.ts owns:
  - formatGroup / formatUser     identity-aware name resolution
  - formatMessageSegments         shared element preview (replaces
                                  the inline switch in
                                  logReceivedMessage)
  - formatReply                   one-level reply chain expansion
  - formatEvent                   notice-class event renderer

Every formatter wraps its lookup in try/catch and degrades to the
prior numeric form on cache miss / throw, so log formatting can
never crash the calling path. The QQ numeric ID is preserved
alongside the name so third-party parsers that scrape uids still
find them.

26 unit tests cover cache hit / miss, malformed input, throw
recovery, and per-event-kind rendering shapes.
2026-05-18 12:32:18 +08:00