Skip to content

feat(cookies): add direct cookie access methods and update translations#7073

Draft
sanish-bruno wants to merge 4 commits intousebruno:mainfrom
sanish-bruno:feat/new-coookies-apis
Draft

feat(cookies): add direct cookie access methods and update translations#7073
sanish-bruno wants to merge 4 commits intousebruno:mainfrom
sanish-bruno:feat/new-coookies-apis

Conversation

@sanish-bruno
Copy link
Collaborator

@sanish-bruno sanish-bruno commented Feb 6, 2026

Jira

Summary

Adds direct bru.cookies.* access methods that mirror Postman's pm.cookies API, allowing users to read, iterate, and manipulate cookies without going through bru.cookies.jar().

Previously, all cookie operations required explicitly creating a jar and passing URLs:

const jar = bru.cookies.jar();
const cookie = await jar.getCookie("https://example.com", "session");

Now, users can work with cookies scoped to the current request URL directly:

const value = bru.cookies.get("session");
await bru.cookies.add({ key: "token", value: "abc" });

Changes

New classes (packages/bruno-js/src/)

  • ReadOnlyPropertyList - Base collection class with read/search/iteration/transform methods. Supports both static mode (in-memory array) and dynamic mode (data source function).
  • PropertyList (extends ReadOnlyPropertyList) - Adds mutation methods for static mode (headers, query params, etc.).
  • CookieList (extends ReadOnlyPropertyList) - Cookie-specific collection using dynamic mode. Read methods delegate to the cookie jar via URL; write methods (add, upsert, remove, delete, clear) delegate async operations to the jar.

New bru.cookies methods

Category Methods
Read get(name), has(name, [value]), one(name), all(), count(), idx(n), indexOf(item), toObject(), toString()
Iteration each(fn), find(fn), filter(fn), map(fn), reduce(fn, acc)
Write add(obj), upsert(obj), remove(name), delete(name), clear()

