From ecbd218c346ef58bd2b96fd2ce21dcd283d7d138 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Sun, 27 Sep 2026 07:47:17 +0200 Subject: [PATCH] fix: sync only the primary account's collections by default #34 The settings chooser and the reminder filter treat only the capability's primary account as the user's own, while the engine also counted any account the server marks as personal. On a server that lists a second such account, its address books and calendars synced although the chooser showed them off. The engine now uses the same rule as the app. --- src/device-sync/__tests__/engine/internals.test.ts | 13 +++++++++++++ src/device-sync/jmap/session.ts | 8 ++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/device-sync/__tests__/engine/internals.test.ts b/src/device-sync/__tests__/engine/internals.test.ts index 4fee104b..07ec9348 100644 --- a/src/device-sync/__tests__/engine/internals.test.ts +++ b/src/device-sync/__tests__/engine/internals.test.ts @@ -297,6 +297,19 @@ describe('JMAP side', () => { expect(accountsWithCapability(session, JMAP_CALENDARS).map((a) => a.id)).toEqual(['a']); }); + it("counts only the capability's primary account as personal, like the app's chooser", () => { + const server = new FakeJmapServer(); + server.addAccount('a', { name: 'alice@example.com' }); + // Another account the server calls personal (a second mailbox of the same login, say). + server.addAccount('home', { name: 'alice-home@example.com', isPersonal: true }); + const session = server.port().session(); + + expect(accountsWithCapability(session, JMAP_CONTACTS).map((a) => [a.id, a.primary, a.personal])).toEqual([ + ['a', true, true], + ['home', false, false], + ]); + }); + it('takes the login as the owner address and survives a server without identities', async () => { const server = new FakeJmapServer(); server.addAccount('a', { name: 'Alice@Example.com' }); diff --git a/src/device-sync/jmap/session.ts b/src/device-sync/jmap/session.ts index caf93550..b6d6743b 100644 --- a/src/device-sync/jmap/session.ts +++ b/src/device-sync/jmap/session.ts @@ -12,7 +12,11 @@ export interface CapabilityAccount { name: string; /** The capability's primary account (the user's own). */ primary: boolean; - /** Collections of personal accounts are selected by default, shared ones are not. */ + /** + * Collections of the personal account are selected by default, those of the others are not. It is the + * capability's primary account only, whatever `isPersonal` says: one rule with the app's chooser and + * reminder filter, which know only the primary account per authority. + */ personal: boolean; readOnly: boolean; } @@ -31,7 +35,7 @@ export function accountsWithCapability(session: JmapSessionView, capability: str id, name: account.name || id, primary: isPrimary, - personal: isPrimary || account.isPersonal, + personal: isPrimary, readOnly: !!account.isReadOnly, }); };