@usebruno/filestore 0.5.0 → 0.6.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 (157) hide show
  1. package/dist/cjs/index.js +1 -1
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/workers/worker-script.js +1 -1
  4. package/dist/cjs/workers/worker-script.js.map +1 -1
  5. package/dist/esm/index.js +1 -1
  6. package/dist/esm/index.js.map +1 -1
  7. package/dist/esm/workers/worker-script.js +1 -1
  8. package/dist/esm/workers/worker-script.js.map +1 -1
  9. package/dist/formats/bru/index.d.ts +20 -0
  10. package/dist/formats/bru/index.d.ts.map +1 -0
  11. package/dist/formats/bru/tests/fixtures/oauth2-additional-params.d.ts +57 -0
  12. package/dist/formats/bru/tests/fixtures/oauth2-additional-params.d.ts.map +1 -0
  13. package/dist/formats/bru/tests/oauth2-additional-params.spec.d.ts +2 -0
  14. package/dist/formats/bru/tests/oauth2-additional-params.spec.d.ts.map +1 -0
  15. package/dist/formats/bru/tests/request-parse-and-redact-body-data.spec.d.ts +2 -0
  16. package/dist/formats/bru/tests/request-parse-and-redact-body-data.spec.d.ts.map +1 -0
  17. package/dist/{cjs/workers/formats → formats}/bru/utils/oauth2-additional-params.d.ts +1 -0
  18. package/dist/formats/bru/utils/oauth2-additional-params.d.ts.map +1 -0
  19. package/dist/{esm/formats → formats}/bru/utils/request-parse-and-redact-body-data.d.ts +1 -0
  20. package/dist/formats/bru/utils/request-parse-and-redact-body-data.d.ts.map +1 -0
  21. package/dist/formats/yml/common/actions.d.ts +14 -0
  22. package/dist/formats/yml/common/actions.d.ts.map +1 -0
  23. package/dist/formats/yml/common/assertions.d.ts +5 -0
  24. package/dist/formats/yml/common/assertions.d.ts.map +1 -0
  25. package/dist/formats/yml/common/auth-oauth2.d.ts +5 -0
  26. package/dist/formats/yml/common/auth-oauth2.d.ts.map +1 -0
  27. package/dist/formats/yml/common/auth.d.ts +5 -0
  28. package/dist/formats/yml/common/auth.d.ts.map +1 -0
  29. package/dist/formats/yml/common/body.d.ts +5 -0
  30. package/dist/formats/yml/common/body.d.ts.map +1 -0
  31. package/dist/formats/yml/common/headers.d.ts +7 -0
  32. package/dist/formats/yml/common/headers.d.ts.map +1 -0
  33. package/dist/formats/yml/common/params.d.ts +5 -0
  34. package/dist/formats/yml/common/params.d.ts.map +1 -0
  35. package/dist/formats/yml/common/scripts.d.ts +14 -0
  36. package/dist/formats/yml/common/scripts.d.ts.map +1 -0
  37. package/dist/formats/yml/common/variables.d.ts +17 -0
  38. package/dist/formats/yml/common/variables.d.ts.map +1 -0
  39. package/dist/formats/yml/index.d.ts +10 -0
  40. package/dist/formats/yml/index.d.ts.map +1 -0
  41. package/dist/formats/yml/items/parseGraphQLRequest.d.ts +5 -0
  42. package/dist/formats/yml/items/parseGraphQLRequest.d.ts.map +1 -0
  43. package/dist/formats/yml/items/parseGrpcRequest.d.ts +5 -0
  44. package/dist/formats/yml/items/parseGrpcRequest.d.ts.map +1 -0
  45. package/dist/formats/yml/items/parseHttpRequest.d.ts +5 -0
  46. package/dist/formats/yml/items/parseHttpRequest.d.ts.map +1 -0
  47. package/dist/formats/yml/items/parseScript.d.ts +5 -0
  48. package/dist/formats/yml/items/parseScript.d.ts.map +1 -0
  49. package/dist/formats/yml/items/parseWebsocketRequest.d.ts +5 -0
  50. package/dist/formats/yml/items/parseWebsocketRequest.d.ts.map +1 -0
  51. package/dist/formats/yml/items/stringifyGraphQLRequest.d.ts +4 -0
  52. package/dist/formats/yml/items/stringifyGraphQLRequest.d.ts.map +1 -0
  53. package/dist/formats/yml/items/stringifyGrpcRequest.d.ts +4 -0
  54. package/dist/formats/yml/items/stringifyGrpcRequest.d.ts.map +1 -0
  55. package/dist/formats/yml/items/stringifyHttpRequest.d.ts +4 -0
  56. package/dist/formats/yml/items/stringifyHttpRequest.d.ts.map +1 -0
  57. package/dist/formats/yml/items/stringifyScript.d.ts +4 -0
  58. package/dist/formats/yml/items/stringifyScript.d.ts.map +1 -0
  59. package/dist/formats/yml/items/stringifyWebsocketRequest.d.ts +4 -0
  60. package/dist/formats/yml/items/stringifyWebsocketRequest.d.ts.map +1 -0
  61. package/dist/formats/yml/parseCollection.d.ts +8 -0
  62. package/dist/formats/yml/parseCollection.d.ts.map +1 -0
  63. package/dist/formats/yml/parseEnvironment.d.ts +4 -0
  64. package/dist/formats/yml/parseEnvironment.d.ts.map +1 -0
  65. package/dist/formats/yml/parseFolder.d.ts +4 -0
  66. package/dist/formats/yml/parseFolder.d.ts.map +1 -0
  67. package/dist/formats/yml/parseItem.d.ts +4 -0
  68. package/dist/formats/yml/parseItem.d.ts.map +1 -0
  69. package/dist/formats/yml/stringifyCollection.d.ts +3 -0
  70. package/dist/formats/yml/stringifyCollection.d.ts.map +1 -0
  71. package/dist/formats/yml/stringifyEnvironment.d.ts +4 -0
  72. package/dist/formats/yml/stringifyEnvironment.d.ts.map +1 -0
  73. package/dist/formats/yml/stringifyFolder.d.ts +4 -0
  74. package/dist/formats/yml/stringifyFolder.d.ts.map +1 -0
  75. package/dist/formats/yml/stringifyItem.d.ts +4 -0
  76. package/dist/formats/yml/stringifyItem.d.ts.map +1 -0
  77. package/dist/formats/yml/utils.d.ts +3 -0
  78. package/dist/formats/yml/utils.d.ts.map +1 -0
  79. package/dist/{cjs/workers/index.d.ts → index.d.ts} +13 -6
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/types.d.ts +19 -0
  82. package/dist/types.d.ts.map +1 -0
  83. package/dist/utils/index.d.ts +5 -0
  84. package/dist/utils/index.d.ts.map +1 -0
  85. package/dist/{esm/workers → workers}/WorkerQueue/index.d.ts +1 -0
  86. package/dist/workers/WorkerQueue/index.d.ts.map +1 -0
  87. package/dist/workers/index.d.ts +12 -0
  88. package/dist/workers/index.d.ts.map +1 -0
  89. package/dist/workers/worker-script.d.ts +2 -0
  90. package/dist/workers/worker-script.d.ts.map +1 -0
  91. package/package.json +12 -6
  92. package/src/formats/bru/index.ts +9 -9
  93. package/src/formats/bru/tests/oauth2-additional-params.spec.js +1 -1
  94. package/src/formats/bru/utils/oauth2-additional-params.ts +17 -18
  95. package/src/formats/bru/utils/request-parse-and-redact-body-data.ts +13 -13
  96. package/src/formats/yml/common/actions.ts +78 -0
  97. package/src/formats/yml/common/assertions.ts +146 -0
  98. package/src/formats/yml/common/auth-oauth2.ts +555 -0
  99. package/src/formats/yml/common/auth.ts +245 -0
  100. package/src/formats/yml/common/body.ts +238 -0
  101. package/src/formats/yml/common/headers.ts +58 -0
  102. package/src/formats/yml/common/params.ts +57 -0
  103. package/src/formats/yml/common/scripts.ts +64 -0
  104. package/src/formats/yml/common/variables.ts +68 -0
  105. package/src/formats/yml/index.ts +20 -0
  106. package/src/formats/yml/items/parseGraphQLRequest.ts +137 -0
  107. package/src/formats/yml/items/parseGrpcRequest.ts +116 -0
  108. package/src/formats/yml/items/parseHttpRequest.ts +195 -0
  109. package/src/formats/yml/items/parseScript.ts +25 -0
  110. package/src/formats/yml/items/parseWebsocketRequest.ts +106 -0
  111. package/src/formats/yml/items/stringifyGraphQLRequest.ts +168 -0
  112. package/src/formats/yml/items/stringifyGrpcRequest.ts +137 -0
  113. package/src/formats/yml/items/stringifyHttpRequest.ts +221 -0
  114. package/src/formats/yml/items/stringifyScript.ts +22 -0
  115. package/src/formats/yml/items/stringifyWebsocketRequest.ts +114 -0
  116. package/src/formats/yml/parseCollection.ts +198 -0
  117. package/src/formats/yml/parseEnvironment.ts +56 -0
  118. package/src/formats/yml/parseFolder.ts +88 -0
  119. package/src/formats/yml/parseItem.ts +102 -0
  120. package/src/formats/yml/stringifyCollection.ts +230 -0
  121. package/src/formats/yml/stringifyEnvironment.ts +64 -0
  122. package/src/formats/yml/stringifyFolder.ts +96 -0
  123. package/src/formats/yml/stringifyItem.ts +37 -0
  124. package/src/formats/yml/utils.ts +38 -0
  125. package/src/index.ts +57 -27
  126. package/src/types/bruno-lang.d.ts +1 -1
  127. package/src/types.ts +5 -124
  128. package/src/utils/index.ts +15 -0
  129. package/src/workers/WorkerQueue/index.ts +10 -10
  130. package/src/workers/index.ts +20 -20
  131. package/src/workers/worker-script.ts +20 -6
  132. package/dist/cjs/formats/bru/index.d.ts +0 -19
  133. package/dist/cjs/formats/bru/utils/oauth2-additional-params.d.ts +0 -38
  134. package/dist/cjs/formats/bru/utils/request-parse-and-redact-body-data.d.ts +0 -9
  135. package/dist/cjs/index.d.ts +0 -16
  136. package/dist/cjs/types.d.ts +0 -142
  137. package/dist/cjs/workers/WorkerQueue/index.d.ts +0 -26
  138. package/dist/cjs/workers/formats/bru/index.d.ts +0 -19
  139. package/dist/cjs/workers/formats/bru/utils/request-parse-and-redact-body-data.d.ts +0 -9
  140. package/dist/cjs/workers/types.d.ts +0 -142
  141. package/dist/cjs/workers/worker-script.d.ts +0 -1
  142. package/dist/cjs/workers/workers/WorkerQueue/index.d.ts +0 -26
  143. package/dist/cjs/workers/workers/index.d.ts +0 -10
  144. package/dist/cjs/workers/workers/worker-script.d.ts +0 -1
  145. package/dist/esm/formats/bru/index.d.ts +0 -19
  146. package/dist/esm/formats/bru/utils/oauth2-additional-params.d.ts +0 -38
  147. package/dist/esm/index.d.ts +0 -16
  148. package/dist/esm/types.d.ts +0 -142
  149. package/dist/esm/workers/formats/bru/index.d.ts +0 -19
  150. package/dist/esm/workers/formats/bru/utils/oauth2-additional-params.d.ts +0 -38
  151. package/dist/esm/workers/formats/bru/utils/request-parse-and-redact-body-data.d.ts +0 -9
  152. package/dist/esm/workers/index.d.ts +0 -16
  153. package/dist/esm/workers/types.d.ts +0 -142
  154. package/dist/esm/workers/worker-script.d.ts +0 -1
  155. package/dist/esm/workers/workers/WorkerQueue/index.d.ts +0 -26
  156. package/dist/esm/workers/workers/index.d.ts +0 -10
  157. package/dist/esm/workers/workers/worker-script.d.ts +0 -1
@@ -0,0 +1,198 @@
1
+ import type { OpenCollection } from '@opencollection/types';
2
+ import type { FolderRoot } from '@usebruno/schema-types/collection/folder';
3
+ import { parseYml } from './utils';
4
+ import { toBrunoAuth } from './common/auth';
5
+ import { toBrunoHttpHeaders } from './common/headers';
6
+ import { toBrunoVariables } from './common/variables';
7
+ import { toBrunoScripts } from './common/scripts';
8
+
9
+ interface ParsedCollection {
10
+ collectionRoot: FolderRoot;
11
+ brunoConfig: Record<string, any>;
12
+ }
13
+
14
+ const parseCollection = (ymlString: string): ParsedCollection => {
15
+ try {
16
+ const oc: OpenCollection = parseYml(ymlString);
17
+
18
+ // bruno config
19
+ const brunoConfig: Record<string, any> = {
20
+ opencollection: oc.opencollection || '1.0.0',
21
+ name: oc.info?.name || 'Untitled Collection',
22
+ type: 'collection',
23
+ ignore: []
24
+ };
25
+ if (oc.extensions?.ignore && Array.isArray(oc.extensions.ignore)) {
26
+ brunoConfig.ignore = oc.extensions.ignore;
27
+ }
28
+
29
+ // presets
30
+ if (oc.extensions?.presets) {
31
+ const presets = oc.extensions.presets as any;
32
+ if (presets.request) {
33
+ brunoConfig.presets = {
34
+ requestType: presets.request.type || [],
35
+ requestUrl: presets.request.url || []
36
+ };
37
+ }
38
+ }
39
+
40
+ // protobuf
41
+ if (oc.config?.protobuf) {
42
+ brunoConfig.protobuf = {
43
+ protofFiles: oc.config.protobuf.protoFiles?.map((protoFile: any) => ({
44
+ path: protoFile.path
45
+ })) || [],
46
+ importPaths: oc.config.protobuf.importPaths?.map((importPath: any) => ({
47
+ path: importPath.path,
48
+ disabled: importPath.disabled || false
49
+ })) || []
50
+ };
51
+ }
52
+
53
+ // proxy - only support newer format
54
+ // Default: inherit from global preferences
55
+ brunoConfig.proxy = {
56
+ inherit: true,
57
+ config: {
58
+ protocol: 'http',
59
+ hostname: '',
60
+ port: '',
61
+ auth: {
62
+ username: '',
63
+ password: ''
64
+ },
65
+ bypassProxy: ''
66
+ }
67
+ };
68
+
69
+ if (oc.config?.proxy && typeof oc.config.proxy === 'object') {
70
+ // Validate newer format: must have 'inherit' and 'config' properties
71
+ const proxyConfig = oc.config.proxy as any;
72
+
73
+ if ('inherit' in proxyConfig && typeof proxyConfig.inherit === 'boolean' && proxyConfig.config && typeof proxyConfig.config === 'object') {
74
+ // Valid newer format
75
+ brunoConfig.proxy = {
76
+ inherit: proxyConfig.inherit,
77
+ config: {
78
+ protocol: proxyConfig.config.protocol || 'http',
79
+ hostname: proxyConfig.config.hostname || '',
80
+ port: proxyConfig.config.port || '',
81
+ auth: {
82
+ username: proxyConfig.config.auth?.username || '',
83
+ password: proxyConfig.config.auth?.password || ''
84
+ },
85
+ bypassProxy: proxyConfig.config.bypassProxy || ''
86
+ }
87
+ };
88
+
89
+ // Handle optional disabled field
90
+ if (proxyConfig.disabled === true) {
91
+ brunoConfig.proxy.disabled = true;
92
+ }
93
+
94
+ // Handle optional auth.disabled field
95
+ if (proxyConfig.config.auth?.disabled === true) {
96
+ brunoConfig.proxy.config.auth.disabled = true;
97
+ }
98
+ }
99
+ // If not in newer format, use default (inherit: true)
100
+ }
101
+
102
+ // client certificates
103
+ if (oc.config?.clientCertificates?.length) {
104
+ brunoConfig.clientCertificates = {
105
+ certs: oc.config.clientCertificates.map((cert: any) => {
106
+ if (cert.type === 'pem') {
107
+ return {
108
+ domain: cert.domain,
109
+ type: 'cert',
110
+ certFilePath: cert.certificateFilePath,
111
+ keyFilePath: cert.privateKeyFilePath,
112
+ passphrase: cert.passphrase || ''
113
+ };
114
+ } else if (cert.type === 'pkcs12') {
115
+ return {
116
+ domain: cert.domain,
117
+ type: 'pfx',
118
+ pfxFilePath: cert.pkcs12FilePath,
119
+ passphrase: cert.passphrase || ''
120
+ };
121
+ }
122
+ return null;
123
+ }).filter((cert: any) => cert !== null)
124
+ };
125
+ }
126
+
127
+ // collection root
128
+ const collectionRoot: FolderRoot = {
129
+ meta: null,
130
+ request: null,
131
+ docs: null
132
+ };
133
+
134
+ // request defaults
135
+ if (oc.request) {
136
+ collectionRoot.request = {
137
+ headers: null,
138
+ auth: null,
139
+ script: {
140
+ req: null,
141
+ res: null
142
+ },
143
+ vars: {
144
+ req: [],
145
+ res: []
146
+ },
147
+ tests: null
148
+ };
149
+
150
+ // headers
151
+ const headers = toBrunoHttpHeaders(oc.request.headers);
152
+ collectionRoot.request.headers = headers || [];
153
+
154
+ // auth
155
+ const auth = toBrunoAuth(oc.request.auth);
156
+ if (auth) {
157
+ collectionRoot.request.auth = auth;
158
+ }
159
+
160
+ // variables
161
+ const variables = toBrunoVariables(oc.request.variables);
162
+ collectionRoot.request.vars = variables;
163
+
164
+ // scripts
165
+ const scripts = toBrunoScripts(oc.request.scripts);
166
+ if (scripts?.script && collectionRoot.request.script) {
167
+ if (scripts.script.req) {
168
+ collectionRoot.request.script.req = scripts.script.req;
169
+ }
170
+ if (scripts.script.res) {
171
+ collectionRoot.request.script.res = scripts.script.res;
172
+ }
173
+ }
174
+ if (scripts?.tests) {
175
+ collectionRoot.request.tests = scripts.tests;
176
+ }
177
+ }
178
+
179
+ // docs
180
+ if (oc.docs) {
181
+ if (typeof oc.docs === 'string') {
182
+ collectionRoot.docs = oc.docs;
183
+ } else if (typeof oc.docs === 'object' && oc.docs.content) {
184
+ collectionRoot.docs = oc.docs.content;
185
+ }
186
+ }
187
+
188
+ return {
189
+ collectionRoot,
190
+ brunoConfig
191
+ };
192
+ } catch (error) {
193
+ console.error('Error parsing collection:', error);
194
+ throw error;
195
+ }
196
+ };
197
+
198
+ export default parseCollection;
@@ -0,0 +1,56 @@
1
+ import type { Environment as BrunoEnvironment, EnvironmentVariable as BrunoEnvironmentVariable } from '@usebruno/schema-types/collection/environment';
2
+ import type { Environment } from '@opencollection/types/config/environments';
3
+ import type { Variable, SecretVariable } from '@opencollection/types/common/variables';
4
+ import { parseYml } from './utils';
5
+ import { uuid } from '../../utils';
6
+
7
+ const isSecretVariable = (v: Variable | SecretVariable): v is SecretVariable => {
8
+ return 'secret' in v && v.secret === true;
9
+ };
10
+
11
+ const toBrunoEnvironmentVariables = (variables: (Variable | SecretVariable)[] | null | undefined): BrunoEnvironmentVariable[] => {
12
+ if (!variables?.length) {
13
+ return [];
14
+ }
15
+
16
+ return variables.map((v): BrunoEnvironmentVariable => {
17
+ if (isSecretVariable(v)) {
18
+ return {
19
+ uid: uuid(),
20
+ name: v.name || '',
21
+ value: '',
22
+ type: 'text',
23
+ enabled: v.disabled !== true,
24
+ secret: true
25
+ };
26
+ }
27
+ const variable: BrunoEnvironmentVariable = {
28
+ uid: uuid(),
29
+ name: v.name || '',
30
+ value: (typeof v.value === 'string' ? v.value : '') || '',
31
+ type: 'text',
32
+ enabled: v.disabled !== true,
33
+ secret: false
34
+ };
35
+ return variable;
36
+ });
37
+ };
38
+
39
+ const parseEnvironment = (ymlString: string): BrunoEnvironment => {
40
+ try {
41
+ const ocEnvironment: Environment = parseYml(ymlString);
42
+
43
+ const brunoEnvironment: BrunoEnvironment = {
44
+ uid: uuid(),
45
+ name: ocEnvironment.name || 'Untitled Environment',
46
+ variables: toBrunoEnvironmentVariables(ocEnvironment.variables)
47
+ };
48
+
49
+ return brunoEnvironment;
50
+ } catch (error) {
51
+ console.error('Error parsing environment:', error);
52
+ throw error;
53
+ }
54
+ };
55
+
56
+ export default parseEnvironment;
@@ -0,0 +1,88 @@
1
+ import type { FolderRoot } from '@usebruno/schema-types/collection/folder';
2
+ import type { Folder } from '@opencollection/types/collection/item';
3
+ import { parseYml } from './utils';
4
+ import { toBrunoAuth } from './common/auth';
5
+ import { toBrunoHttpHeaders } from './common/headers';
6
+ import { toBrunoVariables } from './common/variables';
7
+ import { toBrunoScripts } from './common/scripts';
8
+ import { isNonEmptyString } from '../../utils';
9
+
10
+ const parseFolder = (ymlString: string): FolderRoot => {
11
+ try {
12
+ const ocFolder: Folder = parseYml(ymlString);
13
+
14
+ const info = ocFolder.info;
15
+
16
+ const folderRoot: FolderRoot = {
17
+ meta: {
18
+ name: info?.name || 'Untitled Folder',
19
+ seq: info?.seq || 1
20
+ },
21
+ request: null,
22
+ docs: null
23
+ };
24
+
25
+ // request defaults
26
+ if (ocFolder.request) {
27
+ folderRoot.request = {
28
+ headers: [],
29
+ auth: null,
30
+ script: {
31
+ req: null,
32
+ res: null
33
+ },
34
+ vars: {
35
+ req: [],
36
+ res: []
37
+ },
38
+ tests: null
39
+ };
40
+
41
+ // headers
42
+ const headers = toBrunoHttpHeaders(ocFolder.request.headers);
43
+ if (headers) {
44
+ folderRoot.request.headers = headers;
45
+ }
46
+
47
+ // auth
48
+ const auth = toBrunoAuth(ocFolder.request.auth);
49
+ if (auth) {
50
+ folderRoot.request.auth = auth;
51
+ }
52
+
53
+ // variables
54
+ const variables = toBrunoVariables(ocFolder.request.variables);
55
+ folderRoot.request.vars = variables;
56
+
57
+ // scripts
58
+ const scripts = toBrunoScripts(ocFolder.request.scripts);
59
+ if (scripts?.script && folderRoot.request.script) {
60
+ if (scripts.script.req) {
61
+ folderRoot.request.script.req = scripts.script.req;
62
+ }
63
+ if (scripts.script.res) {
64
+ folderRoot.request.script.res = scripts.script.res;
65
+ }
66
+ }
67
+ if (scripts?.tests) {
68
+ folderRoot.request.tests = scripts.tests;
69
+ }
70
+ }
71
+
72
+ // docs (now at root level)
73
+ if (ocFolder.docs) {
74
+ if (typeof ocFolder.docs === 'string' && ocFolder.docs.trim().length) {
75
+ folderRoot.docs = ocFolder.docs;
76
+ } else if (typeof ocFolder.docs === 'object' && ocFolder.docs.content?.trim().length) {
77
+ folderRoot.docs = ocFolder.docs.content;
78
+ }
79
+ }
80
+
81
+ return folderRoot;
82
+ } catch (error) {
83
+ console.error('Error parsing folder:', error);
84
+ throw error;
85
+ }
86
+ };
87
+
88
+ export default parseFolder;
@@ -0,0 +1,102 @@
1
+ import type { Item as BrunoItem } from '@usebruno/schema-types/collection/item';
2
+ import type { Item, ScriptFile } from '@opencollection/types/collection/item';
3
+ import type { HttpRequest } from '@opencollection/types/requests/http';
4
+ import type { GraphQLRequest } from '@opencollection/types/requests/graphql';
5
+ import type { GrpcRequest } from '@opencollection/types/requests/grpc';
6
+ import type { WebSocketRequest } from '@opencollection/types/requests/websocket';
7
+ import { parseYml } from './utils';
8
+ import parseHttpRequest from './items/parseHttpRequest';
9
+ import parseGraphQLRequest from './items/parseGraphQLRequest';
10
+ import parseGrpcRequest from './items/parseGrpcRequest';
11
+ import parseWebsocketRequest from './items/parseWebsocketRequest';
12
+ import parseScript from './items/parseScript';
13
+
14
+ // Helper to get the type from an item (now in info block)
15
+ const getItemType = (item: Item): string | undefined => {
16
+ if ('info' in item && item.info && 'type' in item.info) {
17
+ return item.info.type;
18
+ }
19
+ // For ScriptFile which still has type at root
20
+ if ('type' in item) {
21
+ return (item as ScriptFile).type;
22
+ }
23
+ return undefined;
24
+ };
25
+
26
+ /**
27
+ * In v3.0.0-rc1 release auth was present under runtime property for all requests
28
+ * This has now been moved to the respective request properties
29
+ * This backward compatibility has been put in place for folks who tried out our early preview
30
+ * Should be safe to remove this in 3 months. Delete after 5 Apr 2026
31
+ */
32
+ const ensureAuthV3Rc1BackwardsCompatibility = (parsedItemYml: any): any => {
33
+ const itemType = parsedItemYml?.info?.type;
34
+
35
+ switch (itemType) {
36
+ case 'http':
37
+ if (parsedItemYml.runtime?.auth && !parsedItemYml.http?.auth) {
38
+ parsedItemYml.http.auth = parsedItemYml.runtime.auth;
39
+ }
40
+ break;
41
+ case 'graphql':
42
+ if (parsedItemYml.runtime?.auth && !parsedItemYml.graphql?.auth) {
43
+ parsedItemYml.graphql.auth = parsedItemYml.runtime.auth;
44
+ }
45
+ break;
46
+ case 'grpc':
47
+ if (parsedItemYml.runtime?.auth && !parsedItemYml.grpc?.auth) {
48
+ parsedItemYml.grpc.auth = parsedItemYml.runtime.auth;
49
+ }
50
+ break;
51
+ case 'websocket':
52
+ if (parsedItemYml.runtime?.auth && !parsedItemYml.websocket?.auth) {
53
+ parsedItemYml.websocket.auth = parsedItemYml.runtime.auth;
54
+ }
55
+ break;
56
+ default:
57
+ break;
58
+ }
59
+
60
+ return parsedItemYml;
61
+ };
62
+
63
+ const parseItem = (ymlString: string): BrunoItem => {
64
+ try {
65
+ const parsedYml = parseYml(ymlString);
66
+
67
+ const ocItem: Item = ensureAuthV3Rc1BackwardsCompatibility(parsedYml);
68
+ const itemType = getItemType(ocItem);
69
+
70
+ if (!ocItem || !itemType) {
71
+ throw new Error('Invalid item: missing type');
72
+ }
73
+
74
+ switch (itemType) {
75
+ case 'http':
76
+ return parseHttpRequest(ocItem as HttpRequest);
77
+
78
+ case 'graphql':
79
+ return parseGraphQLRequest(ocItem as GraphQLRequest);
80
+
81
+ case 'grpc':
82
+ return parseGrpcRequest(ocItem as GrpcRequest);
83
+
84
+ case 'websocket':
85
+ return parseWebsocketRequest(ocItem as WebSocketRequest);
86
+
87
+ case 'script':
88
+ return parseScript(ocItem as ScriptFile);
89
+
90
+ case 'folder':
91
+ throw new Error('Folder items should be handled separately using parseFolder');
92
+
93
+ default:
94
+ throw new Error(`Unsupported item type: ${itemType}`);
95
+ }
96
+ } catch (error) {
97
+ console.error('Error parsing item:', error);
98
+ throw error;
99
+ }
100
+ };
101
+
102
+ export default parseItem;
@@ -0,0 +1,230 @@
1
+ import type { OpenCollection } from '@opencollection/types';
2
+ import type { ProtoFileItem, ProtoFileImportPath } from '@opencollection/types/config/protobuf';
3
+ import type { HttpRequestHeader } from '@opencollection/types/requests/http';
4
+ import type { ClientCertificate, PemCertificate, Pkcs12Certificate } from '@opencollection/types/config/certificates';
5
+ import type { Variable } from '@opencollection/types/common/variables';
6
+ import type { Scripts } from '@opencollection/types/common/scripts';
7
+ import { stringifyYml } from './utils';
8
+ import { toOpenCollectionAuth } from './common/auth';
9
+ import { toOpenCollectionHttpHeaders } from './common/headers';
10
+ import { toOpenCollectionVariables } from './common/variables';
11
+ import { toOpenCollectionScripts } from './common/scripts';
12
+ import type { Auth } from '@opencollection/types/common/auth';
13
+
14
+ const hasCollectionConfig = (brunoConfig: any): boolean => {
15
+ // protobuf
16
+ const hasProtobuf = (
17
+ brunoConfig.protobuf?.protofFiles?.length > 0
18
+ || brunoConfig.protobuf?.importPaths?.length > 0
19
+ );
20
+
21
+ // proxy - check if proxy is configured in newer format
22
+ // Valid newer format: has 'inherit' property and 'config' object
23
+ const isValidProxyFormat = brunoConfig.proxy
24
+ && typeof brunoConfig.proxy === 'object'
25
+ && 'inherit' in brunoConfig.proxy
26
+ && brunoConfig.proxy.config
27
+ && typeof brunoConfig.proxy.config === 'object';
28
+
29
+ const hasProxy = isValidProxyFormat;
30
+
31
+ // client certificates
32
+ const hasClientCertificates = brunoConfig.clientCertificates?.certs?.length > 0;
33
+
34
+ return hasProtobuf || hasProxy || hasClientCertificates;
35
+ };
36
+
37
+ const hasRequestDefaults = (collectionRoot: any): boolean => {
38
+ const requestRoot = collectionRoot?.request;
39
+
40
+ return Boolean((requestRoot?.headers?.length)
41
+ || (requestRoot?.vars?.req?.length)
42
+ || hasRequestScripts(collectionRoot)
43
+ || hasRequestAuth(collectionRoot));
44
+ };
45
+
46
+ const hasRequestAuth = (collectionRoot: any): boolean => {
47
+ return Boolean((collectionRoot.request?.auth?.mode !== 'none'));
48
+ };
49
+
50
+ const hasRequestScripts = (collectionRoot: any): boolean => {
51
+ return (collectionRoot.request?.script?.req)
52
+ || (collectionRoot.request?.script?.res)
53
+ || (collectionRoot.request?.tests);
54
+ };
55
+
56
+ const hasPresets = (brunoConfig: any): boolean => {
57
+ return brunoConfig?.presets?.requestType?.length
58
+ || brunoConfig?.presets?.requestUrl?.length;
59
+ };
60
+
61
+ const stringifyCollection = (collectionRoot: any, brunoConfig: any): string => {
62
+ try {
63
+ const oc: OpenCollection = {};
64
+
65
+ oc.opencollection = '1.0.0';
66
+ oc.info = {
67
+ name: brunoConfig.name || 'Untitled Collection'
68
+ };
69
+
70
+ // collection config
71
+ if (hasCollectionConfig(brunoConfig)) {
72
+ oc.config = {};
73
+
74
+ if (brunoConfig.protobuf?.protofFiles?.length) {
75
+ oc.config.protobuf = {
76
+ protoFiles: brunoConfig.protobuf.protofFiles.map((protoFile: any): ProtoFileItem => ({
77
+ type: 'file' as const,
78
+ path: protoFile.path
79
+ })),
80
+ importPaths: brunoConfig.protobuf.importPaths.map((importPath: any): ProtoFileImportPath => ({
81
+ path: importPath.path,
82
+ disabled: importPath.disabled
83
+ }))
84
+ };
85
+ }
86
+
87
+ // proxy - only write newer format
88
+ // Validate that brunoConfig.proxy is in newer format before writing
89
+ const isValidProxyFormat = brunoConfig.proxy
90
+ && typeof brunoConfig.proxy === 'object'
91
+ && 'inherit' in brunoConfig.proxy
92
+ && brunoConfig.proxy.config
93
+ && typeof brunoConfig.proxy.config === 'object';
94
+
95
+ if (isValidProxyFormat) {
96
+ oc.config.proxy = {
97
+ inherit: brunoConfig.proxy.inherit,
98
+ config: {
99
+ protocol: brunoConfig.proxy.config.protocol || 'http',
100
+ hostname: brunoConfig.proxy.config.hostname || '',
101
+ port: brunoConfig.proxy.config.port || '',
102
+ auth: {
103
+ username: brunoConfig.proxy.config.auth?.username || '',
104
+ password: brunoConfig.proxy.config.auth?.password || ''
105
+ },
106
+ bypassProxy: brunoConfig.proxy.config.bypassProxy || ''
107
+ }
108
+ };
109
+
110
+ // Add optional disabled field if true
111
+ if (brunoConfig.proxy.disabled === true) {
112
+ oc.config.proxy.disabled = true;
113
+ }
114
+
115
+ // Add optional auth.disabled field if true
116
+ if (brunoConfig.proxy.config?.auth?.disabled === true) {
117
+ if (oc.config.proxy.config && oc.config.proxy.config.auth) {
118
+ oc.config.proxy.config.auth.disabled = true;
119
+ }
120
+ }
121
+ }
122
+
123
+ // client certificates
124
+ if (brunoConfig.clientCertificates?.certs?.length) {
125
+ oc.config.clientCertificates = brunoConfig.clientCertificates.certs
126
+ .map((cert: any): ClientCertificate | null => {
127
+ if (cert.type === 'pem') {
128
+ const pemCert: PemCertificate = {
129
+ domain: cert.domain,
130
+ type: 'pem',
131
+ certificateFilePath: cert.certFilePath,
132
+ privateKeyFilePath: cert.keyFilePath,
133
+ ...(cert.passphrase && { passphrase: cert.passphrase })
134
+ };
135
+ return pemCert;
136
+ } else if (cert.type === 'pkcs12') {
137
+ const pkcs12Cert: Pkcs12Certificate = {
138
+ domain: cert.domain,
139
+ type: 'pkcs12',
140
+ pkcs12FilePath: cert.pfxFilePath,
141
+ ...(cert.passphrase && { passphrase: cert.passphrase })
142
+ };
143
+ return pkcs12Cert;
144
+ } else {
145
+ // Unsupported certificate type - ignore silently
146
+ return null;
147
+ }
148
+ })
149
+ .filter((cert: ClientCertificate | null): cert is ClientCertificate => cert !== null);
150
+ }
151
+ }
152
+
153
+ // request defaults
154
+ if (hasRequestDefaults(collectionRoot)) {
155
+ oc.request = {};
156
+
157
+ // headers
158
+ if (collectionRoot.request?.headers?.length) {
159
+ const ocHeaders: HttpRequestHeader[] | undefined = toOpenCollectionHttpHeaders(collectionRoot.request?.headers);
160
+ if (ocHeaders) {
161
+ oc.request.headers = ocHeaders;
162
+ }
163
+ }
164
+
165
+ // auth
166
+ if (hasRequestAuth(collectionRoot)) {
167
+ const ocAuth: Auth | undefined = toOpenCollectionAuth(collectionRoot.request?.auth);
168
+ if (ocAuth) {
169
+ oc.request.auth = ocAuth;
170
+ }
171
+ }
172
+
173
+ // variables
174
+ if (collectionRoot.request?.vars?.req?.length) {
175
+ const ocVariables: Variable[] | undefined = toOpenCollectionVariables(collectionRoot.request?.vars);
176
+ if (ocVariables) {
177
+ oc.request.variables = ocVariables;
178
+ }
179
+ }
180
+
181
+ // scripts
182
+ if (hasRequestScripts(collectionRoot)) {
183
+ const ocScripts: Scripts | undefined = toOpenCollectionScripts(collectionRoot.request);
184
+ if (ocScripts) {
185
+ oc.request.scripts = ocScripts;
186
+ }
187
+ }
188
+ }
189
+
190
+ // docs
191
+ if (collectionRoot.docs?.trim().length) {
192
+ oc.docs = {
193
+ content: collectionRoot.docs,
194
+ type: 'text/markdown'
195
+ };
196
+ }
197
+
198
+ // bundled
199
+ oc.bundled = false;
200
+
201
+ // extensions
202
+ oc.extensions = {};
203
+ if (brunoConfig.ignore?.length) {
204
+ const ignoreList: string[] = [];
205
+ brunoConfig.ignore.forEach((ignore: string) => {
206
+ ignoreList.push(ignore);
207
+ });
208
+ oc.extensions.ignore = ignoreList;
209
+ }
210
+ if (hasPresets(brunoConfig)) {
211
+ const presetsRequest: any = {};
212
+ if (brunoConfig.presets.requestType?.length) {
213
+ presetsRequest.type = brunoConfig.presets.requestType;
214
+ }
215
+ if (brunoConfig.presets.requestUrl?.length) {
216
+ presetsRequest.url = brunoConfig.presets.requestUrl;
217
+ }
218
+ oc.extensions.presets = {
219
+ request: presetsRequest
220
+ } as any;
221
+ }
222
+
223
+ return stringifyYml(oc);
224
+ } catch (error) {
225
+ console.error('Error stringifying opencollection.yml:', error);
226
+ throw error;
227
+ }
228
+ };
229
+
230
+ export default stringifyCollection;