Updated files

  • bru.js - Replaced inline cookies object with new CookieList(...), accepts requestUrl parameter
  • sandbox/quickjs/shims/bru.js - Exposed all new cookie methods to the QuickJS sandbox
  • runtime/*.js - Pass requestUrl to Bru constructor
  • postman-translations.js - Added regex translations for pm.cookies.* direct access methods
  • postman-to-bruno-translator.js - Added AST translations for pm.cookies.*
  • bruno-to-postman-translator.js - Added reverse translations for bru.cookies.*

E2E tests (packages/bruno-tests/collection/scripting/api/bru/cookies/)

  • directGet.bru - Tests get() and has()
  • directReadMethods.bru - Tests one(), all(), count(), idx(), toObject(), toString()
  • directIteration.bru - Tests each(), find(), filter(), map(), reduce()
  • directWrite.bru - Tests add(), upsert(), remove(), delete(), clear()

Unit tests (packages/bruno-js/tests/)

  • readonly-property-list.spec.js - 119 lines covering all read/search/iteration methods
  • property-list.spec.js - 409 lines covering static-mode mutation methods
  • cookie-list.spec.js - 294 lines covering async write delegation and jar integration

Test plan

  • Unit tests pass: npm run test --workspace=packages/bruno-js
  • Converter tests pass: npm run test --workspace=packages/bruno-converters
  • E2E cookie tests pass: bru run scripting/api/bru/cookies --env=Prod (42/42 pass)
  • Manual: open desktop app, run a request with cookies, verify bru.cookies.get() works in pre-request/test scripts
  • Manual: import a Postman collection using pm.cookies.get() and verify it translates correctly

Contribution Checklist:

  • I've used AI significantly to create this pull request
  • The pull request only addresses one issue or adds one feature.
  • The pull request does not introduce any breaking changes
  • I have added screenshots or gifs to help explain the change if applicable.
  • I have read the contribution guidelines.
  • Create an issue and link to the pull request.

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

  • New Features

    • Direct cookie APIs exposed (get, has, toObject, toString, clear, add/upsert/remove, iteration helpers) for easier script access and manipulation.
    • URL-aware cookie list and jar helpers for more accurate cookie operations.
    • Improved Bruno ↔ Postman cookie translation for smoother conversions.
  • Tests

    • Extensive tests covering cookie APIs, cookie-list behavior, and new property-list utilities.

- Introduced new methods for direct cookie access: `bru.cookies.get`, `bru.cookies.has`, and `bru.cookies.toObject`.
- Updated translation mappings in `bruno-to-postman-translator` and `postman-to-bruno-translator` to support these new methods.
- Enhanced tests to verify correct translation between `bru` and `pm` cookie methods, including mixed usage scenarios.
- Updated `Bru` class to handle cookie access based on the current request URL.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 6, 2026

Walkthrough

Adds first-class direct cookie APIs across translators, runtime, QuickJS shim, and Bru core by introducing CookieList/PropertyList/ReadOnlyPropertyList, passing request URL into Bru, and expanding pm↔bru cookie translation mappings with tests for both directions.

Changes

Cohort / File(s) Summary
Translation mappings
packages/bruno-converters/src/postman/postman-translations.js, packages/bruno-converters/src/utils/bruno-to-postman-translator.js, packages/bruno-converters/src/utils/postman-to-bruno-translator.js
Adds extensive pm.cookies ↔ bru.cookies 1:1 mappings (get/has/toObject/toString/clear/delete and PropertyList-style methods). Keeps jar() mapping and applies both regex/post-translation replacements.
Bru core + cookie plumbing
packages/bruno-js/src/bru.js, packages/bruno-js/src/cookie-list.js, packages/bruno-js/src/property-list.js, packages/bruno-js/src/readonly-property-list.js
Introduces CookieList, PropertyList, ReadOnlyPropertyList modules; Bru constructor gains requestUrl and now instantiates this.cookies = new CookieList(...) wired to getCookiesForUrl and URL interpolation.
Runtime callsites
packages/bruno-js/src/runtime/assert-runtime.js, packages/bruno-js/src/runtime/script-runtime.js, packages/bruno-js/src/runtime/test-runtime.js, packages/bruno-js/src/runtime/vars-runtime.js
Updates all Bru constructor invocations to pass request?.url as the final argument.
QuickJS shim
packages/bruno-js/src/sandbox/quickjs/shims/bru.js
Exposes a full bru.cookies API surface (get, has, toObject, one, all, idx, count, indexOf, add/upsert/remove/clear wrappers, iterator helpers) implemented as VM functions and async wrappers.
Unit tests — bruno-js
packages/bruno-js/tests/cookie-list.spec.js, packages/bruno-js/tests/property-list.spec.js, packages/bruno-js/tests/readonly-property-list.spec.js
Adds comprehensive tests for CookieList, PropertyList, and ReadOnlyPropertyList covering static/dynamic modes, URL interpolation, write delegation to jar, and mutation semantics.
Unit tests — converters
packages/bruno-converters/tests/bruno/bruno-to-postman-translations/cookies.test.js, packages/bruno-converters/tests/postman/postman-translations/postman-cookie-conversions.spec.js
Adds tests validating pm↔bru cookie translation mappings, including conditional and mixed jar/direct scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant Script as Script (user code)
    participant Translator as Converter (pm↔bru)
    participant Bru as Bru instance
    participant CookieList as CookieList
    participant Jar as CookieJar / requests.cookies

    Script->>Translator: translate cookie call (pm.cookies.get / bru.cookies.get)
    Translator->>Bru: produce translated code referencing bru.cookies.get(name)
    Script->>Bru: invoke bru.cookies.get(name)
    Bru->>CookieList: CookieList.get(name) with interpolated requestUrl
    CookieList->>Jar: getCookiesForUrl(requestUrl) / jar.getCookie(...)
    Jar-->>CookieList: cookie(s)
    CookieList-->>Bru: cookie value
    Bru-->>Script: return value
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • helloanoop
  • lohit-bruno
  • naman-bruno
  • bijin-bruno

Poem

🍪 A cookie API now rides the breeze,
From pm to bru with graceful ease,
Jar or direct, the paths align,
Translators, runtime, shim — in line,
Small crumbs of code bring developer glee.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main changes: adding direct cookie access methods and updating translation mappings for Postman-to-Bruno cookie API conversion.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sanish-bruno sanish-bruno marked this pull request as draft February 6, 2026 13:18
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/bruno-js/src/bru.js`:
- Around line 48-70: The get() method currently uses cookies.find(...) which
returns the first matching cookie while toObject() ends up with "last wins"
semantics; update get() (in the object containing get, has, toObject) to return
the last matching cookie for the interpolated this.requestUrl — e.g. use
Array.prototype.findLast (or iterate the cookies array in reverse) when
selecting cookie by key so get(name) and toObject() are consistent; keep the
existing interpolate(this.requestUrl) and getCookiesForUrl(url) usage and
preserve returning undefined when no url or no match.
🧹 Nitpick comments (2)
packages/bruno-js/src/runtime/vars-runtime.js (1)

40-40: 14 positional args to Bru is getting unwieldy.

The change itself is correct — passing request?.url aligns with the other runtime call sites. However, this constructor now takes 14 positional arguments with undefined placeholders for unused params. Consider moving to an options object in a follow-up to prevent ordering mistakes.

packages/bruno-js/src/bru.js (1)

31-31: 14 positional constructor parameters — existing debt, but worth noting.

This constructor keeps growing. A single options/config object would make call sites far more readable and resilient to parameter ordering bugs. I see this is pre-existing debt (flagged in script-runtime.js:15-16), so not blocking.

- Added new cookie methods: `toString`, `clear`, `delete`, `one`, `all`, `idx`, `count`, `indexOf`, `find`, `filter`, `each`, `map`, and `reduce` to `bru.cookies`.
- Refactored `Bru` class to utilize a new `CookieList` for cookie management, improving structure and readability.
- Updated translation mappings in `bruno-to-postman-translator` and `postman-to-bruno-translator` to include new cookie methods.
- Introduced `PropertyList` and `ReadOnlyPropertyList` classes for better data structure management.
- Enhanced tests for comprehensive coverage of new cookie functionalities and their interactions.
@sanish-bruno
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 9, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/bruno-js/src/sandbox/quickjs/shims/bru.js`:
- Line 579: The wrapper for globalThis.bru.cookies.reduce always forwards acc
(which may be undefined) and thus breaks the no-initial-value semantics; change
the reduce wrapper around _allNative() so it forwards the call conditionally: if
the caller provided an initial accumulator (check arguments.length or presence
of a second arg) call _allNative().reduce(fn, acc), otherwise call
_allNative().reduce(fn) so the native behavior (use first element as initial or
throw on empty array) is preserved; update the function bound to
globalThis.bru.cookies.reduce accordingly.
🧹 Nitpick comments (7)
packages/bruno-js/src/readonly-property-list.js (2)

157-159: reduce() behaves differently from native Array.reduce when called without an accumulator.

list.reduce(fn) passes undefined as the initial value to Array.prototype.reduce, which differs from calling items.reduce(fn) directly (native reduce without a second arg uses the first element as the initial accumulator and throws on empty arrays). If this is intentional to mirror Postman's PropertyList, it's fine — just worth a note.

Optional: match native semantics
- reduce(fn, acc) {
-   return this._getItems().reduce(fn, acc);
+ reduce(fn, ...args) {
+   return this._getItems().reduce(fn, ...args);
  }

36-38: Dynamic mode: _dataSource() errors will bubble up unhandled.

If a dataSource function throws, every read method will propagate the exception. This is likely fine for the cookie use case (where getCookiesForUrl is trusted internal code), but worth noting if this base class will be used more broadly.

packages/bruno-js/src/cookie-list.js (1)

39-75: Write methods are clean — consistent null-URL guard pattern.

Each method properly short-circuits on falsy URL with callback/Promise fallback. The deleteremove alias is straightforward.

One small note: these public methods lack individual JSDoc (only the class-level doc lists them). Consider adding brief JSDoc per method. As per coding guidelines: "Add JSDoc comments to abstractions for additional details."

packages/bruno-js/src/property-list.js (2)

124-136: populate() and repopulate() are identical implementations.

Both methods assign this._items = Array.isArray(items) ? [...items] : []. Since JS assignment is atomic, the "clear then populate" semantics of repopulate collapse to the same operation. If this mirrors Postman's SDK surface, keeping both is fine for API compatibility, but a deduplication would be cleaner.

Optional: deduplicate
  populate(items) {
    this._assertStatic('populate');
    this._items = Array.isArray(items) ? [...items] : [];
  }

  repopulate(items) {
    this._assertStatic('repopulate');
-   this._items = Array.isArray(items) ? [...items] : [];
+   this.populate(items);
  }

66-76: insertAfter() silently appends when after is undefined, unlike insert() which handles it explicitly.

insert(item, before) explicitly checks before === undefined and appends. insertAfter(item, after) doesn't — it falls through to indexOf(undefined) === -1 → append. The behavior is the same, but the intent is implicit. Consider adding an explicit guard for consistency, or documenting the fallback.

packages/bruno-js/src/bru.js (1)

32-32: 14 positional constructor parameters is getting unwieldy.

This isn't new to this PR, but adding requestUrl as the 14th positional arg increases the risk of callers passing arguments in the wrong order. Consider consolidating into an options object in a follow-up.

packages/bruno-js/src/sandbox/quickjs/shims/bru.js (1)

550-580: Duplicate callWithCallback definition — consider extracting to a shared helper.

callWithCallback is defined identically both inside the block scope (Line 553) and in the jar() function (Line 585). This isn't a bug due to block scoping, but it's copy-pasted logic.

globalThis.bru.cookies.filter = (fn) => _allNative().filter(fn);
globalThis.bru.cookies.find = (fn) => _allNative().find(fn);
globalThis.bru.cookies.map = (fn) => _allNative().map(fn);
globalThis.bru.cookies.reduce = (fn, acc) => _allNative().reduce(fn, acc);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

reduce wrapper always passes acc, breaking no-initial-value semantics.

When a user calls bru.cookies.reduce(fn) without an initial accumulator, acc is undefined and _allNative().reduce(fn, undefined) is invoked. This differs from Array.prototype.reduce(fn) which uses the first element as the initial value. Result: unexpected coercion (e.g., "undefined" + ...).

Proposed fix
-      globalThis.bru.cookies.reduce = (fn, acc) => _allNative().reduce(fn, acc);
+      globalThis.bru.cookies.reduce = (fn, ...rest) => rest.length ? _allNative().reduce(fn, rest[0]) : _allNative().reduce(fn);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
globalThis.bru.cookies.reduce = (fn, acc) => _allNative().reduce(fn, acc);
globalThis.bru.cookies.reduce = (fn, ...rest) => rest.length ? _allNative().reduce(fn, rest[0]) : _allNative().reduce(fn);
🤖 Prompt for AI Agents
In `@packages/bruno-js/src/sandbox/quickjs/shims/bru.js` at line 579, The wrapper
for globalThis.bru.cookies.reduce always forwards acc (which may be undefined)
and thus breaks the no-initial-value semantics; change the reduce wrapper around
_allNative() so it forwards the call conditionally: if the caller provided an
initial accumulator (check arguments.length or presence of a second arg) call
_allNative().reduce(fn, acc), otherwise call _allNative().reduce(fn) so the
native behavior (use first element as initial or throw on empty array) is
preserved; update the function bound to globalThis.bru.cookies.reduce
accordingly.

@ahamayeah59
Copy link

Glad to see a new cookies handling method. Anyway, don't forget to fix this before 9d3341e

@sanish-bruno
Copy link
Collaborator Author

Glad to see a new cookies handling method. Anyway, don't forget to fix this before 9d3341e

sure @ahamayeah59 #6679 the changes seems to be straight forward, will do my best to get it tested/reviewed and merged as soon as possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants