@apiquest/plugin-vault-file 1.0.4

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.
package/README.md ADDED
@@ -0,0 +1,140 @@
1
+ # @apiquest/plugin-vault-file
2
+
3
+ File-based vault provider plugin for ApiQuest. Provides secure secret storage using encrypted or plain JSON files.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # Using npm
9
+ npm install -g @apiquest/plugin-vault-file
10
+
11
+ # Or using fracture CLI
12
+ fracture plugin install vault-file
13
+ ```
14
+
15
+ ## Features
16
+
17
+ - Read secrets from JSON files
18
+ - AES-256-GCM encryption support
19
+ - Environment variable integration for encryption keys
20
+ - Read-only access (no write operations)
21
+ - Secure key handling from environment variables
22
+
23
+ ## Usage
24
+
25
+ Configure the plugin in your collection's runtime options:
26
+
27
+ ### Plain JSON Vault
28
+
29
+ ```json
30
+ {
31
+ "$schema": "https://apiquest.net/schemas/collection-v1.0.json",
32
+ "protocol": "http",
33
+ "options": {
34
+ "plugins": {
35
+ "vault:file": {
36
+ "filePath": "./secrets.json"
37
+ }
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ **secrets.json:**
44
+ ```json
45
+ {
46
+ "apiKey": "sk_live_abc123",
47
+ "dbPassword": "secret_password",
48
+ "jwtSecret": "my_jwt_secret"
49
+ }
50
+ ```
51
+
52
+ ### Encrypted Vault
53
+
54
+ For encrypted vaults, specify the encryption key from an environment variable:
55
+
56
+ ```json
57
+ {
58
+ "options": {
59
+ "plugins": {
60
+ "vault:file": {
61
+ "filePath": "./secrets.json.enc",
62
+ "key": "VAULT_KEY",
63
+ "source": "env"
64
+ }
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ This reads the encryption key from `process.env.VAULT_KEY`.
71
+
72
+ ### Accessing Vault Secrets
73
+
74
+ Use the `{{$vault:file:secretName}}` syntax in your requests:
75
+
76
+ ```json
77
+ {
78
+ "type": "request",
79
+ "id": "api-call",
80
+ "name": "API Call with Secret",
81
+ "auth": {
82
+ "type": "apikey",
83
+ "apikey": {
84
+ "key": "x-api-key",
85
+ "value": "{{$vault:file:apiKey}}",
86
+ "in": "header"
87
+ }
88
+ }
89
+ }
90
+ ```
91
+
92
+ ### Using in Scripts
93
+
94
+ ```javascript
95
+ // preRequestScript
96
+ const dbPassword = await quest.vault.get('file', 'dbPassword');
97
+ quest.variables.set('password', dbPassword);
98
+
99
+ quest.test('Vault accessible', async () => {
100
+ const secret = await quest.vault.get('file', 'apiKey');
101
+ expect(secret).to.be.a('string');
102
+ });
103
+ ```
104
+
105
+ ## Encryption
106
+
107
+ To create an encrypted vault file, use AES-256-GCM encryption with the following format:
108
+
109
+ ```json
110
+ {
111
+ "_encrypted": "aes-256-gcm",
112
+ "_iv": "base64_initialization_vector",
113
+ "_authTag": "base64_authentication_tag",
114
+ "_data": "base64_encrypted_data"
115
+ }
116
+ ```
117
+
118
+ The plugin automatically detects encrypted files by the presence of the `_encrypted` field.
119
+
120
+ ## Security Best Practices
121
+
122
+ 1. **Never commit unencrypted secrets** to version control
123
+ 2. **Store encryption keys in environment variables**, not in code
124
+ 3. **Use different vault files** for different environments (dev, staging, prod)
125
+ 4. **Rotate secrets regularly** and update vault files
126
+ 5. **Use encrypted vaults** for sensitive production secrets
127
+
128
+ ## Compatibility
129
+
130
+ - **Protocols:** Works with all plugins
131
+ - **Node.js:** Requires Node.js 20+
132
+
133
+ ## Documentation
134
+
135
+ - [Fracture Documentation](https://apiquest.net/docs/fracture)
136
+ - [Schema Reference](https://apiquest.net/schemas/collection-v1.0.json)
137
+
138
+ ## License
139
+
140
+ Dual-licensed under AGPL-3.0-or-later and commercial license. See LICENSE.txt for details.
@@ -0,0 +1,125 @@
1
+ import { IValueProviderPlugin, ValidationResult, ExecutionContext, ILogger } from '@apiquest/types';
2
+ /**
3
+ * Encrypted file format
4
+ */
5
+ interface EncryptedFile {
6
+ _encrypted: 'aes-256-gcm';
7
+ _iv: string;
8
+ _authTag: string;
9
+ _data: string;
10
+ }
11
+ /**
12
+ * File-based Vault Provider Plugin
13
+ * Reads secrets from a JSON file (plain or AES-256-GCM encrypted)
14
+ *
15
+ * Configuration:
16
+ * - filePath: Path to JSON file containing secrets
17
+ * - key: Encryption key or name of environment variable (when source="env")
18
+ * - source: "env" to read key from process.env[key], omit to use key directly
19
+ *
20
+ * Usage - Unencrypted:
21
+ * {
22
+ * "plugins": {
23
+ * "vault:file": {
24
+ * "filePath": "./secrets.json"
25
+ * }
26
+ * }
27
+ * }
28
+ *
29
+ * Usage - Encrypted with env var:
30
+ * {
31
+ * "plugins": {
32
+ * "vault:file": {
33
+ * "filePath": "./secrets.json.enc",
34
+ * "key": "VAULT_KEY",
35
+ * "source": "env"
36
+ * }
37
+ * }
38
+ * }
39
+ *
40
+ * Usage - Encrypted with variable resolution:
41
+ * {
42
+ * "variables": [{"key": "vaultKey", "value": "my-secret"}],
43
+ * "plugins": {
44
+ * "vault:file": {
45
+ * "filePath": "./secrets.json.enc",
46
+ * "key": "{{vaultKey}}"
47
+ * }
48
+ * }
49
+ * }
50
+ *
51
+ * Plain secrets.json format:
52
+ * {
53
+ * "apiKey": "secret-value",
54
+ * "database": {
55
+ * "password": "db-password"
56
+ * }
57
+ * }
58
+ *
59
+ * Encrypted secrets.json.enc format:
60
+ * {
61
+ * "_encrypted": "aes-256-gcm",
62
+ * "_iv": "base64_encoded_iv",
63
+ * "_authTag": "base64_encoded_auth_tag",
64
+ * "_data": "base64_encoded_encrypted_json"
65
+ * }
66
+ *
67
+ * Access nested keys with dot notation: "database.password"
68
+ */
69
+ export declare class FileVaultProvider implements IValueProviderPlugin {
70
+ provider: string;
71
+ name: string;
72
+ description: string;
73
+ configSchema: {
74
+ type: string;
75
+ properties: {
76
+ filePath: {
77
+ type: string;
78
+ description: string;
79
+ };
80
+ key: {
81
+ type: string;
82
+ description: string;
83
+ };
84
+ source: {
85
+ type: string;
86
+ enum: string[];
87
+ description: string;
88
+ };
89
+ };
90
+ required: string[];
91
+ };
92
+ private cache;
93
+ getValue(key: string, config?: unknown, context?: ExecutionContext, logger?: ILogger): Promise<string | null>;
94
+ validate(config?: unknown): ValidationResult;
95
+ /**
96
+ * Resolve the encryption key from config
97
+ * - If source="env", read from process.env[config.key]
98
+ * - Otherwise, use config.key directly
99
+ */
100
+ private resolveEncryptionKey;
101
+ /**
102
+ * Check if data is an encrypted file
103
+ */
104
+ private isEncryptedFile;
105
+ /**
106
+ * Decrypt an encrypted file using AES-256-GCM
107
+ */
108
+ private decryptFile;
109
+ /**
110
+ * Encrypt data to create an encrypted file (utility method for generating encrypted files)
111
+ */
112
+ static encryptData(data: unknown, key: string): EncryptedFile;
113
+ /**
114
+ * Get nested value from object using dot notation
115
+ * Example: getNestedValue({ a: { b: { c: 'value' } } }, 'a.b.c') => 'value'
116
+ */
117
+ private getNestedValue;
118
+ /**
119
+ * Clear the cache (useful for testing or forcing reload)
120
+ */
121
+ clearCache(): void;
122
+ }
123
+ export declare const fileVaultProvider: FileVaultProvider;
124
+ export default fileVaultProvider;
125
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAmB,gBAAgB,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAKrH;;GAEG;AACH,UAAU,aAAa;IACrB,UAAU,EAAE,aAAa,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAWD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,qBAAa,iBAAkB,YAAW,oBAAoB;IAC5D,QAAQ,SAAgB;IACxB,IAAI,SAAyB;IAC7B,WAAW,SAAqE;IAEhF,YAAY;;;;;;;;;;;;;;;;;;MAkBV;IAEF,OAAO,CAAC,KAAK,CAA8B;IAErC,QAAQ,CACZ,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,gBAAgB,EAC1B,MAAM,CAAC,EAAE,OAAO,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA8DzB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,gBAAgB;IAoH5C;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAe5B;;OAEG;IACH,OAAO,CAAC,eAAe;IASvB;;OAEG;IACH,OAAO,CAAC,WAAW;IA4BnB;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa;IA6B7D;;;OAGG;IACH,OAAO,CAAC,cAAc;IAiBtB;;OAEG;IACH,UAAU,IAAI,IAAI;CAGnB;AAGD,eAAO,MAAM,iBAAiB,mBAA0B,CAAC;AAGzD,eAAe,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,357 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as crypto from 'crypto';
4
+
5
+ /**
6
+ * File-based Vault Provider Plugin
7
+ * Reads secrets from a JSON file (plain or AES-256-GCM encrypted)
8
+ *
9
+ * Configuration:
10
+ * - filePath: Path to JSON file containing secrets
11
+ * - key: Encryption key or name of environment variable (when source="env")
12
+ * - source: "env" to read key from process.env[key], omit to use key directly
13
+ *
14
+ * Usage - Unencrypted:
15
+ * {
16
+ * "plugins": {
17
+ * "vault:file": {
18
+ * "filePath": "./secrets.json"
19
+ * }
20
+ * }
21
+ * }
22
+ *
23
+ * Usage - Encrypted with env var:
24
+ * {
25
+ * "plugins": {
26
+ * "vault:file": {
27
+ * "filePath": "./secrets.json.enc",
28
+ * "key": "VAULT_KEY",
29
+ * "source": "env"
30
+ * }
31
+ * }
32
+ * }
33
+ *
34
+ * Usage - Encrypted with variable resolution:
35
+ * {
36
+ * "variables": [{"key": "vaultKey", "value": "my-secret"}],
37
+ * "plugins": {
38
+ * "vault:file": {
39
+ * "filePath": "./secrets.json.enc",
40
+ * "key": "{{vaultKey}}"
41
+ * }
42
+ * }
43
+ * }
44
+ *
45
+ * Plain secrets.json format:
46
+ * {
47
+ * "apiKey": "secret-value",
48
+ * "database": {
49
+ * "password": "db-password"
50
+ * }
51
+ * }
52
+ *
53
+ * Encrypted secrets.json.enc format:
54
+ * {
55
+ * "_encrypted": "aes-256-gcm",
56
+ * "_iv": "base64_encoded_iv",
57
+ * "_authTag": "base64_encoded_auth_tag",
58
+ * "_data": "base64_encoded_encrypted_json"
59
+ * }
60
+ *
61
+ * Access nested keys with dot notation: "database.password"
62
+ */
63
+ class FileVaultProvider {
64
+ provider = 'vault:file';
65
+ name = 'File Vault Provider';
66
+ description = 'Load secrets from a JSON file (supports AES-256-GCM encryption)';
67
+ configSchema = {
68
+ type: 'object',
69
+ properties: {
70
+ filePath: {
71
+ type: 'string',
72
+ description: 'Path to JSON file containing secrets'
73
+ },
74
+ key: {
75
+ type: 'string',
76
+ description: 'Encryption key or environment variable name'
77
+ },
78
+ source: {
79
+ type: 'string',
80
+ enum: ['env'],
81
+ description: 'Set to "env" to read key from process.env'
82
+ }
83
+ },
84
+ required: ['filePath']
85
+ };
86
+ cache = new Map();
87
+ async getValue(key, config, context, logger) {
88
+ if (config === undefined || config === null || typeof config !== 'object') {
89
+ logger?.error('Vault file configuration missing');
90
+ throw new Error('FileVaultProvider: filePath not configured in options.plugins["vault:file"]');
91
+ }
92
+ const configObj = config;
93
+ if (!('filePath' in configObj) || typeof configObj.filePath !== 'string') {
94
+ logger?.error('Vault filePath missing in configuration');
95
+ throw new Error('FileVaultProvider: filePath not configured in options.plugins["vault:file"]');
96
+ }
97
+ const filePath = path.resolve(configObj.filePath);
98
+ const cacheKey = filePath;
99
+ // Cache load
100
+ if (!this.cache.has(cacheKey)) {
101
+ try {
102
+ logger?.debug('Loading vault file', { filePath });
103
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
104
+ const fileData = JSON.parse(fileContent);
105
+ if (this.isEncryptedFile(fileData)) {
106
+ const encryptionKey = this.resolveEncryptionKey(configObj);
107
+ if (encryptionKey === null || encryptionKey === undefined || encryptionKey === '') {
108
+ logger?.error('Encrypted vault file missing encryption key');
109
+ throw new Error('FileVaultProvider: Encrypted vault file requires encryption key (config.key)');
110
+ }
111
+ const decrypted = this.decryptFile(fileData, encryptionKey);
112
+ this.cache.set(cacheKey, decrypted);
113
+ logger?.debug('Encrypted vault file decrypted and cached');
114
+ }
115
+ else {
116
+ this.cache.set(cacheKey, fileData);
117
+ logger?.debug('Vault file cached');
118
+ }
119
+ }
120
+ catch (error) {
121
+ if (error !== null && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
122
+ logger?.error('Vault file not found', { filePath });
123
+ throw new Error(`FileVaultProvider: Vault file not found: ${filePath}`);
124
+ }
125
+ if (error instanceof SyntaxError) {
126
+ logger?.error('Vault file JSON parsing failed', { filePath });
127
+ throw new Error(`FileVaultProvider: Invalid JSON in vault file: ${filePath}`);
128
+ }
129
+ throw error;
130
+ }
131
+ }
132
+ const secrets = this.cache.get(cacheKey);
133
+ const value = this.getNestedValue(secrets, key);
134
+ if (value === undefined) {
135
+ logger?.trace('Vault key not found', { key });
136
+ return null;
137
+ }
138
+ logger?.trace('Vault key resolved', { key });
139
+ return String(value);
140
+ }
141
+ validate(config) {
142
+ if (config === undefined || config === null) {
143
+ return {
144
+ valid: false,
145
+ errors: [{
146
+ message: 'Configuration required: must specify filePath',
147
+ location: '',
148
+ source: 'vault'
149
+ }]
150
+ };
151
+ }
152
+ // Type guard to check if config is an object and has filePath
153
+ if (typeof config !== 'object' || config === null) {
154
+ return {
155
+ valid: false,
156
+ errors: [{
157
+ message: 'Configuration must be an object',
158
+ location: '',
159
+ source: 'vault'
160
+ }]
161
+ };
162
+ }
163
+ const configObj = config;
164
+ if (!('filePath' in configObj) || configObj.filePath === undefined || configObj.filePath === null) {
165
+ return {
166
+ valid: false,
167
+ errors: [{
168
+ message: 'filePath is required in configuration',
169
+ location: '',
170
+ source: 'vault'
171
+ }]
172
+ };
173
+ }
174
+ if (typeof configObj.filePath !== 'string') {
175
+ return {
176
+ valid: false,
177
+ errors: [{
178
+ message: 'filePath must be a string',
179
+ location: '',
180
+ source: 'vault'
181
+ }]
182
+ };
183
+ }
184
+ // Check if file exists
185
+ const filePath = path.resolve(configObj.filePath);
186
+ if (!fs.existsSync(filePath)) {
187
+ return {
188
+ valid: false,
189
+ errors: [{
190
+ message: `Vault file not found: ${filePath}`,
191
+ location: '',
192
+ source: 'vault'
193
+ }]
194
+ };
195
+ }
196
+ // Try to parse JSON and check encryption
197
+ try {
198
+ const content = fs.readFileSync(filePath, 'utf-8');
199
+ const data = JSON.parse(content);
200
+ // If file is encrypted, validate we have a key
201
+ if (this.isEncryptedFile(data)) {
202
+ const vaultConfig = {
203
+ filePath: String(configObj.filePath),
204
+ key: typeof configObj.key === 'string' ? configObj.key : undefined,
205
+ source: configObj.source === 'env' ? 'env' : undefined
206
+ };
207
+ const encryptionKey = this.resolveEncryptionKey(vaultConfig);
208
+ if (encryptionKey === null || encryptionKey === undefined || encryptionKey === '') {
209
+ return {
210
+ valid: false,
211
+ errors: [{
212
+ message: 'Encrypted vault file requires encryption key (config.key)',
213
+ location: '',
214
+ source: 'vault'
215
+ }]
216
+ };
217
+ }
218
+ // Try to decrypt to validate key
219
+ try {
220
+ this.decryptFile(data, encryptionKey);
221
+ }
222
+ catch (decryptError) {
223
+ const errorMessage = decryptError instanceof Error ? decryptError.message : 'Decryption failed';
224
+ return {
225
+ valid: false,
226
+ errors: [{
227
+ message: `Failed to decrypt vault file: ${errorMessage}`,
228
+ location: '',
229
+ source: 'vault'
230
+ }]
231
+ };
232
+ }
233
+ }
234
+ }
235
+ catch (error) {
236
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
237
+ return {
238
+ valid: false,
239
+ errors: [{
240
+ message: `Invalid JSON in vault file: ${errorMessage}`,
241
+ location: '',
242
+ source: 'vault'
243
+ }]
244
+ };
245
+ }
246
+ return { valid: true };
247
+ }
248
+ /**
249
+ * Resolve the encryption key from config
250
+ * - If source="env", read from process.env[config.key]
251
+ * - Otherwise, use config.key directly
252
+ */
253
+ resolveEncryptionKey(config) {
254
+ if (config.key === undefined || config.key === null || config.key === '') {
255
+ return null;
256
+ }
257
+ if (config.source === 'env') {
258
+ // Read from environment variable
259
+ const envValue = process.env[config.key];
260
+ return envValue ?? null;
261
+ }
262
+ // Use key directly (could be resolved variable like {{vaultKey}})
263
+ return config.key;
264
+ }
265
+ /**
266
+ * Check if data is an encrypted file
267
+ */
268
+ isEncryptedFile(data) {
269
+ if (typeof data !== 'object' || data === null) {
270
+ return false;
271
+ }
272
+ const obj = data;
273
+ return '_encrypted' in obj && obj._encrypted === 'aes-256-gcm';
274
+ }
275
+ /**
276
+ * Decrypt an encrypted file using AES-256-GCM
277
+ */
278
+ decryptFile(encryptedFile, key) {
279
+ try {
280
+ // Derive a 32-byte key from the provided key using SHA-256
281
+ const keyBuffer = crypto.createHash('sha256').update(key).digest();
282
+ // Decode base64 values
283
+ const iv = Buffer.from(encryptedFile._iv, 'base64');
284
+ const authTag = Buffer.from(encryptedFile._authTag, 'base64');
285
+ const encryptedData = Buffer.from(encryptedFile._data, 'base64');
286
+ // Create decipher
287
+ const decipher = crypto.createDecipheriv('aes-256-gcm', keyBuffer, iv);
288
+ decipher.setAuthTag(authTag);
289
+ // Decrypt
290
+ const decrypted = Buffer.concat([
291
+ decipher.update(encryptedData),
292
+ decipher.final()
293
+ ]);
294
+ // Parse JSON
295
+ return JSON.parse(decrypted.toString('utf-8'));
296
+ }
297
+ catch (error) {
298
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
299
+ throw new Error(`Failed to decrypt vault file: ${errorMessage}`);
300
+ }
301
+ }
302
+ /**
303
+ * Encrypt data to create an encrypted file (utility method for generating encrypted files)
304
+ */
305
+ static encryptData(data, key) {
306
+ // Derive a 32-byte key from the provided key using SHA-256
307
+ const keyBuffer = crypto.createHash('sha256').update(key).digest();
308
+ // Generate random IV (12 bytes for GCM)
309
+ const iv = crypto.randomBytes(12);
310
+ // Create cipher
311
+ const cipher = crypto.createCipheriv('aes-256-gcm', keyBuffer, iv);
312
+ // Encrypt
313
+ const jsonData = JSON.stringify(data);
314
+ const encrypted = Buffer.concat([
315
+ cipher.update(jsonData, 'utf-8'),
316
+ cipher.final()
317
+ ]);
318
+ // Get auth tag
319
+ const authTag = cipher.getAuthTag();
320
+ // Return encrypted file format
321
+ return {
322
+ _encrypted: 'aes-256-gcm',
323
+ _iv: iv.toString('base64'),
324
+ _authTag: authTag.toString('base64'),
325
+ _data: encrypted.toString('base64')
326
+ };
327
+ }
328
+ /**
329
+ * Get nested value from object using dot notation
330
+ * Example: getNestedValue({ a: { b: { c: 'value' } } }, 'a.b.c') => 'value'
331
+ */
332
+ getNestedValue(obj, key) {
333
+ const keys = key.split('.');
334
+ let current = obj;
335
+ for (const k of keys) {
336
+ if (current === null || current === undefined) {
337
+ return undefined;
338
+ }
339
+ if (typeof current !== 'object') {
340
+ return undefined;
341
+ }
342
+ current = current[k];
343
+ }
344
+ return current;
345
+ }
346
+ /**
347
+ * Clear the cache (useful for testing or forcing reload)
348
+ */
349
+ clearCache() {
350
+ this.cache.clear();
351
+ }
352
+ }
353
+ // Export singleton instance
354
+ const fileVaultProvider = new FileVaultProvider();
355
+
356
+ export { FileVaultProvider, fileVaultProvider as default, fileVaultProvider };
357
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@apiquest/plugin-vault-file",
3
+ "version": "1.0.4",
4
+ "description": "File-based vault provider plugin for ApiQuest (JSON, readonly)",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/hh-apiquest/fracture.git",
11
+ "directory": "packages/plugin-vault-file"
12
+ },
13
+ "scripts": {
14
+ "build": "rollup -c && tsc --emitDeclarationOnly",
15
+ "dev": "rollup -c --watch",
16
+ "test": "vitest"
17
+ },
18
+ "keywords": [
19
+ "apiquest",
20
+ "vault",
21
+ "secrets",
22
+ "plugin",
23
+ "file"
24
+ ],
25
+ "author": "ApiQuest",
26
+ "license": "AGPL-3.0-or-later",
27
+ "apiquest": {
28
+ "type": "value",
29
+ "runtime": [
30
+ "fracture"
31
+ ],
32
+ "capabilities": {
33
+ "provides": {
34
+ "provider": "file"
35
+ }
36
+ }
37
+ },
38
+ "dependencies": {
39
+ "@apiquest/types": "workspace:*"
40
+ },
41
+ "devDependencies": {
42
+ "@apiquest/types": "workspace:*",
43
+ "@rollup/plugin-commonjs": "^29.0.0",
44
+ "@rollup/plugin-node-resolve": "^16.0.3",
45
+ "@rollup/plugin-typescript": "^12.3.0",
46
+ "@types/node": "^25.2.3",
47
+ "rollup": "^4.57.1",
48
+ "typescript": "^5.3.3",
49
+ "vitest": "^4.0.18"
50
+ },
51
+ "peerDependencies": {
52
+ "@apiquest/types": "^1.0.0"
53
+ }
54
+ }