@usebruno/filestore 0.10.0 → 0.11.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 (118) 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/constants.d.ts +2 -0
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/esm/index.js +1 -1
  8. package/dist/esm/index.js.map +1 -1
  9. package/dist/esm/workers/worker-script.js +1 -1
  10. package/dist/esm/workers/worker-script.js.map +1 -1
  11. package/dist/formats/bru/index.d.ts.map +1 -1
  12. package/dist/formats/bru/utils/redact-large-text-blocks.d.ts +11 -0
  13. package/dist/formats/bru/utils/redact-large-text-blocks.d.ts.map +1 -0
  14. package/dist/formats/yml/common/app.d.ts +8 -0
  15. package/dist/formats/yml/common/app.d.ts.map +1 -0
  16. package/dist/formats/yml/common/auth.d.ts.map +1 -1
  17. package/dist/formats/yml/common/body.d.ts.map +1 -1
  18. package/dist/formats/yml/common/datatype.d.ts +14 -0
  19. package/dist/formats/yml/common/datatype.d.ts.map +1 -0
  20. package/dist/formats/yml/common/headers.d.ts.map +1 -1
  21. package/dist/formats/yml/common/variables.d.ts +1 -2
  22. package/dist/formats/yml/common/variables.d.ts.map +1 -1
  23. package/dist/formats/yml/items/parseApp.d.ts +13 -0
  24. package/dist/formats/yml/items/parseApp.d.ts.map +1 -0
  25. package/dist/formats/yml/items/parseGraphQLRequest.d.ts.map +1 -1
  26. package/dist/formats/yml/items/parseGrpcRequest.d.ts.map +1 -1
  27. package/dist/formats/yml/items/parseHttpRequest.d.ts.map +1 -1
  28. package/dist/formats/yml/items/parseWebsocketRequest.d.ts.map +1 -1
  29. package/dist/formats/yml/items/stringifyApp.d.ts +4 -0
  30. package/dist/formats/yml/items/stringifyApp.d.ts.map +1 -0
  31. package/dist/formats/yml/items/stringifyGraphQLRequest.d.ts.map +1 -1
  32. package/dist/formats/yml/items/stringifyGrpcRequest.d.ts.map +1 -1
  33. package/dist/formats/yml/items/stringifyHttpRequest.d.ts.map +1 -1
  34. package/dist/formats/yml/items/stringifyWebsocketRequest.d.ts.map +1 -1
  35. package/dist/formats/yml/parseCollection.d.ts.map +1 -1
  36. package/dist/formats/yml/parseEnvironment.d.ts +3 -1
  37. package/dist/formats/yml/parseEnvironment.d.ts.map +1 -1
  38. package/dist/formats/yml/parseFolder.d.ts.map +1 -1
  39. package/dist/formats/yml/parseItem.d.ts.map +1 -1
  40. package/dist/formats/yml/stringifyCollection.d.ts.map +1 -1
  41. package/dist/formats/yml/stringifyEnvironment.d.ts +3 -1
  42. package/dist/formats/yml/stringifyEnvironment.d.ts.map +1 -1
  43. package/dist/formats/yml/stringifyItem.d.ts.map +1 -1
  44. package/dist/index.d.ts +4 -0
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/types.d.ts +6 -0
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/utils/secretsJsonToEnvironments.d.ts +38 -0
  49. package/dist/utils/secretsJsonToEnvironments.d.ts.map +1 -0
  50. package/package.json +7 -5
  51. package/src/constants.ts +9 -0
  52. package/src/formats/bru/index.ts +52 -0
  53. package/src/formats/bru/tests/parseBruEnvironment.spec.js +63 -0
  54. package/src/formats/bru/tests/redact-large-text-blocks.spec.js +313 -0
  55. package/src/formats/bru/utils/redact-large-text-blocks.ts +102 -0
  56. package/src/formats/yml/common/actions.ts +1 -1
  57. package/src/formats/yml/common/app.ts +27 -0
  58. package/src/formats/yml/common/auth.ts +53 -1
  59. package/src/formats/yml/common/body.spec.ts +62 -0
  60. package/src/formats/yml/common/body.ts +27 -9
  61. package/src/formats/yml/common/datatype.spec.ts +110 -0
  62. package/src/formats/yml/common/datatype.ts +57 -0
  63. package/src/formats/yml/common/headers.ts +4 -0
  64. package/src/formats/yml/common/variables.spec.ts +127 -0
  65. package/src/formats/yml/common/variables.ts +14 -22
  66. package/src/formats/yml/items/parseApp.ts +37 -0
  67. package/src/formats/yml/items/parseGraphQLRequest.ts +8 -0
  68. package/src/formats/yml/items/parseGrpcRequest.ts +24 -3
  69. package/src/formats/yml/items/parseHttpRequest.ts +13 -0
  70. package/src/formats/yml/items/parseWebsocketRequest.ts +29 -9
  71. package/src/formats/yml/items/stringifyApp.ts +45 -0
  72. package/src/formats/yml/items/stringifyGraphQLRequest.ts +3 -0
  73. package/src/formats/yml/items/stringifyGrpcRequest.ts +9 -11
  74. package/src/formats/yml/items/stringifyHttpRequest.ts +10 -0
  75. package/src/formats/yml/items/stringifyWebsocketRequest.ts +22 -9
  76. package/src/formats/yml/parseCollection.spec.ts +70 -0
  77. package/src/formats/yml/parseCollection.ts +8 -3
  78. package/src/formats/yml/parseEnvironment.spec.ts +99 -0
  79. package/src/formats/yml/parseEnvironment.ts +41 -19
  80. package/src/formats/yml/parseFolder.spec.ts +52 -0
  81. package/src/formats/yml/parseFolder.ts +14 -21
  82. package/src/formats/yml/parseItem.spec.ts +147 -0
  83. package/src/formats/yml/parseItem.ts +4 -0
  84. package/src/formats/yml/stringifyCollection.spec.ts +77 -0
  85. package/src/formats/yml/stringifyCollection.ts +4 -0
  86. package/src/formats/yml/stringifyEnvironment.spec.ts +91 -0
  87. package/src/formats/yml/stringifyEnvironment.ts +55 -20
  88. package/src/formats/yml/stringifyFolder.spec.ts +47 -0
  89. package/src/formats/yml/stringifyItem.spec.ts +53 -0
  90. package/src/formats/yml/stringifyItem.ts +4 -0
  91. package/src/formats/yml/tests/fixtures/presets/empty-request.yml +7 -0
  92. package/src/formats/yml/tests/fixtures/presets/no-presets.yml +3 -0
  93. package/src/formats/yml/tests/fixtures/presets/no-request-key.yml +6 -0
  94. package/src/formats/yml/tests/fixtures/presets/type-only-realistic.yml +24 -0
  95. package/src/formats/yml/tests/fixtures/presets/url-only-realistic.yml +25 -0
  96. package/src/formats/yml/tests/fixtures/presets/with-type-and-url.yml +9 -0
  97. package/src/formats/yml/tests/parseCollection.spec.js +63 -0
  98. package/src/formats/yml/tests/parseEnvironment.spec.js +24 -63
  99. package/src/formats/yml/tests/parseEnvironment.spec.ts +160 -0
  100. package/src/formats/yml/tests/stringifyEnvironment.spec.ts +204 -0
  101. package/src/formats/yml/tests/variables.spec.js +7 -7
  102. package/src/index.ts +5 -0
  103. package/src/types/bruno-lang.d.ts +1 -0
  104. package/src/types.ts +7 -0
  105. package/src/utils/secretsJsonToEnvironments.spec.ts +211 -0
  106. package/src/utils/secretsJsonToEnvironments.ts +129 -0
  107. package/dist/formats/bru/tests/example-status-swap.spec.d.ts +0 -2
  108. package/dist/formats/bru/tests/example-status-swap.spec.d.ts.map +0 -1
  109. package/dist/formats/bru/tests/fixtures/oauth2-additional-params.d.ts +0 -57
  110. package/dist/formats/bru/tests/fixtures/oauth2-additional-params.d.ts.map +0 -1
  111. package/dist/formats/bru/tests/oauth2-additional-params.spec.d.ts +0 -2
  112. package/dist/formats/bru/tests/oauth2-additional-params.spec.d.ts.map +0 -1
  113. package/dist/formats/bru/tests/request-parse-and-redact-body-data.spec.d.ts +0 -2
  114. package/dist/formats/bru/tests/request-parse-and-redact-body-data.spec.d.ts.map +0 -1
  115. package/dist/formats/yml/tests/parseEnvironment.spec.d.ts +0 -2
  116. package/dist/formats/yml/tests/parseEnvironment.spec.d.ts.map +0 -1
  117. package/dist/formats/yml/tests/variables.spec.d.ts +0 -2
  118. package/dist/formats/yml/tests/variables.spec.d.ts.map +0 -1
