feat: migrate models to insomnia-data - p6 (#9763)

This commit is contained in:
Bingbing
2026-04-08 17:09:02 +08:00
committed by GitHub
parent 6de2de31fe
commit 6a6bb4708d
166 changed files with 1553 additions and 1091 deletions

View File

@@ -10,8 +10,6 @@ import { pick } from 'es-toolkit';
import { isDevelopment, JSON_ORDER_PREFIX, JSON_ORDER_SEPARATOR } from 'insomnia/src/common/constants';
import { insomniaFetch } from 'insomnia/src/common/insomnia-fetch';
import { getSendRequestCallbackMemDb } from 'insomnia/src/common/send-request';
import type { Request } from 'insomnia/src/models/request';
import type { RequestGroup } from 'insomnia/src/models/request-group';
import { deserializeNDJSON } from 'insomnia/src/utils/ndjson';
import { configureFetch } from 'insomnia-api';
import { generate, runTestsCli } from 'insomnia-testing';
@@ -19,7 +17,7 @@ import orderedJSON from 'json-order';
import { parseArgsStringToArgv } from 'string-argv';
import { v4 as uuidv4 } from 'uuid';
import type { Environment, UserUploadEnvironment, Workspace } from '~/insomnia-data';
import type { Environment, Request, RequestGroup, UserUploadEnvironment, Workspace } from '~/insomnia-data';
import { initServices, models } from '~/insomnia-data';
import { servicesNodeImpl } from '~/insomnia-data/node';

View File

@@ -4,8 +4,14 @@ import nodePath from 'node:path';
import type { Consola } from 'consola';
import { pick } from 'es-toolkit';
import type { Environment, UserUploadEnvironment, Workspace } from '~/insomnia-data';
import type { Request, RequestAuthentication, RequestHeader } from '~/models/request';
import type {
Environment,
Request,
RequestAuthentication,
RequestHeader,
UserUploadEnvironment,
Workspace,
} from '~/insomnia-data';
import { typedKeys } from '~/utils';
import type { RequestTestResult } from '../../../../insomnia-scripting-environment/src/objects';

View File

@@ -1,6 +1,7 @@
import type { OAuth2ResponseType, RequestAuthentication } from 'insomnia/src/models/request';
import type { OAuth1SignatureMethod } from 'insomnia/src/network/o-auth-1/constants';
import type { OAuth2ResponseType, RequestAuthentication } from '~/insomnia-data';
import { Property } from './properties';
import { Variable, VariableList } from './variables';

View File

@@ -1,8 +1,7 @@
import { expect } from 'chai';
import type { RequestHeader } from 'insomnia/src/models/request';
import { filterClientCertificates } from 'insomnia/src/network/certificate';
import type { ClientCertificate, Settings } from '~/insomnia-data';
import type { ClientCertificate, RequestHeader, Settings } from '~/insomnia-data';
import { toPreRequestAuth } from './auth';
import { getExistingConsole } from './console';

View File

@@ -1,7 +1,6 @@
import type { Request } from 'insomnia/src/models/request';
import type { sendCurlAndWriteTimelineError, sendCurlAndWriteTimelineResponse } from 'insomnia/src/network/network';
import type { ClientCertificate, CookieJar, Settings } from '~/insomnia-data';
import type { ClientCertificate, CookieJar, Request, Settings } from '~/insomnia-data';
import type { ExecutionOption } from './execution';
import type { RequestInfoOption } from './request-info';

View File

@@ -1,12 +1,12 @@
import type {
ClientCertificate,
Request as InsomniaRequest,
RequestBody as InsomniaRequestBody,
RequestBodyParameter,
RequestPathParameter,
} from 'insomnia/src/models/request';
import type { Settings } from '~/insomnia-data';
import { type ClientCertificate, models } from '~/insomnia-data';
Settings,
} from '~/insomnia-data';
import { models } from '~/insomnia-data';
import { type AuthOptions, type AuthOptionTypes, fromPreRequestAuth, RequestAuth } from './auth';
import type { CertificateOptions } from './certificates';

View File

