feat(mock-api): implement endpoint for seeding Cloud Sync projects and handling associated state
feat(cloud-sync): enhance Cloud Sync page with unknown fields handling and commit confirmation dialogs
test(git-sync): add tests for handling unknown fields in commits and ensuring proper warnings are displayed
test(cloud-sync): implement tests for scenarios involving unknown fields in remote documents and their impact on commits
fix(tests): update existing tests to ensure compatibility with new unknown fields handling logic
- Implement tests to verify that request cards display all sections correctly, including parameters, body, authentication, headers, and scripts.
- Add tests to ensure that requests moved into new folders are handled correctly and can be restored.
- Verify that same-named headers are distinguished in the UI.
- Ensure Socket.IO and WebSocket request cards show their respective sections accurately.
- Test staging and unstaging requests maintains consistency in the staged and unstaged lists.
- Confirm that vault-backed secrets are masked in environment cards.
- Validate that the visual view shows appropriate notices for conflicted and non-Insomnia files.
- Ensure unknown fields are preserved during entity actions without introducing ghost changes.
* feat(Git Diff): add a read-only Visual diff view to the commit modal
Adds a "Visual (Beta)" toggle next to the Text diff in the staging modal. The
Visual view lists the changed entities of the previewed file as cards: requests
and folders get tabbed cards that mirror their editors, every other entity uses
a generic card for now. Each card has a Settings catch-all for changes no tab
shows, and long values are shown as a lazily created Monaco diff.
Also stops the Text view from hiding indentation-only changes, which are
structural in YAML.
Co-authored-by: James Gatz <jamesgatzos@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* test(Git Diff): show same-named params as rows, not via the Settings catch-all
With same-named items told apart in the diff, a change to one of them now
shows as its own row in the tab rather than as a raw value in the Settings
catch-all. The catch-all stays for changes a tab can't show as rows, such as
reordering.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(Git Diff): scroll long values inside a card instead of stretching it
A long value shown on one side only (eg. the body of a newly added request)
and a highlighted diff of a large change both grew to their full height, so one
card could be thousands of pixels tall. Both are now capped at `max-h-96` and
scroll inside; past their top or bottom the wheel scrolls the card list.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(Git Diff): start a card collapsed when it has nothing below its header
A card with no tabs (eg. only the name or URL changed) only had "No further
details to show." below its header, taking up a row for nothing. It now starts
collapsed; expanding it still shows that line.
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>
* feat: mask confidential valut in timeline
* mask longest first
* handle script log
* prevent circular dependency
* fix comment
* fix test
* feat: close the remaining confidential-value leaks to disk
Covers items #2-#5 and #7a of the post-T10 follow-up list.
Register values the script itself wrote (#2)
A pre-request script's console output is written before any render, and an
after-response script is followed by no render at all, so a value the script
put into a confidential key (insomnia.environment.set('token', ...)) was never
registered and reached the timeline in cleartext. tryToExecuteScript now
registers the script's output data before writing its logs.
The registration logic moves into registerConfidentialValues(layers, collector),
which takes confidential flags from kvPairData and values from the layer's data
- the same split buildRenderContext already uses at render time. The pre-fill
now goes through it too, so there is one implementation rather than two, and
disabled rows, SECRET rows and duplicate names behave identically in both.
Register numeric leaves (#5)
collectLeafStrings only collected strings, so a confidential JSON value like
{ "pin": 1234 } rendered into the request as plaintext. Renamed to
collectLeafValues; numbers register as String(value). Booleans, null and
non-finite numbers stay skipped - they carry no secrecy and would mangle
unrelated JSON. No minimum-length threshold, matching the trade-off already
accepted for short strings: over-redaction beats an unprotected short secret.
Redact response documents and test results (#3, #4)
Response documents are persisted without passing through the timeline's
withRedaction wrapper. Their url (the effective URL), error (most often a
script throw, which readily echoes a value - chai prints the actual value, and
V8 echoes its input for things like JSON.parse(token)) and requestTestResults
(user-supplied test names and chai's ACTUAL/EXPECTED) are now redacted at every
write point, including the RunnerTestResult the collection runner persists.
{% response 'url' %} now throws when it finds a redacted URL instead of
silently chaining the mask to the server. Storing the real URL and masking only
on display was the alternative, but that keeps plaintext secrets on disk.
Redact the four send-bypass paths (#7a)
The OAuth2 token request, plugin sendRequest, the templating worker's
dependent-request path and mock send all call sendCurlAndWriteTimeline without
a runtime. That does not skip the timeline - it falls back to the non-redacting
default - so all four wrote rendered confidential values to disk, in the
timeline as well as the response document.
The OAuth2 call also passed no render purpose, and the policy is fail-closed,
so it was interpolating the mask into the token request instead of the
credential. develop has the same omission (it affected SECRET vault values
there); marking a variable confidential widened it. Fixed with purpose: 'send',
which has to land together with the collector: on its own it would turn a
broken-but-safe path into a leaking one.
Verification
Unit tests for the helpers, plus a smoke spec that drives the real app and
reads what landed on disk, since none of this wiring is reachable from the
node test runtime. Three cases: setting on (nothing in the timeline or the
response document, but the real value still goes over the wire), a request
re-sent by a template tag, and - as a negative control, so the first case
cannot pass vacuously - setting off, where the values must be written in
cleartext.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix test
* fix comment
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
## Background
In a Git-synced project, restarting Insomnia without any change marked every design document as modified in the Git staging list. The diff of each affected YAML contained exactly one line: the embedded ApiSpec `meta.modified` timestamp.
The v5 design-doc YAML does not serialize `ApiSpec.fileName` (the v5 schema has no such field), while v5 import parses a missing `fileName` as an empty string. Any git round-trip therefore reset `fileName` to empty in the database, and the startup repair (`_applyApiSpecName`) rewrote it via `docUpdate`, which unconditionally restamped `modified: Date.now()` for every design document in one burst. RepoFileWatcher then re-exported the database to disk and git status reported all files as modified, repeating on every startup until committed.
## Changes
- Import: fall back `ApiSpec.fileName` to the file top-level name when the spec uses the `{ contents }` shape, so a round-trip never stores an empty fileName.
- Repair: skip the fileName backfill when it would write the existing value; a no-op write only restamps `modified`.
- Regression tests for both behaviors.
Fixes INS-4058
* add basic utility for cloud sync check
* do not show error when entire deleted
* add confirmation window when submit contains unknown fields in cloud sync
* feat(phase3-ui): apply confidential policy to all preview surfaces
Wire purpose:'preview' explicitly into RenderedText, RenderedQueryString,
CookiesModal, CodeEditor, and OneLineEditor so they respond to the
hideSecretValuesInPreviewAndConsole setting (Phase 3.2).
Refactor VariableEditor to use isRevealed state with forceReveal instead
of toggling purpose, making the eye button available for all variable
types (normal confidential, SECRET, external vault).
Short-circuit external vault tag run() in both liquid-extension.ts and
liquid-extension-worker.ts via shouldMaskExternalVaultTag() so no
provider fetch occurs when the policy says mask (Phase 3.3).
Add isRevealed/forceReveal to TagEditor for consistent reveal UX.
Wire purpose:'codegen' in request-actions-dropdown and
generate-code-modal callers to complete the codegen/export split
(Phase 3.4 UI callers).
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* refactor(phase3-ui): generate-code callers use purpose:preview instead of codegen
Now that codegen purpose has been removed from RenderPurpose, switch both
Generate Code modal and Copy as cURL (request-actions-dropdown) to pass
purpose:'preview'. Behaviour is identical: setting ON masks confidential values,
setting OFF reveals them.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* update
* fix: process in worker
* fix: smoke test
* fix lint
---------
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* feat(phase3-engine): implement confidential value policy and render engine
Introduce getConfidentialValuePolicy() as the single decision point for
reveal/mask across all render surfaces (Phase 3.0). Extend RenderPurpose
with 'codegen' and add forceReveal/getSettings() to BaseRenderContext.
Update buildRenderContext() to track per-key ConfidentialValueKind via
EnvironmentRenderLayer so normal-confidential KV pairs are masked before
entering renderSubContext() — preview cannot pollute subsequent send
(Phase 3.1).
Wire maskOrDecryptVaultDataIfNecessary() through the same policy so
SECRET reveal/mask follows hideSecretValuesInPreviewAndConsole.
Add explicit purpose:'codegen' to exportHarWithRequest/exportHarRequest
IPC path so Generate Code always masks confidential values independent of
the user setting (Phase 3.4 IPC layer).
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* refactor(phase3-engine): remove codegen purpose — generate-code callers use preview
codegen and preview now have identical policy semantics (both controlled by
hideSecretValuesInPreviewAndConsole; forceReveal only applies at call-site for
preview). Keeping a separate purpose added complexity with no behavioural benefit.
Remove 'codegen' from RenderPurpose, drop the codegen branch from
getConfidentialValuePolicy, and restore shouldMaskExternalVaultTag to intercept
only 'preview'. Generate Code / Copy as cURL callers will pass purpose:'preview'
instead (updated in the UI branch).
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* refactor(phase3-engine): extract buildEnvironmentRenderLayers from buildRenderContext
Pure extract-function: the environment layer construction is unchanged,
just moved into its own exported function so downstream stacked PRs
(T9/T10 confidential-value prefill) can reuse the same layer
enumeration instead of re-implementing it. buildRenderContext's
behavior is unchanged and remains covered by render.test.ts.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* fix(phase3-engine): stop buildEnvironmentRenderLayers mutating the ancestors array
for (const doc of (ancestors || []).reverse()) reversed the caller's
array in place. Now that the layer construction is extracted into a
standalone function, downstream callers (e.g. a T9/T10 prefill pass
that enumerates the same layers before the real render pass) can
receive the same ancestors array and call it twice, flipping the
folder precedence order on the second call. Copy before reversing so
the caller's array is left untouched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
* update
* fix: comment
---------
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Introduced `GitChangeList` enum to categorize changes as Staged or Unstaged.
- Implemented multiple test cases to verify the behavior of undiscardable changes:
- Committing a reordered file leaves the working tree clean.
- Confirming discard on a reordered file brings the change back.
- Mixed changes (real edits with reorders) are not flagged until the real edit is discarded.
- Non-Insomnia added and deleted files show no undiscardable warning.
- Files from older schemas are flagged as undiscardable.
- Real edits show no undiscardable warning in diffs or discard confirmations.
- Staged hand-reordered files show no undiscardable warning.
- Warnings are consistent in both diffs and discard confirmations for hand-reordered files.
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>
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>
Purpose-built cards for WebSocket, Socket.IO and gRPC requests, the MCP
request, mock routes, the cookie jar and environments, each with tabs that
mirror its editor. Vault-backed secrets are always masked.
Co-authored-by: James Gatz <jamesgatzos@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
With same-named items told apart in the diff, a change to one of them now
shows as its own row in the tab rather than as a raw value in the Settings
catch-all. The catch-all stays for changes a tab can't show as rows, such as
reordering.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds a "Visual (Beta)" toggle next to the Text diff in the staging modal. The
Visual view lists the changed entities of the previewed file as cards: requests
and folders get tabbed cards that mirror their editors, every other entity uses
a generic card for now. Each card has a Settings catch-all for changes no tab
shows, and long values are shown as a lazily created Monaco diff.
Also stops the Text view from hiding indentation-only changes, which are
structural in YAML.
Co-authored-by: James Gatz <jamesgatzos@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(Git Diff): add an entity-level diff engine for Insomnia YAML files
Parses both sides of a git-synced Insomnia file, matches requests, folders,
environments, mock routes, the MCP request, the cookie jar and the file-level
sections by id, and returns the added / removed / modified entities with their
field-level changes. Not wired into any UI yet.
Co-authored-by: James Gatz <jamesgatzos@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(Git Diff): tell same-named params and headers apart in the diff
diffByKey matched items by name only, so of two same-named items (eg. a
disabled default User-Agent header next to a custom one) the later hid the
earlier: a change to the first was invisible, and adding or removing one read
as a modification. Items sharing a name are now numbered by their order among
that name, as "User-Agent (1)" and "User-Agent (2)", on both sides.
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>
- Added McpPrimitiveType enum to categorize sidebar row types.
- Introduced McpListAction enum to standardize action names in capability menus.
- Updated references in tests and flows to use new enums instead of string literals for improved maintainability and clarity.
- Refactored related tests to ensure compatibility with the new enum structure.
- Added new methods in McpClientFlow for handling capability errors, toggling capabilities, refreshing lists, and loading more items.
- Implemented a scriptable list-response server for testing various scenarios with MCP Client.
- Introduced comprehensive tests for error responses, including handling invalid entries, whole-response errors, and ensuring proper UI behavior for error panels.
- Updated McpClientPage to manage capability items and their associated error panels more effectively.
- Enhanced constants and configuration for better server interaction and testing.
- Added new methods in McpClientFlow for handling capability errors, toggling capabilities, refreshing lists, and loading more items.
- Implemented a scriptable list-response server for testing various scenarios with MCP Client.
- Introduced comprehensive tests for error responses, including handling invalid entries, whole-response errors, and ensuring proper UI behavior for error panels.
- Updated McpClientPage to manage capability items and their associated error panels more effectively.
- Enhanced constants and configuration for better server interaction and testing.
* chore: bumped zod@3.25.76 to zod@4.6.5
Zod 4 treats a required z.undefined() object key as non-optional, so
absent keys in the RequestCollectionSchema union discriminators failed.
Wrap those keys in .optional() to keep v3 semantics.
Update the deep-strict auth test to expect the unrecognized_keys issue
that zod 4 reports for the strict empty-object fallback branch.
* chore: bumped jsdom@25.0.1 to jsdom@30.1.2
- Clears @asamuzakjp/css-color@3.2.0 advisory (AIKIDO-2026-199800); css-color now 7.1.4.
- No source changes needed: none of the jsdom 26-30 breaking changes hit the repo's jsdom tests.
* chore: bumped @bufbuild/protobuf@1.10.1 to @bufbuild/protobuf@2.16.0
Moves the gRPC stack to connect v2 alongside protobuf v2 (connect-node
and connect 1.7.0 -> 2.2.0). This clears the transitive undici 5.29.0
and @fastify/busboy 2.1.1 under connect-node 1.x.
Source changes:
- grpc.ts: createPromiseClient is removed in v2, so the reflection
service is now built from a FileDescriptorProto via fromJson and
createFileRegistry (proto3.makeMessageType is removed). The unary call
goes through transport.unary directly because createClient cannot type
a runtime-built descriptor.
- grpc.ts: toBinary takes the schema (FileDescriptorSetSchema from wkt).
- grpc.test.ts: mock transport uses the v2 unary signature (no service
argument, method.output, fromJsonString).
* chore: regenerate insomnia JSON schema for dependency bumps
* test: add grpc reflection regression tests for connect v2
* test: add smoke tests for buf reflection API
* fix: don't auto-send gRPC reflection API key on request open
* fix: drop non-standard starts_with format from published schema