@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
@@ -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","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","content","options","format","bruToJsonV2","requestType","type","tags","method","upperCase","url","params","body","assertions","mode","e","bruRequestToJson","requestObj","bruJson","http","lowerCase","jsonToBruV2","jsonRequestToBru","globalWorkerInstance","getWorkerInstance","parseRequestViaWorker","fileParserWorker","stringifyRequestViaWorker","parseCollection","stringifyCollection","collectionObj","parseFolder","stringifyFolder","folderObj","parseEnvironment","bru","bruToEnvJsonV2","variables","each","v","bruEnvironmentToJson","stringifyEnvironment","envObj","envJsonToBruV2","jsonEnvironmentToBru","parseDotEnv","dotenvToJson"],"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 {};
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@usebruno/filestore",
3
+ "version": "0.1.0",
4
+ "license": "MIT",
5
+ "main": "dist/cjs/index.js",
6
+ "module": "dist/esm/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "src",
11
+ "package.json"
12
+ ],
13
+ "scripts": {
14
+ "clean": "rimraf dist",
15
+ "prebuild": "npm run clean",
16
+ "build": "rollup -c",
17
+ "watch": "rollup -c -w",
18
+ "test": "jest",
19
+ "test:watch": "jest --watch",
20
+ "prepack": "npm run build"
21
+ },
22
+ "devDependencies": {
23
+ "@babel/preset-env": "^7.22.0",
24
+ "@babel/preset-typescript": "^7.22.0",
25
+ "@rollup/plugin-commonjs": "^23.0.2",
26
+ "@rollup/plugin-node-resolve": "^15.0.1",
27
+ "@rollup/plugin-typescript": "^9.0.2",
28
+ "@types/jest": "^29.5.11",
29
+ "@types/lodash": "^4.14.191",
30
+ "@types/node": "^24.1.0",
31
+ "babel-jest": "^29.7.0",
32
+ "jest": "^29.2.0",
33
+ "rimraf": "^3.0.2",
34
+ "rollup": "3.29.5",
35
+ "rollup-plugin-dts": "^5.0.0",
36
+ "rollup-plugin-peer-deps-external": "^2.2.4",
37
+ "rollup-plugin-terser": "^7.0.2",
38
+ "typescript": "^4.8.4"
39
+ },
40
+ "overrides": {
41
+ "rollup": "3.29.5"
42
+ },
43
+ "dependencies": {
44
+ "@usebruno/lang": "0.26.1",
45
+ "lodash": "^4.17.21"
46
+ }
47
+ }