123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- import { convert, ImportRequest } from "insomnia-importers"
- import { pipe, flow } from "fp-ts/function"
- import {
- HoppRESTAuth,
- HoppRESTHeader,
- HoppRESTParam,
- HoppRESTReqBody,
- HoppRESTRequest,
- knownContentTypes,
- makeRESTRequest,
- HoppCollection,
- makeCollection,
- } from "@hoppscotch/data"
- import * as A from "fp-ts/Array"
- import * as S from "fp-ts/string"
- import * as TO from "fp-ts/TaskOption"
- import * as TE from "fp-ts/TaskEither"
- import { step } from "../steps"
- import { defineImporter, IMPORTER_INVALID_FILE_FORMAT } from "."
- // TODO: Insomnia allows custom prefixes for Bearer token auth, Hoppscotch doesn't. We just ignore the prefix for now
- type UnwrapPromise<T extends Promise<any>> = T extends Promise<infer Y>
- ? Y
- : never
- type InsomniaDoc = UnwrapPromise<ReturnType<typeof convert>>
- type InsomniaResource = ImportRequest
- type InsomniaFolderResource = ImportRequest & { _type: "request_group" }
- type InsomniaRequestResource = ImportRequest & { _type: "request" }
- const parseInsomniaDoc = (content: string) =>
- TO.tryCatch(() => convert(content))
- const replaceVarTemplating = flow(
- S.replace(/{{\s*/g, "<<"),
- S.replace(/\s*}}/g, ">>")
- )
- const getFoldersIn = (
- folder: InsomniaFolderResource | null,
- resources: InsomniaResource[]
- ) =>
- pipe(
- resources,
- A.filter(
- (x): x is InsomniaFolderResource =>
- (x._type === "request_group" || x._type === "workspace") &&
- x.parentId === (folder?._id ?? null)
- )
- )
- const getRequestsIn = (
- folder: InsomniaFolderResource | null,
- resources: InsomniaResource[]
- ) =>
- pipe(
- resources,
- A.filter(
- (x): x is InsomniaRequestResource =>
- x._type === "request" && x.parentId === (folder?._id ?? null)
- )
- )
- /**
- * The provided type by insomnia-importers, this type corrects it
- */
- type InsoReqAuth =
- | { type: "basic"; disabled?: boolean; username?: string; password?: string }
- | {
- type: "oauth2"
- disabled?: boolean
- accessTokenUrl?: string
- authorizationUrl?: string
- clientId?: string
- scope?: string
- }
- | {
- type: "bearer"
- disabled?: boolean
- token?: string
- }
- const getHoppReqAuth = (req: InsomniaRequestResource): HoppRESTAuth => {
- if (!req.authentication) return { authType: "none", authActive: true }
- const auth = req.authentication as InsoReqAuth
- if (auth.type === "basic")
- return {
- authType: "basic",
- authActive: true,
- username: replaceVarTemplating(auth.username ?? ""),
- password: replaceVarTemplating(auth.password ?? ""),
- }
- else if (auth.type === "oauth2")
- return {
- authType: "oauth-2",
- authActive: !(auth.disabled ?? false),
- accessTokenURL: replaceVarTemplating(auth.accessTokenUrl ?? ""),
- authURL: replaceVarTemplating(auth.authorizationUrl ?? ""),
- clientID: replaceVarTemplating(auth.clientId ?? ""),
- oidcDiscoveryURL: "",
- scope: replaceVarTemplating(auth.scope ?? ""),
- token: "",
- }
- else if (auth.type === "bearer")
- return {
- authType: "bearer",
- authActive: true,
- token: replaceVarTemplating(auth.token ?? ""),
- }
- return { authType: "none", authActive: true }
- }
- const getHoppReqBody = (req: InsomniaRequestResource): HoppRESTReqBody => {
- if (!req.body) return { contentType: null, body: null }
- if (typeof req.body === "string") {
- const contentType =
- req.headers?.find(
- (header) => header.name.toLowerCase() === "content-type"
- )?.value ?? "text/plain"
- return { contentType, body: replaceVarTemplating(req.body) }
- }
- if (req.body.mimeType === "multipart/form-data") {
- return {
- contentType: "multipart/form-data",
- body:
- req.body.params?.map((param) => ({
- key: replaceVarTemplating(param.name),
- value: replaceVarTemplating(param.value ?? ""),
- active: !(param.disabled ?? false),
- isFile: false,
- })) ?? [],
- }
- } else if (req.body.mimeType === "application/x-www-form-urlencoded") {
- return {
- contentType: "application/x-www-form-urlencoded",
- body:
- req.body.params
- ?.filter((param) => !(param.disabled ?? false))
- .map(
- (param) =>
- `${replaceVarTemplating(param.name)}: ${replaceVarTemplating(
- param.value ?? ""
- )}`
- )
- .join("\n") ?? "",
- }
- } else if (
- Object.keys(knownContentTypes).includes(req.body.mimeType ?? "text/plain")
- ) {
- return {
- contentType: (req.body.mimeType ?? "text/plain") as any,
- body: replaceVarTemplating(req.body.text ?? "") as any,
- }
- }
- return { contentType: null, body: null }
- }
- const getHoppReqHeaders = (req: InsomniaRequestResource): HoppRESTHeader[] =>
- req.headers?.map((header) => ({
- key: replaceVarTemplating(header.name),
- value: replaceVarTemplating(header.value),
- active: !header.disabled,
- })) ?? []
- const getHoppReqParams = (req: InsomniaRequestResource): HoppRESTParam[] =>
- req.parameters?.map((param) => ({
- key: replaceVarTemplating(param.name),
- value: replaceVarTemplating(param.value ?? ""),
- active: !(param.disabled ?? false),
- })) ?? []
- const getHoppRequest = (req: InsomniaRequestResource): HoppRESTRequest =>
- makeRESTRequest({
- name: req.name ?? "Untitled Request",
- method: req.method?.toUpperCase() ?? "GET",
- endpoint: replaceVarTemplating(req.url ?? ""),
- auth: getHoppReqAuth(req),
- body: getHoppReqBody(req),
- headers: getHoppReqHeaders(req),
- params: getHoppReqParams(req),
- preRequestScript: "",
- testScript: "",
- })
- const getHoppFolder = (
- folderRes: InsomniaFolderResource,
- resources: InsomniaResource[]
- ): HoppCollection<HoppRESTRequest> =>
- makeCollection({
- name: folderRes.name ?? "",
- folders: getFoldersIn(folderRes, resources).map((f) =>
- getHoppFolder(f, resources)
- ),
- requests: getRequestsIn(folderRes, resources).map(getHoppRequest),
- })
- const getHoppCollections = (doc: InsomniaDoc) =>
- getFoldersIn(null, doc.data.resources).map((f) =>
- getHoppFolder(f, doc.data.resources)
- )
- export default defineImporter({
- id: "insomnia",
- name: "import.from_insomnia",
- applicableTo: ["my-collections", "team-collections", "url-import"],
- icon: "insomnia",
- steps: [
- step({
- stepName: "FILE_IMPORT",
- metadata: {
- caption: "import.from_insomnia_description",
- acceptedFileTypes: ".json, .yaml",
- },
- }),
- ] as const,
- importer: ([fileContent]) =>
- pipe(
- fileContent,
- parseInsomniaDoc,
- TO.map(getHoppCollections),
- TE.fromTaskOption(() => IMPORTER_INVALID_FILE_FORMAT)
- ),
- })
|