@@ -0,0 +1,63 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import parseCollection from '../parseCollection';
4
+
5
+ const loadFixture = (name) =>
6
+ fs.readFileSync(path.join(__dirname, 'fixtures', 'presets', `${name}.yml`), 'utf8');
7
+
8
+ describe('yml parseCollection - presets', () => {
9
+ it('parses presets when request.type and request.url are present', () => {
10
+ const { brunoConfig } = parseCollection(loadFixture('with-type-and-url'));
11
+
12
+ expect(brunoConfig.presets).toEqual({
13
+ requestType: 'graphql',
14
+ requestUrl: 'https://example.com/graphql'
15
+ });
16
+ });
17
+
18
+ it('defaults requestType and requestUrl to empty strings (not arrays) when request fields are missing', () => {
19
+ const { brunoConfig } = parseCollection(loadFixture('empty-request'));
20
+
21
+ expect(brunoConfig.presets).toEqual({
22
+ requestType: '',
23
+ requestUrl: ''
24
+ });
25
+ expect(Array.isArray(brunoConfig.presets.requestType)).toBe(false);
26
+ expect(Array.isArray(brunoConfig.presets.requestUrl)).toBe(false);
27
+ });
28
+
29
+ it('does not set presets when the extension has no presets block', () => {
30
+ const { brunoConfig } = parseCollection(loadFixture('no-presets'));
31
+
32
+ expect(brunoConfig.presets).toBeUndefined();
33
+ });
34
+
35
+ it('does not set presets when presets exists but request key is absent', () => {
36
+ const { brunoConfig } = parseCollection(loadFixture('no-request-key'));
37
+
38
+ expect(brunoConfig.presets).toBeUndefined();
39
+ });
40
+
41
+ it('parses a realistic collection with only request.type set (no url) — defaults url to empty string', () => {
42
+ const { brunoConfig } = parseCollection(loadFixture('type-only-realistic'));
43
+
44
+ expect(brunoConfig.presets).toEqual({
45
+ requestType: 'graphql',
46
+ requestUrl: ''
47
+ });
48
+ expect(Array.isArray(brunoConfig.presets.requestUrl)).toBe(false);
49
+ expect(brunoConfig.ignore).toEqual(['node_modules', '.git']);
50
+ });
51
+
52
+ it('parses a realistic collection with request.type http and request.url set', () => {
53
+ const { brunoConfig } = parseCollection(loadFixture('url-only-realistic'));
54
+
55
+ expect(brunoConfig.presets).toEqual({
56
+ requestType: 'http',
57
+ requestUrl: 'https://example.com/graphql'
58
+ });
59
+ expect(Array.isArray(brunoConfig.presets.requestType)).toBe(false);
60
+ expect(Array.isArray(brunoConfig.presets.requestUrl)).toBe(false);
61
+ expect(brunoConfig.ignore).toEqual(['node_modules', '.git']);
62
+ });
63
+ });
@@ -48,46 +48,46 @@ variables:
48
48
  const byName = (env) => Object.fromEntries(env.variables.map((v) => [v.name, v]));
