fix(git-sync): git-http stream error handlers + close test gaps (#119 review)

Addresses the stability + test-coverage warnings from the #119 review:

- git-http-backend.service.ts: add `'error'` handlers to child.stdout/stderr. An
  EventEmitter 'error' with no listener (e.g. EPIPE when the client aborts
  mid-response) is rethrown by Node as an uncaught exception and crashes the
  process; now swallowed + logged (never echoed to the client).
- TEST INFRA: a jest setupFile shims `navigator`/`MessageChannel` for the `node`
  testEnvironment. react-dom@18 reads `navigator` at module-init (pulled in via
  @docmost/editor-ext -> @tiptap/react), so every spec transitively importing the
  conversion engine — including git-http.service.spec.ts — previously FAILED TO
  LOAD ("navigator is not defined") and ran ZERO tests. With the shim those specs
  now run (git-sync integration: 11 suites / 133 tests green).
- git-http.service.spec.ts: cover the 503 lock-held push path — `ingestExternalPush`
  rejecting `GitSyncLockHeldError` -> 503 + Retry-After + "git-sync busy, retry",
  no double header write (+ the already-headers-sent no-rewrite path).
- git-http-backend.service.spec.ts: unit-test run() — child 'error'/'close' before
  headers -> 500; normal CGI parse+stream; stdout/stderr 'error' (EPIPE) swallowed;
  synchronous spawn throw -> 500.
- page-change.listener.ts: implement OnModuleDestroy to clearTimeout all pending
  debounce timers on shutdown (+ test).
- .env.example: vaults are non-bare working repos, not "bare repos".

(Docs deleted by the stray commit were restored in 9cdbce54.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
claude code agent 227
2026-06-24 13:25:04 +03:00
parent 3b00cd5021
commit fc472bfc31
8 changed files with 327 additions and 3 deletions

View File

@@ -201,6 +201,13 @@ export class GitHttpBackendService {
flushHeadersAndBody(chunk);
}
});
// A stream 'error' (e.g. EPIPE when the client aborts mid-response) is an
// EventEmitter 'error' with no listener -> Node rethrows it as an uncaught
// exception and crashes the process. Swallow + log it (never echo to the
// client); child.on('close')/'error' below drives the actual cleanup.
child.stdout?.on('error', (err) => {
this.logger.warn(`git http-backend stdout stream error: ${err.message}`);
});
let stderr = '';
child.stderr?.on('data', (chunk: Buffer) => {
@@ -208,6 +215,9 @@ export class GitHttpBackendService {
// CGI errors here. We do NOT log the request body or any credentials.
if (stderr.length < 8192) stderr += chunk.toString('utf8');
});
child.stderr?.on('error', (err) => {
this.logger.warn(`git http-backend stderr stream error: ${err.message}`);
});
child.on('error', (err) => {
if (!headerParsed && !rawRes.headersSent) {