Skip to content

refactor(ipc): split sync-handlers.ts god module (Phase 2.1–2.4) - #241

Merged
h4yfans merged 6 commits into
mainfrom
debt/phase-2-sync-split
Apr 16, 2026
Merged

refactor(ipc): split sync-handlers.ts god module (Phase 2.1–2.4)#241
h4yfans merged 6 commits into
mainfrom
debt/phase-2-sync-split

Conversation

@h4yfans

@h4yfans h4yfans commented Apr 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Splits the 1318-line apps/desktop/src/main/ipc/sync-handlers.ts IPC god-module into 4
cohesive files plus a shared sync/device-registration.ts helper. Behavior-preserving;
no channel renames, no contract changes, no preload changes. Part of Phase 2 of
tech-debt-remediation.md (C3 in the audit).

Before: 1318 lines mixing OAuth loopback, OTP+clipboard, device linking, R2 attachment
chunking, and sync-engine control.
After: 5 files, all <500 lines, each with a single cohesive responsibility.

File Lines Responsibility
sync/device-registration.ts 180 PLATFORM_MAP + registerDevice + persistKeysAndRegisterDevice (shared by OAuth/OTP/recovery/linking)
ipc/auth-oauth-handlers.ts 294 OAuth loopback + PKCE + SETUP_FIRST_DEVICE + recovery confirmation + logout
ipc/auth-device-handlers.ts 416 OTP auth + clipboard detection + device linking + device CRUD
ipc/sync-attachment-handlers.ts 293 AttachmentSyncService + upload queue + UPLOAD/DOWNLOAD_ATTACHMENT + R2 event plumbing
ipc/sync-core-handlers.ts 281 Sync engine control (status/trigger/pause/resume/history/etc.) + checkSyncIntegrity + composes the 3 sub-modules

sync-core-handlers exposes the same public API (registerSyncHandlers, unregisterSyncHandlers,
checkSyncIntegrity, clearInMemoryAuthState) so ipc/index.ts and session-teardown.ts stay
simple. Cross-module state leakage is replaced with narrow interfaces: performFirstDeviceSetup
and getAndClearPendingRecoveryPhrase are exported from auth-device so auth-oauth can drive
SETUP_FIRST_DEVICE and GET_RECOVERY_PHRASE without reading module-private state.

Commits (5)

  1. refactor(sync): extract device-registration module (7e1df54)
  2. refactor(ipc): extract auth-oauth-handlers from sync-handlers (Phase 2.1) (0c8c381)
  3. refactor(ipc): extract auth-device-handlers from sync-handlers (Phase 2.2) (00468cc)
  4. refactor(ipc): extract sync-attachment-handlers from sync-handlers (Phase 2.3) (e28e24f)
  5. refactor(ipc): rename sync-handlers → sync-core-handlers (Phase 2.4) (fa82ee1)

Deferred

Phase 2.5 (apply registerCommand wrapper) is not included in this PR. Migrating the
18 schema-input handlers from ipcMain.handle(…, createValidatedHandler(…)) to
registerCommand(…) adds implicit withErrorHandler wrapping around throws, which changes
the error envelope contract for handlers that currently rely on propagating thrown errors
directly to the renderer (e.g., LINK_VIA_RECOVERY, APPROVE_LINKING, REMOVE_DEVICE).
Deferred to a follow-up PR so the blast radius of that semantic change is reviewed in
isolation.

Test plan

  • pnpm lint — 0 errors (warnings unchanged from main baseline)
  • pnpm --filter @memry/desktop exec tsc --noEmit -p tsconfig.node.json — clean
  • pnpm --filter @memry/desktop test — 5827/5828 pass (1 skipped, unchanged from main)
  • pnpm ipc:check — IPC invoke map + generated RPC up to date
  • Manual OTP sign-in flow (email → OTP → setup → recovery phrase)
  • Manual OAuth sign-in flow (loopback callback → setup)
  • Manual sign-out + re-entry (verifies clearInMemoryAuthState composes across 3 child modules — per CRDT sign-out memory, mixed concerns previously caused a production bug here)
  • Settings → Devices: list, rename
  • Attach a file to a note → upload/download round-trip

h4yfans added 6 commits April 16, 2026 07:29
Move PLATFORM_MAP, registerDevice, and persistKeysAndRegisterDevice
from apps/desktop/src/main/ipc/sync-handlers.ts into a new
apps/desktop/src/main/sync/device-registration.ts. This is a
prerequisite for the Phase 2 sync-handlers split: these helpers are
needed by multiple child handler files (auth-oauth, auth-device) and
already have external consumers (sync/linking-service.ts,
main/test-hooks.ts).

- sync-handlers.ts shrinks 1318 → 1157 lines
- No behavior change; imports redirected in linking-service.ts and
  test-hooks.ts
- Part of Phase 2 (tech-debt-remediation.md): prep commit before
  splitting handlers
…2.1)

