Skip to content
This repository was archived by the owner on May 29, 2025. It is now read-only.

Commit 8c0f889

Browse files
authored
Insomnia v5 importer (#7)
Add support for the new Insomnia 5 export format
1 parent 20b0b4f commit 8c0f889

10 files changed

Lines changed: 853 additions & 273 deletions

File tree

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@
1919
"workspaces-run": "^1.0.2"
2020
},
2121
"dependencies": {
22-
"@yaakapp/api": "^0.5.1"
22+
"@yaakapp/api": "^0.5.3"
2323
}
2424
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
2+
export function convertSyntax(variable: string): string {
3+
if (!isJSString(variable)) return variable;
4+
return variable.replaceAll(/{{\s*(_\.)?([^}]+)\s*}}/g, '${[$2]}');
5+
}
6+
7+
export function isJSObject(obj: any) {
8+
return Object.prototype.toString.call(obj) === '[object Object]';
9+
}
10+
11+
export function isJSString(obj: any) {
12+
return Object.prototype.toString.call(obj) === '[object String]';
13+
}
14+
15+
export function convertId(id: string): string {
16+
if (id.startsWith('GENERATE_ID::')) {
17+
return id;
18+
}
19+
return `GENERATE_ID::${id}`;
20+
}
21+
22+
export function deleteUndefinedAttrs<T>(obj: T): T {
23+
if (Array.isArray(obj) && obj != null) {
24+
return obj.map(deleteUndefinedAttrs) as T;
25+
} else if (typeof obj === 'object' && obj != null) {
26+
return Object.fromEntries(
27+
Object.entries(obj)
28+
.filter(([, v]) => v !== undefined)
29+
.map(([k, v]) => [k, deleteUndefinedAttrs(v)]),
30+
) as T;
31+
} else {
32+
return obj;
33+
}
34+
}
Lines changed: 9 additions & 265 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,15 @@
1-
import { Context, Environment, Folder, GrpcRequest, HttpRequest, PluginDefinition, Workspace } from '@yaakapp/api';
1+
import { Context, PluginDefinition } from '@yaakapp/api';
22
import YAML from 'yaml';
3-
4-
type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
5-
6-
export interface ExportResources {
7-
workspaces: AtLeast<Workspace, 'name' | 'id' | 'model'>[];
8-
environments: AtLeast<Environment, 'name' | 'id' | 'model' | 'workspaceId'>[];
9-
httpRequests: AtLeast<HttpRequest, 'name' | 'id' | 'model' | 'workspaceId'>[];
10-
grpcRequests: AtLeast<GrpcRequest, 'name' | 'id' | 'model' | 'workspaceId'>[];
11-
folders: AtLeast<Folder, 'name' | 'id' | 'model' | 'workspaceId'>[];
12-
}
3+
import { deleteUndefinedAttrs, isJSObject } from './common';
4+
import { convertInsomniaV4 } from './v4';
5+
import { convertInsomniaV5 } from './v5';
136