@@ -2,13 +2,11 @@ import path from 'node:path';
import { beforeEach, describe, expect, it } from 'vitest';
import type { Cookie } from '~/insomnia-data';
import type { Cookie, Request, Response } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { database as db } from '../../common/database';
import * as models from '../../models';
import type { Request } from '../../models/request';
import type { Response } from '../../models/response';
import { exportHar, exportHarResponse, exportHarWithRequest } from '../har';
import { getRenderedRequestAndContext } from '../render';
@@ -25,7 +23,7 @@ describe('export', () => {
_id: 'wrk_1',
name: 'Workspace',
});
const req1 = await models.request.create({
const req1 = await services.request.create({
_id: 'req_1',
name: 'Request 1',
parentId: wrk._id,
@@ -52,7 +50,7 @@ describe('export', () => {
},
],
});
await models.response.create({
await services.response.create({
parentId: req1._id,
statusCode: 200,
statusMessage: 'OK',
@@ -149,7 +147,7 @@ describe('export', () => {
_id: 'wrk_1',
name: 'Workspace',
});
const baseReq = await models.request.create({
const baseReq = await services.request.create({
_id: 'req_0',
type: models.request.type,
name: 'Request',
@@ -164,30 +162,30 @@ describe('export', () => {
},
],
});
const req1 = await models.request.duplicate(baseReq);
const req1 = await services.request.duplicate(baseReq);
req1._id = 'req_1';
req1.name = 'Request 1';
req1.headers.push({
name: 'X-Request',
value: '1',
});
await models.request.create(req1);
const req2 = await models.request.duplicate(baseReq);
await services.request.create(req1);
const req2 = await services.request.duplicate(baseReq);
req2._id = 'req_2';
req2.name = 'Request 2';
req2.headers.push({
name: 'X-Request',
value: '2',
});
await models.request.create(req2);
const req3 = await models.request.duplicate(baseReq);
await services.request.create(req2);
const req3 = await services.request.duplicate(baseReq);
req3._id = 'req_3';
req3.name = 'Request 3';
req3.headers.push({
name: 'X-Request',
value: '3',
});
await models.request.create(req3);
await services.request.create(req3);
const envBase = await services.environment.getOrCreateForParentId(workspace._id);
await services.environment.update(envBase, {
data: {
@@ -211,17 +209,17 @@ describe('export', () => {
envvalue: 'private',
},
});
await models.response.create({
await services.response.create({
_id: 'res_1',
parentId: req1._id,
statusCode: 204,
});
await models.response.create({
await services.response.create({
_id: 'res_2',
parentId: req2._id,
statusCode: 404,
});
await models.response.create({
await services.response.create({
_id: 'res_3',
parentId: req3._id,
statusCode: 500,

View File

@@ -6,7 +6,6 @@ import { parse } from 'yaml';
import { EnvironmentKvPairDataType, EnvironmentType, services } from '~/insomnia-data';
import { request, requestGroup } from '../../models';
import * as importUtil from '../import';
import { INSOMNIA_SCHEMA_VERSION } from '../insomnia-schema-migrations/schema-version';
import { tryImportV5Data } from '../insomnia-v5';
@@ -162,7 +161,7 @@ describe('importRaw()', () => {
const workspacesCount = await services.workspace.count();
const projectWorkspaces = await services.workspace.findByParentId(projectToImportTo._id);
const curlRequests = await request.findByParentId(projectWorkspaces[0]._id);
const curlRequests = await services.request.findByParentId(projectWorkspaces[0]._id);
expect(workspacesCount).toBe(1);
@@ -192,7 +191,7 @@ describe('importRaw()', () => {
workspaceId: existingWorkspace._id,
});
const curlRequests = await request.findByParentId(existingWorkspace._id);
const curlRequests = await services.request.findByParentId(existingWorkspace._id);
expect(curlRequests[0]).toMatchObject({
body: {
@@ -220,8 +219,8 @@ describe('importRaw()', () => {
const projectWorkspaces = await services.workspace.findByParentId(projectToImportTo._id);
const requestGroups = await requestGroup.findByParentId(projectWorkspaces[0]._id);
const requests = await request.findByParentId(requestGroups[0]._id);
const requestGroups = await services.requestGroup.findByParentId(projectWorkspaces[0]._id);
const requests = await services.request.findByParentId(requestGroups[0]._id);
expect(requests[0]).toMatchObject({
url: 'https://insomnia.rest',
@@ -247,8 +246,8 @@ describe('importRaw()', () => {
workspaceId: existingWorkspace._id,
});
const requestGroups = await requestGroup.findByParentId(existingWorkspace._id);
const requests = await request.findByParentId(requestGroups[0]._id);
const requestGroups = await services.requestGroup.findByParentId(existingWorkspace._id);
const requests = await services.request.findByParentId(requestGroups[0]._id);
expect(requests[0]).toMatchObject({
url: 'https://insomnia.rest',
@@ -495,7 +494,7 @@ describe('importRaw()', () => {
const workspaces = await importUtil.importResourcesToProject({ projectId: proj._id });
expect(workspaces).toHaveLength(1);
const reqs = await request.findByParentId(workspaces[0]._id);
const reqs = await services.request.findByParentId(workspaces[0]._id);
expect(reqs).toHaveLength(1);
});

View File

@@ -8,11 +8,10 @@
import { beforeEach, describe, expect, it } from 'vitest';
import YAML from 'yaml';
import type { Request } from '~/insomnia-data';
import { EnvironmentKvPairDataType, services } from '~/insomnia-data';
import { INSOMNIA_SCHEMA_VERSION } from '../../common/insomnia-schema-migrations/schema-version';
import * as models from '../../models';
import type { Request } from '../../models/request';
import { database as db } from '../database';
import {
getInsomniaV5DataExport,
@@ -168,7 +167,7 @@ collection: []
scope: 'collection',
});
await models.request.create({
await services.request.create({
_id: 'req_export_test',
name: 'Export Test Request',
parentId: workspace._id,
@@ -244,7 +243,7 @@ collection: []
data: {},
});
const req1 = await models.request.create({
const req1 = await services.request.create({
_id: 'req_filter_1',
name: 'Request 1',
parentId: workspace._id,
@@ -252,7 +251,7 @@ collection: []
method: 'GET',
});
await models.request.create({
await services.request.create({
_id: 'req_filter_2',
name: 'Request 2',
parentId: workspace._id,

View File

@@ -1,8 +1,9 @@
import type { RequestHeader } from '~/insomnia-data';
import allCharsets from '../datasets/charsets';
import allMimeTypes from '../datasets/content-types';
import allEncodings from '../datasets/encodings';
import allHeaderNames from '../datasets/header-names';
import type { RequestHeader } from '../models/request';
export const SINGLE_VALUE_HEADERS = [
'proxy-authorization',

View File

@@ -2,15 +2,12 @@ import clone from 'clone';
import type * as Har from 'har-format';
import { Cookie as ToughCookie } from 'tough-cookie';
import type { Workspace } from '~/insomnia-data';
import type { Request, RequestGroup, Response, Workspace } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { getBodyBuffer } from '~/models/helpers/response-operations';
import type { BaseModel } from '../models';
import * as models from '../models';
import { isRequest, type Request } from '../models/request';
import type { RequestGroup } from '../models/request-group';
import type { Response } from '../models/response';
import { getAuthHeader } from '../network/authentication';
import * as plugins from '../plugins';
import * as pluginApp from '../plugins/context/app';
@@ -26,6 +23,8 @@ import { database } from './database';
import { filterHeaders, getSetCookieHeaders, hasAuthHeader } from './misc';
import { getRenderedRequestAndContext } from './render';
const { isRequest } = models.request;
const getDocWithDescendants =
(includePrivateDocs = false) =>
async (parentDoc: BaseModel | null) => {
@@ -139,7 +138,7 @@ export async function exportHar(exportRequests: ExportRequest[]) {
const entries: Har.Entry[] = [];
for (const exportRequest of exportRequests) {
const request = await models.request.getById(exportRequest.requestId);
const request = await services.request.getById(exportRequest.requestId);
if (!request) {
continue;
@@ -152,8 +151,8 @@ export async function exportHar(exportRequests: ExportRequest[]) {
}
const response = await (exportRequest.responseId
? models.response.getById(exportRequest.responseId)
: models.response.getLatestForRequestId(exportRequest.requestId, exportRequest.environmentId || null));
? services.response.getById(exportRequest.responseId)
: services.response.getLatestForRequestId(exportRequest.requestId, exportRequest.environmentId || null));
const harResponse = await exportHarResponse(response);
@@ -227,7 +226,7 @@ export async function exportHarResponse(response?: Response) {
}
export async function exportHarRequest(requestId: string, environmentId: string, addContentLength = false) {
const request = await models.request.getById(requestId);
const request = await services.request.getById(requestId);
if (!request) {
return null;

View File

@@ -9,6 +9,7 @@ import type {
GrpcRequest,
McpRequest,
MockRoute,
Request,
SocketIORequest,
UnitTest,
UnitTestSuite,
@@ -24,8 +25,6 @@ import { pathWithParamsAsPathParameters } from '../main/importers/importers/open
import { id as postmanEnvImporterId } from '../main/importers/importers/postman-env';
import * as models from '../models/index';
import { type AllTypes, type BaseModel, getModel } from '../models/index';
import { isRequest, type Request } from '../models/request';
import { isRequestGroup } from '../models/request-group';
import { invariant } from '../utils/invariant';
import { parseApiSpec, type ParsedApiSpec } from './api-specs';
import { JSON_ORDER_PREFIX, JSON_ORDER_SEPARATOR } from './constants';
@@ -33,7 +32,9 @@ import { database as db } from './database';
import { tryImportV5Data } from './insomnia-v5';
import { generateId } from './misc';
const { isRequest } = models.request;
const { isApiSpec } = models.apiSpec;
const { isRequestGroup } = models.requestGroup;
export const IMPORT_SOURCE_TYPES = ['file', 'uri', 'curl', 'clipboard', 'mcp'] as const;
export type ImportSourceType = (typeof IMPORT_SOURCE_TYPES)[number];
@@ -560,7 +561,7 @@ export const importResourcesToWorkspace = async ({
} else if (models.unitTest.isUnitTest(resource)) {
await services.unitTest.create(objectToWrite);
} else if (isRequest(resource)) {
await models.request.create(objectToWrite);
await services.request.create(objectToWrite);
} else {
await db.docCreate(model.type, objectToWrite);
}
@@ -649,7 +650,7 @@ export const importResourcesToNewWorkspace = async ({
} else if (models.unitTest.isUnitTest(resource)) {
await services.unitTest.create(objectToWrite);
} else if (isRequest(resource)) {
await models.request.create(objectToWrite);
await services.request.create(objectToWrite);
} else {
await db.docCreate(model.type, objectToWrite);
}

View File

@@ -26,6 +26,11 @@ import type {
McpRequest,
MockRoute,
MockServer,
Request,
RequestBody,
RequestGroup,
RequestHeader,
RequestParameter,
SocketIORequest,
UnitTest,
UnitTestSuite,
@@ -38,8 +43,6 @@ import { maskVaultEnvironmentData } from '~/utils/environment-utils';
import { invariant } from '~/utils/invariant';
import * as models from '../models';
import type { Request, RequestBody, RequestHeader, RequestParameter } from '../models/request';
import type { RequestGroup } from '../models/request-group';
import { database } from './database';
import {
type Insomnia_GRPCRequest,

View File

@@ -6,6 +6,8 @@ import type {
GrpcRequest,
GrpcRequestBody,
McpRequest,
Request,
RequestGroup,
SocketIORequest,
UserUploadEnvironment,
WebSocketRequest,
@@ -14,8 +16,6 @@ import type {
import { services } from '~/insomnia-data';
import * as models from '../models';
import { PATH_PARAMETER_REGEX, type Request } from '../models/request';
import { isRequestGroup, type RequestGroup } from '../models/request-group';
import { getOrInheritAuthentication, getOrInheritHeaders } from '../network/network';
import * as templating from '../templating';
import { RenderError } from '../templating/render-error';
@@ -33,6 +33,9 @@ import { setDefaultProtocol } from '../utils/url/protocol';
import { CONTENT_TYPE_GRAPHQL, JSON_ORDER_SEPARATOR } from './constants';
import { database as db } from './database';
const { PATH_PARAMETER_REGEX } = models.request;
const { isRequestGroup } = models.requestGroup;
export async function buildRenderContext({
ancestors,
rootEnvironment,

View File

@@ -1,10 +1,11 @@
import type { GrpcRequest } from '~/insomnia-data';
import type { GrpcRequest, Request, RequestGroup } from '~/insomnia-data';
import { models } from '~/insomnia-data';
import { isRequest, type Request } from '../models/request';
import { isRequestGroup, type RequestGroup } from '../models/request-group';
import { type DashboardSortOrder, HTTP_METHODS, type SortOrder } from './constants';
const { isRequest } = models.request;
const { isRequestGroup } = models.requestGroup;
type SortableModel = Request | RequestGroup | GrpcRequest;
type SortFunction<SortableType> = (a: SortableType, b: SortableType) => number;

View File

@@ -2,6 +2,8 @@ import * as fs from 'node:fs';
import { contextBridge, ipcRenderer, type IpcRendererEvent } from 'electron';
import type { Compression } from '~/insomnia-data';
import {
asyncTasksAllSettled,
OriginalPromise,
@@ -10,7 +12,6 @@ import {
resetAsyncTasks,
stopMonitorAsyncTasks,
} from '../../insomnia-scripting-environment/src/objects';
import type { Compression } from './models/response';
// this will also import lots of node_modules into the preload script, consider moving this file insomnia-scripting-environment
import { requireInterceptor } from './require-interceptor';

View File

@@ -37,8 +37,8 @@ describe('onChange()', () => {
};
db.onChange(callback);
const newDoc = await models.request.create(doc);
const updatedDoc = await models.request.update(newDoc, {
const newDoc = await services.request.create(doc);
const updatedDoc = await services.request.update(newDoc, {
name: 'bar',
});
expect(changesSeen).toEqual([[['insert', newDoc, []]], [['update', updatedDoc, [{ name: 'bar' }]]]]);
@@ -60,9 +60,9 @@ describe('bufferChanges()', () => {
db.onChange(callback);
await db.bufferChanges();
const newDoc = await models.request.create(doc);
const newDoc = await services.request.create(doc);
// @ts-expect-error -- TSCONVERSION appears to be genuine
const updatedDoc = await models.request.update(newDoc);
const updatedDoc = await services.request.update(newDoc);
// Assert no change seen before flush
expect(changesSeen.length).toBe(0);
// Assert changes seen after flush
@@ -97,9 +97,9 @@ describe('bufferChanges()', () => {
db.onChange(callback);
await db.bufferChanges();
const newDoc = await models.request.create(doc);
const newDoc = await services.request.create(doc);
// @ts-expect-error -- TSCONVERSION appears to be genuine
const updatedDoc = await models.request.update(newDoc);
const updatedDoc = await services.request.update(newDoc);
// Default flush timeout is 1000ms after starting buffering
await new Promise(resolve => setTimeout(resolve, 1500));
expect(changesSeen).toEqual([
@@ -124,9 +124,9 @@ describe('bufferChanges()', () => {
db.onChange(callback);
await db.bufferChanges(500);
const newDoc = await models.request.create(doc);
const newDoc = await services.request.create(doc);
// @ts-expect-error -- TSCONVERSION appears to be genuine
const updatedDoc = await models.request.update(newDoc);
const updatedDoc = await services.request.update(newDoc);
await new Promise(resolve => setTimeout(resolve, 1000));
expect(changesSeen).toEqual([
[
@@ -152,9 +152,9 @@ describe('bufferChangesIndefinitely()', () => {
db.onChange(callback);
await db.bufferChangesIndefinitely();
const newDoc = await models.request.create(doc);
const newDoc = await services.request.create(doc);
// @ts-expect-error -- TSCONVERSION appears to be genuine
const updatedDoc = await models.request.update(newDoc);
const updatedDoc = await services.request.update(newDoc);
// Default flush timeout is 1000ms after starting buffering
await new Promise(resolve => setTimeout(resolve, 1500));
// Assert no change seen before flush
@@ -177,7 +177,7 @@ describe('requestCreate()', () => {
name: 'My Request',
parentId: 'wrk_123',
};
const r = await models.request.create(patch);
const r = await services.request.create(patch);
expect(Object.keys(r).length).toBe(24);
expect(r._id).toMatch(/^req_[a-zA-Z0-9]{32}$/);
expect(r.created).toBeGreaterThanOrEqual(now);
@@ -196,7 +196,7 @@ describe('requestCreate()', () => {
it('throws when missing parentID', () => {
const fn = () =>
models.request.create({
services.request.create({
name: 'My Request',
});
@@ -623,13 +623,13 @@ describe('duplicate()', () => {
it('should rewrite chained request references when duplicating a folder', async () => {
const workspace = await services.workspace.create({ name: 'Workspace' });
const folder = await models.requestGroup.create({ parentId: workspace._id, name: 'Folder' });
const req1 = await models.request.create({
const folder = await services.requestGroup.create({ parentId: workspace._id, name: 'Folder' });
const req1 = await services.request.create({
parentId: folder._id,
name: 'Request 1',
url: 'https://example.com/first',
});
const req2 = await models.request.create({
const req2 = await services.request.create({
parentId: folder._id,
name: 'Request 2',
url: `https://example.com/{% response 'body', '${req1._id}', 'b64::JC5pZA==::46b', 'never', 60 %}`,
@@ -678,16 +678,16 @@ describe('withAncestors()', () => {
const wrk = await services.workspace.create({
parentId: spc._id,
});
const wrkReq = await models.request.create({
const wrkReq = await services.request.create({
parentId: wrk._id,
});
const wrkGrpcReq = await services.grpcRequest.create({
parentId: wrk._id,
});
const grp = await models.requestGroup.create({
const grp = await services.requestGroup.create({
parentId: wrk._id,
});
const grpReq = await models.request.create({
const grpReq = await services.request.create({
parentId: grp._id,
});
const grpGrpcReq = await services.grpcRequest.create({
@@ -755,19 +755,19 @@ describe('getWithDescendants()', () => {
},
],
});
const folder1 = await models.requestGroup.create({
const folder1 = await services.requestGroup.create({
_id: 'grp1',
parentId: workspace._id,
});
const folder2 = await models.requestGroup.create({
const folder2 = await services.requestGroup.create({
_id: 'grp2',
parentId: folder1._id,
});
const request1 = await models.request.create({
const request1 = await services.request.create({
_id: 'req1',
parentId: workspace._id,
});
const request2 = await models.request.create({
const request2 = await services.request.create({
_id: 'req2',
parentId: folder1._id,
});

View File

@@ -18,6 +18,12 @@ import * as pluginDataService from './plugin-data';
import * as projectService from './project';
import * as protoDirectoryService from './proto-directory';
import * as protoFileService from './proto-file';
import * as requestService from './request';
import * as requestGroupService from './request-group';
import * as requestGroupMetaService from './request-group-meta';
import * as requestMetaService from './request-meta';
import * as requestVersionService from './request-version';
import * as responseService from './response';
import * as runnerTestResultService from './runner-test-result';
import * as settingsService from './settings';
import * as socketIOPayloadService from './socket-io-payload';
@@ -53,6 +59,12 @@ export const servicesNodeImpl = {
pluginData: pluginDataService,
protoDirectory: protoDirectoryService,
protoFile: protoFileService,
request: requestService,
requestGroup: requestGroupService,
requestGroupMeta: requestGroupMetaService,
requestMeta: requestMetaService,
requestVersion: requestVersionService,
response: responseService,
runnerTestResult: runnerTestResultService,
project: projectService,
settings: settingsService,

View File

@@ -3,7 +3,8 @@ import * as requestOperations from '~/models/helpers/request-operations';
import { database as db } from '../../src/database';
import { type McpResponse } from '../../src/models/types';
import * as SettingsService from './settings';
import * as requestVersionService from './request-version';
import * as settingsService from './settings';
const { type } = models.mcpResponse;
@@ -27,14 +28,14 @@ export async function create(patch: Partial<McpResponse> = {}, maxResponses = 20
const { parentId } = patch;
// Create request version snapshot
const request = await requestOperations.getById(parentId);
const requestVersion = request ? await models.requestVersion.create(request) : null;
const requestVersion = request ? await requestVersionService.create(request) : null;
patch.requestVersionId = requestVersion ? requestVersion._id : null;
// Filter responses by environment if setting is enabled
const query: Record<string, any> = {
parentId,
};
if ((await SettingsService.get()).filterResponsesByEnv && 'environmentId' in patch) {
if ((await settingsService.get()).filterResponsesByEnv && 'environmentId' in patch) {
query.environmentId = patch.environmentId;
}
@@ -72,7 +73,7 @@ export async function updateOrCreate(patch: Partial<McpResponse>, maxResponses =
export async function getLatestForRequestId(requestId: string, environmentId: string | null) {
// Filter responses by environment if setting is enabled
const shouldFilter = (await SettingsService.get()).filterResponsesByEnv;
const shouldFilter = (await settingsService.get()).filterResponsesByEnv;
const response = await db.findOne<McpResponse>(
type,

View File

@@ -0,0 +1,24 @@
import type { RequestGroupMeta } from '~/insomnia-data';
import { database as db, models } from '~/insomnia-data';
const { type } = models.requestGroupMeta;
export function create(patch: Partial<RequestGroupMeta> = {}) {
if (!patch.parentId) {
throw new Error('New RequestGroupMeta missing `parentId`: ' + JSON.stringify(patch));
}
return db.docCreate<RequestGroupMeta>(type, patch);
}
export function update(requestGroupMeta: RequestGroupMeta, patch: Partial<RequestGroupMeta>) {
return db.docUpdate<RequestGroupMeta>(requestGroupMeta, patch);
}
export function getByParentId(parentId: string) {
return db.findOne<RequestGroupMeta>(type, { parentId });
}
export function all() {
return db.find<RequestGroupMeta>(type);
}

View File

@@ -0,0 +1,58 @@
import type { RequestGroup } from '~/insomnia-data';
import { database as db, models } from '~/insomnia-data';
const { type } = models.requestGroup;
export function create(patch: Partial<RequestGroup> = {}) {
if (!patch.parentId) {
throw new Error('New RequestGroup missing `parentId`: ' + JSON.stringify(patch));
}
return db.docCreate<RequestGroup>(type, patch);
}
export function update(requestGroup: RequestGroup, patch: Partial<RequestGroup> = {}) {
return db.docUpdate<RequestGroup>(requestGroup, patch);
}
export function getById(id: string) {
return db.findOne<RequestGroup>(type, { _id: id });
}
export function findByParentId(parentId: string) {
return db.find<RequestGroup>(type, { parentId });
}
export function remove(requestGroup: RequestGroup) {
return db.remove(requestGroup);
}
export function all() {
return db.find<RequestGroup>(type);
}
export async function duplicate(requestGroup: RequestGroup, patch: Partial<RequestGroup> = {}) {
if (!patch.name) {
patch.name = `${requestGroup.name} (Copy)`;
}
const q = {
metaSortKey: {
$gt: requestGroup.metaSortKey,
},
};
const [nextRequestGroup] = await db.find<RequestGroup>(type, q, {
metaSortKey: 1,
});
const nextSortKey = nextRequestGroup ? nextRequestGroup.metaSortKey : requestGroup.metaSortKey + 100;
// Calculate new sort key
const sortKeyIncrement = (nextSortKey - requestGroup.metaSortKey) / 2;
const metaSortKey = requestGroup.metaSortKey + sortKeyIncrement;
return db.duplicate<RequestGroup>(requestGroup, {
metaSortKey,
...patch,
});
}

View File

@@ -0,0 +1,49 @@
import type { RequestMeta } from '~/insomnia-data';
import { database as db, models } from '~/insomnia-data';
const { type } = models.requestMeta;
export function create(patch: Partial<RequestMeta> = {}) {
if (!patch.parentId) {
throw new Error('New RequestMeta missing `parentId` ' + JSON.stringify(patch));
}
return db.docCreate<RequestMeta>(type, patch);
}
export function update(requestMeta: RequestMeta, patch: Partial<RequestMeta>) {
return db.docUpdate<RequestMeta>(requestMeta, patch);
}
export function getByParentId(parentId: string): Promise<RequestMeta | undefined> {
return db.findOne<RequestMeta>(type, { parentId });
}
export async function getOrCreateByParentId(parentId: string) {
const requestMeta = await getByParentId(parentId);
if (requestMeta) {
return requestMeta;
}
return create({ parentId });
}
export async function updateOrCreateByParentId(parentId: string, patch: Partial<RequestMeta>) {
const requestMeta = await getByParentId(parentId);
if (requestMeta) {
return update(requestMeta, patch);
}
const newPatch = Object.assign(
{
parentId,
},
patch,
);
return create(newPatch);
}
export function all() {
return db.find<RequestMeta>(type);
}

View File

@@ -1,34 +1,19 @@
import deepEqual from 'deep-equal';
import type { GrpcRequest, McpRequest, SocketIORequest, WebSocketRequest } from '~/insomnia-data';
import { models } from '~/insomnia-data';
import { compressObject, decompressObject } from '~/common/misc';
import type {
GrpcRequest,
McpRequest,
Request,
RequestVersion,
SocketIORequest,
WebSocketRequest,
} from '~/insomnia-data';
import { database, database as db, models } from '~/insomnia-data';
import * as requestOperations from '~/models/helpers/request-operations';
import { database, database as db } from '../common/database';
import { compressObject, decompressObject } from '../common/misc';
import * as requestOperations from '../models/helpers/request-operations';
import { isRequest, type Request } from './request';
import type { BaseModel } from './types';
/* When viewing a specific request, the user can click the Send button to test-send it.
Each time the user sends the request, the parameters may differthey might edit the body, headers, and so onand Insomnia records every sent request as history.
When the user browses the send history for a request and selects one of the entries, the current request is restored to the exact state it had when that request was sent, including the body, headers, and other settings.
A Request Version is essentially a snapshot of the request at the moment it was test-sent. */
export const name = 'Request Version';
export const type = 'RequestVersion';
export const prefix = 'rvr';
export const canDuplicate = false;
export const canSync = false;
interface BaseRequestVersion {
compressedRequest: string | null;
}
export type RequestVersion = BaseModel & BaseRequestVersion;
const { isRequest } = models.request;
const { type } = models.requestVersion;
const FIELDS_TO_IGNORE = [
'_id',
@@ -41,18 +26,6 @@ const FIELDS_TO_IGNORE = [
'name',
] as const;
export const isRequestVersion = (model: Pick<BaseModel, 'type'>): model is RequestVersion => model.type === type;
export function init() {
return {
compressedRequest: null,
};
}
export function migrate(doc: RequestVersion) {
return doc;
}
export function getById(id: string) {
return db.findOne<RequestVersion>(type, { _id: id });
}
@@ -73,7 +46,7 @@ export async function create(request: Request | WebSocketRequest | GrpcRequest |
const parentId = request._id;
const latestRequestVersion = await database.findOne<RequestVersion>(
'RequestVersion',
type,
{
parentId,
},

View File

@@ -0,0 +1,67 @@
import type { Request } from '~/insomnia-data';
import { database as db, models } from '~/insomnia-data';
const { type, name } = models.request;
export function create(patch: Partial<Request> = {}) {
if (!patch.parentId) {
throw new Error(`New Requests missing \`parentId\`: ${JSON.stringify(patch)}`);
}
return db.docCreate<Request>(type, patch);
}
export function getById(id: string): Promise<Request | undefined> {
return db.findOne<Request>(type, { _id: id });
}
export function getByParentId(parentId: string) {
return db.findOne<Request>(type, { parentId: parentId });
}
export function findByParentId(parentId: string) {
return db.find<Request>(type, { parentId: parentId });
}
export function update(request: Request, patch: Partial<Request>) {
return db.docUpdate<Request>(request, patch);
}
export async function duplicate(request: Request, patch: Partial<Request> = {}) {
// Only set name and "(Copy)" if the patch does
// not define it and the request itself has a name.
// Otherwise leave it blank so the request URL can
// fill it in automatically.
if (!patch.name && request.name) {
patch.name = `${request.name} (Copy)`;
}
// Get sort key of next request
const q = {
metaSortKey: {
$gt: request.metaSortKey,
},
};
const [nextRequest] = await db.find<Request>(type, q, {
metaSortKey: 1,
});
const nextSortKey = nextRequest ? nextRequest.metaSortKey : request.metaSortKey + 100;
// Calculate new sort key
const sortKeyIncrement = (nextSortKey - request.metaSortKey) / 2;
const metaSortKey = request.metaSortKey + sortKeyIncrement;
return db.duplicate<Request>(request, {
name,
metaSortKey,
...patch,
});
}
export function remove(request: Request) {
return db.remove(request);
}
export async function all() {
return db.find<Request>(type);
}

View File

@@ -0,0 +1,75 @@
import { database as db } from '~/common/database';
import type { Response } from '~/insomnia-data';
import { models } from '~/insomnia-data';
import * as requestOperations from '~/models/helpers/request-operations';
import * as requestVersionService from './request-version';
import * as settingsService from './settings';
const { type } = models.response;
export function getById(id: string) {
return db.findOne<Response>(type, { _id: id });
}
export function findByParentId(parentId: string) {
return db.find<Response>(type, { parentId: parentId });
}
export async function all() {
return db.find<Response>(type);
}
export async function getLatestForRequestId(
requestId: string,
environmentId: string | null,
): Promise<Response | undefined> {
// Filter responses by environment if setting is enabled
const shouldFilter = (await settingsService.get()).filterResponsesByEnv;
const response = await db.findOne<Response>(
type,
{
parentId: requestId,
...(shouldFilter ? { environmentId } : {}),
},
{ modified: -1 },
);
return response;
}
export async function create(patch: Partial<Response> = {}, maxResponses = 20): Promise<Response> {
if (!patch.parentId) {
console.log('[db] Attempted to create response without `parentId`', patch);
throw new Error('New Response missing `parentId`');
}
const { parentId } = patch;
// Create request version snapshot
const request = await requestOperations.getById(parentId);
const requestVersion = request ? await requestVersionService.create(request) : null;
patch.requestVersionId = requestVersion ? requestVersion._id : null;
// Filter responses by environment if setting is enabled
const settings = await settingsService.get();
const shouldQueryByEnvId = 'environmentId' in patch && settings.filterResponsesByEnv;
const query = {
parentId,
...(shouldQueryByEnvId ? { environmentId: patch.environmentId } : {}),
};
// Delete all other responses before creating the new one
const responsesToShow = Math.max(1, maxResponses);
const allResponses = await db.find<Response>(type, query, { modified: -1 }, responsesToShow);
const recentIds = allResponses.map(r => r._id);
// Remove all that were in the last query, except the first `maxResponses` IDs
await db.removeWhere(type, {
...query,
_id: {
$nin: recentIds,
},
});
// Actually create the new response
return db.docCreate(type, patch);
}

View File

@@ -3,6 +3,7 @@ import * as requestOperations from '~/models/helpers/request-operations';
import { database as db } from '../../src/database';
import { type SocketIOResponse } from '../../src/models/types';
import * as requestVersionService from './request-version';
import * as settingsService from './settings';
const { type } = models.socketIOResponse;
@@ -31,7 +32,7 @@ export async function create(patch: Partial<SocketIOResponse> = {}, maxResponses
const { parentId } = patch;
// Create request version snapshot
const request = await requestOperations.getById(parentId);
const requestVersion = request ? await models.requestVersion.create(request) : null;
const requestVersion = request ? await requestVersionService.create(request) : null;
patch.requestVersionId = requestVersion ? requestVersion._id : null;
// Filter responses by environment if setting is enabled
const query: Record<string, any> = {

View File

@@ -1,7 +1,6 @@
import type { Project, Stats, Workspace } from '~/insomnia-data';
import type { Project, RequestGroup, Stats, Workspace } from '~/insomnia-data';
import { database as db } from '~/insomnia-data';
import * as models from '~/models';
import type { RequestGroup } from '~/models/request-group';
const { type } = models.stats;
const { isRequest } = models.request;

View File

@@ -1,9 +1,9 @@
import { requestVersion as requestVersionModel } from '~/models';
import * as requestOperations from '~/models/helpers/request-operations';
import { database as db } from '../../src/database';
import { models } from '../../src/models';
import { type WebSocketResponse } from '../../src/models/types';
import * as requestVersionService from './request-version';
import * as settingsService from './settings';
const { type } = models.webSocketResponse;
@@ -28,8 +28,7 @@ export async function create(patch: Partial<WebSocketResponse> = {}, maxResponse
const { parentId } = patch;
// Create request version snapshot
const request = await requestOperations.getById(parentId);
// FIX ME, this should be changed to insomnia data model after request version is migrated
const requestVersion = request ? await requestVersionModel.create(request) : null;
const requestVersion = request ? await requestVersionService.create(request) : null;
patch.requestVersionId = requestVersion ? requestVersion._id : null;
// Filter responses by environment if setting is enabled
const query: Record<string, any> = {

View File

@@ -19,6 +19,12 @@ import * as pluginData from './plugin-data';
import * as project from './project';
import * as protoDirectory from './proto-directory';
import * as protoFile from './proto-file';
import * as request from './request';
import * as requestGroup from './request-group';
import * as requestGroupMeta from './request-group-meta';
import * as requestMeta from './request-meta';
import * as requestVersion from './request-version';
import * as response from './response';
import * as runnerTestResult from './runner-test-result';
import * as settings from './settings';
import * as socketIOPayload from './socket-io-payload';
@@ -51,6 +57,12 @@ export const models = {
pluginData,
protoDirectory,
protoFile,
request,
requestGroup,
requestGroupMeta,
requestMeta,
requestVersion,
response,
runnerTestResult,
project,
settings,

View File

@@ -1,6 +1,6 @@
import type { Root } from '@modelcontextprotocol/sdk/types.js';
import type { RequestAuthentication, RequestHeader } from '~/models/request';
import type { RequestAuthentication, RequestHeader } from '~/insomnia-data';
import type { BaseModel } from '~/models/types';
import type { EnvironmentKvPairData } from './environment';

View File

@@ -1,4 +1,4 @@
import type { ResponseHeader } from '~/models/response';
import type { ResponseHeader } from '~/insomnia-data';
import type { BaseModel } from '~/models/types';
import { type McpTransportType, TRANSPORT_TYPES } from './mcp-request';

View File

@@ -1,4 +1,4 @@
import type { RequestHeader } from '~/models/request';
import type { RequestHeader } from '~/insomnia-data';
import type { BaseModel } from '~/models/types';
export const name = 'Mock Route';

View File

@@ -0,0 +1,26 @@
import type { BaseModel } from '~/models/types';
export const name = 'Folder Meta';
export const type = 'RequestGroupMeta';
export const prefix = 'fldm';
export const canDuplicate = false;
export const canSync = false;
interface BaseRequestGroupMeta {
collapsed: boolean;
}
export type RequestGroupMeta = BaseModel & BaseRequestGroupMeta;
export const isRequestGroupMeta = (model: Pick<BaseModel, 'type'>): model is RequestGroupMeta => model.type === type;
export function init() {
return {
parentId: null,
collapsed: false,
};
}

View File

@@ -0,0 +1,60 @@
import { replaceIdsInFields } from '~/models/helpers/replace-ids-in-fields';
import type { BaseModel } from '~/models/types';
import type { EnvironmentKvPairData, EnvironmentType } from './environment';
import type { RequestAuthentication, RequestHeader } from './request';
export const name = 'Folder';
export const type = 'RequestGroup';
export const prefix = 'fld';
export const canDuplicate = true;
export const canSync = true;
// for those keys do not need to add in model init method
export const optionalKeys = ['kvPairData', 'environmentType'];
interface BaseRequestGroup {
name: string;
description: string;
environment: Record<string, any>;
environmentPropertyOrder: Record<string, any> | null;
kvPairData?: EnvironmentKvPairData[];
environmentType?: EnvironmentType;
metaSortKey: number;
preRequestScript?: string;
afterResponseScript?: string;
authentication?: RequestAuthentication | {};
headers?: RequestHeader[];
}
export type RequestGroup = BaseModel & BaseRequestGroup;
export const isRequestGroup = (model: Pick<BaseModel, 'type'>): model is RequestGroup => model.type === type;
export const isRequestGroupId = (id?: string | null) => id?.startsWith(prefix);
export function init(): BaseRequestGroup {
return {
name: 'New Folder',
description: '',
environment: {},
environmentPropertyOrder: null,
metaSortKey: -1 * Date.now(),
preRequestScript: undefined,
afterResponseScript: undefined,
authentication: undefined,
headers: undefined,
};
}
export function rewriteReferences(group: RequestGroup, idMapping: Map<string, string>): RequestGroup {
return {
...group,
...replaceIdsInFields(
group,
['authentication', 'headers', 'preRequestScript', 'afterResponseScript', 'environment', 'kvPairData'],
idMapping,
),
};
}

View File

@@ -0,0 +1,44 @@
import { PREVIEW_MODE_FRIENDLY, type PreviewMode } from '~/common/constants';
import type { BaseModel } from '~/models/types';
export const name = 'Request Meta';
export const type = 'RequestMeta';
export const prefix = 'reqm';
export const canDuplicate = false;
export const canSync = false;
export type RequestAccordionKeys = 'OAuth2AdvancedOptions';
export interface BaseRequestMeta {
parentId: string;
previewMode: PreviewMode;
responseFilter: string;
responseFilterHistory: string[];
activeResponseId: string | null;
savedRequestBody: Record<string, any>;
pinned: boolean;
lastActive: number;
downloadPath: string | null;
expandedAccordionKeys: Partial<Record<RequestAccordionKeys, boolean>>;
activeMcpPrimitive?: string | null;
}
export type RequestMeta = BaseModel & BaseRequestMeta;
export const isRequestMeta = (model: Pick<BaseModel, 'type'>): model is RequestMeta => model.type === type;
export function init() {
return {
parentId: null,
previewMode: PREVIEW_MODE_FRIENDLY,
responseFilter: '',
responseFilterHistory: [],
activeResponseId: null,
savedRequestBody: {},
pinned: false,
lastActive: 0,
downloadPath: null,
expandedAccordionKeys: {},
activeMcpPrimitive: null,
};
}

View File

@@ -0,0 +1,30 @@
import type { BaseModel } from '~/models/types';
/* When viewing a specific request, the user can click the Send button to test-send it.
Each time the user sends the request, the parameters may differ—they might edit the body, headers, and so on—and Insomnia records every sent request as history.
When the user browses the send history for a request and selects one of the entries, the current request is restored to the exact state it had when that request was sent, including the body, headers, and other settings.
A Request Version is essentially a snapshot of the request at the moment it was test-sent. */
export const name = 'Request Version';
export const type = 'RequestVersion';
export const prefix = 'rvr';
export const canDuplicate = false;
export const canSync = false;
interface BaseRequestVersion {
compressedRequest: string | null;
}
export type RequestVersion = BaseModel & BaseRequestVersion;
export const isRequestVersion = (model: Pick<BaseModel, 'type'>): model is RequestVersion => model.type === type;
export function init() {
return {
compressedRequest: null,
};
}

View File

@@ -15,13 +15,12 @@
import { OperationTypeNode } from 'graphql';
import { CONTENT_TYPE_FORM_URLENCODED, getContentTypeFromHeaders, METHOD_GET } from '../common/constants';
import { database as db } from '../common/database';
import type { OAuth1SignatureMethod } from '../network/o-auth-1/constants';
import { getOperationType } from '../utils/graph-ql';
import { deconstructQueryStringToParams } from '../utils/url/querystring';
import { replaceIdsInFields } from './helpers/replace-ids-in-fields';
import type { BaseModel } from './types';
import { CONTENT_TYPE_FORM_URLENCODED, getContentTypeFromHeaders, METHOD_GET } from '~/common/constants';
import { replaceIdsInFields } from '~/models/helpers/replace-ids-in-fields';
import type { BaseModel } from '~/models/types';
import type { OAuth1SignatureMethod } from '~/network/o-auth-1/constants';
import { getOperationType } from '~/utils/graph-ql';
import { deconstructQueryStringToParams } from '~/utils/url/querystring';
export const name = 'Request';
@@ -342,69 +341,6 @@ export function migrate(doc: Request): Request {
}
}
export function create(patch: Partial<Request> = {}) {
if (!patch.parentId) {
throw new Error(`New Requests missing \`parentId\`: ${JSON.stringify(patch)}`);
}
return db.docCreate<Request>(type, patch);
}
export function getById(id: string): Promise<Request | undefined> {
return db.findOne<Request>(type, { _id: id });
}
export function getByParentId(parentId: string) {
return db.findOne<Request>(type, { parentId: parentId });
}
export function findByParentId(parentId: string) {
return db.find<Request>(type, { parentId: parentId });
}
export function update(request: Request, patch: Partial<Request>) {
return db.docUpdate<Request>(request, patch);
}
export async function duplicate(request: Request, patch: Partial<Request> = {}) {
// Only set name and "(Copy)" if the patch does
// not define it and the request itself has a name.
// Otherwise leave it blank so the request URL can
// fill it in automatically.
if (!patch.name && request.name) {
patch.name = `${request.name} (Copy)`;
}
// Get sort key of next request
const q = {
metaSortKey: {
$gt: request.metaSortKey,
},
};
const [nextRequest] = await db.find<Request>(type, q, {
metaSortKey: 1,
});
const nextSortKey = nextRequest ? nextRequest.metaSortKey : request.metaSortKey + 100;
// Calculate new sort key
const sortKeyIncrement = (nextSortKey - request.metaSortKey) / 2;
const metaSortKey = request.metaSortKey + sortKeyIncrement;
return db.duplicate<Request>(request, {
name,
metaSortKey,
...patch,
});
}
export function remove(request: Request) {
return db.remove(request);
}
export async function all() {
return db.find<Request>(type);
}
// ~~~~~~~~~~ //
// Migrations //
// ~~~~~~~~~~ //

View File

@@ -0,0 +1,99 @@
import type { BaseModel } from '~/models/types';
import type { RequestTestResult } from '../../../../../insomnia-scripting-environment/src/objects';
export const name = 'Response';
export const type = 'Response';
export const prefix = 'res';
export const canDuplicate = false;
export const canSync = false;
export interface ResponseHeader {
name: string;
value: string;
}
export type Compression = 'zip' | null | '__NEEDS_MIGRATION__' | undefined;
export interface BaseResponse {
environmentId: string | null;
globalEnvironmentId: string | null;
statusCode: number;
statusMessage: string;
httpVersion: string;
contentType: string;
url: string;
bytesRead: number;
bytesContent: number;
elapsedTime: number;
headers: ResponseHeader[];
bodyPath: string;
// if body is less than 5MB, it's stored in memory
bodyBuffer?: Buffer;
// Actual bodies are stored on the filesystem
timelinePath: string;
// Actual timelines are stored on the filesystem
bodyCompression: Compression;
error: string;
requestVersionId: string | null;
// Things from the request
settingStoreCookies: boolean | null;
settingSendCookies: boolean | null;
requestTestResults: RequestTestResult[];
}
export type Response = BaseModel & BaseResponse;
export const isResponse = (model: Pick<BaseModel, 'type'>): model is Response => model.type === type;
export function init(): BaseResponse {
return {
statusCode: 0,
statusMessage: '',
httpVersion: '',
contentType: '',
url: '',
bytesRead: 0,
// -1 means that it was legacy and this property didn't exist yet
bytesContent: -1,
elapsedTime: 0,
headers: [],
// Actual timelines are stored on the filesystem
timelinePath: '',
// Actual bodies are stored on the filesystem
bodyPath: '',
// For legacy bodies
bodyCompression: '__NEEDS_MIGRATION__',
error: '',
// Things from the request
requestVersionId: null,
settingStoreCookies: null,
settingSendCookies: null,
// Responses sent before environment filtering will have a special value
// so they don't show up at all when filtering is on.
environmentId: '__LEGACY__',
requestTestResults: [],
globalEnvironmentId: null,
};
}
export function migrate(doc: Response) {
try {
return migrateBodyCompression(doc);
} catch (e) {
console.log('[db] Error during response migration', e);
throw e;
}
}
function migrateBodyCompression(doc: Response) {
if (doc.bodyCompression === '__NEEDS_MIGRATION__') {
doc.bodyCompression = 'zip';
}
return doc;
}

View File

@@ -1,7 +1,8 @@
import { replaceIdsInFields } from '~/models/helpers/replace-ids-in-fields';
import type { RequestAuthentication, RequestHeader, RequestParameter, RequestPathParameter } from '~/models/request';
import type { BaseModel } from '~/models/types';
import type { RequestAuthentication, RequestHeader, RequestParameter, RequestPathParameter } from './request';
export const name = 'Socket.IO Request';
export const type = 'SocketIORequest';

View File

@@ -38,6 +38,34 @@ export type { Environment, EnvironmentKvPairData, UserUploadEnvironment } from '
// Keep these enums in the shared entrypoint: unlike type-only exports, enums also exist at runtime,
// so they must be re-exported as values here to preserve a single import path for both type and value usage.
export { EnvironmentType, EnvironmentKvPairDataType } from './environment';
export type {
AuthTypeAPIKey,
AuthTypeAsap,
AuthTypeAwsIam,
AuthTypeBasic,
AuthTypeBearer,
AuthTypeDigest,
AuthTypeHawk,
AuthTypeNetrc,
AuthTypeNone,
AuthTypeNTLM,
AuthTypeOAuth1,
AuthTypeOAuth2,
AuthTypeSingleToken,
OAuth2ResponseType,
Request,
RequestAuthentication,
RequestBody,
RequestBodyParameter,
RequestHeader,
RequestParameter,
RequestPathParameter,
} from './request';
export type { RequestGroup } from './request-group';
export type { RequestGroupMeta } from './request-group-meta';
export type { RequestAccordionKeys, RequestMeta } from './request-meta';
export type { RequestVersion } from './request-version';
export type { Compression, Response, ResponseHeader } from './response';
export type { McpRequest, McpTransportType, McpServerPrimitiveTypes } from './mcp-request';
export type { McpPayload } from './mcp-payload';
export type { McpResponse } from './mcp-response';

View File

@@ -1,7 +1,8 @@
import { replaceIdsInFields } from '~/models/helpers/replace-ids-in-fields';
import type { RequestAuthentication, RequestHeader, RequestParameter, RequestPathParameter } from '~/models/request';
import type { BaseModel } from '~/models/types';
import type { RequestAuthentication, RequestHeader, RequestParameter, RequestPathParameter } from './request';
export const name = 'WebSocket Request';
export const type = 'WebSocketRequest';

View File

@@ -1,6 +1,7 @@
import type { ResponseHeader } from '~/models/response';
import type { BaseModel } from '~/models/types';
import type { ResponseHeader } from './response';
export const name = 'WebSocket Response';
export const type = 'WebSocketResponse';

View File

@@ -1,6 +1,6 @@
import type * as Har from 'har-format';
import type { RequestAuthentication } from '~/models/request';
import type { RequestAuthentication } from '~/insomnia-data';
export interface Comment {
comment?: string;

View File

@@ -2,7 +2,7 @@ import { URL } from 'node:url';
import { type ControlOperator, parse, type ParseEntry } from 'shell-quote';
import type { RequestAuthentication } from '~/models/request';
import type { RequestAuthentication } from '~/insomnia-data';
import { type Converter, type ImportRequest, type Parameter } from '../entities';

View File

@@ -1,8 +1,8 @@
import { CONTENT_TYPE_JSON, CONTENT_TYPE_PLAINTEXT, CONTENT_TYPE_XML } from 'insomnia/src/common/constants';
import type { AuthTypeOAuth2 } from 'insomnia/src/models/request';
import { fakerFunctions } from 'insomnia/src/templating/faker-functions';
import { forceBracketNotation } from 'insomnia/src/templating/utils';
import type { AuthTypeOAuth2 } from '~/insomnia-data';
import { translateHandlersInScript } from '~/main/importers/importers/translate-postman-script';
import type { Converter, ImportRequest, Parameter, PathParameters } from '../entities';

View File

@@ -8,10 +8,10 @@ import {
import { BrowserWindow, ipcMain } from 'electron';
import { getOauthRedirectUrl } from '~/common/constants';
import type { RequestAuthentication } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { authorizeUserInDefaultBrowser } from '~/main/authorize-user-in-default-browser';
import type { ConnectionContext } from '~/main/mcp/common';
import type { RequestAuthentication } from '~/models/request';
import { encryptOAuthUrl } from '~/network/o-auth-2/utils';
import { invariant } from '~/utils/invariant';

View File

@@ -102,7 +102,7 @@ export const createStdioTransport = async (
};
const settings = await services.settings.get();
const res = await services.mcpResponse.updateOrCreate(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: res._id });
services.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: res._id });
}
return originalSend(message);

View File

@@ -9,12 +9,12 @@ import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
import { BrowserWindow } from 'electron';
import type { Dispatcher } from 'undici';
import type { RequestHeader } from '~/insomnia-data';
import { type McpResponse, services } from '~/insomnia-data';
import { type ConnectionContext, getFetchDispatcher, writeEventLogAndNotify, writeTimeline } from '~/main/mcp/common';
import { MCPAuthError, type McpOAuthClientProvider } from '~/main/mcp/oauth-client-provider';
import type { McpAuthEventWithoutBase, OpenMcpHTTPClientConnectionOptions } from '~/main/mcp/types';
import * as models from '~/models';
import type { RequestHeader } from '~/models/request';
// Extend undici RequestInit to include dispatcher, it's in node.js fetch but not in dom fetch.
interface NodeRequestInit extends RequestInit {
@@ -137,7 +137,7 @@ const wrappedFetch = async (
};
const settings = await services.settings.get();
const res = await services.mcpResponse.updateOrCreate(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: res._id });
services.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: res._id });
}
// Avoid infinite loop, only call auth flow once per request

View File

@@ -4,8 +4,8 @@ import type { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/cl
import type { ClientRequest, JSONRPCResponse, Notification } from '@modelcontextprotocol/sdk/types.js';
import type z from 'zod';
import type { RequestAuthentication, RequestHeader } from '~/insomnia-data';
import type * as models from '~/models';
import type { RequestAuthentication, RequestHeader } from '~/models/request';
// Refer the SDK: https://github.com/modelcontextprotocol/typescript-sdk/blob/main/src/shared/protocol.ts#L504
// The Client type has missing transport property

View File

@@ -7,15 +7,12 @@ import electron, { BrowserWindow } from 'electron';
import { v4 as uuidV4 } from 'uuid';
import { REALTIME_EVENTS_CHANNELS } from '~/common/constants';
import type { CookieJar } from '~/insomnia-data';
import type { CookieJar, RequestAuthentication, RequestHeader, Response } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { insecureReadFile } from '~/main/secure-read-file';
import { readCurlResponse } from '~/models/helpers/response-operations';
import { describeByteSize, generateId, getSetCookieHeaders } from '../../common/misc';
import * as models from '../../models';
import type { RequestAuthentication, RequestHeader } from '../../models/request';
import type { Response } from '../../models/response';
import { filterClientCertificates } from '../../network/certificate';
import { addSetCookiesToToughCookieJar } from '../../network/set-cookie-util';
import { invariant } from '../../utils/invariant';
@@ -129,7 +126,7 @@ const openCurlConnection = async (
console.warn('Connection still open to ' + existingConnection.getInfo(Curl.info.EFFECTIVE_URL));
return;
}
const request = await models.request.getById(options.requestId);
const request = await services.request.getById(options.requestId);
const responseId = generateId('res');
if (!request) {
console.warn('Could not find request for ' + options.requestId);
@@ -196,7 +193,7 @@ const openCurlConnection = async (
window.webContents.send(readyStateChannel, false);
}
if (errorCode) {
const res = await models.response.getById(responseId);
const res = await services.response.getById(responseId);
if (!res) {
createErrorResponse(
responseId,
@@ -265,8 +262,8 @@ const openCurlConnection = async (
bodyCompression: null,
};
const settings = await services.settings.get();
const res = await models.response.create(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(request._id, { activeResponseId: res._id });
const res = await services.response.create(responsePatch, settings.maxHistoryResponses);
services.requestMeta.updateOrCreateByParentId(request._id, { activeResponseId: res._id });
if (request.settingStoreCookies) {
const setCookieStrings: string[] = getSetCookieHeaders(responseHeaders).map(h => h.value);
@@ -352,8 +349,8 @@ const createErrorResponse = async (
statusMessage: 'Error',
error: message,
};
const res = await models.response.create(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: res._id });
const res = await services.response.create(responsePatch, settings.maxHistoryResponses);
services.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: res._id });
};
const deleteRequestMaps = async (requestId: string, message: string, event?: CurlCloseEvent | CurlErrorEvent) => {
@@ -404,7 +401,7 @@ const closeCurlConnection = (_event: Electron.IpcMainInvokeEvent, options: { req
const closeAllCurlConnections = (): void => CurlConnections.forEach(curl => curl.isOpen && curl.close());
const findMany = async (options: { responseId: string }): Promise<CurlEvent[]> => {
const response = await models.response.getById(options.responseId);
const response = await services.response.getById(options.responseId);
if (!response || !response.bodyPath) {
return [];
}

View File

@@ -21,13 +21,11 @@ import { isValid } from 'date-fns';
import electron from 'electron';
import { v4 as uuidv4 } from 'uuid';
import type { ClientCertificate } from '~/insomnia-data';
import type { ClientCertificate, RequestHeader, ResponseHeader } from '~/insomnia-data';
import { version } from '../../../package.json';
import { type AuthTypes, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED } from '../../common/constants';
import { cannotAccessPathError, describeByteSize, hasAuthHeader } from '../../common/misc';
import type { RequestHeader } from '../../models/request';
import type { ResponseHeader } from '../../models/response';
import { insecureReadFile, isPathAllowed } from '../secure-read-file';
import { buildMultipart } from './multipart';
import { parseHeaderStrings } from './parse-header-strings';

View File

@@ -204,7 +204,7 @@ const createErrorResponse = async (
};
const res = await services.mcpResponse.updateOrCreate(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: res._id });
services.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: res._id });
};
export const isOpenMcpHTTPClientConnectionOptions = (

View File

@@ -8,7 +8,7 @@ import path from 'node:path';
import { lookup } from 'mime-types';
import type { RequestBodyParameter } from '../../models/request';
import type { RequestBodyParameter } from '~/insomnia-data';
export const DEFAULT_BOUNDARY = 'X-INSOMNIA-BOUNDARY';

View File

@@ -3,7 +3,7 @@ import { parse as urlParse } from 'node:url';
import aws4 from 'aws4';
import clone from 'clone';
import type { RequestAuthentication } from '~/models/request';
import type { RequestAuthentication } from '~/insomnia-data';
import { CONTENT_TYPE_FORM_DATA } from '../../common/constants';
import {

View File

@@ -9,13 +9,17 @@ import { io as SocketIOClient, type ManagerOptions, type Socket, type SocketOpti
import { v4 as uuidV4 } from 'uuid';
import { REALTIME_EVENTS_CHANNELS } from '~/common/constants';
import type { BaseSocketIORequest, CookieJar, SocketIOResponse } from '~/insomnia-data';
import type {
BaseSocketIORequest,
CookieJar,
RequestAuthentication,
RequestHeader,
SocketIOResponse,
} from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { jarFromCookies } from '../../common/cookies';
import { generateId } from '../../common/misc';
import * as models from '../../models';
import { type RequestAuthentication, type RequestHeader } from '../../models/request';
import { filterClientCertificates } from '../../network/certificate';
import { invariant } from '../../utils/invariant';
import { setDefaultProtocol } from '../../utils/url/protocol';
@@ -224,7 +228,7 @@ const createErrorResponse = async (
error: message,
};
const res = await services.socketIOResponse.create(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: res._id });
services.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: res._id });
};
const openSocketIOConnection = async (
@@ -359,7 +363,7 @@ const openSocketIOConnection = async (
};
const res = await services.socketIOResponse.create(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(request._id, { activeResponseId: res._id });
services.requestMeta.updateOrCreateByParentId(request._id, { activeResponseId: res._id });
});
const engine = socket.io.engine;

View File

@@ -12,14 +12,19 @@ import { type CloseEvent, type ErrorEvent, type Event, type MessageEvent, WebSoc
import { REALTIME_EVENTS_CHANNELS } from '~/common/constants';
import { database } from '~/common/database';
import type { BaseWebSocketRequest, CookieJar, WebSocketResponse } from '~/insomnia-data';
import type {
BaseWebSocketRequest,
CookieJar,
Request,
RequestAuthentication,
RequestHeader,
WebSocketResponse,
} from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { jarFromCookies } from '../../common/cookies';
import { generateId, getSetCookieHeaders } from '../../common/misc';
import * as models from '../../models';
import type { Request } from '../../models/request';
import { type RequestAuthentication, type RequestHeader } from '../../models/request';
import { COOKIE, HEADER, QUERY_PARAMS } from '../../network/api-key/constants';
import { getBasicAuthHeader } from '../../network/basic-auth/get-header';
import { getBearerAuthHeader } from '../../network/bearer-auth/get-header';
@@ -146,7 +151,7 @@ const openWebSocketConnection = async (
}
const request = options.isGraphqlSubscriptionRequest
? await models.request.getById(options.requestId)
? await services.request.getById(options.requestId)
: await services.webSocketRequest.getById(options.requestId);
const responseId = generateId('res');
if (!request) {
@@ -320,7 +325,7 @@ const openWebSocketConnection = async (
const settings = await services.settings.get();
const res = await services.webSocketResponse.create(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(request._id, { activeResponseId: res._id });
services.requestMeta.updateOrCreateByParentId(request._id, { activeResponseId: res._id });
if (request.settingStoreCookies) {
const setCookieStrings: string[] = getSetCookieHeaders(responseHeaders).map(h => h.value);
@@ -376,7 +381,7 @@ const openWebSocketConnection = async (
};
const settings = await services.settings.get();
const res = await services.webSocketResponse.create(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(request._id, { activeResponseId: res._id });
services.requestMeta.updateOrCreateByParentId(request._id, { activeResponseId: res._id });
deleteRequestMaps(request._id, `Unexpected response ${incomingMessage.statusCode}`);
});
@@ -520,7 +525,7 @@ const createErrorResponse = async (
error: message,
};
const res = await services.webSocketResponse.create(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: res._id });
services.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: res._id });
};
const deleteRequestMaps = async (

View File

@@ -7,17 +7,14 @@ import iconv from 'iconv-lite';
import { v4 as uuidv4 } from 'uuid';
import { jarFromCookies } from '~/common/cookies';
import type { CloudProviderCredential, Workspace } from '~/insomnia-data';
import type { CloudProviderCredential, Request as DBRequest, RequestGroup, Response, Workspace } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { getBodyBuffer, readCurlResponse } from '~/models/helpers/response-operations';
import { getAppBundlePlugins, RESPONSE_CODE_REASONS } from '../common/constants';
import { isDevelopment } from '../common/constants';
import { database as db } from '../common/database';
import * as models from '../models';
import type { Request as DBRequest } from '../models/request';
import type { RequestGroup } from '../models/request-group';
import type { Response } from '../models/response';
import type * as models from '../models';
import { fetchRequestData, sendCurlAndWriteTimeline, tryToInterpolateRequest } from '../network/network';
import { getPluginCommonContext, type Plugin, type TemplateTag } from '../plugins';
import type { PluginTemplateTag, PluginTemplateTagContext, PluginToMainAPIPaths } from '../templating/types';
@@ -90,7 +87,7 @@ const pluginToMainAPI: Record<PluginToMainAPIPaths, (...args: any[]) => Promise<
return crypto.createHash('md5').update(body.input).digest(body.encoding);
},
'request.getById': async (body: { id: string }) => {
return await models.request.getById(body.id);
return await services.request.getById(body.id);
},
'request.getAncestors': async (body: { request: DBRequest | RequestGroup | Workspace; types: models.AllTypes[] }) => {
return await db.withAncestors<DBRequest | RequestGroup | Workspace>(body.request, body.types);
@@ -110,7 +107,7 @@ const pluginToMainAPI: Record<PluginToMainAPIPaths, (...args: any[]) => Promise<
return jar.getCookiesSync(body.url);
},
'response.getLatestForRequestId': async (body: { requestId: string; environmentId: string }) => {
return await models.response.getLatestForRequestId(body.requestId, body.environmentId);
return await services.response.getLatestForRequestId(body.requestId, body.environmentId);
},
'response.getBodyBuffer': async (body: { response: Response; readFailureValue: string }) => {
return await getBodyBuffer(body.response, body.readFailureValue);
@@ -176,7 +173,7 @@ const pluginToMainAPI: Record<PluginToMainAPIPaths, (...args: any[]) => Promise<
timelinePath,
responseId,
);
return await models.response.create({ ...response, bodyCompression: null }, settings.maxHistoryResponses);
return await services.response.create({ ...response, bodyCompression: null }, settings.maxHistoryResponses);
},
// use libcurl to send request without side effects(do not write to database about request and response)
'network.sendRequestWithoutSideEffects': async (body: {

View File

@@ -1,12 +1,10 @@
import type { Schema } from '@develohpanda/fluent-builder';
import clone from 'clone';
import type { Environment, GrpcRequest, Workspace } from '~/insomnia-data';
import type { Environment, GrpcRequest, Request, RequestGroup, Workspace } from '~/insomnia-data';
import { EnvironmentKvPairDataType, EnvironmentType } from '~/insomnia-data';
import { type AllTypes, type BaseModel, environment, grpcRequest, request, requestGroup, workspace } from '..';
import type { Request } from '../request';
import type { RequestGroup } from '../request-group';
// move into fluent-builder
const toSchema = <T>(obj: T): Schema<T> => {

View File

@@ -1,16 +1,18 @@
import { describe, expect, it } from 'vitest';
import { services } from '~/insomnia-data';
import * as models from '../index';
describe('create()', () => {
it('fails when missing parentId', async () => {
expect(() =>
models.requestMeta.create({
services.requestMeta.create({
pinned: true,
}),
).toThrow('New RequestMeta missing `parentId`');
}); // it('fails when parentId prefix is not that of a Request', async () => {
// expect(() => models.requestMeta.create({ parentId: 'greq_123' })).toThrow(
// expect(() => services.requestMeta.create({ parentId: 'greq_123' })).toThrow(
// 'Expected the parent of RequestMeta to be a Request',
// );
// });

View File

@@ -55,7 +55,7 @@ describe('Request Model - Comprehensive Tests', () => {
scope: 'collection',
});
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_basic',
name: 'Basic Request',
parentId: workspace._id,
@@ -88,7 +88,7 @@ describe('Request Model - Comprehensive Tests', () => {
{ name: 'X-Custom-Header', value: 'custom-value' },
];
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_headers',
name: 'Request with Headers',
parentId: workspace._id,
@@ -115,7 +115,7 @@ describe('Request Model - Comprehensive Tests', () => {
{ name: 'sort', value: 'created_at' },
];
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_params',
name: 'Request with Parameters',
parentId: workspace._id,
@@ -150,7 +150,7 @@ describe('Request Model - Comprehensive Tests', () => {
useISO88591: false,
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_basic_auth',
name: 'Basic Auth Request',
parentId: workspace._id,
@@ -171,7 +171,7 @@ describe('Request Model - Comprehensive Tests', () => {
useISO88591: true,
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_basic_auth_iso',
name: 'Basic Auth ISO Request',
parentId: workspace._id,
@@ -194,7 +194,7 @@ describe('Request Model - Comprehensive Tests', () => {
addTo: 'header',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_apikey_header',
name: 'API Key Header Request',
parentId: workspace._id,
@@ -215,7 +215,7 @@ describe('Request Model - Comprehensive Tests', () => {
addTo: 'query',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_apikey_query',
name: 'API Key Query Request',
parentId: workspace._id,
@@ -245,7 +245,7 @@ describe('Request Model - Comprehensive Tests', () => {
resource: 'https://api.example.com',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_oauth2_auth_code',
name: 'OAuth2 Auth Code Request',
parentId: workspace._id,
@@ -268,7 +268,7 @@ describe('Request Model - Comprehensive Tests', () => {
scope: 'read write',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_oauth2_client_creds',
name: 'OAuth2 Client Creds Request',
parentId: workspace._id,
@@ -293,7 +293,7 @@ describe('Request Model - Comprehensive Tests', () => {
scope: 'read write',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_oauth2_password',
name: 'OAuth2 Password Request',
parentId: workspace._id,
@@ -315,7 +315,7 @@ describe('Request Model - Comprehensive Tests', () => {
password: 'testpass',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_digest_auth',
name: 'Digest Auth Request',
parentId: workspace._id,
@@ -337,7 +337,7 @@ describe('Request Model - Comprehensive Tests', () => {
password: 'testpass',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_ntlm_auth',
name: 'NTLM Auth Request',
parentId: workspace._id,
@@ -362,7 +362,7 @@ describe('Request Model - Comprehensive Tests', () => {
service: 'execute-api',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_aws_iam_auth',
name: 'AWS IAM Auth Request',
parentId: workspace._id,
@@ -387,7 +387,7 @@ describe('Request Model - Comprehensive Tests', () => {
validatePayload: true,
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_hawk_auth',
name: 'Hawk Auth Request',
parentId: workspace._id,
@@ -409,7 +409,7 @@ describe('Request Model - Comprehensive Tests', () => {
prefix: 'Bearer',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_bearer_auth',
name: 'Bearer Auth Request',
parentId: workspace._id,
@@ -440,7 +440,7 @@ describe('Request Model - Comprehensive Tests', () => {
verifier: 'test-verifier',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_oauth1_auth',
name: 'OAuth 1.0 Auth Request',
parentId: workspace._id,
@@ -466,7 +466,7 @@ describe('Request Model - Comprehensive Tests', () => {
additionalClaims: '{"customClaim": "custom-value"}',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_asap_auth',
name: 'ASAP Auth Request',
parentId: workspace._id,
@@ -487,7 +487,7 @@ describe('Request Model - Comprehensive Tests', () => {
token: 'test-single-token',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_single_token_auth',
name: 'Single Token Auth Request',
parentId: workspace._id,
@@ -507,7 +507,7 @@ describe('Request Model - Comprehensive Tests', () => {
type: 'netrc',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_netrc_auth',
name: 'Netrc Auth Request',
parentId: workspace._id,
@@ -541,7 +541,7 @@ describe('Request Model - Comprehensive Tests', () => {
text: '{"name": "test", "value": 123}',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_json_body',
name: 'JSON Body Request',
parentId: workspace._id,
@@ -565,7 +565,7 @@ describe('Request Model - Comprehensive Tests', () => {
],
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_form_data_body',
name: 'Form Data Body Request',
parentId: workspace._id,
@@ -589,7 +589,7 @@ describe('Request Model - Comprehensive Tests', () => {
],
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_multipart_body',
name: 'Multipart Body Request',
parentId: workspace._id,
@@ -610,7 +610,7 @@ describe('Request Model - Comprehensive Tests', () => {
text: 'This is raw text content',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_raw_text_body',
name: 'Raw Text Body Request',
parentId: workspace._id,
@@ -631,7 +631,7 @@ describe('Request Model - Comprehensive Tests', () => {
text: '<?xml version="1.0"?><root><item>value</item></root>',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_xml_body',
name: 'XML Body Request',
parentId: workspace._id,
@@ -652,7 +652,7 @@ describe('Request Model - Comprehensive Tests', () => {
fileName: 'test.bin',
};
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_binary_body',
name: 'Binary Body Request',
parentId: workspace._id,
@@ -680,7 +680,7 @@ describe('Request Model - Comprehensive Tests', () => {
});
it('should detect GraphQL query operation', async () => {
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_graphql_query',
name: 'GraphQL Query',
parentId: workspace._id,
@@ -699,7 +699,7 @@ describe('Request Model - Comprehensive Tests', () => {
});
it('should detect GraphQL mutation operation', async () => {
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_graphql_mutation',
name: 'GraphQL Mutation',
parentId: workspace._id,
@@ -716,7 +716,7 @@ describe('Request Model - Comprehensive Tests', () => {
});
it('should detect GraphQL subscription operation', async () => {
const request = await models.request.create({
const request = await services.request.create({
_id: 'req_graphql_subscription',
name: 'GraphQL Subscription',
parentId: workspace._id,
@@ -745,7 +745,7 @@ describe('Request Model - Comprehensive Tests', () => {
scope: 'collection',
});
request = await models.request.create({
request = await services.request.create({
_id: `req_update_${uuidv4()}`,
name: 'Update Request',
parentId: workspace._id,
@@ -756,7 +756,7 @@ describe('Request Model - Comprehensive Tests', () => {
});
it('should update request name', async () => {
const updatedRequest = await models.request.update(request, {
const updatedRequest = await services.request.update(request, {
name: 'Updated Request Name',
});
@@ -764,7 +764,7 @@ describe('Request Model - Comprehensive Tests', () => {
});
it('should update request URL', async () => {
const updatedRequest = await models.request.update(request, {
const updatedRequest = await services.request.update(request, {
url: 'https://api.example.com/updated',
});
@@ -772,7 +772,7 @@ describe('Request Model - Comprehensive Tests', () => {
});
it('should update request method', async () => {
const updatedRequest = await models.request.update(request, {
const updatedRequest = await services.request.update(request, {
method: 'POST',
});
@@ -785,7 +785,7 @@ describe('Request Model - Comprehensive Tests', () => {
{ name: 'Authorization', value: 'Bearer new-token' },
];
const updatedRequest = await models.request.update(request, {
const updatedRequest = await services.request.update(request, {
headers: newHeaders,
});
@@ -799,7 +799,7 @@ describe('Request Model - Comprehensive Tests', () => {
password: 'newpass',
};
const updatedRequest = await models.request.update(request, {
const updatedRequest = await services.request.update(request, {
authentication: newAuth,
});
@@ -819,7 +819,7 @@ describe('Request Model - Comprehensive Tests', () => {
scope: 'collection',
});
request = await models.request.create({
request = await services.request.create({
_id: `req_delete_${uuidv4()}`,
name: 'Delete Request',
parentId: workspace._id,
@@ -830,9 +830,9 @@ describe('Request Model - Comprehensive Tests', () => {
});
it('should delete request', async () => {
await models.request.remove(request);
await services.request.remove(request);
const deletedRequest = await models.request.getById(request._id);
const deletedRequest = await services.request.getById(request._id);
expect(deletedRequest).toBeUndefined();
});
});

View File

@@ -2,11 +2,11 @@ import { describe, expect, it } from 'vitest';
import { generateId } from '../../../common/misc';
import * as models from '../../index';
import { isRequest } from '../../request';
import { isRequestGroup } from '../../request-group';
const { isProtoDirectory } = models.protoDirectory;
const { isProtoFile } = models.protoFile;
const { isRequest } = models.request;
const { isRequestGroup } = models.requestGroup;
const allTypes = models.types();
const allPrefixes = models.all().map(model => model.prefix);

View File

@@ -18,7 +18,7 @@ describe('queryAllWorkspaceUrls', () => {
const w = await services.workspace.create({
name: 'Workspace',
});
const r1 = await models.request.create({
const r1 = await services.request.create({
name: 'Request 1',
parentId: w._id,
url: 'r1.url',
@@ -33,11 +33,11 @@ describe('queryAllWorkspaceUrls', () => {
parentId: w._id,
url: 'gr2.url',
});
const f2 = await models.requestGroup.create({
const f2 = await services.requestGroup.create({
name: 'Folder 2',
parentId: w._id,
});
const r2 = await models.request.create({
const r2 = await services.request.create({
name: 'Request 2',
parentId: f2._id,
url: 'r2.url',
@@ -48,12 +48,12 @@ describe('queryAllWorkspaceUrls', () => {
parentId: w._id,
url: gr2.url,
});
await models.request.create({
await services.request.create({
name: 'Duplicate url',
parentId: f2._id,
url: r2.url,
});
await models.request.create({
await services.request.create({
name: 'Undefined url',
parentId: f2._id,
url: undefined,
@@ -66,7 +66,7 @@ describe('queryAllWorkspaceUrls', () => {
const w2 = await services.workspace.create({
name: 'Workspace 2',
});
await models.request.create({
await services.request.create({
name: 'Different workspace',
parentId: w2._id,
url: 'diff.url',

View File

@@ -1,15 +1,12 @@
import type { GrpcRequest } from '~/insomnia-data';
import { models, services } from '~/insomnia-data';
import type { GrpcRequest, models, Request } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { database as db } from '../../common/database';
import { invariant } from '../../utils/invariant';
import type { Request, type as RequestType } from '../request';
const grpcRequestType = models.grpcRequest.type;
export const queryAllWorkspaceUrls = async (
workspaceId: string,
reqType: typeof RequestType | typeof grpcRequestType,
reqType: typeof models.request.type | typeof models.grpcRequest.type,
reqId = 'n/a',
): Promise<string[]> => {
const workspace = await services.workspace.getById(workspaceId);

View File

@@ -1,14 +1,13 @@
import type { GrpcRequest, McpRequest, SocketIORequest, WebSocketRequest } from '~/insomnia-data';
import type { GrpcRequest, McpRequest, Request, SocketIORequest, WebSocketRequest } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import * as models from '../index';
import type { Request } from '../request';
export function findByParentId(
parentId: string,
): Promise<(Request | GrpcRequest | WebSocketRequest | SocketIORequest | McpRequest)[]> {
return Promise.all([
models.request.findByParentId(parentId),
services.request.findByParentId(parentId),
services.grpcRequest.findByParentId(parentId),
services.webSocketRequest.findByParentId(parentId),
services.socketIORequest.findByParentId(parentId),
@@ -37,7 +36,7 @@ export function getById(
if (models.mcpRequest.isMcpRequestId(requestId)) {
return services.mcpRequest.getById(requestId);
}
return models.request.getById(requestId);
return services.request.getById(requestId);
}
export function remove(request: Request | GrpcRequest | WebSocketRequest | SocketIORequest | McpRequest) {
@@ -56,7 +55,7 @@ export function remove(request: Request | GrpcRequest | WebSocketRequest | Socke
return services.mcpRequest.remove(request);
}
return models.request.remove(request);
return services.request.remove(request);
}
export function update<T extends object>(request: T, patch: Partial<T> = {}): Promise<T> {
@@ -83,7 +82,7 @@ export function update<T extends object>(request: T, patch: Partial<T> = {}): Pr
}
// @ts-expect-error -- TSCONVERSION
return models.request.update(request, patch);
return services.request.update(request, patch);
}
export function duplicate<T extends object>(request: T, patch: Partial<T> = {}): Promise<T> {
@@ -103,5 +102,5 @@ export function duplicate<T extends object>(request: T, patch: Partial<T> = {}):
return services.socketIORequest.duplicate(request, patch);
}
// @ts-expect-error -- TSCONVERSION
return models.request.duplicate(request, patch);
return services.request.duplicate(request, patch);
}

View File

@@ -3,13 +3,14 @@ import type { Readable } from 'node:stream';
import zlib from 'node:zlib';
import { database as db } from '~/common/database';
import type { McpResponse, SocketIOResponse, WebSocketResponse } from '~/insomnia-data';
import type { Compression, McpResponse, Response, SocketIOResponse, WebSocketResponse } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import type { ResponseTimelineEntry } from '~/main/network/libcurl-promise';
import * as models from '~/models/index';
import { type Compression, isResponse, type Response, type as responseType } from '~/models/response';
import { deserializeNDJSON } from '~/utils/ndjson';
const { isResponse, type: responseType } = models.response;
export async function removeResponsesForRequest(requestId: string, environmentId?: string | null) {
const settings = await services.settings.get();
const query: Record<string, any> = {

View File

@@ -3,12 +3,6 @@ import type { AllTypes, BaseModel } from '~/models/types';
import { generateId } from '../common/misc';
import { typedKeys } from '../utils';
import * as _request from './request';
import * as _requestGroup from './request-group';
import * as _requestGroupMeta from './request-group-meta';
import * as _requestMeta from './request-meta';
import * as _requestVersion from './request-version';
import * as _response from './response';
export type { AllTypes, BaseModel };
// Reference to each model
@@ -23,13 +17,13 @@ export const oAuth2Token = models.oAuth2Token;
export const pluginData = models.pluginData;
export const mockServer = models.mockServer;
export const mockRoute = models.mockRoute;
export const request = _request;
export const requestGroup = _requestGroup;
export const requestGroupMeta = _requestGroupMeta;
export const requestMeta = _requestMeta;
export const requestVersion = _requestVersion;
export const request = models.request;
export const requestGroup = models.requestGroup;
export const requestGroupMeta = models.requestGroupMeta;
export const requestMeta = models.requestMeta;
export const requestVersion = models.requestVersion;
export const runnerTestResult = models.runnerTestResult;
export const response = _response;
export const response = models.response;
export const settings = models.settings;
export const project = models.project;
export const stats = models.stats;

View File

@@ -1,51 +0,0 @@
import { database as db } from '../common/database';
import type { BaseModel } from './types';
export const name = 'Folder Meta';
export const type = 'RequestGroupMeta';
export const prefix = 'fldm';
export const canDuplicate = false;
export const canSync = false;
interface BaseRequestGroupMeta {
collapsed: boolean;
}
export type RequestGroupMeta = BaseModel & BaseRequestGroupMeta;
export const isRequestGroupMeta = (model: Pick<BaseModel, 'type'>): model is RequestGroupMeta => model.type === type;
export function init() {
return {
parentId: null,
collapsed: false,
};
}
export function migrate(doc: RequestGroupMeta) {
return doc;
}
export function create(patch: Partial<RequestGroupMeta> = {}) {
if (!patch.parentId) {
throw new Error('New RequestGroupMeta missing `parentId`: ' + JSON.stringify(patch));
}
return db.docCreate<RequestGroupMeta>(type, patch);
}
export function update(requestGroupMeta: RequestGroupMeta, patch: Partial<RequestGroupMeta>) {
return db.docUpdate<RequestGroupMeta>(requestGroupMeta, patch);
}
export function getByParentId(parentId: string) {
return db.findOne<RequestGroupMeta>(type, { parentId });
}
export function all() {
return db.find<RequestGroupMeta>(type);
}

View File

@@ -1,121 +0,0 @@
import type { EnvironmentKvPairData, EnvironmentType } from '~/insomnia-data';
import { database as db } from '../common/database';
import { replaceIdsInFields } from './helpers/replace-ids-in-fields';
import type { RequestAuthentication, RequestHeader } from './request';
import type { BaseModel } from './types';
export const name = 'Folder';
export const type = 'RequestGroup';
export const prefix = 'fld';
export const canDuplicate = true;
export const canSync = true;
// for those keys do not need to add in model init method
export const optionalKeys = ['kvPairData', 'environmentType'];
interface BaseRequestGroup {
name: string;
description: string;
environment: Record<string, any>;
environmentPropertyOrder: Record<string, any> | null;
kvPairData?: EnvironmentKvPairData[];
environmentType?: EnvironmentType;
metaSortKey: number;
preRequestScript?: string;
afterResponseScript?: string;
authentication?: RequestAuthentication | {};
headers?: RequestHeader[];
}
export type RequestGroup = BaseModel & BaseRequestGroup;
export const isRequestGroup = (model: Pick<BaseModel, 'type'>): model is RequestGroup => model.type === type;
export function init(): BaseRequestGroup {
return {
name: 'New Folder',
description: '',
environment: {},
environmentPropertyOrder: null,
metaSortKey: -1 * Date.now(),
preRequestScript: undefined,
afterResponseScript: undefined,
authentication: undefined,
headers: undefined,
};
}
export function migrate(doc: RequestGroup) {
return doc;
}
export function create(patch: Partial<RequestGroup> = {}) {
if (!patch.parentId) {
throw new Error('New RequestGroup missing `parentId`: ' + JSON.stringify(patch));
}
return db.docCreate<RequestGroup>(type, patch);
}
export function update(requestGroup: RequestGroup, patch: Partial<RequestGroup> = {}) {
return db.docUpdate<RequestGroup>(requestGroup, patch);
}
export function getById(id: string) {
return db.findOne<RequestGroup>(type, { _id: id });
}
export function findByParentId(parentId: string) {
return db.find<RequestGroup>(type, { parentId });
}
export function remove(requestGroup: RequestGroup) {
return db.remove(requestGroup);
}
export function all() {
return db.find<RequestGroup>(type);
}
export async function duplicate(requestGroup: RequestGroup, patch: Partial<RequestGroup> = {}) {
if (!patch.name) {
patch.name = `${requestGroup.name} (Copy)`;
}
// Get sort key of next request
const q = {
metaSortKey: {
$gt: requestGroup.metaSortKey,
},
};
const [nextRequestGroup] = await db.find<RequestGroup>(type, q, {
metaSortKey: 1,
});
const nextSortKey = nextRequestGroup ? nextRequestGroup.metaSortKey : requestGroup.metaSortKey + 100;
// Calculate new sort key
const sortKeyIncrement = (nextSortKey - requestGroup.metaSortKey) / 2;
const metaSortKey = requestGroup.metaSortKey + sortKeyIncrement;
return db.duplicate<RequestGroup>(requestGroup, {
metaSortKey,
...patch,
});
}
export const isRequestGroupId = (id?: string | null) => id?.startsWith(prefix);
export function rewriteReferences(group: RequestGroup, idMapping: Map<string, string>): RequestGroup {
return {
...group,
...replaceIdsInFields(
group,
['authentication', 'headers', 'preRequestScript', 'afterResponseScript', 'environment', 'kvPairData'],
idMapping,
),
};
}

View File

@@ -1,94 +0,0 @@
import { PREVIEW_MODE_FRIENDLY, type PreviewMode } from '../common/constants';
import { database as db } from '../common/database';
import type { BaseModel } from './types';
export const name = 'Request Meta';
export const type = 'RequestMeta';
export const prefix = 'reqm';
export const canDuplicate = false;
export const canSync = false;
export type RequestAccordionKeys = 'OAuth2AdvancedOptions';
export interface BaseRequestMeta {
parentId: string;
previewMode: PreviewMode;
responseFilter: string;
responseFilterHistory: string[];
activeResponseId: string | null;
savedRequestBody: Record<string, any>;
pinned: boolean;
lastActive: number;
downloadPath: string | null;
expandedAccordionKeys: Partial<Record<RequestAccordionKeys, boolean>>;
activeMcpPrimitive?: string | null;
}
export type RequestMeta = BaseModel & BaseRequestMeta;
export const isRequestMeta = (model: Pick<BaseModel, 'type'>): model is RequestMeta => model.type === type;
export function init() {
return {
parentId: null,
previewMode: PREVIEW_MODE_FRIENDLY,
responseFilter: '',
responseFilterHistory: [],
activeResponseId: null,
savedRequestBody: {},
pinned: false,
lastActive: 0,
downloadPath: null,
expandedAccordionKeys: {},
activeMcpPrimitive: null,
};
}
export function migrate(doc: RequestMeta) {
return doc;
}
export function create(patch: Partial<RequestMeta> = {}) {
if (!patch.parentId) {
throw new Error('New RequestMeta missing `parentId` ' + JSON.stringify(patch));
}
return db.docCreate<RequestMeta>(type, patch);
}
export function update(requestMeta: RequestMeta, patch: Partial<RequestMeta>) {
return db.docUpdate<RequestMeta>(requestMeta, patch);
}
export function getByParentId(parentId: string): Promise<RequestMeta | undefined> {
return db.findOne<RequestMeta>(type, { parentId });
}
export async function getOrCreateByParentId(parentId: string) {
const requestMeta = await getByParentId(parentId);
if (requestMeta) {
return requestMeta;
}
return create({ parentId });
}
export async function updateOrCreateByParentId(parentId: string, patch: Partial<RequestMeta>) {
const requestMeta = await getByParentId(parentId);
if (requestMeta) {
return update(requestMeta, patch);
}
const newPatch = Object.assign(
{
parentId,
},
patch,
);
return create(newPatch);
}
export function all() {
return db.find<RequestMeta>(type);
}

View File

@@ -1,168 +0,0 @@
import { services } from '~/insomnia-data';
import type { RequestTestResult } from '../../../insomnia-scripting-environment/src/objects';
import { database as db } from '../common/database';
import * as requestOperations from '../models/helpers/request-operations';
import * as requestVersionModel from './request-version';
import type { BaseModel } from './types';
export const name = 'Response';
export const type = 'Response';
export const prefix = 'res';
export const canDuplicate = false;
export const canSync = false;
export interface ResponseHeader {
name: string;
value: string;
}
export type Compression = 'zip' | null | '__NEEDS_MIGRATION__' | undefined;
export interface BaseResponse {
environmentId: string | null;
globalEnvironmentId: string | null;
statusCode: number;
statusMessage: string;
httpVersion: string;
contentType: string;
url: string;
bytesRead: number;
bytesContent: number;
elapsedTime: number;
headers: ResponseHeader[];
bodyPath: string;
// if body is less than 5MB, it's stored in memory
bodyBuffer?: Buffer;
// Actual bodies are stored on the filesystem
timelinePath: string;
// Actual timelines are stored on the filesystem
bodyCompression: Compression;
error: string;
requestVersionId: string | null;
// Things from the request
settingStoreCookies: boolean | null;
settingSendCookies: boolean | null;
requestTestResults: RequestTestResult[];
}
export type Response = BaseModel & BaseResponse;
export const isResponse = (model: Pick<BaseModel, 'type'>): model is Response => model.type === type;
export function init(): BaseResponse {
return {
statusCode: 0,
statusMessage: '',
httpVersion: '',
contentType: '',
url: '',
bytesRead: 0,
// -1 means that it was legacy and this property didn't exist yet
bytesContent: -1,
elapsedTime: 0,
headers: [],
// Actual timelines are stored on the filesystem
timelinePath: '',
// Actual bodies are stored on the filesystem
bodyPath: '',
// For legacy bodies
bodyCompression: '__NEEDS_MIGRATION__',
error: '',
// Things from the request
requestVersionId: null,
settingStoreCookies: null,
settingSendCookies: null,
// Responses sent before environment filtering will have a special value
// so they don't show up at all when filtering is on.
environmentId: '__LEGACY__',
requestTestResults: [],
globalEnvironmentId: null,
};
}
export function migrate(doc: Response) {
try {
return migrateBodyCompression(doc);
} catch (e) {
console.log('[db] Error during response migration', e);
throw e;
}
}
export function getById(id: string) {
return db.findOne<Response>(type, { _id: id });
}
export function findByParentId(parentId: string) {
return db.find<Response>(type, { parentId: parentId });
}
export async function all() {
return db.find<Response>(type);
}
export async function getLatestForRequestId(
requestId: string,
environmentId: string | null,
): Promise<Response | undefined> {
// Filter responses by environment if setting is enabled
const shouldFilter = (await services.settings.get()).filterResponsesByEnv;
const response = await db.findOne<Response>(
type,
{
parentId: requestId,
...(shouldFilter ? { environmentId } : {}),
},
{ modified: -1 },
);
return response;
}
export async function create(patch: Partial<Response> = {}, maxResponses = 20): Promise<Response> {
if (!patch.parentId) {
console.log('[db] Attempted to create response without `parentId`', patch);
throw new Error('New Response missing `parentId`');
}
const { parentId } = patch;
// Create request version snapshot
const request = await requestOperations.getById(parentId);
const requestVersion = request ? await requestVersionModel.create(request) : null;
patch.requestVersionId = requestVersion ? requestVersion._id : null;
// Filter responses by environment if setting is enabled
const settings = await services.settings.get();
const shouldQueryByEnvId = 'environmentId' in patch && settings.filterResponsesByEnv;
const query = {
parentId,
...(shouldQueryByEnvId ? { environmentId: patch.environmentId } : {}),
};
// Delete all other responses before creating the new one
const responsesToShow = Math.max(1, maxResponses);
const allResponses = await db.find<Response>(type, query, { modified: -1 }, responsesToShow);
const recentIds = allResponses.map(r => r._id);
// Remove all that were in the last query, except the first `maxResponses` IDs
await db.removeWhere(type, {
...query,
_id: {
$nin: recentIds,
},
});
// Actually create the new response
return db.docCreate(type, patch);
}
function migrateBodyCompression(doc: Response) {
if (doc.bodyCompression === '__NEEDS_MIGRATION__') {
doc.bodyCompression = 'zip';
}
return doc;
}

View File

@@ -0,0 +1,116 @@
import type { RequestAuthentication, RequestHeader, RequestParameter, RequestPathParameter } from '~/insomnia-data';
import { database } from '../common/database';
import { replaceIdsInFields } from './helpers/replace-ids-in-fields';
import type { BaseModel } from './types';
export const name = 'Socket.IO Request';
export const type = 'SocketIORequest';
export const prefix = 'socketio-req';
export const canDuplicate = true;
export const canSync = true;
export interface SocketIOEventListener {
id: string;
eventName: string;
desc: string;
isOpen: boolean;
}
export interface BaseSocketIORequest {
name: string;
description: string;
url: string;
metaSortKey: number;
headers: RequestHeader[];
authentication: RequestAuthentication | {};
parameters: RequestParameter[];
pathParameters?: RequestPathParameter[];
settingEncodeUrl: boolean;
settingStoreCookies: boolean;
settingSendCookies: boolean;
settingPath?: string;
eventListeners: SocketIOEventListener[];
}
export type SocketIORequest = BaseModel & BaseSocketIORequest & { type: typeof type };
export const isSocketIORequest = (model: Pick<BaseModel, 'type'>): model is SocketIORequest => model.type === type;
export const isSocketIORequestId = (id?: string | null) => id?.startsWith(`${prefix}_`);
export const init = (): BaseSocketIORequest => ({
name: 'New Socket.IO Request',
url: '',
metaSortKey: -1 * Date.now(),
headers: [],
authentication: {},
parameters: [],
pathParameters: undefined,
settingEncodeUrl: true,
settingStoreCookies: true,
settingSendCookies: true,
settingPath: undefined,
description: '',
eventListeners: [],
});
export const create = (patch: Partial<SocketIORequest> = {}) => {
if (!patch.parentId) {
throw new Error(`New Socket.IO Request missing \`parentId\`: ${JSON.stringify(patch)}`);
}
return database.docCreate<SocketIORequest>(type, patch);
};
export const getById = (_id: string) => database.findOne<SocketIORequest>(type, { _id });
export const findByParentId = (parentId: string) => database.find<SocketIORequest>(type, { parentId });
export const migrate = (doc: SocketIORequest) => doc;
export const remove = (obj: SocketIORequest) => database.remove(obj);
export const update = (obj: SocketIORequest, patch: Partial<SocketIORequest> = {}) => database.docUpdate(obj, patch);
// This is duplicated (lol) from models/request.js
export async function duplicate(request: SocketIORequest, patch: Partial<SocketIORequest> = {}) {
// Only set name and "(Copy)" if the patch does
// not define it and the request itself has a name.
// Otherwise leave it blank so the request URL can
// fill it in automatically.
if (!patch.name && request.name) {
patch.name = `${request.name} (Copy)`;
}
// Get sort key of next request
const q = {
metaSortKey: {
$gt: request.metaSortKey,
},
};
const [nextRequest] = await database.find<SocketIORequest>(type, q, {
metaSortKey: 1,
});
const nextSortKey = nextRequest ? nextRequest.metaSortKey : request.metaSortKey + 100;
// Calculate new sort key
const sortKeyIncrement = (nextSortKey - request.metaSortKey) / 2;
const metaSortKey = request.metaSortKey + sortKeyIncrement;
return database.duplicate<SocketIORequest>(request, {
name,
metaSortKey,
...patch,
});
}
export function rewriteReferences(request: SocketIORequest, idMapping: Map<string, string>): SocketIORequest {
return {
...request,
...replaceIdsInFields(request, ['url', 'headers', 'authentication', 'parameters', 'pathParameters'], idMapping),
};
}

View File

@@ -0,0 +1,113 @@
import type { RequestAuthentication, RequestHeader, RequestParameter, RequestPathParameter } from '~/insomnia-data';
import { database } from '../common/database';
import { replaceIdsInFields } from './helpers/replace-ids-in-fields';
import type { BaseModel } from './types';
export const name = 'WebSocket Request';
export const type = 'WebSocketRequest';
export const prefix = 'ws-req';
export const canDuplicate = true;
export const canSync = true;
export interface BaseWebSocketRequest {
name: string;
description: string;
url: string;
metaSortKey: number;
headers: RequestHeader[];
authentication: RequestAuthentication | {};
parameters: RequestParameter[];
pathParameters?: RequestPathParameter[];
settingEncodeUrl: boolean;
settingStoreCookies: boolean;
settingSendCookies: boolean;
settingFollowRedirects: 'global' | 'on' | 'off';
settingUseProxy?: boolean;
}
export type WebSocketRequest = BaseModel & BaseWebSocketRequest & { type: typeof type };
export const isWebSocketRequest = (model: Pick<BaseModel, 'type'>): model is WebSocketRequest => model.type === type;
export const isWebSocketRequestId = (id?: string | null) => id?.startsWith(`${prefix}_`);
// for those keys do not need to add in model init method but can update
export const optionalKeys = ['settingUseProxy'];
export const init = (): BaseWebSocketRequest => ({
name: 'New WebSocket Request',
url: '',
metaSortKey: -1 * Date.now(),
headers: [],
authentication: {},
parameters: [],
pathParameters: undefined,
settingEncodeUrl: true,
settingStoreCookies: true,
settingSendCookies: true,
settingFollowRedirects: 'global',
description: '',
});
export const migrate = (doc: WebSocketRequest) => doc;
export const create = (patch: Partial<WebSocketRequest> = {}) => {
if (!patch.parentId) {
throw new Error(`New WebSocketRequest missing \`parentId\`: ${JSON.stringify(patch)}`);
}
return database.docCreate<WebSocketRequest>(type, patch);
};
export const remove = (obj: WebSocketRequest) => database.remove(obj);
export const update = (obj: WebSocketRequest, patch: Partial<WebSocketRequest> = {}) => database.docUpdate(obj, patch);
// This is duplicated (lol) from models/request.js
export async function duplicate(request: WebSocketRequest, patch: Partial<WebSocketRequest> = {}) {
// Only set name and "(Copy)" if the patch does
// not define it and the request itself has a name.
// Otherwise leave it blank so the request URL can
// fill it in automatically.
if (!patch.name && request.name) {
patch.name = `${request.name} (Copy)`;
}
// Get sort key of next request
const q = {
metaSortKey: {
$gt: request.metaSortKey,
},
};
const [nextRequest] = await database.find<WebSocketRequest>(type, q, {
metaSortKey: 1,
});
const nextSortKey = nextRequest ? nextRequest.metaSortKey : request.metaSortKey + 100;
// Calculate new sort key
const sortKeyIncrement = (nextSortKey - request.metaSortKey) / 2;
const metaSortKey = request.metaSortKey + sortKeyIncrement;
return database.duplicate<WebSocketRequest>(request, {
name,
metaSortKey,
...patch,
});
}
export const getById = (_id: string) => database.findOne<WebSocketRequest>(type, { _id });
export const findByParentId = (parentId: string) => database.find<WebSocketRequest>(type, { parentId });
export const all = () => database.find<WebSocketRequest>(type);
export function rewriteReferences(request: WebSocketRequest, idMapping: Map<string, string>): WebSocketRequest {
return {
...request,
...replaceIdsInFields(request, ['url', 'headers', 'authentication', 'parameters', 'pathParameters'], idMapping),
};
}

View File

@@ -0,0 +1,126 @@
import type { ResponseHeader } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { database as db } from '../common/database';
import * as requestOperations from './helpers/request-operations';
import type { BaseModel } from './types';
export const name = 'WebSocket Response';
export const type = 'WebSocketResponse';
export const prefix = 'ws-res';
export const canDuplicate = false;
export const canSync = false;
export interface BaseWebSocketResponse {
environmentId: string | null;
statusCode: number;
statusMessage: string;
httpVersion: string;
contentType: string;
url: string;
elapsedTime: number;
headers: ResponseHeader[];
// Event logs are stored on the filesystem
eventLogPath: string;
// Actual timelines are stored on the filesystem
timelinePath: string;
error: string;
requestVersionId: string | null;
settingStoreCookies: boolean | null;
settingSendCookies: boolean | null;
}
export type WebSocketResponse = BaseModel & BaseWebSocketResponse;
export const isWebSocketResponse = (model: Pick<BaseModel, 'type'>): model is WebSocketResponse => model.type === type;
export function init(): BaseWebSocketResponse {
return {
statusCode: 0,
statusMessage: '',
httpVersion: '',
contentType: '',
url: '',
elapsedTime: 0,
headers: [],
timelinePath: '',
eventLogPath: '',
error: '',
requestVersionId: null,
settingStoreCookies: null,
settingSendCookies: null,
environmentId: null,
};
}
export function migrate(doc: WebSocketResponse) {
return doc;
}
export function getById(id: string) {
return db.findOne<WebSocketResponse>(type, { _id: id });
}
export function findByParentId(parentId: string) {
return db.find<WebSocketResponse>(type, { parentId: parentId });
}
export async function all() {
return db.find<WebSocketResponse>(type);
}
export async function create(patch: Partial<WebSocketResponse> = {}, maxResponses = 20) {
if (!patch.parentId) {
throw new Error('New Response missing `parentId`');
}
const { parentId } = patch;
// Create request version snapshot
const request = await requestOperations.getById(parentId);
const requestVersion = request ? await services.requestVersion.create(request) : null;
patch.requestVersionId = requestVersion ? requestVersion._id : null;
// Filter responses by environment if setting is enabled
const query: Record<string, any> = {
parentId,
};
if ((await services.settings.get()).filterResponsesByEnv && 'environmentId' in patch) {
query.environmentId = patch.environmentId;
}
// Delete all other responses before creating the new one
const responsesToShow = Math.max(1, maxResponses);
const allResponses = await db.find<WebSocketResponse>(type, query, { modified: -1 }, responsesToShow);
const recentIds = allResponses.map(r => r._id);
// Remove all that were in the last query, except the first `maxResponses` IDs
await db.removeWhere(type, {
...query,
_id: {
$nin: recentIds,
},
});
// Actually create the new response
return db.docCreate(type, patch);
}
export async function getLatestForRequestId(requestId: string, environmentId: string | null) {
// Filter responses by environment if setting is enabled
const shouldFilter = (await services.settings.get()).filterResponsesByEnv;
const response = await db.findOne<WebSocketResponse>(
type,
{
parentId: requestId,
...(shouldFilter ? { environmentId } : {}),
},
{ modified: -1 },
);
return response;
}

View File

@@ -1,6 +1,7 @@
import * as Hawk from 'hawk';
import type { AuthTypeOAuth2, RequestAuthentication, RequestParameter } from '../models/request';
import type { AuthTypeOAuth2, RequestAuthentication, RequestParameter } from '~/insomnia-data';
import type { RenderedRequest } from '../templating/types';
import { COOKIE, HEADER, QUERY_PARAMS } from './api-key/constants';
import { getBasicAuthHeader } from './basic-auth/get-header';

View File

@@ -1,4 +1,4 @@
import type { RequestHeader } from '../../models/request';
import type { RequestHeader } from '~/insomnia-data';
export function getBasicAuthHeader(username?: string | null, password?: string | null, encoding = 'utf8') {
const name = 'Authorization';

View File

@@ -1,4 +1,4 @@
import type { RequestHeader } from '../../models/request';
import type { RequestHeader } from '~/insomnia-data';
export function getBearerAuthHeader(token: string, prefix?: string) {
const name = 'Authorization';

View File

@@ -1,10 +1,16 @@
import type { queueAsPromised } from 'fastq';
import * as fastq from 'fastq';
import type { ClientCertificate, CookieJar, Environment, Settings, UserUploadEnvironment } from '~/insomnia-data';
import type {
ClientCertificate,
CookieJar,
Environment,
Request,
Settings,
UserUploadEnvironment,
} from '~/insomnia-data';
import type { RequestContext, RequestTestResult } from '../../../insomnia-scripting-environment/src/objects';
import type { Request } from '../models/request';
import { cancellableExecution } from './cancellation';
export interface ExecuteScriptContext {

View File

@@ -13,6 +13,11 @@ import type {
MockRoute,
MockServer,
Project,
Request,
RequestAuthentication,
RequestGroup,
RequestHeader,
RequestParameter,
Settings,
SocketIORequest,
UserUploadEnvironment,
@@ -35,15 +40,6 @@ import { getRenderedRequestAndContext } from '../common/render';
import { ascendingFirstIndexStringSort } from '../common/sorting';
import type { HeaderResult, ResponsePatch, ResponseTimelineEntry } from '../main/network/libcurl-promise';
import * as models from '../models';
import {
type BaseRequest,
isRequest,
type Request,
type RequestAuthentication,
type RequestHeader,
type RequestParameter,
} from '../models/request';
import { isRequestGroup, type RequestGroup } from '../models/request-group';
import * as pluginApp from '../plugins/context/app';
import * as pluginData from '../plugins/context/data';
import * as pluginNetwork from '../plugins/context/network';
@@ -63,6 +59,9 @@ import { filterClientCertificates } from './certificate';
import { runScriptConcurrently, type TransformedExecuteScriptContext } from './concurrency';
import { addSetCookiesToToughCookieJar } from './set-cookie-util';
const { isRequest } = models.request;
const { isRequestGroup } = models.requestGroup;
export interface SendActionRuntime {
appendTimeline: (timelinePath: string, logs: string[]) => Promise<void>;
}
@@ -95,7 +94,7 @@ export function getOrInheritHeaders({
request,
requestGroups,
}: {
request: Pick<BaseRequest, 'headers'>;
request: Pick<Request, 'headers'>;
requestGroups: Pick<RequestGroup, 'headers'>[];
}): RequestHeader[] {
const httpHeaders = new Map<string, string>();
@@ -128,7 +127,7 @@ export function getOrInheritHeaders({
}
// (only used for getOAuth2 token) Intended to gather all required database objects and initialize ids
export const fetchRequestGroupData = async (requestGroupId: string) => {
const requestGroup = await models.requestGroup.getById(requestGroupId);
const requestGroup = await services.requestGroup.getById(requestGroupId);
invariant(requestGroup, 'failed to find requestGroup ' + requestGroupId);
const ancestors = await db.withAncestors<RequestGroup | Workspace | MockRoute | MockServer>(requestGroup, [
models.requestGroup.type,
@@ -169,7 +168,7 @@ export const fetchRequestData = async (
// Override the active environment id to use for the request
overrideEnvironmentId?: string,
) => {
const request = await models.request.getById(requestId);
const request = await services.request.getById(requestId);
invariant(request, 'failed to find request ' + requestId);
const ancestors = await db.withAncestors<Request | RequestGroup | Workspace | Project | MockRoute | MockServer>(
request,
@@ -478,7 +477,7 @@ export async function savePatchesMadeByScript(patches: {
mutatedContext.parentFolders.forEach(mutatedFolder => {
const originalFolder = originalRequestGroups.find(originalFolder => originalFolder._id === mutatedFolder.id);
if (originalFolder) {
models.requestGroup.update(originalFolder, {
services.requestGroup.update(originalFolder, {
environment: mutatedFolder.environment,
// also update kvPairData when folder environment type is table view(kv pair)
...(originalFolder.environmentType === EnvironmentType.KVPAIR && {

View File

@@ -6,8 +6,9 @@ import crypto from 'node:crypto';
import OAuth1 from 'oauth-1.0a';
import type { RequestAuthentication, RequestBody } from '~/insomnia-data';
import { CONTENT_TYPE_FORM_URLENCODED } from '../../common/constants';
import type { RequestAuthentication, RequestBody } from '../../models/request';
import type { OAuth1SignatureMethod } from './constants';
import {
SIGNATURE_METHOD_HMAC_SHA1,

View File

@@ -3,7 +3,16 @@ import querystring from 'node:querystring';
import { v4 as uuidv4 } from 'uuid';
import type { OAuth2Token } from '~/insomnia-data';
import type {
AuthTypeOAuth2,
OAuth2ResponseType,
OAuth2Token,
Request,
RequestGroup,
RequestHeader,
RequestParameter,
Response,
} from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { getBodyBuffer } from '~/models/helpers/response-operations';
import { encryptOAuthUrl } from '~/network/o-auth-2/utils';
@@ -13,10 +22,6 @@ import { getOauthRedirectUrl } from '../../common/constants';
import { database as db } from '../../common/database';
import { escapeRegex } from '../../common/misc';
import * as models from '../../models';
import type { AuthTypeOAuth2, OAuth2ResponseType, RequestHeader, RequestParameter } from '../../models/request';
import type { Request } from '../../models/request';
import { isRequestGroup, isRequestGroupId, type RequestGroup } from '../../models/request-group';
import type { Response } from '../../models/response';
import uiEventBus, { OAUTH2_AUTHORIZATION_STATUS_CHANGE } from '../../ui/event-bus';
import { invariant } from '../../utils/invariant';
import { setDefaultProtocol } from '../../utils/url/protocol';
@@ -33,6 +38,7 @@ import {
} from '../network';
import { type AuthKeys, GRANT_TYPE_AUTHORIZATION_CODE, PKCE_CHALLENGE_S256 } from './constants';
const { isRequestGroup, isRequestGroupId } = models.requestGroup;
const LOCALSTORAGE_KEY_SESSION_ID = 'insomnia::current-oauth-session-id';
export function initNewOAuthSession() {
@@ -267,7 +273,7 @@ async function getExistingAccessTokenAndRefreshIfExpired(
let closestAuthId = requestId;
if (!models.mcpRequest.isMcpRequestId(requestId)) {
const activeRequest = await models.request.getById(requestId);
const activeRequest = await services.request.getById(requestId);
const requestGroups = (
await db.withAncestors<Request | RequestGroup>(activeRequest, [models.requestGroup.type])
).filter(isRequestGroup) as RequestGroup[];
@@ -465,7 +471,7 @@ const sendAccessTokenRequest = async (
);
const responsePatch = await responseTransform(response, activeEnvironmentId, renderedRequest, renderResult.context);
return await models.response.create(responsePatch);
return await services.response.create(responsePatch);
};
export const encodePKCE = (buffer: Buffer) => {
return (

View File

@@ -25,7 +25,7 @@ describe('init()', () => {
_id: 'wrk_1',
name: 'My Workspace',
});
await models.request.create({
await services.request.create({
_id: 'req_1',
parentId: 'wrk_1',
name: 'My Request',
@@ -33,7 +33,7 @@ describe('init()', () => {
});
it('initializes correctly', async () => {
const result = plugin.init(await models.request.getById('req_1'), CONTEXT);
const result = plugin.init(await services.request.getById('req_1'), CONTEXT);
expect(Object.keys(result)).toEqual(['request']);
expect(Object.keys(result.request).sort()).toEqual([
'addHeader',
@@ -72,7 +72,7 @@ describe('init()', () => {
});
it('initializes correctly in read-only mode', async () => {
const result = plugin.init(await models.request.getById('req_1'), CONTEXT, true);
const result = plugin.init(await services.request.getById('req_1'), CONTEXT, true);
expect(Object.keys(result)).toEqual(['request']);
expect(Object.keys(result.request).sort()).toEqual([
'getAuthentication',
@@ -106,7 +106,7 @@ describe('request.*', () => {
_id: 'wrk_1',
name: 'My Workspace',
});
await models.request.create({
await services.request.create({
_id: 'req_1',
parentId: 'wrk_1',
name: 'My Request',
@@ -141,7 +141,7 @@ describe('request.*', () => {
it('works for basic getters', async () => {
const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
const result = plugin.init(await models.request.getById('req_1'), CONTEXT);
const result = plugin.init(await services.request.getById('req_1'), CONTEXT);
expect(result.request.getId()).toBe('req_1');
expect(result.request.getName()).toBe('My Request');
expect(result.request.getUrl()).toBe('');
@@ -154,7 +154,7 @@ describe('request.*', () => {
});
it('works for parameters', async () => {
const result = plugin.init(await models.request.getById('req_1'), CONTEXT);
const result = plugin.init(await services.request.getById('req_1'), CONTEXT);
// getParameters()
expect(result.request.getParameters()).toEqual([
{
@@ -186,7 +186,7 @@ describe('request.*', () => {
});
it('works for headers', async () => {
const result = plugin.init(await models.request.getById('req_1'), CONTEXT);
const result = plugin.init(await services.request.getById('req_1'), CONTEXT);
// getHeaders()
expect(result.request.getHeaders()).toEqual([
{
@@ -218,7 +218,7 @@ describe('request.*', () => {
});
it('works for cookies', async () => {
const request = await models.request.getById('req_1');
const request = await services.request.getById('req_1');
request.cookies = []; // Because the plugin technically needs a RenderedRequest
const result = plugin.init(request, CONTEXT);
@@ -233,7 +233,7 @@ describe('request.*', () => {
});
it('works for environment', async () => {
const request = await models.request.getById('req_1');
const request = await services.request.getById('req_1');
request.cookies = []; // Because the plugin technically needs a RenderedRequest
const result = plugin.init(request, CONTEXT);
@@ -261,7 +261,7 @@ describe('request.*', () => {
});
it('works for authentication', async () => {
const request = await models.request.getById('req_1');
const request = await services.request.getById('req_1');
request.authentication = {}; // Because the plugin technically needs a RenderedRequest
const result = plugin.init(request, CONTEXT);
@@ -276,7 +276,7 @@ describe('request.*', () => {
});
it('works for request body', async () => {
const result = plugin.init(await models.request.getById('req_1'), CONTEXT);
const result = plugin.init(await services.request.getById('req_1'), CONTEXT);
expect(result.request.getBody()).toEqual({
text: 'body',
});

View File

@@ -1,12 +1,10 @@
import { v4 as uuidv4 } from 'uuid';
import type { Request, ResponseHeader } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { readCurlResponse } from '~/models/helpers/response-operations';
import { RESPONSE_CODE_REASONS } from '../../common/constants';
import * as models from '../../models';
import type { Request } from '../../models/request';
import { type ResponseHeader } from '../../models/response';
import {
fetchRequestData,
responseTransform,
@@ -71,7 +69,7 @@ export function init(): {
renderedRequest,
renderResult.context,
);
return models.response.create(responsePatch, settings.maxHistoryResponses);
return services.response.create(responsePatch, settings.maxHistoryResponses);
},
// using node-curl to send a request directly, without context render and database write for request and response
async sendRequestWithoutSideEffects(options: NodeCurlRequestOptions): Promise<NodeCurlResponseType> {

View File

@@ -1,5 +1,6 @@
import type { RequestBody } from '~/insomnia-data';
import * as misc from '../../common/misc';
import type { RequestBody } from '../../models/request';
import type { RenderedRequest } from '../../templating/types';
export function filterParameters<T extends { name: string; value: string }>(parameters: T[], name: string): T[] {
if (!Array.isArray(parameters) || !name) {

View File

@@ -1,8 +1,8 @@
import fs from 'node:fs';
import type { ResponseHeader } from '~/insomnia-data';
import { getBodyBuffer, getBodyStream } from '~/models/helpers/response-operations';
import type { ResponseHeader } from '../../models/response';
interface MaybeResponse {
parentId?: string;

View File

@@ -3,7 +3,7 @@ import path from 'node:path';
import electron from 'electron';
import type { GrpcRequest, SocketIORequest, WebSocketRequest, Workspace } from '~/insomnia-data';
import type { GrpcRequest, Request, RequestGroup, SocketIORequest, WebSocketRequest, Workspace } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { getBodyBuffer } from '~/models/helpers/response-operations';
import { fetchFromTemplateWorkerDatabase } from '~/templating/base-extension-worker';
@@ -13,8 +13,6 @@ import { getAppBundlePlugins, isDevelopment } from '../common/constants';
import { database as db } from '../common/database';
import type { PluginConfigMap } from '../common/settings';
import * as models from '../models';
import type { Request } from '../models/request';
import type { RequestGroup } from '../models/request-group';
import * as pluginApp from '../plugins/context/app';
import * as pluginNetwork from '../plugins/context/network';
import * as pluginStore from '../plugins/context/store';
@@ -387,7 +385,7 @@ export function getPluginCommonContext({
: electron.shell.openExternal(url),
models: {
request: {
getById: models.request.getById,
getById: services.request.getById,
getAncestors: async (request: any) => {
const ancestors = await db.withAncestors<Request | RequestGroup | Workspace>(request, [
models.requestGroup.type,
@@ -412,7 +410,7 @@ export function getPluginCommonContext({
},
},
response: {
getLatestForRequestId: models.response.getLatestForRequestId,
getLatestForRequestId: services.response.getLatestForRequestId,
getBodyBuffer,
},
settings: {

View File

@@ -2,12 +2,18 @@ import type { Organization } from 'insomnia-api';
import { database } from '~/common/database';
import { fuzzyMatch } from '~/common/misc';
import type { Environment, GrpcRequest, Project, WebSocketRequest, Workspace } from '~/insomnia-data';
import type {
Environment,
GrpcRequest,
Project,
Request,
RequestGroup,
WebSocketRequest,
Workspace,
} from '~/insomnia-data';
import { models, services } from '~/insomnia-data';
import { environment, grpcRequest, project, request, requestGroup, workspace } from '~/models';
import { isScratchpadOrganizationId } from '~/models/organization';
import type { Request } from '~/models/request';
import type { RequestGroup } from '~/models/request-group';
import { invariant } from '~/utils/invariant';
import { createFetcherLoadHook } from '~/utils/router';

View File

@@ -1,15 +1,16 @@
import { href } from 'react-router';
import * as models from '~/models';
import { models, services } from '~/insomnia-data';
import { getById, update } from '~/models/helpers/request-operations';
import { isRequestGroup, isRequestGroupId } from '~/models/request-group';
import { invariant } from '~/utils/invariant';
import { createFetcherSubmitHook } from '~/utils/router';
import type { Route } from './+types/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.reorder';
const { isRequestGroup, isRequestGroupId } = models.requestGroup;
const getCollectionItem = async (id: string) => {
const item = await (isRequestGroupId(id) ? models.requestGroup.getById(id) : getById(id));
const item = await (isRequestGroupId(id) ? services.requestGroup.getById(id) : getById(id));
invariant(item, 'Item not found');
@@ -33,7 +34,7 @@ export async function clientAction({ request }: Route.ClientActionArgs) {
const parentId = dropPosition === 'after' && isRequestGroup(targetItem) ? targetItem._id : targetItem.parentId;
await (isRequestGroup(item)
? models.requestGroup.update(item, { parentId, metaSortKey })
? services.requestGroup.update(item, { parentId, metaSortKey })
: update(item, { parentId, metaSortKey }));
return null;

View File

@@ -1,7 +1,7 @@
import { href, redirect, useRouteLoaderData } from 'react-router';
import * as models from '~/models';
import type { RequestGroup } from '~/models/request-group';
import type { RequestGroup } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { showResourceNotFoundToast } from '~/ui/components/toast-notification';
import type { Route } from './+types/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request-group.$requestGroupId';
@@ -13,7 +13,7 @@ export interface RequestGroupLoaderData {
export async function clientLoader({ params }: Route.ClientLoaderArgs) {
const { organizationId, projectId, requestGroupId, workspaceId } = params;
const activeRequestGroup = await models.requestGroup.getById(requestGroupId);
const activeRequestGroup = await services.requestGroup.getById(requestGroupId);
if (!activeRequestGroup) {
showResourceNotFoundToast(`Folder not found: ${requestGroupId}`);
throw redirect(

View File

@@ -1,7 +1,7 @@
import { href } from 'react-router';
import * as models from '~/models';
import type { RequestGroupMeta } from '~/models/request-group-meta';
import type { RequestGroupMeta } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { invariant } from '~/utils/invariant';
import { createFetcherSubmitHook } from '~/utils/router';
@@ -11,12 +11,12 @@ export async function clientAction({ request, params }: Route.ClientActionArgs)
const { requestGroupId } = params;
invariant(typeof requestGroupId === 'string', 'Request Group ID is required');
const patch = (await request.json()) as Partial<RequestGroupMeta>;
const requestGroupMeta = await models.requestGroupMeta.getByParentId(requestGroupId);
const requestGroupMeta = await services.requestGroupMeta.getByParentId(requestGroupId);
if (requestGroupMeta) {
await models.requestGroupMeta.update(requestGroupMeta, patch);
await services.requestGroupMeta.update(requestGroupMeta, patch);
return null;
}
await models.requestGroupMeta.create({ parentId: requestGroupId, collapsed: Boolean(patch?.collapsed) });
await services.requestGroupMeta.create({ parentId: requestGroupId, collapsed: Boolean(patch?.collapsed) });
return null;
}

View File

@@ -1,7 +1,7 @@
import { href } from 'react-router';
import * as models from '~/models';
import type { RequestGroup } from '~/models/request-group';
import type { RequestGroup } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import { invariant } from '~/utils/invariant';
import { createFetcherSubmitHook } from '~/utils/router';
@@ -10,12 +10,12 @@ import type { Route } from './+types/organization.$organizationId.project.$proje
export async function clientAction({ request, params }: Route.ActionArgs) {
const { requestGroupId } = params;
const reqGroup = await models.requestGroup.getById(requestGroupId);
const reqGroup = await services.requestGroup.getById(requestGroupId);
invariant(reqGroup, 'Request Group not found');
const patch = (await request.json()) as Partial<RequestGroup>;
await models.requestGroup.update(reqGroup, patch);
await services.requestGroup.update(reqGroup, patch);
return null;
}

View File

@@ -1,7 +1,6 @@
import { href } from 'react-router';
import { services } from '~/insomnia-data';
import * as models from '~/models';
import { invariant } from '~/utils/invariant';
import { createFetcherSubmitHook } from '~/utils/router';
@@ -11,12 +10,12 @@ export async function clientAction({ request }: Route.ClientActionArgs) {
const formData = await request.formData();
const id = formData.get('id') as string;
const requestGroup = await models.requestGroup.getById(id);
const requestGroup = await services.requestGroup.getById(id);
invariant(requestGroup, 'Request Group not found');
services.stats.incrementDeletedRequestsForDescendents(requestGroup);
await models.requestGroup.remove(requestGroup);
await services.requestGroup.remove(requestGroup);
return null;
}

View File

@@ -1,8 +1,7 @@
import { href } from 'react-router';
import type { RequestGroup } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import * as models from '~/models';
import type { RequestGroup } from '~/models/request-group';
import { invariant } from '~/utils/invariant';
import { createFetcherSubmitHook } from '~/utils/router';
@@ -12,7 +11,7 @@ export async function clientAction({ request }: Route.ClientActionArgs) {
const patch = (await request.json()) as Partial<RequestGroup>;
invariant(patch._id, 'Request group id not found');
const requestGroup = await models.requestGroup.getById(patch._id);
const requestGroup = await services.requestGroup.getById(patch._id);
invariant(requestGroup, 'Request group not found');
if (patch.parentId) {
@@ -20,7 +19,7 @@ export async function clientAction({ request }: Route.ClientActionArgs) {
invariant(workspace, 'Workspace is required');
// TODO: if gRPC, we should also copy the protofile to the destination workspace - INS-267
// Move to top of sort order
const newRequestGroup = await models.requestGroup.duplicate(requestGroup, {
const newRequestGroup = await services.requestGroup.duplicate(requestGroup, {
name: patch.name,
parentId: patch.parentId,
metaSortKey: -1e9,
@@ -31,7 +30,7 @@ export async function clientAction({ request }: Route.ClientActionArgs) {
return null;
}
const newRequestGroup = await models.requestGroup.duplicate(requestGroup, { name: patch.name });
const newRequestGroup = await services.requestGroup.duplicate(requestGroup, { name: patch.name });
services.stats.incrementCreatedRequestsForDescendents(newRequestGroup);

View File

@@ -1,7 +1,6 @@
import { href } from 'react-router';
import { EnvironmentType } from '~/insomnia-data';
import * as models from '~/models';
import { EnvironmentType, services } from '~/insomnia-data';
import { createFetcherSubmitHook } from '~/utils/router';
import type { Route } from './+types/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request-group.new';
@@ -13,9 +12,9 @@ export async function clientAction({ request, params }: Route.ClientActionArgs)
const parentId = formData.get('parentId') as string;
// New folder environment to be key-value pair by default;
const environmentType = (formData.get('environmentType') as EnvironmentType) || EnvironmentType.KVPAIR;
const requestGroup = await models.requestGroup.create({ parentId: parentId || workspaceId, name, environmentType });
const requestGroup = await services.requestGroup.create({ parentId: parentId || workspaceId, name, environmentType });
await models.requestGroupMeta.create({ parentId: requestGroup._id, collapsed: false });
await services.requestGroupMeta.create({ parentId: requestGroup._id, collapsed: false });
return null;
}

View File

@@ -2,12 +2,9 @@ import { GRAPHQL_TRANSPORT_WS_PROTOCOL, MessageType } from 'graphql-ws';
import { href } from 'react-router';
import type { ChangeBufferEvent } from '~/common/database';
import type { CookieJar, McpTransportType } from '~/insomnia-data';
import type { CookieJar, McpTransportType, RequestAuthentication, RequestHeader } from '~/insomnia-data';
import { models } from '~/insomnia-data';
import * as requestOperations from '~/models/helpers/request-operations';
import type { RequestAuthentication, RequestHeader } from '~/models/request';
import { isEventStreamRequest, isGraphqlSubscriptionRequest } from '~/models/request';
import { isRequestMeta } from '~/models/request-meta';
import { getAuthHeader } from '~/network/authentication';
import type { RenderedRequest } from '~/templating/types';
import { invariant } from '~/utils/invariant';
@@ -15,6 +12,9 @@ import { createFetcherSubmitHook } from '~/utils/router';
import type { Route } from './+types/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId.connect';
const { isGraphqlSubscriptionRequest, isEventStreamRequest } = models.request;
const { isRequestMeta } = models.requestMeta;
export interface ConnectActionParams {
url: string;
headers: RequestHeader[];

View File

@@ -32,7 +32,7 @@ export async function clientAction({ request, params }: Route.ClientActionArgs)
} else if (isMcpRequest) {
responseModel = services.mcpResponse;
} else {
responseModel = models.response;
responseModel = services.response;
}
const res = await responseModel.getById(responseId);
@@ -41,9 +41,9 @@ export async function clientAction({ request, params }: Route.ClientActionArgs)
await removeResponse(res);
const response = await responseModel.getLatestForRequestId(requestId, workspaceMeta.activeEnvironmentId);
if (response?.requestVersionId) {
await models.requestVersion.restore(response.requestVersionId);
await services.requestVersion.restore(response.requestVersionId);
}
await models.requestMeta.updateOrCreateByParentId(requestId, {
await services.requestMeta.updateOrCreateByParentId(requestId, {
activeResponseId: response?._id || null,
});

View File

@@ -9,6 +9,7 @@ import { v4 as uuidv4 } from 'uuid';
import { getContentDispositionHeader } from '~/common/misc';
import type {
Environment,
RequestMeta,
ResponseInfo,
RunnerResultPerRequestPerIteration,
UserUploadEnvironment,
@@ -18,7 +19,6 @@ import type { ResponsePatch } from '~/main/network/libcurl-promise';
import type { TimingStep } from '~/main/network/request-timing';
import * as models from '~/models';
import { getBodyStream } from '~/models/helpers/response-operations';
import type { RequestMeta } from '~/models/request-meta';
import {
defaultSendActionRuntime,
fetchRequestData,
@@ -87,14 +87,14 @@ const writeToDownloadPath = (
return new Promise(resolve => {
readStream.on('end', async () => {
responsePatch.error = `Saved to ${downloadPathAndName}`;
const response = await models.response.create(responsePatch, maxHistoryResponses);
await models.requestMeta.update(requestMeta, { activeResponseId: response._id });
const response = await services.response.create(responsePatch, maxHistoryResponses);
await services.requestMeta.update(requestMeta, { activeResponseId: response._id });
resolve(null);
});
readStream.on('error', async err => {
console.warn('Failed to download request after sending', responsePatch.bodyPath, err);
const response = await models.response.create(responsePatch, maxHistoryResponses);
await models.requestMeta.update(requestMeta, { activeResponseId: response._id });
const response = await services.response.create(responsePatch, maxHistoryResponses);
await services.requestMeta.update(requestMeta, { activeResponseId: response._id });
resolve(null);
});
});
@@ -130,7 +130,7 @@ export const sendActionImplementation = async (options: {
window.main.startExecution({ requestId });
const requestData = await fetchRequestData(requestId);
const requestMeta = await models.requestMeta.getOrCreateByParentId(requestId);
const requestMeta = await services.requestMeta.getOrCreateByParentId(requestId);
const transientVariables = nullableTransientVariables || {
...models.environment.init(),
_id: uuidv4(),
@@ -153,7 +153,7 @@ export const sendActionImplementation = async (options: {
);
if ('error' in mutatedContext) {
const createdResponse = await models.response.create(
const createdResponse = await services.response.create(
{
_id: requestData.responseId,
parentId: requestId,
@@ -164,7 +164,7 @@ export const sendActionImplementation = async (options: {
},
requestData.settings.maxHistoryResponses,
);
await models.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: createdResponse._id });
await services.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: createdResponse._id });
window.main.completeExecutionStep({ requestId });
return { nextRequestIdOrName: mutatedContext.execution?.nextRequestIdOrName };
}
@@ -173,7 +173,7 @@ export const sendActionImplementation = async (options: {
// cancel request running if skipRequest in pre-request script
// create and update response to activeResponse
const createdResponse = await models.response.create(
const createdResponse = await services.response.create(
{
_id: requestData.responseId,
parentId: requestId,
@@ -184,7 +184,7 @@ export const sendActionImplementation = async (options: {
},
requestData.settings.maxHistoryResponses,
);
await models.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: createdResponse._id });
await services.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: createdResponse._id });
window.main.completeExecutionStep({ requestId });
return { nextRequestIdOrName: mutatedContext.execution?.nextRequestIdOrName };
}
@@ -228,7 +228,7 @@ export const sendActionImplementation = async (options: {
window.main.completeExecutionStep({ requestId });
if ('error' in response) {
const createdResponse = await models.response.create(
const createdResponse = await services.response.create(
{
_id: requestData.responseId,
parentId: requestId,
@@ -239,7 +239,7 @@ export const sendActionImplementation = async (options: {
},
requestData.settings.maxHistoryResponses,
);
await models.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: createdResponse._id });
await services.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: createdResponse._id });
window.main.completeExecutionStep({ requestId });
return { nextRequestIdOrName: mutatedContext.execution?.nextRequestIdOrName };
}
@@ -270,7 +270,7 @@ export const sendActionImplementation = async (options: {
});
if ('error' in postMutatedContext) {
const createdResponse = await models.response.create(
const createdResponse = await services.response.create(
{
_id: requestData.responseId,
parentId: requestId,
@@ -281,7 +281,7 @@ export const sendActionImplementation = async (options: {
},
requestData.settings.maxHistoryResponses,
);
await models.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: createdResponse._id });
await services.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: createdResponse._id });
window.main.completeExecutionStep({ requestId });
return { nextRequestIdOrName: postMutatedContext.execution?.nextRequestIdOrName };
}
@@ -307,8 +307,8 @@ export const sendActionImplementation = async (options: {
: baseResponsePatch;
if (!shouldWriteToFile) {
const response = await models.response.create(responsePatch, requestData.settings.maxHistoryResponses);
await models.requestMeta.update(requestMeta, { activeResponseId: response._id });
const response = await services.response.create(responsePatch, requestData.settings.maxHistoryResponses);
await services.requestMeta.update(requestMeta, { activeResponseId: response._id });
return { nextRequestIdOrName: postMutatedContext.execution?.nextRequestIdOrName };
}
@@ -351,13 +351,13 @@ export async function clientAction({ request, params }: Route.ClientActionArgs)
ignoreUndefinedEnvVariable,
});
const requestMeta = await models.requestMeta.getByParentId(requestId);
const requestMeta = await services.requestMeta.getByParentId(requestId);
if (requestMeta?.activeResponseId) {
const response = await models.response.getById(requestMeta.activeResponseId);
const response = await services.response.getById(requestMeta.activeResponseId);
if (response) {
const settings = await services.settings.getOrCreate();
const activeRequest = await models.request.getById(requestId);
const activeRequest = await services.request.getById(requestId);
if (activeRequest) {
window.main.trackSegmentEvent({

View File

@@ -9,6 +9,10 @@ import type {
McpResponse,
MockRoute,
MockServer,
Request,
RequestMeta,
RequestVersion,
Response,
SocketIOPayload,
SocketIORequest,
SocketIOResponse,
@@ -20,11 +24,6 @@ import type { BaseModel } from '~/models';
import * as models from '~/models';
import * as requestOperations from '~/models/helpers/request-operations';
import { getBodyBuffer } from '~/models/helpers/response-operations';
import { isGraphqlSubscriptionRequest } from '~/models/request';
import { type Request } from '~/models/request';
import { type RequestMeta } from '~/models/request-meta';
import type { RequestVersion } from '~/models/request-version';
import type { Response } from '~/models/response';
import { showResourceNotFoundToast } from '~/ui/components/toast-notification';
import type { Route } from './+types/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId';
@@ -70,15 +69,19 @@ export interface RequestLoaderData {
mockServerAndRoutes: (MockServer & { routes: MockRoute[] })[];
}
const getResponseModelName = (request: Request | WebSocketRequest | SocketIORequest | GrpcRequest) => {
const { isGraphqlSubscriptionRequest } = models.request;
const getResponseOperations = (request: Request | WebSocketRequest | SocketIORequest | GrpcRequest) => {
const isGraphqlWsRequest = isGraphqlSubscriptionRequest(request);
if (models.webSocketRequest.isWebSocketRequest(request) || isGraphqlWsRequest) {
return 'webSocketResponse' as const;
return services.webSocketResponse;
}
if (models.socketIORequest.isSocketIORequest(request)) {
return 'socketIOResponse' as const;
return services.socketIOResponse;
}
return 'response' as const;
return services.response;
};
export async function clientLoader({ params }: Route.ClientLoaderArgs) {
@@ -122,7 +125,7 @@ export async function clientLoader({ params }: Route.ClientLoaderArgs) {
requestVersions: [],
} as GrpcRequestLoaderData;
}
const activeRequestMeta = await models.requestMeta.updateOrCreateByParentId(requestId, { lastActive: Date.now() });
const activeRequestMeta = await services.requestMeta.updateOrCreateByParentId(requestId, { lastActive: Date.now() });
const { filterResponsesByEnv } = await services.settings.get();
const isGraphqlWsRequest = isGraphqlSubscriptionRequest(activeRequest);
@@ -145,22 +148,16 @@ export async function clientLoader({ params }: Route.ClientLoaderArgs) {
activeResponse: activeResponse || null,
requestPayload,
responses,
requestVersions: await models.requestVersion.findByParentId(requestId),
requestVersions: await services.requestVersion.findByParentId(requestId),
} as McpRequestLoaderData;
}
const responseModelName = getResponseModelName(activeRequest);
const responseService =
responseModelName === 'webSocketResponse'
? services.webSocketResponse
: responseModelName === 'socketIOResponse'
? services.socketIOResponse
: models.response;
const responseOperations = getResponseOperations(activeRequest);
const activeResponse = activeRequestMeta.activeResponseId
? await responseService.getById(activeRequestMeta.activeResponseId)
: await responseService.getLatestForRequestId(requestId, activeWorkspaceMeta.activeEnvironmentId);
const allResponses = (await responseService.findByParentId(requestId)) as (
? await responseOperations.getById(activeRequestMeta.activeResponseId)
: await responseOperations.getLatestForRequestId(requestId, activeWorkspaceMeta.activeEnvironmentId);
const allResponses = (await responseOperations.findByParentId(requestId)) as (
| Response
| WebSocketResponse
| SocketIOResponse
@@ -211,7 +208,7 @@ export async function clientLoader({ params }: Route.ClientLoaderArgs) {
activeRequestMeta,
activeResponse,
responses,
requestVersions: await models.requestVersion.findByParentId(requestId),
requestVersions: await services.requestVersion.findByParentId(requestId),
mockServerAndRoutes,
requestPayload: socketIOPayload,
} as SocketIORequestLoaderData;
@@ -222,7 +219,7 @@ export async function clientLoader({ params }: Route.ClientLoaderArgs) {
activeRequestMeta,
activeResponse,
responses,
requestVersions: await models.requestVersion.findByParentId(requestId),
requestVersions: await services.requestVersion.findByParentId(requestId),
mockServerAndRoutes,
} as RequestLoaderData | WebSocketRequestLoaderData;
}

View File

@@ -1,9 +1,8 @@
import { href } from 'react-router';
import type { GrpcRequestMeta } from '~/insomnia-data';
import type { GrpcRequestMeta, RequestMeta } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import * as models from '~/models';
import type { RequestMeta } from '~/models/request-meta';
import { invariant } from '~/utils/invariant';
import { createFetcherSubmitHook } from '~/utils/router';
@@ -17,7 +16,7 @@ export async function clientAction({ params, request }: Route.ClientActionArgs)
await services.grpcRequestMeta.updateOrCreateByParentId(requestId, patch);
return null;
}
await models.requestMeta.updateOrCreateByParentId(requestId, patch);
await services.requestMeta.updateOrCreateByParentId(requestId, patch);
return null;
}

View File

@@ -3,7 +3,6 @@ import { href } from 'react-router';
import type { WebSocketRequest } from '~/insomnia-data';
import { models } from '~/insomnia-data';
import * as requestOperations from '~/models/helpers/request-operations';
import { getPathParametersFromUrl, isRequest } from '~/models/request';
import { SegmentEvent } from '~/ui/analytics';
import { updateMimeType } from '~/ui/components/dropdowns/content-type-dropdown';
import { invariant } from '~/utils/invariant';
@@ -11,6 +10,8 @@ import { createFetcherSubmitHook } from '~/utils/router';
import type { Route } from './+types/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId.update';
const { getPathParametersFromUrl, isRequest } = models.request;
export async function clientAction({ params, request }: Route.ClientActionArgs) {
const { requestId } = params;

View File

@@ -1,8 +1,7 @@
import { href } from 'react-router';
import type { Request } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import * as models from '~/models';
import type { Request } from '~/models/request';
import {
fetchRequestData,
responseTransform,
@@ -23,10 +22,10 @@ export async function clientAction({ request }: Route.ClientActionArgs) {
const mockRoute = await services.mockRoute.getById(patch.parentId);
invariant(mockRoute, 'mock route not found');
// Get or create a testing request for this mock route
const childRequests = await models.request.findByParentId(mockRoute._id);
const testRequest = childRequests[0] || (await models.request.create({ parentId: mockRoute._id, isPrivate: true }));
const childRequests = await services.request.findByParentId(mockRoute._id);
const testRequest = childRequests[0] || (await services.request.create({ parentId: mockRoute._id, isPrivate: true }));
invariant(testRequest, 'mock route is missing a testing request');
const req = await models.request.update(testRequest, patch);
const req = await services.request.update(testRequest, patch);
const { environment, settings, clientCertificates, caCert, activeEnvironmentId, timelinePath, responseId } =
await fetchRequestData(req._id);
@@ -55,7 +54,7 @@ export async function clientAction({ request }: Route.ClientActionArgs) {
);
const response = await responseTransform(res, activeEnvironmentId, renderedRequest, renderResult.context);
await models.response.create(response);
await services.response.create(response);
window.main.completeExecutionStep({ requestId: req._id });
return null;
}

Some files were not shown because too many files have changed in this diff Show More