Split OAuth loopback, PKCE state, and OAuth-flow handlers out of the
1157-line sync-handlers god module into a cohesive auth-oauth-handlers
module with matching tests. sync-handlers continues to compose the new
module's register/unregister into its public API so ipc/index.ts and
session-teardown consumers stay unchanged this commit.

Moved: AUTH_INIT_OAUTH, AUTH_REFRESH_TOKEN, SETUP_FIRST_DEVICE,
CONFIRM_RECOVERY_PHRASE, GET_RECOVERY_PHRASE, AUTH_LOGOUT + oauthSessions
map, loopback server helpers, and seedOAuthSession export. GET_RECOVERY_PHRASE
consumes pendingRecoveryPhrase via a narrow getter from auth-device-handlers
(still in sync-handlers for now; will land in Phase 2.2).

- sync-handlers.ts 1157 → 866 lines
- sync-handlers.test.ts 749 → 554 lines
- New: auth-oauth-handlers.ts (364), auth-oauth-handlers.test.ts (341)
… 2.2)

Split OTP, device-linking, and device-CRUD handlers (plus OTP clipboard
detection + pendingRecoveryPhrase state) out of sync-handlers into a
dedicated auth-device-handlers module with matching tests.

performFirstDeviceSetup and getAndClearPendingRecoveryPhrase are exported
so auth-oauth-handlers can drive SETUP_FIRST_DEVICE and GET_RECOVERY_PHRASE
through narrow, explicit interfaces instead of reading module-private state.

Moved: AUTH_REQUEST_OTP, AUTH_VERIFY_OTP, AUTH_RESEND_OTP, SETUP_NEW_ACCOUNT,
GENERATE_LINKING_QR, LINK_VIA_QR, COMPLETE_LINKING_QR, LINK_VIA_RECOVERY,
APPROVE_LINKING, GET_LINKING_SAS, GET_DEVICES, REMOVE_DEVICE, RENAME_DEVICE.

- sync-handlers.ts 866 → 542 lines
- sync-handlers.test.ts 554 → 314 lines
- New: auth-device-handlers.ts (416), auth-device-handlers.test.ts (483)
- generated-ipc-invoke-map.ts + preload/generated-rpc.ts regenerated
…hase 2.3)

Move attachment upload/download handlers, AttachmentSyncService +
UploadQueue singletons, broadcastUploadProgress helper, and the
attachmentEvents onSaved/onDownloadNeeded listeners out of sync-handlers
into sync-attachment-handlers. sync-handlers.ts composes the new
module's register/unregister/clear helpers through its public API so
ipc/index.ts and session-teardown stay untouched this commit.

Moved: UPLOAD_ATTACHMENT, GET_UPLOAD_PROGRESS, DOWNLOAD_ATTACHMENT,
GET_DOWNLOAD_PROGRESS + R2 chunking plumbing.

- sync-handlers.ts 542 → 280 lines
- New: sync-attachment-handlers.ts (280 lines) with lifecycle-level
  test coverage (handler registration, event subscription, teardown)
After splitting OAuth, device/OTP, and attachment concerns into their
own handler files, what remains in the former god-module is pure
sync-engine control (status/trigger/history/queue/pause/resume/
emergency-wipe/etc.) plus startup integrity and the cross-cutting
clearInMemoryAuthState composer. Rename the file to reflect that
narrower role and delete the back-compat import path — memry is
pre-production, so the old path has no consumers outside this branch.

- apps/desktop/src/main/ipc/sync-handlers.ts → sync-core-handlers.ts
- apps/desktop/src/main/ipc/sync-handlers.test.ts → sync-core-handlers.test.ts
- Update imports: ipc/index.ts, ipc/index.test.ts (vi.mock path),
  sync/session-teardown.ts
- Regenerate generated-ipc-invoke-map.ts + preload/generated-rpc.ts
Phase 2 split sync-handlers.ts into auth-oauth-handlers.ts,
auth-device-handlers.ts, sync-attachment-handlers.ts, and
sync-core-handlers.ts. All four compose the same imports the old
god-module had (`../sync/runtime`, `../sync/http-client`,
`../sync/token-manager`, etc.), so they inherit the same exemption.

Without this, `pnpm check:architecture` (part of CI Lint, Typecheck, and
Tests) fails with "feature IPC import of sync module" on every Phase 2
file — blocker for merging PR #241.
@h4yfans
h4yfans merged commit 8425b43 into main Apr 16, 2026
2 checks passed
h4yfans added a commit that referenced this pull request May 6, 2026
* refactor(sync): extract device-registration module

Move PLATFORM_MAP, registerDevice, and persistKeysAndRegisterDevice
from apps/desktop/src/main/ipc/sync-handlers.ts into a new
apps/desktop/src/main/sync/device-registration.ts. This is a
prerequisite for the Phase 2 sync-handlers split: these helpers are
needed by multiple child handler files (auth-oauth, auth-device) and
already have external consumers (sync/linking-service.ts,
main/test-hooks.ts).

- sync-handlers.ts shrinks 1318 → 1157 lines
- No behavior change; imports redirected in linking-service.ts and
  test-hooks.ts
