At sign-in, the files, contacts and calendar stores each looped over the accounts shared with the reader and asked each one a question in turn, one request per account per store, before the reader had opened any of those views.
Files.init() now only works out availability and the reader's own account, with no request. The per-account FileNode/query moves to a new discoverShared(), which runs when the Files view opens (FilesTree already re-read the session on every visit) and when the file picker opens. Only those two list shared file accounts. The rule that keeps the reader in a share they're browsing is split between the two: init keeps it while the session still offers the account, and discoverShared drops it once the account holds no files.
Contacts.loadShared() asks every account's AddressBook/get at once, so they share one request. Books are sorted back into the session's order, since answers can arrive in any order.
Calendar.loadSharedCalendars() does the same with Calendar/get. init() runs loadCalendars, ParticipantIdentity/get and the shared calendars side by side instead of one after another.
Contacts and the calendar still load at sign-in: the To field's autocomplete needs contacts, and invitations and "Create event" need the calendar. Only their per-account requests changed.
Related issues
None.
Translations
Adds none.
Testing
New shared-accounts-batched.test.ts, with three shared accounts:
files.init() sends nothing;
discoverShared() sends one request covering all three and keeps only the account with files;
shared address books take one request;
shared calendars take one request and are listed in the session's order.
All 4 fail against main.
npm test -w web (1,324 tests) and npm run typecheck are clean.
Checked in Chrome against npm run dev:mock:
Startup: 6 JMAP requests on this branch and 6 on main. The mock has a single shared account, so one request per account and one combined request come out the same; the saving grows with the number of shared accounts, which the store test covers.
Files: opening it sent the shared account's FileNode/query, and the sidebar listed it under "Shared with me".
File picker: in a fresh page where nothing had asked yet, "Attach from Files" listed "My files" and the shared account.
Contacts and calendar: the calendar sidebar showed the shared calendar under "Available to add", and the contacts sidebar showed the shared address book.
## Summary
At sign-in, the files, contacts and calendar stores each looped over the accounts shared with the reader and asked each one a question in turn, one request per account per store, before the reader had opened any of those views.
- **Files.** `init()` now only works out availability and the reader's own account, with no request. The per-account `FileNode/query` moves to a new `discoverShared()`, which runs when the Files view opens (`FilesTree` already re-read the session on every visit) and when the file picker opens. Only those two list shared file accounts. The rule that keeps the reader in a share they're browsing is split between the two: `init` keeps it while the session still offers the account, and `discoverShared` drops it once the account holds no files.
- **Contacts.** `loadShared()` asks every account's `AddressBook/get` at once, so they share one request. Books are sorted back into the session's order, since answers can arrive in any order.
- **Calendar.** `loadSharedCalendars()` does the same with `Calendar/get`. `init()` runs `loadCalendars`, `ParticipantIdentity/get` and the shared calendars side by side instead of one after another.
Contacts and the calendar still load at sign-in: the To field's autocomplete needs contacts, and invitations and "Create event" need the calendar. Only their per-account requests changed.
## Related issues
None.
## Translations
Adds none.
## Testing
- New `shared-accounts-batched.test.ts`, with three shared accounts:
- `files.init()` sends nothing;
- `discoverShared()` sends one request covering all three and keeps only the account with files;
- shared address books take one request;
- shared calendars take one request and are listed in the session's order.
- **All 4 fail against `main`.**
- `npm test -w web` (1,324 tests) and `npm run typecheck` are clean.
- Checked in Chrome against `npm run dev:mock`:
- **Startup:** 6 JMAP requests on this branch and 6 on `main`. The mock has a single shared account, so one request per account and one combined request come out the same; the saving grows with the number of shared accounts, which the store test covers.
- **Files:** opening it sent the shared account's `FileNode/query`, and the sidebar listed it under "Shared with me".
- **File picker:** in a fresh page where nothing had asked yet, "Attach from Files" listed "My files" and the shared account.
- **Contacts and calendar:** the calendar sidebar showed the shared calendar under "Available to add", and the contacts sidebar showed the shared address book.
**Merged** 2026-09-16 as coffey-labs/ihasmail@60904420580b
<sub>Rebuilt from: GH Archive, git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
At sign-in, the files, contacts and calendar stores each looped over the accounts shared with the reader and asked each one a question in turn, one request per account per store, before the reader had opened any of those views.
init()now only works out availability and the reader's own account, with no request. The per-accountFileNode/querymoves to a newdiscoverShared(), which runs when the Files view opens (FilesTreealready re-read the session on every visit) and when the file picker opens. Only those two list shared file accounts. The rule that keeps the reader in a share they're browsing is split between the two:initkeeps it while the session still offers the account, anddiscoverShareddrops it once the account holds no files.loadShared()asks every account'sAddressBook/getat once, so they share one request. Books are sorted back into the session's order, since answers can arrive in any order.loadSharedCalendars()does the same withCalendar/get.init()runsloadCalendars,ParticipantIdentity/getand the shared calendars side by side instead of one after another.Contacts and the calendar still load at sign-in: the To field's autocomplete needs contacts, and invitations and "Create event" need the calendar. Only their per-account requests changed.
Related issues
None.
Translations
Adds none.
Testing
shared-accounts-batched.test.ts, with three shared accounts:files.init()sends nothing;discoverShared()sends one request covering all three and keeps only the account with files;main.npm test -w web(1,324 tests) andnpm run typecheckare clean.npm run dev:mock:main. The mock has a single shared account, so one request per account and one combined request come out the same; the saving grows with the number of shared accounts, which the store test covers.FileNode/query, and the sidebar listed it under "Shared with me".Merged 2026-09-16 as coffey-labs/ihasmail@6090442058
Rebuilt from: GH Archive, git history, session transcript.