147
export const plugin: PluginDefinition = {
158
importer: {
169
name: 'Insomnia',
1710
description: 'Import Insomnia workspaces',
18-
onImport(_ctx: Context, args: { text: string }) {
19-
return convertInsomnia(args.text) as any;
11+
async onImport(_ctx: Context, args: { text: string }) {
12+
return convertInsomnia(args.text);
2013
},
2114
},
2215
};
@@ -34,258 +27,9 @@ export function convertInsomnia(contents: string) {
3427
} catch (e) {
3528
}
3629

37-
if (!isJSObject(parsed)) return;
38-
if (!Array.isArray(parsed.resources)) return;
39-
40-
const resources: ExportResources = {
41-
workspaces: [],
42-
httpRequests: [],
43-
grpcRequests: [],
44-
environments: [],
45-
folders: [],
46-
};
47-
48-
// Import workspaces
49-
const workspacesToImport = parsed.resources.filter(isWorkspace);
50-
for (const w of workspacesToImport) {
51-
resources.workspaces.push({
52-
id: convertId(w._id),
53-
createdAt: w.created ? new Date(w.created).toISOString().replace('Z', '') : undefined,
54-
updatedAt: w.updated ? new Date(w.updated).toISOString().replace('Z', '') : undefined,
55-
model: 'workspace',
56-
name: w.name,
57-
description: w.description || undefined,
58-
});
59-
const environmentsToImport = parsed.resources.filter(
60-
(r: any) => isEnvironment(r),
61-
);
62-
resources.environments.push(
63-
...environmentsToImport.map((r: any) => importEnvironment(r, w._id)),
64-
);
65-
66-
const nextFolder = (parentId: string) => {
67-
const children = parsed.resources.filter((r: any) => r.parentId === parentId);
68-
let sortPriority = 0;
69-
for (const child of children) {
70-
if (isRequestGroup(child)) {
71-
resources.folders.push(importFolder(child, w._id));
72-
nextFolder(child._id);
73-
} else if (isHttpRequest(child)) {
74-
resources.httpRequests.push(
75-
importHttpRequest(child, w._id, sortPriority++),
76-
);
77-
} else if (isGrpcRequest(child)) {
78-
resources.grpcRequests.push(
79-
importGrpcRequest(child, w._id, sortPriority++),
80-
);
81-
}
82-
}
83-
};
84-
85-
// Import folders
86-
nextFolder(w._id);
87-
}
88-
89-
// Filter out any `null` values
90-
resources.httpRequests = resources.httpRequests.filter(Boolean);
91-
resources.grpcRequests = resources.grpcRequests.filter(Boolean);
92-
resources.environments = resources.environments.filter(Boolean);
93-
resources.workspaces = resources.workspaces.filter(Boolean);
94-
95-
return { resources: deleteUndefinedAttrs(resources) };
96-
}
97-
98-
function importEnvironment(e: any, workspaceId: string): ExportResources['environments'][0] {
99-
return {
100-
id: convertId(e._id),
101-
createdAt: e.created ? new Date(e.created).toISOString().replace('Z', '') : undefined,
102-
updatedAt: e.updated ? new Date(e.updated).toISOString().replace('Z', '') : undefined,
103-
workspaceId: convertId(workspaceId),
104-
base: e.parentId === workspaceId,
105-
model: 'environment',
106-
name: e.name,
107-
variables: Object.entries(e.data).map(([name, value]) => ({
108-
enabled: true,
109-
name,
110-
value: `${value}`,
111-
})),
112-
};
113-
}
114-
115-
function importFolder(f: any, workspaceId: string): ExportResources['folders'][0] {
116-
return {
117-
id: convertId(f._id),
118-
createdAt: f.created ? new Date(f.created).toISOString().replace('Z', '') : undefined,
119-
updatedAt: f.updated ? new Date(f.updated).toISOString().replace('Z', '') : undefined,
120-
folderId: f.parentId === workspaceId ? null : convertId(f.parentId),
121-
workspaceId: convertId(workspaceId),
122-
description: f.description || undefined,
123-
model: 'folder',
124-
name: f.name,
125-
};
126-
}
127-
128-
function importGrpcRequest(
129-
r: any,
130-
workspaceId: string,
131-
sortPriority = 0,
132-
): ExportResources['grpcRequests'][0] {
133-
const parts = r.protoMethodName.split('/').filter((p: any) => p !== '');
134-
const service = parts[0] ?? null;
135-
const method = parts[1] ?? null;
30+
if (!isJSObject(parsed)) return null;
13631

137-
return {
138-
id: convertId(r._id),
139-
createdAt: r.created ? new Date(r.created).toISOString().replace('Z', '') : undefined,
140-
updatedAt: r.updated ? new Date(r.updated).toISOString().replace('Z', '') : undefined,
141-
workspaceId: convertId(workspaceId),
142-
folderId: r.parentId === workspaceId ? null : convertId(r.parentId),
143-
model: 'grpc_request',
144-
sortPriority,
145-
name: r.name,
146-
description: r.description || undefined,
147-
url: convertSyntax(r.url),
148-
service,
149-
method,
150-
message: r.body?.text ?? '',
151-
metadata: (r.metadata ?? [])
152-
.map((h: any) => ({
153-
enabled: !h.disabled,
154-
name: h.name ?? '',
155-
value: h.value ?? '',
156-
}))
157-
.filter(({ name, value }: any) => name !== '' || value !== ''),
158-
};
159-
}
32+
const result = convertInsomniaV5(parsed) ?? convertInsomniaV4(parsed);
16033

