Skip to content
Merged
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
403 changes: 403 additions & 0 deletions docs/superpowers/plans/2026-05-03-http-import-formats.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/website/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export default defineConfig({
{ text: 'HTTP Client', link: '/documentation/http/' },
{ text: 'Requests', link: '/documentation/http/requests' },
{ text: 'Environments', link: '/documentation/http/environments' },
{ text: 'Importing Collections', link: '/documentation/http/importing' },
],
},
{
Expand Down
71 changes: 71 additions & 0 deletions docs/website/documentation/http/importing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: Importing HTTP Collections
description: "Import OpenAPI, Postman, and Bruno collections into the massCode HTTP space."
---

# Importing Collections

Use import when you already have API collections or specifications in another tool and want to bring them into the HTTP space without recreating requests by hand.

<img :src="withBase('/http-import.png')">

## Supported Formats

HTTP import supports:

- **OpenAPI JSON/YAML** - generates requests from OpenAPI operations.
- **Postman Collection v2.1 JSON** - imports folders, requests, params, headers, bodies, descriptions, and supported auth.
- **Postman Environment JSON** - optional environment file imported together with a Postman collection.
- **Bruno OpenCollection YAML** - imports single-file Bruno OpenCollection exports.
- **Bruno OpenCollection ZIP** - imports zipped Bruno OpenCollection exports.

## Opening Import

Open the **HTTP** space and click the import button in the HTTP sidebar header. The import button is next to the **HTTP Client** title because importing can create folders, requests, and environments.

## Selecting Files

Use either method in the import dialog:

- Click **Choose files** and select one or more files from disk.
- Drag files into the drop zone.

For Postman, select the collection JSON and, optionally, the environment JSON in the same import dialog.

## Preview

After files are selected, massCode reads them and shows a preview before anything is written to your vault.

The preview includes:

- number of collections
- number of requests
- number of environments
- collection names with folder and request counts
- environment names with variable counts
- warnings for skipped or unsupported features

Click **Import** to create the previewed items in the HTTP space.

## Where Imported Data Goes

Each imported collection becomes a new top-level folder in the HTTP space. Nested folders and requests are created under that collection folder.

Imported environments are added to the **Environments** panel. Environment variables are stored as plain text in your vault, the same as variables created manually in HTTP.

## Warnings

Some external client features do not have an equivalent in the current HTTP space model. When that happens, import keeps the request data it can represent and shows a warning.

Common warnings include:

- runtime scripts skipped
- assertions skipped
- disabled environment variables skipped
- unsupported auth skipped or converted when possible

Requests and environments are still importable when warnings are shown.

<script setup>
import { withBase } from 'vitepress'
</script>
9 changes: 7 additions & 2 deletions docs/website/documentation/http/index.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
---
title: HTTP Client
description: "Use the HTTP space in massCode as a lightweight local-first API client for saved requests, environments, previews, and responses."
description: "Use the HTTP space in massCode as a lightweight local-first API client for saved requests, imported collections, environments, previews, and responses."
---

# HTTP Client

<AppVersion text=">=5.3" />

HTTP is the API client space inside massCode. Use it to keep reusable requests next to your snippets and notes, test endpoints during development, and store small API collections in your local vault.
HTTP is the API client space inside massCode. Use it to keep reusable requests next to your snippets and notes, import existing API collections, test endpoints during development, and store small API collections in your local vault.

Access HTTP from the **HTTP** icon in the Space rail. The layout follows the same workspace pattern as Code and Notes: folders on the left, requests in the middle, and the request editor with preview and response panels on the right.

Expand All @@ -19,6 +19,7 @@ Use HTTP when you want a lightweight request client without leaving massCode.

- test local or remote API endpoints
- save repeatable requests by project or service
- import collections from OpenAPI, Postman, or Bruno
- keep request descriptions close to implementation notes
- switch variables between local, staging, and production environments
- copy a request as raw HTTP or cURL for debugging and sharing
Expand All @@ -33,6 +34,10 @@ Requests store the method, URL, params, headers, body, auth settings, and markdo

Environments store reusable variables for local, staging, and production APIs. The URL field keeps variables visible while you edit, while preview and request execution resolve values from the active environment.

### [Importing Collections](/documentation/http/importing)

Importing creates HTTP folders, requests, and environments from external collection files. HTTP supports OpenAPI JSON/YAML, Postman Collection v2.1 JSON with optional Postman Environment JSON, and Bruno OpenCollection YAML or ZIP exports.

## Folders

HTTP requests are organized in folders. Selecting a folder shows its requests and selects the first request in that folder. Folders support nesting, drag and drop ordering, inline rename, and custom folder icons.
Expand Down
2 changes: 1 addition & 1 deletion docs/website/documentation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Use Notes for longer markdown documents that do not fit well into snippets: proj

## HTTP

Use HTTP as a lightweight API client inside massCode. Store requests in folders, switch environments, preview the outgoing request as raw HTTP or cURL, send it from the editor, and inspect the response body and headers without leaving your workspace.
Use HTTP as a lightweight API client inside massCode. Store requests in folders, import collections from OpenAPI, Postman, or Bruno, switch environments, preview the outgoing request as raw HTTP or cURL, send it from the editor, and inspect the response body and headers without leaving your workspace.

## Math

Expand Down
Binary file added docs/website/public/http-import.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
"interactjs": "^1.10.27",
"js-yaml": "^4.1.0",
"jsondiffpatch": "^0.7.3",
"jszip": "^3.10.1",
"ky": "^1.7.5",
"lucide-vue-next": "^0.476.0",
"markmap-lib": "^0.18.11",
Expand Down
35 changes: 35 additions & 0 deletions pnpm-lock.yaml

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

62 changes: 62 additions & 0 deletions src/main/api/dto/http-import.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import Elysia, { t } from 'elysia'

const httpImportFile = t.Object({
content: t.String(),
encoding: t.Optional(t.Union([t.Literal('text'), t.Literal('base64')])),
name: t.String(),
})

const httpImportWarning = t.Object({
message: t.String(),
source: t.String(),
})

const httpImportPreviewCollection = t.Object({
folders: t.Number(),
index: t.Number(),
name: t.String(),
requests: t.Number(),
})

const httpImportPreviewEnvironment = t.Object({
index: t.Number(),
name: t.String(),
variables: t.Number(),
})

const httpImportPreviewInput = t.Object({
files: t.Array(httpImportFile),
})

const httpImportApplyInput = t.Object({
files: t.Array(httpImportFile),
selectedCollectionIndexes: t.Optional(t.Array(t.Number())),
selectedEnvironmentIndexes: t.Optional(t.Array(t.Number())),
})

const httpImportPreviewResponse = t.Object({
collections: t.Array(httpImportPreviewCollection),
environments: t.Array(httpImportPreviewEnvironment),
warnings: t.Array(httpImportWarning),
})

const httpImportApplyResponse = t.Object({
collections: t.Number(),
createdCollectionNames: t.Array(t.String()),
environments: t.Number(),
folders: t.Number(),
requests: t.Number(),
warnings: t.Array(httpImportWarning),
})

export const httpImportDTO = new Elysia().model({
httpImportApplyInput,
httpImportApplyResponse,
httpImportPreviewInput,
httpImportPreviewResponse,
})

export type HttpImportPreviewInput = typeof httpImportPreviewInput.static
export type HttpImportApplyInput = typeof httpImportApplyInput.static
export type HttpImportPreviewResponse = typeof httpImportPreviewResponse.static
export type HttpImportApplyResponse = typeof httpImportApplyResponse.static
2 changes: 2 additions & 0 deletions src/main/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import folders from './routes/folders'
import httpEnvironments from './routes/http-environments'
import httpFolders from './routes/http-folders'
import httpHistory from './routes/http-history'
import httpImport from './routes/http-import'
import httpRequests from './routes/http-requests'
import noteFolders from './routes/note-folders'
import noteTags from './routes/note-tags'
Expand Down Expand Up @@ -51,6 +52,7 @@ export async function initApi() {
.use(httpRequests)
.use(httpEnvironments)
.use(httpHistory)
.use(httpImport)
.listen(port)

// eslint-disable-next-line no-console
Expand Down
75 changes: 75 additions & 0 deletions src/main/api/routes/http-import.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import type {
HttpImportApplyResponse,
HttpImportPreviewResponse,
} from '../dto/http-import'
import { Elysia } from 'elysia'
import { applyHttpImport, previewHttpImport } from '../../http/import'
import { commonMessageResponse } from '../dto/common/response'
import { httpImportDTO } from '../dto/http-import'

const app = new Elysia({ prefix: '/http-import' })

function mapImportError(status: unknown, error: unknown): never {
const setStatus = status as (
code: number,
payload: { message: string },
) => never

if (error instanceof Error) {
return setStatus(400, { message: error.message })
}

return setStatus(500, { message: 'Import failed' })
}

app
.use(httpImportDTO)
.post(
'/preview',
async ({ body, status }) => {
try {
return (await previewHttpImport(
body.files,
)) as HttpImportPreviewResponse
}
catch (error) {
return mapImportError(status, error)
}
},
{
body: 'httpImportPreviewInput',
response: {
200: 'httpImportPreviewResponse',
400: commonMessageResponse,
},
detail: {
tags: ['HTTP Import'],
},
},
)
.post(
'/apply',
async ({ body, status }) => {
try {
return (await applyHttpImport(body.files, {
selectedCollectionIndexes: body.selectedCollectionIndexes,
selectedEnvironmentIndexes: body.selectedEnvironmentIndexes,
})) as HttpImportApplyResponse
}
catch (error) {
return mapImportError(status, error)
}
},
{
body: 'httpImportApplyInput',
response: {
200: 'httpImportApplyResponse',
400: commonMessageResponse,
},
detail: {
tags: ['HTTP Import'],
},
},
)

export default app
Loading