feat(integrations): pear-side integrations feature (manager + catalog + Nango logos)#9
Conversation
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (6)
Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login. Comment |
| private async persistIntegration(projectId: string, integration: ConnectedIntegration): Promise<void> { | ||
| const data = loadStore() | ||
| const project = data.projects.find((entry) => entry.id === projectId) | ||
| if (!project) throw new Error(`Project not found: ${projectId}`) | ||
|
|
||
| const displayName = await this.displayNameForProvider(integration.provider) | ||
| const stored = toStoredIntegration(integration, displayName) | ||
| project.integrations = project.integrations.filter((entry) => { | ||
| const current = normalizeConnectedIntegration(entry) | ||
| return current?.integrationId !== integration.integrationId | ||
| }) | ||
| project.integrations.push(stored) | ||
| saveStore(data) | ||
| } |
There was a problem hiding this comment.
🔴 Store race condition in persistIntegration causes data loss when catalog cache is stale
The persistIntegration method reads the store with loadStore() at line 822, then awaits this.displayNameForProvider(integration.provider) at line 826 (which calls listCatalog() and may perform a network fetch when the 5-minute catalog cache expires), then writes the store with saveStore(data) at line 833. During the async gap, any other IPC handler that modifies and saves the store (e.g., project:update, project:add-channel, project:add-root) will have its changes silently overwritten by the stale data object. This contrasts with removePersistedIntegration at src/main/integrations.ts:836 which is effectively synchronous (load → modify → save without yielding).
Prompt for agents
In IntegrationsManager.persistIntegration (src/main/integrations.ts lines 821-834), the method calls loadStore(), then awaits displayNameForProvider (which may trigger a network fetch when the catalog cache is stale), then calls saveStore(data). During the async gap from the await, other IPC handlers can run and modify the store, and those changes will be lost when the stale data is saved.
To fix this, move the async displayNameForProvider call BEFORE loadStore(), or re-read the store after the await. The simplest fix:
1. Call `const displayName = await this.displayNameForProvider(integration.provider)` first
2. Then do the synchronous loadStore() → modify → saveStore() sequence without any async gaps in between
This matches the pattern used by removePersistedIntegration which correctly keeps the load-modify-save sequence synchronous.
Was this helpful? React with 👍 or 👎 to provide feedback.
… + Nango logos) Spec 02 scaffolding plus the catalog/logo work done this session: - src/main/integrations.ts: IntegrationsManager. listCatalog filters to ACTIVE_PROVIDERS (the non-deprecated relayfile providers in cloud/packages/web/lib/integrations/providers.ts). authHeaders is async and routes through resolveCloudAuth. loadStaticCatalog is a static import (not a dynamic variable import, which the bundler couldn't resolve and which left the static fallback empty at runtime). - src/main/integrations.types.ts: IntegrationAdapter + visibility types. - src/main/integrations.catalog.ts: 36 generated adapters with iconUrl pointing at https://app.nango.dev/images/template-logos/{slug}.svg. - scripts/build-integrations-catalog.mjs: regenerates the catalog from ../relayfile-adapters/packages. Adds NANGO_LOGO_SLUG override map (gmail→google-mail, teams→microsoft-teams, x→twitter) and emits iconUrl per entry. - src/renderer/src/components/settings/AccountSettings.tsx: <IntegrationLogo> component with onError fallback to the generic plug icon (light tile makes the dark/monochrome SVGs legible), used in both the CATALOG grid and the CONNECTED list. Builds on shared scaffolding (#7). Remaining gaps — scope-picker components + per-project visibility section + ../relayfile-cloud workspace-integrations route — are tracked in specs/02-integrations.md. The Connect-flow rework is spec 05. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nous Resolve the async displayNameForProvider lookup BEFORE loadStore() so no await sits between load and save. With the async gap in place, any concurrent IPC handler (project:update, project:add-channel, etc.) that wrote to projects.json during the awaited catalog refresh would have its changes silently overwritten when we saved the stale data we loaded earlier. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5de2c4e to
540a06a
Compare
Fix #9: track last-sent rows/cols and skip duplicate resizePty IPC. The ResizeObserver fires on every dragged pixel; the cell grid only changes at discrete steps. Fix #12: refuse a second concurrent mount of the same runtime into a different container. Currently chunkAgents doesn't trigger this, but silently reparenting would tear xterm out from under the original owner. Fix #15: post-font-settle metrics may differ from the pre-settle ones the predictor was built with. Call predictiveEcho.onResize after the refit so column wraps line up with the real grid. Also adds refreshOnShow() and setInputSrttGetter() to the runtime interface in preparation for use-terminal wiring.
Spec 02 scaffolding plus the catalog/logo work done this session. Builds on #7 (shared scaffold).
integrations.ts:IntegrationsManager.listCatalogfilters toACTIVE_PROVIDERS(the non-deprecated relayfile providers fromcloud/packages/web/lib/integrations/providers.ts).authHeadersis async and usesresolveCloudAuth.loadStaticCatalogis a static import — the previous dynamic variable importawait import(CATALOG_MODULE_PATH)couldn't be resolved by the bundler, so the static fallback was empty at runtime.integrations.catalog.ts: 36 generated adapters withiconUrlNango logos.scripts/build-integrations-catalog.mjs: emitsiconUrlwith theNANGO_LOGO_SLUGoverrides (gmail→google-mail,teams→microsoft-teams,x→twitter).AccountSettings.tsx:<IntegrationLogo>with onError fallback to the plug icon; used in both the CATALOG grid and the CONNECTED list.Remaining gaps (scope pickers, per-project visibility section,
../relayfile-cloudworkspace-integrations route) tracked in slim specspecs/02-integrations.mdfrom #5. Connect-flow rework is spec 05.🤖 Generated with Claude Code