Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Insomnia Format v5 #8209

Draft
wants to merge 12 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion packages/insomnia/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"scripts": {
"build": "npm run build:app",
"build:app": "esr --cache ./scripts/build.ts --noErrorTruncation",
"generate:schema": "esr ./src/schema.ts",
"build:main.min.js": "cross-env NODE_ENV=development esr esbuild.main.ts",
"lint": "eslint . --ext .js,.ts,.tsx --cache",
"package": "npm run build:app && cross-env USE_HARD_LINKS=false electron-builder build --config electron-builder.config.js",
Expand Down Expand Up @@ -82,7 +83,8 @@
"tough-cookie": "^4.1.3",
"uuid": "^9.0.1",
"yaml": "^1.6.0",
"yaml-source-map": "^2.1.1"
"yaml-source-map": "^2.1.1",
"zod": "^3.23.8"
},
"devDependencies": {
"@develohpanda/fluent-builder": "^2.1.2",
Expand Down
159 changes: 39 additions & 120 deletions packages/insomnia/src/common/export.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import { showAlert, showError, showModal } from '../ui/components/modals';
import { AskModal } from '../ui/components/modals/ask-modal';
import { SelectModal } from '../ui/components/modals/select-modal';
import type { Insomnia4Data } from '../utils/importers/importers';
import { invariant } from '../utils/invariant';
import {
EXPORT_TYPE_API_SPEC,
EXPORT_TYPE_COOKIE_JAR,
Expand All @@ -46,6 +45,7 @@ import {
} from './constants';
import { database, database as db } from './database';
import * as har from './har';
import { getInsomniaV5DataExport } from './insomnia-v5';
import { strings } from './strings';

const EXPORT_FORMAT = 4;
Expand Down Expand Up @@ -293,11 +293,7 @@ const showSelectExportTypeModal = ({ onDone }: {
}) => {
const options = [
{
name: 'Insomnia v4 (JSON)',
value: VALUE_JSON,
},
{
name: 'Insomnia v4 (YAML)',
name: 'Insomnia v5',
value: VALUE_YAML,
},
{
Expand Down Expand Up @@ -434,122 +430,49 @@ export const exportProjectToFile = (activeProjectName: string, workspacesForActi
},
});
};
const exportMockServer = async (workspace: Workspace, selectedFormat: 'json' | 'yaml') => {
const data: Insomnia4Data = {
_type: 'export',
__export_format: EXPORT_FORMAT,
__export_date: new Date(),
__export_source: `insomnia.desktop.app:v${getAppVersion()}`,
resources: [],
};
const mockServer = await models.mockServer.getByParentId(workspace._id);
invariant(mockServer, 'expected mock server to be defined');
const mockRoutes = await models.mockRoute.findByParentId(mockServer._id);

// unclear why we need a _type here, or if they should match prefix or not
data.resources.push({ ...workspace, _type: 'workspace' });
data.resources.push({ ...mockServer, _type: 'mock' });
mockRoutes.map(mockRoute => data.resources.push({ ...mockRoute, _type: 'mock_route' }));
if (selectedFormat === 'yaml') {
return YAML.stringify(data);
}
return JSON.stringify(data);
};

export const exportMockServerToFile = async (workspace: Workspace) => {
const options = [{ name: 'Insomnia v4 (JSON)', value: VALUE_JSON }, { name: 'Insomnia v4 (YAML)', value: VALUE_YAML }];
const lastFormat = window.localStorage.getItem('insomnia.lastExportFormat');
const defaultValue = options.find(({ value }) => value === lastFormat) ? lastFormat : VALUE_JSON;

showModal(SelectModal, {
title: 'Select Export Type',
value: defaultValue,
options,
message: 'Which format would you like to export as?',
onDone: async selectedFormat => {
invariant(selectedFormat, 'expected selected format to be defined');
invariant(selectedFormat === 'json' || selectedFormat === 'yaml', 'unexpected selected format');
window.localStorage.setItem('insomnia.lastExportFormat', selectedFormat);
const fileName = await showSaveExportedFileDialog({
exportedFileNamePrefix: workspace.name,
selectedFormat,
});
if (!fileName) {
return;
}
try {
const stringifiedExport = await exportMockServer(workspace, selectedFormat);
writeExportedFileToFileSystem(fileName, stringifiedExport, err => err && console.warn('Export failed', err));
window.main.trackSegmentEvent({ event: SegmentEvent.dataExport, properties: { type: selectedFormat, scope: 'mock-server' } });
} catch (err) {
showError({
title: 'Export Failed',
error: err,
message: 'Export failed due to an unexpected error',
});
return;
}
},
const fileName = await showSaveExportedFileDialog({
exportedFileNamePrefix: workspace.name,
selectedFormat: 'yaml',
});
};

const exportGlobalEnvironment = async (workspace: Workspace, selectedFormat: 'json' | 'yaml') => {
const data: Insomnia4Data = {
_type: 'export',
__export_format: EXPORT_FORMAT,
__export_date: new Date(),
__export_source: `insomnia.desktop.app:v${getAppVersion()}`,
resources: [],
};

const baseEnvironment = await models.environment.getOrCreateForParentId(workspace._id);
const subEnvironments = await models.environment.findByParentId(baseEnvironment._id);

data.resources.push({ ...workspace, _type: 'workspace' });
data.resources.push({ ...baseEnvironment, _type: 'environment' });
subEnvironments.map(environment => data.resources.push({ ...environment, _type: 'environment' }));

if (selectedFormat === 'yaml') {
return YAML.stringify(data);
if (!fileName) {
return;
}
try {
const stringifiedExport = await getInsomniaV5DataExport(workspace._id);
writeExportedFileToFileSystem(fileName, stringifiedExport, err => err && console.warn('Export failed', err));
window.main.trackSegmentEvent({ event: SegmentEvent.dataExport, properties: { type: 'yaml', scope: 'mock-server' } });
} catch (err) {
showError({
title: 'Export Failed',
error: err,
message: 'Export failed due to an unexpected error',
});
return;
}
return JSON.stringify(data);
};

export const exportGlobalEnvironmentToFile = async (workspace: Workspace) => {
const options = [{ name: 'Insomnia v4 (JSON)', value: VALUE_JSON }, { name: 'Insomnia v4 (YAML)', value: VALUE_YAML }];
const lastFormat = window.localStorage.getItem('insomnia.lastExportFormat');
const defaultValue = options.find(({ value }) => value === lastFormat) ? lastFormat : VALUE_JSON;

showModal(SelectModal, {
title: 'Select Export Type',
value: defaultValue,
options,
message: 'Which format would you like to export as?',
onDone: async selectedFormat => {
invariant(selectedFormat, 'expected selected format to be defined');
invariant(selectedFormat === 'json' || selectedFormat === 'yaml', 'unexpected selected format');
window.localStorage.setItem('insomnia.lastExportFormat', selectedFormat);
const fileName = await showSaveExportedFileDialog({
exportedFileNamePrefix: workspace.name,
selectedFormat,
});
if (!fileName) {
return;
}
try {
const stringifiedExport = await exportGlobalEnvironment(workspace, selectedFormat);
writeExportedFileToFileSystem(fileName, stringifiedExport, err => err && console.warn('Export failed', err));
window.main.trackSegmentEvent({ event: SegmentEvent.dataExport, properties: { type: selectedFormat, scope: 'environment' } });
} catch (err) {
showError({
title: 'Export Failed',
error: err,
message: 'Export failed due to an unexpected error',
});
return;
}
},
const fileName = await showSaveExportedFileDialog({
exportedFileNamePrefix: workspace.name,
selectedFormat: 'yaml',
});
if (!fileName) {
return;
}
try {
const stringifiedExport = await getInsomniaV5DataExport(workspace._id);
writeExportedFileToFileSystem(fileName, stringifiedExport, err => err && console.warn('Export failed', err));
window.main.trackSegmentEvent({ event: SegmentEvent.dataExport, properties: { type: 'yaml', scope: 'environment' } });
} catch (err) {
showError({
title: 'Export Failed',
error: err,
message: 'Export failed due to an unexpected error',
});
return;
}
};

export const exportRequestsToFile = (workspaceId: string, requestIds: string[]) => {
Expand Down Expand Up @@ -583,7 +506,7 @@ export const exportRequestsToFile = (workspaceId: string, requestIds: string[])
return;
}

let stringifiedExport;
let stringifiedExport = '';

try {
switch (selectedFormat) {
Expand All @@ -592,11 +515,7 @@ export const exportRequestsToFile = (workspaceId: string, requestIds: string[])
break;

case VALUE_YAML:
stringifiedExport = await exportRequestsData(requests, shouldExportPrivateEnvironments, 'yaml');
break;

case VALUE_JSON:
stringifiedExport = await exportRequestsData(requests, shouldExportPrivateEnvironments, 'json');
stringifiedExport = await getInsomniaV5DataExport(workspaceId);
break;

default:
Expand Down
18 changes: 17 additions & 1 deletion packages/insomnia/src/common/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { convert, type InsomniaImporter } from '../utils/importers/convert';
import { id as postmanEnvImporterId } from '../utils/importers/importers/postman-env';
import { invariant } from '../utils/invariant';
import { database as db } from './database';
import { importInsomniaV5Data } from './insomnia-v5';
import { generateId } from './misc';

export interface ExportedModel extends BaseModel {
Expand Down Expand Up @@ -125,7 +126,22 @@ export async function scanResources(contentList: string[] | ImportFileDetail[]):
let result: ConvertResult | null = null;

try {
result = (await convert(contentStr)) as unknown as ConvertResult;
const insomnia5Import = importInsomniaV5Data(contentStr);
if (insomnia5Import.length > 0) {
result = {
type: {
id: 'insomnia-5',
name: 'Insomnia v5',
description: 'Insomnia v5',
},
data: {
// @ts-expect-error -- TSCONVERSION
resources: insomnia5Import,
},
};
} else {
result = (await convert(contentStr)) as unknown as ConvertResult;
}
} catch (err: unknown) {
if (err instanceof Error) {
return {
Expand Down
Loading
Loading