@brainfish-ai/devdoc 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +33 -0
- package/README.md +415 -0
- package/bin/devdoc.js +13 -0
- package/dist/cli/commands/build.d.ts +5 -0
- package/dist/cli/commands/build.js +87 -0
- package/dist/cli/commands/check.d.ts +1 -0
- package/dist/cli/commands/check.js +143 -0
- package/dist/cli/commands/create.d.ts +24 -0
- package/dist/cli/commands/create.js +387 -0
- package/dist/cli/commands/deploy.d.ts +9 -0
- package/dist/cli/commands/deploy.js +433 -0
- package/dist/cli/commands/dev.d.ts +6 -0
- package/dist/cli/commands/dev.js +139 -0
- package/dist/cli/commands/init.d.ts +11 -0
- package/dist/cli/commands/init.js +238 -0
- package/dist/cli/commands/keys.d.ts +12 -0
- package/dist/cli/commands/keys.js +165 -0
- package/dist/cli/commands/start.d.ts +5 -0
- package/dist/cli/commands/start.js +56 -0
- package/dist/cli/commands/upload.d.ts +13 -0
- package/dist/cli/commands/upload.js +238 -0
- package/dist/cli/commands/whoami.d.ts +8 -0
- package/dist/cli/commands/whoami.js +91 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +106 -0
- package/dist/config/index.d.ts +80 -0
- package/dist/config/index.js +133 -0
- package/dist/constants.d.ts +9 -0
- package/dist/constants.js +13 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +12 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.js +61 -0
- package/dist/utils/paths.d.ts +16 -0
- package/dist/utils/paths.js +50 -0
- package/package.json +51 -0
- package/renderer/app/api/assets/[...path]/route.ts +123 -0
- package/renderer/app/api/assets/route.ts +124 -0
- package/renderer/app/api/assets/upload/route.ts +177 -0
- package/renderer/app/api/auth-schemes/route.ts +77 -0
- package/renderer/app/api/chat/route.ts +858 -0
- package/renderer/app/api/codegen/route.ts +72 -0
- package/renderer/app/api/collections/route.ts +1016 -0
- package/renderer/app/api/debug/route.ts +53 -0
- package/renderer/app/api/deploy/route.ts +234 -0
- package/renderer/app/api/device/route.ts +42 -0
- package/renderer/app/api/docs/route.ts +187 -0
- package/renderer/app/api/keys/regenerate/route.ts +80 -0
- package/renderer/app/api/openapi-spec/route.ts +151 -0
- package/renderer/app/api/projects/[slug]/route.ts +153 -0
- package/renderer/app/api/projects/[slug]/stats/route.ts +96 -0
- package/renderer/app/api/projects/register/route.ts +152 -0
- package/renderer/app/api/proxy/route.ts +149 -0
- package/renderer/app/api/proxy-stream/route.ts +168 -0
- package/renderer/app/api/redirects/route.ts +47 -0
- package/renderer/app/api/schema/route.ts +65 -0
- package/renderer/app/api/subdomains/check/route.ts +172 -0
- package/renderer/app/api/suggestions/route.ts +144 -0
- package/renderer/app/favicon.ico +0 -0
- package/renderer/app/globals.css +1103 -0
- package/renderer/app/layout.tsx +47 -0
- package/renderer/app/llms-full.txt/route.ts +346 -0
- package/renderer/app/llms.txt/route.ts +279 -0
- package/renderer/app/page.tsx +14 -0
- package/renderer/app/robots.txt/route.ts +84 -0
- package/renderer/app/sitemap.xml/route.ts +199 -0
- package/renderer/components/docs/index.ts +12 -0
- package/renderer/components/docs/mdx/accordion.tsx +169 -0
- package/renderer/components/docs/mdx/badge.tsx +132 -0
- package/renderer/components/docs/mdx/callouts.tsx +154 -0
- package/renderer/components/docs/mdx/cards.tsx +213 -0
- package/renderer/components/docs/mdx/changelog.tsx +120 -0
- package/renderer/components/docs/mdx/code-block.tsx +186 -0
- package/renderer/components/docs/mdx/code-group.tsx +421 -0
- package/renderer/components/docs/mdx/file-embeds.tsx +105 -0
- package/renderer/components/docs/mdx/frame.tsx +112 -0
- package/renderer/components/docs/mdx/highlight.tsx +151 -0
- package/renderer/components/docs/mdx/iframe.tsx +134 -0
- package/renderer/components/docs/mdx/image.tsx +235 -0
- package/renderer/components/docs/mdx/index.ts +204 -0
- package/renderer/components/docs/mdx/mermaid.tsx +240 -0
- package/renderer/components/docs/mdx/param-field.tsx +200 -0
- package/renderer/components/docs/mdx/steps.tsx +113 -0
- package/renderer/components/docs/mdx/tabs.tsx +86 -0
- package/renderer/components/docs/mdx-renderer.tsx +100 -0
- package/renderer/components/docs/navigation/breadcrumbs.tsx +76 -0
- package/renderer/components/docs/navigation/index.ts +8 -0
- package/renderer/components/docs/navigation/page-nav.tsx +64 -0
- package/renderer/components/docs/navigation/sidebar.tsx +515 -0
- package/renderer/components/docs/navigation/toc.tsx +113 -0
- package/renderer/components/docs/notice.tsx +105 -0
- package/renderer/components/docs-header.tsx +274 -0
- package/renderer/components/docs-viewer/agent/agent-chat.tsx +2076 -0
- package/renderer/components/docs-viewer/agent/cards/debug-context-card.tsx +90 -0
- package/renderer/components/docs-viewer/agent/cards/endpoint-context-card.tsx +49 -0
- package/renderer/components/docs-viewer/agent/cards/index.tsx +50 -0
- package/renderer/components/docs-viewer/agent/cards/response-options-card.tsx +212 -0
- package/renderer/components/docs-viewer/agent/cards/types.ts +84 -0
- package/renderer/components/docs-viewer/agent/chat-message.tsx +17 -0
- package/renderer/components/docs-viewer/agent/index.tsx +6 -0
- package/renderer/components/docs-viewer/agent/messages/assistant-message.tsx +119 -0
- package/renderer/components/docs-viewer/agent/messages/chat-message.tsx +46 -0
- package/renderer/components/docs-viewer/agent/messages/index.ts +17 -0
- package/renderer/components/docs-viewer/agent/messages/tool-call-display.tsx +721 -0
- package/renderer/components/docs-viewer/agent/messages/types.ts +61 -0
- package/renderer/components/docs-viewer/agent/messages/typing-indicator.tsx +24 -0
- package/renderer/components/docs-viewer/agent/messages/user-message.tsx +51 -0
- package/renderer/components/docs-viewer/code-editor/index.tsx +2 -0
- package/renderer/components/docs-viewer/code-editor/notes-mode.tsx +1283 -0
- package/renderer/components/docs-viewer/content/changelog-page.tsx +331 -0
- package/renderer/components/docs-viewer/content/doc-page.tsx +285 -0
- package/renderer/components/docs-viewer/content/documentation-viewer.tsx +17 -0
- package/renderer/components/docs-viewer/content/index.tsx +29 -0
- package/renderer/components/docs-viewer/content/introduction.tsx +21 -0
- package/renderer/components/docs-viewer/content/request-details.tsx +330 -0
- package/renderer/components/docs-viewer/content/sections/auth.tsx +69 -0
- package/renderer/components/docs-viewer/content/sections/body.tsx +66 -0
- package/renderer/components/docs-viewer/content/sections/headers.tsx +43 -0
- package/renderer/components/docs-viewer/content/sections/overview.tsx +40 -0
- package/renderer/components/docs-viewer/content/sections/parameters.tsx +43 -0
- package/renderer/components/docs-viewer/content/sections/responses.tsx +87 -0
- package/renderer/components/docs-viewer/global-auth-modal.tsx +352 -0
- package/renderer/components/docs-viewer/index.tsx +1466 -0
- package/renderer/components/docs-viewer/playground/auth-editor.tsx +280 -0
- package/renderer/components/docs-viewer/playground/body-editor.tsx +221 -0
- package/renderer/components/docs-viewer/playground/code-editor.tsx +224 -0
- package/renderer/components/docs-viewer/playground/code-snippet.tsx +387 -0
- package/renderer/components/docs-viewer/playground/graphql-playground.tsx +745 -0
- package/renderer/components/docs-viewer/playground/index.tsx +671 -0
- package/renderer/components/docs-viewer/playground/key-value-editor.tsx +261 -0
- package/renderer/components/docs-viewer/playground/method-selector.tsx +60 -0
- package/renderer/components/docs-viewer/playground/request-builder.tsx +179 -0
- package/renderer/components/docs-viewer/playground/request-tabs.tsx +237 -0
- package/renderer/components/docs-viewer/playground/response-cards/idle-card.tsx +21 -0
- package/renderer/components/docs-viewer/playground/response-cards/index.tsx +93 -0
- package/renderer/components/docs-viewer/playground/response-cards/loading-card.tsx +16 -0
- package/renderer/components/docs-viewer/playground/response-cards/network-error-card.tsx +23 -0
- package/renderer/components/docs-viewer/playground/response-cards/response-body-card.tsx +268 -0
- package/renderer/components/docs-viewer/playground/response-cards/types.ts +82 -0
- package/renderer/components/docs-viewer/playground/response-viewer.tsx +43 -0
- package/renderer/components/docs-viewer/search/index.ts +2 -0
- package/renderer/components/docs-viewer/search/search-dialog.tsx +331 -0
- package/renderer/components/docs-viewer/search/use-search.ts +117 -0
- package/renderer/components/docs-viewer/shared/markdown-renderer.tsx +431 -0
- package/renderer/components/docs-viewer/shared/method-badge.tsx +41 -0
- package/renderer/components/docs-viewer/shared/schema-viewer.tsx +349 -0
- package/renderer/components/docs-viewer/sidebar/collection-tree.tsx +239 -0
- package/renderer/components/docs-viewer/sidebar/endpoint-options.tsx +316 -0
- package/renderer/components/docs-viewer/sidebar/index.tsx +343 -0
- package/renderer/components/docs-viewer/sidebar/right-sidebar.tsx +202 -0
- package/renderer/components/docs-viewer/sidebar/sidebar-group.tsx +118 -0
- package/renderer/components/docs-viewer/sidebar/sidebar-item.tsx +226 -0
- package/renderer/components/docs-viewer/sidebar/sidebar-section.tsx +52 -0
- package/renderer/components/theme-provider.tsx +11 -0
- package/renderer/components/theme-toggle.tsx +76 -0
- package/renderer/components/ui/badge.tsx +46 -0
- package/renderer/components/ui/button.tsx +59 -0
- package/renderer/components/ui/dialog.tsx +118 -0
- package/renderer/components/ui/dropdown-menu.tsx +257 -0
- package/renderer/components/ui/input.tsx +21 -0
- package/renderer/components/ui/label.tsx +24 -0
- package/renderer/components/ui/navigation-menu.tsx +168 -0
- package/renderer/components/ui/select.tsx +190 -0
- package/renderer/components/ui/spinner.tsx +114 -0
- package/renderer/components/ui/tabs.tsx +66 -0
- package/renderer/components/ui/tooltip.tsx +61 -0
- package/renderer/hooks/use-code-copy.ts +88 -0
- package/renderer/hooks/use-openapi-title.ts +44 -0
- package/renderer/lib/api-docs/agent/index.ts +6 -0
- package/renderer/lib/api-docs/agent/indexer.ts +323 -0
- package/renderer/lib/api-docs/agent/spec-summary.ts +335 -0
- package/renderer/lib/api-docs/agent/types.ts +116 -0
- package/renderer/lib/api-docs/auth/auth-context.tsx +225 -0
- package/renderer/lib/api-docs/auth/auth-storage.ts +87 -0
- package/renderer/lib/api-docs/auth/crypto.ts +89 -0
- package/renderer/lib/api-docs/auth/index.ts +4 -0
- package/renderer/lib/api-docs/code-editor/db.ts +164 -0
- package/renderer/lib/api-docs/code-editor/hooks.ts +266 -0
- package/renderer/lib/api-docs/code-editor/index.ts +6 -0
- package/renderer/lib/api-docs/code-editor/mode-context.tsx +207 -0
- package/renderer/lib/api-docs/code-editor/types.ts +105 -0
- package/renderer/lib/api-docs/codegen/definitions.ts +297 -0
- package/renderer/lib/api-docs/codegen/har.ts +251 -0
- package/renderer/lib/api-docs/codegen/index.ts +159 -0
- package/renderer/lib/api-docs/factories.ts +151 -0
- package/renderer/lib/api-docs/index.ts +17 -0
- package/renderer/lib/api-docs/mobile-context.tsx +112 -0
- package/renderer/lib/api-docs/navigation-context.tsx +88 -0
- package/renderer/lib/api-docs/parsers/graphql/README.md +129 -0
- package/renderer/lib/api-docs/parsers/graphql/index.ts +91 -0
- package/renderer/lib/api-docs/parsers/graphql/parser.ts +491 -0
- package/renderer/lib/api-docs/parsers/graphql/transformer.ts +246 -0
- package/renderer/lib/api-docs/parsers/graphql/types.ts +283 -0
- package/renderer/lib/api-docs/parsers/openapi/README.md +32 -0
- package/renderer/lib/api-docs/parsers/openapi/dereferencer.ts +60 -0
- package/renderer/lib/api-docs/parsers/openapi/extractors/auth.ts +574 -0
- package/renderer/lib/api-docs/parsers/openapi/extractors/body.ts +403 -0
- package/renderer/lib/api-docs/parsers/openapi/extractors/index.ts +232 -0
- package/renderer/lib/api-docs/parsers/openapi/index.ts +171 -0
- package/renderer/lib/api-docs/parsers/openapi/transformer.ts +277 -0
- package/renderer/lib/api-docs/parsers/openapi/validator.ts +31 -0
- package/renderer/lib/api-docs/playground/context.tsx +107 -0
- package/renderer/lib/api-docs/playground/navigation-context.tsx +124 -0
- package/renderer/lib/api-docs/playground/request-builder.ts +223 -0
- package/renderer/lib/api-docs/playground/request-runner.ts +282 -0
- package/renderer/lib/api-docs/playground/types.ts +35 -0
- package/renderer/lib/api-docs/types.ts +269 -0
- package/renderer/lib/api-docs/utils.ts +311 -0
- package/renderer/lib/cache.ts +193 -0
- package/renderer/lib/docs/config/index.ts +29 -0
- package/renderer/lib/docs/config/loader.ts +142 -0
- package/renderer/lib/docs/config/schema.ts +298 -0
- package/renderer/lib/docs/index.ts +12 -0
- package/renderer/lib/docs/mdx/compiler.ts +176 -0
- package/renderer/lib/docs/mdx/frontmatter.ts +80 -0
- package/renderer/lib/docs/mdx/index.ts +26 -0
- package/renderer/lib/docs/navigation/generator.ts +348 -0
- package/renderer/lib/docs/navigation/index.ts +12 -0
- package/renderer/lib/docs/navigation/types.ts +123 -0
- package/renderer/lib/docs-navigation-context.tsx +80 -0
- package/renderer/lib/multi-tenant/context.ts +105 -0
- package/renderer/lib/storage/blob.ts +845 -0
- package/renderer/lib/utils.ts +6 -0
- package/renderer/next.config.ts +76 -0
- package/renderer/package.json +66 -0
- package/renderer/postcss.config.mjs +5 -0
- package/renderer/public/assets/images/screenshot.png +0 -0
- package/renderer/public/assets/logo/dark.svg +9 -0
- package/renderer/public/assets/logo/light.svg +9 -0
- package/renderer/public/assets/logo.svg +9 -0
- package/renderer/public/file.svg +1 -0
- package/renderer/public/globe.svg +1 -0
- package/renderer/public/icon.png +0 -0
- package/renderer/public/logo.svg +9 -0
- package/renderer/public/window.svg +1 -0
- package/renderer/tsconfig.json +28 -0
- package/templates/basic/README.md +139 -0
- package/templates/basic/assets/favicon.svg +4 -0
- package/templates/basic/assets/logo.svg +9 -0
- package/templates/basic/docs.json +47 -0
- package/templates/basic/guides/configuration.mdx +149 -0
- package/templates/basic/guides/overview.mdx +96 -0
- package/templates/basic/index.mdx +39 -0
- package/templates/basic/package.json +14 -0
- package/templates/basic/quickstart.mdx +92 -0
- package/templates/basic/vercel.json +6 -0
- package/templates/graphql/README.md +139 -0
- package/templates/graphql/api-reference/schema.graphql +305 -0
- package/templates/graphql/assets/favicon.svg +4 -0
- package/templates/graphql/assets/logo.svg +9 -0
- package/templates/graphql/docs.json +54 -0
- package/templates/graphql/guides/configuration.mdx +149 -0
- package/templates/graphql/guides/overview.mdx +96 -0
- package/templates/graphql/index.mdx +39 -0
- package/templates/graphql/package.json +14 -0
- package/templates/graphql/quickstart.mdx +92 -0
- package/templates/graphql/vercel.json +6 -0
- package/templates/openapi/README.md +139 -0
- package/templates/openapi/api-reference/openapi.json +419 -0
- package/templates/openapi/assets/favicon.svg +4 -0
- package/templates/openapi/assets/logo.svg +9 -0
- package/templates/openapi/docs.json +61 -0
- package/templates/openapi/guides/configuration.mdx +149 -0
- package/templates/openapi/guides/overview.mdx +96 -0
- package/templates/openapi/index.mdx +39 -0
- package/templates/openapi/package.json +14 -0
- package/templates/openapi/quickstart.mdx +92 -0
- package/templates/openapi/vercel.json +6 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL Transformer
|
|
3
|
+
*
|
|
4
|
+
* Converts parsed GraphQL schema to BrainfishCollection format
|
|
5
|
+
* for integration with the existing documentation system.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { BrainfishCollection, BrainfishRESTRequest } from '../../types'
|
|
9
|
+
import { makeBrainfishCollection } from '../../factories'
|
|
10
|
+
import {
|
|
11
|
+
formatTypeRef,
|
|
12
|
+
type GraphQLSchema,
|
|
13
|
+
type GraphQLOperation,
|
|
14
|
+
type BrainfishGraphQLCollection,
|
|
15
|
+
type BrainfishGraphQLRequest,
|
|
16
|
+
type GraphQLTypeDef,
|
|
17
|
+
} from './types'
|
|
18
|
+
import { generateExampleVariables, generateOperationQuery } from './parser'
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// GraphQL to REST-like Request Conversion
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Convert a GraphQL operation to a REST-like request for the playground
|
|
26
|
+
* This allows us to reuse the existing API client UI
|
|
27
|
+
*/
|
|
28
|
+
function convertOperationToRESTRequest(
|
|
29
|
+
operation: GraphQLOperation,
|
|
30
|
+
endpoint: string
|
|
31
|
+
): BrainfishRESTRequest {
|
|
32
|
+
// Generate the query string
|
|
33
|
+
const query = generateOperationQuery(operation)
|
|
34
|
+
|
|
35
|
+
// Generate example variables
|
|
36
|
+
const variables = generateExampleVariables(operation)
|
|
37
|
+
|
|
38
|
+
// GraphQL always uses POST with JSON body
|
|
39
|
+
const body = JSON.stringify(
|
|
40
|
+
{
|
|
41
|
+
query,
|
|
42
|
+
variables,
|
|
43
|
+
operationName: operation.name,
|
|
44
|
+
},
|
|
45
|
+
null,
|
|
46
|
+
2
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
id: operation.id,
|
|
51
|
+
name: operation.name,
|
|
52
|
+
description: operation.description || formatOperationDescription(operation),
|
|
53
|
+
method: 'POST',
|
|
54
|
+
endpoint,
|
|
55
|
+
params: [],
|
|
56
|
+
headers: [
|
|
57
|
+
{
|
|
58
|
+
key: 'Content-Type',
|
|
59
|
+
value: 'application/json',
|
|
60
|
+
active: true,
|
|
61
|
+
description: 'GraphQL requests use JSON',
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
auth: {
|
|
65
|
+
authType: 'inherit',
|
|
66
|
+
authActive: true,
|
|
67
|
+
},
|
|
68
|
+
body: {
|
|
69
|
+
contentType: 'application/json',
|
|
70
|
+
body,
|
|
71
|
+
},
|
|
72
|
+
requestVariables: operation.args.map(arg => ({
|
|
73
|
+
key: arg.name,
|
|
74
|
+
value: JSON.stringify(generateExampleVariables({ ...operation, args: [arg] })[arg.name]),
|
|
75
|
+
active: true,
|
|
76
|
+
})),
|
|
77
|
+
responses: {},
|
|
78
|
+
tags: [operation.operationType],
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Format a description for an operation based on its signature
|
|
84
|
+
*/
|
|
85
|
+
function formatOperationDescription(operation: GraphQLOperation): string {
|
|
86
|
+
const args = operation.args
|
|
87
|
+
.map(arg => `${arg.name}: ${formatTypeRef(arg.type)}`)
|
|
88
|
+
.join(', ')
|
|
89
|
+
|
|
90
|
+
const returnType = formatTypeRef(operation.returnType)
|
|
91
|
+
|
|
92
|
+
return `${operation.operationType} ${operation.name}(${args}): ${returnType}`
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ============================================================================
|
|
96
|
+
// Main Transformer Functions
|
|
97
|
+
// ============================================================================
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Convert GraphQL schema to a BrainfishGraphQLCollection
|
|
101
|
+
*/
|
|
102
|
+
export function convertGraphQLToCollection(
|
|
103
|
+
schema: GraphQLSchema,
|
|
104
|
+
name: string,
|
|
105
|
+
endpoint: string,
|
|
106
|
+
description?: string
|
|
107
|
+
): BrainfishGraphQLCollection {
|
|
108
|
+
// Convert operations to our request format
|
|
109
|
+
const queries: BrainfishGraphQLRequest[] = schema.queries.map(op => ({
|
|
110
|
+
id: op.id,
|
|
111
|
+
name: op.name,
|
|
112
|
+
description: op.description,
|
|
113
|
+
operationType: 'query',
|
|
114
|
+
query: generateOperationQuery(op),
|
|
115
|
+
variables: op.args,
|
|
116
|
+
returnType: op.returnType,
|
|
117
|
+
tags: ['Query'],
|
|
118
|
+
exampleVariables: generateExampleVariables(op),
|
|
119
|
+
}))
|
|
120
|
+
|
|
121
|
+
const mutations: BrainfishGraphQLRequest[] = schema.mutations.map(op => ({
|
|
122
|
+
id: op.id,
|
|
123
|
+
name: op.name,
|
|
124
|
+
description: op.description,
|
|
125
|
+
operationType: 'mutation',
|
|
126
|
+
query: generateOperationQuery(op),
|
|
127
|
+
variables: op.args,
|
|
128
|
+
returnType: op.returnType,
|
|
129
|
+
tags: ['Mutation'],
|
|
130
|
+
exampleVariables: generateExampleVariables(op),
|
|
131
|
+
}))
|
|
132
|
+
|
|
133
|
+
const subscriptions: BrainfishGraphQLRequest[] = schema.subscriptions.map(op => ({
|
|
134
|
+
id: op.id,
|
|
135
|
+
name: op.name,
|
|
136
|
+
description: op.description,
|
|
137
|
+
operationType: 'subscription',
|
|
138
|
+
query: generateOperationQuery(op),
|
|
139
|
+
variables: op.args,
|
|
140
|
+
returnType: op.returnType,
|
|
141
|
+
tags: ['Subscription'],
|
|
142
|
+
exampleVariables: generateExampleVariables(op),
|
|
143
|
+
}))
|
|
144
|
+
|
|
145
|
+
// Extract custom types (exclude built-in scalars)
|
|
146
|
+
const customTypes: GraphQLTypeDef[] = Object.values(schema.types).filter(
|
|
147
|
+
type => !['String', 'Int', 'Float', 'Boolean', 'ID'].includes(type.name)
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
id: `graphql-${name.toLowerCase().replace(/\s+/g, '-')}`,
|
|
152
|
+
name,
|
|
153
|
+
description: description || schema.info.description,
|
|
154
|
+
endpoint,
|
|
155
|
+
schema,
|
|
156
|
+
queries,
|
|
157
|
+
mutations,
|
|
158
|
+
subscriptions,
|
|
159
|
+
types: customTypes,
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Convert GraphQL schema to BrainfishCollection format
|
|
165
|
+
* This allows integration with the existing REST-based UI
|
|
166
|
+
*/
|
|
167
|
+
export function convertGraphQLToBrainfishCollection(
|
|
168
|
+
schema: GraphQLSchema,
|
|
169
|
+
name: string,
|
|
170
|
+
endpoint: string,
|
|
171
|
+
description?: string
|
|
172
|
+
): BrainfishCollection {
|
|
173
|
+
// Create folders for each operation type
|
|
174
|
+
const queryFolder = makeBrainfishCollection({
|
|
175
|
+
name: 'Queries',
|
|
176
|
+
description: 'GraphQL Query operations',
|
|
177
|
+
requests: schema.queries.map(op => convertOperationToRESTRequest(op, endpoint)),
|
|
178
|
+
folders: [],
|
|
179
|
+
variables: [],
|
|
180
|
+
auth: { authType: 'none', authActive: false },
|
|
181
|
+
headers: [],
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
const mutationFolder = makeBrainfishCollection({
|
|
185
|
+
name: 'Mutations',
|
|
186
|
+
description: 'GraphQL Mutation operations',
|
|
187
|
+
requests: schema.mutations.map(op => convertOperationToRESTRequest(op, endpoint)),
|
|
188
|
+
folders: [],
|
|
189
|
+
variables: [],
|
|
190
|
+
auth: { authType: 'none', authActive: false },
|
|
191
|
+
headers: [],
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
const subscriptionFolder = makeBrainfishCollection({
|
|
195
|
+
name: 'Subscriptions',
|
|
196
|
+
description: 'GraphQL Subscription operations',
|
|
197
|
+
requests: schema.subscriptions.map(op => convertOperationToRESTRequest(op, endpoint)),
|
|
198
|
+
folders: [],
|
|
199
|
+
variables: [],
|
|
200
|
+
auth: { authType: 'none', authActive: false },
|
|
201
|
+
headers: [],
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
// Only include folders that have operations
|
|
205
|
+
const folders: BrainfishCollection[] = []
|
|
206
|
+
if (schema.queries.length > 0) folders.push(queryFolder)
|
|
207
|
+
if (schema.mutations.length > 0) folders.push(mutationFolder)
|
|
208
|
+
if (schema.subscriptions.length > 0) folders.push(subscriptionFolder)
|
|
209
|
+
|
|
210
|
+
return makeBrainfishCollection({
|
|
211
|
+
name,
|
|
212
|
+
description: description || schema.info.description || 'GraphQL API',
|
|
213
|
+
folders,
|
|
214
|
+
requests: [],
|
|
215
|
+
variables: [],
|
|
216
|
+
auth: { authType: 'none', authActive: false },
|
|
217
|
+
headers: [
|
|
218
|
+
{
|
|
219
|
+
key: 'Content-Type',
|
|
220
|
+
value: 'application/json',
|
|
221
|
+
active: true,
|
|
222
|
+
description: 'GraphQL requests use JSON',
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Merge GraphQL collection with existing REST collection
|
|
230
|
+
*/
|
|
231
|
+
export function mergeWithRESTCollection(
|
|
232
|
+
restCollection: BrainfishCollection,
|
|
233
|
+
graphqlSchema: GraphQLSchema,
|
|
234
|
+
graphqlEndpoint: string
|
|
235
|
+
): BrainfishCollection {
|
|
236
|
+
const graphqlCollection = convertGraphQLToBrainfishCollection(
|
|
237
|
+
graphqlSchema,
|
|
238
|
+
'GraphQL',
|
|
239
|
+
graphqlEndpoint
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
...restCollection,
|
|
244
|
+
folders: [...restCollection.folders, graphqlCollection],
|
|
245
|
+
}
|
|
246
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GraphQL Types for Brainfish API Documentation
|
|
3
|
+
*
|
|
4
|
+
* Types for parsing and representing GraphQL schemas in the documentation system.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// GraphQL Scalar Types
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
export type GraphQLScalarType =
|
|
12
|
+
| 'String'
|
|
13
|
+
| 'Int'
|
|
14
|
+
| 'Float'
|
|
15
|
+
| 'Boolean'
|
|
16
|
+
| 'ID'
|
|
17
|
+
| string // Custom scalars
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// GraphQL Type Kinds
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
export type GraphQLTypeKind =
|
|
24
|
+
| 'SCALAR'
|
|
25
|
+
| 'OBJECT'
|
|
26
|
+
| 'INPUT_OBJECT'
|
|
27
|
+
| 'ENUM'
|
|
28
|
+
| 'INTERFACE'
|
|
29
|
+
| 'UNION'
|
|
30
|
+
| 'LIST'
|
|
31
|
+
| 'NON_NULL'
|
|
32
|
+
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// GraphQL Type Reference
|
|
35
|
+
// ============================================================================
|
|
36
|
+
|
|
37
|
+
export interface GraphQLTypeRef {
|
|
38
|
+
kind: GraphQLTypeKind
|
|
39
|
+
name: string | null
|
|
40
|
+
ofType?: GraphQLTypeRef | null
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// GraphQL Argument
|
|
45
|
+
// ============================================================================
|
|
46
|
+
|
|
47
|
+
export interface GraphQLArgument {
|
|
48
|
+
name: string
|
|
49
|
+
description: string | null
|
|
50
|
+
type: GraphQLTypeRef
|
|
51
|
+
defaultValue: string | null
|
|
52
|
+
isRequired: boolean
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ============================================================================
|
|
56
|
+
// GraphQL Field
|
|
57
|
+
// ============================================================================
|
|
58
|
+
|
|
59
|
+
export interface GraphQLField {
|
|
60
|
+
name: string
|
|
61
|
+
description: string | null
|
|
62
|
+
args: GraphQLArgument[]
|
|
63
|
+
type: GraphQLTypeRef
|
|
64
|
+
isDeprecated: boolean
|
|
65
|
+
deprecationReason: string | null
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ============================================================================
|
|
69
|
+
// GraphQL Enum Value
|
|
70
|
+
// ============================================================================
|
|
71
|
+
|
|
72
|
+
export interface GraphQLEnumValue {
|
|
73
|
+
name: string
|
|
74
|
+
description: string | null
|
|
75
|
+
isDeprecated: boolean
|
|
76
|
+
deprecationReason: string | null
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ============================================================================
|
|
80
|
+
// GraphQL Input Field
|
|
81
|
+
// ============================================================================
|
|
82
|
+
|
|
83
|
+
export interface GraphQLInputField {
|
|
84
|
+
name: string
|
|
85
|
+
description: string | null
|
|
86
|
+
type: GraphQLTypeRef
|
|
87
|
+
defaultValue: string | null
|
|
88
|
+
isRequired: boolean
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ============================================================================
|
|
92
|
+
// GraphQL Type Definitions
|
|
93
|
+
// ============================================================================
|
|
94
|
+
|
|
95
|
+
export interface GraphQLScalarTypeDef {
|
|
96
|
+
kind: 'SCALAR'
|
|
97
|
+
name: string
|
|
98
|
+
description: string | null
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface GraphQLObjectTypeDef {
|
|
102
|
+
kind: 'OBJECT'
|
|
103
|
+
name: string
|
|
104
|
+
description: string | null
|
|
105
|
+
fields: GraphQLField[]
|
|
106
|
+
interfaces: string[]
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface GraphQLInputObjectTypeDef {
|
|
110
|
+
kind: 'INPUT_OBJECT'
|
|
111
|
+
name: string
|
|
112
|
+
description: string | null
|
|
113
|
+
inputFields: GraphQLInputField[]
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface GraphQLEnumTypeDef {
|
|
117
|
+
kind: 'ENUM'
|
|
118
|
+
name: string
|
|
119
|
+
description: string | null
|
|
120
|
+
enumValues: GraphQLEnumValue[]
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface GraphQLInterfaceTypeDef {
|
|
124
|
+
kind: 'INTERFACE'
|
|
125
|
+
name: string
|
|
126
|
+
description: string | null
|
|
127
|
+
fields: GraphQLField[]
|
|
128
|
+
possibleTypes: string[]
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface GraphQLUnionTypeDef {
|
|
132
|
+
kind: 'UNION'
|
|
133
|
+
name: string
|
|
134
|
+
description: string | null
|
|
135
|
+
possibleTypes: string[]
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export type GraphQLTypeDef =
|
|
139
|
+
| GraphQLScalarTypeDef
|
|
140
|
+
| GraphQLObjectTypeDef
|
|
141
|
+
| GraphQLInputObjectTypeDef
|
|
142
|
+
| GraphQLEnumTypeDef
|
|
143
|
+
| GraphQLInterfaceTypeDef
|
|
144
|
+
| GraphQLUnionTypeDef
|
|
145
|
+
|
|
146
|
+
// ============================================================================
|
|
147
|
+
// GraphQL Operation Types
|
|
148
|
+
// ============================================================================
|
|
149
|
+
|
|
150
|
+
export type GraphQLOperationType = 'query' | 'mutation' | 'subscription'
|
|
151
|
+
|
|
152
|
+
export interface GraphQLOperation {
|
|
153
|
+
id: string
|
|
154
|
+
name: string
|
|
155
|
+
description: string | null
|
|
156
|
+
operationType: GraphQLOperationType
|
|
157
|
+
args: GraphQLArgument[]
|
|
158
|
+
returnType: GraphQLTypeRef
|
|
159
|
+
isDeprecated: boolean
|
|
160
|
+
deprecationReason: string | null
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ============================================================================
|
|
164
|
+
// GraphQL Directive
|
|
165
|
+
// ============================================================================
|
|
166
|
+
|
|
167
|
+
export interface GraphQLDirective {
|
|
168
|
+
name: string
|
|
169
|
+
description: string | null
|
|
170
|
+
locations: string[]
|
|
171
|
+
args: GraphQLArgument[]
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ============================================================================
|
|
175
|
+
// GraphQL Schema
|
|
176
|
+
// ============================================================================
|
|
177
|
+
|
|
178
|
+
export interface GraphQLSchemaInfo {
|
|
179
|
+
/** Schema description */
|
|
180
|
+
description: string | null
|
|
181
|
+
/** Query type name (usually "Query") */
|
|
182
|
+
queryType: string | null
|
|
183
|
+
/** Mutation type name (usually "Mutation") */
|
|
184
|
+
mutationType: string | null
|
|
185
|
+
/** Subscription type name (usually "Subscription") */
|
|
186
|
+
subscriptionType: string | null
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export interface GraphQLSchema {
|
|
190
|
+
/** Schema metadata */
|
|
191
|
+
info: GraphQLSchemaInfo
|
|
192
|
+
/** All type definitions */
|
|
193
|
+
types: Record<string, GraphQLTypeDef>
|
|
194
|
+
/** All directives */
|
|
195
|
+
directives: GraphQLDirective[]
|
|
196
|
+
/** Parsed queries */
|
|
197
|
+
queries: GraphQLOperation[]
|
|
198
|
+
/** Parsed mutations */
|
|
199
|
+
mutations: GraphQLOperation[]
|
|
200
|
+
/** Parsed subscriptions */
|
|
201
|
+
subscriptions: GraphQLOperation[]
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ============================================================================
|
|
205
|
+
// GraphQL Collection (for integration with existing system)
|
|
206
|
+
// ============================================================================
|
|
207
|
+
|
|
208
|
+
export interface BrainfishGraphQLRequest {
|
|
209
|
+
id: string
|
|
210
|
+
name: string
|
|
211
|
+
description: string | null
|
|
212
|
+
operationType: GraphQLOperationType
|
|
213
|
+
/** The GraphQL query/mutation/subscription string */
|
|
214
|
+
query: string
|
|
215
|
+
/** Variables schema */
|
|
216
|
+
variables: GraphQLArgument[]
|
|
217
|
+
/** Return type */
|
|
218
|
+
returnType: GraphQLTypeRef
|
|
219
|
+
/** Tags for grouping */
|
|
220
|
+
tags: string[]
|
|
221
|
+
/** Example variables */
|
|
222
|
+
exampleVariables?: Record<string, unknown>
|
|
223
|
+
/** Example response */
|
|
224
|
+
exampleResponse?: unknown
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export interface BrainfishGraphQLCollection {
|
|
228
|
+
id: string
|
|
229
|
+
name: string
|
|
230
|
+
description: string | null
|
|
231
|
+
/** GraphQL endpoint URL */
|
|
232
|
+
endpoint: string
|
|
233
|
+
/** Schema information */
|
|
234
|
+
schema: GraphQLSchema
|
|
235
|
+
/** All operations organized */
|
|
236
|
+
queries: BrainfishGraphQLRequest[]
|
|
237
|
+
mutations: BrainfishGraphQLRequest[]
|
|
238
|
+
subscriptions: BrainfishGraphQLRequest[]
|
|
239
|
+
/** Custom types for reference */
|
|
240
|
+
types: GraphQLTypeDef[]
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ============================================================================
|
|
244
|
+
// Helper Functions
|
|
245
|
+
// ============================================================================
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Format a GraphQL type reference as a string
|
|
249
|
+
* e.g., [String!]! -> "[String!]!"
|
|
250
|
+
*/
|
|
251
|
+
export function formatTypeRef(typeRef: GraphQLTypeRef): string {
|
|
252
|
+
if (typeRef.kind === 'NON_NULL' && typeRef.ofType) {
|
|
253
|
+
return `${formatTypeRef(typeRef.ofType)}!`
|
|
254
|
+
}
|
|
255
|
+
if (typeRef.kind === 'LIST' && typeRef.ofType) {
|
|
256
|
+
return `[${formatTypeRef(typeRef.ofType)}]`
|
|
257
|
+
}
|
|
258
|
+
return typeRef.name || 'Unknown'
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Check if a type is required (non-null at the top level)
|
|
263
|
+
*/
|
|
264
|
+
export function isTypeRequired(typeRef: GraphQLTypeRef): boolean {
|
|
265
|
+
return typeRef.kind === 'NON_NULL'
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Get the base type name from a type reference
|
|
270
|
+
*/
|
|
271
|
+
export function getBaseTypeName(typeRef: GraphQLTypeRef): string {
|
|
272
|
+
if (typeRef.ofType) {
|
|
273
|
+
return getBaseTypeName(typeRef.ofType)
|
|
274
|
+
}
|
|
275
|
+
return typeRef.name || 'Unknown'
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Check if a type is a scalar type
|
|
280
|
+
*/
|
|
281
|
+
export function isScalarType(typeName: string): boolean {
|
|
282
|
+
return ['String', 'Int', 'Float', 'Boolean', 'ID'].includes(typeName)
|
|
283
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# OpenAPI Parser
|
|
2
|
+
|
|
3
|
+
This directory contains the OpenAPI parsing logic ported from Hoppscotch.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
- `index.ts` - Main importer function
|
|
8
|
+
- `validator.ts` - OpenAPI validation logic
|
|
9
|
+
- `dereferencer.ts` - Reference resolution
|
|
10
|
+
- `transformer.ts` - OpenAPI → BrainfishCollection conversion
|
|
11
|
+
- `parsers/` - Version-specific parsers (v2, v3, v31)
|
|
12
|
+
- `extractors/` - Extraction functions (auth, params, headers, body, responses)
|
|
13
|
+
- `example-generators/` - Example generation from schemas
|
|
14
|
+
|
|
15
|
+
## Dependencies Required
|
|
16
|
+
|
|
17
|
+
Before implementing, install these dependencies:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @apidevtools/swagger-parser openapi-types js-yaml lodash-es
|
|
21
|
+
npm install -D @types/js-yaml @types/lodash-es
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Porting Strategy
|
|
25
|
+
|
|
26
|
+
1. Copy functions from Hoppscotch's `openapi/index.ts`
|
|
27
|
+
2. Replace `HoppCollection` → `BrainfishCollection`
|
|
28
|
+
3. Replace `HoppRESTRequest` → `BrainfishRESTRequest`
|
|
29
|
+
4. Replace `makeCollection` → `makeBrainfishCollection`
|
|
30
|
+
5. Replace `makeRESTRequest` → `makeBrainfishRESTRequest`
|
|
31
|
+
6. Convert fp-ts to native TypeScript (optional)
|
|
32
|
+
7. Convert Web Worker to Next.js API route or direct function calls
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI Dereferencer
|
|
3
|
+
*
|
|
4
|
+
* Ported from Hoppscotch's openapi-import-worker.ts
|
|
5
|
+
* Converts Web Worker pattern to direct function calls for Next.js
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import SwaggerParser from '@apidevtools/swagger-parser'
|
|
9
|
+
import type { OpenAPI } from 'openapi-types'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Dereferences all $ref references in an OpenAPI document
|
|
13
|
+
*
|
|
14
|
+
* @param docs - The OpenAPI document to dereference
|
|
15
|
+
* @returns Promise resolving to dereferenced OpenAPI document
|
|
16
|
+
* @throws Error if dereferencing fails
|
|
17
|
+
*/
|
|
18
|
+
export async function dereferenceOpenAPISpec(
|
|
19
|
+
docs: OpenAPI.Document
|
|
20
|
+
): Promise<OpenAPI.Document> {
|
|
21
|
+
try {
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
const dereferenced = await SwaggerParser.dereference(docs as any)
|
|
24
|
+
return dereferenced as OpenAPI.Document
|
|
25
|
+
} catch {
|
|
26
|
+
throw new Error('COULD_NOT_DEREFERENCE')
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Checks if a document has unresolved $ref references
|
|
32
|
+
*
|
|
33
|
+
* @param obj - The object to check
|
|
34
|
+
* @param visited - Set of visited objects to detect circular references
|
|
35
|
+
* @returns true if unresolved references are found
|
|
36
|
+
*/
|
|
37
|
+
export function hasUnresolvedRefs(
|
|
38
|
+
obj: unknown,
|
|
39
|
+
visited = new WeakSet()
|
|
40
|
+
): boolean {
|
|
41
|
+
// Handle non-objects or null
|
|
42
|
+
if (!obj || typeof obj !== 'object') return false
|
|
43
|
+
|
|
44
|
+
// Check for circular references
|
|
45
|
+
if (visited.has(obj)) return false
|
|
46
|
+
|
|
47
|
+
// Add current object to visited set
|
|
48
|
+
visited.add(obj)
|
|
49
|
+
|
|
50
|
+
// Check if current object has $ref property
|
|
51
|
+
if ('$ref' in obj && typeof obj.$ref === 'string') return true
|
|
52
|
+
|
|
53
|
+
// Check arrays
|
|
54
|
+
if (Array.isArray(obj)) {
|
|
55
|
+
return obj.some((item) => hasUnresolvedRefs(item, visited))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Check object properties
|
|
59
|
+
return Object.values(obj).some((value) => hasUnresolvedRefs(value, visited))
|
|
60
|
+
}
|