@usebruno/filestore 0.1.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.
Files changed (40) hide show
  1. package/LICENSE.md +22 -0
  2. package/README.md +50 -0
  3. package/dist/cjs/formats/bru/index.d.ts +6 -0
  4. package/dist/cjs/index.d.ts +15 -0
  5. package/dist/cjs/index.js +2 -0
  6. package/dist/cjs/index.js.map +1 -0
  7. package/dist/cjs/types.d.ts +142 -0
  8. package/dist/cjs/workers/WorkerQueue/index.d.ts +26 -0
  9. package/dist/cjs/workers/formats/bru/index.d.ts +6 -0
  10. package/dist/cjs/workers/index.d.ts +15 -0
  11. package/dist/cjs/workers/types.d.ts +142 -0
  12. package/dist/cjs/workers/worker-script.d.ts +1 -0
  13. package/dist/cjs/workers/worker-script.js +2 -0
  14. package/dist/cjs/workers/worker-script.js.map +1 -0
  15. package/dist/cjs/workers/workers/WorkerQueue/index.d.ts +26 -0
  16. package/dist/cjs/workers/workers/index.d.ts +10 -0
  17. package/dist/cjs/workers/workers/worker-script.d.ts +1 -0
  18. package/dist/esm/formats/bru/index.d.ts +6 -0
  19. package/dist/esm/index.d.ts +15 -0
  20. package/dist/esm/index.js +2 -0
  21. package/dist/esm/index.js.map +1 -0
  22. package/dist/esm/types.d.ts +142 -0
  23. package/dist/esm/workers/WorkerQueue/index.d.ts +26 -0
  24. package/dist/esm/workers/formats/bru/index.d.ts +6 -0
  25. package/dist/esm/workers/index.d.ts +15 -0
  26. package/dist/esm/workers/types.d.ts +142 -0
  27. package/dist/esm/workers/worker-script.d.ts +1 -0
  28. package/dist/esm/workers/worker-script.js +2 -0
  29. package/dist/esm/workers/worker-script.js.map +1 -0
  30. package/dist/esm/workers/workers/WorkerQueue/index.d.ts +26 -0
  31. package/dist/esm/workers/workers/index.d.ts +10 -0
  32. package/dist/esm/workers/workers/worker-script.d.ts +1 -0
  33. package/package.json +47 -0
  34. package/src/formats/bru/index.ts +203 -0
  35. package/src/index.ts +100 -0
  36. package/src/types/bruno-lang.d.ts +9 -0
  37. package/src/types.ts +141 -0
  38. package/src/workers/WorkerQueue/index.ts +114 -0
  39. package/src/workers/index.ts +86 -0
  40. package/src/workers/worker-script.ts +27 -0
