From 010c37fa4419fa1d11d961c4e38919f726287c4e Mon Sep 17 00:00:00 2001 From: Bingbing Date: Tue, 3 Nov 2026 11:29:17 +0800 Subject: [PATCH] refactor: break route<->component circular dependencies in debug/mock routes ## Background The debug and mock-route routes are imported back by the components they render: the gRPC panes import `GrpcRequestState` from the debug route, and the mock editors and panes import the loader hook and patcher from the mock-route route. The request update action also imports `updateMimeType` from the content-type dropdown, which pulls `use-request` back to the action route. Those edges close six route <-> component cycles. ## Changes - Move `GrpcMessage`/`GrpcRequestState` to `ui/utils/grpc.ts`; repoint the debug route and the two gRPC panes. - Move the mock-route loader hook and patcher into `ui/hooks/use-mock-route.ts`. The route keeps its `clientLoader` and `satisfies MockRouteLoaderData`; the components import the neutral hook. The patcher still uses the update action route's generated fetcher. - Move the pure `updateMimeType`/`newBodyGraphQL` helpers from the content-type dropdown into `common/request-mime-type.ts`, so the action route no longer imports a UI component. - Remove the six now-resolved entries from `scripts/circular-references/known-violations.json`. ## Testing - `npm run check-cycle-references`: insomnia 19 -> 13 cycles, 0 new. - `npm run type-check -w insomnia` and eslint on the changed files: clean. ## References Follows #10496 in the circular-reference cleanup chain. --- .../insomnia/src/common/request-mime-type.ts | 68 +++++++++++++++++++ ...paceId.debug.request.$requestId.update.tsx | 2 +- ...projectId.workspace.$workspaceId.debug.tsx | 24 ++----- ...Id.mock-server.mock-route.$mockRouteId.tsx | 43 ++---------- .../dropdowns/content-type-dropdown.tsx | 60 ---------------- .../editors/mock-response-extractor.tsx | 6 +- .../editors/mock-response-headers-editor.tsx | 5 +- .../components/mocks/mock-response-pane.tsx | 2 +- .../src/ui/components/mocks/mock-url-bar.tsx | 2 +- .../ui/components/panes/grpc-request-pane.tsx | 2 +- .../components/panes/grpc-response-pane.tsx | 2 +- .../insomnia/src/ui/hooks/use-mock-route.ts | 40 +++++++++++ packages/insomnia/src/ui/utils/grpc.ts | 20 ++++++ .../circular-references/known-violations.json | 6 -- 14 files changed, 146 insertions(+), 136 deletions(-) create mode 100644 packages/insomnia/src/common/request-mime-type.ts create mode 100644 packages/insomnia/src/ui/hooks/use-mock-route.ts diff --git a/packages/insomnia/src/common/request-mime-type.ts b/packages/insomnia/src/common/request-mime-type.ts new file mode 100644 index 0000000000..fc0ea6885e --- /dev/null +++ b/packages/insomnia/src/common/request-mime-type.ts @@ -0,0 +1,68 @@ +import type { Request, RequestBody, RequestHeader, RequestParameter } from 'insomnia-data'; +import { deconstructQueryStringToParams } from 'insomnia-data/common'; + +import { + CONTENT_TYPE_FILE, + CONTENT_TYPE_FORM_DATA, + CONTENT_TYPE_FORM_URLENCODED, + CONTENT_TYPE_GRAPHQL, + CONTENT_TYPE_JSON, + METHOD_POST, +} from '~/common/constants'; + +function newBodyGraphQL(rawBody: string): RequestBody { + try { + // Only strip the newlines if rawBody is a parsable JSON + JSON.parse(rawBody); + return { + mimeType: CONTENT_TYPE_GRAPHQL, + text: rawBody.replace(/\\\\n/g, ''), + }; + } catch (error) { + if (error instanceof SyntaxError) { + return { + mimeType: CONTENT_TYPE_GRAPHQL, + text: rawBody, + }; + } + throw error; + } +} + +export const updateMimeType = ( + request: Request, + mimeType: string | null, +): { body: RequestBody; headers: RequestHeader[]; params?: RequestParameter[]; method?: string } => { + const withoutContentType = request.headers.filter(h => h?.name?.toLowerCase() !== 'content-type'); + // 'No body' selected + if (typeof mimeType !== 'string') { + return { + body: {}, + headers: withoutContentType, + }; + } + if (mimeType === CONTENT_TYPE_GRAPHQL) { + return { + body: newBodyGraphQL(request.body.text || ''), + headers: [{ name: 'Content-Type', value: CONTENT_TYPE_JSON }, ...withoutContentType], + method: METHOD_POST, + }; + } + if (mimeType === CONTENT_TYPE_FORM_URLENCODED || mimeType === CONTENT_TYPE_FORM_DATA) { + const params = request.body.params || deconstructQueryStringToParams(request.body.text); + return { + body: { mimeType, params }, + headers: [{ name: 'Content-Type', value: mimeType || '' }, ...withoutContentType], + }; + } + if (mimeType === CONTENT_TYPE_FILE) { + return { + body: { mimeType, fileName: '' }, + headers: [{ name: 'Content-Type', value: mimeType || '' }, ...withoutContentType], + }; + } + return { + body: { mimeType: mimeType.split(';')[0], text: request.body.text || '' }, + headers: [{ name: 'Content-Type', value: mimeType || '' }, ...withoutContentType], + }; +}; diff --git a/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId.update.tsx b/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId.update.tsx index 5b67f9c08c..025a4bdd28 100644 --- a/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId.update.tsx +++ b/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId.update.tsx @@ -2,9 +2,9 @@ import type { WebSocketRequest } from 'insomnia-data'; import { models, services } from 'insomnia-data'; import { href } from 'react-router'; +import { updateMimeType } from '~/common/request-mime-type'; import { invariant } from '~/common/utils/invariant'; import { AnalyticsEvent } from '~/ui/analytics'; -import { updateMimeType } from '~/ui/components/dropdowns/content-type-dropdown'; import { createFetcherSubmitHook } from '~/ui/utils/router'; import type { Route } from './+types/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId.update'; diff --git a/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.tsx b/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.tsx index 977b3c7b21..6ac00ccc8f 100644 --- a/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.tsx +++ b/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.tsx @@ -1,4 +1,3 @@ -import type { ServiceError, StatusObject } from '@grpc/grpc-js'; import type { ChangeBufferEvent, Request } from 'insomnia-data'; import { models, services } from 'insomnia-data'; import type { OpenAPIV3 } from 'openapi-types'; @@ -8,7 +7,6 @@ import { href, redirect, useLoaderData, useMatch, useParams } from 'react-router import YAML from 'yaml'; import { generateId } from '~/common/misc'; -import type { GrpcMethodInfo } from '~/main/ipc/grpc'; import { useWorkspaceLoaderData, WORKSPACE_CONTENT_WRAPPER, @@ -47,29 +45,17 @@ import { useTabNavigate } from '~/ui/hooks/use-insomnia-tab'; import { type CreateRequestType, useRequestMetaPatcher } from '~/ui/hooks/use-request'; import { useRootLoaderData } from '~/ui/hooks/use-root-loader-data'; import { resolveGitRepoBaseDir } from '~/ui/utils/git-repo-path'; -import { getGrpcConnectionErrorDetails, isGrpcConnectionError } from '~/ui/utils/grpc'; +import { + getGrpcConnectionErrorDetails, + type GrpcRequestState, + isGrpcConnectionError, +} from '~/ui/utils/grpc'; import type { Route } from './+types/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug'; const { isEventStreamRequest, isGraphqlSubscriptionRequest, isRequest, isRequestId } = models.request; const { isRequestGroupId } = models.requestGroup; -export interface GrpcMessage { - id: string; - text: string; - created: number; -} - -export interface GrpcRequestState { - requestId: string; - running: boolean; - requestMessages: GrpcMessage[]; - responseMessages: GrpcMessage[]; - status?: StatusObject; - error?: ServiceError; - methods: GrpcMethodInfo[]; -} - const INITIAL_GRPC_REQUEST_STATE = { running: false, requestMessages: [], diff --git a/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId.tsx b/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId.tsx index 099038fbff..759eaf4e54 100644 --- a/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId.tsx +++ b/packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId.tsx @@ -1,11 +1,10 @@ import type * as Har from 'har-format'; import { isApiError, upsertMockbin } from 'insomnia-api'; -import type { MockRoute, MockServer, Request, RequestHeader, Response } from 'insomnia-data'; +import type { Request, RequestHeader, Response } from 'insomnia-data'; import { models, services } from 'insomnia-data'; import { RESPONSE_CODE_REASONS } from 'insomnia-data/common'; -import { useCallback } from 'react'; import { Button, Tab, TabList, TabPanel, Tabs, Toolbar } from 'react-aria-components'; -import { useParams, useRouteLoaderData } from 'react-router'; +import { useParams } from 'react-router'; import { CONTENT_TYPE_JSON, @@ -21,7 +20,6 @@ import { database as db } from '~/common/database'; import { invariant } from '~/common/utils/invariant'; import { utf8ByteLength } from '~/common/utils/utf8-bytes'; import { useRequestNewMockSendActionFetcher } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.new-mock-send'; -import { useMockRouteUpdateActionFetcher } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId.update'; import { AnalyticsEvent } from '~/ui/analytics'; import { CodeEditor } from '~/ui/components/.client/codemirror/code-editor'; import { Dropdown, DropdownItem, ItemContent } from '~/ui/components/base/dropdown'; @@ -33,16 +31,11 @@ import { AlertModal } from '~/ui/components/modals/alert-modal'; import { EmptyStatePane } from '~/ui/components/panes/empty-state-pane'; import { Pane, PaneBody, PaneHeader } from '~/ui/components/panes/pane'; import { SvgIcon } from '~/ui/components/svg-icon'; +import { type MockRouteLoaderData, useMockRouteLoaderData, useMockRoutePatcher } from '~/ui/hooks/use-mock-route'; import { useRootLoaderData } from '~/ui/hooks/use-root-loader-data'; import type { Route } from './+types/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId'; -export interface MockRouteLoaderData { - mockServer: MockServer; - mockRoute: MockRoute; - activeResponse?: Response; -} - export async function clientLoader({ params }: Route.ClientLoaderArgs) { const { workspaceId, mockRouteId } = params; @@ -73,7 +66,7 @@ export async function clientLoader({ params }: Route.ClientLoaderArgs) { mockServer, mockRoute, activeResponse, - }; + } satisfies MockRouteLoaderData; } const mockContentTypes = [ @@ -85,6 +78,7 @@ const mockContentTypes = [ ]; export const isInMockContentTypeList = (contentType: string): boolean => Boolean(contentType && mockContentTypes.includes(contentType)); + // mockbin expect a HAR response structure export const mockRouteToHar = async ({ statusCode, @@ -118,33 +112,6 @@ export const mockRouteToHar = async ({ }; }; -export const useMockRoutePatcher = () => { - const { organizationId, projectId, workspaceId } = useParams() as { - organizationId: string; - projectId: string; - workspaceId: string; - }; - const { submit } = useMockRouteUpdateActionFetcher(); - return useCallback( - (id: string, patch: Partial) => { - return submit({ - mockRouteId: id, - organizationId, - projectId, - workspaceId, - patch, - }); - }, - [organizationId, projectId, submit, workspaceId], - ); -}; - -export function useMockRouteLoaderData() { - return useRouteLoaderData( - 'routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId', - ); -} - export const MockRouteRoute = () => { const { mockServer, mockRoute } = useMockRouteLoaderData()!; diff --git a/packages/insomnia/src/ui/components/dropdowns/content-type-dropdown.tsx b/packages/insomnia/src/ui/components/dropdowns/content-type-dropdown.tsx index 3d5bda0751..1df7c12fbf 100644 --- a/packages/insomnia/src/ui/components/dropdowns/content-type-dropdown.tsx +++ b/packages/insomnia/src/ui/components/dropdowns/content-type-dropdown.tsx @@ -1,6 +1,4 @@ import type { IconName } from '@fortawesome/fontawesome-svg-core'; -import type { Request, RequestBody, RequestHeader, RequestParameter } from 'insomnia-data'; -import { deconstructQueryStringToParams } from 'insomnia-data/common'; import React, { type FC } from 'react'; import { Button, @@ -27,7 +25,6 @@ import { CONTENT_TYPE_XML, CONTENT_TYPE_YAML, getContentTypeName, - METHOD_POST, } from '../../../common/constants'; import { type RequestLoaderData, @@ -227,60 +224,3 @@ export const ContentTypeDropdown: FC = () => { ); }; - -export function newBodyGraphQL(rawBody: string): RequestBody { - try { - // Only strip the newlines if rawBody is a parsable JSON - JSON.parse(rawBody); - return { - mimeType: CONTENT_TYPE_GRAPHQL, - text: rawBody.replace(/\\\\n/g, ''), - }; - } catch (error) { - if (error instanceof SyntaxError) { - return { - mimeType: CONTENT_TYPE_GRAPHQL, - text: rawBody, - }; - } - throw error; - } -} - -export const updateMimeType = ( - request: Request, - mimeType: string | null, -): { body: RequestBody; headers: RequestHeader[]; params?: RequestParameter[]; method?: string } => { - const withoutContentType = request.headers.filter(h => h?.name?.toLowerCase() !== 'content-type'); - // 'No body' selected - if (typeof mimeType !== 'string') { - return { - body: {}, - headers: withoutContentType, - }; - } - if (mimeType === CONTENT_TYPE_GRAPHQL) { - return { - body: newBodyGraphQL(request.body.text || ''), - headers: [{ name: 'Content-Type', value: CONTENT_TYPE_JSON }, ...withoutContentType], - method: METHOD_POST, - }; - } - if (mimeType === CONTENT_TYPE_FORM_URLENCODED || mimeType === CONTENT_TYPE_FORM_DATA) { - const params = request.body.params || deconstructQueryStringToParams(request.body.text); - return { - body: { mimeType, params }, - headers: [{ name: 'Content-Type', value: mimeType || '' }, ...withoutContentType], - }; - } - if (mimeType === CONTENT_TYPE_FILE) { - return { - body: { mimeType, fileName: '' }, - headers: [{ name: 'Content-Type', value: mimeType || '' }, ...withoutContentType], - }; - } - return { - body: { mimeType: mimeType.split(';')[0], text: request.body.text || '' }, - headers: [{ name: 'Content-Type', value: mimeType || '' }, ...withoutContentType], - }; -}; diff --git a/packages/insomnia/src/ui/components/editors/mock-response-extractor.tsx b/packages/insomnia/src/ui/components/editors/mock-response-extractor.tsx index 6ffc370988..93c4d05d9d 100644 --- a/packages/insomnia/src/ui/components/editors/mock-response-extractor.tsx +++ b/packages/insomnia/src/ui/components/editors/mock-response-extractor.tsx @@ -4,11 +4,9 @@ import { Button } from 'react-aria-components'; import { useNavigate, useParams } from 'react-router'; import { useRequestLoaderData } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId'; -import { - isInMockContentTypeList, - useMockRoutePatcher, -} from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId'; +import { isInMockContentTypeList } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId'; import { useCurrentPlan } from '~/ui/hooks/use-account-server-data'; +import { useMockRoutePatcher } from '~/ui/hooks/use-mock-route'; import { getContentTypeName, getMimeTypeFromContentType } from '../../../common/constants'; import { useWorkspaceLoaderData } from '../../../routes/organization.$organizationId.project.$projectId.workspace.$workspaceId'; diff --git a/packages/insomnia/src/ui/components/editors/mock-response-headers-editor.tsx b/packages/insomnia/src/ui/components/editors/mock-response-headers-editor.tsx index 87453651b8..e4b04877a1 100644 --- a/packages/insomnia/src/ui/components/editors/mock-response-headers-editor.tsx +++ b/packages/insomnia/src/ui/components/editors/mock-response-headers-editor.tsx @@ -2,11 +2,8 @@ import type { RequestHeader } from 'insomnia-data'; import React, { type FC, useCallback } from 'react'; import { useParams } from 'react-router'; -import { - useMockRouteLoaderData, - useMockRoutePatcher, -} from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId'; import { CodeEditor } from '~/ui/components/.client/codemirror/code-editor'; +import { useMockRouteLoaderData, useMockRoutePatcher } from '~/ui/hooks/use-mock-route'; import { getCommonHeaderNames, getCommonHeaderValues } from '../../../common/common-headers'; import { KeyValueEditor } from '../key-value-editor/key-value-editor'; diff --git a/packages/insomnia/src/ui/components/mocks/mock-response-pane.tsx b/packages/insomnia/src/ui/components/mocks/mock-response-pane.tsx index bfba14274b..23cd11d637 100644 --- a/packages/insomnia/src/ui/components/mocks/mock-response-pane.tsx +++ b/packages/insomnia/src/ui/components/mocks/mock-response-pane.tsx @@ -8,8 +8,8 @@ import * as reactUse from 'react-use'; import { bodyBufferToUtf8 } from '~/common/utils/utf8-bytes'; import { useRequestNewMockSendActionFetcher } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.new-mock-send'; -import { useMockRouteLoaderData } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId'; import { CodeEditor } from '~/ui/components/.client/codemirror/code-editor'; +import { useMockRouteLoaderData } from '~/ui/hooks/use-mock-route'; import { useRootLoaderData } from '~/ui/hooks/use-root-loader-data'; import { jsonPrettify } from '~/ui/utils/prettify/json'; diff --git a/packages/insomnia/src/ui/components/mocks/mock-url-bar.tsx b/packages/insomnia/src/ui/components/mocks/mock-url-bar.tsx index 1bef010738..f71db58787 100644 --- a/packages/insomnia/src/ui/components/mocks/mock-url-bar.tsx +++ b/packages/insomnia/src/ui/components/mocks/mock-url-bar.tsx @@ -3,7 +3,7 @@ import React, { useEffect, useRef, useState } from 'react'; import { Button } from 'react-aria-components'; import * as reactUse from 'react-use'; -import { useMockRouteLoaderData } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId'; +import { useMockRouteLoaderData } from '~/ui/hooks/use-mock-route'; import { useRootLoaderData } from '~/ui/hooks/use-root-loader-data'; import { getMockServiceBinURL } from '../../../common/constants'; diff --git a/packages/insomnia/src/ui/components/panes/grpc-request-pane.tsx b/packages/insomnia/src/ui/components/panes/grpc-request-pane.tsx index 8d8a1c6d58..916af143c2 100644 --- a/packages/insomnia/src/ui/components/panes/grpc-request-pane.tsx +++ b/packages/insomnia/src/ui/components/panes/grpc-request-pane.tsx @@ -23,7 +23,6 @@ import { getRenderedGrpcRequest, getRenderedGrpcRequestMessage } from '../../../ import type { GrpcMethodType } from '../../../main/ipc/grpc'; import { getOrInheritHeaders } from '../../../network/network'; import { useWorkspaceLoaderData } from '../../../routes/organization.$organizationId.project.$projectId.workspace.$workspaceId'; -import type { GrpcRequestState } from '../../../routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug'; import { type GrpcRequestLoaderData, useRequestLoaderData, @@ -31,6 +30,7 @@ import { import { useInsomniaTabContext } from '../../context/app/insomnia-tab-context'; import { useRequestPatcher } from '../../hooks/use-request'; import { useGitVCSVersion } from '../../hooks/use-vcs-version'; +import type { GrpcRequestState } from '../../utils/grpc'; import { GrpcSendButton } from '../buttons/grpc-send-button'; import { GrpcMethodDropdown } from '../dropdowns/grpc-method-dropdown/grpc-method-dropdown'; import { ErrorBoundary } from '../error-boundary'; diff --git a/packages/insomnia/src/ui/components/panes/grpc-response-pane.tsx b/packages/insomnia/src/ui/components/panes/grpc-response-pane.tsx index 5b47888ffc..1197c349e1 100644 --- a/packages/insomnia/src/ui/components/panes/grpc-response-pane.tsx +++ b/packages/insomnia/src/ui/components/panes/grpc-response-pane.tsx @@ -3,7 +3,7 @@ import { Tab, TabList, TabPanel, Tabs } from 'react-aria-components'; import { CodeEditor } from '~/ui/components/.client/codemirror/code-editor'; -import type { GrpcRequestState } from '../../../routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug'; +import type { GrpcRequestState } from '../../utils/grpc'; import { GrpcStatusTag } from '../tags/grpc-status-tag'; import { Pane, PaneBody, PaneHeader } from './pane'; interface Props { diff --git a/packages/insomnia/src/ui/hooks/use-mock-route.ts b/packages/insomnia/src/ui/hooks/use-mock-route.ts new file mode 100644 index 0000000000..4cc478bcf8 --- /dev/null +++ b/packages/insomnia/src/ui/hooks/use-mock-route.ts @@ -0,0 +1,40 @@ +import type { MockRoute, MockServer, Response } from 'insomnia-data'; +import { useCallback } from 'react'; +import { useParams, useRouteLoaderData } from 'react-router'; + +import { useMockRouteUpdateActionFetcher } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId.update'; + +export interface MockRouteLoaderData { + mockServer: MockServer; + mockRoute: MockRoute; + activeResponse?: Response; +} + +// Reads the mock-route route's loader data by route id so consumers (and the route itself) don't +// import the route module, which renders those consumers — importing it would close a +// route <-> component cycle. The route's `clientLoader` conforms to `MockRouteLoaderData`. +export const useMockRouteLoaderData = () => + useRouteLoaderData( + 'routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId', + ) as MockRouteLoaderData | undefined; + +export const useMockRoutePatcher = () => { + const { organizationId, projectId, workspaceId } = useParams() as { + organizationId: string; + projectId: string; + workspaceId: string; + }; + const { submit } = useMockRouteUpdateActionFetcher(); + return useCallback( + (id: string, patch: Partial) => { + return submit({ + mockRouteId: id, + organizationId, + projectId, + workspaceId, + patch, + }); + }, + [organizationId, projectId, submit, workspaceId], + ); +}; diff --git a/packages/insomnia/src/ui/utils/grpc.ts b/packages/insomnia/src/ui/utils/grpc.ts index 476a739b3b..ee794f66e6 100644 --- a/packages/insomnia/src/ui/utils/grpc.ts +++ b/packages/insomnia/src/ui/utils/grpc.ts @@ -1,3 +1,7 @@ +import type { ServiceError, StatusObject } from '@grpc/grpc-js'; + +import type { GrpcMethodInfo } from '~/main/ipc/grpc'; + const GRPC_CONNECTION_ERROR_STRINGS = { SERVER_SELF_SIGNED: 'self signed certificate in certificate chain', CLIENT_CERT_REQUIRED: 'CERTIFICATE_REQUIRED', @@ -57,3 +61,19 @@ export function getGrpcConnectionErrorDetails(error: Error) { message, }; } + +export interface GrpcMessage { + id: string; + text: string; + created: number; +} + +export interface GrpcRequestState { + requestId: string; + running: boolean; + requestMessages: GrpcMessage[]; + responseMessages: GrpcMessage[]; + status?: StatusObject; + error?: ServiceError; + methods: GrpcMethodInfo[]; +} diff --git a/scripts/circular-references/known-violations.json b/scripts/circular-references/known-violations.json index 36ebff6029..98b2d71838 100644 --- a/scripts/circular-references/known-violations.json +++ b/scripts/circular-references/known-violations.json @@ -7,12 +7,6 @@ "packages/insomnia/src/main/plugin-window.ts -> packages/insomnia/src/main/window-utils.ts", "packages/insomnia/src/main/templating-worker-database.ts -> packages/insomnia/src/plugins/index.ts", "packages/insomnia/src/main/templating-worker-database.ts -> packages/insomnia/src/templating/index.ts -> packages/insomnia/src/plugins/index.ts", - "packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId.update.tsx -> packages/insomnia/src/ui/components/dropdowns/content-type-dropdown.tsx -> packages/insomnia/src/ui/hooks/use-request.ts", - "packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.tsx -> packages/insomnia/src/ui/components/panes/grpc-request-pane.tsx", - "packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.tsx -> packages/insomnia/src/ui/components/panes/grpc-response-pane.tsx", - "packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId.tsx -> packages/insomnia/src/ui/components/editors/mock-response-headers-editor.tsx", - "packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId.tsx -> packages/insomnia/src/ui/components/mocks/mock-response-pane.tsx", - "packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.mock-server.mock-route.$mockRouteId.tsx -> packages/insomnia/src/ui/components/mocks/mock-url-bar.tsx", "packages/insomnia/src/sync/git/providers/github.ts -> packages/insomnia/src/sync/git/utils.ts -> packages/insomnia/src/sync/git/providers/index.ts", "packages/insomnia/src/sync/git/providers/gitlab.ts -> packages/insomnia/src/sync/git/utils.ts -> packages/insomnia/src/sync/git/providers/index.ts", "packages/insomnia/src/ui/components/modals/export-requests-modal.tsx -> packages/insomnia/src/ui/components/settings/import-export.tsx",