feat(calendar): provider registry and a generic calendar IPC surface (#1392) - #1422
Draft
h4yfans wants to merge 1 commit into
Draft
Conversation
|
React Doctor found no new issues. 🎉 Reviewed by React Doctor for commit |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
This was referenced Aug 13, 2026
…1392) `calendar-handlers.ts` hard-rejected any non-Google provider in four places, and four channel names were nailed to Google. The contract was already `provider: z.string().min(1)` rather than an enum, so this extends without breaking it. New `calendar/provider/registry.ts`: a `CalendarProviderDefinition` carrying `id`, `capabilities`, `createAdapter`, `connect`, `disconnect`, account and auth queries, discovery, sync and runner control. `providers/google/ provider-definition.ts` implements it over the existing Google modules; `provider/builtin.ts` registers it. The four `input.provider !== 'google'` guards become registry lookups. An unregistered provider gets the byte-identical message it got before — `Unsupported calendar provider: <id>` — via one shared `unsupportedProviderMessage()` so no call site can drift. The connect handler now composes source ids as `${providerId}-account:` / `${providerId}-calendar:`, which produces exactly the strings the google literals produced, so existing rows keep matching. New channels, with the Google-named originals kept as permanent aliases: | New | Legacy (kept) | |---|---| | `calendar:list-provider-calendars` | `calendar:list-google-calendars` | | `calendar:set-default-provider-calendar` | `calendar:set-default-google-calendar` | | `calendar:retry-source-sync` | `calendar:retry-google-source-sync` | | `settings:{get,set}CalendarProviderSettings` | `settings:{get,set}CalendarGoogleSettings` | Also `calendar:list-providers`, so the settings page is fed from main instead of a hardcoded renderer list, and `CalendarProviderStatus.capabilities` so the renderer can hide write/push affordances. `capabilities` is null for a provider this build does not know — which is what an older client sees for a provider added later. The legacy channels are a compatibility surface, not dead code: during a partial update an older renderer talks to a newer main, and deleting a channel breaks the app for the length of that window. Comments say so at every definition site.
h4yfans
force-pushed
the
h4yfans/calendar-provider-registry
branch
from
August 13, 2026 16:17
36bcac9 to
f80627b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1392. Phase 0 of the multi-provider calendar epic #1390.
What
main/ipc/calendar-handlers.tshard-rejected any non-Google provider in four places. The contract was alreadyprovider: z.string().min(1)rather than an enum, so this extends without breaking it.Registry —
calendar/provider/registry.tsdefinesCalendarProviderDefinition(id,capabilities,createAdapter,connect,disconnect, account/auth queries, discovery, sync, runner control) plusregisterProvider/getProvider/listProviders.providers/google/provider-definition.tsimplements it over the existing Google modules;provider/builtin.tsdoes the registration.The four guards become registry lookups. The rejection string is byte-identical to before —
Unsupported calendar provider: <id>— produced by one sharedunsupportedProviderMessage()so no call site can drift, and asserted verbatim in tests.Source ids. The connect handler composes
${providerId}-account:/${providerId}-calendar:, which for google produces exactly the strings the literals produced. Existing rows keep matching; no migration.Channels — legacy ones are kept as permanent aliases:
calendar:list-provider-calendarscalendar:list-google-calendarscalendar:set-default-provider-calendarcalendar:set-default-google-calendarcalendar:retry-source-synccalendar:retry-google-source-syncsettings:{get,set}CalendarProviderSettingssettings:{get,set}CalendarGoogleSettingsPlus
calendar:list-providers, so the settings page is fed from main instead of a hardcoded renderer list.CalendarProviderStatusgainscapabilities: CalendarProviderCapabilities | null. Null means "this build does not know that provider id" — which is exactly what an older client sees for a provider added later. The capability model itself moved intopackages/contracts/src/calendar-api.ts(the renderer needs it) andprovider/adapter.tsre-exports it under the main-process names.Why the legacy channels are permanent
During a partial update an older renderer talks to a newer main. Deleting a channel breaks the app for the length of that window. They are a compatibility surface, not dead code — a comment says so at each definition site, and a test asserts each one still resolves to the same handler as its neutral twin.
Scope notes
settings:{get,set}CalendarProviderSettingscurrently reads and writescalendar.<providerId>, which for google is the samecalendar.googlerow it always was. The per-provider schema split is [calendar][P0] Per-provider credential storage + settings namespace #1394's job.googleIntegrationOperationsexclusion list inagent-mcp-channels.test.ts. They reach the same connected accounts as their Google-named twins, so allowlisting one would re-open the Workspace Limited Use hole the original exclusion closes.calendar_google_connected) with a pointer to [calendar][P5] Multi-provider telemetry, docs, and epic close-out #1406; google is still the only registered provider, so nothing changes for users.Verification
pnpm typecheck— 16/16 tasks greenpnpm lint— 0 errorspnpm ipc:generate && pnpm ipc:check— green (bindings regenerated)pnpm check:architecture/pnpm check:contracts— green@memry/contracts— 50 files, 1655 tests passedshared2455 ·main6348 passed / 1 expected fail / 4 skipped ·main-integration9 ·renderer6965 passed / 6 skippedNew tests in
calendar-handlers.test.ts:calendar:list-providersreports google with its capabilities; connect/disconnect/refresh each reject an unregistered provider with the exact historical string and acapabilities: nullstatus; an unregistered provider never reaches a Google flow; each legacy channel resolves to the same handler as its neutral twin; every registered channel is unregistered. Plusprovider/registry.test.tsfor lookup, isolation between two registered providers, and the message.Three existing status assertions gained the new
capabilitiesfield — asserted againstGOOGLE_CAPABILITIESfrom the definition rather than a copied literal, so a capability flip has to be a deliberate one-place edit.Docs
MEMRY_DOCS_IMPACT_SKIP=1on push: no user-facing change. Google is still the only registered provider and every surface behaves identically; the new channels have no UI yet (that is #1395). Docs land with #1394 and #1396.