package/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+
2
+ MIT License
3
+
4
+ Copyright (c) 2022 Anoop M D, Anusree P S and Contributors
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # Bruno Filestore
2
+
3
+ A generic file storage and parsing package for Bruno API client.
4
+
5
+ ## Purpose
6
+
7
+ This package abstracts the file format operations for Bruno, providing a clean interface for parsing and stringifying Bruno requests, collections, folders, and environments.
8
+
9
+ ## Features
10
+
11
+ - Format-agnostic APIs for file operations
12
+ - Currently supports Bruno's custom `.bru` format
13
+ - Designed for future extensibility to support YAML and other formats
14
+
15
+ ## Usage
16
+
17
+ ```javascript
18
+ const {
19
+ parseRequest,
20
+ stringifyRequest,
21
+ parseCollection,
22
+ stringifyCollection,
23
+ parseEnvironment,
24
+ stringifyEnvironment,
25
+ parseDotEnv
26
+ } = require('@usebruno/filestore');
27
+
28
+ // Parse a .bru request file
29
+ const requestData = parseRequest(bruContent);
30
+
31
+ // Stringify request data to .bru format
32
+ const bruContent = stringifyRequest(requestData);
33
+
34
+ // Example with future format support (not yet implemented)
35
+ const requestData = parseRequest(yamlContent, { format: 'yaml' });
36
+ ```
37
+
38
+ ## API
39
+
40
+ The package provides the following functions:
41
+
42
+ - `parseRequest(content, options = { format: 'bru' })`: Parse request file content
43
+ - `stringifyRequest(requestObj, options = { format: 'bru' })`: Convert request object to file content
44
+ - `parseCollection(content, options = { format: 'bru' })`: Parse collection file content
45
+ - `stringifyCollection(collectionObj, options = { format: 'bru' })`: Convert collection object to file content
46
+ - `parseFolder(content, options = { format: 'bru' })`: Parse folder file content
47
+ - `stringifyFolder(folderObj, options = { format: 'bru' })`: Convert folder object to file content
48
+ - `parseEnvironment(content, options = { format: 'bru' })`: Parse environment file content
49
+ - `stringifyEnvironment(envObj, options = { format: 'bru' })`: Convert environment object to file content
50
+ - `parseDotEnv(content)`: Parse .env file content
@@ -0,0 +1,6 @@
1
+ export declare const bruRequestToJson: (data: string | any, parsed?: boolean) => any;
2
+ export declare const jsonRequestToBru: (json: any) => string;
3
+ export declare const bruCollectionToJson: (data: string | any, parsed?: boolean) => any;
4
+ export declare const jsonCollectionToBru: (json: any, isFolder?: boolean) => string;
5
+ export declare const bruEnvironmentToJson: (bru: string) => any;
6
+ export declare const jsonEnvironmentToBru: (json: any) => string;
@@ -0,0 +1,15 @@
1
+ import BruParserWorker from './workers';
2
+ import { ParseOptions, StringifyOptions, ParsedRequest, ParsedCollection, ParsedEnvironment } from './types';
3
+ export declare const parseRequest: (content: string, options?: ParseOptions) => any;
4
+ export declare const stringifyRequest: (requestObj: ParsedRequest, options?: StringifyOptions) => string;
5
+ export declare const parseRequestViaWorker: (content: string) => Promise<any>;
6
+ export declare const stringifyRequestViaWorker: (requestObj: any) => Promise<string>;
7
+ export declare const parseCollection: (content: string, options?: ParseOptions) => any;
8
+ export declare const stringifyCollection: (collectionObj: ParsedCollection, options?: StringifyOptions) => string;
9
+ export declare const parseFolder: (content: string, options?: ParseOptions) => any;
10
+ export declare const stringifyFolder: (folderObj: any, options?: StringifyOptions) => string;
11
+ export declare const parseEnvironment: (content: string, options?: ParseOptions) => any;
12
+ export declare const stringifyEnvironment: (envObj: ParsedEnvironment, options?: StringifyOptions) => string;
13
+ export declare const parseDotEnv: (content: string) => Record<string, string>;
14
+ export { BruParserWorker };
15
+ export * from './types';
@@ -0,0 +1,2 @@
1
+ "use strict";var e=require("lodash"),t=require("@usebruno/lang"),r=require("node:worker_threads"),s=require("node:path");function o(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var s=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,s.get?s:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var a=o(e);const u=(e,r=!1)=>{try{const s=r?e:t.collectionBruToJson(e),o={request:{headers:a.get(s,"headers",[]),auth:a.get(s,"auth",{}),script:a.get(s,"script",{}),vars:a.get(s,"vars",{}),tests:a.get(s,"tests","")},settings:a.get(s,"settings",{}),docs:a.get(s,"docs","")};if(s.meta&&(o.meta={name:s.meta.name},void 0!==s.meta.seq)){const e=s.meta.seq;o.meta.seq=isNaN(e)?1:Number(e)}return o}catch(e){return Promise.reject(e)}},n=(e,r)=>{try{const s={headers:a.get(e,"request.headers",[]),script:{req:a.get(e,"request.script.req",""),res:a.get(e,"request.script.res","")},vars:{req:a.get(e,"request.vars.req",[]),res:a.get(e,"request.vars.res",[])},tests:a.get(e,"request.tests",""),auth:a.get(e,"request.auth",{}),docs:a.get(e,"docs","")};if(e?.meta&&(s.meta={name:e.meta.name},void 0!==e.meta.seq)){const t=e.meta.seq;s.meta.seq=isNaN(t)?1:Number(t)}return r||(s.auth=a.get(e,"request.auth",{})),t.jsonToCollectionBru(s)}catch(e){throw e}};class i{constructor(){this.queue=[],this.isProcessing=!1,this.workers={}}async getWorkerForScriptPath(e){this.workers||(this.workers={});let t=this.workers[e];return t&&-1!==t.threadId||(this.workers[e]=t=new r.Worker(e)),t}async enqueue(e){const{priority:t,scriptPath:r,data:s,taskType:o}=e;return new Promise(((e,a)=>{this.queue.push({priority:t,scriptPath:r,data:s,taskType:o,resolve:e,reject:a}),this.queue?.sort(((e,t)=>e?.priority-t?.priority)),this.processQueue()}))}async processQueue(){if(this.isProcessing||0===this.queue.length)return;this.isProcessing=!0;const{scriptPath:e,data:t,taskType:r,resolve:s,reject:o}=this.queue.shift();try{const o=await this.runWorker({scriptPath:e,data:t,taskType:r});s?.(o)}catch(e){o?.(e)}finally{this.isProcessing=!1,this.processQueue()}}async runWorker({scriptPath:e,data:t,taskType:r}){return new Promise((async(s,o)=>{let a=await this.getWorkerForScriptPath(e);const u=e=>{a.off("message",u),a.off("error",n),a.off("exit",i),e?.error?o(new Error(e?.error)):s(e)},n=e=>{a.off("message",u),a.off("error",n),a.off("exit",i),o(e)},i=t=>{a.off("message",u),a.off("error",n),a.off("exit",i),delete this.workers[e],o(new Error(`Worker stopped with exit code ${t}`))};a.on("message",u),a.on("error",n),a.on("exit",i),a.postMessage({taskType:r,data:t})}))}async cleanup(){const e=Object.values(this.workers).map((e=>-1!==e.threadId?e.terminate():Promise.resolve()));await Promise.allSettled(e),this.workers={}}}const c=[{maxSize:.005},{maxSize:.1},{maxSize:1},{maxSize:10},{maxSize:100}];class p{constructor(){this.workerQueues=c?.map((e=>({maxSize:e?.maxSize,workerQueue:new i})))}getWorkerQueue(e){const t=this.workerQueues.find((t=>t.maxSize>=e));return t?.workerQueue??this.workerQueues[this.workerQueues.length-1].workerQueue}async enqueueTask({data:e,taskType:t}){const r=(e=>("string"==typeof e?Buffer.byteLength(e,"utf8"):Buffer.byteLength(JSON.stringify(e),"utf8"))/1048576)(e),o=this.getWorkerQueue(r),a=s.join(__dirname,"./workers/worker-script.js");return o.enqueue({data:e,priority:r,scriptPath:a,taskType:t})}async parseRequest(e){return this.enqueueTask({data:e,taskType:"parse"})}async stringifyRequest(e){return this.enqueueTask({data:e,taskType:"stringify"})}async cleanup(){const e=this.workerQueues.map((({workerQueue:e})=>e.cleanup()));await Promise.allSettled(e)}}let h=null;const m=()=>(h||(h=new p),h);exports.BruParserWorker=p,exports.parseCollection=(e,t={format:"bru"})=>{if("bru"===t.format)return u(e);throw new Error(`Unsupported format: ${t.format}`)},exports.parseDotEnv=e=>t.dotenvToJson(e),exports.parseEnvironment=(e,r={format:"bru"})=>{if("bru"===r.format)return(e=>{try{const r=t.bruToEnvJsonV2(e);return r&&r.variables&&r.variables.length&&a.each(r.variables,(e=>e.type="text")),r}catch(e){return Promise.reject(e)}})(e);throw new Error(`Unsupported format: ${r.format}`)},exports.parseFolder=(e,t={format:"bru"})=>{if("bru"===t.format)return u(e);throw new Error(`Unsupported format: ${t.format}`)},exports.parseRequest=(e,r={format:"bru"})=>{if("bru"===r.format)return((e,r=!1)=>{try{const s=r?e:t.bruToJsonV2(e);let o=a.get(s,"meta.type");o="http"===o?"http-request":"graphql"===o?"graphql-request":"http-request";const u=a.get(s,"meta.seq"),n={type:o,name:a.get(s,"meta.name"),seq:a.isNaN(u)?1:Number(u),settings:a.get(s,"settings",{}),tags:a.get(s,"meta.tags",[]),request:{method:a.upperCase(a.get(s,"http.method")),url:a.get(s,"http.url"),params:a.get(s,"params",[]),headers:a.get(s,"headers",[]),auth:a.get(s,"auth",{}),body:a.get(s,"body",{}),script:a.get(s,"script",{}),vars:a.get(s,"vars",{}),assertions:a.get(s,"assertions",[]),tests:a.get(s,"tests",""),docs:a.get(s,"docs","")}};return n.request.auth.mode=a.get(s,"http.auth","none"),n.request.body.mode=a.get(s,"http.body","none"),n}catch(e){return Promise.reject(e)}})(e);throw new Error(`Unsupported format: ${r.format}`)},exports.parseRequestViaWorker=async e=>{const t=m();return await t.parseRequest(e)},exports.stringifyCollection=(e,t={format:"bru"})=>{if("bru"===t.format)return n(e,!1);throw new Error(`Unsupported format: ${t.format}`)},exports.stringifyEnvironment=(e,r={format:"bru"})=>{if("bru"===r.format)return(e=>{try{return t.envJsonToBruV2(e)}catch(e){throw e}})(e);throw new Error(`Unsupported format: ${r.format}`)},exports.stringifyFolder=(e,t={format:"bru"})=>{if("bru"===t.format)return n(e,!0);throw new Error(`Unsupported format: ${t.format}`)},exports.stringifyRequest=(e,r={format:"bru"})=>{if("bru"===r.format)return(e=>{try{let r=a.get(e,"type");r="http-request"===r?"http":"graphql-request"===r?"graphql":"http";const s=a.get(e,"seq"),o={meta:{name:a.get(e,"name"),type:r,seq:a.isNaN(s)?1:Number(s),tags:a.get(e,"tags",[])},http:{method:a.lowerCase(a.get(e,"request.method")),url:a.get(e,"request.url"),auth:a.get(e,"request.auth.mode","none"),body:a.get(e,"request.body.mode","none")},params:a.get(e,"request.params",[]),headers:a.get(e,"request.headers",[]),auth:a.get(e,"request.auth",{}),body:a.get(e,"request.body",{}),script:a.get(e,"request.script",{}),vars:{req:a.get(e,"request.vars.req",[]),res:a.get(e,"request.vars.res",[])},assertions:a.get(e,"request.assertions",[]),tests:a.get(e,"request.tests",""),settings:a.get(e,"settings",{}),docs:a.get(e,"request.docs","")};return t.jsonToBruV2(o)}catch(e){throw e}})(e);throw new Error(`Unsupported format: ${r.format}`)},exports.stringifyRequestViaWorker=async e=>{const t=m();return await t.stringifyRequest(e)};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../src/formats/bru/index.ts","../../src/workers/WorkerQueue/index.ts","../../src/workers/index.ts","../../src/index.ts"],"sourcesContent":["import * as _ from 'lodash';\nimport {\n bruToJsonV2,\n jsonToBruV2,\n bruToEnvJsonV2,\n envJsonToBruV2,\n collectionBruToJson as _collectionBruToJson,\n jsonToCollectionBru as _jsonToCollectionBru\n} from '@usebruno/lang';\n\nexport const bruRequestToJson = (data: string | any, parsed: boolean = false): any => {\n try {\n const json = parsed ? data : bruToJsonV2(data);\n\n let requestType = _.get(json, 'meta.type');\n if (requestType === 'http') {\n requestType = 'http-request';\n } else if (requestType === 'graphql') {\n requestType = 'graphql-request';\n } else {\n requestType = 'http-request';\n }\n\n const sequence = _.get(json, 'meta.seq');\n const transformedJson = {\n type: requestType,\n name: _.get(json, 'meta.name'),\n seq: !_.isNaN(sequence) ? Number(sequence) : 1,\n settings: _.get(json, 'settings', {}),\n tags: _.get(json, 'meta.tags', []),\n request: {\n method: _.upperCase(_.get(json, 'http.method')),\n url: _.get(json, 'http.url'),\n params: _.get(json, 'params', []),\n headers: _.get(json, 'headers', []),\n auth: _.get(json, 'auth', {}),\n body: _.get(json, 'body', {}),\n script: _.get(json, 'script', {}),\n vars: _.get(json, 'vars', {}),\n assertions: _.get(json, 'assertions', []),\n tests: _.get(json, 'tests', ''),\n docs: _.get(json, 'docs', '')\n }\n };\n\n transformedJson.request.auth.mode = _.get(json, 'http.auth', 'none');\n transformedJson.request.body.mode = _.get(json, 'http.body', 'none');\n\n return transformedJson;\n } catch (e) {\n return Promise.reject(e);\n }\n};\n\nexport const jsonRequestToBru = (json: any): string => {\n try {\n let type = _.get(json, 'type');\n if (type === 'http-request') {\n type = 'http';\n } else if (type === 'graphql-request') {\n type = 'graphql';\n } else {\n type = 'http';\n }\n\n const sequence = _.get(json, 'seq');\n const bruJson = {\n meta: {\n name: _.get(json, 'name'),\n type: type,\n seq: !_.isNaN(sequence) ? Number(sequence) : 1,\n tags: _.get(json, 'tags', []),\n },\n http: {\n method: _.lowerCase(_.get(json, 'request.method')),\n url: _.get(json, 'request.url'),\n auth: _.get(json, 'request.auth.mode', 'none'),\n body: _.get(json, 'request.body.mode', 'none')\n },\n params: _.get(json, 'request.params', []),\n headers: _.get(json, 'request.headers', []),\n auth: _.get(json, 'request.auth', {}),\n body: _.get(json, 'request.body', {}),\n script: _.get(json, 'request.script', {}),\n vars: {\n req: _.get(json, 'request.vars.req', []),\n res: _.get(json, 'request.vars.res', [])\n },\n assertions: _.get(json, 'request.assertions', []),\n tests: _.get(json, 'request.tests', ''),\n settings: _.get(json, 'settings', {}),\n docs: _.get(json, 'request.docs', '')\n };\n\n const bru = jsonToBruV2(bruJson);\n return bru;\n } catch (error) {\n throw error;\n }\n};\n\nexport const bruCollectionToJson = (data: string | any, parsed: boolean = false): any => {\n try {\n const json = parsed ? data : _collectionBruToJson(data);\n\n const transformedJson: any = {\n request: {\n headers: _.get(json, 'headers', []),\n auth: _.get(json, 'auth', {}),\n script: _.get(json, 'script', {}),\n vars: _.get(json, 'vars', {}),\n tests: _.get(json, 'tests', '')\n },\n settings: _.get(json, 'settings', {}),\n docs: _.get(json, 'docs', '')\n };\n\n // add meta if it exists\n // this is only for folder bru file\n if (json.meta) {\n transformedJson.meta = {\n name: json.meta.name\n };\n \n // Include seq if it exists\n if (json.meta.seq !== undefined) {\n const sequence = json.meta.seq;\n transformedJson.meta.seq = !isNaN(sequence) ? Number(sequence) : 1;\n }\n }\n\n return transformedJson;\n } catch (error) {\n return Promise.reject(error);\n }\n};\n\nexport const jsonCollectionToBru = (json: any, isFolder?: boolean): string => {\n try {\n const collectionBruJson: any = {\n headers: _.get(json, 'request.headers', []),\n script: {\n req: _.get(json, 'request.script.req', ''),\n res: _.get(json, 'request.script.res', '')\n },\n vars: {\n req: _.get(json, 'request.vars.req', []),\n res: _.get(json, 'request.vars.res', [])\n },\n tests: _.get(json, 'request.tests', ''),\n auth: _.get(json, 'request.auth', {}),\n docs: _.get(json, 'docs', '')\n };\n\n // add meta if it exists\n // this is only for folder bru file\n if (json?.meta) {\n collectionBruJson.meta = {\n name: json.meta.name\n };\n \n // Include seq if it exists\n if (json.meta.seq !== undefined) {\n const sequence = json.meta.seq;\n collectionBruJson.meta.seq = !isNaN(sequence) ? Number(sequence) : 1;\n }\n }\n\n if (!isFolder) {\n collectionBruJson.auth = _.get(json, 'request.auth', {});\n }\n\n return _jsonToCollectionBru(collectionBruJson);\n } catch (error) {\n throw error;\n }\n};\n\nexport const bruEnvironmentToJson = (bru: string): any => {\n try {\n const json = bruToEnvJsonV2(bru);\n\n // the app env format requires each variable to have a type\n // this need to be evaluated and safely removed\n // i don't see it being used in schema validation\n if (json && json.variables && json.variables.length) {\n _.each(json.variables, (v: any) => (v.type = 'text'));\n }\n\n return json;\n } catch (error) {\n return Promise.reject(error);\n }\n};\n\nexport const jsonEnvironmentToBru = (json: any): string => {\n try {\n const bru = envJsonToBruV2(json);\n return bru;\n } catch (error) {\n throw error;\n }\n}; ","import { Worker } from 'node:worker_threads';\n\ninterface QueuedTask {\n priority: number;\n scriptPath: string;\n data: any;\n taskType: 'parse' | 'stringify';\n resolve?: (value: any) => void;\n reject?: (reason?: any) => void;\n}\n\nclass WorkerQueue {\n private queue: QueuedTask[];\n private isProcessing: boolean;\n private workers: Record<string, Worker>;\n\n constructor() {\n this.queue = [];\n this.isProcessing = false;\n this.workers = {};\n }\n\n async getWorkerForScriptPath(scriptPath: string) {\n if (!this.workers) this.workers = {}; \n let worker = this.workers[scriptPath];\n if (!worker || worker.threadId === -1) {\n this.workers[scriptPath] = worker = new Worker(scriptPath);\n }\n return worker;\n }\n \n async enqueue(task: QueuedTask) {\n const { priority, scriptPath, data, taskType } = task;\n\n return new Promise((resolve, reject) => {\n this.queue.push({ priority, scriptPath, data, taskType, resolve, reject });\n this.queue?.sort((taskX, taskY) => taskX?.priority - taskY?.priority);\n this.processQueue();\n });\n }\n\n async processQueue() {\n if (this.isProcessing || this.queue.length === 0){\n return;\n } \n\n this.isProcessing = true;\n const { scriptPath, data, taskType, resolve, reject } = this.queue.shift() as QueuedTask;\n\n try {\n const result = await this.runWorker({ scriptPath, data, taskType });\n resolve?.(result);\n } catch (error) {\n reject?.(error);\n } finally {\n this.isProcessing = false;\n this.processQueue();\n }\n }\n\n async runWorker({ scriptPath, data, taskType }: { scriptPath: string; data: any; taskType: 'parse' | 'stringify' }) {\n return new Promise(async (resolve, reject) => {\n let worker = await this.getWorkerForScriptPath(scriptPath);\n \n const messageHandler = (data: any) => {\n worker.off('message', messageHandler);\n worker.off('error', errorHandler);\n worker.off('exit', exitHandler);\n \n if (data?.error) {\n reject(new Error(data?.error));\n } else {\n resolve(data);\n }\n };\n\n const errorHandler = (error: Error) => {\n worker.off('message', messageHandler);\n worker.off('error', errorHandler);\n worker.off('exit', exitHandler);\n reject(error);\n };\n\n const exitHandler = (code: number) => {\n worker.off('message', messageHandler);\n worker.off('error', errorHandler);\n worker.off('exit', exitHandler);\n // Remove dead worker from cache\n delete this.workers[scriptPath];\n reject(new Error(`Worker stopped with exit code ${code}`));\n };\n \n worker.on('message', messageHandler);\n worker.on('error', errorHandler);\n worker.on('exit', exitHandler);\n\n worker.postMessage({ taskType, data });\n });\n }\n\n async cleanup() {\n const promises = Object.values(this.workers).map(worker => {\n if (worker.threadId !== -1) {\n return worker.terminate();\n }\n return Promise.resolve();\n });\n \n await Promise.allSettled(promises);\n this.workers = {};\n }\n}\n\nexport default WorkerQueue;","import WorkerQueue from './WorkerQueue';\nimport { Lane } from '../types';\nimport path from 'node:path';\n\nconst sizeInMB = (size: number): number => {\n return size / (1024 * 1024);\n}\n\nconst getSize = (data: any): number => {\n return sizeInMB(typeof data === 'string' ? Buffer.byteLength(data, 'utf8') : Buffer.byteLength(JSON.stringify(data), 'utf8'));\n}\n\n/**\n * Lanes are used to determine which worker queue to use based on the size of the data.\n * \n * The first lane is for smaller files (<0.1MB), the second lane is for larger files (>=0.1MB).\n * This helps with parsing performance.\n */\nconst LANES: Lane[] = [{\n maxSize: 0.005\n},{\n maxSize: 0.1\n},{\n maxSize: 1\n},{\n maxSize: 10\n},{\n maxSize: 100\n}];\n\ninterface WorkerQueueWithSize {\n maxSize: number;\n workerQueue: WorkerQueue;\n\n}\n\nclass BruParserWorker {\n private workerQueues: WorkerQueueWithSize[];\n\n constructor() {\n this.workerQueues = LANES?.map(lane => ({\n maxSize: lane?.maxSize,\n workerQueue: new WorkerQueue()\n }));\n }\n\n private getWorkerQueue(size: number): WorkerQueue {\n // Find the first queue that can handle the given size\n // or fallback to the last queue for largest files\n const queueForSize = this.workerQueues.find((queue) => \n queue.maxSize >= size\n );\n\n return queueForSize?.workerQueue ?? this.workerQueues[this.workerQueues.length - 1].workerQueue;\n }\n\n private async enqueueTask({ data, taskType }: { data: any; taskType: 'parse' | 'stringify' }): Promise<any> {\n const size = getSize(data);\n const workerQueue = this.getWorkerQueue(size);\n const workerScriptPath = path.join(__dirname, './workers/worker-script.js');\n \n return workerQueue.enqueue({\n data,\n priority: size,\n scriptPath: workerScriptPath,\n taskType,\n });\n }\n\n async parseRequest(data: any): Promise<any> {\n return this.enqueueTask({ data, taskType: 'parse' });\n }\n\n async stringifyRequest(data: any): Promise<any> {\n return this.enqueueTask({ data, taskType: 'stringify' });\n }\n\n async cleanup(): Promise<void> {\n const cleanupPromises = this.workerQueues.map(({ workerQueue }) => \n workerQueue.cleanup()\n );\n await Promise.allSettled(cleanupPromises);\n }\n}\n\nexport default BruParserWorker; ","import {\n bruRequestToJson,\n jsonRequestToBru,\n bruCollectionToJson,\n jsonCollectionToBru,\n bruEnvironmentToJson,\n jsonEnvironmentToBru\n} from './formats/bru';\nimport { dotenvToJson } from '@usebruno/lang';\nimport BruParserWorker from './workers';\nimport {\n ParseOptions,\n StringifyOptions,\n ParsedRequest,\n ParsedCollection,\n ParsedEnvironment\n} from './types';\n\nexport const parseRequest = (content: string, options: ParseOptions = { format: 'bru' }): any => {\n if (options.format === 'bru') {\n return bruRequestToJson(content);\n }\n throw new Error(`Unsupported format: ${options.format}`);\n};\n\nexport const stringifyRequest = (requestObj: ParsedRequest, options: StringifyOptions = { format: 'bru' }): string => {\n if (options.format === 'bru') {\n return jsonRequestToBru(requestObj);\n }\n throw new Error(`Unsupported format: ${options.format}`);\n};\n\nlet globalWorkerInstance: BruParserWorker | null = null;\n\nconst getWorkerInstance = (): BruParserWorker => {\n if (!globalWorkerInstance) {\n globalWorkerInstance = new BruParserWorker();\n }\n return globalWorkerInstance;\n};\n\nexport const parseRequestViaWorker = async (content: string): Promise<any> => {\n const fileParserWorker = getWorkerInstance();\n return await fileParserWorker.parseRequest(content);\n};\n\nexport const stringifyRequestViaWorker = async (requestObj: any): Promise<string> => {\n const fileParserWorker = getWorkerInstance();\n return await fileParserWorker.stringifyRequest(requestObj);\n};\n\nexport const parseCollection = (content: string, options: ParseOptions = { format: 'bru' }): any => {\n if (options.format === 'bru') {\n return bruCollectionToJson(content);\n }\n throw new Error(`Unsupported format: ${options.format}`);\n};\n\nexport const stringifyCollection = (collectionObj: ParsedCollection, options: StringifyOptions = { format: 'bru' }): string => {\n if (options.format === 'bru') {\n return jsonCollectionToBru(collectionObj, false);\n }\n throw new Error(`Unsupported format: ${options.format}`);\n};\n\nexport const parseFolder = (content: string, options: ParseOptions = { format: 'bru' }): any => {\n if (options.format === 'bru') {\n return bruCollectionToJson(content);\n }\n throw new Error(`Unsupported format: ${options.format}`);\n};\n\nexport const stringifyFolder = (folderObj: any, options: StringifyOptions = { format: 'bru' }): string => {\n if (options.format === 'bru') {\n return jsonCollectionToBru(folderObj, true);\n }\n throw new Error(`Unsupported format: ${options.format}`);\n};\n\nexport const parseEnvironment = (content: string, options: ParseOptions = { format: 'bru' }): any => {\n if (options.format === 'bru') {\n return bruEnvironmentToJson(content);\n }\n throw new Error(`Unsupported format: ${options.format}`);\n};\n\nexport const stringifyEnvironment = (envObj: ParsedEnvironment, options: StringifyOptions = { format: 'bru' }): string => {\n if (options.format === 'bru') {\n return jsonEnvironmentToBru(envObj);\n }\n throw new Error(`Unsupported format: ${options.format}`);\n};\n\n\nexport const parseDotEnv = (content: string): Record<string, string> => {\n return dotenvToJson(content);\n};\n\nexport { BruParserWorker };\nexport * from './types';"],"names":["bruCollectionToJson","data","parsed","json","_collectionBruToJson","collectionBruToJson","transformedJson","request","headers","_","get","auth","script","vars","tests","settings","docs","meta","name","undefined","seq","sequence","isNaN","Number","error","Promise","reject","jsonCollectionToBru","isFolder","collectionBruJson","req","res","_jsonToCollectionBru","WorkerQueue","constructor","this","queue","isProcessing","workers","getWorkerForScriptPath","scriptPath","worker","threadId","Worker","enqueue","task","priority","taskType","resolve","push","sort","taskX","taskY","processQueue","length","shift","result","runWorker","async","messageHandler","off","errorHandler","exitHandler","Error","code","on","postMessage","cleanup","promises","Object","values","map","terminate","allSettled","LANES","maxSize","BruParserWorker","workerQueues","lane","workerQueue","getWorkerQueue","size","queueForSize","find","enqueueTask","Buffer","byteLength","JSON","stringify","getSize","workerScriptPath","path","join","__dirname","parseRequest","stringifyRequest","cleanupPromises","globalWorkerInstance","getWorkerInstance","content","options","format","dotenvToJson","bru","bruToEnvJsonV2","variables","each","v","type","bruEnvironmentToJson","bruToJsonV2","requestType","tags","method","upperCase","url","params","body","assertions","mode","e","bruRequestToJson","fileParserWorker","collectionObj","envObj","envJsonToBruV2","jsonEnvironmentToBru","folderObj","requestObj","bruJson","http","lowerCase","jsonToBruV2","jsonRequestToBru"],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ export interface ParseOptions {
2
+ format?: 'bru' | 'yaml';
3
+ }
4
+ export interface StringifyOptions {
5
+ format?: 'bru' | 'yaml';
6
+ }
7
+ export interface RequestBody {
8
+ mode?: string;
9
+ raw?: string;
10
+ formUrlEncoded?: Array<{
11
+ name: string;
12
+ value: string;
13
+ enabled: boolean;
14
+ }>;
15
+ multipartForm?: Array<{
16
+ name: string;
17
+ value: string;
18
+ type: string;
19
+ enabled: boolean;
20
+ }>;
21
+ json?: string;
22
+ xml?: string;
23
+ sparql?: string;
24
+ graphql?: {
25
+ query?: string;
26
+ variables?: string;
27
+ };
28
+ }
29
+ export interface AuthConfig {
30
+ mode?: string;
31
+ basic?: {
32
+ username?: string;
33
+ password?: string;
34
+ };
35
+ bearer?: {
36
+ token?: string;
37
+ };
38
+ apikey?: {
39
+ key?: string;
40
+ value?: string;
41
+ placement?: string;
42
+ };
43
+ awsv4?: {
44
+ accessKeyId?: string;
45
+ secretAccessKey?: string;
46
+ sessionToken?: string;
47
+ service?: string;
48
+ region?: string;
49
+ profileName?: string;
50
+ };
51
+ oauth2?: {
52
+ grantType?: string;
53
+ callbackUrl?: string;
54
+ authorizationUrl?: string;
55
+ accessTokenUrl?: string;
56
+ clientId?: string;
57
+ clientSecret?: string;
58
+ scope?: string;
59
+ state?: string;
60
+ pkce?: boolean;
61
+ };
62
+ }
63
+ export interface RequestParam {
64
+ name: string;
65
+ value: string;
66
+ enabled: boolean;
67
+ }
68
+ export interface RequestHeader {
69
+ name: string;
70
+ value: string;
71
+ enabled: boolean;
72
+ }
73
+ export interface RequestAssertion {
74
+ name: string;
75
+ value: string;
76
+ enabled: boolean;
77
+ }
78
+ export interface RequestVars {
79
+ req?: Array<{
80
+ name: string;
81
+ value: string;
82
+ enabled: boolean;
83
+ }>;
84
+ res?: Array<{
85
+ name: string;
86
+ value: string;
87
+ enabled: boolean;
88
+ }>;
89
+ }
90
+ export interface RequestScript {
91
+ req?: string;
92
+ res?: string;
93
+ }
94
+ export interface RequestSettings {
95
+ [key: string]: any;
96
+ }
97
+ export interface RequestData {
98
+ method: string;
99
+ url: string;
100
+ params: RequestParam[];
101
+ headers: RequestHeader[];
102
+ auth: AuthConfig;
103
+ body: RequestBody;
104
+ script: RequestScript;
105
+ vars: RequestVars;
106
+ assertions: RequestAssertion[];
107
+ tests: string;
108
+ docs: string;
109
+ }
110
+ export interface ParsedRequest {
111
+ type: 'http-request' | 'graphql-request';
112
+ name: string;
113
+ seq: number;
114
+ settings: RequestSettings;
115
+ tags: string[];
116
+ request: RequestData;
117
+ }
118
+ export interface ParsedCollection {
119
+ name: string;
120
+ type?: string;
121
+ version?: string;
122
+ [key: string]: any;
123
+ }
124
+ export interface EnvironmentVariable {
125
+ name: string;
126
+ value: string;
127
+ enabled: boolean;
128
+ }
129
+ export interface ParsedEnvironment {
130
+ variables: EnvironmentVariable[];
131
+ }
132
+ export interface WorkerTask {
133
+ data: any;
134
+ priority: number;
135
+ scriptPath: string;
136
+ taskType?: 'parse' | 'stringify';
137
+ resolve?: (value: any) => void;
138
+ reject?: (reason?: any) => void;
139
+ }
140
+ export interface Lane {
141
+ maxSize: number;
142
+ }
@@ -0,0 +1,26 @@
1
+ /// <reference types="node" />
2
+ import { Worker } from 'node:worker_threads';
3
+ interface QueuedTask {
4
+ priority: number;
5
+ scriptPath: string;
6
+ data: any;
7
+ taskType: 'parse' | 'stringify';
8
+ resolve?: (value: any) => void;
9
+ reject?: (reason?: any) => void;
10
+ }
11
+ declare class WorkerQueue {
12
+ private queue;
13
+ private isProcessing;
14
+ private workers;
15
+ constructor();
16
+ getWorkerForScriptPath(scriptPath: string): Promise<Worker>;
17
+ enqueue(task: QueuedTask): Promise<unknown>;
18
+ processQueue(): Promise<void>;
19
+ runWorker({ scriptPath, data, taskType }: {
20
+ scriptPath: string;
21
+ data: any;
22
+ taskType: 'parse' | 'stringify';
23
+ }): Promise<unknown>;
24
+ cleanup(): Promise<void>;
25
+ }
26
+ export default WorkerQueue;
@@ -0,0 +1,6 @@
1
+ export declare const bruRequestToJson: (data: string | any, parsed?: boolean) => any;
2
+ export declare const jsonRequestToBru: (json: any) => string;
3
+ export declare const bruCollectionToJson: (data: string | any, parsed?: boolean) => any;
4
+ export declare const jsonCollectionToBru: (json: any, isFolder?: boolean) => string;
5
+ export declare const bruEnvironmentToJson: (bru: string) => any;
6
+ export declare const jsonEnvironmentToBru: (json: any) => string;
@@ -0,0 +1,15 @@
1
+ import BruParserWorker from './workers';
2
+ import { ParseOptions, StringifyOptions, ParsedRequest, ParsedCollection, ParsedEnvironment } from './types';
3
+ export declare const parseRequest: (content: string, options?: ParseOptions) => any;
4
+ export declare const stringifyRequest: (requestObj: ParsedRequest, options?: StringifyOptions) => string;
5
+ export declare const parseRequestViaWorker: (content: string) => Promise<any>;
6
+ export declare const stringifyRequestViaWorker: (requestObj: any) => Promise<string>;
7
+ export declare const parseCollection: (content: string, options?: ParseOptions) => any;
8
+ export declare const stringifyCollection: (collectionObj: ParsedCollection, options?: StringifyOptions) => string;
9
+ export declare const parseFolder: (content: string, options?: ParseOptions) => any;
10
+ export declare const stringifyFolder: (folderObj: any, options?: StringifyOptions) => string;
11
+ export declare const parseEnvironment: (content: string, options?: ParseOptions) => any;
12
+ export declare const stringifyEnvironment: (envObj: ParsedEnvironment, options?: StringifyOptions) => string;
13
+ export declare const parseDotEnv: (content: string) => Record<string, string>;
14
+ export { BruParserWorker };
15
+ export * from './types';
@@ -0,0 +1,142 @@
1
+ export interface ParseOptions {
2
+ format?: 'bru' | 'yaml';
3
+ }
4
+ export interface StringifyOptions {
5
+ format?: 'bru' | 'yaml';
6
+ }
7
+ export interface RequestBody {
8
+ mode?: string;
9
+ raw?: string;
10
+ formUrlEncoded?: Array<{
11
+ name: string;
12
+ value: string;
13
+ enabled: boolean;
14
+ }>;
15
+ multipartForm?: Array<{
16
+ name: string;
17
+ value: string;
18
+ type: string;
19
+ enabled: boolean;
20
+ }>;
21
+ json?: string;
22
+ xml?: string;
23
+ sparql?: string;
24
+ graphql?: {
25
+ query?: string;
26
+ variables?: string;
27
+ };
28
+ }
29
+ export interface AuthConfig {
30
+ mode?: string;
31
+ basic?: {
32
+ username?: string;
33
+ password?: string;
34
+ };
35
+ bearer?: {
36
+ token?: string;
37
+ };
38
+ apikey?: {
39
+ key?: string;
40
+ value?: string;
41
+ placement?: string;
42
+ };
43
+ awsv4?: {
44
+ accessKeyId?: string;
45
+ secretAccessKey?: string;
46
+ sessionToken?: string;
47
+ service?: string;
48
+ region?: string;
49
+ profileName?: string;
50
+ };
51
+ oauth2?: {
52
+ grantType?: string;
53
+ callbackUrl?: string;
54
+ authorizationUrl?: string;
55
+ accessTokenUrl?: string;
56
+ clientId?: string;
57
+ clientSecret?: string;
58
+ scope?: string;
59
+ state?: string;
60
+ pkce?: boolean;
61
+ };
62
+ }
63
+ export interface RequestParam {
64
+ name: string;
65
+ value: string;
66
+ enabled: boolean;
67
+ }
68
+ export interface RequestHeader {
69
+ name: string;
70
+ value: string;
71
+ enabled: boolean;
72
+ }
73
+ export interface RequestAssertion {
74
+ name: string;
75
+ value: string;
76
+ enabled: boolean;
77
+ }
78
+ export interface RequestVars {
79
+ req?: Array<{
80
+ name: string;
81
+ value: string;
82
+ enabled: boolean;
83
+ }>;
84
+ res?: Array<{
85
+ name: string;
86
+ value: string;
87
+ enabled: boolean;
88
+ }>;
89
+ }
90
+ export interface RequestScript {
91
+ req?: string;
92
+ res?: string;
93
+ }
94
+ export interface RequestSettings {
95
+ [key: string]: any;
96
+ }
97
+ export interface RequestData {
98
+ method: string;
99
+ url: string;
100
+ params: RequestParam[];
101
+ headers: RequestHeader[];
102
+ auth: AuthConfig;
103
+ body: RequestBody;
104
+ script: RequestScript;
105
+ vars: RequestVars;
106
+ assertions: RequestAssertion[];
107
+ tests: string;
108
+ docs: string;
109
+ }
110
+ export interface ParsedRequest {
111
+ type: 'http-request' | 'graphql-request';
112
+ name: string;
113
+ seq: number;
114
+ settings: RequestSettings;
115
+ tags: string[];
116
+ request: RequestData;
117
+ }
118
+ export interface ParsedCollection {
119
+ name: string;
120
+ type?: string;
121
+ version?: string;
122
+ [key: string]: any;
123
+ }
124
+ export interface EnvironmentVariable {
125
+ name: string;
126
+ value: string;
127
+ enabled: boolean;
128
+ }
129
+ export interface ParsedEnvironment {
130
+ variables: EnvironmentVariable[];
131
+ }
132
+ export interface WorkerTask {
133
+ data: any;
134
+ priority: number;
135
+ scriptPath: string;
136
+ taskType?: 'parse' | 'stringify';
137
+ resolve?: (value: any) => void;
138
+ reject?: (reason?: any) => void;
139
+ }
140
+ export interface Lane {
141
+ maxSize: number;
142
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";var e=require("node:worker_threads"),t=require("lodash"),r=require("@usebruno/lang");function s(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var s=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,s.get?s:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var a=s(t);e.parentPort?.on("message",(async t=>{try{const{taskType:s,data:o}=t;let g;if("parse"===s)g=((e,t=!1)=>{try{const s=t?e:r.bruToJsonV2(e);let o=a.get(s,"meta.type");o="http"===o?"http-request":"graphql"===o?"graphql-request":"http-request";const g=a.get(s,"meta.seq"),u={type:o,name:a.get(s,"meta.name"),seq:a.isNaN(g)?1:Number(g),settings:a.get(s,"settings",{}),tags:a.get(s,"meta.tags",[]),request:{method:a.upperCase(a.get(s,"http.method")),url:a.get(s,"http.url"),params:a.get(s,"params",[]),headers:a.get(s,"headers",[]),auth:a.get(s,"auth",{}),body:a.get(s,"body",{}),script:a.get(s,"script",{}),vars:a.get(s,"vars",{}),assertions:a.get(s,"assertions",[]),tests:a.get(s,"tests",""),docs:a.get(s,"docs","")}};return u.request.auth.mode=a.get(s,"http.auth","none"),u.request.body.mode=a.get(s,"http.body","none"),u}catch(e){return Promise.reject(e)}})(o);else{if("stringify"!==s)throw new Error(`Unknown task type: ${s}`);g=(e=>{try{let t=a.get(e,"type");t="http-request"===t?"http":"graphql-request"===t?"graphql":"http";const s=a.get(e,"seq"),o={meta:{name:a.get(e,"name"),type:t,seq:a.isNaN(s)?1:Number(s),tags:a.get(e,"tags",[])},http:{method:a.lowerCase(a.get(e,"request.method")),url:a.get(e,"request.url"),auth:a.get(e,"request.auth.mode","none"),body:a.get(e,"request.body.mode","none")},params:a.get(e,"request.params",[]),headers:a.get(e,"request.headers",[]),auth:a.get(e,"request.auth",{}),body:a.get(e,"request.body",{}),script:a.get(e,"request.script",{}),vars:{req:a.get(e,"request.vars.req",[]),res:a.get(e,"request.vars.res",[])},assertions:a.get(e,"request.assertions",[]),tests:a.get(e,"request.tests",""),settings:a.get(e,"settings",{}),docs:a.get(e,"request.docs","")};return r.jsonToBruV2(o)}catch(e){throw e}})(o)}e.parentPort?.postMessage(g)}catch(t){console.error("Worker error:",t),e.parentPort?.postMessage({error:t?.message})}}));
2
+ //# sourceMappingURL=worker-script.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-script.js","sources":["../../../src/workers/worker-script.ts","../../../src/formats/bru/index.ts"],"sourcesContent":["import { parentPort } from 'node:worker_threads';\nimport { bruRequestToJson, jsonRequestToBru } from '../formats/bru';\n\ninterface WorkerMessage {\n taskType: 'parse' | 'stringify';\n data: any;\n}\n\nparentPort?.on('message', async (message: WorkerMessage) => {\n try {\n const { taskType, data } = message;\n let result: any;\n\n if (taskType === 'parse') {\n result = bruRequestToJson(data);\n } else if (taskType === 'stringify') {\n result = jsonRequestToBru(data);\n } else {\n throw new Error(`Unknown task type: ${taskType}`);\n }\n\n parentPort?.postMessage(result);\n } catch (error: any) {\n console.error('Worker error:', error);\n parentPort?.postMessage({ error: error?.message });\n }\n});","import * as _ from 'lodash';\nimport {\n bruToJsonV2,\n jsonToBruV2,\n bruToEnvJsonV2,\n envJsonToBruV2,\n collectionBruToJson as _collectionBruToJson,\n jsonToCollectionBru as _jsonToCollectionBru\n} from '@usebruno/lang';\n\nexport const bruRequestToJson = (data: string | any, parsed: boolean = false): any => {\n try {\n const json = parsed ? data : bruToJsonV2(data);\n\n let requestType = _.get(json, 'meta.type');\n if (requestType === 'http') {\n requestType = 'http-request';\n } else if (requestType === 'graphql') {\n requestType = 'graphql-request';\n } else {\n requestType = 'http-request';\n }\n\n const sequence = _.get(json, 'meta.seq');\n const transformedJson = {\n type: requestType,\n name: _.get(json, 'meta.name'),\n seq: !_.isNaN(sequence) ? Number(sequence) : 1,\n settings: _.get(json, 'settings', {}),\n tags: _.get(json, 'meta.tags', []),\n request: {\n method: _.upperCase(_.get(json, 'http.method')),\n url: _.get(json, 'http.url'),\n params: _.get(json, 'params', []),\n headers: _.get(json, 'headers', []),\n auth: _.get(json, 'auth', {}),\n body: _.get(json, 'body', {}),\n script: _.get(json, 'script', {}),\n vars: _.get(json, 'vars', {}),\n assertions: _.get(json, 'assertions', []),\n tests: _.get(json, 'tests', ''),\n docs: _.get(json, 'docs', '')\n }\n };\n\n transformedJson.request.auth.mode = _.get(json, 'http.auth', 'none');\n transformedJson.request.body.mode = _.get(json, 'http.body', 'none');\n\n return transformedJson;\n } catch (e) {\n return Promise.reject(e);\n }\n};\n\nexport const jsonRequestToBru = (json: any): string => {\n try {\n let type = _.get(json, 'type');\n if (type === 'http-request') {\n type = 'http';\n } else if (type === 'graphql-request') {\n type = 'graphql';\n } else {\n type = 'http';\n }\n\n const sequence = _.get(json, 'seq');\n const bruJson = {\n meta: {\n name: _.get(json, 'name'),\n type: type,\n seq: !_.isNaN(sequence) ? Number(sequence) : 1,\n tags: _.get(json, 'tags', []),\n },\n http: {\n method: _.lowerCase(_.get(json, 'request.method')),\n url: _.get(json, 'request.url'),\n auth: _.get(json, 'request.auth.mode', 'none'),\n body: _.get(json, 'request.body.mode', 'none')\n },\n params: _.get(json, 'request.params', []),\n headers: _.get(json, 'request.headers', []),\n auth: _.get(json, 'request.auth', {}),\n body: _.get(json, 'request.body', {}),\n script: _.get(json, 'request.script', {}),\n vars: {\n req: _.get(json, 'request.vars.req', []),\n res: _.get(json, 'request.vars.res', [])\n },\n assertions: _.get(json, 'request.assertions', []),\n tests: _.get(json, 'request.tests', ''),\n settings: _.get(json, 'settings', {}),\n docs: _.get(json, 'request.docs', '')\n };\n\n const bru = jsonToBruV2(bruJson);\n return bru;\n } catch (error) {\n throw error;\n }\n};\n\nexport const bruCollectionToJson = (data: string | any, parsed: boolean = false): any => {\n try {\n const json = parsed ? data : _collectionBruToJson(data);\n\n const transformedJson: any = {\n request: {\n headers: _.get(json, 'headers', []),\n auth: _.get(json, 'auth', {}),\n script: _.get(json, 'script', {}),\n vars: _.get(json, 'vars', {}),\n tests: _.get(json, 'tests', '')\n },\n settings: _.get(json, 'settings', {}),\n docs: _.get(json, 'docs', '')\n };\n\n // add meta if it exists\n // this is only for folder bru file\n if (json.meta) {\n transformedJson.meta = {\n name: json.meta.name\n };\n \n // Include seq if it exists\n if (json.meta.seq !== undefined) {\n const sequence = json.meta.seq;\n transformedJson.meta.seq = !isNaN(sequence) ? Number(sequence) : 1;\n }\n }\n\n return transformedJson;\n } catch (error) {\n return Promise.reject(error);\n }\n};\n\nexport const jsonCollectionToBru = (json: any, isFolder?: boolean): string => {\n try {\n const collectionBruJson: any = {\n headers: _.get(json, 'request.headers', []),\n script: {\n req: _.get(json, 'request.script.req', ''),\n res: _.get(json, 'request.script.res', '')\n },\n vars: {\n req: _.get(json, 'request.vars.req', []),\n res: _.get(json, 'request.vars.res', [])\n },\n tests: _.get(json, 'request.tests', ''),\n auth: _.get(json, 'request.auth', {}),\n docs: _.get(json, 'docs', '')\n };\n\n // add meta if it exists\n // this is only for folder bru file\n if (json?.meta) {\n collectionBruJson.meta = {\n name: json.meta.name\n };\n \n // Include seq if it exists\n if (json.meta.seq !== undefined) {\n const sequence = json.meta.seq;\n collectionBruJson.meta.seq = !isNaN(sequence) ? Number(sequence) : 1;\n }\n }\n\n if (!isFolder) {\n collectionBruJson.auth = _.get(json, 'request.auth', {});\n }\n\n return _jsonToCollectionBru(collectionBruJson);\n } catch (error) {\n throw error;\n }\n};\n\nexport const bruEnvironmentToJson = (bru: string): any => {\n try {\n const json = bruToEnvJsonV2(bru);\n\n // the app env format requires each variable to have a type\n // this need to be evaluated and safely removed\n // i don't see it being used in schema validation\n if (json && json.variables && json.variables.length) {\n _.each(json.variables, (v: any) => (v.type = 'text'));\n }\n\n return json;\n } catch (error) {\n return Promise.reject(error);\n }\n};\n\nexport const jsonEnvironmentToBru = (json: any): string => {\n try {\n const bru = envJsonToBruV2(json);\n return bru;\n } catch (error) {\n throw error;\n }\n}; "],"names":["parentPort","on","async","message","taskType","data","result","parsed","json","bruToJsonV2","requestType","_","get","sequence","transformedJson","type","name","seq","isNaN","Number","settings","tags","request","method","upperCase","url","params","headers","auth","body","script","vars","assertions","tests","docs","mode","e","Promise","reject","bruRequestToJson","Error","bruJson","meta","http","lowerCase","req","res","jsonToBruV2","error","jsonRequestToBru","postMessage","console"],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /// <reference types="node" />
2
+ import { Worker } from 'node:worker_threads';
3
+ interface QueuedTask {
4
+ priority: number;
5
+ scriptPath: string;
6
+ data: any;
7
+ taskType: 'parse' | 'stringify';
8
+ resolve?: (value: any) => void;
9
+ reject?: (reason?: any) => void;
10
+ }
11
+ declare class WorkerQueue {
12
+ private queue;
13
+ private isProcessing;
14
+ private workers;
15
+ constructor();
16
+ getWorkerForScriptPath(scriptPath: string): Promise<Worker>;
17
+ enqueue(task: QueuedTask): Promise<unknown>;
18
+ processQueue(): Promise<void>;
19
+ runWorker({ scriptPath, data, taskType }: {
20
+ scriptPath: string;
21
+ data: any;
22
+ taskType: 'parse' | 'stringify';
23
+ }): Promise<unknown>;
24
+ cleanup(): Promise<void>;
25
+ }
26
+ export default WorkerQueue;
@@ -0,0 +1,10 @@
1
+ declare class BruParserWorker {
2
+ private workerQueues;
3
+ constructor();
4
+ private getWorkerQueue;
5
+ private enqueueTask;
6
+ parseRequest(data: any): Promise<any>;
7
+ stringifyRequest(data: any): Promise<any>;
8
+ cleanup(): Promise<void>;
9
+ }
10
+ export default BruParserWorker;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ export declare const bruRequestToJson: (data: string | any, parsed?: boolean) => any;
2
+ export declare const jsonRequestToBru: (json: any) => string;
3
+ export declare const bruCollectionToJson: (data: string | any, parsed?: boolean) => any;
4
+ export declare const jsonCollectionToBru: (json: any, isFolder?: boolean) => string;
5
+ export declare const bruEnvironmentToJson: (bru: string) => any;
6
+ export declare const jsonEnvironmentToBru: (json: any) => string;
@@ -0,0 +1,15 @@
1
+ import BruParserWorker from './workers';
2
+ import { ParseOptions, StringifyOptions, ParsedRequest, ParsedCollection, ParsedEnvironment } from './types';
3
+ export declare const parseRequest: (content: string, options?: ParseOptions) => any;
4
+ export declare const stringifyRequest: (requestObj: ParsedRequest, options?: StringifyOptions) => string;
5
+ export declare const parseRequestViaWorker: (content: string) => Promise<any>;
6
+ export declare const stringifyRequestViaWorker: (requestObj: any) => Promise<string>;
7
+ export declare const parseCollection: (content: string, options?: ParseOptions) => any;
8
+ export declare const stringifyCollection: (collectionObj: ParsedCollection, options?: StringifyOptions) => string;
9
+ export declare const parseFolder: (content: string, options?: ParseOptions) => any;
10
+ export declare const stringifyFolder: (folderObj: any, options?: StringifyOptions) => string;
11
+ export declare const parseEnvironment: (content: string, options?: ParseOptions) => any;
12
+ export declare const stringifyEnvironment: (envObj: ParsedEnvironment, options?: StringifyOptions) => string;
13
+ export declare const parseDotEnv: (content: string) => Record<string, string>;
14
+ export { BruParserWorker };
15
+ export * from './types';
@@ -0,0 +1,2 @@
1
+ import*as e from"lodash";import{bruToJsonV2 as t,jsonToBruV2 as r,collectionBruToJson as s,jsonToCollectionBru as a,bruToEnvJsonV2 as o,envJsonToBruV2 as u,dotenvToJson as n}from"@usebruno/lang";import{Worker as i}from"node:worker_threads";import h from"node:path";const m=(t,r=!1)=>{try{const a=r?t:s(t),o={request:{headers:e.get(a,"headers",[]),auth:e.get(a,"auth",{}),script:e.get(a,"script",{}),vars:e.get(a,"vars",{}),tests:e.get(a,"tests","")},settings:e.get(a,"settings",{}),docs:e.get(a,"docs","")};if(a.meta&&(o.meta={name:a.meta.name},void 0!==a.meta.seq)){const e=a.meta.seq;o.meta.seq=isNaN(e)?1:Number(e)}return o}catch(e){return Promise.reject(e)}},c=(t,r)=>{try{const s={headers:e.get(t,"request.headers",[]),script:{req:e.get(t,"request.script.req",""),res:e.get(t,"request.script.res","")},vars:{req:e.get(t,"request.vars.req",[]),res:e.get(t,"request.vars.res",[])},tests:e.get(t,"request.tests",""),auth:e.get(t,"request.auth",{}),docs:e.get(t,"docs","")};if(t?.meta&&(s.meta={name:t.meta.name},void 0!==t.meta.seq)){const e=t.meta.seq;s.meta.seq=isNaN(e)?1:Number(e)}return r||(s.auth=e.get(t,"request.auth",{})),a(s)}catch(e){throw e}};class p{constructor(){this.queue=[],this.isProcessing=!1,this.workers={}}async getWorkerForScriptPath(e){this.workers||(this.workers={});let t=this.workers[e];return t&&-1!==t.threadId||(this.workers[e]=t=new i(e)),t}async enqueue(e){const{priority:t,scriptPath:r,data:s,taskType:a}=e;return new Promise(((e,o)=>{this.queue.push({priority:t,scriptPath:r,data:s,taskType:a,resolve:e,reject:o}),this.queue?.sort(((e,t)=>e?.priority-t?.priority)),this.processQueue()}))}async processQueue(){if(this.isProcessing||0===this.queue.length)return;this.isProcessing=!0;const{scriptPath:e,data:t,taskType:r,resolve:s,reject:a}=this.queue.shift();try{const a=await this.runWorker({scriptPath:e,data:t,taskType:r});s?.(a)}catch(e){a?.(e)}finally{this.isProcessing=!1,this.processQueue()}}async runWorker({scriptPath:e,data:t,taskType:r}){return new Promise((async(s,a)=>{let o=await this.getWorkerForScriptPath(e);const u=e=>{o.off("message",u),o.off("error",n),o.off("exit",i),e?.error?a(new Error(e?.error)):s(e)},n=e=>{o.off("message",u),o.off("error",n),o.off("exit",i),a(e)},i=t=>{o.off("message",u),o.off("error",n),o.off("exit",i),delete this.workers[e],a(new Error(`Worker stopped with exit code ${t}`))};o.on("message",u),o.on("error",n),o.on("exit",i),o.postMessage({taskType:r,data:t})}))}async cleanup(){const e=Object.values(this.workers).map((e=>-1!==e.threadId?e.terminate():Promise.resolve()));await Promise.allSettled(e),this.workers={}}}const g=[{maxSize:.005},{maxSize:.1},{maxSize:1},{maxSize:10},{maxSize:100}];class f{constructor(){this.workerQueues=g?.map((e=>({maxSize:e?.maxSize,workerQueue:new p})))}getWorkerQueue(e){const t=this.workerQueues.find((t=>t.maxSize>=e));return t?.workerQueue??this.workerQueues[this.workerQueues.length-1].workerQueue}async enqueueTask({data:e,taskType:t}){const r=(e=>("string"==typeof e?Buffer.byteLength(e,"utf8"):Buffer.byteLength(JSON.stringify(e),"utf8"))/1048576)(e),s=this.getWorkerQueue(r),a=h.join(__dirname,"./workers/worker-script.js");return s.enqueue({data:e,priority:r,scriptPath:a,taskType:t})}async parseRequest(e){return this.enqueueTask({data:e,taskType:"parse"})}async stringifyRequest(e){return this.enqueueTask({data:e,taskType:"stringify"})}async cleanup(){const e=this.workerQueues.map((({workerQueue:e})=>e.cleanup()));await Promise.allSettled(e)}}const d=(r,s={format:"bru"})=>{if("bru"===s.format)return((r,s=!1)=>{try{const a=s?r:t(r);let o=e.get(a,"meta.type");o="http"===o?"http-request":"graphql"===o?"graphql-request":"http-request";const u=e.get(a,"meta.seq"),n={type:o,name:e.get(a,"meta.name"),seq:e.isNaN(u)?1:Number(u),settings:e.get(a,"settings",{}),tags:e.get(a,"meta.tags",[]),request:{method:e.upperCase(e.get(a,"http.method")),url:e.get(a,"http.url"),params:e.get(a,"params",[]),headers:e.get(a,"headers",[]),auth:e.get(a,"auth",{}),body:e.get(a,"body",{}),script:e.get(a,"script",{}),vars:e.get(a,"vars",{}),assertions:e.get(a,"assertions",[]),tests:e.get(a,"tests",""),docs:e.get(a,"docs","")}};return n.request.auth.mode=e.get(a,"http.auth","none"),n.request.body.mode=e.get(a,"http.body","none"),n}catch(e){return Promise.reject(e)}})(r);throw new Error(`Unsupported format: ${s.format}`)},q=(t,s={format:"bru"})=>{if("bru"===s.format)return(t=>{try{let s=e.get(t,"type");s="http-request"===s?"http":"graphql-request"===s?"graphql":"http";const a=e.get(t,"seq"),o={meta:{name:e.get(t,"name"),type:s,seq:e.isNaN(a)?1:Number(a),tags:e.get(t,"tags",[])},http:{method:e.lowerCase(e.get(t,"request.method")),url:e.get(t,"request.url"),auth:e.get(t,"request.auth.mode","none"),body:e.get(t,"request.body.mode","none")},params:e.get(t,"request.params",[]),headers:e.get(t,"request.headers",[]),auth:e.get(t,"request.auth",{}),body:e.get(t,"request.body",{}),script:e.get(t,"request.script",{}),vars:{req:e.get(t,"request.vars.req",[]),res:e.get(t,"request.vars.res",[])},assertions:e.get(t,"request.assertions",[]),tests:e.get(t,"request.tests",""),settings:e.get(t,"settings",{}),docs:e.get(t,"request.docs","")};return r(o)}catch(e){throw e}})(t);throw new Error(`Unsupported format: ${s.format}`)};let y=null;const w=()=>(y||(y=new f),y),l=async e=>{const t=w();return await t.parseRequest(e)},k=async e=>{const t=w();return await t.stringifyRequest(e)},b=(e,t={format:"bru"})=>{if("bru"===t.format)return m(e);throw new Error(`Unsupported format: ${t.format}`)},P=(e,t={format:"bru"})=>{if("bru"===t.format)return c(e,!1);throw new Error(`Unsupported format: ${t.format}`)},v=(e,t={format:"bru"})=>{if("bru"===t.format)return m(e);throw new Error(`Unsupported format: ${t.format}`)},x=(e,t={format:"bru"})=>{if("bru"===t.format)return c(e,!0);throw new Error(`Unsupported format: ${t.format}`)},Q=(t,r={format:"bru"})=>{if("bru"===r.format)return(t=>{try{const r=o(t);return r&&r.variables&&r.variables.length&&e.each(r.variables,(e=>e.type="text")),r}catch(e){return Promise.reject(e)}})(t);throw new Error(`Unsupported format: ${r.format}`)},N=(e,t={format:"bru"})=>{if("bru"===t.format)return(e=>{try{return u(e)}catch(e){throw e}})(e);throw new Error(`Unsupported format: ${t.format}`)},S=e=>n(e);export{f as BruParserWorker,b as parseCollection,S as parseDotEnv,Q as parseEnvironment,v as parseFolder,d as parseRequest,l as parseRequestViaWorker,P as stringifyCollection,N as stringifyEnvironment,x as stringifyFolder,q as stringifyRequest,k as stringifyRequestViaWorker};
2
+ //# sourceMappingURL=index.js.map