mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-29 15:44:13 +00:00
* feat(cookies): add direct cookie access methods and update translations
- 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.
* feat(cookies): enhance cookie management with new methods and refactor
- 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.
* docs(readonly-property-list): clarify array usage in constructor comments
* feat(cookies): add direct cookie manipulation tests and methods
* feat(cookies): add hasCookie method for checking cookie existence
* fix
* refactor(cookies): simplify cookie method translations
* feat(cookies): expand cookie API with new methods and tests
- Added new cookie methods: `get`, `has`, `toString`, `clear`, `upsert`, `remove`, `idx`, and `indexOf` to enhance cookie management.
- Updated translation mappings for `bru.cookies` to include new methods in `bruno-to-postman-translator` and `postman-to-bruno-translator`.
- Introduced tests for new methods and their interactions, ensuring comprehensive coverage of cookie functionalities.
- Enhanced existing tests to validate correct behavior of cookie methods across different scenarios.
* refactor(cookies): update CookieList to extend PropertyList and improve error handling
* test(cookies): add regression tests for jar and direct cookie patterns
- Introduced regression tests to ensure that jar patterns are correctly prioritized over direct cookie access patterns in translations.
- Updated `CookieList` to extend `ReadOnlyPropertyList` instead of `PropertyList`, clarifying its functionality.
- Refactored cookie method handling in the `bru` shim to utilize a new asynchronous bridge for improved error handling and consistency.
* refactor(cookies): update translations and remove PropertyList
- Enhanced comments in `postman-translations.js` to clarify the order of cookie jar translations.
- Updated `cookie-list.js` comments to better describe the factory function for the cookie jar.
- Removed the `PropertyList` class and its associated tests, streamlining the codebase and focusing on `ReadOnlyPropertyList` and `CookieList` for cookie management.
* fix(cookies): normalize tough-cookie objects and improve remove method comments
- Updated `CookieList` to normalize tough-cookie instances to plain objects, preventing circular references and exposing internal structures.
- Enhanced comments in the `remove` method to clarify behavior when removing non-existent or empty-named cookies.
* test(cookies): update tests to use async/await for consistency
* test(cookies): use async/await in cookie tests for consistency
* refactor(readonly-property-list): update get and reduce methods for improved behavior
* fix(cookies): update cookie method signature in autocomplete hints and enhance translation comments
- Modified the autocomplete hint for `bru.cookies.has` to include the new signature with an optional value parameter.
- Improved comments in `postman-translations.js` to clarify the order of cookie jar translation patterns for better understanding.
* refactor(cookies): introduce PropertyList for enhanced cookie management
* refactor(property-list): simplify repopulate method and enhance item handling logic
* feat(cookies): implement PropertyList bridge for enhanced cookie management
- Introduced a new `createPropertyListBridge` utility to streamline the integration of cookie methods into the QuickJS VM.
- Replaced the previous async cookie bridge with a more flexible approach, allowing for both synchronous and asynchronous cookie operations.
- Added comprehensive tests to validate the functionality of the new cookie methods in both developer and safe modes.
- Updated existing cookie tests to ensure compatibility with the new PropertyList structure.
* fix(tests): correct expected passed requests in cookie tests
- Updated the expected number of passed requests in the cookie tests from 34 to 6 to reflect the correct validation results.
- Ensured consistency in test assertions across multiple test cases for the PropertyList API.
* fix(cookies): update cookie URLs to use localhost for testing
- Changed all cookie-related test scripts to use `{{localhost}}` instead of `{{host}}` for the ping URL, ensuring consistency in local testing environments.
- Updated the cookie test suite to reflect the new URL structure, enhancing the reliability of the tests.
- Removed outdated cookie test files to streamline the test suite.
* refactor(cookies): standardize cookie handling with localhost variable
- Updated cookie test scripts to utilize the `{{localhost}}` variable for setting and retrieving cookies, ensuring consistency across tests.
- Enhanced clarity in comments regarding cookie behavior for different domains.
- Improved test assertions to validate cookie management functionality more effectively.
* refactor(property-list, readonly-property-list): update methods to use private class fields
* feat(cookies): enhance CookieList API with detailed documentation and method improvements
- Updated the `CookieList` class to provide comprehensive documentation on cookie management methods, including `add`, `upsert`, `remove`, and `delete`.
- Improved method signatures to support both callback and Promise-based usage for asynchronous operations.
- Added detailed descriptions for read and write methods, including examples and expected behavior.
- Enhanced the integration of the `CookieList` with the QuickJS VM by updating the property list bridge to include `toJSON` in sync read object methods.
* feat(cookies): add detailed examples and improve async bridge documentation
- Enhanced the `createPropertyListBridge` function documentation with comprehensive examples for setting up cookie methods in QuickJS.
- Clarified the two-phase setup process for async write methods, detailing the registration of bridge functions and the generation of JavaScript code for method wrappers.
- Added a new test case for the `toJSON()` method to ensure it returns a cloned array of all cookies, validating the expected structure and properties.
* fix(assert-runtime): correct syntax error in response parser assignment
- Added a semicolon at the end of the response parser assignment to ensure proper syntax in the AssertRuntime class.
273 lines
11 KiB
JavaScript
273 lines
11 KiB
JavaScript
const PropertyList = require('./property-list');
|
|
|
|
/**
|
|
* CookieList — the `bru.cookies` API for reading and writing cookies in scripts.
|
|
*
|
|
* Extends PropertyList in dynamic mode: the cookie list is freshly read from the
|
|
* cookie jar on every access, and write operations delegate to the jar rather
|
|
* than mutating an in-memory array.
|
|
*
|
|
* ---
|
|
*
|
|
* ## Cookie object shape
|
|
*
|
|
* Every cookie surfaced by this list is a plain object:
|
|
*
|
|
* ```js
|
|
* { key, value, domain, path, secure, httpOnly, expires }
|
|
* ```
|
|
*
|
|
* ---
|
|
*
|
|
* ## Read methods (inherited from ReadOnlyPropertyList)
|
|
*
|
|
* | Method | Description | Example return value |
|
|
* |--------------------|--------------------------------------------------|---------------------------------------|
|
|
* | `get(name)` | Value of the first cookie with `key === name` | `'abc123'` |
|
|
* | `one(name)` | Full cookie object for `key === name` | `{ key: 'sid', value: 'abc123', … }` |
|
|
* | `all()` | Cloned array of all cookie objects | `[{ key: 'sid', … }, …]` |
|
|
* | `idx(index)` | Cookie at positional index | `{ key: 'sid', … }` |
|
|
* | `count()` | Number of cookies for the current request URL | `3` |
|
|
*
|
|
* ## Search methods (inherited)
|
|
*
|
|
* | Method | Description | Example return value |
|
|
* |--------------------|--------------------------------------------------|----------------------|
|
|
* | `has(name)` | `true` if a cookie with that key exists | `true` |
|
|
* | `has(name, value)` | `true` if key exists **and** value matches | `false` |
|
|
* | `find(predicate)` | First cookie matching the predicate function | `{ key: 'sid', … }` |
|
|
* | `filter(predicate)`| Array of cookies matching the predicate | `[{ key: … }, …]` |
|
|
* | `indexOf(item)` | Index of a structurally-equal cookie, or `-1` | `0` |
|
|
*
|
|
* ## Iteration methods (inherited)
|
|
*
|
|
* | Method | Description |
|
|
* |-------------------------|----------------------------------------------|
|
|
* | `each(fn)` | Calls `fn(cookie, index)` for every cookie |
|
|
* | `map(fn)` | Returns a new array of mapped values |
|
|
* | `reduce(fn, initial?)` | Reduces cookies to a single value |
|
|
*
|
|
* ## Transform methods (inherited)
|
|
*
|
|
* | Method | Description | Example return value |
|
|
* |---------------|-----------------------------------------------------|-------------------------------------|
|
|
* | `toObject()` | `{ key: value }` map of all cookies | `{ sid: 'abc123', lang: 'en' }` |
|
|
* | `toString()` | Semicolon-separated `key=value` string | `'sid=abc123; lang=en'` |
|
|
* | `toJSON()` | Same as `all()` — suitable for `JSON.stringify()` | `[{ key: 'sid', … }]` |
|
|
*
|
|
* ## Write methods (CookieList overrides)
|
|
*
|
|
* | Method | Description |
|
|
* |--------------------------|------------------------------------------------------|
|
|
* | `add(cookieObj, cb?)` | Alias for `upsert()` — sets a cookie in the jar |
|
|
* | `upsert(cookieObj, cb?)` | Sets (or replaces) a cookie in the jar |
|
|
* | `remove(name, cb?)` | Deletes a single cookie by name (no-op if missing) |
|
|
* | `delete(name, cb?)` | Alias for `remove()` |
|
|
* | `clear(cb?)` | Removes **all** cookies for the current request URL |
|
|
*
|
|
* ## Jar access
|
|
*
|
|
* | Method | Description |
|
|
* |---------|--------------------------------------------------------------------------|
|
|
* | `jar()` | Returns a jar handle with URL interpolation for cross-URL cookie access |
|
|
*
|
|
* The jar handle exposes: `getCookie`, `getCookies`, `setCookie`, `setCookies`,
|
|
* `deleteCookie`, `deleteCookies`, `hasCookie`, and `clear`.
|
|
*/
|
|
class CookieList extends PropertyList {
|
|
/**
|
|
* @param {object} options
|
|
* @param {Function} options.getUrl - Returns the interpolated request URL (or falsy if unavailable)
|
|
* @param {Function} options.interpolate - Interpolates variables in a string
|
|
* @param {Function} options.createCookieJar - Factory that returns a cookie jar instance
|
|
* @param {Function} options.getCookiesForUrl - Returns cookies array for a given URL
|
|
*/
|
|
constructor({ getUrl, interpolate, createCookieJar, getCookiesForUrl }) {
|
|
super({
|
|
keyProperty: 'key',
|
|
dataSource: () => {
|
|
const url = getUrl();
|
|
if (!url) return [];
|
|
// Normalize tough-cookie Cookie instances to plain objects to avoid
|
|
// circular references and exposing internal library structures.
|
|
return getCookiesForUrl(url).map(({ key, value, domain, path, secure, httpOnly, expires }) =>
|
|
({ key, value, domain, path, secure, httpOnly, expires })
|
|
);
|
|
}
|
|
});
|
|
this._getUrl = getUrl;
|
|
this._interpolateFn = interpolate;
|
|
// Factory function — returns a wrapper around the module-level cookie jar singleton
|
|
this._createCookieJar = createCookieJar;
|
|
}
|
|
|
|
// ── Write methods (cookie jar delegation) ─────────────────────────────
|
|
|
|
/**
|
|
* Add a cookie to the jar (alias for {@link CookieList#upsert}).
|
|
*
|
|
* @param {object} cookieObj - Cookie object with at least `key` and `value`.
|
|
* @param {Function} [callback] - Optional `(error) => void` callback. If omitted, returns a Promise.
|
|
* @returns {Promise<void>|void} A Promise when no callback is given.
|
|
* @example
|
|
* // Promise usage
|
|
* await bru.cookies.add({ key: 'lang', value: 'en' });
|
|
*
|
|
* // Callback usage
|
|
* bru.cookies.add({ key: 'lang', value: 'en' }, (err) => { if (err) throw err; });
|
|
*/
|
|
add(cookieObj, callback) {
|
|
return this.upsert(cookieObj, callback);
|
|
}
|
|
|
|
/**
|
|
* Set (or replace) a cookie in the jar for the current request URL.
|
|
*
|
|
* If a cookie with the same key already exists for this URL, it is overwritten.
|
|
* Rejects with an error if `cookieObj` is not a non-null object.
|
|
*
|
|
* @param {object} cookieObj - Cookie object with at least `key` and `value`.
|
|
* @param {Function} [callback] - Optional `(error) => void` callback. If omitted, returns a Promise.
|
|
* @returns {Promise<void>|void} A Promise when no callback is given.
|
|
* @example
|
|
* await bru.cookies.upsert({ key: 'sid', value: 'abc123', secure: true });
|
|
*/
|
|
upsert(cookieObj, callback) {
|
|
if (!cookieObj || typeof cookieObj !== 'object') {
|
|
const error = new Error('cookieObj must be a non-null object');
|
|
if (callback) return callback(error);
|
|
return Promise.reject(error);
|
|
}
|
|
const url = this._getUrl();
|
|
if (!url) {
|
|
if (callback) return callback(undefined);
|
|
return Promise.resolve();
|
|
}
|
|
const jar = this._createCookieJar();
|
|
return jar.setCookie(url, cookieObj, callback);
|
|
}
|
|
|
|
/**
|
|
* Remove a single cookie by name from the current request URL.
|
|
*
|
|
* A no-op if `name` is falsy or if no cookie with that name exists
|
|
* (analogous to `Map.prototype.delete`).
|
|
*
|
|
* @param {string} name - The cookie key to remove.
|
|
* @param {Function} [callback] - Optional `(error) => void` callback. If omitted, returns a Promise.
|
|
* @returns {Promise<void>|void} A Promise when no callback is given.
|
|
* @example
|
|
* await bru.cookies.remove('sid');
|
|
*/
|
|
remove(name, callback) {
|
|
const url = this._getUrl();
|
|
if (!url || !name) {
|
|
if (callback) return callback(undefined);
|
|
return Promise.resolve();
|
|
}
|
|
const jar = this._createCookieJar();
|
|
return jar.deleteCookie(url, name, callback);
|
|
}
|
|
|
|
/**
|
|
* Remove cookies scoped to the current request URL only.
|
|
* Unlike jar().clear() which removes ALL cookies globally, this only
|
|
* removes cookies matching the current request's domain and path.
|
|
*/
|
|
clear(callback) {
|
|
const url = this._getUrl();
|
|
if (!url) {
|
|
if (callback) return callback(undefined);
|
|
return Promise.resolve();
|
|
}
|
|
const jar = this._createCookieJar();
|
|
return jar.deleteCookies(url, callback);
|
|
}
|
|
|
|
/**
|
|
* Delete a cookie by name (alias for {@link CookieList#remove}).
|
|
*
|
|
* @param {string} name - The cookie key to delete.
|
|
* @param {Function} [callback] - Optional `(error) => void` callback. If omitted, returns a Promise.
|
|
* @returns {Promise<void>|void} A Promise when no callback is given.
|
|
* @example
|
|
* await bru.cookies.delete('sid');
|
|
*/
|
|
delete(name, callback) {
|
|
return this.remove(name, callback);
|
|
}
|
|
|
|
// ── Cookie-specific method ────────────────────────────────────────────
|
|
|
|
/**
|
|
* Returns a jar handle for cross-URL cookie operations.
|
|
*
|
|
* Unlike the CookieList methods (which are scoped to the current request URL),
|
|
* the jar handle lets you read/write cookies for **any** URL. All URL arguments
|
|
* are automatically interpolated with environment/collection variables.
|
|
*
|
|
* @returns {{ getCookie, getCookies, setCookie, setCookies, deleteCookie, deleteCookies, hasCookie, clear }}
|
|
* @example
|
|
* const jar = bru.cookies.jar();
|
|
*
|
|
* // Read a cookie from a different URL
|
|
* const token = await jar.getCookie('{{authBaseUrl}}/login', 'access_token');
|
|
*
|
|
* // Set a cookie on a specific URL
|
|
* await jar.setCookie('{{apiBaseUrl}}', { key: 'sid', value: 'abc' });
|
|
* await jar.setCookie('{{apiBaseUrl}}', 'theme', 'dark');
|
|
*
|
|
* // Check if a cookie exists
|
|
* const exists = await jar.hasCookie('{{apiBaseUrl}}', 'sid');
|
|
*
|
|
* // Clear ALL cookies globally
|
|
* await jar.clear();
|
|
*/
|
|
jar() {
|
|
const cookieJar = this._createCookieJar();
|
|
|
|
return {
|
|
getCookie: (url, cookieName, callback) => {
|
|
const interpolatedUrl = this._interpolateFn(url);
|
|
return cookieJar.getCookie(interpolatedUrl, cookieName, callback);
|
|
},
|
|
|
|
getCookies: (url, callback) => {
|
|
const interpolatedUrl = this._interpolateFn(url);
|
|
return cookieJar.getCookies(interpolatedUrl, callback);
|
|
},
|
|
|
|
setCookie: (url, nameOrCookieObj, valueOrCallback, maybeCallback) => {
|
|
const interpolatedUrl = this._interpolateFn(url);
|
|
return cookieJar.setCookie(interpolatedUrl, nameOrCookieObj, valueOrCallback, maybeCallback);
|
|
},
|
|
|
|
setCookies: (url, cookiesArray, callback) => {
|
|
const interpolatedUrl = this._interpolateFn(url);
|
|
return cookieJar.setCookies(interpolatedUrl, cookiesArray, callback);
|
|
},
|
|
|
|
clear: (callback) => {
|
|
return cookieJar.clear(callback);
|
|
},
|
|
|
|
deleteCookies: (url, callback) => {
|
|
const interpolatedUrl = this._interpolateFn(url);
|
|
return cookieJar.deleteCookies(interpolatedUrl, callback);
|
|
},
|
|
|
|
deleteCookie: (url, cookieName, callback) => {
|
|
const interpolatedUrl = this._interpolateFn(url);
|
|
return cookieJar.deleteCookie(interpolatedUrl, cookieName, callback);
|
|
},
|
|
|
|
hasCookie: (url, cookieName, callback) => {
|
|
const interpolatedUrl = this._interpolateFn(url);
|
|
return cookieJar.hasCookie(interpolatedUrl, cookieName, callback);
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
module.exports = CookieList;
|