49
49
 
50
50
  describe('yml parseEnvironment - typed values', () => {
51
- it('keeps the value as a string and preserves the type via datatype', () => {
51
+ it('coerces the value to its native JS type and preserves the type via dataType', () => {
52
52
  const variables = byName(parseEnvironment(ENV_YML));
53
53
 
54
- expect(variables.env_num).toMatchObject({ value: '300', type: 'text', datatype: 'number' });
55
- expect(typeof variables.env_num.value).toBe('string');
54
+ expect(variables.env_num).toMatchObject({ value: 300, type: 'text', dataType: 'number' });
55
+ expect(typeof variables.env_num.value).toBe('number');
56
56
 
57
- expect(variables.env_bool).toMatchObject({ value: 'true', datatype: 'boolean' });
58
- expect(variables.falsy_num).toMatchObject({ value: '0', datatype: 'number' });
59
- expect(variables.falsy_bool).toMatchObject({ value: 'false', datatype: 'boolean' });
57
+ expect(variables.env_bool).toMatchObject({ value: true, dataType: 'boolean' });
58
+ expect(variables.falsy_num).toMatchObject({ value: 0, dataType: 'number' });
59
+ expect(variables.falsy_bool).toMatchObject({ value: false, dataType: 'boolean' });
60
60
 
61
- expect(variables.env_obj.datatype).toBe('object');
62
- expect(typeof variables.env_obj.value).toBe('string');
63
- expect(variables.env_obj.value).toContain('"scope": "env"');
61
+ expect(variables.env_obj.dataType).toBe('object');
62
+ expect(typeof variables.env_obj.value).toBe('object');
63
+ expect(variables.env_obj.value).toMatchObject({ scope: 'env' });
64
64
 
65
- expect(variables.env_array_obj).toMatchObject({ value: '[1,2,3,4]', datatype: 'object' });
65
+ expect(variables.env_array_obj).toMatchObject({ value: [1, 2, 3, 4], dataType: 'object' });
66
66
  });
67
67
 
68
- it('does not set datatype for plain string values', () => {
68
+ it('does not set dataType for plain string values', () => {
69
69
  const variables = byName(parseEnvironment(ENV_YML));
70
70
 
71
71
  expect(variables.env_str).toMatchObject({ value: 'env_string', type: 'text', secret: false });
72
- expect(variables.env_str).not.toHaveProperty('datatype');
72
+ expect(variables.env_str).not.toHaveProperty('dataType');
73
73
  });
74
74
 
75
- it('parses secret variables with no value or datatype', () => {
75
+ it('parses secret variables with no value or dataType', () => {
76
76
  const variables = byName(parseEnvironment(ENV_YML));
77
77
 
78
78
  expect(variables.env_secret_str).toMatchObject({ name: 'env_secret_str', value: '', secret: true });
79
- expect(variables.env_secret_str).not.toHaveProperty('datatype');
79
+ expect(variables.env_secret_str).not.toHaveProperty('dataType');
80
80
  });
81
81
 
82
- it('parses secret variables with a type, keeping the value empty and the type in datatype', () => {
82
+ it('parses secret variables with a type, keeping the value empty and the type in dataType', () => {
83
83
  const variables = byName(parseEnvironment(ENV_YML));
84
84
 
85
- expect(variables.env_secret_num).toMatchObject({ value: '', secret: true, datatype: 'number' });
86
- expect(variables.env_secret_bool).toMatchObject({ value: '', secret: true, datatype: 'boolean' });
87
- expect(variables.env_secret_obj).toMatchObject({ value: '', secret: true, datatype: 'object' });
85
+ expect(variables.env_secret_num).toMatchObject({ value: '', secret: true, dataType: 'number' });
86
+ expect(variables.env_secret_bool).toMatchObject({ value: '', secret: true, dataType: 'boolean' });
87
+ expect(variables.env_secret_obj).toMatchObject({ value: '', secret: true, dataType: 'object' });
88
88
  });
89
89
 
90
- it('serializes secret variable datatype back to a type field, omitting it for plain secrets', () => {
90
+ it('serializes secret variable dataType back to a type field, omitting it for plain secrets', () => {
91
91
  const yml = stringifyEnvironment(parseEnvironment(ENV_YML));
92
92
 
93
93
  expect(yml).toContain('- secret: true\n name: env_secret_num\n type: number');
@@ -97,19 +97,19 @@ describe('yml parseEnvironment - typed values', () => {
97
97
  expect(yml).not.toContain('name: env_secret_str\n type:');
98
98
  });
99
99
 
100
- it('serializes datatype back to an OpenCollection { type, data } value', () => {
100
+ it('serializes dataType back to an OpenCollection { type, data } value', () => {
101
101
  const yml = stringifyEnvironment(parseEnvironment(ENV_YML));
102
102
 
103
103
  expect(yml).toContain('type: number');
104
104
  expect(yml).toContain('data: "300"');
105
105
  expect(yml).toContain('type: boolean');
106
106
  expect(yml).toContain('type: object');
107
- // plain strings stay plain, never wrapped as a string datatype
107
+ // plain strings stay plain, never wrapped as a string dataType
108
108
  expect(yml).toContain('value: env_string');
109
109
  expect(yml).not.toContain('type: string');
110
110
  });
111
111
 
112
- it('round-trips value and datatype through parse -> stringify -> parse', () => {
112
+ it('round-trips value and dataType through parse -> stringify -> parse', () => {
113
113
  const env = parseEnvironment(ENV_YML);
114
114
  const reparsed = parseEnvironment(stringifyEnvironment(env));
115
115
 
@@ -118,44 +118,5 @@ describe('yml parseEnvironment - typed values', () => {
118
118
  });
119
119
  });
120
120
 
121
- const EXTERNAL_SECRETS_YML = `name: test_env
122
- variables:
123
- - name: env_str
124
- value: env_string
125
- externalSecrets:
126
- type: my-vault
127
- variables:
128
- - name: by_path
129
- path: secret/data/secret
130
- - name: by_secret_name
131
- secretName: secret
132
- - name: by_vault_name
133
- vaultName: secret
134
- `;
135
-
136
- describe('yml parseEnvironment - external secrets', () => {
137
- it('parses externalSecrets, preserving the type and arbitrary variable keys', () => {
138
- const env = parseEnvironment(EXTERNAL_SECRETS_YML);
139
-
140
- expect(env.externalSecrets).toEqual({
141
- type: 'my-vault',
142
- variables: [
143
- { name: 'by_path', path: 'secret/data/secret' },
144
- { name: 'by_secret_name', secretName: 'secret' },
145
- { name: 'by_vault_name', vaultName: 'secret' }
146
- ]
147
- });
148
- });
149
-
150
- it('does not set externalSecrets when the yml has none', () => {
151
- const env = parseEnvironment('name: test_env\nvariables: []\n');
152
- expect(env.externalSecrets).toBeUndefined();
153
- });
154
-
155
- it('round-trips externalSecrets through parse -> stringify -> parse', () => {
156
- const env = parseEnvironment(EXTERNAL_SECRETS_YML);
157
- const reparsed = parseEnvironment(stringifyEnvironment(env));
158
-
159
- expect(reparsed.externalSecrets).toEqual(env.externalSecrets);
160
- });
161
- });
121
+ // External-secrets parsing/serialization is covered in parseEnvironment.spec.ts and
122
+ // stringifyEnvironment.spec.ts against the strict { type, variables } model.
@@ -0,0 +1,160 @@
1
+ import parseEnvironment from '../parseEnvironment';
2
+
3
+ describe('yml env parser', () => {
4
+ it('should parse empty variables', () => {
5
+ const input = `name: test\n`;
6
+
7
+ const output = parseEnvironment(input);
8
+
9
+ expect(output.name).toBe('test');
10
+ expect(output.variables).toEqual([]);
11
+ expect(output.externalSecrets).toBeUndefined();
12
+ expect(output.color).toBeNull();
13
+ });
14
+
15
+ it('should parse multiple regular variables with disabled flag', () => {
16
+ const input = `name: test
17
+ variables:
18
+ - name: url
19
+ value: http://localhost:3000
20
+ - name: port
21
+ value: "3000"
22
+ disabled: true
23
+ `;
24
+
25
+ const output = parseEnvironment(input);
26
+
27
+ expect(output.variables).toHaveLength(2);
28
+ expect(output.variables[0]).toMatchObject({ name: 'url', value: 'http://localhost:3000', enabled: true });
29
+ expect(output.variables[1]).toMatchObject({ name: 'port', value: '3000', enabled: false });
30
+ });
31
+
32
+ it('should parse a secret variable', () => {
33
+ const input = `name: test
34
+ variables:
35
+ - secret: true
36
+ name: token
37
+ `;
38
+
39
+ const output = parseEnvironment(input);
40
+
41
+ expect(output.variables).toHaveLength(1);
42
+ expect(output.variables[0]).toMatchObject({
43
+ name: 'token',
44
+ value: '',
45
+ enabled: true,
46
+ secret: true
47
+ });
48
+ });
49
+
50
+ it('should parse a hashicorp-vault provider block with disabled entries', () => {
51
+ const input = `name: test
52
+ variables:
53
+ - name: url
54
+ value: http://localhost:3000
55
+ externalSecrets:
56
+ type: hashicorp-vault-cloud
57
+ variables:
58
+ - name: cloudSecret
59
+ path: secret/data/cloud
60
+ - name: dbPassword
61
+ path: secret/data/db-password
62
+ disabled: true
63
+ `;
64
+
65
+ const output = parseEnvironment(input);
66
+
67
+ expect(output.variables).toHaveLength(1);
68
+ expect(output.externalSecrets!.type).toBe('hashicorp-vault-cloud');
69
+ expect(output.externalSecrets!.variables).toMatchObject([
70
+ { name: 'cloudSecret', path: 'secret/data/cloud', enabled: true },
71
+ { name: 'dbPassword', path: 'secret/data/db-password', enabled: false }
72
+ ]);
73
+ output.externalSecrets!.variables.forEach((variable: any) => {
74
+ expect(variable.uid).toMatch(/^[a-zA-Z0-9]{21}$/);
75
+ });
76
+ });
77
+
78
+ it('should parse an aws-secrets-manager provider block', () => {
79
+ const input = `name: test
80
+ externalSecrets:
81
+ type: aws-secrets-manager
82
+ variables:
83
+ - name: awsSecret
84
+ secretName: my-aws-secret
85
+ `;
86
+
87
+ const output = parseEnvironment(input);
88
+
89
+ expect(output.externalSecrets!.type).toBe('aws-secrets-manager');
90
+ expect(output.externalSecrets!.variables).toMatchObject([{ name: 'awsSecret', secretName: 'my-aws-secret', enabled: true }]);
91
+ });
92
+
93
+ it('should parse an azure-key-vault provider block', () => {
94
+ const input = `name: test
95
+ externalSecrets:
96
+ type: azure-key-vault
97
+ variables:
98
+ - name: azureSecret
99
+ vaultName: my-key-vault
100
+ `;
101
+
102
+ const output = parseEnvironment(input);
103
+
104
+ expect(output.externalSecrets!.type).toBe('azure-key-vault');
105
+ expect(output.externalSecrets!.variables).toMatchObject([{ name: 'azureSecret', vaultName: 'my-key-vault', enabled: true }]);
106
+ });
107
+
108
+ it('should keep a half-filled row (a name with an empty identifier)', () => {
109
+ const input = `name: test
110
+ externalSecrets:
111
+ type: hashicorp-vault-server
112
+ variables:
113
+ - name: good
114
+ path: secret/data/good
115
+ - name: bad
116
+ path: ''
117
+ `;
118
+
119
+ const output = parseEnvironment(input);
120
+
121
+ expect(output.externalSecrets!.type).toBe('hashicorp-vault-server');
122
+ expect(output.externalSecrets!.variables).toMatchObject([
123
+ { name: 'good', path: 'secret/data/good', enabled: true },
124
+ { name: 'bad', path: '', enabled: true }
125
+ ]);
126
+ });
127
+
128
+ it('should parse a provider block with no variables', () => {
129
+ const input = `name: test
130
+ externalSecrets:
131
+ type: aws-secrets-manager
132
+ `;
133
+
134
+ const output = parseEnvironment(input);
135
+
136
+ expect(output.externalSecrets!.type).toBe('aws-secrets-manager');
137
+ expect(output.externalSecrets!.variables).toEqual([]);
138
+ });
139
+
140
+ it('should drop the block for an unknown provider type', () => {
141
+ const input = `name: test
142
+ externalSecrets:
143
+ type: made-up-provider
144
+ variables:
145
+ - name: x
146
+ path: p/x
147
+ `;
148
+
149
+ const output = parseEnvironment(input);
150
+ expect(output.externalSecrets).toBeUndefined();
151
+ });
152
+
153
+ it('should default name to Untitled Environment when missing', () => {
154
+ const input = `variables:\n - name: foo\n value: bar\n`;
155
+
156
+ const output = parseEnvironment(input);
157
+
158
+ expect(output.name).toBe('Untitled Environment');
159
+ });
160
+ });
@@ -0,0 +1,204 @@
1
+ import stringifyEnvironment from '../stringifyEnvironment';
2
+
3
+ describe('yml env stringifier', () => {
4
+ it('should stringify empty environment', () => {
5
+ const output = stringifyEnvironment({
6
+ uid: 'env1',
7
+ name: 'test',
8
+ variables: [],
9
+ color: null
10
+ } as any);
11
+
12
+ expect(output).toBe('name: test\n');
13
+ });
14
+
15
+ it('should stringify multiple regular variables with disabled flag', () => {
16
+ const output = stringifyEnvironment({
17
+ uid: 'env1',
18
+ name: 'test',
19
+ variables: [
20
+ { uid: 'v1', name: 'url', value: 'http://localhost:3000', type: 'text', enabled: true },
21
+ { uid: 'v2', name: 'port', value: '3000', type: 'text', enabled: false }
22
+ ],
23
+ color: null
24
+ } as any);
25
+
26
+ expect(output).toBe(`name: test
27
+ variables:
28
+ - name: url
29
+ value: http://localhost:3000
30
+ - name: port
31
+ value: "3000"
32
+ disabled: true
33
+ `);
34
+ });
35
+
36
+ it('should stringify secret variables without their values', () => {
37
+ const output = stringifyEnvironment({
38
+ uid: 'env1',
39
+ name: 'test',
40
+ variables: [
41
+ { uid: 'v1', name: 'token', value: 'secret-value-not-persisted', type: 'text', enabled: true, secret: true }
42
+ ],
43
+ color: null
44
+ } as any);
45
+
46
+ expect(output).toBe(`name: test
47
+ variables:
48
+ - secret: true
49
+ name: token
50
+ `);
51
+ });
52
+
53
+ it('should stringify a hashicorp-vault provider block with disabled entries', () => {
54
+ const output = stringifyEnvironment({
55
+ uid: 'env1',
56
+ name: 'test',
57
+ variables: [
58
+ { uid: 'v1', name: 'url', value: 'http://localhost:3000', type: 'text', enabled: true }
59
+ ],
60
+ externalSecrets: {
61
+ type: 'hashicorp-vault-cloud',
62
+ variables: [
63
+ { uid: 'e1', name: 'cloudSecret', path: 'secret/data/cloud', enabled: true },
64
+ { uid: 'e2', name: 'dbPassword', path: 'secret/data/db-password', enabled: false }
65
+ ]
66
+ },
67
+ color: null
68
+ } as any);
69
+
70
+ expect(output).toBe(`name: test
71
+ variables:
72
+ - name: url
73
+ value: http://localhost:3000
74
+ externalSecrets:
75
+ type: hashicorp-vault-cloud
76
+ variables:
77
+ - name: cloudSecret
78
+ path: secret/data/cloud
79
+ - name: dbPassword
80
+ path: secret/data/db-password
81
+ disabled: true
82
+ `);
83
+ });
84
+
85
+ it('should stringify an aws-secrets-manager provider block', () => {
86
+ const output = stringifyEnvironment({
87
+ uid: 'env1',
88
+ name: 'test',
89
+ variables: [],
90
+ externalSecrets: {
91
+ type: 'aws-secrets-manager',
92
+ variables: [
93
+ { uid: 'e1', name: 'awsSecret', secretName: 'my-aws-secret', enabled: true }
94
+ ]
95
+ },
96
+ color: null
97
+ } as any);
98
+
99
+ expect(output).toBe(`name: test
100
+ externalSecrets:
101
+ type: aws-secrets-manager
102
+ variables:
103
+ - name: awsSecret
104
+ secretName: my-aws-secret
105
+ `);
106
+ });
107
+
108
+ it('should stringify an azure-key-vault provider block', () => {
109
+ const output = stringifyEnvironment({
110
+ uid: 'env1',
111
+ name: 'test',
112
+ variables: [],
113
+ externalSecrets: {
114
+ type: 'azure-key-vault',
115
+ variables: [
116
+ { uid: 'e1', name: 'azureSecret', vaultName: 'my-key-vault', enabled: true }
117
+ ]
118
+ },
119
+ color: null
120
+ } as any);
121
+
122
+ expect(output).toBe(`name: test
123
+ externalSecrets:
124
+ type: azure-key-vault
125
+ variables:
126
+ - name: azureSecret
127
+ vaultName: my-key-vault
128
+ `);
129
+ });
130
+
131
+ it('should keep a half-filled row (a name with an empty identifier)', () => {
132
+ const output = stringifyEnvironment({
133
+ uid: 'env1',
134
+ name: 'test',
135
+ variables: [],
136
+ externalSecrets: {
137
+ type: 'hashicorp-vault-server',
138
+ variables: [
139
+ { uid: 'e1', name: 'good', path: 'secret/data/good', enabled: true },
140
+ { uid: 'e2', name: 'bad', path: '', enabled: true }
141
+ ]
142
+ },
143
+ color: null
144
+ } as any);
145
+
146
+ // The half-filled 'bad' row is serialized with an explicit empty identifier, not dropped.
147
+ expect(output).toContain(` - name: good
148
+ path: secret/data/good`);
149
+ expect(output).toContain(` - name: bad
150
+ path: ""`);
151
+ });
152
+
153
+ it('coerces a non-string identifier to a string (matching the parser) instead of dropping it', () => {
154
+ const output = stringifyEnvironment({
155
+ uid: 'env1',
156
+ name: 'test',
157
+ variables: [],
158
+ externalSecrets: {
159
+ type: 'hashicorp-vault-server',
160
+ variables: [{ uid: 'e1', name: 'num', path: 123, enabled: true }]
161
+ },
162
+ color: null
163
+ } as any);
164
+
165
+ // 123 is coerced to '123', not dropped to an empty identifier.
166
+ expect(output).toContain('123');
167
+ expect(output).not.toContain(`- name: num
168
+ path: ""`);
169
+ });
170
+
171
+ it('should emit only the provider block when variables is empty', () => {
172
+ const output = stringifyEnvironment({
173
+ uid: 'env1',
174
+ name: 'test',
175
+ variables: [],
176
+ externalSecrets: {
177
+ type: 'aws-secrets-manager',
178
+ variables: []
179
+ },
180
+ color: null
181
+ } as any);
182
+
183
+ expect(output).toBe(`name: test
184
+ externalSecrets:
185
+ type: aws-secrets-manager
186
+ variables: []
187
+ `);
188
+ });
189
+
190
+ it('should not emit the external-secret section for an unknown provider type', () => {
191
+ const output = stringifyEnvironment({
192
+ uid: 'env1',
193
+ name: 'test',
194
+ variables: [],
195
+ externalSecrets: {
196
+ type: 'made-up-provider',
197
+ variables: [{ uid: 'e1', name: 'x', path: 'p/x', enabled: true }]
198
+ },
199
+ color: null
200
+ } as any);
201
+
202
+ expect(output).toBe('name: test\n');
203
+ });
204
+ });
@@ -1,7 +1,7 @@
1
1
  import { toBrunoVariables, toOpenCollectionVariables } from '../common/variables';
2
2
 
3
3
  describe('yml variables - typed values (collection / folder / request vars)', () => {
4
- it('reads a typed value keeping the value as a string and the type in datatype', () => {
4
+ it('reads a typed value coercing it to its native JS type and records the dataType', () => {
5
5
  const ocVariables = [
6
6
  { name: 'var_str', value: 'plain' },
7
7
  { name: 'var_num', value: { type: 'number', data: '300' } },
@@ -12,16 +12,16 @@ describe('yml variables - typed values (collection / folder / request vars)', ()
12
12
  const { req } = toBrunoVariables(ocVariables);
13
13
 
14
14
  expect(req.find((v) => v.name === 'var_str')).toMatchObject({ value: 'plain' });
15
- expect(req.find((v) => v.name === 'var_str')).not.toHaveProperty('datatype');
16
- expect(req.find((v) => v.name === 'var_num')).toMatchObject({ value: '300', datatype: 'number' });
17
- expect(req.find((v) => v.name === 'var_bool')).toMatchObject({ value: 'false', datatype: 'boolean' });
18
- expect(req.find((v) => v.name === 'var_obj')).toMatchObject({ value: '{"scope":"folder"}', datatype: 'object' });
15
+ expect(req.find((v) => v.name === 'var_str')).not.toHaveProperty('dataType');
16
+ expect(req.find((v) => v.name === 'var_num')).toMatchObject({ value: 300, dataType: 'number' });
17
+ expect(req.find((v) => v.name === 'var_bool')).toMatchObject({ value: false, dataType: 'boolean' });
18
+ expect(req.find((v) => v.name === 'var_obj')).toMatchObject({ value: { scope: 'folder' }, dataType: 'object' });
19
19
  });
20
20
 
21
- it('writes datatype back as a { type, data } value, leaving plain strings untouched', () => {
21
+ it('writes dataType back as a { type, data } value, leaving plain strings untouched', () => {
22
22
  const brunoVariables = [
23
23
  { uid: 'u1', name: 'var_str', value: 'plain', enabled: true, local: false },
24
- { uid: 'u2', name: 'var_num', value: '300', datatype: 'number', enabled: true, local: false }
24
+ { uid: 'u2', name: 'var_num', value: '300', dataType: 'number', enabled: true, local: false }
25
25
  ];
26
26
 
27
27
  const ocVariables = toOpenCollectionVariables(brunoVariables);
package/src/index.ts CHANGED
@@ -27,6 +27,7 @@ import {
27
27
  } from './types';
28
28
  import { DEFAULT_COLLECTION_FORMAT } from './constants';
29
29
  import { bruRequestParseAndRedactBodyData } from './formats/bru/utils/request-parse-and-redact-body-data';
30
+ import { redactLargeBruTextBlocks, restoreRedactedBlocks } from './formats/bru/utils/redact-large-text-blocks';
30
31
 
31
32
  // request
32
33
  export const parseRequest = (content: string, options: ParseOptions = { format: DEFAULT_COLLECTION_FORMAT }): any => {
@@ -135,6 +136,10 @@ export const parseDotEnv = (content: string): Record<string, string> => {
135
136
  return dotenvToJson(content);
136
137
  };
137
138
 
139
+ export { redactLargeBruTextBlocks, restoreRedactedBlocks };
140
+ export type { RedactedBlock, RedactionResult } from './formats/bru/utils/redact-large-text-blocks';
141
+ export { migrateSecretsJsonToEnvironments } from './utils/secretsJsonToEnvironments';
142
+
138
143
  export { BruParserWorker };
139
144
  export * from './types';
140
145
  export * from './constants';
@@ -6,4 +6,5 @@ declare module '@usebruno/lang' {
6
6
  export function collectionBruToJson(bruContent: string): any;
7
7
  export function jsonToCollectionBru(jsonData: any): string;
8
8
  export function dotenvToJson(envContent: string): Record<string, string>;
9
+ export function outdentString(str: string, spaces?: number): string;
9
10
  }
package/src/types.ts CHANGED
@@ -20,3 +20,10 @@ export interface WorkerTask {
20
20
  export interface Lane {
21
21
  maxSize: number;
22
22
  }
23
+
24
+ export interface BrunoPresetsExtension {
25
+ request?: {
26
+ type?: string;
27
+ url?: string;
28
+ };
29
+ }