export & import in opencollection format#6329
Conversation
WalkthroughThis PR introduces comprehensive OpenCollection format support to Bruno, enabling users to export collections in OpenCollection format and import collections from OpenCollection files. Implementation spans UI components for export, new import/export pipelines, bidirectional converters in TypeScript, and build configuration updates. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant UI as ShareCollection<br/>Component
participant Redux as Redux Store
participant Exporter as OpenCollection<br/>Exporter
participant FS as FileSaver
User->>UI: Clicks "Export in OpenCollection format"
UI->>UI: Show loading spinner
UI->>Redux: Dispatch collection clone
Redux->>Exporter: Call exportCollection(collection)
Exporter->>Exporter: Convert to OpenCollection via<br/>brunoToOpenCollection()
Exporter->>Exporter: Serialize to YAML<br/>(indent: 2, no refs, sorted keys)
Exporter->>FS: Blob + sanitized filename
FS->>FS: saveAs() download
Exporter-->>Redux: Complete
Redux-->>UI: Hide loading, close modal
UI-->>User: File downloaded
sequenceDiagram
actor User
participant UI as ImportCollection<br/>Location
participant Importer as OpenCollection<br/>Processor
participant Converter as openCollectionToBruno<br/>Converter
participant Schema as Bruno Schema<br/>Validator
User->>UI: Select OpenCollection file
UI->>UI: Detect format via isOpenCollection()
UI->>Importer: processOpenCollection(jsonData)
Importer->>Converter: openCollectionToBruno(data)
Converter->>Converter: Map items (HTTP/GraphQL/<br/>gRPC/WebSocket/Folders)
Converter->>Converter: Convert environments,<br/>auth, scripts, variables
Converter->>Schema: Validate against<br/>BrunoCollection schema
Schema-->>Converter: Valid ✓
Converter-->>Importer: BrunoCollection
Importer->>Importer: Hydrate sequences,<br/>augment UIDs
Importer-->>UI: Finalized collection
UI-->>User: Collection imported
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Multiple interdependent TypeScript converter modules with dense type-safe logic, rollup/TypeScript build configuration changes, and integration across two packages requiring careful tracing of conversion flows. Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (5)
packages/bruno-app/src/utils/exporters/opencollection.js (2)
750-757: Dead code:config.environmentsdeletion is unreachable.
transformConfignever creates anenvironmentsproperty, so this check and deletion will never execute.const config = transformConfig(collection.brunoConfig); if (config) { openCollection.config = config; - - if (config.environments) { - delete config.environments; - } }
797-811: Sanitize filename to prevent issues with special characters.
collection.namecould contain characters invalid for filenames (e.g.,/,\,:). Consider sanitizing before use.+const sanitizeFilename = (name) => { + return (name || 'collection').replace(/[/\\:*?"<>|]/g, '_'); +}; + export const exportCollection = (collection) => { const openCollection = brunoToOpenCollection(collection); const yamlContent = jsyaml.dump(openCollection, { indent: 2, lineWidth: -1, noRefs: true, sortKeys: false }); - const fileName = `${collection.name}.yml`; + const fileName = `${sanitizeFilename(collection.name)}.yml`; const fileBlob = new Blob([yamlContent], { type: 'application/x-yaml' }); FileSaver.saveAs(fileBlob, fileName); };packages/bruno-app/src/utils/importers/opencollection.js (3)
280-292: Minor edge case: array values.Line 286 uses
typeof v.value === 'object'which is also true for arrays. Ifv.valuewere an array, accessing.datawould returnundefined, falling back to''. This works but relies on implicit behavior.If arrays are never expected here, consider adding explicit handling for clarity:
- value: typeof v.value === 'object' ? v.value.data || '' : v.value || '', + value: typeof v.value === 'object' && v.value !== null && !Array.isArray(v.value) ? v.value.data || '' : v.value || '',
605-628: Redundant condition.Line 605: The
&& config.proxy !== falsecheck is redundant sinceconfig.proxybeingfalsewould already fail the first condition.- if (config.proxy && config.proxy !== false) { + if (config.proxy) {That said, if the explicit intent is to document that
falseis a valid sentinel value in OpenCollection, keeping it is acceptable for readability.
740-752: Original error context lost in BrunoError.The catch block logs the original error but throws a generic
BrunoErrorwithout the original message or cause. This can make debugging import failures difficult.Consider including the original error message:
} catch (err) { console.error('Error processing OpenCollection:', err); - throw new BrunoError('Import OpenCollection failed'); + throw new BrunoError(`Import OpenCollection failed: ${err.message}`); }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
packages/bruno-app/src/components/ShareCollection/index.js(3 hunks)packages/bruno-app/src/components/Sidebar/ImportCollection/index.js(3 hunks)packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js(3 hunks)packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js(1 hunks)packages/bruno-app/src/utils/exporters/opencollection.js(1 hunks)packages/bruno-app/src/utils/importers/opencollection.js(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CODING_STANDARDS.md)
**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions.() => {}is good
No space between function name and parentheses.func()notfunc ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly
Files:
packages/bruno-app/src/utils/exporters/opencollection.jspackages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.jspackages/bruno-app/src/utils/importers/opencollection.jspackages/bruno-app/src/components/ShareCollection/index.jspackages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.jspackages/bruno-app/src/components/Sidebar/ImportCollection/index.js
🧬 Code graph analysis (5)
packages/bruno-app/src/utils/exporters/opencollection.js (1)
packages/bruno-app/src/utils/importers/opencollection.js (8)
transformItem(532-554)transformFolder(491-530)transformItems(556-560)transformEnvironments(562-575)root(658-658)brunoConfig(578-583)config(585-585)collection(742-742)
packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js (1)
packages/bruno-app/src/utils/importers/opencollection.js (3)
collection(742-742)processOpenCollection(740-752)processOpenCollection(740-752)
packages/bruno-app/src/utils/importers/opencollection.js (2)
packages/bruno-app/src/utils/exporters/opencollection.js (20)
auth(324-324)auth(423-423)auth(481-481)auth(536-536)auth(592-592)auth(657-657)headers(315-315)headers(410-410)headers(514-514)headers(591-591)headers(654-654)params(318-318)params(413-413)body(321-321)variables(330-330)variables(429-429)variables(487-487)variables(542-542)variables(594-594)variables(660-660)packages/bruno-app/src/utils/common/error.js (1)
BrunoError(4-10)
packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js (1)
packages/bruno-app/src/utils/importers/opencollection.js (3)
processOpenCollection(740-752)processOpenCollection(740-752)collection(742-742)
packages/bruno-app/src/components/Sidebar/ImportCollection/index.js (1)
packages/bruno-app/src/utils/importers/opencollection.js (2)
isOpenCollection(754-768)isOpenCollection(754-768)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: SSL Tests - Windows
- GitHub Check: SSL Tests - macOS
- GitHub Check: SSL Tests - Linux
- GitHub Check: Playwright E2E Tests
- GitHub Check: Unit Tests
- GitHub Check: CLI Tests
🔇 Additional comments (24)
packages/bruno-app/src/utils/exporters/opencollection.js (5)
4-66: LGTM on auth transformation.Comprehensive handling of all auth modes including basic, bearer, digest, NTLM, AWS v4, API key, WSSE, and OAuth2. The early returns for
noneandinheritmodes are clean.
68-176: OAuth2 transformation covers all standard grant types.Good coverage of client_credentials, password, authorization_code, and implicit flows with proper token configuration mapping.
178-251: Clean header, param, and body transformers.Appropriate use of spread for optional properties. The body transformer handles all Bruno body modes including GraphQL bodies correctly.
304-397: HTTP request transformation is thorough.Includes examples transformation with proper request/response mapping. All optional fields are conditionally added.
556-576: Verify item type mapping consistency with importer.The switch cases use Bruno's internal types (
http-request,graphql-request, etc.) while the transformation functions output OpenCollection types. Confirm the importer'stransformItemcorrectly reverses this mapping (e.g.,http→http-request).packages/bruno-app/src/components/Sidebar/ImportCollection/index.js (3)
11-11: LGTM on import addition.Correct import path for the new OpenCollection validator.
76-77: Detection order is appropriate.OpenCollection is checked after more specific formats (OpenAPI, WSDL, Postman, Insomnia) but before Bruno's native format. Since
isOpenCollectionchecks for theopencollectionversion string property, this ordering prevents false positives.
165-165: Help text updated correctly.Users are now informed that OpenCollection format is supported alongside other formats.
packages/bruno-app/src/components/Sidebar/ImportCollectionLocation/index.js (3)
11-11: LGTM on import.
40-41: Collection name extraction follows existing patterns.Correctly accesses
info.namewith fallback to 'OpenCollection', consistent with other formats.
70-72: Conversion case correctly uses async processor.
processOpenCollectionhandles schema validation, UID hydration, and sequence numbering per the relevant snippet.packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js (1)
37-40: LGTM on Redux action handler.Follows established dynamic import pattern for code splitting, consistent with other collection types.
packages/bruno-app/src/components/ShareCollection/index.js (3)
3-3: LGTM on new imports.
IconFileExportis appropriate for a generic export action, differentiating from Bruno's logo and Postman's download icon.Also applies to: 8-8
52-56: Export handler follows established pattern.Uses
transformCollectionToSaveToExportAsFilelike Bruno export, ensuring consistent data preparation.
86-105: OpenCollection export UI is well-integrated.No warning banner needed here since OpenCollection format supports gRPC and WebSocket requests (unlike Postman). Loading states and click handlers mirror existing export options.
packages/bruno-app/src/utils/importers/opencollection.js (9)
1-4: LGTM!Imports are clean and all are utilized throughout the file.
6-196: LGTM!Auth transformation covers all expected types including comprehensive OAuth2 flow handling. The nested helper functions for token/credentials placement are cleanly encapsulated.
318-394: LGTM!HTTP and GraphQL item transformers are thorough. Examples handling correctly maps both request and response data. Default method for GraphQL being 'POST' is appropriate.
396-489: LGTM!gRPC and WebSocket transformers handle both single-message and multi-message formats gracefully. Using
metadatafor gRPC headers is the correct OpenCollection convention.
532-560: LGTM!The
transformItemswitch handles all expected types and gracefully returnsnullfor unknown types, whichtransformItemsfilters out. Clean recursive pattern for nested structures.
562-575: LGTM!Environment transformation correctly maps OpenCollection's
transientproperty to Bruno'ssecretfield.
681-692: LGTM!
openCollectionToBrunocleanly orchestrates the conversion by delegating to specialized transform functions. Good separation of concerns.
694-738: LGTM!Recursive UID assignment for root and nested folder roots is correct. The mutation pattern is consistent with the related
updateUidsInCollectionutility.
754-768: LGTM!
isOpenCollectionprovides robust structural validation for format detection. The checks for requiredopencollectionstring andinfoobject are appropriate guards.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
packages/bruno-app/src/utils/importers/opencollection.js (2)
7-51: Consider extracting duplicate UID assignment logic.The UID assignment for
headers,vars.req, andvars.resis duplicated between the collection root (lines 8-22) and folder roots (lines 27-41). A small helper would reduce repetition.🔎 Proposed refactor
+const assignUidsToRootRequest = (root) => { + if (root?.request?.headers) { + each(root.request.headers, (header) => { + header.uid = uuid(); + }); + } + if (root?.request?.vars?.req) { + each(root.request.vars.req, (v) => { + v.uid = uuid(); + }); + } + if (root?.request?.vars?.res) { + each(root.request.vars.res, (v) => { + v.uid = uuid(); + }); + } +}; + const addUidsToRoot = (collection) => { - if (collection.root?.request?.headers) { - each(collection.root.request.headers, (header) => { - header.uid = uuid(); - }); - } - // ... similar blocks + assignUidsToRootRequest(collection.root); const addUidsToFolderRoot = (items) => { each(items, (item) => { if (item.type === 'folder') { - // ... duplicated logic + assignUidsToRootRequest(item.root); if (item.items?.length) { addUidsToFolderRoot(item.items); } } }); }; // ... };
61-64: Preserve original error context in the thrown error.The original error message is logged but lost when re-throwing. Including it aids debugging.
🔎 Proposed fix
} catch (err) { console.error('Error processing OpenCollection:', err); - throw new BrunoError('Import OpenCollection failed'); + throw new BrunoError(`Import OpenCollection failed: ${err.message}`); }packages/bruno-app/src/utils/opencollection/stringifyBundledCollection.js (2)
326-330: Consider addingnameandseqto script items.Script items lose their
nameandseqproperties during serialization, which may affect ordering or identification on re-import.🔎 Proposed fix
case 'js': return { type: 'script', + ...(item.name && { name: item.name }), + ...(item.seq && { seq: item.seq }), script: item.fileContent || item.raw || '' };
461-468: Dead code:config.environmentsis never set bystringifyConfig.The deletion at line 466 is unnecessary since
stringifyConfigdoesn't addenvironmentsto the config object.🔎 Proposed fix
const config = stringifyConfig(collection.brunoConfig); if (config) { openCollection.config = config; - - if (config.environments) { - delete config.environments; - } }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
packages/bruno-app/src/utils/exporters/opencollection.jspackages/bruno-app/src/utils/importers/opencollection.jspackages/bruno-app/src/utils/opencollection/common/assertions.jspackages/bruno-app/src/utils/opencollection/common/auth.jspackages/bruno-app/src/utils/opencollection/common/body.jspackages/bruno-app/src/utils/opencollection/common/headers.jspackages/bruno-app/src/utils/opencollection/common/index.jspackages/bruno-app/src/utils/opencollection/common/params.jspackages/bruno-app/src/utils/opencollection/common/scripts.jspackages/bruno-app/src/utils/opencollection/common/variables.jspackages/bruno-app/src/utils/opencollection/index.jspackages/bruno-app/src/utils/opencollection/parseBundledCollection.jspackages/bruno-app/src/utils/opencollection/stringifyBundledCollection.js
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CODING_STANDARDS.md)
**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions.() => {}is good
No space between function name and parentheses.func()notfunc ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly
Files:
packages/bruno-app/src/utils/opencollection/parseBundledCollection.jspackages/bruno-app/src/utils/opencollection/common/scripts.jspackages/bruno-app/src/utils/opencollection/common/assertions.jspackages/bruno-app/src/utils/opencollection/common/variables.jspackages/bruno-app/src/utils/opencollection/index.jspackages/bruno-app/src/utils/opencollection/stringifyBundledCollection.jspackages/bruno-app/src/utils/importers/opencollection.jspackages/bruno-app/src/utils/opencollection/common/headers.jspackages/bruno-app/src/utils/opencollection/common/params.jspackages/bruno-app/src/utils/opencollection/common/body.jspackages/bruno-app/src/utils/opencollection/common/index.jspackages/bruno-app/src/utils/opencollection/common/auth.jspackages/bruno-app/src/utils/exporters/opencollection.js
🧠 Learnings (3)
📚 Learning: 2025-12-16T07:16:23.647Z
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.
Applied to files:
packages/bruno-app/src/utils/opencollection/parseBundledCollection.jspackages/bruno-app/src/utils/opencollection/common/scripts.jspackages/bruno-app/src/utils/opencollection/common/assertions.jspackages/bruno-app/src/utils/opencollection/stringifyBundledCollection.jspackages/bruno-app/src/utils/importers/opencollection.jspackages/bruno-app/src/utils/opencollection/common/index.jspackages/bruno-app/src/utils/exporters/opencollection.js
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.
Applied to files:
packages/bruno-app/src/utils/opencollection/parseBundledCollection.jspackages/bruno-app/src/utils/opencollection/common/scripts.jspackages/bruno-app/src/utils/opencollection/common/assertions.jspackages/bruno-app/src/utils/opencollection/common/variables.jspackages/bruno-app/src/utils/opencollection/index.jspackages/bruno-app/src/utils/opencollection/stringifyBundledCollection.jspackages/bruno-app/src/utils/importers/opencollection.jspackages/bruno-app/src/utils/opencollection/common/headers.jspackages/bruno-app/src/utils/opencollection/common/params.jspackages/bruno-app/src/utils/opencollection/common/body.jspackages/bruno-app/src/utils/opencollection/common/index.jspackages/bruno-app/src/utils/opencollection/common/auth.jspackages/bruno-app/src/utils/exporters/opencollection.js
📚 Learning: 2025-12-02T07:24:50.311Z
Learnt from: bijin-bruno
Repo: usebruno/bruno PR: 6263
File: packages/bruno-requests/src/auth/oauth2-helper.ts:249-249
Timestamp: 2025-12-02T07:24:50.311Z
Learning: In OAuth2 Basic Auth headers for Bruno, clientSecret is optional and can be omitted. When constructing the Authorization header in `packages/bruno-requests/src/auth/oauth2-helper.ts`, use `clientSecret || ''` instead of `clientSecret!` to properly handle cases where only clientId is provided, per community requests.
Applied to files:
packages/bruno-app/src/utils/opencollection/common/headers.jspackages/bruno-app/src/utils/opencollection/common/index.jspackages/bruno-app/src/utils/opencollection/common/auth.js
🧬 Code graph analysis (9)
packages/bruno-app/src/utils/opencollection/parseBundledCollection.js (5)
packages/bruno-app/src/utils/opencollection/common/headers.js (2)
toBrunoHeaders(3-13)toBrunoHeaders(3-13)packages/bruno-app/src/utils/opencollection/common/params.js (2)
toBrunoParams(3-14)toBrunoParams(3-14)packages/bruno-app/src/utils/opencollection/common/body.js (2)
toBrunoBody(3-63)toBrunoBody(3-63)packages/bruno-app/src/utils/opencollection/common/auth.js (2)
toBrunoAuth(115-191)toBrunoAuth(115-191)packages/bruno-app/src/utils/opencollection/common/variables.js (2)
toBrunoVariables(3-16)toBrunoVariables(3-16)
packages/bruno-app/src/utils/opencollection/common/assertions.js (1)
packages/bruno-app/src/utils/opencollection/stringifyBundledCollection.js (3)
assertions(40-40)assertions(139-139)assertions(203-203)
packages/bruno-app/src/utils/opencollection/stringifyBundledCollection.js (7)
packages/bruno-app/src/utils/opencollection/common/headers.js (2)
toOpenCollectionHeaders(15-24)toOpenCollectionHeaders(15-24)packages/bruno-app/src/utils/opencollection/common/params.js (2)
toOpenCollectionParams(16-26)toOpenCollectionParams(16-26)packages/bruno-app/src/utils/opencollection/common/body.js (2)
toOpenCollectionBody(65-115)toOpenCollectionBody(65-115)packages/bruno-app/src/utils/opencollection/common/auth.js (2)
toOpenCollectionAuth(301-363)toOpenCollectionAuth(301-363)packages/bruno-app/src/utils/opencollection/common/scripts.js (3)
scripts(15-15)toOpenCollectionScripts(14-28)toOpenCollectionScripts(14-28)packages/bruno-app/src/utils/opencollection/common/variables.js (2)
toOpenCollectionVariables(18-28)toOpenCollectionVariables(18-28)packages/bruno-app/src/utils/opencollection/common/assertions.js (2)
toOpenCollectionAssertions(15-25)toOpenCollectionAssertions(15-25)
packages/bruno-app/src/utils/importers/opencollection.js (2)
packages/bruno-app/src/utils/opencollection/parseBundledCollection.js (2)
parseBundledCollection(387-398)parseBundledCollection(387-398)packages/bruno-app/src/utils/common/error.js (1)
BrunoError(4-10)
packages/bruno-app/src/utils/opencollection/common/headers.js (1)
packages/bruno-app/src/utils/opencollection/stringifyBundledCollection.js (5)
headers(22-22)headers(117-117)headers(227-227)headers(282-282)headers(365-365)
packages/bruno-app/src/utils/opencollection/common/params.js (1)
packages/bruno-app/src/utils/opencollection/stringifyBundledCollection.js (2)
params(25-25)params(120-120)
packages/bruno-app/src/utils/opencollection/common/body.js (1)
packages/bruno-app/src/utils/opencollection/stringifyBundledCollection.js (1)
body(28-28)
packages/bruno-app/src/utils/opencollection/common/auth.js (2)
packages/bruno-app/src/utils/opencollection/stringifyBundledCollection.js (6)
auth(31-31)auth(130-130)auth(194-194)auth(249-249)auth(283-283)auth(368-368)packages/bruno-electron/src/utils/oauth2.js (1)
oauth2(732-741)
packages/bruno-app/src/utils/exporters/opencollection.js (1)
packages/bruno-app/src/utils/opencollection/stringifyBundledCollection.js (3)
stringifyBundledCollection(453-506)stringifyBundledCollection(453-506)openCollection(454-459)
🔇 Additional comments (24)
packages/bruno-app/src/utils/opencollection/common/variables.js (1)
1-28: LGTM!Clean bidirectional variable transformers with proper handling of object-typed values and appropriate default fallbacks.
packages/bruno-app/src/utils/opencollection/index.js (1)
1-3: LGTM!Clean barrel export consolidating the OpenCollection utilities.
packages/bruno-app/src/utils/opencollection/common/scripts.js (1)
1-28: LGTM!Script transformers are correctly implemented. The asymmetry where
toOpenCollectionScriptshandlestestsbuttoBrunoScriptsdoesn't is intentional—tests are extracted separately inparseBundledCollectionviaitem.scripts?.tests.packages/bruno-app/src/utils/opencollection/common/headers.js (1)
1-24: LGTM!Consistent header transformers matching the pattern of other converters.
packages/bruno-app/src/utils/opencollection/common/params.js (1)
1-26: LGTM!Clean param transformers with proper type preservation.
packages/bruno-app/src/utils/opencollection/parseBundledCollection.js (5)
193-233: Mutual recursion betweenparseFolderandparseItemsis safe.
parseFolder(Line 229) callsparseItemswhich is defined later at Line 260. This works because:
- Both are
constarrow functions- The entry point is
parseBundledCollection(Line 387), which runs after all declarations- By execution time,
parseItemsis initializedNo issues here—just noting for clarity.
12-91: LGTM!HTTP and GraphQL parsers correctly utilize the common helpers with appropriate fallbacks. The example parsing logic handles nested request/response structures well.
93-191: LGTM!gRPC and WebSocket parsers handle message variations correctly. Using
item.metadatafor gRPC headers follows the gRPC convention.
235-281: LGTM!Item dispatcher and environment parser are well-structured. The
transient→secretmapping for environment variables is a reasonable semantic translation.
283-398: LGTM!Config and collection root parsers are comprehensive, covering protobuf, proxy configurations, client certificates, and collection metadata.
packages/bruno-app/src/utils/importers/opencollection.js (1)
67-81: LGTM!The structural validation is defensive and correctly handles null/non-object inputs. The checks for
opencollectionandinfoproperties are appropriate.packages/bruno-app/src/utils/opencollection/stringifyBundledCollection.js (6)
11-104: LGTM!The HTTP request serialization is comprehensive, handling all request components including examples with their request/response pairs. The conditional field inclusion pattern is clean.
106-151: LGTM!GraphQL request serialization correctly handles the specific body structure with
queryandvariablesfields.
153-215: LGTM!gRPC request serialization handles the protocol-specific fields well, including the metadata transformation and message array handling.
217-267: LGTM!WebSocket serialization is consistent with the pattern and correctly handles the message structure variants.
269-312: LGTM!Folder serialization handles nested items recursively and correctly wraps documentation with the expected type.
453-506: LGTM!The main
stringifyBundledCollectionfunction correctly assembles the OpenCollection structure with proper handling of config, environments, items, request defaults, docs, and extensions.packages/bruno-app/src/utils/opencollection/common/index.js (1)
1-7: LGTM!Clean barrel file providing a single entry point for all common transformation utilities.
packages/bruno-app/src/utils/opencollection/common/body.js (2)
3-63: LGTM!The
toBrunoBodyfunction correctly handles all body types with appropriate UID generation for form fields. The GraphQL special handling viarequestTypeparameter is a clean approach.
65-115: LGTM!The
toOpenCollectionBodyfunction correctly reverses the transformation, stripping UIDs and using conditional spread for optional fields. The GraphQL body structure is intentionally different from other modes.packages/bruno-app/src/utils/opencollection/common/auth.js (4)
1-113: LGTM!The
fromOpenCollectionOAuth2function comprehensively handles all four OAuth2 grant types with proper extraction of token placement, credentials placement, and lifecycle settings.
115-191: LGTM!The
toBrunoAuthfunction cleanly handles all authentication types with consistent structure and appropriate delegation to the OAuth2 handler.
301-363: LGTM!The
toOpenCollectionAuthfunction correctly converts Bruno auth structures to OpenCollection format with proper handling of all authentication modes.
263-263: No action needed. Bruno's OAuth2 schema stores PKCE as a boolean flag only (pkce?: boolean | null;), with no support for multiple PKCE methods. The hardcoding to 'S256' at this line is intentional and correct—there is no method field to lose during export.Likely an incorrect or invalid review comment.
packages/bruno-app/src/utils/opencollection/common/assertions.js
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 7
♻️ Duplicate comments (1)
packages/bruno-app/src/utils/exporters/opencollection.js (1)
19-19: Sanitize collection name for safe filename usage.
collection.namemay contain characters invalid for filenames (e.g.,/,\,:,*). This could cause unexpected behavior or failures depending on the OS/browser.🔎 Proposed fix
- const fileName = `${collection.name}.yml`; + const sanitizedName = (collection.name || 'collection').replace(/[/\\:*?"<>|]/g, '_'); + const fileName = `${sanitizedName}.yml`;
🧹 Nitpick comments (8)
packages/bruno-converters/rollup.config.js (1)
7-7: Consider usingnode:prefix for built-in modules.For consistency with
postman-translator-worker.jsand modern Node.js conventions, userequire('node:path')instead ofrequire('path'). This clarifies that it's a built-in module and prevents potential conflicts with user-land packages.🔎 Proposed change
-const path = require('path'); +const path = require('node:path');packages/bruno-converters/src/opencollection/folder.ts (1)
90-90: Avoid type cast toany.The type assertion
as anybypasses TypeScript's type checking when callingtoOpenCollectionScripts. This suggests a type mismatch betweenfolderRequestand the expectedBrunoRequestparameter.Consider defining a proper type or interface that encompasses both request types to avoid the escape hatch.
🔎 Proposed approach
Define a union type or adjust the
toOpenCollectionScriptssignature to accept bothBrunoRequestand the folder request shape, or create a helper type that explicitly models the shared fields:type RequestLike = { script?: BrunoScript | null; tests?: string | null; }; // Then update toOpenCollectionScripts signature: export const toOpenCollectionScripts = (request: RequestLike | null | undefined): Scripts | undefined => { // ... }packages/bruno-converters/src/opencollection/common/headers.ts (1)
21-44: Minor: Redundant empty check on line 43.The early return on lines 22-24 guarantees
headersis non-empty, soocHeaderswill always have at least one element. The check on line 43 is technically redundant but doesn't cause issues.🔎 Optional simplification
- return ocHeaders.length ? ocHeaders : undefined; + return ocHeaders;packages/bruno-converters/src/opencollection/items/graphql.ts (1)
29-85: Consider reducing repetition in settings assignment.Lines 63-78 repeat the same pattern four times. Could be consolidated for maintainability.
🔎 Optional: Consolidate settings assignment
- if (settings.encodeUrl !== undefined) { - brunoItem.settings = brunoItem.settings || {}; - (brunoItem.settings as any).encodeUrl = settings.encodeUrl; - } - if (settings.timeout !== undefined) { - brunoItem.settings = brunoItem.settings || {}; - (brunoItem.settings as any).timeout = settings.timeout; - } - if (settings.followRedirects !== undefined) { - brunoItem.settings = brunoItem.settings || {}; - (brunoItem.settings as any).followRedirects = settings.followRedirects; - } - if (settings.maxRedirects !== undefined) { - brunoItem.settings = brunoItem.settings || {}; - (brunoItem.settings as any).maxRedirects = settings.maxRedirects; - } + const settingsKeys = ['encodeUrl', 'timeout', 'followRedirects', 'maxRedirects'] as const; + settingsKeys.forEach((key) => { + if (settings[key] !== undefined) { + brunoItem.settings = brunoItem.settings || {}; + (brunoItem.settings as any)[key] = settings[key]; + } + });packages/bruno-converters/src/opencollection/items/websocket.ts (1)
59-62: Type casts toanyfor ws body mode.The casts on lines 60-61 suggest
BrunoItemtypes may not fully support the ws body structure. Consider extending the type definitions to avoid runtime type erosion.packages/bruno-converters/src/opencollection/common/body.ts (1)
93-99: Consider extracting description and disabled field handling into a helper.The logic for handling
description(string vs object with content) andenabled/disabledflags is repeated across multiple body types (form-urlencoded, multipart-form). This pattern appears in both conversion directions.🔎 Proposed helper to reduce duplication
const mapDescription = (description: string | { content: string } | undefined): string | null => { if (!description) return null; return typeof description === 'string' ? description : description.content || null; }; const shouldIncludeDescription = (description: string | null | undefined): boolean => { return !!(description && typeof description === 'string' && description.trim().length); };Then use in conversions:
formUrlEncoded: (formBody.data || []).map((field): BrunoKeyValue => ({ uid: uuid(), name: field.name || '', value: field.value || '', - description: typeof field.description === 'string' ? field.description : field.description?.content || null, + description: mapDescription(field.description), enabled: field.disabled !== true }))Also applies to: 108-116, 158-173, 179-195
packages/bruno-converters/src/opencollection/items/http.ts (2)
70-85: Reduce repetitive settings assignment with a helper.Lines 70-85 repeat the same pattern four times for different settings properties. This duplication makes the code harder to maintain.
🔎 Proposed refactor using a loop
+ const settingsToMap = [ + 'encodeUrl', + 'timeout', + 'followRedirects', + 'maxRedirects' + ] as const; + + settingsToMap.forEach((key) => { + if (settings[key] !== undefined) { + brunoItem.settings = brunoItem.settings || {}; + (brunoItem.settings as any)[key] = settings[key]; + } + }); - - if (settings.encodeUrl !== undefined) { - brunoItem.settings = brunoItem.settings || {}; - (brunoItem.settings as any).encodeUrl = settings.encodeUrl; - } - if (settings.timeout !== undefined) { - brunoItem.settings = brunoItem.settings || {}; - (brunoItem.settings as any).timeout = settings.timeout; - } - if (settings.followRedirects !== undefined) { - brunoItem.settings = brunoItem.settings || {}; - (brunoItem.settings as any).followRedirects = settings.followRedirects; - } - if (settings.maxRedirects !== undefined) { - brunoItem.settings = brunoItem.settings || {}; - (brunoItem.settings as any).maxRedirects = settings.maxRedirects; - }
184-189: Simplify default settings assignment.Lines 184-189 use ternary operators for each setting. Consider using the nullish coalescing operator (
??) for cleaner, more concise code.🔎 Proposed simplification
ocRequest.settings = { - encodeUrl: brunoSettings.encodeUrl !== undefined ? brunoSettings.encodeUrl : true, - timeout: brunoSettings.timeout !== undefined ? brunoSettings.timeout : 0, - followRedirects: brunoSettings.followRedirects !== undefined ? brunoSettings.followRedirects : true, - maxRedirects: brunoSettings.maxRedirects !== undefined ? brunoSettings.maxRedirects : 5 + encodeUrl: brunoSettings.encodeUrl ?? true, + timeout: brunoSettings.timeout ?? 0, + followRedirects: brunoSettings.followRedirects ?? true, + maxRedirects: brunoSettings.maxRedirects ?? 5 };
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (25)
packages/bruno-app/src/utils/exporters/opencollection.jspackages/bruno-app/src/utils/importers/opencollection.jspackages/bruno-converters/package.jsonpackages/bruno-converters/rollup.config.jspackages/bruno-converters/src/index.jspackages/bruno-converters/src/opencollection/collection.tspackages/bruno-converters/src/opencollection/common/assertions.tspackages/bruno-converters/src/opencollection/common/auth.tspackages/bruno-converters/src/opencollection/common/body.tspackages/bruno-converters/src/opencollection/common/headers.tspackages/bruno-converters/src/opencollection/common/index.tspackages/bruno-converters/src/opencollection/common/params.tspackages/bruno-converters/src/opencollection/common/scripts.tspackages/bruno-converters/src/opencollection/common/variables.tspackages/bruno-converters/src/opencollection/environment.tspackages/bruno-converters/src/opencollection/folder.tspackages/bruno-converters/src/opencollection/index.tspackages/bruno-converters/src/opencollection/items/graphql.tspackages/bruno-converters/src/opencollection/items/grpc.tspackages/bruno-converters/src/opencollection/items/http.tspackages/bruno-converters/src/opencollection/items/index.tspackages/bruno-converters/src/opencollection/items/websocket.tspackages/bruno-converters/src/opencollection/types.tspackages/bruno-converters/src/wsdl/wsdl-to-bruno.jspackages/bruno-converters/tsconfig.json
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/bruno-app/src/utils/importers/opencollection.js
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CODING_STANDARDS.md)
**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions.() => {}is good
No space between function name and parentheses.func()notfunc ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly
Files:
packages/bruno-converters/src/opencollection/common/params.tspackages/bruno-converters/src/opencollection/common/headers.tspackages/bruno-converters/src/index.jspackages/bruno-converters/src/opencollection/common/index.tspackages/bruno-converters/src/wsdl/wsdl-to-bruno.jspackages/bruno-converters/src/opencollection/common/body.tspackages/bruno-converters/src/opencollection/folder.tspackages/bruno-converters/src/opencollection/items/websocket.tspackages/bruno-converters/src/opencollection/items/graphql.tspackages/bruno-converters/src/opencollection/common/auth.tspackages/bruno-converters/src/opencollection/collection.tspackages/bruno-converters/src/opencollection/common/variables.tspackages/bruno-converters/src/opencollection/items/grpc.tspackages/bruno-converters/src/opencollection/common/assertions.tspackages/bruno-converters/src/opencollection/common/scripts.tspackages/bruno-converters/src/opencollection/environment.tspackages/bruno-converters/rollup.config.jspackages/bruno-converters/src/opencollection/items/http.tspackages/bruno-converters/src/opencollection/index.tspackages/bruno-app/src/utils/exporters/opencollection.jspackages/bruno-converters/src/opencollection/items/index.tspackages/bruno-converters/src/opencollection/types.ts
🧠 Learnings (5)
📓 Common learnings
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.
📚 Learning: 2025-12-16T07:16:23.647Z
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.
Applied to files:
packages/bruno-converters/src/index.jspackages/bruno-converters/src/opencollection/collection.tspackages/bruno-converters/src/opencollection/index.tspackages/bruno-app/src/utils/exporters/opencollection.js
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.
Applied to files:
packages/bruno-converters/src/index.jspackages/bruno-converters/src/wsdl/wsdl-to-bruno.jspackages/bruno-converters/rollup.config.jspackages/bruno-app/src/utils/exporters/opencollection.js
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : No trailing commas
Applied to files:
packages/bruno-converters/tsconfig.json
📚 Learning: 2025-12-02T07:24:50.311Z
Learnt from: bijin-bruno
Repo: usebruno/bruno PR: 6263
File: packages/bruno-requests/src/auth/oauth2-helper.ts:249-249
Timestamp: 2025-12-02T07:24:50.311Z
Learning: In OAuth2 Basic Auth headers for Bruno, clientSecret is optional and can be omitted. When constructing the Authorization header in `packages/bruno-requests/src/auth/oauth2-helper.ts`, use `clientSecret || ''` instead of `clientSecret!` to properly handle cases where only clientId is provided, per community requests.
Applied to files:
packages/bruno-converters/src/opencollection/common/auth.ts
🧬 Code graph analysis (4)
packages/bruno-converters/src/opencollection/common/headers.ts (3)
packages/bruno-converters/src/opencollection/common/index.ts (2)
fromOpenCollectionHeaders(2-2)toOpenCollectionHeaders(2-2)packages/bruno-converters/src/opencollection/index.ts (2)
fromOpenCollectionHeaders(23-23)toOpenCollectionHeaders(24-24)packages/bruno-converters/src/opencollection/types.ts (1)
HttpRequestHeader(13-13)
packages/bruno-converters/rollup.config.js (2)
scripts/setup.js (2)
require(1-1)path(3-3)packages/bruno-converters/src/workers/postman-translator-worker.js (1)
path(2-2)
packages/bruno-app/src/utils/exporters/opencollection.js (1)
packages/bruno-converters/src/opencollection/collection.ts (1)
toOpenCollection(289-358)
packages/bruno-converters/src/opencollection/items/index.ts (1)
packages/bruno-converters/src/opencollection/types.ts (11)
Item(5-5)Item(103-103)Folder(5-5)HttpRequest(9-9)HttpRequest(143-143)GraphQLRequest(34-34)GrpcRequest(45-45)GrpcRequest(150-150)WebSocketRequest(57-57)WebSocketRequest(156-156)ScriptFile(5-5)
🪛 GitHub Actions: SSL Tests
packages/bruno-converters/package.json
[warning] 1-1: EBADENGINE Unsupported engine: current node 'v22.17.0' (npm '10.9.2') does not satisfy package requirement for 'httpsnippet@3.0.9' (required: ^14.19.1 || ^16.14.2 || ^18.0.0 || ^20.0.0).
🔇 Additional comments (36)
packages/bruno-converters/src/wsdl/wsdl-to-bruno.js (1)
11-11: Remove unusedfilterimport from lodash.The
filterfunction is not used in this file, so removing it from the import statement is correct and reduces unnecessary dependencies.import { get, each } from 'lodash';packages/bruno-converters/rollup.config.js (1)
34-87: TypeScript integration and dual build structure look solid.The refactored build configuration properly supports TypeScript compilation with dual CJS/ESM output. Key improvements:
- Output directories correctly derived from package.json
- TypeScript plugin properly configured with source maps
- Node resolver includes TypeScript extensions
- External dependencies properly excluded from both builds
- Consistent structure across both configurations
packages/bruno-converters/src/opencollection/common/params.ts (2)
8-21: LGTM!The
fromOpenCollectionParamsfunction handles edge cases well, including optional arrays, description as string or object, and proper enabled/disabled flag mapping.
23-47: LGTM!The
toOpenCollectionParamsfunction correctly omits empty/undefined results and conditionally includes description and disabled flags only when necessary, keeping the output lean.packages/bruno-app/src/utils/exporters/opencollection.js (2)
5-7: LGTM!The
brunoToOpenCollectionwrapper provides a clean delegation to the converter package.
12-17: LGTM!The YAML serialization options are appropriate:
indent: 2for readability,lineWidth: -1to avoid line wrapping,noRefs: trueto prevent reference cycles, andsortKeys: falseto preserve declaration order.packages/bruno-converters/src/opencollection/common/scripts.ts (2)
12-37: LGTM!The
fromOpenCollectionScriptsfunction correctly maps OpenCollection script types to Bruno's internal structure with appropriate defaults.
44-64: LGTM!The
toOpenCollectionScriptsfunction properly handles null/undefined input and returnsundefinedwhen no scripts are present, keeping the output clean.packages/bruno-converters/src/opencollection/common/auth.ts (5)
15-78: LGTM!The OAuth2 helper functions and
buildOAuth2Configproperly handle token placement, credentials placement, and default values across all OAuth2 fields.
80-165: LGTM!The
fromOpenCollectionOAuth2function correctly maps all four OAuth2 flows (client_credentials, resource_owner_password_credentials, authorization_code, implicit) with appropriate field mappings and defaults.
167-284: LGTM!The
fromOpenCollectionAuthfunction handles all auth types comprehensively, including inherit and none modes, with proper defaults and type-safe conversions.
286-398: LGTM!The
toOpenCollectionOAuth2function correctly reverses the OAuth2 mapping for all grant types, including proper handling of PKCE, token placement, and credentials placement.
400-470: LGTM!The
toOpenCollectionAuthfunction completes the bidirectional auth conversion, handling all auth modes and delegating OAuth2 conversion appropriately.packages/bruno-converters/package.json (2)
31-32: LGTM!Adding
@opencollection/typesand@usebruno/schema-typesas devDependencies correctly supports the new OpenCollection converter implementations.
1-11: Type declarations are properly configured and will be discovered automatically.The removal of the
"types"field is intentional and correct. TypeScript 3.1+ supports automatic discovery of type definitions—the compiler will findindex.d.tscolocated with your main and module entry points. Sincetsconfig.jsonhas"declaration": trueand the Rollup TypeScript plugin is configured to emit to bothdist/cjsanddist/esmdirectories, type declarations will be generated and properly resolved by TypeScript consumers without needing an explicit"types"field.packages/bruno-converters/src/index.js (1)
9-43: LGTM!The comprehensive set of OpenCollection converter exports provides a clean public API for bidirectional conversions between Bruno and OpenCollection formats. The naming convention is consistent and the re-export pattern aligns with existing exports in this file.
packages/bruno-converters/src/opencollection/folder.ts (2)
20-67: LGTM!The
fromOpenCollectionFolderfunction properly converts OpenCollection folders to Bruno items, handling all optional fields (root data, docs, tags, nested items) and correctly applying defaults.
69-126: LGTM!The
toOpenCollectionFolderfunction correctly converts Bruno folder items back to OpenCollection format, conditionally including root data, docs, and nested items while preserving folder metadata.packages/bruno-converters/src/opencollection/common/headers.ts (1)
7-19: LGTM!Clean implementation with proper null guards and sensible defaults. The optional chaining on
header.description?.contenthandles both string and object description formats well.packages/bruno-converters/src/opencollection/common/assertions.ts (2)
7-19: LGTM!Solid mapping logic. The
${a.operator || 'eq'} ${a.value || ''}.trim()` pattern handles missing fields gracefully.
21-48: LGTM!The split-and-rejoin approach on lines 28-30 correctly preserves spaces within the assertion value while extracting the operator.
packages/bruno-converters/src/opencollection/items/graphql.ts (1)
87-162: LGTM!The export function correctly reconstructs the OpenCollection format with sensible defaults for settings. The conditional runtime block assembly (lines 130-148) is clean.
packages/bruno-converters/src/opencollection/common/index.ts (1)
1-7: LGTM!Clean barrel file aggregating all common converters. Follows standard module export patterns.
packages/bruno-converters/src/opencollection/common/variables.ts (2)
84-104: Response variables always get scope marker in description.This design means res vars without descriptions will have
description: '[post-response]'. This is intentional for round-trip identification, but worth noting that it adds metadata to exported variables.
40-51: No type issue here. TheBrunoVariable.descriptionfield acceptsstring | null(as defined inpackages/bruno-schema-types/src/common/variables.ts), so assigningnullon line 48 is type-safe.packages/bruno-converters/src/opencollection/items/websocket.ts (1)
78-147: LGTM!The export logic correctly differentiates between single-message and multi-message WebSocket configurations (lines 106-119). Runtime block assembly follows the same clean pattern as other item converters.
packages/bruno-converters/src/opencollection/collection.ts (3)
67-150: LGTM!Thorough config conversion handling protobuf, proxy, and client certificates. The filter pattern on line 145 correctly removes null entries from the cert array.
277-287:hasRequestDefaultscheck is well-structured.Correctly identifies when meaningful request defaults exist. The
auth.mode !== 'none'check ensures empty auth configurations don't trigger the request block.
289-358:bundled: trueis always set on export.Line 347 unconditionally sets
bundled = true. If there's a use case for non-bundled exports, consider making this configurable.Is
bundled: truethe intended default for all OpenCollection exports, or should this be parameterized?packages/bruno-converters/src/opencollection/environment.ts (2)
10-42: LGTM!Clean environment import logic with proper secret variable handling. The type narrowing approach using
'secret' in vis safe and TypeScript-idiomatic.
44-81: LGTM!Export logic correctly differentiates secret variables (line 53-63) from regular variables. The
String(v.value ?? '')fallback on line 68 handles edge cases well.packages/bruno-converters/src/opencollection/common/body.ts (1)
114-114: Verify that contentType should always be null for multipart form entries.Line 114 unconditionally sets
contentType: nullfor all multipart form entries. Confirm whether this is intentional or if it should map from the OpenCollection source data.packages/bruno-converters/src/opencollection/items/index.ts (2)
17-50: LGTM: Clean type detection logic.The
getItemTypefunction uses a straightforward cascading pattern to determine item types. The priority ordering (script → info.type → protocol-specific fields → folder → unknown) is clear and appropriate.
52-112: LGTM: Clean delegation pattern with proper null filtering.The conversion functions appropriately delegate to type-specific converters and use type predicates in the filter functions (lines 105, 111) to ensure type safety for the returned arrays.
packages/bruno-converters/src/opencollection/index.ts (1)
1-36: LGTM: Clean barrel export pattern.This index file appropriately aggregates and re-exports the OpenCollection converter API, providing a clean public interface.
packages/bruno-converters/src/opencollection/types.ts (1)
1-159: LGTM: Comprehensive type aggregation.This type-only module effectively centralizes OpenCollection and Bruno type definitions, providing a single import point for the converter modules.
| copy({ | ||
| patterns: 'src/workers/scripts/**/*', | ||
| rootDir: '.' | ||
| }) |
There was a problem hiding this comment.
Duplicate copy plugin execution in both build configs.
The copy plugin appears with identical configuration in both the CJS (lines 53-56) and ESM (lines 81-84) build configs. This causes the same files to be copied twice during the build process, which is inefficient and could potentially cause race conditions if builds run in parallel.
Consider either:
- Moving the copy operation outside the rollup configs (e.g., separate npm script)
- Including it in only one of the configs
- Using a rollup plugin that ensures the copy runs only once
Also applies to: 81-84
🤖 Prompt for AI Agents
In packages/bruno-converters/rollup.config.js around lines 53-56 and 81-84, the
copy plugin is configured identically in both the CJS and ESM build configs
causing duplicate file copies; remove the duplicate by keeping the copy(...)
call in only one of the configs (either CJS or ESM) or move the copy operation
out of rollup into a separate npm script that runs once before/after builds, or
replace with a plugin/utility that guarantees a single execution; update the
file to delete the redundant copy(...) block from one config (or delete both and
add the npm script) and ensure package.json scripts invoke the single copy step
when needed.
| className={`flex border border-gray-200 dark:border-gray-600 items-center p-3 rounded-lg transition-colors ${ | ||
| isCollectionLoading | ||
| ? 'opacity-50 cursor-not-allowed' | ||
| : 'hover:bg-gray-100 dark:hover:bg-gray-500/10 cursor-pointer' |
There was a problem hiding this comment.
Please use colors from theme
| sortKeys: false | ||
| }); | ||
|
|
||
| const fileName = `${collection.name}.yml`; |
There was a problem hiding this comment.
Sanitize collection name
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (2)
packages/bruno-converters/rollup.config.js (1)
82-85: Copy plugin still duplicated across both build configs.The identical
copyplugin configuration exists in both CJS (lines 54-57) and ESM configs. Consider moving the copy to a single location or a separate build step to avoid redundant file operations.packages/bruno-converters/src/opencollection/items/grpc.ts (1)
84-90: Double cast still bypasses type safety.The pattern
as unknown as Record<string, unknown>is equivalent toas anyin terms of type safety bypass. This was flagged in a previous review. Consider extending the BrunoItem request type to include optional gRPC-specific fields.
🧹 Nitpick comments (7)
packages/bruno-converters/src/opencollection/items/websocket.ts (2)
33-50: Consider runtime validation for message type guards.The type narrowing at line 34 checks for property existence but doesn't validate the actual shape. If
websocket.messagehas an unexpected structure, the type assertion at line 35 could lead to runtime errors.Consider adding runtime validation or using a type-safe validation library.
113-113: Potential type safety issue with message type assertion.The assertion
(messages[0].type as WebSocketMessage['type'])assumes the message type is valid, but if it's an unexpected value, OpenCollection might reject it or cause issues.Consider validating the type or providing a safe default:
type: (['json', 'text', 'binary'].includes(messages[0].type) ? messages[0].type : 'json') as WebSocketMessage['type']packages/bruno-converters/src/opencollection/types.ts (1)
10-11: Clarify the dual export ofHttpRequestHeader.
HttpRequestHeaderis exported both asHttpHeader(line 10) and as itself (line 11). This might be intentional to provide both a short alias and the full name, but it could confuse consumers.Consider documenting this choice or removing the duplicate if only one name is needed.
packages/bruno-converters/src/opencollection/items/graphql.ts (1)
162-168: Settings always included with defaults.Unlike
fromOpenCollectionGraphqlItemwhich conditionally includes settings,toOpenCollectionGraphqlItemalways outputs settings with defaults. This asymmetry could lead to round-trip differences.Consider making settings optional and only including them when values differ from defaults.
🔎 Suggested approach
- const settings: GraphQLRequestSettings = { - encodeUrl: typeof brunoSettings.encodeUrl === 'boolean' ? brunoSettings.encodeUrl : true, - timeout: typeof brunoSettings.timeout === 'number' ? brunoSettings.timeout : 0, - followRedirects: typeof brunoSettings.followRedirects === 'boolean' ? brunoSettings.followRedirects : true, - maxRedirects: typeof brunoSettings.maxRedirects === 'number' ? brunoSettings.maxRedirects : 5 - }; - ocRequest.settings = settings; + const hasNonDefaultSettings = + (typeof brunoSettings.encodeUrl === 'boolean' && brunoSettings.encodeUrl !== true) || + (typeof brunoSettings.timeout === 'number' && brunoSettings.timeout !== 0) || + (typeof brunoSettings.followRedirects === 'boolean' && brunoSettings.followRedirects !== true) || + (typeof brunoSettings.maxRedirects === 'number' && brunoSettings.maxRedirects !== 5); + + if (hasNonDefaultSettings || Object.keys(brunoSettings).length > 0) { + const settings: GraphQLRequestSettings = { + encodeUrl: typeof brunoSettings.encodeUrl === 'boolean' ? brunoSettings.encodeUrl : true, + timeout: typeof brunoSettings.timeout === 'number' ? brunoSettings.timeout : 0, + followRedirects: typeof brunoSettings.followRedirects === 'boolean' ? brunoSettings.followRedirects : true, + maxRedirects: typeof brunoSettings.maxRedirects === 'number' ? brunoSettings.maxRedirects : 5 + }; + ocRequest.settings = settings; + }packages/bruno-converters/src/opencollection/collection.ts (2)
58-65: Weak typing forrequestfield.Using
anyhere undermines type safety. Consider defining a proper interface for the request shape based on whatfromOpenCollectionRootreturns (headers, auth, script, vars, tests).🔎 Proposed type
interface BrunoCollectionRoot { - request?: any; + request?: { + headers?: BrunoKeyValue[]; + auth?: BrunoAuth; + script?: { req?: string | null; res?: string | null }; + vars?: BrunoVars; + tests?: string | null; + }; docs?: string; meta?: { name?: string; seq?: number; }; }
334-337: Avoidas anycast for scripts conversion.The cast bypasses type safety. Consider using a more specific type assertion.
🔎 Proposed fix
- const scripts = toOpenCollectionScripts(request as any); + const scripts = toOpenCollectionScripts(request as Parameters<typeof toOpenCollectionScripts>[0]);packages/bruno-converters/src/opencollection/items/index.ts (1)
116-120: Type guarditem is unknownis trivially true.The filter guard
(item): item is unknown => item !== nulldoesn't provide useful narrowing since all values are assignable tounknown. Consider simplifying.🔎 Proposed fix
export const toOpenCollectionItems = (items: BrunoItem[] | undefined | null, stringifyFolder: (folder: BrunoItem) => unknown): unknown[] => { return (items || []) .map((item) => toOpenCollectionItem(item, stringifyFolder)) - .filter((item): item is unknown => item !== null); + .filter((item) => item !== null); };
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (15)
packages/bruno-converters/package.jsonpackages/bruno-converters/rollup.config.jspackages/bruno-converters/src/opencollection/collection.tspackages/bruno-converters/src/opencollection/common/body.tspackages/bruno-converters/src/opencollection/common/headers.tspackages/bruno-converters/src/opencollection/common/scripts.tspackages/bruno-converters/src/opencollection/environment.tspackages/bruno-converters/src/opencollection/folder.tspackages/bruno-converters/src/opencollection/items/graphql.tspackages/bruno-converters/src/opencollection/items/grpc.tspackages/bruno-converters/src/opencollection/items/http.tspackages/bruno-converters/src/opencollection/items/index.tspackages/bruno-converters/src/opencollection/items/websocket.tspackages/bruno-converters/src/opencollection/types.tspackages/bruno-converters/tsconfig.json
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/bruno-converters/src/opencollection/folder.ts
- packages/bruno-converters/src/opencollection/items/http.ts
- packages/bruno-converters/src/opencollection/common/headers.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CODING_STANDARDS.md)
**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions.() => {}is good
No space between function name and parentheses.func()notfunc ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly
Files:
packages/bruno-converters/src/opencollection/common/body.tspackages/bruno-converters/src/opencollection/common/scripts.tspackages/bruno-converters/src/opencollection/items/graphql.tspackages/bruno-converters/src/opencollection/items/websocket.tspackages/bruno-converters/src/opencollection/items/index.tspackages/bruno-converters/src/opencollection/collection.tspackages/bruno-converters/rollup.config.jspackages/bruno-converters/src/opencollection/environment.tspackages/bruno-converters/src/opencollection/types.tspackages/bruno-converters/src/opencollection/items/grpc.ts
🧠 Learnings (6)
📓 Common learnings
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Add in JSDoc comments to add more details to the abstractions if needed
Applied to files:
packages/bruno-converters/tsconfig.json
📚 Learning: 2025-12-16T07:16:23.647Z
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.
Applied to files:
packages/bruno-converters/tsconfig.jsonpackages/bruno-converters/src/opencollection/collection.ts
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : No trailing commas
Applied to files:
packages/bruno-converters/tsconfig.json
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.
Applied to files:
packages/bruno-converters/rollup.config.js
📚 Learning: 2025-12-02T07:24:50.311Z
Learnt from: bijin-bruno
Repo: usebruno/bruno PR: 6263
File: packages/bruno-requests/src/auth/oauth2-helper.ts:249-249
Timestamp: 2025-12-02T07:24:50.311Z
Learning: In OAuth2 Basic Auth headers for Bruno, clientSecret is optional and can be omitted. When constructing the Authorization header in `packages/bruno-requests/src/auth/oauth2-helper.ts`, use `clientSecret || ''` instead of `clientSecret!` to properly handle cases where only clientId is provided, per community requests.
Applied to files:
packages/bruno-converters/src/opencollection/items/grpc.ts
🧬 Code graph analysis (4)
packages/bruno-converters/src/opencollection/common/body.ts (1)
packages/bruno-converters/src/opencollection/types.ts (10)
HttpRequestBody(14-14)HttpRequestBody(146-146)GraphQLBody(40-40)RawBody(24-24)FormUrlEncodedBody(25-25)MultipartFormBody(27-27)FileBody(29-29)FormUrlEncodedEntry(26-26)MultipartFormEntry(28-28)MultipartFormEntry(139-139)
packages/bruno-converters/src/opencollection/items/graphql.ts (4)
packages/bruno-converters/src/opencollection/common/headers.ts (2)
fromOpenCollectionHeaders(7-19)toOpenCollectionHeaders(21-44)packages/bruno-converters/src/opencollection/common/params.ts (2)
fromOpenCollectionParams(8-21)toOpenCollectionParams(23-47)packages/bruno-converters/src/opencollection/common/body.ts (2)
fromOpenCollectionBody(19-137)toOpenCollectionGraphqlBody(218-227)packages/bruno-converters/src/opencollection/common/auth.ts (2)
fromOpenCollectionAuth(167-284)toOpenCollectionAuth(400-470)
packages/bruno-converters/src/opencollection/collection.ts (7)
packages/bruno-converters/src/opencollection/common/scripts.ts (2)
fromOpenCollectionScripts(32-64)toOpenCollectionScripts(7-30)packages/bruno-converters/src/opencollection/common/headers.ts (2)
fromOpenCollectionHeaders(7-19)toOpenCollectionHeaders(21-44)packages/bruno-converters/src/opencollection/common/auth.ts (2)
fromOpenCollectionAuth(167-284)toOpenCollectionAuth(400-470)packages/bruno-converters/src/opencollection/common/variables.ts (2)
fromOpenCollectionVariables(13-55)toOpenCollectionVariables(57-107)packages/bruno-converters/src/opencollection/items/index.ts (2)
fromOpenCollectionItems(110-114)toOpenCollectionItems(116-120)packages/bruno-converters/src/opencollection/folder.ts (2)
fromOpenCollectionFolder(23-72)toOpenCollectionFolder(74-135)packages/bruno-converters/src/opencollection/environment.ts (2)
fromOpenCollectionEnvironments(16-47)toOpenCollectionEnvironments(49-79)
packages/bruno-converters/src/opencollection/items/grpc.ts (4)
packages/bruno-converters/src/opencollection/common/scripts.ts (2)
fromOpenCollectionScripts(32-64)toOpenCollectionScripts(7-30)packages/bruno-converters/src/opencollection/common/auth.ts (2)
fromOpenCollectionAuth(167-284)toOpenCollectionAuth(400-470)packages/bruno-converters/src/opencollection/common/variables.ts (2)
fromOpenCollectionVariables(13-55)toOpenCollectionVariables(57-107)packages/bruno-converters/src/opencollection/common/assertions.ts (2)
fromOpenCollectionAssertions(7-19)toOpenCollectionAssertions(21-48)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: CLI Tests
- GitHub Check: Playwright E2E Tests
- GitHub Check: Unit Tests
- GitHub Check: SSL Tests - Windows
- GitHub Check: SSL Tests - Linux
- GitHub Check: SSL Tests - macOS
🔇 Additional comments (37)
packages/bruno-converters/rollup.config.js (3)
1-7: LGTM!Imports are clean and appropriate for the TypeScript-enabled dual-format build configuration.
11-30: LGTM!The
externalDepsarray is well-organized with clear grouping. The addition oflodash/mapaddresses the prior review feedback, and regex patterns correctly handle subpath exports.
32-60: LGTM!CJS build config is well-structured with proper TypeScript integration and dynamic output path resolution.
packages/bruno-converters/src/opencollection/items/websocket.ts (1)
1-25: LGTM!Imports are well-organized and follow coding guidelines.
packages/bruno-converters/src/opencollection/common/body.ts (4)
1-18: LGTM!Imports are well-structured and follow coding guidelines.
139-216: LGTM!The toOpenCollectionBody function properly mirrors the fromOpenCollectionBody logic with appropriate conditionals and type mappings. The separation of graphql body handling is clean.
218-227: LGTM!Clean and focused GraphQL body converter with proper guards.
108-116: No issues found. OpenCollection'sMultipartFormEntrytype does not include acontentTypefield, only file entries support it. SettingcontentType: nullis appropriate as there is no source data to preserve.packages/bruno-converters/src/opencollection/environment.ts (3)
1-14: LGTM!Imports and the OCVariable interface are well-defined.
16-47: LGTM!Proper handling of environment variables with good secret detection and value extraction logic.
49-79: LGTM!Proper reverse conversion with correct secret handling (omitting values for secret variables in export).
packages/bruno-converters/src/opencollection/types.ts (1)
1-161: LGTM!Type aggregation file is well-organized, providing a centralized export surface for OpenCollection and Bruno types.
packages/bruno-converters/src/opencollection/common/scripts.ts (3)
1-6: LGTM!Imports are clean and follow coding guidelines.
7-30: LGTM!Proper script conversion with appropriate trimming and type mapping.
32-64: LGTM!Proper reverse conversion with lazy initialization and correct type mapping.
packages/bruno-converters/src/opencollection/items/graphql.ts (3)
1-30: LGTM!Imports are well-organized and follow coding guidelines.
32-39: LGTM!Helper correctly handles single GraphQL body and variant arrays with proper selection logic.
69-84: Settings conditionals ensure clean output.Good practice to only include settings properties when they exist in the source, avoiding unnecessary fields in the output.
packages/bruno-converters/tsconfig.json (1)
25-26: The path mapping for@opencollection/typesis correct. The npm registry confirms thatdist/opencollection.d.tsis the package's declared types entry point, and the tsconfig.json mapping matches it exactly. No changes needed.Likely an incorrect or invalid review comment.
packages/bruno-converters/src/opencollection/collection.ts (5)
1-24: Imports and type dependencies look good.Clean import structure with proper separation between common helpers, item converters, folder/environment utilities, and types.
67-150: Config conversion logic is well-structured.Proper handling of nested optional fields with sensible defaults for ignore list, protobuf, proxy, and client certificates.
152-177: Root conversion handles polymorphic docs correctly.Good use of ternary to handle both string and object-based docs format.
179-191: Main import function composes helpers well.Clean delegation to specialized converters for items, environments, config, and root.
193-275: Export config conversion mirrors import correctly.Proper handling of empty config check and null filtering for certificates.
packages/bruno-converters/src/opencollection/items/grpc.ts (7)
1-24: Clean imports with proper type declarations.Good separation of auth, scripts, variables, and assertions helpers.
26-38: Metadata conversion handles polymorphic description correctly.Good null-safe access for the description field.
45-58: Message handling covers both single and array formats.Good fallback naming convention for untitled messages.
99-108: Export function structure is sound.Using
Record<string, unknown>cast for request is acceptable given the current type definitions.
127-145: Metadata export handles optional fields cleanly.Good pattern of conditionally adding description and disabled only when needed.
147-158: Message serialization correctly differentiates single vs multiple.Good optimization to output string for single message, array for multiple.
165-190: Runtime assembly uses type-safe Parameters pattern.Good improvement over
as anycasts. Conditional object building keeps the output clean.packages/bruno-converters/src/opencollection/items/index.ts (6)
1-8: Clean imports and type declarations.Good modular structure importing per-type converters.
10-22: OCItem interface usesunknownappropriately.Safer than
anyfor the protocol-specific fields where detailed typing isn't needed for dispatch.
24-54: Type inference logic with clear priority order.Good defensive approach checking explicit type first, then falling back to structural detection.
56-83: Import dispatcher with inline script handling.Clean dispatch pattern. Script items are handled inline which is appropriate given their simplicity.
85-108: Export dispatcher mirrors import structure.Symmetric implementation with proper delegation for folders.
122-125: Re-exports consolidate the public API.Good pattern for barrel exports.
| "@opencollection/types": "0.3.0", | ||
| "@usebruno/schema-types": "0.0.1", |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if the specified versions exist on npm registry
echo "=== Checking @opencollection/types@0.3.0 ==="
npm view @opencollection/types@0.3.0 version 2>&1 || echo "Version not found"
echo -e "\n=== Checking @usebruno/schema-types@0.0.1 ==="
npm view @usebruno/schema-types@0.0.1 version 2>&1 || echo "Version not found"
echo -e "\n=== Latest versions ==="
npm view @opencollection/types version 2>&1 || echo "Package not found"
npm view @usebruno/schema-types version 2>&1 || echo "Package not found"Repository: usebruno/bruno
Length of output: 1234
@usebruno/schema-types@0.0.1 does not exist on the npm registry.
The package @opencollection/types@0.3.0 is valid, but @usebruno/schema-types@0.0.1 returns a 404 error and cannot be installed. This dependency will fail resolution for any consumer. Verify the correct version or registry location for this package.
🤖 Prompt for AI Agents
In packages/bruno-converters/package.json around lines 31 to 32, the dependency
"@usebruno/schema-types": "0.0.1" does not exist on the npm registry and will
cause install failures; update package.json to point to a valid source by either
replacing the version with the correct published version, referencing a valid
git URL (e.g., "git+https://...#commit_or_tag"), using a workspace/local path if
it's an internal package, or removing the dependency if unused, then run the
package manager install and lockfile update to verify resolution succeeds.
| const hasRequestDefaults = (root: BrunoCollectionRoot | undefined): boolean => { | ||
| const request = root?.request; | ||
| return Boolean( | ||
| request?.headers?.length || | ||
| request?.vars?.req?.length || | ||
| request?.script?.req || | ||
| request?.script?.res || | ||
| request?.tests || | ||
| (request?.auth && request.auth.mode !== 'none') | ||
| ); | ||
| }; |
There was a problem hiding this comment.
hasRequestDefaults may miss response variables.
The check only considers vars?.req?.length but ignores vars?.res?.length. If only response variables are present, this would return false and they wouldn't be exported.
🔎 Proposed fix
const hasRequestDefaults = (root: BrunoCollectionRoot | undefined): boolean => {
const request = root?.request;
return Boolean(
request?.headers?.length ||
request?.vars?.req?.length ||
+ request?.vars?.res?.length ||
request?.script?.req ||
request?.script?.res ||
request?.tests ||
(request?.auth && request.auth.mode !== 'none')
);
};🤖 Prompt for AI Agents
In packages/bruno-converters/src/opencollection/collection.ts around lines 277
to 287, the hasRequestDefaults function only checks request.vars?.req?.length
and thus will miss when only response variables exist; update the boolean
expression to also consider request.vars?.res?.length (i.e. include a check for
request?.vars?.res?.length alongside req) so response-only variables cause
hasRequestDefaults to return true.
| headers: fromOpenCollectionHeaders(graphql.headers), | ||
| params: fromOpenCollectionParams(graphql.params), | ||
| body: fromOpenCollectionBody(graphqlBody, 'graphql'), | ||
| auth: fromOpenCollectionAuth(runtime.auth as Auth), |
There was a problem hiding this comment.
Unsafe type assertion for auth field.
Similar to the websocket converter, runtime.auth as Auth assumes the structure matches without runtime validation.
Consider adding runtime validation or using type guards to ensure auth structure validity.
🤖 Prompt for AI Agents
In packages/bruno-converters/src/opencollection/items/graphql.ts around line 60,
the code unsafely asserts runtime.auth as Auth; instead, add a runtime
validation or type guard to verify runtime.auth shape before casting — implement
an isAuth(value): value is Auth function (or use a schema validator like Zod)
and call it before passing to fromOpenCollectionAuth, returning a safe fallback
or throwing/logging a clear error if validation fails; ensure
fromOpenCollectionAuth accepts the validated type (or unknown and performs its
own validation) so no unchecked "as Auth" assertion remains.
| url: websocket.url || '', | ||
| headers: fromOpenCollectionHeaders(websocket.headers), | ||
| body: wsBody, | ||
| auth: fromOpenCollectionAuth(runtime.auth as Auth), |
There was a problem hiding this comment.
Unsafe type assertion for auth field.
The assertion runtime.auth as Auth assumes the runtime auth matches the Auth type, but there's no runtime validation. If the data doesn't match, downstream code could fail.
🔎 Suggested approach
Add runtime validation or use a type guard function to ensure the auth structure is valid before casting.
🤖 Prompt for AI Agents
In packages/bruno-converters/src/opencollection/items/websocket.ts around line
68, the code unsafely asserts runtime.auth as Auth when calling
fromOpenCollectionAuth; replace the direct cast with a runtime validation:
implement a small type-guard (e.g. isAuth(obj): obj is Auth) that checks
required fields/types or add validation inside fromOpenCollectionAuth to accept
unknown and validate, then call fromOpenCollectionAuth only after the guard
succeeds; if validation fails, handle the case explicitly (throw a clear error,
return a safe default, or skip mapping) instead of casting to avoid runtime
failures.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
packages/bruno-app/src/components/ShareCollection/StyledWrapper.js (1)
30-43: LGTM! Well-structured share button styling.The new
.share-buttonblock correctly uses theme props for all colors and follows the established patterns in the codebase. The hover effect and cursor feedback provide good UX.One minor refinement: since only
background-colorchanges on hover, consider making the transition more specific for better performance.🔎 Optional refinement for transition specificity
cursor: pointer; - transition: all 0.1s ease; + transition: background-color 0.1s ease;packages/bruno-app/src/utils/exporters/opencollection.js (1)
6-8: Consider if the wrapper adds value.
brunoToOpenCollectionis a thin wrapper that simply delegates totoOpenCollection. If no additional transformation is needed, you could exporttoOpenCollectiondirectly or remove the wrapper. However, this may be intentional for consistency with other exporters or as a future extension point.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/bruno-app/src/components/ShareCollection/StyledWrapper.jspackages/bruno-app/src/components/ShareCollection/index.jspackages/bruno-app/src/utils/exporters/opencollection.js
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CODING_STANDARDS.md)
**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions.() => {}is good
No space between function name and parentheses.func()notfunc ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly
Files:
packages/bruno-app/src/components/ShareCollection/StyledWrapper.jspackages/bruno-app/src/components/ShareCollection/index.jspackages/bruno-app/src/utils/exporters/opencollection.js
🧠 Learnings (6)
📓 Common learnings
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.{jsx,tsx} : Styled Components are used as wrappers to define both self and children components style; Tailwind classes are used specifically for layout based styles
Applied to files:
packages/bruno-app/src/components/ShareCollection/StyledWrapper.js
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.{jsx,tsx} : Styled Component CSS might also change layout but Tailwind classes shouldn't define colors
Applied to files:
packages/bruno-app/src/components/ShareCollection/StyledWrapper.js
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.{jsx,tsx} : Use styled component's theme prop to manage CSS colors and not CSS variables when in the context of a styled component or any React component using the styled component
Applied to files:
packages/bruno-app/src/components/ShareCollection/StyledWrapper.jspackages/bruno-app/src/components/ShareCollection/index.js
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.
Applied to files:
packages/bruno-app/src/components/ShareCollection/StyledWrapper.jspackages/bruno-app/src/components/ShareCollection/index.jspackages/bruno-app/src/utils/exporters/opencollection.js
📚 Learning: 2025-12-16T07:16:23.647Z
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.
Applied to files:
packages/bruno-app/src/components/ShareCollection/index.jspackages/bruno-app/src/utils/exporters/opencollection.js
🧬 Code graph analysis (1)
packages/bruno-app/src/components/ShareCollection/index.js (1)
packages/bruno-app/src/utils/collections/index.js (2)
transformCollectionToSaveToExportAsFile(173-660)transformCollectionToSaveToExportAsFile(173-660)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Playwright E2E Tests
- GitHub Check: Unit Tests
- GitHub Check: CLI Tests
- GitHub Check: SSL Tests - Linux
- GitHub Check: SSL Tests - macOS
- GitHub Check: SSL Tests - Windows
🔇 Additional comments (6)
packages/bruno-app/src/components/ShareCollection/index.js (4)
3-3: LGTM!Import additions are clean and follow existing patterns.
Also applies to: 8-8
52-56: LGTM!Export handler follows the established pattern consistently, using proper deep cloning and transformation.
70-74: LGTM!The refactoring to use consistent
share-buttonstyling across all export options improves maintainability and visual consistency.Also applies to: 87-91, 108-111
86-105: No action needed.OpenCollection supports gRPC and WebSocket request types natively. The converters include
toOpenCollectionGrpcItemandtoOpenCollectionWebsocketItemfunctions that handle these types, so the absence of a warning banner is correct. This differs from Postman, which has inherent limitations on these request types.Likely an incorrect or invalid review comment.
packages/bruno-app/src/utils/exporters/opencollection.js (2)
20-21: LGTM!Good use of
sanitizeNameto handle invalid filename characters. This addresses the previous review concern about unsafe filename generation.
10-25: LGTM!The export implementation is clean and well-structured. YAML serialization options are appropriate (proper indentation, no line wrapping, no references, preserved key order), and file handling follows best practices.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
packages/bruno-converters/src/opencollection/items/graphql.ts (1)
66-66: Unsafe type assertion for auth field.The
runtime.auth as Authassertion assumes structure validity without runtime validation, as noted in previous review.
🧹 Nitpick comments (5)
packages/bruno-converters/src/opencollection/bruno-to-opencollection.ts (1)
148-151: Avoidas anytype assertion.The
request as anycast bypasses type checking. Consider defining a proper type or using a more specific assertion.🔎 Proposed fix
- const scripts = toOpenCollectionScripts(request as any); + const scripts = toOpenCollectionScripts(request as Parameters<typeof toOpenCollectionScripts>[0]);packages/bruno-converters/src/opencollection/opencollection-to-bruno.ts (2)
70-76: Minor asymmetry in passphrase handling.
toOpenCollectionConfigconditionally includespassphraseonly when present, butfromOpenCollectionConfigalways sets it to''. This is functionally fine but could be made consistent by omitting the field when empty.🔎 Proposed fix
return { domain: pemCert.domain || '', type: 'pem' as const, certFilePath: pemCert.certificateFilePath || '', - keyFilePath: pemCert.privateKeyFilePath || '', - passphrase: pemCert.passphrase || '' + keyFilePath: pemCert.privateKeyFilePath || '', + ...(pemCert.passphrase ? { passphrase: pemCert.passphrase } : {}) };
126-126: Inline folder callback is verbose.The type coercion wrapper could be simplified if
fromOpenCollectionItemsaccepted a more flexible folder handler signature.🔎 Proposed fix
- items: fromOpenCollectionItems(openCollection.items, (folder: unknown) => fromOpenCollectionFolder(folder as Parameters<typeof fromOpenCollectionFolder>[0])), + items: fromOpenCollectionItems(openCollection.items, fromOpenCollectionFolder),If the types don't align, consider updating
fromOpenCollectionItemsto use generics or a union type for the folder handler.packages/bruno-app/src/utils/exporters/opencollection.js (1)
6-21: Export function is clean, consider error handling.The YAML dump options are well-chosen. The filename sanitization addresses the past review concern. Consider wrapping in try-catch to handle potential conversion errors gracefully.
🔎 Proposed fix
export const exportCollection = (collection) => { + try { const openCollection = brunoToOpenCollection(collection); const yamlContent = jsyaml.dump(openCollection, { indent: 2, lineWidth: -1, noRefs: true, sortKeys: false }); const sanitizedName = sanitizeName(collection.name); const fileName = `${sanitizedName}.yml`; const fileBlob = new Blob([yamlContent], { type: 'application/x-yaml' }); FileSaver.saveAs(fileBlob, fileName); + } catch (error) { + console.error('Failed to export collection:', error); + throw error; + } };packages/bruno-converters/src/opencollection/items/http.ts (1)
147-147: Consider removing type assertion for better type safety.While
as BrunoHttpItemSettings | undefinedis safer than the previousas any, it still bypasses compile-time checks. Ifitem.settingsis already typed correctly inBrunoItem, this cast may be unnecessary.Refactor suggestion
If
BrunoItem.settingscan be typed asBrunoHttpItemSettings | nullin the type definition, this cast can be removed entirely:- const brunoSettings = item.settings as BrunoHttpItemSettings | undefined; + const brunoSettings = item.settings;
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
packages/bruno-app/src/utils/exporters/opencollection.jspackages/bruno-app/src/utils/importers/opencollection.jspackages/bruno-converters/src/index.jspackages/bruno-converters/src/opencollection/bruno-to-opencollection.tspackages/bruno-converters/src/opencollection/common/actions.tspackages/bruno-converters/src/opencollection/common/body.tspackages/bruno-converters/src/opencollection/common/headers.tspackages/bruno-converters/src/opencollection/common/index.tspackages/bruno-converters/src/opencollection/common/variables.tspackages/bruno-converters/src/opencollection/index.tspackages/bruno-converters/src/opencollection/items/graphql.tspackages/bruno-converters/src/opencollection/items/grpc.tspackages/bruno-converters/src/opencollection/items/http.tspackages/bruno-converters/src/opencollection/items/websocket.tspackages/bruno-converters/src/opencollection/opencollection-to-bruno.tspackages/bruno-converters/src/opencollection/types.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- packages/bruno-converters/src/opencollection/common/body.ts
- packages/bruno-converters/src/opencollection/items/grpc.ts
- packages/bruno-converters/src/index.js
- packages/bruno-converters/src/opencollection/items/websocket.ts
- packages/bruno-app/src/utils/importers/opencollection.js
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CODING_STANDARDS.md)
**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions.() => {}is good
No space between function name and parentheses.func()notfunc ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly
Files:
packages/bruno-converters/src/opencollection/bruno-to-opencollection.tspackages/bruno-converters/src/opencollection/items/http.tspackages/bruno-converters/src/opencollection/opencollection-to-bruno.tspackages/bruno-converters/src/opencollection/common/actions.tspackages/bruno-converters/src/opencollection/common/headers.tspackages/bruno-converters/src/opencollection/common/variables.tspackages/bruno-app/src/utils/exporters/opencollection.jspackages/bruno-converters/src/opencollection/common/index.tspackages/bruno-converters/src/opencollection/items/graphql.tspackages/bruno-converters/src/opencollection/index.tspackages/bruno-converters/src/opencollection/types.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.
📚 Learning: 2025-12-16T07:16:23.647Z
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.
Applied to files:
packages/bruno-converters/src/opencollection/bruno-to-opencollection.tspackages/bruno-converters/src/opencollection/opencollection-to-bruno.tspackages/bruno-converters/src/opencollection/index.tspackages/bruno-converters/src/opencollection/types.ts
📚 Learning: 2025-12-02T07:24:50.311Z
Learnt from: bijin-bruno
Repo: usebruno/bruno PR: 6263
File: packages/bruno-requests/src/auth/oauth2-helper.ts:249-249
Timestamp: 2025-12-02T07:24:50.311Z
Learning: In OAuth2 Basic Auth headers for Bruno, clientSecret is optional and can be omitted. When constructing the Authorization header in `packages/bruno-requests/src/auth/oauth2-helper.ts`, use `clientSecret || ''` instead of `clientSecret!` to properly handle cases where only clientId is provided, per community requests.
Applied to files:
packages/bruno-converters/src/opencollection/items/http.tspackages/bruno-converters/src/opencollection/items/graphql.ts
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.
Applied to files:
packages/bruno-app/src/utils/exporters/opencollection.js
🧬 Code graph analysis (5)
packages/bruno-converters/src/opencollection/bruno-to-opencollection.ts (3)
packages/bruno-converters/src/opencollection/types.ts (8)
BrunoConfig(168-199)CollectionConfig(69-69)Protobuf(70-70)ClientCertificate(72-72)PemCertificate(72-72)Pkcs12Certificate(72-72)BrunoCollectionRoot(201-208)OpenCollection(2-2)packages/bruno-converters/src/opencollection/common/headers.ts (1)
toOpenCollectionHeaders(21-44)packages/bruno-converters/src/opencollection/common/variables.ts (1)
toOpenCollectionVariables(46-75)
packages/bruno-converters/src/opencollection/opencollection-to-bruno.ts (3)
packages/bruno-converters/src/opencollection/types.ts (5)
OpenCollection(2-2)BrunoConfig(168-199)PemCertificate(72-72)Pkcs12Certificate(72-72)BrunoCollectionRoot(201-208)packages/bruno-converters/src/opencollection/common/headers.ts (1)
fromOpenCollectionHeaders(7-19)packages/bruno-converters/src/opencollection/common/variables.ts (1)
fromOpenCollectionVariables(13-44)
packages/bruno-converters/src/opencollection/common/headers.ts (3)
packages/bruno-converters/src/opencollection/common/index.ts (2)
fromOpenCollectionHeaders(2-2)toOpenCollectionHeaders(2-2)packages/bruno-converters/src/opencollection/index.ts (2)
fromOpenCollectionHeaders(24-24)toOpenCollectionHeaders(25-25)packages/bruno-converters/src/opencollection/types.ts (1)
HttpRequestHeader(10-10)
packages/bruno-converters/src/opencollection/common/variables.ts (3)
packages/bruno-converters/src/opencollection/common/index.ts (2)
fromOpenCollectionVariables(5-5)toOpenCollectionVariables(5-5)packages/bruno-converters/src/opencollection/index.ts (2)
fromOpenCollectionVariables(31-31)toOpenCollectionVariables(32-32)packages/bruno-converters/src/opencollection/types.ts (2)
Variable(80-80)Variable(130-130)
packages/bruno-converters/src/opencollection/items/graphql.ts (8)
packages/bruno-converters/src/opencollection/common/scripts.ts (2)
fromOpenCollectionScripts(32-64)toOpenCollectionScripts(7-30)packages/bruno-converters/src/opencollection/common/variables.ts (2)
fromOpenCollectionVariables(13-44)toOpenCollectionVariables(46-75)packages/bruno-converters/src/opencollection/common/actions.ts (2)
fromOpenCollectionActions(52-83)toOpenCollectionActions(15-46)packages/bruno-converters/src/opencollection/common/headers.ts (2)
fromOpenCollectionHeaders(7-19)toOpenCollectionHeaders(21-44)packages/bruno-converters/src/opencollection/common/params.ts (2)
fromOpenCollectionParams(8-21)toOpenCollectionParams(23-47)packages/bruno-converters/src/opencollection/common/body.ts (1)
fromOpenCollectionBody(19-137)packages/bruno-converters/src/opencollection/common/auth.ts (2)
fromOpenCollectionAuth(167-284)toOpenCollectionAuth(400-470)packages/bruno-converters/src/opencollection/common/assertions.ts (2)
fromOpenCollectionAssertions(7-19)toOpenCollectionAssertions(21-48)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: SSL Tests - Linux
- GitHub Check: SSL Tests - Windows
- GitHub Check: SSL Tests - macOS
- GitHub Check: CLI Tests
- GitHub Check: Unit Tests
- GitHub Check: Playwright E2E Tests
🔇 Additional comments (29)
packages/bruno-converters/src/opencollection/bruno-to-opencollection.ts (4)
1-5: Imports are well-organized.Type and function imports are cleanly separated and sourced from appropriate internal modules.
7-89: Config conversion logic is robust.The function handles undefined inputs, maps protobuf/proxy/clientCertificates correctly, and filters unknown certificate types. The empty-object check at line 88 ensures no spurious empty configs are returned.
91-101: Helper function is concise and correct.The
hasRequestDefaultscheck covers all relevant request properties with proper optional chaining.
103-172: Main export function is well-structured.The conversion flow is logical: config → environments → items → request defaults → docs → extensions. Conditional property assignment keeps the output clean.
packages/bruno-converters/src/opencollection/opencollection-to-bruno.ts (2)
1-7: Imports are correctly structured.External and internal imports are appropriately sourced.
94-119: Root conversion handles both docs formats correctly.The function properly handles
docsas either a string or an object withcontent, and consistently setsmeta.name.packages/bruno-converters/src/opencollection/common/headers.ts (3)
1-5: Imports are appropriate.Type imports and utility function sourced correctly.
7-19: Conversion from OpenCollection headers is correct.Handles both string and object descriptions, maps
disabledtoenabledappropriately, and generates unique IDs.
21-44: Conversion to OpenCollection headers is well-implemented.The function correctly omits empty descriptions and only sets
disabledwhen explicitly false. The final length check at line 43 is redundant but harmless.packages/bruno-app/src/utils/exporters/opencollection.js (1)
1-4: Imports are appropriate for the export functionality.Dependencies are minimal and well-chosen: FileSaver for download, js-yaml for serialization, and converters for transformation.
packages/bruno-converters/src/opencollection/common/index.ts (1)
1-8: Clean barrel export file.All common converters are properly re-exported for easy consumption by other modules.
packages/bruno-converters/src/opencollection/common/variables.ts (3)
1-11: Imports and local interface are well-defined.The
BrunoVarsinterface clearly defines the expected structure withreqandresarrays.
13-44: Variable conversion correctly separates pre/post-response handling.OpenCollection variables map to
req(pre-request), whileresremains empty as post-response variables are handled via actions. The value extraction handles both string and object formats.
46-75: Reverse conversion handles multiple input shapes.The function correctly handles both folder-style
{req, res}and direct array inputs, mapping onlyreqvariables to OpenCollection format.packages/bruno-converters/src/opencollection/common/actions.ts (3)
1-8: Imports are correctly sourced.Type imports for action-related types are appropriate for the conversion logic.
15-46: Post-response variable to action conversion is well-documented.The JSDoc comment clearly explains the purpose. The mapping of
localto scope and conditional property inclusion is correct.
52-83: Action to post-response variable conversion filters appropriately.Only
set-variableactions withafter-responsephase are converted, correctly ignoring other action types. The type cast after the conditional check is safe.packages/bruno-converters/src/opencollection/items/graphql.ts (3)
1-32: Comprehensive imports for GraphQL item conversion.All necessary converters and types are imported for bidirectional mapping.
34-41: GraphQL body helper handles variant selection correctly.The function properly resolves body from either a single
GraphQLBodyor an array ofGraphQLBodyVariant, preferring the selected variant.
102-192: GraphQL item export is comprehensive.The function correctly maps all BrunoItem fields to the OpenCollection GraphQL format, including runtime, settings, and docs. The
Parameters<typeof ...>[0]pattern for type assertions is safer than rawascasts.packages/bruno-converters/src/opencollection/items/http.ts (5)
1-36: LGTM!Imports are well-organized and the addition of
BrunoHttpItemSettingsfrom@usebruno/schema-typesproperly addresses the previous type safety concern about settings.
38-45: LGTM!The helper correctly handles multiple body format variations: undefined, array with selection, array without selection, and single body. The logic is clean and defensive.
47-103: LGTM!The converter provides comprehensive default handling for all fields, including a thorough default body structure covering all modes. The separation of concerns between scripts, variables, and actions is clear.
105-142: LGTM!The settings are now properly typed using
BrunoHttpItemSettingswith appropriate type guards and sensible defaults. The examples mapping comprehensively handles all fields including nested request/response structures.
222-228: Settings are always assigned, even when undefined.Unlike the conditional
runtimeobject (lines 183-220), settings are always created and assigned with defaults. This differs fromfromOpenCollectionHttpItemwhich only assigns settings whenocRequest.settingsexists. Consider whether this asymmetry is intentional.If OpenCollection format requires settings to always be present, this is correct. Otherwise, consider making it conditional:
if (brunoSettings || /* always needed */) { const settings: HttpRequestSettings = { encodeUrl: typeof brunoSettings?.encodeUrl === 'boolean' ? brunoSettings.encodeUrl : true, timeout: typeof brunoSettings?.timeout === 'number' ? brunoSettings.timeout : 0, followRedirects: typeof brunoSettings?.followRedirects === 'boolean' ? brunoSettings.followRedirects : true, maxRedirects: typeof brunoSettings?.maxRedirects === 'number' ? brunoSettings.maxRedirects : 5 }; ocRequest.settings = settings; }packages/bruno-converters/src/opencollection/index.ts (1)
1-37: LGTM!Clean barrel export file with logical grouping of converters. The organization makes it easy to understand the public API surface.
packages/bruno-converters/src/opencollection/types.ts (3)
1-107: LGTM!Comprehensive and well-organized OpenCollection type exports. The categorization by request type (HTTP, GraphQL, gRPC, WebSocket) and common types makes navigation straightforward.
109-166: LGTM!The Bruno type aliases provide a stable public API layer. Prefixing with "Bruno" clearly distinguishes these from OpenCollection types and allows independent evolution.
168-199: LGTM!The
BrunoConfiginterface comprehensively covers configuration needs for protobuf, proxy, and client certificates. The optional properties provide flexibility for different use cases.
|
|
||
| if (example.response.body) { | ||
| ocExample.response.body = { | ||
| type: (example.response.body.type as 'json' | 'text' | 'xml' | 'html' | 'binary') || 'text', |
There was a problem hiding this comment.
Type assertion bypasses runtime type safety.
The type assertion as 'json' | 'text' | 'xml' | 'html' | 'binary' assumes example.response.body.type matches one of these values. If it contains an unexpected value, this could cause issues downstream in OpenCollection processing.
Suggested fix with validation
+ const validBodyTypes = ['json', 'text', 'xml', 'html', 'binary'] as const;
+ const bodyType = validBodyTypes.includes(example.response.body.type as any)
+ ? (example.response.body.type as 'json' | 'text' | 'xml' | 'html' | 'binary')
+ : 'text';
+
if (example.response.body) {
ocExample.response.body = {
- type: (example.response.body.type as 'json' | 'text' | 'xml' | 'html' | 'binary') || 'text',
+ type: bodyType,
data: String(example.response.body.content || '')
};
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In packages/bruno-converters/src/opencollection/items/http.ts around line 284,
the code unsafely asserts example.response.body.type to a union which can bypass
runtime safety; replace the assertion with runtime validation: check whether
example.response?.body?.type is one of the allowed values
('json','text','xml','html','binary') and only use it if valid, otherwise fall
back to 'text'; implement this with a small helper or inline conditional (e.g.
Array.includes or switch) so unexpected strings don't propagate and the result
is strongly typed for downstream use.
| export interface BrunoCollectionRoot { | ||
| request?: any; | ||
| docs?: string; | ||
| meta?: { | ||
| name?: string; | ||
| seq?: number; | ||
| }; | ||
| } No newline at end of file |
There was a problem hiding this comment.
Type the request field instead of using any.
Line 202 uses request?: any, which completely bypasses TypeScript's type safety. This defeats the purpose of using TypeScript and could allow invalid data to flow through the system unchecked.
Determine and apply proper type
The request field should be typed based on what it actually represents. Possible options:
// Option 1: If it's one of the known request types
request?: BrunoHttpRequest | BrunoGrpcRequest | BrunoWebSocketRequest;
// Option 2: If it's a union with null/undefined
request?: BrunoHttpRequest | null;
// Option 3: If structure is unknown but has some shape
request?: Record<string, unknown>;
// Option 4: If truly anything goes (discouraged)
request?: unknown; // Better than 'any' as it forces type checking🤖 Prompt for AI Agents
packages/bruno-converters/src/opencollection/types.ts around lines 201 to 208:
the BrunoCollectionRoot.request field is currently typed as any which disables
TS checks; replace it with a concrete type that matches the actual request shape
(for example use a union of existing request types like BrunoHttpRequest |
BrunoGrpcRequest | BrunoWebSocketRequest, or BrunoHttpRequest | null if
nullable, or Record<string, unknown> if only shape is known, or unknown as last
resort), import or declare the chosen request types and update the request?: any
to request?: <chosen-type> to restore type safety.
* feat: button storybook * feat: update button component with new rounded options and story * fix: pasting request ito parent folder even if request is selected (#6446) * Add right-click context menu to request tabs with MenuDropdown # (#6502) * refactor: replace Dropdown with MenuDropdown in RequestTab component; update Dropdown props handling in Dropdown component * refactor: remove Portal import and simplify menuDropdown rendering in RequestTab component * refactor: streamline RequestTabMenu functionality and improve tab closing methods with async handling * refactor: enhance Dropdown and MenuDropdown components with improved props handling and styling adjustments * refactor: enhance Dropdown and MenuDropdown components by improving structure and removing unused styles * refactor: update Dropdown and MenuDropdown components to append to sidebar sections container for improved layout * refactor: integrate dropdownContainerRef for improved MenuDropdown positioning in RequestTabs and Sidebar components * refactor: update Dropdown component to include 'tippy-box' class for e2e test selections * refactor: update dropdown item selection logic in selectRequestPaneTab function for improved accuracy * refactor: add fixed positioning to popperOptions in Collection and CollectionItem components for improved dropdown behavior --------- Co-authored-by: sanjai <sanjai@usebruno.com> * export & import in opencollection format (#6329) --------- Co-authored-by: Anoop M D <anoop.md1421@gmail.com> Co-authored-by: Anoop M D <anoop@usebruno.com> Co-authored-by: Pooja <pooja@usebruno.com> Co-authored-by: Abhishek S Lal <abhishek@usebruno.com> Co-authored-by: sanjai <sanjai@usebruno.com> Co-authored-by: naman-bruno <naman@usebruno.com>
Description
Contribution Checklist:
Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.
Publishing to New Package Managers
Please see here for more information.
Summary by CodeRabbit
Release Notes
New Features
Documentation
Style
✏️ Tip: You can customize this high-level summary in your review settings.