- Part of Phase 2 (tech-debt-remediation.md): prep commit before
  splitting handlers

* refactor(ipc): extract auth-oauth-handlers from sync-handlers (Phase 2.1)

Split OAuth loopback, PKCE state, and OAuth-flow handlers out of the
1157-line sync-handlers god module into a cohesive auth-oauth-handlers
module with matching tests. sync-handlers continues to compose the new
module's register/unregister into its public API so ipc/index.ts and
session-teardown consumers stay unchanged this commit.

Moved: AUTH_INIT_OAUTH, AUTH_REFRESH_TOKEN, SETUP_FIRST_DEVICE,
CONFIRM_RECOVERY_PHRASE, GET_RECOVERY_PHRASE, AUTH_LOGOUT + oauthSessions
map, loopback server helpers, and seedOAuthSession export. GET_RECOVERY_PHRASE
consumes pendingRecoveryPhrase via a narrow getter from auth-device-handlers
(still in sync-handlers for now; will land in Phase 2.2).

- sync-handlers.ts 1157 → 866 lines
- sync-handlers.test.ts 749 → 554 lines
- New: auth-oauth-handlers.ts (364), auth-oauth-handlers.test.ts (341)

* refactor(ipc): extract auth-device-handlers from sync-handlers (Phase 2.2)

Split OTP, device-linking, and device-CRUD handlers (plus OTP clipboard
detection + pendingRecoveryPhrase state) out of sync-handlers into a
dedicated auth-device-handlers module with matching tests.

performFirstDeviceSetup and getAndClearPendingRecoveryPhrase are exported
so auth-oauth-handlers can drive SETUP_FIRST_DEVICE and GET_RECOVERY_PHRASE
through narrow, explicit interfaces instead of reading module-private state.

Moved: AUTH_REQUEST_OTP, AUTH_VERIFY_OTP, AUTH_RESEND_OTP, SETUP_NEW_ACCOUNT,
GENERATE_LINKING_QR, LINK_VIA_QR, COMPLETE_LINKING_QR, LINK_VIA_RECOVERY,
APPROVE_LINKING, GET_LINKING_SAS, GET_DEVICES, REMOVE_DEVICE, RENAME_DEVICE.

- sync-handlers.ts 866 → 542 lines
- sync-handlers.test.ts 554 → 314 lines
- New: auth-device-handlers.ts (416), auth-device-handlers.test.ts (483)
- generated-ipc-invoke-map.ts + preload/generated-rpc.ts regenerated

* refactor(ipc): extract sync-attachment-handlers from sync-handlers (Phase 2.3)

Move attachment upload/download handlers, AttachmentSyncService +
UploadQueue singletons, broadcastUploadProgress helper, and the
attachmentEvents onSaved/onDownloadNeeded listeners out of sync-handlers
into sync-attachment-handlers. sync-handlers.ts composes the new
module's register/unregister/clear helpers through its public API so
ipc/index.ts and session-teardown stay untouched this commit.

Moved: UPLOAD_ATTACHMENT, GET_UPLOAD_PROGRESS, DOWNLOAD_ATTACHMENT,
GET_DOWNLOAD_PROGRESS + R2 chunking plumbing.

- sync-handlers.ts 542 → 280 lines
- New: sync-attachment-handlers.ts (280 lines) with lifecycle-level
  test coverage (handler registration, event subscription, teardown)

* refactor(ipc): rename sync-handlers → sync-core-handlers (Phase 2.4)

After splitting OAuth, device/OTP, and attachment concerns into their
own handler files, what remains in the former god-module is pure
sync-engine control (status/trigger/history/queue/pause/resume/
emergency-wipe/etc.) plus startup integrity and the cross-cutting
clearInMemoryAuthState composer. Rename the file to reflect that
narrower role and delete the back-compat import path — memry is
pre-production, so the old path has no consumers outside this branch.

- apps/desktop/src/main/ipc/sync-handlers.ts → sync-core-handlers.ts
- apps/desktop/src/main/ipc/sync-handlers.test.ts → sync-core-handlers.test.ts
- Update imports: ipc/index.ts, ipc/index.test.ts (vi.mock path),
  sync/session-teardown.ts
- Regenerate generated-ipc-invoke-map.ts + preload/generated-rpc.ts

* chore(arch): extend sync-boundary IPC exemption to Phase 2 split files

Phase 2 split sync-handlers.ts into auth-oauth-handlers.ts,
auth-device-handlers.ts, sync-attachment-handlers.ts, and
sync-core-handlers.ts. All four compose the same imports the old
god-module had (`../sync/runtime`, `../sync/http-client`,
`../sync/token-manager`, etc.), so they inherit the same exemption.

Without this, `pnpm check:architecture` (part of CI Lint, Typecheck, and
Tests) fails with "feature IPC import of sync module" on every Phase 2
file — blocker for merging PR #241.
@h4yfans
h4yfans deleted the debt/phase-2-sync-split branch May 6, 2026 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant