feat(git-sync): двусторонний Docmost↔git синк на унифицированном конвертере (#359)
Схлопнутая дельта feat/git-sync-2 поверх актуального develop (3085ec1b). Почему squash, а не буквальный rebase: в ветке 113 коммитов, из которых develop уже впитал ~80 в курированном виде при унификации конвертера (#326/#293) — но не patch-identical, поэтому они не отваливаются сами; а коммит, УДАЛЯЮЩИЙ вендоренную копию конвертера, апстримный и в replay-набор не входит, так что наивный replay заново добавил бы вендоренные копии. Поэтому корректный итог — «develop + чистая net-дельта ветки», сведённая 3-way мержом (merge-base5336f06d). Net-дельта: серверный git-sync модуль (GitSyncModule/orchestrator/HTTP), движок git-sync (layout/reconcile/pull/push/stabilize + QA), два фикса round-trip/data-loss конвертера поверх УНИФИЦИРОВАННОГО @docmost/prosemirror-markdown (вендоренной копии больше нет — git-sync целиком на унифицированном конвертере, поведение унифицированного принято за эталон), e2e-скрипты, доки. Конфликты (4) слиты объединением: main.ts (метрики + GitHttpService), apps/server/package.json (pretest-суперсет; moduleNameMapper: git-sync→src и .js-strip оставлены, а bare-specifier @docmost/prosemirror-markdown→src УБРАН — серверный jest выровнен на develop-подход #345 со сборённым пакетом), .env.example (метрики + GIT_SYNC блоки), AGENTS.md (строки про пакеты; устаревшая заметка про «три hand-synced копии схемы» в git-sync поправлена — схема теперь только в @docmost/prosemirror-markdown). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -65,6 +65,16 @@ describe('GitSyncClient contract (type-level)', () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
it('pageIdsExist(ids) -> ids subset (D-P3-1 ghost guard seam)', () => {
|
||||
expectTypeOf<GitSyncClient['pageIdsExist']>().parameters.toEqualTypeOf<
|
||||
[string[]]
|
||||
>();
|
||||
expectTypeOf<
|
||||
Awaited<ReturnType<GitSyncClient['pageIdsExist']>>
|
||||
>().toEqualTypeOf<string[]>();
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
|
||||
it('a structurally-correct adapter satisfies GitSyncClient (drift => compile error)', () => {
|
||||
// A minimal dummy adapter mirroring the EXACT result shapes the engine reads.
|
||||
// The `satisfies GitSyncClient` clause is the contract guard: any drift in a
|
||||
@@ -74,6 +84,7 @@ describe('GitSyncClient contract (type-level)', () => {
|
||||
pages: [] as GitSyncPageNodeLite[],
|
||||
complete: true,
|
||||
}),
|
||||
pageIdsExist: async (_pageIds: string[]) => [] as string[],
|
||||
getPageJson: async (pageId: string) => ({
|
||||
id: pageId,
|
||||
slugId: 'slug',
|
||||
@@ -130,6 +141,7 @@ describe('GitSyncClient contract (type-level)', () => {
|
||||
// in BOTH directions).
|
||||
const bad = {
|
||||
listSpaceTree: async () => ({ pages: [] as GitSyncPageNodeLite[], complete: true }),
|
||||
pageIdsExist: async () => [] as string[],
|
||||
getPageJson: async (pageId: string) => ({
|
||||
id: pageId,
|
||||
slugId: 's',
|
||||
|
||||
Reference in New Issue
Block a user