@usebruno/filestore 0.8.0 → 0.9.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/formats/bru/index.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,eAAe,SAAU,MAAM,GAAG,GAAG,WAAU,OAAO,KAAW,GAuG7E,CAAC;AAEF,eAAO,MAAM,mBAAmB,SAAU,GAAG,KAAG,MA+G/C,CAAC;AAEF,eAAO,MAAM,kBAAkB,SAAU,MAAM,GAAG,GAAG,WAAU,OAAO,KAAW,GA4ChF,CAAC;AAEF,eAAO,MAAM,sBAAsB,SAAU,GAAG,aAAa,OAAO,KAAG,MAuCtE,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAS,MAAM,KAAG,GAejD,CAAC;AAEF,eAAO,MAAM,uBAAuB,SAAU,GAAG,KAAG,MAOnD,CAAC;AAGF,eAAO,MAAM,gBAAgB,SAAU,MAAM,GAAG,GAAG,WAAU,OAAO,eAAuB,MAAM,iBAAiB,MAAM,KAAG,GA6D1H,CAAC;AAEF,eAAO,MAAM,gBAAgB,SAAU,GAAG;;;;;;;;;;;CAsBzC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/formats/bru/index.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,eAAe,SAAU,MAAM,GAAG,GAAG,WAAU,OAAO,KAAW,GAwG7E,CAAC;AAEF,eAAO,MAAM,mBAAmB,SAAU,GAAG,KAAG,MA+G/C,CAAC;AAEF,eAAO,MAAM,kBAAkB,SAAU,MAAM,GAAG,GAAG,WAAU,OAAO,KAAW,GA4ChF,CAAC;AAEF,eAAO,MAAM,sBAAsB,SAAU,GAAG,aAAa,OAAO,KAAG,MAuCtE,CAAC;AAEF,eAAO,MAAM,mBAAmB,QAAS,MAAM,KAAG,GAejD,CAAC;AAEF,eAAO,MAAM,uBAAuB,SAAU,GAAG,KAAG,MAOnD,CAAC;AAGF,eAAO,MAAM,gBAAgB,SAAU,MAAM,GAAG,GAAG,WAAU,OAAO,eAAuB,MAAM,iBAAiB,MAAM,KAAG,GAwE1H,CAAC;AAEF,eAAO,MAAM,gBAAgB,SAAU,GAAG;;;;;;;;;;;CAsBzC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=example-status-swap.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"example-status-swap.spec.d.ts","sourceRoot":"","sources":["../../../../src/formats/bru/tests/example-status-swap.spec.js"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../../src/formats/yml/common/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,IAAI,EAQL,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,oCAAoC,CAAC;AA2G5E,eAAO,MAAM,oBAAoB,UAAW,SAAS,GAAG,IAAI,KAAG,IAAI,GAAG,SA8BrE,CAAC;AAEF,eAAO,MAAM,WAAW,SAAU,IAAI,GAAG,IAAI,GAAG,SAAS,KAAG,SAAS,GAAG,IA+FvE,CAAC"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../../src/formats/yml/common/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,IAAI,EASL,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,IAAI,IAAI,SAAS,EAAiC,MAAM,oCAAoC,CAAC;AAwI3G,eAAO,MAAM,oBAAoB,UAAW,SAAS,GAAG,IAAI,KAAG,IAAI,GAAG,SAgCrE,CAAC;AAEF,eAAO,MAAM,WAAW,SAAU,IAAI,GAAG,IAAI,GAAG,SAAS,KAAG,SAAS,GAAG,IAoHvE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usebruno/filestore",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -29,23 +29,23 @@
29
29
  "@types/jest": "^29.5.11",
30
30
  "@types/lodash": "^4.14.191",
31
31
  "@types/node": "^24.1.0",
32
- "@usebruno/schema-types": "0.3.0",
32
+ "@usebruno/schema-types": "0.4.0",
33
33
  "babel-jest": "^29.7.0",
34
34
  "jest": "^29.2.0",
35
35
  "nanoid": "3.3.8",
36
36
  "rimraf": "^3.0.2",
37
- "rollup": "3.29.5",
37
+ "rollup": "3.30.0",
38
38
  "rollup-plugin-dts": "^5.0.0",
39
39
  "rollup-plugin-peer-deps-external": "^2.2.4",
40
- "rollup-plugin-terser": "^7.0.2",
40
+ "@rollup/plugin-terser": "^1.0.0",
41
41
  "typescript": "^4.8.4"
42
42
  },
43
43
  "overrides": {
44
- "rollup": "3.29.5"
44
+ "rollup": "3.30.0"
45
45
  },
46
46
  "dependencies": {
47
47
  "@types/nanoid": "^2.1.0",
48
- "@usebruno/lang": "0.35.0",
48
+ "@usebruno/lang": "0.36.0",
49
49
  "ajv": "^8.17.1",
50
50
  "lodash": "^4.17.21",
51
51
  "yaml": "^2.3.4"
@@ -32,6 +32,7 @@ export const parseBruRequest = (data: string | any, parsed: boolean = false): an
32
32
  }
33
33
 
34
34
  const sequence = _.get(json, 'meta.seq');
35
+ const tags = _.get(json, 'meta.tags', []);
35
36
  const urlPath: Record<typeof requestType, string> = {
36
37
  'grpc-request': 'grpc.url',
37
38
  'ws-request': 'ws.url',
@@ -42,7 +43,7 @@ export const parseBruRequest = (data: string | any, parsed: boolean = false): an
42
43
  name: _.get(json, 'meta.name'),
43
44
  seq: !_.isNaN(sequence) ? Number(sequence) : 1,
44
45
  settings: _.get(json, 'settings', {}),
45
- tags: _.get(json, 'meta.tags', []),
46
+ tags: Array.isArray(tags) ? tags : [],
46
47
  request: {
47
48
  // Preserving special characters in custom methods. Using _.upperCase strips special characters.
48
49
  method:
@@ -367,6 +368,17 @@ export const bruExampleToJson = (data: string | any, parsed: boolean = false, pa
367
368
  transformedType = 'http-request';
368
369
  }
369
370
 
371
+ /**
372
+ * Backward compatibility (pre-v3.0.2 - v3.2.0): Postman imports before PR #6876 stored status/statusText swapped
373
+ * (code: "OK", text: "202" instead of code: 202, text: "OK"). Detect and swap back.
374
+ * TODO(Sid / Shubh): Remove after v5 — all collections should be migrated by then.
375
+ */
376
+ let status = _.get(json, 'response.status', '200');
377
+ let statusText = _.get(json, 'response.statusText', 'OK');
378
+ if (isNaN(Number(status)) && !isNaN(Number(statusText))) {
379
+ [status, statusText] = [statusText, status];
380
+ }
381
+
370
382
  // Follow the same structure as the main request, but with missing fields for examples
371
383
  const transformedJson = {
372
384
  type: transformedType,
@@ -388,8 +400,8 @@ export const bruExampleToJson = (data: string | any, parsed: boolean = false, pa
388
400
  name: header.name,
389
401
  value: header.value
390
402
  })),
391
- status: String(_.get(json, 'response.status', '200')),
392
- statusText: _.get(json, 'response.statusText', 'OK'),
403
+ status: Number(status) || 200,
404
+ statusText: statusText || 'OK',
393
405
  body: {
394
406
  type: _.get(json, 'response.body.type', 'json'),
395
407
  content: _.get(json, 'response.body.content', '')
@@ -0,0 +1,109 @@
1
+ const { bruExampleToJson } = require('../index');
2
+
3
+ describe('bruExampleToJson - status/statusText swap fix', () => {
4
+ it('should parse normal status and statusText correctly', () => {
5
+ const parsed = {
6
+ name: 'Normal Example',
7
+ description: '',
8
+ request: { url: 'https://api.example.com/test', method: 'get' },
9
+ response: {
10
+ headers: [],
11
+ status: '200',
12
+ statusText: 'OK',
13
+ body: { type: 'json', content: '{}' }
14
+ }
15
+ };
16
+
17
+ const result = bruExampleToJson(parsed, true, 'http', 'GET');
18
+ expect(result.response.status).toBe(200);
19
+ expect(result.response.statusText).toBe('OK');
20
+ });
21
+
22
+ it('should swap back status and statusText when they are reversed (pre-fix Postman import)', () => {
23
+ const parsed = {
24
+ name: 'Swapped Example',
25
+ description: '',
26
+ request: { url: 'https://api.example.com/test', method: 'get' },
27
+ response: {
28
+ headers: [],
29
+ status: 'Accepted',
30
+ statusText: '202',
31
+ body: { type: 'json', content: '{}' }
32
+ }
33
+ };
34
+
35
+ const result = bruExampleToJson(parsed, true, 'http', 'GET');
36
+ expect(result.response.status).toBe(202);
37
+ expect(result.response.statusText).toBe('Accepted');
38
+ });
39
+
40
+ it('should swap back status OK and statusText 200', () => {
41
+ const parsed = {
42
+ name: 'Swapped OK Example',
43
+ description: '',
44
+ request: { url: 'https://api.example.com/test', method: 'get' },
45
+ response: {
46
+ headers: [],
47
+ status: 'OK',
48
+ statusText: '200',
49
+ body: { type: 'json', content: '{}' }
50
+ }
51
+ };
52
+
53
+ const result = bruExampleToJson(parsed, true, 'http', 'GET');
54
+ expect(result.response.status).toBe(200);
55
+ expect(result.response.statusText).toBe('OK');
56
+ });
57
+
58
+ it('should swap back status Not Found and statusText 404', () => {
59
+ const parsed = {
60
+ name: 'Swapped Not Found Example',
61
+ description: '',
62
+ request: { url: 'https://api.example.com/test', method: 'get' },
63
+ response: {
64
+ headers: [],
65
+ status: 'Not Found',
66
+ statusText: '404',
67
+ body: { type: 'json', content: '{}' }
68
+ }
69
+ };
70
+
71
+ const result = bruExampleToJson(parsed, true, 'http', 'GET');
72
+ expect(result.response.status).toBe(404);
73
+ expect(result.response.statusText).toBe('Not Found');
74
+ });
75
+
76
+ it('should not swap when status is already numeric and statusText is text (correct order)', () => {
77
+ const parsed = {
78
+ name: 'Correct Order Example',
79
+ description: '',
80
+ request: { url: 'https://api.example.com/test', method: 'get' },
81
+ response: {
82
+ headers: [],
83
+ status: '404',
84
+ statusText: 'Not Found',
85
+ body: { type: 'json', content: '{}' }
86
+ }
87
+ };
88
+
89
+ const result = bruExampleToJson(parsed, true, 'http', 'GET');
90
+ expect(result.response.status).toBe(404);
91
+ expect(result.response.statusText).toBe('Not Found');
92
+ });
93
+
94
+ it('should use defaults when response has no status', () => {
95
+ const parsed = {
96
+ name: 'No Status Example',
97
+ description: '',
98
+ request: { url: 'https://api.example.com/test', method: 'get' },
99
+ response: {
100
+ headers: [],
101
+ body: { type: 'json', content: '{}' }
102
+ }
103
+ };
104
+
105
+ const result = bruExampleToJson(parsed, true, 'http', 'GET');
106
+ expect(result.response.status).toBe(200);
107
+ expect(result.response.statusText).toBe('OK');
108
+ });
109
+ });
@@ -6,9 +6,10 @@ import type {
6
6
  AuthBearer,
7
7
  AuthDigest,
8
8
  AuthNTLM,
9
+ AuthOAuth1,
9
10
  AuthWsse
10
11
  } from '@opencollection/types/common/auth';
11
- import type { Auth as BrunoAuth } from '@usebruno/schema-types/common/auth';
12
+ import type { Auth as BrunoAuth, AuthOauth1 as BrunoAuthOauth1 } from '@usebruno/schema-types/common/auth';
12
13
  import { isString } from '../../../utils';
13
14
  import { toOpenCollectionOAuth2, toBrunoOAuth2 } from './auth-oauth2';
14
15
 
@@ -115,6 +116,35 @@ const buildApiKeyAuth = (config?: BrunoAuth['apikey']): AuthApiKey => {
115
116
  return auth;
116
117
  };
117
118
 
119
+ const buildOAuth1Auth = (config?: BrunoAuth['oauth1']): AuthOAuth1 => {
120
+ const auth: AuthOAuth1 = { type: 'oauth1' };
121
+
122
+ if (!config) {
123
+ return auth;
124
+ }
125
+
126
+ if (isString(config.consumerKey)) auth.consumerKey = config.consumerKey;
127
+ if (isString(config.consumerSecret)) auth.consumerSecret = config.consumerSecret;
128
+ if (isString(config.accessToken)) auth.accessToken = config.accessToken;
129
+ if (isString(config.accessTokenSecret)) auth.accessTokenSecret = config.accessTokenSecret;
130
+ if (isString(config.callbackUrl)) auth.callbackUrl = config.callbackUrl;
131
+ if (isString(config.verifier)) auth.verifier = config.verifier;
132
+ if (isString(config.signatureMethod)) auth.signatureMethod = config.signatureMethod;
133
+ if (isString(config.privateKey)) {
134
+ auth.privateKey = config.privateKeyType === 'file'
135
+ ? { type: 'file' as const, value: config.privateKey }
136
+ : { type: 'text' as const, value: config.privateKey };
137
+ }
138
+ if (isString(config.timestamp)) auth.timestamp = config.timestamp;
139
+ if (isString(config.nonce)) auth.nonce = config.nonce;
140
+ if (isString(config.version)) auth.version = config.version;
141
+ if (isString(config.realm)) auth.realm = config.realm;
142
+ if (isString(config.placement)) auth.placement = config.placement as AuthOAuth1['placement'];
143
+ if (typeof config.includeBodyHash === 'boolean') auth.includeBodyHash = config.includeBodyHash;
144
+
145
+ return auth;
146
+ };
147
+
118
148
  export const toOpenCollectionAuth = (auth?: BrunoAuth | null): Auth | undefined => {
119
149
  if (!auth || auth.mode === 'none') {
120
150
  return undefined;
@@ -139,6 +169,8 @@ export const toOpenCollectionAuth = (auth?: BrunoAuth | null): Auth | undefined
139
169
  return buildWsseAuth(auth.wsse);
140
170
  case 'apikey':
141
171
  return buildApiKeyAuth(auth.apikey);
172
+ case 'oauth1':
173
+ return buildOAuth1Auth(auth.oauth1);
142
174
  case 'oauth2':
143
175
  return toOpenCollectionOAuth2(auth.oauth2);
144
176
  default:
@@ -231,6 +263,27 @@ export const toBrunoAuth = (auth: Auth | null | undefined): BrunoAuth | null =>
231
263
  };
232
264
  break;
233
265
 
266
+ case 'oauth1':
267
+ brunoAuth.mode = 'oauth1';
268
+ brunoAuth.oauth1 = {
269
+ consumerKey: auth.consumerKey || null,
270
+ consumerSecret: auth.consumerSecret || null,
271
+ accessToken: auth.accessToken || null,
272
+ accessTokenSecret: auth.accessTokenSecret || null,
273
+ callbackUrl: auth.callbackUrl || null,
274
+ verifier: auth.verifier || null,
275
+ signatureMethod: (auth.signatureMethod as BrunoAuthOauth1['signatureMethod']) || 'HMAC-SHA1',
276
+ privateKey: (typeof auth.privateKey === 'object' && auth.privateKey ? auth.privateKey.value : auth.privateKey) || null,
277
+ privateKeyType: (typeof auth.privateKey === 'object' && auth.privateKey ? auth.privateKey.type : 'text') as BrunoAuthOauth1['privateKeyType'],
278
+ timestamp: auth.timestamp || null,
279
+ nonce: auth.nonce || null,
280
+ version: auth.version || '1.0',
281
+ realm: auth.realm || null,
282
+ placement: (auth.placement as BrunoAuthOauth1['placement']) || 'header',
283
+ includeBodyHash: auth.includeBodyHash || false
284
+ };
285
+ break;
286
+
234
287
  case 'oauth2':
235
288
  brunoAuth.mode = 'oauth2';
236
289
  brunoAuth.oauth2 = toBrunoOAuth2(auth);