Fix postman import and import Insomnia gRPC

This commit is contained in:
Gregory Schier
2024-03-18 08:18:04 -07:00
parent 7e8ec36474
commit 7198534640
12 changed files with 1861 additions and 83 deletions

View File

@@ -6,10 +6,14 @@ export function isRequestGroup(obj) {
return isJSObject(obj) && obj._type === 'request_group'; return isJSObject(obj) && obj._type === 'request_group';
} }
export function isRequest(obj) { export function isHttpRequest(obj) {
return isJSObject(obj) && obj._type === 'request'; return isJSObject(obj) && obj._type === 'request';
} }
export function isGrpcRequest(obj) {
return isJSObject(obj) && obj._type === 'grpc_request';
}
export function isEnvironment(obj) { export function isEnvironment(obj) {
return isJSObject(obj) && obj._type === 'environment'; return isJSObject(obj) && obj._type === 'environment';
} }

View File

@@ -0,0 +1,37 @@
import { convertSyntax } from '../helpers/variables.js';
/**
* Import an Insomnia GRPC request object.
* @param {Object} r - The request object to import.
* @param workspaceId - The workspace ID to use for the request.
* @param {number} sortPriority - The sort priority to use for the request.
*/
export function importGrpcRequest(r, workspaceId, sortPriority = 0) {
console.log('IMPORTING GRPC REQUEST', r._id, r.name, JSON.stringify(r, null, 2));
const parts = r.protoMethodName.split('/').filter((p) => p !== '');
const service = parts[0] ?? null;
const method = parts[1] ?? null;
return {
id: r._id,
createdAt: new Date(r.created ?? Date.now()).toISOString().replace('Z', ''),
updatedAt: new Date(r.updated ?? Date.now()).toISOString().replace('Z', ''),
workspaceId,
folderId: r.parentId === workspaceId ? null : r.parentId,
model: 'grpc_request',
sortPriority,
name: r.name,
url: convertSyntax(r.url),
service,
method,
message: r.body?.text ?? '',
metadata: (r.metadata ?? [])
.map(({ name, value, disabled }) => ({
enabled: !disabled,
name,
value,
}))
.filter(({ name, value }) => name !== '' || value !== ''),
};
}

View File

