Commit Graph
4595 Commits
Author SHA1 Message Date
Curry YangandClaude Opus 5.5 49a8adfa23 refactor(landing): one way out of the empty project view
The empty project view already leaves through `MissingEntityRedirect` once
projects appear, but it kept two other ways out: a loader redirect when the
database had projects, and `useCreateInitialProject` (a mutation deduped
through the mutation cache, navigating on success). They go:

- No loader. Opening the view in an organization that has projects is
  handled like projects appearing later: `MissingEntityRedirect` re-reads,
  then lands through `/organization/:organizationId`.
- The first-landing "Drafts" project is created by the startup sync query
  once the team projects are synced (still checking the database, still only
  for an account's first landing). The view opens it through the same
  redirect, with `?isExpanded=true` as before.

The project route keeps its own fallback (first project of the
organization data): `/organization/:organizationId` restores the last
visited project without checking its organization, which could send a
project moved to another organization straight back to its old URL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:25:22 +08:00
Curry YangandClaude Opus 5.5 b774babfe9 refactor(landing): guard the session in the organization middleware
The organization layout's middleware already reads the session before
every route inside an organization, so it now also sends a signed-out user
to the login page (the scratchpad being the only organization reachable
without one). The guards it replaces in the `/organization`, project and
empty-project loaders are removed, and `prepareAccount` takes the session
the middleware read instead of reading it again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:25:22 +08:00
Curry YangandClaude Opus 5.5 0daf983dff refactor(landing): phase4 - one loading path for the organization list
The organization list was loaded twice over: the landing chain read
localStorage and called `syncOrganizations`, while `useAccountServerData`
seeded `accountServerDataQuery` from localStorage and fetched through its
queryFn. `accountServerDataQuery` is now the only path, with localStorage
as its persistence layer:

- It moves to `common/organization.ts` (the hook module imports
  `~/root`, an import cycle risk for the landing code) and seeds itself
  from the persisted list through `initialData`. Without a persisted
  list there is no seed, so the first read fetches; every fetch still
  writes through for the remaining localStorage readers.
- `prepareAccount` loads it with `ensureQueryData`: cache first, a fetch
  only when nothing is persisted. `resolveLandingRoute` reads the query
  cache, i.e. the latest list the organization layout loaded.
- The authorize action refreshes it with `fetchQuery` instead of
  `syncOrganizations`, which is removed.

Behavior change: a fetch the landing waits on (nothing persisted) now
follows the server client's default `retry: 2` before failing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-03 16:25:22 +08:00
Curry YangandClaude Opus 5.5 504c9f61c0 refactor(landing): phase4 - one landing chain, account preparation in the organization layout
There were two startup paths doing the same thing: `getInitialEntry`
computed the landing route before hydration, while signing in went
through `/organization` (blocking `syncOrganizations` + migrations) and
then `$organizationId._index`. Both now share `src/ui/landing-route.ts`:

- `getInitialEntry` returns `/organization` once signed in; picking the
  organization, the Konnect escape check and the "no cached
  organizations" branch move out of it.
- `/organization` resolves the route with `resolveLandingRoute` (signin
  redirect target > last visited organization > first) and redirects
  once, restoring the last workspace as the startup path did.
  `$organizationId._index` uses `resolveOrganizationLandingRoute`.

Account preparation (organization list when none is cached, the Konnect
migration and access, the legacy project migration) moves into
`prepareAccount`, awaited by a `clientMiddleware` on the organization
layout. It replaces the pre-hydration block in `entry.client.tsx`, the
migration in the startup sync and the blocking sync in
`organization._index`. The layout is the parent of every organization
route, `/organization` included, so entries that skip `/organization`
(e.g. deep links opened from the onboarding or git migration screen) are
still prepared. Once per session, deduped by session id; only a missing
organization list fails it, the migrations log their failures.

The organization list is only fetched when none is cached, so signing in
refreshes it in the authorize action: the cached list is from an earlier
session and may hold organizations the account has left.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-03 16:25:22 +08:00
Curry YangandClaude Opus 5.5 1ea23e611a refactor(landing): phase4 - stop blocking the landing on the project sync
Entering an organization (`$organizationId._index`) no longer awaits
`syncProjects`: it lands with local data, and the startup sync that
Phase 3 runs on entering an organization brings the team projects in
the background.

What the blocking sync made safe, now handled by the empty project view:
- While the organization's startup sync has not finished, it shows a
  delayed loading indicator rather than the "create a project" form.
  `useStartupSyncStatus` exposes the raw status of the startup sync
  query, `pending` from this route's first render.
- Creating the "Drafts" project on an account's first landing moves from
  the loader into the component: it used to rely on the team projects
  having been synced already, so it would now add a Drafts project to an
  organization whose projects simply haven't arrived yet. It waits for
  the sync to succeed and checks the database, not the cache, before
  creating; deduped per organization in the mutation cache.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-03 16:25:22 +08:00
Curry Yang 441b894b15 fix: type 2026-11-03 16:25:21 +08:00
Curry YangandClaude Opus 5.5 6963772bae fix(landing): read the import modal's workspace name inside the cache providers
`Root` read `useWorkspaceLoaderData()` in its own body for the import
modal's header. Since the workspace facade derives its project fields from
the organization data query, that read calls `useDBQueryClient`, and Root's
body sits outside `AppDataCacheProvider`, which Root itself renders: every
render threw "useDBQueryClient must be used within an AppDataCacheProvider".

The read moves into `RootImportModal`, rendered inside the providers. It
also means Root no longer subscribes to organization data, so it doesn't
re-render on every change to it; the modal only reads it while open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:25:21 +08:00
Curry YangandClaude Opus 5.5 e4805c90c5 refactor(landing): one useActiveProject hook for the project facades
`useProjectLoaderData` no longer read any loader data, and the workspace
facade repeated its derivation (including stripping the joined git
repository). Both now use `useActiveProject` from `ui/hooks`, and the
project facade is removed; its consumers call the hook directly.

The hook subscribes to the project only (`select`): organization data
changes on every workspace meta write, which is patched into it, and the
selected project keeps its reference while unchanged, so those writes no
longer re-render the hook's callers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:25:21 +08:00
Curry YangandClaude Opus 5.5 df74b47fa6 refactor(landing): startup sync as a query
"Once per organization and session" is what a query keyed by organization
already does, so the startup sync no longer needs to emulate it on top of a
mutation (looking the run up in the mutation cache from an effect, keeping
runs with `gcTime: Infinity`, reading the status through `useMutationState`
to survive StrictMode). It is now `startupSyncQuery(orgId)`: every reader
shares one run, `refetch` is the retry, and `retryOnMount: false` keeps a
failed run from retrying by itself when the layout mounts again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:25:21 +08:00
Curry YangandClaude Opus 5.5 d16ead978c refactor(landing): phase3 - sync-projects action as a mutation
TeamProjectChanged from the event stream now syncs through useSyncProjects
instead of submitting the sync-projects action. The results reach the UI via
db.changes, and the no-project view moves on by itself once projects appear,
so the action's loader re-run is no longer needed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-03 16:25:21 +08:00
Curry YangandClaude Opus 5.5 19ad8a22a8 refactor(landing): phase3 - startup sync as a mutation, drop asyncTaskList
Replace the asyncTaskList router state and the sync-organizations-and-projects
action with a background mutation (useStartupSync). It runs the first time an
organization is entered in a session, migrating legacy projects before syncing
team projects, and no longer relies on the action re-running loaders.

What used to refresh through that re-run now follows db.changes:
- project route: the loader only guards the session and prefetches organization
  data; useProjectLoaderData derives the project from it, and a missing project
  renders MissingEntityRedirect (re-read once, then redirect when idle)
- workspace facade: activeProject / projects derive from organization data
- project home: local files come from localFilesQuery
- no-project view: redirects once projects appear

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-03 16:25:21 +08:00
Curry YangandClaude Opus 5.5 a94b73e309 refactor(landing): drop skipActionRevalidation until a route needs it
Nothing in this PR exports it: the routes whose data moves to queries keep
re-running after actions until every field they serve comes from a query
(Phase 7d). Add it back together with the first route that uses it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:25:20 +08:00
Curry YangandClaude Opus 5.5 ad34569fc5 fix(landing): break import cycles introduced by useUntrackedProjects
`useUntrackedProjects` read `useRootLoaderData` from `~/root` and
`useOrganizations` from `use-account-server-data` (which also imports
`~/root`). Since `import-export.tsx` is reached from root through the
settings modal, both added new cycles back to root. Take the
organizations and account id from the callers, which already have them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:25:20 +08:00
Curry YangandClaude Opus 5.5 cdb83a73b7 refactor(landing): replace untracked-projects fetcher with a DB query
The untracked-projects route was only ever loaded through a fetcher on mount
(organization layout and the import/export settings), and refreshed as a
side effect of every action's revalidation.

- Add `untrackedProjectsQuery` keyed by the tracked organization ids, derived
  reactively from `useOrganizations()` instead of reading localStorage.
- Invalidate it from `updateAppDataOnDbChanges` on project / workspace changes.
- Count workspaces per project in parallel instead of serially.
- Remove the `untracked-projects` route.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:25:20 +08:00
Curry YangandClaude Opus 5.5 e2eb19f135 refactor(landing): phase1 - query client singletons and shared query options
Infrastructure for moving landing-path data off React Router loaders onto
TanStack Query. No behaviour change intended.

- Export module-level `dbQueryClient` / `serverQueryClient`; providers use
  them so loaders can call `ensureQueryData` on the same cache as the hooks.
- Subscribe `db.changes` at module level instead of in the provider effect,
  so the cache stays in sync before the provider mounts.
- Lift `AppDataCacheProvider` from the organization layout into root.
- Clear both caches on logout and cross-window session change, since
  the clients now outlive the organization subtree.
- Add `organizationDataQuery`, `workspaceChildrenQuery` and
  `accountServerDataQuery` option factories shared by hooks and loaders.
- Add `useDBMutation` / `useServerMutation`.
- Add `skipActionRevalidation` for loaders whose data is owned by queries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 16:25:20 +08:00
Bingbing bf6dc9658e fix(smoke-test): drop test title from trace file names (#10696)
## Background

CI occasionally fails while uploading smoke test traces with `The path for one of the files in artifact is not valid: ... Colon :`.

The Electron-context trace in the `app` fixture names the zip file from the raw `testInfo.title`. Titles such as `project environment: show variable source and value renders the source inline` contain a colon, which `actions/upload-artifact` rejects. On Windows the file cannot be written at all. Because traces are retained only for failed tests, the upload error also hides the real test failure.

## Changes

- Name the trace `trace-${testInfo.status}.zip` instead of embedding the test title.
- `testInfo.outputDir` already contains the sanitized test title, project, retry, and repeat index, so the title in the file name adds only redundancy and invalid characters.

## Testing

- `npm run test:dev -w insomnia-smoke-test -- --project=Smoke --trace on -g "project environment: show variable source and value renders the source inline"` → 1 passed; trace written as `traces/smoke-variable-source-live-...-Smoke/trace-passed.zip`.
- `eslint packages/insomnia-smoke-test/playwright/test.ts`
2026-11-02 16:32:48 +08:00
Bingbing f6f3849594 refactor: extract useRootLoaderData out of root.tsx (break 55 circular imports) (#10494)
[INS-3831](https://konghq.atlassian.net/browse/INS-3831)

## Summary
- Extract `useRootLoaderData` + `RootLoaderData` from `src/root.tsx` into `src/ui/hooks/use-root-loader-data.ts`.
- Repoint all 65 importers from `~/root` to the new module, plus the two `vi.mock('~/root')` test stubs; remove the now-dead exports (and divergent stale shape) from root.tsx; annotate `clientLoader` return as `Promise<RootLoaderData>`.
- Hook return type keeps the documented `| undefined` contract of `useRouteLoaderData`.

## Why
root.tsx imports modals/settings/codemirror modules which import `useRootLoaderData` back — 55 of the 83 baselined cycles close through this single edge.
2026-10-29 10:55:26 +00:00
George d6e9ea3ade refactor: improve scratchpad tutorial panel snooze time (#10672)
* chore: improve scratchpad tutorial panel snooze time

* fix: comment
2026-10-29 08:32:05 +00:00
Bingbing f4d768160b refactor: inject curl executor into scripting environment (#10483)
[INS-3767](https://konghq.atlassian.net/browse/INS-3767)

## Summary
- Remove the scripting environment dependency on Insomnia's libcurl module.
- Inject a curl request executor into InsomniaObject instead.
- Keep node execution on the node curl implementation and renderer execution on the hidden-window bridge.
- Enable TypeScript checking for the scripting-environment source after the application runtime dependency is removed.

## Risk isolation
This is intentionally stacked on #10482 so the curlRequest plumbing can be reviewed separately.
2026-10-29 07:59:13 +00:00
yaoweiprcandClaude Sonnet 5 547a7f291a fix(Git Diff): clarify invalid file message in visual diff view (#10677)
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-29 07:26:59 +00:00
Curry Yang 1d42a66ac8 chore: update dompurify (#10667) 2026-10-28 10:21:22 +00:00
Bingbing 7863413757 fix: clear stale sync flags after a project leaves cloud sync [INS-3899] (#10668)
## Background

Workspace `hasUncommittedChanges` / `hasUnpushedChanges` flags are written only by cloud sync. When a project stopped being a cloud project, those flags were never cleared, so the project overview cards kept showing "Uncommitted changes".

Repro:

1. Open a cloud project whose workspaces have uncommitted changes.
2. Remove the project from the remote.
3. Open the project overview. The cards still show "Uncommitted changes" although the project is now local.

A project converted from cloud to git carries the same residual flags, because the values come from its former cloud state.

## Changes

- Clear both workspace sync flags when a project's `remoteId` becomes `null` in the project service. Remote deletion, conversion to local, cross-organization move, and conversion to git all update the project through this service.
- Reuse the cleanup in the startup database repair to fix existing stale records. Only dirty workspace metas are written, and `modified` is preserved.
- Add service and repair tests.

## Testing

- `npm test -w insomnia-data` (538 tests)
- `npm run type-check -w insomnia-data`
- `npm run lint -w insomnia-data`

## References

- INS-3899
2026-10-28 09:58:34 +00:00
kwburns-kong 1251e39523 fix(sync): INS-3700 (#10560)
* fix(sync): enforce write containment against symlinks in git sync

isomorphic-git checkout could create a symlink whose relative target
resolves outside the repo's working directory (fs-client.ts had no
containment check on symlink targets). Later, automatic disk flushes
(project lint ruleset, workspace YAML exports) wrote through that path
with a plain fs.promises.writeFile, which follows symlinks, letting
committed repo content land on a file outside the repo.

- fs-client.ts: reject symlink targets that resolve outside the repo
  during checkout.
- Add main/safe-fs-write.ts: a shared write helper that opens the final
  path component with O_NOFOLLOW and verifies (via realpath) that no
  symlinked intermediate directory can redirect the write outside the
  intended base directory.
- Apply it to every write site that joins a stored/imported relative
  path onto a project directory: repo-file-watcher.ts's four flush
  writers, the clone-flow ruleset write in git-service.ts, and
  git-repo-migration.ts's workspace export writer.
- Sanitize gitFilePath at its source (common/import.ts) so an imported
  workspace/collection name can no longer inject a path separator or
  traversal sequence.
- Add the same containment check to backup.ts's restoreBackup, which
  joins a renderer-supplied version string onto the backups directory
  with no prior validation.

Each fix has a regression test verified to fail against the prior
code and pass against the fix.

* fix(sync): surface writes blocked outside the git working directory

isomorphic-git's checkout write phase catches each file/symlink write
error itself and never rethrows, so a containment refusal during
checkout previously had no way to reach the user. Report it instead:

- fs-client.ts: call an onBlockedWrite hook before throwing.
- git-service.ts: route it into a pull's own result while a pull is in
  flight, otherwise record it as a file problem.
- git-vcs.ts: pullWithConflictSupport collects and dedupes blocked
  writes and folds them into that pull's own success/failure result.
- repo-file-watcher.ts: the DB→FS flush now reports and clears
  write-blocked problems per path instead of only logging them.
- git-project-sync-dropdown.tsx: toast once per newly-blocked path for
  writes blocked outside of an active pull.

* fix(sync): don't reject in-repo files whose name legally starts with ..

path.relative() returns a string starting with .. for a legitimate
filename like ..notes.yaml inside the base directory, not just for
a real traversal. The lexical containment check in fs-client.ts and
safe-fs-write.ts was misreading that as an escape attempt, so status,
pull, and push failed (and checkout silently dropped the file) for
such filenames. Only treat the relative path as an escape when it is
exactly .. or starts with a .. path segment.

* fix(sync): refuse a symlinked leaf on Windows before opening it

O_NOFOLLOW is unavailable on Windows, so the open() call there
followed a symlink at the final path component instead of refusing
it. Windows has allowed unprivileged symlink creation via Developer
Mode since 10 1703, so a crafted checkout's commit can still plant
such a symlink. Add an lstat pre-check gated on O_NOFOLLOW being
unavailable, refusing the write if the leaf is a symlink.

* fix(sync): show the real error in the write-blocked toast

Every write failure from the DB→FS flush (permission errors, disk
full, etc.) was labeled as a write blocked outside the git working
directory, hiding the actual cause from the user. Show the
underlying problem message alongside the path instead.

* fix(sync): report blocked writes with the correct client base path

The workspace-scoped FS client's onBlockedWrite handler always
resolved relPath against baseDir, even when reporting for the
"other" data client, which is actually rooted at baseDir/other. A
write blocked by that client recorded a filePath/relPath pair that
didn't match the real target, misleading the write-blocked problem
list. Bind the handler to each client's own base.

* fix(sync): skip orphan removal on pull when writes were blocked

importAllFiles ran before pullFromGitRemote checked pullResult for
blocked writes, so removeOrphanedWorkspaces could delete a
previously-synced workspace whose YAML checkout left disk in an
inconsistent state (file removed, replacement write refused) —
before the pull ever reported failure. Add a skipOrphanRemoval
option and set it whenever the pull reports blocked writes.

* fix(sync): surface blocked writes during the initial clone

The RepoFileWatcher isn't started until after initFromClone runs, so
its reportWriteBlocked was a no-op for the whole clone: a repository
whose checked-out commit held an escaping symlink or path silently
dropped that file and the clone still reported success. Collect
blocked writes directly around the clone call and return them as a
failure, matching how pull already reports them.

* fix(sync): harden fs-client symlink containment against pre-existing symlinks

resolveWithinBase only did a lexical ..-check, unlike safe-fs-write.ts's
assertPathWithinDir which also resolves ancestor-directory symlinks. A
directory or leaf file inside basePath that's already a symlink pointing
outside it (planted by some other mechanism) could let reads/writes
transparently escape basePath. Reuse assertPathWithinDir for the ancestor
check, and add a leaf-symlink guard for readFile/writeFile/stat.

* fix(git-sync): allow the repo working dir itself in safe-fs-write containment check

assertPathWithinDir checked the parent of the target, so when the target was the base dir itself (isomorphic-git stats/readdirs '.') the parent resolved outside the base and was rejected as a symlink escape, breaking git sync. The base is now treated as the trusted root. Also tighten the realpath '..' prefix check so names like '..foo' are not misclassified. Adds regression tests for '.', symlinked base dir, and in-repo symlink escape still being blocked.
2026-10-28 09:35:22 +00:00
yaoweiprcandClaude Sonnet 5.5 9cfd499185 fix: upgrade node-forge to 1.4.2 for CVE-2026-85393 (#10669)
* fix: upgrade node-forge to 1.4.2 for CVE-2026-85393 (INS-3936)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix: upgrade node-forge to 1.4.2 in component-docs lockfile (INS-3936)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-28 08:32:49 +00:00
Kent Wang eecc5b004e fix: handle invalid vault tag when there is no args set (#10663)
* handle invalid vault tag when no args is set

* add a errorboundary
2026-10-27 14:43:27 +08:00
Kent Wang 038eb606ed fix: Request name is applied to request list css (#10659)
* fix request name is applied to request list css issue

* using test id instead
2026-10-27 03:07:47 +00:00
Kent Wang 96edcab595 fix: Hashcorp vault form to support the new credential pattern (#10658)
* fix credential id issue

* add unit test

* fix issues from comment
2026-10-26 10:42:49 +00:00
GeorgeandClaude Sonnet 5.5 7dc422dfac fix: closing modal when deleting local proj workspace (#10657)
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-26 09:34:51 +00:00
Kent Wang 0fe6a0c576 fix: MCP primitive UI issue when returning item with same name (#10655)
* fix mcp item with same name issue

* fix selected issue
2026-10-26 16:11:29 +08:00
Bingbing 9a468f990f fix: keep variable source tooltip interactive in the environments modal (#10650)
## Background

Inside the Manage Environments modal, hovering a template tag shows the variable-source tooltip but the bubble cannot be hovered, focused, or clicked, so its **Open** action does nothing. The bubble is portalled to `<body>`, outside the modal subtree, and react-aria marks everything outside an open modal inert.

Repro:

1. Open a collection's Manage Environments modal.
2. Hover a template tag in an environment value.
3. Hover the tooltip or click Open — no response.

Related issues found while fixing it:

- Clicking Open on a folder-environment source navigated the app but left the modal mounted over the destination.
- Once another environment was selected, Open for the same source did nothing, because the modal only reacted to a changed environment id.
- On the project environment page, the `?environmentId=` deep link could stop reapplying after an interrupted cleanup, so a repeated Open left the page on the previous environment.

## Changes

- Mark the tooltip bubble as a react-aria top layer (`data-react-aria-top-layer`), so an open modal does not make it inert or treat clicks inside it as outside interactions.
- Track the location key the environments modal was opened on and close it on any navigation, including search-only changes such as `?tab=environment` or `?environmentId=`.
- Keep the environments modal mounted and carry a request id with each open request, so every Open reselects the requested environment.
- Reapply the project environment page's `?environmentId=` selection on every navigation, not only when the search string changes.
- Add smoke coverage: Open works inside the modal, repeated Open reselects the source, no second dialog for a collection source, the modal closes on path and search navigation, and project-environment sources land on the environment page with the source selected.

## Testing

- `npm run test:smoke:dev -- tests/smoke/variable-source-live-preview.test.ts tests/smoke/environment-cascade.test.ts tests/smoke/global-environments.test.ts`
- `npm run type-check -w insomnia`
- eslint on changed files

New smoke cases were verified red before their fix and green after. The existing hover tooltip cases now reuse the hover retry helper to remove a flake.

## References

- INS-4113
2026-10-26 07:08:23 +00:00
Kent Wang 992605adf9 fix: Loose the id meta check for certain request models (#10656)
* loose the id meta id check

* update schema
2026-10-26 14:43:34 +08:00
Bingbing 121ab68e17 fix: attribute project environment page sources to the project [INS-4083] (#10649)
## Background

On a project environment page, a variable that resolves from the environment file's own base or sub environment showed `Collection Environment : <name>` as its source. The rendered value and the `Open` navigation were already correct, so only the source type was wrong.

Repro: open a project environment page, select a sub environment whose value references a base environment variable, then hover or click the variable tag. The source reads `Collection Environment` instead of `Project Environment`.

## Changes

- `getRenderContext` now tells `buildRenderContext` whether the rendered workspace is a project environment file.
- `buildEnvironmentRenderLayers` labels that workspace's own base and sub environment layers as `Project Environment` in that case.
- Merge order, source metadata ids, vault and confidentiality handling are unchanged.

## Testing

- New unit test in `render.test.ts` and a smoke test with a dedicated `project-environment-source.yaml` fixture; both fail without the fix.
- `vitest run src/common`: 831 passed.
- `tsc` and `eslint` pass on the changed packages.
- `variable-source-live-preview` smoke suite: 18 passed (one unrelated fixture-import flake passed on retry).

Refs: INS-4083, INS-3943
2026-10-26 03:13:02 +00:00
Kent Wang 88ae88d6e5 add unite test for mcp, focus on undici upgrade (#10648) 2026-10-23 15:17:42 +08:00
Kent Wang fee93b675a fix issues caused by undici bump (#10645) 2026-10-22 09:24:47 +00:00
George 25858ff7c8 fix(one-line-editor): after clicking add button, focus should be on the new one line editor (#10631)
* fix: after clicking add button, focus should be on the new one line editor

* fix: comment
2026-10-22 08:25:03 +00:00
yaoweiprcandClaude Opus 5.5 95fcf1b4fc feat(Git Diff): Warn when a file isn't in the format Insomnia writes [8/8] (#10641)
* feat(Git Diff): warn when a file isn't in the format Insomnia writes

The Visual view matches entities by id and splices them into a file written
the way Insomnia exports it, so a file in any other shape, eg. edited by hand,
can show incomplete cards, and acting on a card rewrites the whole file.

Each previewed diff now checks both sides by replaying them through Git Sync's
import -> export: a side that doesn't match the Insomnia file format shows a
note pointing to the Text view instead of cards, and a valid side Insomnia would
write differently (comments, formatting, order, missing or duplicated parts,
unrecognized fields, another version) shows a warning above the cards.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(Git Diff): show one format warning at most above the diff

A file with unrecognized fields, or one whose change is only Insomnia
reformatting it, already gets its own warning above the diff, which says more.
The Visual view's format warning no longer stacks on top of those, and its text
is shorter.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* perf(Git Diff): check a file's format in the background, not in diffFileLoader

The format check replays both sides of the diff through import -> export, which
held up every diff, including in the Text view. It's now a separate loader the
Visual view calls after rendering its cards, so the diff shows right away and
the warning follows once the check is done.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 08:04:44 +00:00
George 7498c30b57 fix(sidebar): scope the del shortcut without backspace (#10644)
* fix: scope the del shortcut without backspace

* test: add e2e
2026-10-22 07:49:51 +00:00
Curry YangandClaude Opus 5 59d832ba10 Fix/socket io&websocket payload in export (#10634)
* fix: carry Socket.IO and WebSocket payloads through the v5 format [INS-3123]

A Socket.IO request's body (event name, ack, args) lives in its own
SocketIOPayload document rather than on the request, and the Insomnia v5
YAML format did not represent it at all. WebSocketPayload has the same
shape and the same gap.

Duplicating a collection goes through a v5 export/import round-trip, so
the payload was silently dropped and the copy came back with an empty
Body tab while url and headers survived.

The same gap is worse under Git Sync projects: `deleteOrphans` removes
every workspace descendant that is `canSync` and absent from the imported
file, and the importer could never produce a payload. A `git pull`, a
checkout, an edit to any part of the YAML, or merely restarting the app
therefore deleted them. Editing a payload in the app never wrote to disk
either, since the exported YAML did not change, so those edits only ever
existed in the database until the next sync removed them.

Both request nodes now carry an optional `body` holding the payload
document's own id, so a re-import updates the same document instead of
orphaning it. An untouched payload is omitted entirely: opening a
Socket.IO request creates an empty payload document, and writing that out
would add a spurious block and a git diff to every repository.

The branches of `RequestCollectionSchema` are told apart only by the
`meta.id` prefix, and `z.object` strips unknown keys rather than
rejecting them, so a node without `meta` matched the WebSocket branch and
lost its Socket.IO-only keys — `eventListeners` already went this way.
Extend the existing `z.undefined()` guard idiom to cover them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: export Socket.IO requests from design documents

The design-scope export filter listed request groups, HTTP, WebSocket and
gRPC requests but not Socket.IO ones, so a Socket.IO request created in a
design document vanished from its YAML.

Under a Git Sync project that is data loss rather than a missing field:
the request is absent from the imported file, so `deleteOrphans` removes
the request document itself on the next sync.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(smoke): assert the Socket.IO body survives import

The fixture had a Socket.IO request whose body the v5 format could not
express, so the smoke test connected and sent nothing. Give it an event
name and a payload, and assert both are populated after importing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix comment

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-10-22 07:30:58 +00:00
Curry YangandClaude Opus 5.5 1a5a33aaed fix: keep confidential flags through v5 export/import and Git Sync (#10632)
* fix: keep confidential flags through v5 export/import and Git Sync

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* update schema

* fix comment

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 06:31:11 +00:00
5c14ddfa81 fix(vul): update grpc reflection deps (#10642)
* chore: update google-protobuf to 4.0.3 (INS-3888)

google-protobuf <4.0.3 has no depth limit when skipping unknown group
fields during binary deserialization, so a crafted payload of nested
START_GROUP tags overflows the call stack (AIKIDO-2026-834673).

It is only a transitive dependency (grpc-reflection-js at runtime,
@ravanallc/grpc-server-reflection in the smoke tests) and both declare a
^3.x range, so force 4.0.3 through root overrides. npm does not apply the
global override to the @ravanallc edge, hence the scoped override.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* chore: replace @ravanallc/grpc-server-reflection with @grpc/reflection (INS-3888)

@ravanallc/grpc-server-reflection is unmaintained (last release 2022) and
depends on google-protobuf ^3, which forced a scoped override to 4.0.3 for
the unknown-group recursion DoS fix.

The official @grpc/reflection uses protobufjs and does not depend on
google-protobuf. The smoke test server already loads the proto through
@grpc/proto-loader, so it builds the reflection service from that package
definition and the pre-built route_guide.bin fixture is no longer needed.

The scoped override is removed. Only the runtime grpc-reflection-js fork
still needs the global google-protobuf override.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* chore: update grpc-reflection-js to 0.4.0 and drop google-protobuf override (INS-3888)

grpc-reflection-js 0.4.0 depends on google-protobuf ^4.0.3, which contains
the fix for the unknown-group recursion DoS. The global google-protobuf
override is no longer needed, so remove it and refresh the lockfile to the
new fork commit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: yaoweiprc <6896642+yaoweiprc@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 06:00:01 +00:00
yaoweiprcandClaude Opus 5.5 1a0c2ad2db fix(Git Diff): don't let stage / unstage / discard actions overlap (#10638)
A card's Stage clicked right before "Stage this file" ran both at once: they
rewrite the same index entry, and whichever finished last won, so the file
could end up with only that one entity staged. The cards' busy guard didn't
cover the file-level buttons.

Every stage / unstage / discard in the commit modal now goes through one
gate. A card's action is skipped while another is in flight (it's computed
from the diff that one is about to change); file-level actions don't depend
on the diff on screen, so they wait for it instead of being dropped.

Fixes INS-4079.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 13:05:46 +08:00
yaoweiprcandClaude Opus 5.5 b647e8d515 fix(Git Diff): no Discard for an added base environment or cookie jar (#10637)
Insomnia recreates a workspace's base environment and cookie jar as soon as
they're missing, so discarding one that was just added (eg. in a new file)
was undone the next time the collection was opened. Their cards no longer
offer Discard; the file-level Discard removes a new file as a whole.

Fixes INS-4076.

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 12:39:40 +08:00
Kent Wang 53b9cf5ac0 feat: Show validation errors for invalid MCP tool/resource/prompt list responses (#10554)
* show primitive error detail

* fix type failures

* update the error content

* make update and refresh primitive could handle mcp server error properly

* fix issues from comment

* fix errors

* fix empty error issue

* fix issue from bugs

* add related unit test
2026-10-22 04:04:21 +00:00
Curry Yang c9b20dd809 fix/confidential variable (#10629)
* fix: url preview

* fix: mask confidential value in auth header

* hide eye icon when there are no confidential values

* fix comment

* fix

* fix: keep timeline lines parseable when redacting short confidential values

* fix: url preview prefix

* fix: url preview in codegen & copy as curl scenario

* fix: smoke test
2026-10-22 11:39:22 +08:00
0eb0410769 feat(Git Diff): discard individual entities, and write results the way Git Sync exports them (#10619)
Unstaged cards get a click-to-confirm Discard that rewrites only that entity in
the working-tree file and syncs it back into the database; discarding a folder
that only exists in the working tree warns that its contents go with it.

Before a per-entity stage, unstage or discard is written, the grafted file is
replayed through Git Sync's import -> export in a scratch in-memory database,
so it comes out exactly as Insomnia would export it. Files that can't be
replayed, or whose replay would add placeholder entities, are written as is.

Co-authored-by: James Gatz <jamesgatzos@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 03:23:03 +00:00
Bingbing 319c18e11f fix: ignore inherited keys when resolving variable source (#10640)
keyContextMeta is a plain object, so keys such as constructor or __proto__ resolved through Object.prototype and produced an empty Source row. Require an own property before indexing it, and cover the case in the smoke test.
2026-10-22 02:22:56 +00:00
yaoweiprcandClaude Sonnet 5.5 db419cdb87 feat: Debug Mode setting that enables the Git commit diagnostic panel [INS-3829] (#10470)
* diagnostic panel

* ci: temporarily enable code signing for PR #10470 recurring builds

* Revert "ci: temporarily enable code signing for PR #10470 recurring builds"

This reverts commit d10322c979.

* feat: gate the Git change analysis behind a Debug Mode setting [INS-3829]

Add a per-user `debugMode` setting, toggled from Help > Enable/Disable Debug
Mode (right under Show App Logs Folder). The Git commit dialog's change
analysis is now only computed and rendered while it is on.

- diffFileLoader skips buildInsomniaChangeReport and returns no diagnostics
  when debugMode is off, so the dialog pays nothing for it.
- The menu label follows the setting across every open window via db.onChange.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix: key change-report containers by parent id instead of display path

The container identity embedded the parent's display path, so renaming a
folder or collection made every descendant look moved and skipped reorder
detection inside the renamed parent, and same-named parents were merged into
one reorder group. Key containers by the parent id and keep the path only as
a display label.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 13:53:50 +00:00
9d2222cc7c feat(Git Diff): Stage and unstage individual entities [4/5] (#10618)
* feat(Git Diff): stage and unstage individual entities from the Visual diff view

Every card gets a Stage (or Unstage) button. The file's index entry is set to
the base side with only that entity grafted in from the other side, written
straight into git's index so the rest of the file's changes stay where they
are. Staging the last entity of a deleted file stages the deletion, and
unstaging the last entity of a new file takes it out of the index.

Co-authored-by: James Gatz <jamesgatzos@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* chore: retrigger CI

A queued e2e re-run on the previous commit got stuck and kept the required
checks from being reported. An empty commit starts a fresh set of runs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: James Gatz <jamesgatzos@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 20:14:33 +08:00
Curry Yang 4c35c25626 feat/option toggle prompt (#10607)
* change option text

* add space between icon

* add option toggle prompt

* fix smoke test

* fix comment

* update response clear UI
2026-10-21 18:32:18 +08:00
Bingbing b6c7a0c53c fix: sync variable source with live preview edits (#10639)
## Background:
The Edit Variable modal captured a variable's source when its chip was clicked and kept it for the modal's lifetime. Switching the selected variable or editing a custom template refreshed the Live Preview but left the Source row and Open action pointing at the previous environment.

## Changes:
- Derive the source from the current template via the render context inside VariableEditor; hide the row unless the template is exactly one known variable reference.
- Ignore superseded async runs so preview, error, options and source always describe the same template.
- Drop the one-shot variableSource option from NunjucksModal; onOpenSource now receives the freshly derived metadata.
- Cover variable switching, custom-template editing, hiding and Open in the variable-source smoke test.

Follow-up to #10583.
2026-10-21 10:14:48 +00:00