refactor(mcp): распил client.ts (5206 строк) на доменные модули за тонким фасадом (#450) #478
Reference in New Issue
Block a user
Delete Branch "refactor/450-split-client"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
packages/mcp/src/client.tsбыл god-object'ом на 5206 строк / ~65 методов / 5 ответственностей — любая правка рисковала всем write-path, обработка ошибок неоднородна. Разнесли на доменные модули;DocmostClientостаётся тонким фасадом с неизменным внешним контрактом. Чистый структурный рефакторинг, поведение не меняется. closes #450Стоит стопкой на #449 (
refactor/449-write-invariants, PR #475) — база указывает на неё, в диффе только распил. Мержить после #475 (тогда перенацелю базу на develop).Структура
client.ts(93 строки) композирует 10 миксинов над общим абстрактным базовым классом.DocmostClientи переопределяют seam'ы (mutatePage/replacePage/resolvePageId/getPageRaw/…), ожидая, что методы в других модулях увидят override черезthis.. Единая цепочка прототипов сохраняет виртуальную диспетчеризацию; context-object её бы сломал.client/context.ts(база, ≤700): всё общее состояние (axios, apiUrl, токены, кэши resolvePageId/collab-token, sandbox/metrics-синки), конструктор + оба интерсептора,login/ensureAuthenticated/paginateAll/resolvePageId/mutateLiveContentUnlocked+ write-seam'ы.private→protected(внутреннее, не в публичном.d.ts).read,pages,nodes-write,media(images/attachments/drawio),comments,transforms(markdown + JS-sandboxtransformPage),tables,stash,doc-validate.errors.ts— единый REST error-mapping (formatDocmostAxiosError, довершение #437; тексты сообщений без изменений).Внешний контракт — СОХРАНЁН (доказано компиляцией с ОБЕИХ сторон)
DocmostClientчерезimplements IXMixin-интерфейсы (без ручного зеркала, #446).tscпакета → 0 ошибок вclient/,client.ts,tool-specs.ts.apps/servertype-probe →Pick<DocmostClient, DocmostClientMethod>(loader) иPick(tool-specs) резолвятся, реальныйDocmostClientприсваивается обоим (rc=0).replaceImageдержит одинwithPageLockсmutateLiveContentUnlockedвнутри (#425); self-resolve UUID (#449); единый error-путь. Ни одного дубля публичного метода (stub+impl всегда затеняется реальной реализацией).zod v3→v4
Investigate-only, рекомендация отложить: SDK 1.29 поддерживает v4 (peer
^3.25 || ^4.0),tool-specs.tsиспользует только v3/v4-общий поднабор — но мажор-бамп трогает всю схема-поверхность и оба хоста, смешивать со структурным распилом рискованно. Отдельным follow-up.How verified
mcptscчисто (2 pre-existingws-типа в нетронутомlib/, идентичны базе);node --test— 800/800 (== база, рефакторинг поведения не добавляет).docmost-client.loaderjest прошёл; type-probe обеихPick— rc=0.Checklist
Стоит стопкой на #449 (PR #475) — база указывает на refactor/449, в диффе только распил client.ts. Мержить после #475; тогда перенацелю базу на develop (учёл урок с прошлой стопкой — при мерже базу надо ставить develop).
Что: god-object client.ts (5206 строк) → фасад 93 строки + 11 модулей в client/ через миксины над общим базовым классом. Внешний контракт неизменен. Единый REST error-helper. zod v4 — investigate, отложил (findings в теле PR).
Проверка: mcp tsc чисто, node --test 800/800 (== база), контракт доказан компиляцией с обеих сторон (53 метода, оба Pick резолвятся, множество async 59==59). Нагруженные seam'ы байт-идентичны. Ноль строк кода потеряно.
Внутренний цикл: 1 проход (адверсарно, исчерпывающе по 6 рискам — главные: сохранение контракта через полное перечисление 53 методов + компиляционное доказательство с обеих сторон, и миксин-диспетчеризация / отсутствие дублей публичных методов). Блокеров/багов нет.
Прим.: ветка содержит ТОЛЬКО src (client.ts + client/*). Кодер при прогоне тестов правил node_modules-симлинки в worktree для подтяжки deps — эти изменения в коммит не попали (проверил: 0 node_modules-путей в diff).
Ревью — #478
refactor(mcp): распил client.ts (5206 строк) на доменные модули за тонким фасадом (#450)Вердикт: PASS ✅
Полный веер из 9 аспектов по изолированной дельте (на ветке #449/#475; ревьюил
9a8671c3..14d7b21d= 13 файлов, +6088/−5203 — почти целиком перенос). Чистый структурный рефакторинг, поведение не меняется. Гейт зелёный.Поведение-сохранение — статически + суитом подтверждено (клик)
god-object client.ts 5206 строк → фасад 93 строки (пустой subclass
DocmostClientBase) + 12 доменных модулей (read/pages/nodes-write/tables/media/stash/drawio/comments/transforms/doc-validate + context + errors), композированных МИКСИНАМИ над общей абстрактной базой context.ts.this.replacePage) — проходят ⇒ mixin-прототип-цепочка даёт корректную виртуальную диспетчеризациюthis.cross-module (context-object её бы сломал; паттерн выбран вынужденно и обоснованно)../lib/→../lib/); 59 async-методов → 59 (ни один не потерян/переименован). #449-инварианты целы (UUID-assert, resolve-then-lock в replaceImage, self-resolve seams в context.ts, no-await-окно). Shared state (axios/токены/кэши) — protected в context.ts, без дублей. Cross-module seam'ы — 8 protected-стабов на базе с throw-guard'ами (громко если миксин не подключён). private→protected для нужных cross-mixin вызовов (validateDocUrls) — осознанно.⛔ DROP — кодеру НЕ делать
[inherited]low[stability] server-tsc import.meta красный — унаследован от develop (#472/drawio), #478 не трогает server/не добавляет import.meta. Не CI-проверка. Не #478.[below-threshold]low[conventions] часть return-типов всплыла какany(методы, полагавшиеся на inference, теперь явныйanyв интерфейсах миксинов) — задокументированный trade-off, не поведенческое изменение.DO/ESCALATE нет. Распил чисто механический: 800/800 суит идентичен до/после, методы вербатим, errors-равномерность пред-существовала, #449-инварианты целы, mixin-диспетч работает (субклас-override тесты зелёные), внешний контракт неизменен. God-object-риск снят доменной изоляцией. Approve. Merge-order: после #475.
#450, на #475. 9 аспектов (behavior-preservation+mixin, conv+arch+simp+docs+testcov — оба LGTM, 82+44 тул-кола). errors.ts вербатим (равномерность пред-существовала); методы byte-identical; mixin this.-диспетч подтверждён субклас-override тестами; контракт неизменен; 800/800 идентичны. server-tsc-red унаследован. Escalate нет.