@@ -6,7 +6,7 @@ import { convertSyntax } from '../helpers/variables.js';
* @param workspaceId - The workspace ID to use for the request. * @param workspaceId - The workspace ID to use for the request.
* @param {number} sortPriority - The sort priority to use for the request. * @param {number} sortPriority - The sort priority to use for the request.
*/ */
export function importRequest(r, workspaceId, sortPriority = 0) { export function importHttpRequest(r, workspaceId, sortPriority = 0) {
console.log('IMPORTING REQUEST', r._id, r.name, JSON.stringify(r, null, 2)); console.log('IMPORTING REQUEST', r._id, r.name, JSON.stringify(r, null, 2));
let bodyType = null; let bodyType = null;

View File

@@ -1,17 +1,18 @@
import { importEnvironment } from './importers/environment.js'; import { importEnvironment } from './importers/environment';
import { importRequest } from './importers/request.js'; import { importHttpRequest } from './importers/httpRequest';
import { import {
isEnvironment, isEnvironment,
isJSObject, isJSObject,
isRequest, isHttpRequest,
isRequestGroup, isRequestGroup,
isWorkspace, isWorkspace,
isGrpcRequest,
} from './helpers/types.js'; } from './helpers/types.js';
import { parseVariables } from './helpers/variables.js'; import { parseVariables } from './helpers/variables.js';
import { importFolder } from './importers/folder.js'; import { importFolder } from './importers/folder.js';
import { importGrpcRequest } from './importers/grpcRequest';
export function pluginHookImport(contents) { export function pluginHookImport(contents) {
console.log('RUNNING INSOMNIA');
let parsed; let parsed;
try { try {
parsed = JSON.parse(contents); parsed = JSON.parse(contents);
@@ -24,7 +25,8 @@ export function pluginHookImport(contents) {
const resources = { const resources = {
workspaces: [], workspaces: [],
requests: [], httpRequests: [],
grpcRequests: [],
environments: [], environments: [],
folders: [], folders: [],
}; };
@@ -57,8 +59,15 @@ export function pluginHookImport(contents) {
if (isRequestGroup(child)) { if (isRequestGroup(child)) {
resources.folders.push(importFolder(child, workspaceToImport._id)); resources.folders.push(importFolder(child, workspaceToImport._id));
nextFolder(child._id); nextFolder(child._id);
} else if (isRequest(child)) { } else if (isHttpRequest(child)) {
resources.requests.push(importRequest(child, workspaceToImport._id, sortPriority++)); resources.httpRequests.push(
importHttpRequest(child, workspaceToImport._id, sortPriority++),
);
} else if (isGrpcRequest(child)) {
console.log('GRPC', JSON.stringify(child, null, 1));
resources.grpcRequests.push(
importGrpcRequest(child, workspaceToImport._id, sortPriority++),
);
} }
} }
}; };
@@ -68,7 +77,8 @@ export function pluginHookImport(contents) {
} }
// Filter out any `null` values // Filter out any `null` values
resources.requests = resources.requests.filter(Boolean); resources.httpRequests = resources.httpRequests.filter(Boolean);
resources.grpcRequests = resources.grpcRequests.filter(Boolean);
resources.environments = resources.environments.filter(Boolean); resources.environments = resources.environments.filter(Boolean);
resources.workspaces = resources.workspaces.filter(Boolean); resources.workspaces = resources.workspaces.filter(Boolean);

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,7 @@
{ {
"name": "importer-postman", "name": "importer-postman",
"version": "0.0.1" "version": "0.0.1",
"devDependencies": {
"vitest": "^1.4.0"
}
} }

View File

@@ -9,7 +9,7 @@ type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
interface ExportResources { interface ExportResources {
workspaces: AtLeast<Workspace, 'name' | 'id' | 'model'>[]; workspaces: AtLeast<Workspace, 'name' | 'id' | 'model'>[];
environments: AtLeast<Environment, 'name' | 'id' | 'model' | 'workspaceId'>[]; environments: AtLeast<Environment, 'name' | 'id' | 'model' | 'workspaceId'>[];
requests: AtLeast<HttpRequest, 'name' | 'id' | 'model' | 'workspaceId'>[]; httpRequests: AtLeast<HttpRequest, 'name' | 'id' | 'model' | 'workspaceId'>[];
folders: AtLeast<Folder, 'name' | 'id' | 'model' | 'workspaceId'>[]; folders: AtLeast<Folder, 'name' | 'id' | 'model' | 'workspaceId'>[];
} }
@@ -26,7 +26,7 @@ export function pluginHookImport(contents: string): { resources: ExportResources
const exportResources: ExportResources = { const exportResources: ExportResources = {
workspaces: [], workspaces: [],
environments: [], environments: [],
requests: [], httpRequests: [],
folders: [], folders: [],
}; };
@@ -55,7 +55,7 @@ export function pluginHookImport(contents: string): { resources: ExportResources
const r = toRecord(v.request); const r = toRecord(v.request);
const bodyPatch = importBody(r.body); const bodyPatch = importBody(r.body);
const authPatch = importAuth(r.auth); const authPatch = importAuth(r.auth);
const request: ExportResources['requests'][0] = { const request: ExportResources['httpRequests'][0] = {
model: 'http_request', model: 'http_request',
id: generateId('rq'), id: generateId('rq'),
workspaceId: workspace.id, workspaceId: workspace.id,
@@ -79,7 +79,7 @@ export function pluginHookImport(contents: string): { resources: ExportResources
}), }),
], ],
}; };
exportResources.requests.push(request); exportResources.httpRequests.push(request);
} else { } else {
console.log('Unknown item', v, folderId); console.log('Unknown item', v, folderId);
} }
@@ -213,7 +213,7 @@ function convertTemplateSyntax<T>(obj: T): T {
} }
} }
function generateId(prefix: 'wk' | 'rq' | 'fl'): string { export function generateId(prefix: 'wk' | 'rq' | 'fl'): string {
const alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; const alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
let id = `${prefix}_`; let id = `${prefix}_`;
for (let i = 0; i < 10; i++) { for (let i = 0; i < 10; i++) {

View File

@@ -0,0 +1,164 @@
{
"info": {
"_postman_id": "9e6dfada-256c-49ea-a38f-7d1b05b7ca2d",
"name": "New Collection",
"schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json",
"_exporter_id": "18798"
},
"item": [
{
"name": "New Folder",
"item": [
{
"name": "FOlder 2",
"item": [
{
"name": "Basic Auth",
"request": {
"auth": {
"type": "basic",
"basic": {
"password": "pass",
"username": "user"
}
},
"method": "GET",
"header": [],
"url": "https://schier.co"
},
"response": []
}
]
},
{
"name": "Form Data",
"request": {
"method": "POST",
"header": [
{
"key": "X-foo",
"value": "bar",
"description": "description",
"type": "text"
},
{
"key": "Disabled",
"value": "tnroant",
"description": "ntisorantosra",
"type": "text",
"disabled": true
}
],
"body": {
"mode": "formdata",
"formdata": [
{
"key": "Form",
"value": "Value",
"description": "descirption",
"type": "text"
},
{
"key": "Disabled",
"value": "foo",
"description": "bar",
"type": "text",
"disabled": true
},
{
"key": "file",
"type": "file",
"src": "/Users/gschier/Desktop/foo.json"
},
{
"key": "Rendered",
"value": "{{Foo}}",
"type": "text"
}
]
},
"url": {
"raw": "schier.co?firstkey=firstvalue&hi=there",
"host": [
"schier",
"co"
],
"query": [
{
"key": "disabled",
"value": "secondvalue",
"description": "this is disabled",
"disabled": true
},
{
"key": "firstkey",
"value": "firstvalue"
},
{
"key": "hi",
"value": "there"
}
]
}
},
"response": []
}
]
},
{
"name": "Form URL",
"request": {
"method": "POST",
"header": [
{
"key": "X-foo",
"value": "bar",
"description": "description",
"type": "text"
},
{
"key": "Disabled",
"value": "tnroant",
"description": "ntisorantosra",
"type": "text",
"disabled": true
}
],
"body": {
"mode": "urlencoded",
"urlencoded": [
{
"key": "foo",
"value": "bar",
"type": "text"
}
]
},
"url": {
"raw": "schier.co?firstkey=firstvalue&hi=there",
"host": [
"schier",
"co"
],
"query": [
{
"key": "disabled",
"value": "secondvalue",
"description": "this is disabled",
"disabled": true
},
{
"key": "firstkey",
"value": "firstvalue"
},
{
"key": "hi",
"value": "there"
}
]
}
},
"response": []
}
]
}

View File

@@ -0,0 +1,35 @@
import * as fs from 'node:fs';
import * as path from 'node:path';
import { expect, test, describe, beforeEach, afterEach, vi } from 'vitest';
import { pluginHookImport } from '../src';
let originalRandom = Math.random;
describe('importer-postman', () => {
beforeEach(() => {
let i = 0;
const mocked = vi.fn(() => ((i++ * 1000) % 133) / 100);
Math.random = mocked;
});
afterEach(() => {
Math.random = originalRandom;
});
const p = path.join(__dirname, 'fixtures');
const fixtures = fs.readdirSync(p);
console.log('FIXTURES', fixtures);
for (const fixture of fixtures) {
test('Imports ' + fixture, () => {
const contents = fs.readFileSync(path.join(p, fixture), 'utf-8');
const imported = pluginHookImport(contents);
expect(imported).toEqual({
resources: {
environments: [],
requests: [],
},
});
});
}
});

View File

@@ -1,27 +1,30 @@
function S(e, t) { function g(e, n) {
return console.log("IMPORTING Environment", e._id, e.name, JSON.stringify(e, null, 2)), { return console.log("IMPORTING Environment", e._id, e.name, JSON.stringify(e, null, 2)), {
id: e._id, id: e._id,
createdAt: new Date(e.created ?? Date.now()).toISOString().replace("Z", ""), createdAt: new Date(e.created ?? Date.now()).toISOString().replace("Z", ""),
updatedAt: new Date(e.updated ?? Date.now()).toISOString().replace("Z", ""), updatedAt: new Date(e.updated ?? Date.now()).toISOString().replace("Z", ""),
workspaceId: t, workspaceId: n,
model: "environment", model: "environment",
name: e.name, name: e.name,
variables: Object.entries(e.data).map(([n, a]) => ({ variables: Object.entries(e.data).map(([t, a]) => ({
enabled: !0, enabled: !0,
name: n, name: t,
value: `${a}` value: `${a}`
})) }))
}; };
} }
function I(e) { function S(e) {
return m(e) && e._type === "workspace"; return m(e) && e._type === "workspace";
} }
function y(e) { function I(e) {
return m(e) && e._type === "request_group"; return m(e) && e._type === "request_group";
} }
function g(e) { function y(e) {
return m(e) && e._type === "request"; return m(e) && e._type === "request";
} }
function h(e) {
return m(e) && e._type === "grpc_request";
}
function f(e) { function f(e) {
return m(e) && e._type === "environment"; return m(e) && e._type === "environment";
} }
@@ -32,103 +35,131 @@ function w(e) {
return Object.prototype.toString.call(e) === "[object String]"; return Object.prototype.toString.call(e) === "[object String]";
} }
function O(e) { function O(e) {
return Object.entries(e).map(([t, n]) => ({ return Object.entries(e).map(([n, t]) => ({
enabled: !0, enabled: !0,
name: t, name: n,
value: `${n}` value: `${t}`
})); }));
} }
function l(e) { function d(e) {
return w(e) ? e.replaceAll(/{{\s*(_\.)?([^}]+)\s*}}/g, "${[$2]}") : e; return w(e) ? e.replaceAll(/{{\s*(_\.)?([^}]+)\s*}}/g, "${[$2]}") : e;
} }
function h(e, t, n = 0) { function _(e, n, t = 0) {
var c, o; var l, r;
console.log("IMPORTING REQUEST", e._id, e.name, JSON.stringify(e, null, 2)); console.log("IMPORTING REQUEST", e._id, e.name, JSON.stringify(e, null, 2));
let a = null, r = null; let a = null, o = null;
((c = e.body) == null ? void 0 : c.mimeType) === "application/graphql" ? (a = "graphql", r = l(e.body.text)) : ((o = e.body) == null ? void 0 : o.mimeType) === "application/json" && (a = "application/json", r = l(e.body.text)); ((l = e.body) == null ? void 0 : l.mimeType) === "application/graphql" ? (a = "graphql", o = d(e.body.text)) : ((r = e.body) == null ? void 0 : r.mimeType) === "application/json" && (a = "application/json", o = d(e.body.text));
let i = null, u = {}; let s = null, p = {};
return e.authentication.type === "bearer" ? (i = "bearer", u = { return e.authentication.type === "bearer" ? (s = "bearer", p = {
token: l(e.authentication.token) token: d(e.authentication.token)
}) : e.authentication.type === "basic" && (i = "basic", u = { }) : e.authentication.type === "basic" && (s = "basic", p = {
username: l(e.authentication.username), username: d(e.authentication.username),
password: l(e.authentication.password) password: d(e.authentication.password)
}), { }), {
id: e._id, id: e._id,
createdAt: new Date(e.created ?? Date.now()).toISOString().replace("Z", ""), createdAt: new Date(e.created ?? Date.now()).toISOString().replace("Z", ""),
updatedAt: new Date(e.updated ?? Date.now()).toISOString().replace("Z", ""), updatedAt: new Date(e.updated ?? Date.now()).toISOString().replace("Z", ""),
workspaceId: t, workspaceId: n,
folderId: e.parentId === t ? null : e.parentId, folderId: e.parentId === n ? null : e.parentId,
model: "http_request", model: "http_request",
sortPriority: n, sortPriority: t,
name: e.name, name: e.name,
url: l(e.url), url: d(e.url),
body: r, body: o,
bodyType: a, bodyType: a,
authentication: u, authentication: p,
authenticationType: i, authenticationType: s,
method: e.method, method: e.method,
headers: (e.headers ?? []).map(({ name: d, value: p, disabled: s }) => ({ headers: (e.headers ?? []).map(({ name: u, value: c, disabled: i }) => ({
enabled: !s, enabled: !i,
name: d, name: u,
value: p value: c
})).filter(({ name: d, value: p }) => d !== "" || p !== "") })).filter(({ name: u, value: c }) => u !== "" || c !== "")
}; };
} }
function _(e, t) { function R(e, n) {
return console.log("IMPORTING FOLDER", e._id, e.name, JSON.stringify(e, null, 2)), { return console.log("IMPORTING FOLDER", e._id, e.name, JSON.stringify(e, null, 2)), {
id: e._id, id: e._id,
createdAt: new Date(e.created ?? Date.now()).toISOString().replace("Z", ""), createdAt: new Date(e.created ?? Date.now()).toISOString().replace("Z", ""),
updatedAt: new Date(e.updated ?? Date.now()).toISOString().replace("Z", ""), updatedAt: new Date(e.updated ?? Date.now()).toISOString().replace("Z", ""),
folderId: e.parentId === t ? null : e.parentId, folderId: e.parentId === n ? null : e.parentId,
workspaceId: t, workspaceId: n,
model: "folder", model: "folder",
name: e.name name: e.name
}; };
} }
function b(e) { function D(e, n, t = 0) {
console.log("RUNNING INSOMNIA"); var p;
let t; console.log("IMPORTING GRPC REQUEST", e._id, e.name, JSON.stringify(e, null, 2));
const a = e.protoMethodName.split("/").filter((l) => l !== ""), o = a[0] ?? null, s = a[1] ?? null;
return {
id: e._id,
createdAt: new Date(e.created ?? Date.now()).toISOString().replace("Z", ""),
updatedAt: new Date(e.updated ?? Date.now()).toISOString().replace("Z", ""),
workspaceId: n,
folderId: e.parentId === n ? null : e.parentId,
model: "grpc_request",
sortPriority: t,
name: e.name,
url: d(e.url),
service: o,
method: s,
message: ((p = e.body) == null ? void 0 : p.text) ?? "",
metadata: (e.metadata ?? []).map(({ name: l, value: r, disabled: u }) => ({
enabled: !u,
name: l,
value: r
})).filter(({ name: l, value: r }) => l !== "" || r !== "")
};
}
function q(e) {
let n;
try { try {
t = JSON.parse(e); n = JSON.parse(e);
} catch { } catch {
return; return;
} }
if (!m(t) || !Array.isArray(t.resources)) if (!m(n) || !Array.isArray(n.resources))
return; return;
const n = { const t = {
workspaces: [], workspaces: [],
requests: [], httpRequests: [],
grpcRequests: [],
environments: [], environments: [],
folders: [] folders: []
}, a = t.resources.filter(I); }, a = n.resources.filter(S);
for (const r of a) { for (const o of a) {
const i = t.resources.find( const s = n.resources.find(
(o) => f(o) && o.parentId === r._id (r) => f(r) && r.parentId === o._id
); );
n.workspaces.push({ t.workspaces.push({
id: r._id, id: o._id,
createdAt: new Date(a.created ?? Date.now()).toISOString().replace("Z", ""), createdAt: new Date(a.created ?? Date.now()).toISOString().replace("Z", ""),
updatedAt: new Date(a.updated ?? Date.now()).toISOString().replace("Z", ""), updatedAt: new Date(a.updated ?? Date.now()).toISOString().replace("Z", ""),
model: "workspace", model: "workspace",
name: r.name, name: o.name,
variables: i ? O(i.data) : [] variables: s ? O(s.data) : []
}); });
const u = t.resources.filter( const p = n.resources.filter(
(o) => f(o) && o.parentId === (i == null ? void 0 : i._id) (r) => f(r) && r.parentId === (s == null ? void 0 : s._id)
); );
n.environments.push( t.environments.push(
...u.map((o) => S(o, r._id)) ...p.map((r) => g(r, o._id))
); );
const c = (o) => { const l = (r) => {
const d = t.resources.filter((s) => s.parentId === o); const u = n.resources.filter((i) => i.parentId === r);
let p = 0; let c = 0;
for (const s of d) for (const i of u)
y(s) ? (n.folders.push(_(s, r._id)), c(s._id)) : g(s) && n.requests.push(h(s, r._id, p++)); I(i) ? (t.folders.push(R(i, o._id)), l(i._id)) : y(i) ? t.httpRequests.push(
_(i, o._id, c++)
) : h(i) && (console.log("GRPC", JSON.stringify(i, null, 1)), t.grpcRequests.push(
D(i, o._id, c++)
));
}; };
c(r._id); l(o._id);
} }
return n.requests = n.requests.filter(Boolean), n.environments = n.environments.filter(Boolean), n.workspaces = n.workspaces.filter(Boolean), { resources: n }; return t.httpRequests = t.httpRequests.filter(Boolean), t.grpcRequests = t.grpcRequests.filter(Boolean), t.environments = t.environments.filter(Boolean), t.workspaces = t.workspaces.filter(Boolean), { resources: t };
} }
export { export {
b as pluginHookImport q as pluginHookImport
}; };

View File

@@ -9,7 +9,7 @@ function q(e) {
const i = { const i = {
workspaces: [], workspaces: [],
environments: [], environments: [],
requests: [], httpRequests: [],
folders: [] folders: []
}, c = { }, c = {
model: "workspace", model: "workspace",
@@ -53,7 +53,7 @@ function q(e) {
})) }))
] ]
}; };
i.requests.push(g); i.httpRequests.push(g);
} else } else
console.log("Unknown item", r, u); console.log("Unknown item", r, u);
}; };
@@ -156,5 +156,6 @@ function m(e) {
return n; return n;
} }
export { export {
m as generateId,
q as pluginHookImport q as pluginHookImport
}; };

View File

@@ -8,7 +8,7 @@
}, },
"package": { "package": {
"productName": "Yaak", "productName": "Yaak",
"version": "2024.3.6" "version": "2024.3.7"
}, },
"tauri": { "tauri": {
"windows": [], "windows": [],