161-
function importHttpRequest(
162-
r: any,
163-
workspaceId: string,
164-
sortPriority = 0,
165-
): ExportResources['httpRequests'][0] {
166-
let bodyType: string | null = null;
167-
let body = {};
168-
if (r.body.mimeType === 'application/octet-stream') {
169-
bodyType = 'binary';
170-
body = { filePath: r.body.fileName ?? '' };
171-
} else if (r.body?.mimeType === 'application/x-www-form-urlencoded') {
172-
bodyType = 'application/x-www-form-urlencoded';
173-
body = {
174-
form: (r.body.params ?? []).map((p: any) => ({
175-
enabled: !p.disabled,
176-
name: p.name ?? '',
177-
value: p.value ?? '',
178-
})),
179-
};
180-
} else if (r.body?.mimeType === 'multipart/form-data') {
181-
bodyType = 'multipart/form-data';
182-
body = {
183-
form: (r.body.params ?? []).map((p: any) => ({
184-
enabled: !p.disabled,
185-
name: p.name ?? '',
186-
value: p.value ?? '',
187-
file: p.fileName ?? null,
188-
})),
189-
};
190-
} else if (r.body?.mimeType === 'application/graphql') {
191-
bodyType = 'graphql';
192-
body = { text: convertSyntax(r.body.text ?? '') };
193-
} else if (r.body?.mimeType === 'application/json') {
194-
bodyType = 'application/json';
195-
body = { text: convertSyntax(r.body.text ?? '') };
196-
}
197-
198-
let authenticationType: string | null = null;
199-
let authentication = {};
200-
if (r.authentication.type === 'bearer') {
201-
authenticationType = 'bearer';
202-
authentication = {
203-
token: convertSyntax(r.authentication.token),
204-
};
205-
} else if (r.authentication.type === 'basic') {
206-
authenticationType = 'basic';
207-
authentication = {
208-
username: convertSyntax(r.authentication.username),
209-
password: convertSyntax(r.authentication.password),
210-
};
211-
}
212-
213-
return {
214-
id: convertId(r._id),
215-
createdAt: r.created ? new Date(r.created).toISOString().replace('Z', '') : undefined,
216-
updatedAt: r.updated ? new Date(r.updated).toISOString().replace('Z', '') : undefined,
217-
workspaceId: convertId(workspaceId),
218-
folderId: r.parentId === workspaceId ? null : convertId(r.parentId),
219-
model: 'http_request',
220-
sortPriority,
221-
name: r.name,
222-
description: r.description || undefined,
223-
url: convertSyntax(r.url),
224-
body,
225-
bodyType,
226-
authentication,
227-
authenticationType,
228-
method: r.method,
229-
headers: (r.headers ?? [])
230-
.map((h: any) => ({
231-
enabled: !h.disabled,
232-
name: h.name ?? '',
233-
value: h.value ?? '',
234-
}))
235-
.filter(({ name, value }: any) => name !== '' || value !== ''),
236-
};
237-
}
238-
239-
function convertSyntax(variable: string): string {
240-
if (!isJSString(variable)) return variable;
241-
return variable.replaceAll(/{{\s*(_\.)?([^}]+)\s*}}/g, '${[$2]}');
242-
}
243-
244-
function isWorkspace(obj: any) {
245-
return isJSObject(obj) && obj._type === 'workspace';
246-
}
247-
248-
function isRequestGroup(obj: any) {
249-
return isJSObject(obj) && obj._type === 'request_group';
250-
}
251-
252-
function isHttpRequest(obj: any) {
253-
return isJSObject(obj) && obj._type === 'request';
254-
}
255-
256-
function isGrpcRequest(obj: any) {
257-
return isJSObject(obj) && obj._type === 'grpc_request';
258-
}
259-
260-
function isEnvironment(obj: any) {
261-
return isJSObject(obj) && obj._type === 'environment';
262-
}
263-
264-
function isJSObject(obj: any) {
265-
return Object.prototype.toString.call(obj) === '[object Object]';
266-
}
267-
268-
function isJSString(obj: any) {
269-
return Object.prototype.toString.call(obj) === '[object String]';
270-
}
271-
272-
function convertId(id: string): string {
273-
if (id.startsWith('GENERATE_ID::')) {
274-
return id;
275-
}
276-
return `GENERATE_ID::${id}`;
277-
}
278-
279-
function deleteUndefinedAttrs<T>(obj: T): T {
280-
if (Array.isArray(obj) && obj != null) {
281-
return obj.map(deleteUndefinedAttrs) as T;
282-
} else if (typeof obj === 'object' && obj != null) {
283-
return Object.fromEntries(
284-
Object.entries(obj)
285-
.filter(([, v]) => v !== undefined)
286-
.map(([k, v]) => [k, deleteUndefinedAttrs(v)]),
287-
) as T;
288-
} else {
289-
return obj;
290-
}
34+
return deleteUndefinedAttrs(result);
29135
}

0 commit comments

Comments
 (0)