mirror of
https://github.com/Kong/insomnia.git
synced 2026-09-17 08:59:33 -04:00
* Move Konnect projects into a global Control Planes organization * fix: break new circular dependency in Konnect organization utils useKonnectOrganization() imported useRootLoaderData from ~/root to read accountId, but organization-utils.ts is itself reached from root.tsx via the settings modal chain, closing a new import cycle flagged by CI's dependency-cruiser check. Pass accountId in from the caller (useOrganizations), which already has it, instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Konnect moved onboarding nudge. * Can sync when the konnect org is empty. * fix: guard two develop-introduced hooks against the Konnect organization use-organization-storage-rule.ts and use-remote-files.ts's useRemoteBackendProjects were added by develop's account-data refactor after this plan's original API-guard audit, and both issued real network/IPC calls for the local-only Konnect organization: - useOrganizationStorageRule called the raw API directly and only checked isScratchpadOrganizationId, missing Konnect. Fixed by delegating to fetchAndCacheOrganizationStorageRule (which already returns the correct local-only rules with no network call) instead of gating with `enabled`, since a naive gate would fall back to the permissive DEFAULT_STORAGE_RULES and surface Cloud Sync/Git Sync inside Control Planes. - useRemoteBackendProjects had no organization guard at all, firing window.main.sync.remoteBackendProjectsOfTeam for an org whose projects never have a remoteId. Fixed with an isLocalOrganizationId check on its `enabled` gate. Re-audited every other organizationId-scoped API guard in the plan; no further gaps found. Plan doc updated with both findings. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix: disable Connect & Sync in Konnect settings modal without entitlement The modal let a user validate and store a PAT even when the account lacks the Konnect control-planes entitlement, even though syncing could never run in that state — the sidebar's Sync button was already disabled here but the modal's own Connect & Sync button was not. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix: re-fetch Konnect entitlements after logging back into the same account refreshKonnectAccess deduped by accountId, but signing in never reloads the renderer, so its module-level guard survives a logout — and a fresh login into the same account keeps the same accountId, silently skipping the re-fetch of /v1/user/entitlements. Key the guard on sessionId instead: a new login always mints a new session token even for the same account, so this still dedupes the normal cold-start case (startup call and post-login loader share one session) while correctly re-resolving after logout/login. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix: navigate away when the Konnect organization becomes invisible Deleting a user's last Konnect project (one at a time via the project delete action, or in bulk via Disconnect) could leave them stranded on a URL for an organization that no longer appears in the dropdown, with no automatic navigation elsewhere. Add getKonnectOrganizationEscapeRoute(organizationId), which re-checks visibility with a fresh local project count (no network call — only that half can change from a plain NeDB delete) combined with the last-resolved entitlement, updates the shared access store so useOrganizations() reflects it immediately, and returns the account's first real organization to redirect to when the org just went dark. Call it from both places that can remove the last Konnect project: - organization.$organizationId._index.tsx's loader, which every "no reachable project" fallback already redirects through - organization.$organizationId.project.$projectId.delete.tsx's action, which previously short-circuited straight back into the same (now invisible) organization instead of going through that loader Extracted the shared "recompute + store update" logic into reconcileKonnectAccess() to avoid duplicating it between refreshKonnectAccess() and the new escape-route check. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Migrate after login * Force fetch storage rule * Replace Konnect sync module-var trigger with event bus Swaps the register/run module variable in konnect-sync-trigger.ts for uiEventBus so the sync callback is subscribed/unsubscribed via useEffect instead of being reassigned on every render with no cleanup. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * Remove plan --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
insomnia-data
A runtime-agnostic data layer for Insomnia, based on interface + IoC.
Core idea
src/: runtime-agnostic contracts (IDatabase,Services, model metadata/types)node-src/: Node/main concrete implementations (createNedbDatabase,servicesNodeImpl)- entry points wire once:
initDatabase(impl)initServices(impl)
After wiring, business code always uses the same APIs: database, services, models.
Process flows
Database (main / renderer / inso)
flowchart LR
subgraph Renderer
R0[initDatabase] --> R1[clientDatabase implementation]
R2[feature code] --> R3[database from insomnia-data]
R3 --> R1
R1 --> R4[window.database.invoke]
R4 --> R5[ipcRenderer.invoke database.invoke]
end
subgraph Main
M0[initDatabase] --> M1[mainDatabase implementation]
M1 --> M2[createNedbDatabase impl]
M2 --> M3[(NeDB)]
M4[main feature code] --> M5[database from insomnia-data]
M5 --> M1
M6[ipcMain.handle database.invoke] --> M1
M1 --> M7[webContents.send db.changes]
end
subgraph Inso
I0[initDatabase] --> I1[inso database implementation]
I1 --> I2[createNedbDatabase impl]
I2 --> I3[(NeDB)]
I4[inso feature code] --> I5[database from insomnia-data]
I5 --> I1
end
R5 --> M6
M7 -.notify.-> R2
Services (main / renderer / inso)
flowchart LR
subgraph Renderer
R0[initServices] --> R1[preload servicesProxy implementation]
R2[feature code] --> R3[services from insomnia-data]
R3 --> R1
R1 --> R4[ipcRenderer.invoke services.invoke]
end
subgraph Main
M0[initServices] --> M1[servicesNodeImpl]
M2[feature code] --> M3[services from insomnia-data]
M3 --> M1
M1 --> M4[service logic]
M4 --> M5[database]
M5 --> M6[(NeDB)]
M7[ipcMain.handle services.invoke] --> M1
end
subgraph Inso
I0[initServices] --> I1[servicesNodeImpl]
I2[feature code] --> I3[services from insomnia-data]
I3 --> I1
I1 --> I6[(NeDB)]
end
R4 --> M7
Renderer services path:
services.xxx -> preload proxy -> IPC -> main handler -> servicesNodeImpl -> database.
Why this design
- Same API across runtimes: main, renderer, inso.
- Feature code is decoupled from Electron/IPC/NeDB details.
- Renderer has a safer boundary (bridge + IPC, no direct DB internals and node API access).
- Easy to test or swap implementations by injecting at startup.
Minimal usage
Main
import { initDatabase, initServices } from 'insomnia-data';
import { mainDatabase } from '~/main/database.main';
import { servicesNodeImpl } from 'insomnia-data/node';
await initDatabase(mainDatabase);
initServices(servicesNodeImpl);
Renderer
import { initDatabase, initServices } from 'insomnia-data';
import { clientDatabase } from '~/ui/database.client';
await initDatabase(clientDatabase);
initServices(window._dataServices);
Inso / Node
import { initDatabase, initServices } from 'insomnia-data';
import { createNedbDatabase, servicesNodeImpl } from 'insomnia-data/node';
await initDatabase(createNedbDatabase());
initServices(servicesNodeImpl);
Consuming
import { services, models, type Request } from 'insomnia-data';
const mcpRequest = await services.mcpRequest.create({ url: 'http://localhost:3000' });
const all = await services.mcpRequest.all();
const request: Request = {};
const requestType = models.request.type;