@usebruno/js 0.46.1 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -7
- package/src/bru.js +173 -75
- package/src/bruno-request.js +15 -7
- package/src/bruno-response.js +4 -0
- package/src/cookie-list.js +272 -0
- package/src/header-list.js +497 -0
- package/src/index.js +27 -2
- package/src/property-list.js +184 -0
- package/src/readonly-property-list.js +227 -0
- package/src/runtime/assert-runtime.js +164 -10
- package/src/runtime/script-runtime.js +55 -6
- package/src/runtime/test-runtime.js +19 -1
- package/src/runtime/vars-runtime.js +20 -3
- package/src/sandbox/bundle-browser-rollup.js +72 -66
- package/src/sandbox/bundle-libraries.js +10 -2
- package/src/sandbox/quickjs/index.js +8 -41
- package/src/sandbox/quickjs/shims/bru.js +31 -1
- package/src/sandbox/quickjs/shims/bruno-request.js +24 -3
- package/src/sandbox/quickjs/shims/bruno-response.js +57 -5
- package/src/sandbox/quickjs/shims/bruno-response.spec.js +91 -0
- package/src/sandbox/quickjs/shims/lib/uuid.spec.js +166 -0
- package/src/sandbox/quickjs/shims/require.js +56 -0
- package/src/sandbox/quickjs/shims/require.spec.js +154 -0
- package/src/sandbox/quickjs/shims/test.js +175 -2
- package/src/sandbox/quickjs/utils/property-list-bridge.js +190 -0
- package/src/sandbox/quickjs/utils/test-helpers.js +31 -0
- package/src/utils/error-formatter.js +345 -20
- package/src/utils/error-formatter.spec.js +683 -1
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
const PropertyList = require('./property-list');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CookieList — the `bru.cookies` API for reading and writing cookies in scripts.
|
|
5
|
+
*
|
|
6
|
+
* Extends PropertyList in dynamic mode: the cookie list is freshly read from the
|
|
7
|
+
* cookie jar on every access, and write operations delegate to the jar rather
|
|
8
|
+
* than mutating an in-memory array.
|
|
9
|
+
*
|
|
10
|
+
* ---
|
|
11
|
+
*
|
|
12
|
+
* ## Cookie object shape
|
|
13
|
+
*
|
|
14
|
+
* Every cookie surfaced by this list is a plain object:
|
|
15
|
+
*
|
|
16
|
+
* ```js
|
|
17
|
+
* { key, value, domain, path, secure, httpOnly, expires }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* ---
|
|
21
|
+
*
|
|
22
|
+
* ## Read methods (inherited from ReadOnlyPropertyList)
|
|
23
|
+
*
|
|
24
|
+
* | Method | Description | Example return value |
|
|
25
|
+
* |--------------------|--------------------------------------------------|---------------------------------------|
|
|
26
|
+
* | `get(name)` | Value of the first cookie with `key === name` | `'abc123'` |
|
|
27
|
+
* | `one(name)` | Full cookie object for `key === name` | `{ key: 'sid', value: 'abc123', … }` |
|
|
28
|
+
* | `all()` | Cloned array of all cookie objects | `[{ key: 'sid', … }, …]` |
|
|
29
|
+
* | `idx(index)` | Cookie at positional index | `{ key: 'sid', … }` |
|
|
30
|
+
* | `count()` | Number of cookies for the current request URL | `3` |
|
|
31
|
+
*
|
|
32
|
+
* ## Search methods (inherited)
|
|
33
|
+
*
|
|
34
|
+
* | Method | Description | Example return value |
|
|
35
|
+
* |--------------------|--------------------------------------------------|----------------------|
|
|
36
|
+
* | `has(name)` | `true` if a cookie with that key exists | `true` |
|
|
37
|
+
* | `has(name, value)` | `true` if key exists **and** value matches | `false` |
|
|
38
|
+
* | `find(predicate)` | First cookie matching the predicate function | `{ key: 'sid', … }` |
|
|
39
|
+
* | `filter(predicate)`| Array of cookies matching the predicate | `[{ key: … }, …]` |
|
|
40
|
+
* | `indexOf(item)` | Index of a structurally-equal cookie, or `-1` | `0` |
|
|
41
|
+
*
|
|
42
|
+
* ## Iteration methods (inherited)
|
|
43
|
+
*
|
|
44
|
+
* | Method | Description |
|
|
45
|
+
* |-------------------------|----------------------------------------------|
|
|
46
|
+
* | `each(fn)` | Calls `fn(cookie, index)` for every cookie |
|
|
47
|
+
* | `map(fn)` | Returns a new array of mapped values |
|
|
48
|
+
* | `reduce(fn, initial?)` | Reduces cookies to a single value |
|
|
49
|
+
*
|
|
50
|
+
* ## Transform methods (inherited)
|
|
51
|
+
*
|
|
52
|
+
* | Method | Description | Example return value |
|
|
53
|
+
* |---------------|-----------------------------------------------------|-------------------------------------|
|
|
54
|
+
* | `toObject()` | `{ key: value }` map of all cookies | `{ sid: 'abc123', lang: 'en' }` |
|
|
55
|
+
* | `toString()` | Semicolon-separated `key=value` string | `'sid=abc123; lang=en'` |
|
|
56
|
+
* | `toJSON()` | Same as `all()` — suitable for `JSON.stringify()` | `[{ key: 'sid', … }]` |
|
|
57
|
+
*
|
|
58
|
+
* ## Write methods (CookieList overrides)
|
|
59
|
+
*
|
|
60
|
+
* | Method | Description |
|
|
61
|
+
* |--------------------------|------------------------------------------------------|
|
|
62
|
+
* | `add(cookieObj, cb?)` | Alias for `upsert()` — sets a cookie in the jar |
|
|
63
|
+
* | `upsert(cookieObj, cb?)` | Sets (or replaces) a cookie in the jar |
|
|
64
|
+
* | `remove(name, cb?)` | Deletes a single cookie by name (no-op if missing) |
|
|
65
|
+
* | `delete(name, cb?)` | Alias for `remove()` |
|
|
66
|
+
* | `clear(cb?)` | Removes **all** cookies for the current request URL |
|
|
67
|
+
*
|
|
68
|
+
* ## Jar access
|
|
69
|
+
*
|
|
70
|
+
* | Method | Description |
|
|
71
|
+
* |---------|--------------------------------------------------------------------------|
|
|
72
|
+
* | `jar()` | Returns a jar handle with URL interpolation for cross-URL cookie access |
|
|
73
|
+
*
|
|
74
|
+
* The jar handle exposes: `getCookie`, `getCookies`, `setCookie`, `setCookies`,
|
|
75
|
+
* `deleteCookie`, `deleteCookies`, `hasCookie`, and `clear`.
|
|
76
|
+
*/
|
|
77
|
+
class CookieList extends PropertyList {
|
|
78
|
+
/**
|
|
79
|
+
* @param {object} options
|
|
80
|
+
* @param {Function} options.getUrl - Returns the interpolated request URL (or falsy if unavailable)
|
|
81
|
+
* @param {Function} options.interpolate - Interpolates variables in a string
|
|
82
|
+
* @param {Function} options.createCookieJar - Factory that returns a cookie jar instance
|
|
83
|
+
* @param {Function} options.getCookiesForUrl - Returns cookies array for a given URL
|
|
84
|
+
*/
|
|
85
|
+
constructor({ getUrl, interpolate, createCookieJar, getCookiesForUrl }) {
|
|
86
|
+
super({
|
|
87
|
+
keyProperty: 'key',
|
|
88
|
+
dataSource: () => {
|
|
89
|
+
const url = getUrl();
|
|
90
|
+
if (!url) return [];
|
|
91
|
+
// Normalize tough-cookie Cookie instances to plain objects to avoid
|
|
92
|
+
// circular references and exposing internal library structures.
|
|
93
|
+
return getCookiesForUrl(url).map(({ key, value, domain, path, secure, httpOnly, expires }) =>
|
|
94
|
+
({ key, value, domain, path, secure, httpOnly, expires })
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
this._getUrl = getUrl;
|
|
99
|
+
this._interpolateFn = interpolate;
|
|
100
|
+
// Factory function — returns a wrapper around the module-level cookie jar singleton
|
|
101
|
+
this._createCookieJar = createCookieJar;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ── Write methods (cookie jar delegation) ─────────────────────────────
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Add a cookie to the jar (alias for {@link CookieList#upsert}).
|
|
108
|
+
*
|
|
109
|
+
* @param {object} cookieObj - Cookie object with at least `key` and `value`.
|
|
110
|
+
* @param {Function} [callback] - Optional `(error) => void` callback. If omitted, returns a Promise.
|
|
111
|
+
* @returns {Promise<void>|void} A Promise when no callback is given.
|
|
112
|
+
* @example
|
|
113
|
+
* // Promise usage
|
|
114
|
+
* await bru.cookies.add({ key: 'lang', value: 'en' });
|
|
115
|
+
*
|
|
116
|
+
* // Callback usage
|
|
117
|
+
* bru.cookies.add({ key: 'lang', value: 'en' }, (err) => { if (err) throw err; });
|
|
118
|
+
*/
|
|
119
|
+
add(cookieObj, callback) {
|
|
120
|
+
return this.upsert(cookieObj, callback);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Set (or replace) a cookie in the jar for the current request URL.
|
|
125
|
+
*
|
|
126
|
+
* If a cookie with the same key already exists for this URL, it is overwritten.
|
|
127
|
+
* Rejects with an error if `cookieObj` is not a non-null object.
|
|
128
|
+
*
|
|
129
|
+
* @param {object} cookieObj - Cookie object with at least `key` and `value`.
|
|
130
|
+
* @param {Function} [callback] - Optional `(error) => void` callback. If omitted, returns a Promise.
|
|
131
|
+
* @returns {Promise<void>|void} A Promise when no callback is given.
|
|
132
|
+
* @example
|
|
133
|
+
* await bru.cookies.upsert({ key: 'sid', value: 'abc123', secure: true });
|
|
134
|
+
*/
|
|
135
|
+
upsert(cookieObj, callback) {
|
|
136
|
+
if (!cookieObj || typeof cookieObj !== 'object') {
|
|
137
|
+
const error = new Error('cookieObj must be a non-null object');
|
|
138
|
+
if (callback) return callback(error);
|
|
139
|
+
return Promise.reject(error);
|
|
140
|
+
}
|
|
141
|
+
const url = this._getUrl();
|
|
142
|
+
if (!url) {
|
|
143
|
+
if (callback) return callback(undefined);
|
|
144
|
+
return Promise.resolve();
|
|
145
|
+
}
|
|
146
|
+
const jar = this._createCookieJar();
|
|
147
|
+
return jar.setCookie(url, cookieObj, callback);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Remove a single cookie by name from the current request URL.
|
|
152
|
+
*
|
|
153
|
+
* A no-op if `name` is falsy or if no cookie with that name exists
|
|
154
|
+
* (analogous to `Map.prototype.delete`).
|
|
155
|
+
*
|
|
156
|
+
* @param {string} name - The cookie key to remove.
|
|
157
|
+
* @param {Function} [callback] - Optional `(error) => void` callback. If omitted, returns a Promise.
|
|
158
|
+
* @returns {Promise<void>|void} A Promise when no callback is given.
|
|
159
|
+
* @example
|
|
160
|
+
* await bru.cookies.remove('sid');
|
|
161
|
+
*/
|
|
162
|
+
remove(name, callback) {
|
|
163
|
+
const url = this._getUrl();
|
|
164
|
+
if (!url || !name) {
|
|
165
|
+
if (callback) return callback(undefined);
|
|
166
|
+
return Promise.resolve();
|
|
167
|
+
}
|
|
168
|
+
const jar = this._createCookieJar();
|
|
169
|
+
return jar.deleteCookie(url, name, callback);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Remove cookies scoped to the current request URL only.
|
|
174
|
+
* Unlike jar().clear() which removes ALL cookies globally, this only
|
|
175
|
+
* removes cookies matching the current request's domain and path.
|
|
176
|
+
*/
|
|
177
|
+
clear(callback) {
|
|
178
|
+
const url = this._getUrl();
|
|
179
|
+
if (!url) {
|
|
180
|
+
if (callback) return callback(undefined);
|
|
181
|
+
return Promise.resolve();
|
|
182
|
+
}
|
|
183
|
+
const jar = this._createCookieJar();
|
|
184
|
+
return jar.deleteCookies(url, callback);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Delete a cookie by name (alias for {@link CookieList#remove}).
|
|
189
|
+
*
|
|
190
|
+
* @param {string} name - The cookie key to delete.
|
|
191
|
+
* @param {Function} [callback] - Optional `(error) => void` callback. If omitted, returns a Promise.
|
|
192
|
+
* @returns {Promise<void>|void} A Promise when no callback is given.
|
|
193
|
+
* @example
|
|
194
|
+
* await bru.cookies.delete('sid');
|
|
195
|
+
*/
|
|
196
|
+
delete(name, callback) {
|
|
197
|
+
return this.remove(name, callback);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ── Cookie-specific method ────────────────────────────────────────────
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Returns a jar handle for cross-URL cookie operations.
|
|
204
|
+
*
|
|
205
|
+
* Unlike the CookieList methods (which are scoped to the current request URL),
|
|
206
|
+
* the jar handle lets you read/write cookies for **any** URL. All URL arguments
|
|
207
|
+
* are automatically interpolated with environment/collection variables.
|
|
208
|
+
*
|
|
209
|
+
* @returns {{ getCookie, getCookies, setCookie, setCookies, deleteCookie, deleteCookies, hasCookie, clear }}
|
|
210
|
+
* @example
|
|
211
|
+
* const jar = bru.cookies.jar();
|
|
212
|
+
*
|
|
213
|
+
* // Read a cookie from a different URL
|
|
214
|
+
* const token = await jar.getCookie('{{authBaseUrl}}/login', 'access_token');
|
|
215
|
+
*
|
|
216
|
+
* // Set a cookie on a specific URL
|
|
217
|
+
* await jar.setCookie('{{apiBaseUrl}}', { key: 'sid', value: 'abc' });
|
|
218
|
+
* await jar.setCookie('{{apiBaseUrl}}', 'theme', 'dark');
|
|
219
|
+
*
|
|
220
|
+
* // Check if a cookie exists
|
|
221
|
+
* const exists = await jar.hasCookie('{{apiBaseUrl}}', 'sid');
|
|
222
|
+
*
|
|
223
|
+
* // Clear ALL cookies globally
|
|
224
|
+
* await jar.clear();
|
|
225
|
+
*/
|
|
226
|
+
jar() {
|
|
227
|
+
const cookieJar = this._createCookieJar();
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
getCookie: (url, cookieName, callback) => {
|
|
231
|
+
const interpolatedUrl = this._interpolateFn(url);
|
|
232
|
+
return cookieJar.getCookie(interpolatedUrl, cookieName, callback);
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
getCookies: (url, callback) => {
|
|
236
|
+
const interpolatedUrl = this._interpolateFn(url);
|
|
237
|
+
return cookieJar.getCookies(interpolatedUrl, callback);
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
setCookie: (url, nameOrCookieObj, valueOrCallback, maybeCallback) => {
|
|
241
|
+
const interpolatedUrl = this._interpolateFn(url);
|
|
242
|
+
return cookieJar.setCookie(interpolatedUrl, nameOrCookieObj, valueOrCallback, maybeCallback);
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
setCookies: (url, cookiesArray, callback) => {
|
|
246
|
+
const interpolatedUrl = this._interpolateFn(url);
|
|
247
|
+
return cookieJar.setCookies(interpolatedUrl, cookiesArray, callback);
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
clear: (callback) => {
|
|
251
|
+
return cookieJar.clear(callback);
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
deleteCookies: (url, callback) => {
|
|
255
|
+
const interpolatedUrl = this._interpolateFn(url);
|
|
256
|
+
return cookieJar.deleteCookies(interpolatedUrl, callback);
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
deleteCookie: (url, cookieName, callback) => {
|
|
260
|
+
const interpolatedUrl = this._interpolateFn(url);
|
|
261
|
+
return cookieJar.deleteCookie(interpolatedUrl, cookieName, callback);
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
hasCookie: (url, cookieName, callback) => {
|
|
265
|
+
const interpolatedUrl = this._interpolateFn(url);
|
|
266
|
+
return cookieJar.hasCookie(interpolatedUrl, cookieName, callback);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
module.exports = CookieList;
|