keyenv 0.1.0 → 1.1.1
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 +19 -0
- package/dist/index.d.mts +154 -4
- package/dist/index.d.ts +154 -4
- package/dist/index.js +207 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +207 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -40,20 +40,28 @@ var KeyEnvError = class extends Error {
|
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
// src/client.ts
|
|
43
|
-
var
|
|
43
|
+
var DEFAULT_BASE_URL = "https://api.keyenv.dev";
|
|
44
44
|
var DEFAULT_TIMEOUT = 3e4;
|
|
45
|
+
function getCacheKey(projectId, environment) {
|
|
46
|
+
return `${projectId}:${environment}`;
|
|
47
|
+
}
|
|
45
48
|
var KeyEnv = class {
|
|
46
49
|
token;
|
|
50
|
+
baseUrl;
|
|
47
51
|
timeout;
|
|
52
|
+
cacheTtl;
|
|
53
|
+
secretsCache = /* @__PURE__ */ new Map();
|
|
48
54
|
constructor(options) {
|
|
49
55
|
if (!options.token) {
|
|
50
56
|
throw new Error("KeyEnv token is required");
|
|
51
57
|
}
|
|
52
58
|
this.token = options.token;
|
|
59
|
+
this.baseUrl = (options.baseUrl ?? process.env.KEYENV_API_URL ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
53
60
|
this.timeout = options.timeout || DEFAULT_TIMEOUT;
|
|
61
|
+
this.cacheTtl = options.cacheTtl ?? (process.env.KEYENV_CACHE_TTL ? parseInt(process.env.KEYENV_CACHE_TTL, 10) : 0);
|
|
54
62
|
}
|
|
55
63
|
async request(method, path, body) {
|
|
56
|
-
const url = `${
|
|
64
|
+
const url = `${this.baseUrl}${path}`;
|
|
57
65
|
const controller = new AbortController();
|
|
58
66
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
59
67
|
try {
|
|
@@ -92,7 +100,8 @@ var KeyEnv = class {
|
|
|
92
100
|
}
|
|
93
101
|
/** Get the current user or service token info */
|
|
94
102
|
async getCurrentUser() {
|
|
95
|
-
|
|
103
|
+
const response = await this.request("GET", "/api/v1/users/me");
|
|
104
|
+
return response.data;
|
|
96
105
|
}
|
|
97
106
|
/** Validate the token and return user info */
|
|
98
107
|
async validateToken() {
|
|
@@ -101,15 +110,17 @@ var KeyEnv = class {
|
|
|
101
110
|
/** List all accessible projects */
|
|
102
111
|
async listProjects() {
|
|
103
112
|
const response = await this.request("GET", "/api/v1/projects");
|
|
104
|
-
return response.
|
|
113
|
+
return response.data;
|
|
105
114
|
}
|
|
106
115
|
/** Get a project by ID */
|
|
107
116
|
async getProject(projectId) {
|
|
108
|
-
|
|
117
|
+
const response = await this.request("GET", `/api/v1/projects/${projectId}`);
|
|
118
|
+
return response.data;
|
|
109
119
|
}
|
|
110
120
|
/** Create a new project */
|
|
111
121
|
async createProject(teamId, name) {
|
|
112
|
-
|
|
122
|
+
const response = await this.request("POST", "/api/v1/projects", { team_id: teamId, name });
|
|
123
|
+
return response.data;
|
|
113
124
|
}
|
|
114
125
|
/** Delete a project */
|
|
115
126
|
async deleteProject(projectId) {
|
|
@@ -121,15 +132,16 @@ var KeyEnv = class {
|
|
|
121
132
|
"GET",
|
|
122
133
|
`/api/v1/projects/${projectId}/environments`
|
|
123
134
|
);
|
|
124
|
-
return response.
|
|
135
|
+
return response.data;
|
|
125
136
|
}
|
|
126
137
|
/** Create a new environment */
|
|
127
138
|
async createEnvironment(projectId, name, inheritsFrom) {
|
|
128
|
-
|
|
139
|
+
const response = await this.request(
|
|
129
140
|
"POST",
|
|
130
141
|
`/api/v1/projects/${projectId}/environments`,
|
|
131
142
|
{ name, inherits_from: inheritsFrom }
|
|
132
143
|
);
|
|
144
|
+
return response.data;
|
|
133
145
|
}
|
|
134
146
|
/** Delete an environment */
|
|
135
147
|
async deleteEnvironment(projectId, environment) {
|
|
@@ -141,10 +153,11 @@ var KeyEnv = class {
|
|
|
141
153
|
"GET",
|
|
142
154
|
`/api/v1/projects/${projectId}/environments/${environment}/secrets`
|
|
143
155
|
);
|
|
144
|
-
return response.
|
|
156
|
+
return response.data;
|
|
145
157
|
}
|
|
146
158
|
/**
|
|
147
|
-
* Export all secrets with their decrypted values
|
|
159
|
+
* Export all secrets with their decrypted values.
|
|
160
|
+
* Results are cached when cacheTtl > 0.
|
|
148
161
|
* @example
|
|
149
162
|
* ```ts
|
|
150
163
|
* const secrets = await client.exportSecrets('project-id', 'production');
|
|
@@ -154,11 +167,27 @@ var KeyEnv = class {
|
|
|
154
167
|
* ```
|
|
155
168
|
*/
|
|
156
169
|
async exportSecrets(projectId, environment) {
|
|
170
|
+
const cacheKey = getCacheKey(projectId, environment);
|
|
171
|
+
if (this.cacheTtl > 0) {
|
|
172
|
+
const cached = this.secretsCache.get(cacheKey);
|
|
173
|
+
if (cached && Date.now() < cached.expiresAt) {
|
|
174
|
+
return cached.secrets;
|
|
175
|
+
}
|
|
176
|
+
if (cached) {
|
|
177
|
+
this.secretsCache.delete(cacheKey);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
157
180
|
const response = await this.request(
|
|
158
181
|
"GET",
|
|
159
182
|
`/api/v1/projects/${projectId}/environments/${environment}/secrets/export`
|
|
160
183
|
);
|
|
161
|
-
|
|
184
|
+
if (this.cacheTtl > 0) {
|
|
185
|
+
this.secretsCache.set(cacheKey, {
|
|
186
|
+
secrets: response.data,
|
|
187
|
+
expiresAt: Date.now() + this.cacheTtl * 1e3
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return response.data;
|
|
162
191
|
}
|
|
163
192
|
/**
|
|
164
193
|
* Export secrets as a key-value object
|
|
@@ -178,7 +207,7 @@ var KeyEnv = class {
|
|
|
178
207
|
"GET",
|
|
179
208
|
`/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`
|
|
180
209
|
);
|
|
181
|
-
return response.
|
|
210
|
+
return response.data;
|
|
182
211
|
}
|
|
183
212
|
/** Create a new secret */
|
|
184
213
|
async createSecret(projectId, environment, key, value, description) {
|
|
@@ -187,7 +216,8 @@ var KeyEnv = class {
|
|
|
187
216
|
`/api/v1/projects/${projectId}/environments/${environment}/secrets`,
|
|
188
217
|
{ key, value, description }
|
|
189
218
|
);
|
|
190
|
-
|
|
219
|
+
this.clearCache(projectId, environment);
|
|
220
|
+
return response.data;
|
|
191
221
|
}
|
|
192
222
|
/** Update a secret's value */
|
|
193
223
|
async updateSecret(projectId, environment, key, value, description) {
|
|
@@ -196,7 +226,8 @@ var KeyEnv = class {
|
|
|
196
226
|
`/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`,
|
|
197
227
|
{ value, description }
|
|
198
228
|
);
|
|
199
|
-
|
|
229
|
+
this.clearCache(projectId, environment);
|
|
230
|
+
return response.data;
|
|
200
231
|
}
|
|
201
232
|
/** Set a secret (create or update) */
|
|
202
233
|
async setSecret(projectId, environment, key, value, description) {
|
|
@@ -215,6 +246,7 @@ var KeyEnv = class {
|
|
|
215
246
|
"DELETE",
|
|
216
247
|
`/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`
|
|
217
248
|
);
|
|
249
|
+
this.clearCache(projectId, environment);
|
|
218
250
|
}
|
|
219
251
|
/** Get secret version history */
|
|
220
252
|
async getSecretHistory(projectId, environment, key) {
|
|
@@ -222,7 +254,7 @@ var KeyEnv = class {
|
|
|
222
254
|
"GET",
|
|
223
255
|
`/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}/history`
|
|
224
256
|
);
|
|
225
|
-
return response.
|
|
257
|
+
return response.data;
|
|
226
258
|
}
|
|
227
259
|
/**
|
|
228
260
|
* Bulk import secrets
|
|
@@ -235,11 +267,13 @@ var KeyEnv = class {
|
|
|
235
267
|
* ```
|
|
236
268
|
*/
|
|
237
269
|
async bulkImport(projectId, environment, secrets, options = {}) {
|
|
238
|
-
|
|
270
|
+
const response = await this.request(
|
|
239
271
|
"POST",
|
|
240
272
|
`/api/v1/projects/${projectId}/environments/${environment}/secrets/bulk`,
|
|
241
273
|
{ secrets, overwrite: options.overwrite ?? false }
|
|
242
274
|
);
|
|
275
|
+
this.clearCache(projectId, environment);
|
|
276
|
+
return response.data;
|
|
243
277
|
}
|
|
244
278
|
/**
|
|
245
279
|
* Load secrets into process.env
|
|
@@ -267,8 +301,8 @@ var KeyEnv = class {
|
|
|
267
301
|
];
|
|
268
302
|
for (const secret of secrets) {
|
|
269
303
|
const value = secret.value;
|
|
270
|
-
if (value.includes("\n") || value.includes('"') || value.includes("'") || value.includes(" ")) {
|
|
271
|
-
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
304
|
+
if (value.includes("\n") || value.includes('"') || value.includes("'") || value.includes(" ") || value.includes("$")) {
|
|
305
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\$/g, "\\$");
|
|
272
306
|
lines.push(`${secret.key}="${escaped}"`);
|
|
273
307
|
} else {
|
|
274
308
|
lines.push(`${secret.key}=${value}`);
|
|
@@ -276,6 +310,161 @@ var KeyEnv = class {
|
|
|
276
310
|
}
|
|
277
311
|
return lines.join("\n") + "\n";
|
|
278
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* Clear the secrets cache.
|
|
315
|
+
* @param projectId - Clear cache for specific project (optional)
|
|
316
|
+
* @param environment - Clear cache for specific environment (requires projectId)
|
|
317
|
+
*/
|
|
318
|
+
clearCache(projectId, environment) {
|
|
319
|
+
if (projectId && environment) {
|
|
320
|
+
this.secretsCache.delete(getCacheKey(projectId, environment));
|
|
321
|
+
} else if (projectId) {
|
|
322
|
+
for (const key of this.secretsCache.keys()) {
|
|
323
|
+
if (key.startsWith(`${projectId}:`)) {
|
|
324
|
+
this.secretsCache.delete(key);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
} else {
|
|
328
|
+
this.secretsCache.clear();
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
// ============================================================================
|
|
332
|
+
// Environment Permission Management
|
|
333
|
+
// ============================================================================
|
|
334
|
+
/**
|
|
335
|
+
* List all permissions for an environment.
|
|
336
|
+
* @param projectId - The project ID
|
|
337
|
+
* @param environment - The environment name
|
|
338
|
+
* @returns Array of environment permissions
|
|
339
|
+
* @example
|
|
340
|
+
* ```ts
|
|
341
|
+
* const permissions = await client.listPermissions('project-id', 'production');
|
|
342
|
+
* for (const perm of permissions) {
|
|
343
|
+
* console.log(`${perm.user_email}: ${perm.role}`);
|
|
344
|
+
* }
|
|
345
|
+
* ```
|
|
346
|
+
*/
|
|
347
|
+
async listPermissions(projectId, environment) {
|
|
348
|
+
const response = await this.request(
|
|
349
|
+
"GET",
|
|
350
|
+
`/api/v1/projects/${projectId}/environments/${environment}/permissions`
|
|
351
|
+
);
|
|
352
|
+
return response.data;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Set a user's permission for an environment.
|
|
356
|
+
* @param projectId - The project ID
|
|
357
|
+
* @param environment - The environment name
|
|
358
|
+
* @param userId - The user ID to set permission for
|
|
359
|
+
* @param role - The permission role ('none', 'read', 'write', or 'admin')
|
|
360
|
+
* @returns The created or updated permission
|
|
361
|
+
* @example
|
|
362
|
+
* ```ts
|
|
363
|
+
* const permission = await client.setPermission('project-id', 'production', 'user-id', 'write');
|
|
364
|
+
* console.log(`Set ${permission.user_email} to ${permission.role}`);
|
|
365
|
+
* ```
|
|
366
|
+
*/
|
|
367
|
+
async setPermission(projectId, environment, userId, role) {
|
|
368
|
+
const response = await this.request(
|
|
369
|
+
"PUT",
|
|
370
|
+
`/api/v1/projects/${projectId}/environments/${environment}/permissions/${userId}`,
|
|
371
|
+
{ role }
|
|
372
|
+
);
|
|
373
|
+
return response.data;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Delete a user's permission for an environment.
|
|
377
|
+
* @param projectId - The project ID
|
|
378
|
+
* @param environment - The environment name
|
|
379
|
+
* @param userId - The user ID to delete permission for
|
|
380
|
+
* @example
|
|
381
|
+
* ```ts
|
|
382
|
+
* await client.deletePermission('project-id', 'production', 'user-id');
|
|
383
|
+
* ```
|
|
384
|
+
*/
|
|
385
|
+
async deletePermission(projectId, environment, userId) {
|
|
386
|
+
await this.request(
|
|
387
|
+
"DELETE",
|
|
388
|
+
`/api/v1/projects/${projectId}/environments/${environment}/permissions/${userId}`
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Bulk set permissions for multiple users in an environment.
|
|
393
|
+
* @param projectId - The project ID
|
|
394
|
+
* @param environment - The environment name
|
|
395
|
+
* @param permissions - Array of user permissions to set
|
|
396
|
+
* @returns Array of created or updated permissions
|
|
397
|
+
* @example
|
|
398
|
+
* ```ts
|
|
399
|
+
* const permissions = await client.bulkSetPermissions('project-id', 'production', [
|
|
400
|
+
* { userId: 'user-1', role: 'write' },
|
|
401
|
+
* { userId: 'user-2', role: 'read' },
|
|
402
|
+
* ]);
|
|
403
|
+
* ```
|
|
404
|
+
*/
|
|
405
|
+
async bulkSetPermissions(projectId, environment, permissions) {
|
|
406
|
+
const response = await this.request(
|
|
407
|
+
"PUT",
|
|
408
|
+
`/api/v1/projects/${projectId}/environments/${environment}/permissions`,
|
|
409
|
+
{ permissions: permissions.map((p) => ({ user_id: p.userId, role: p.role })) }
|
|
410
|
+
);
|
|
411
|
+
return response.data;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Get the current user's permissions for all environments in a project.
|
|
415
|
+
* @param projectId - The project ID
|
|
416
|
+
* @returns The user's permissions and team admin status
|
|
417
|
+
* @example
|
|
418
|
+
* ```ts
|
|
419
|
+
* const { permissions, is_team_admin } = await client.getMyPermissions('project-id');
|
|
420
|
+
* for (const perm of permissions) {
|
|
421
|
+
* console.log(`${perm.environment_name}: ${perm.role} (can_write: ${perm.can_write})`);
|
|
422
|
+
* }
|
|
423
|
+
* ```
|
|
424
|
+
*/
|
|
425
|
+
async getMyPermissions(projectId) {
|
|
426
|
+
return this.request("GET", `/api/v1/projects/${projectId}/my-permissions`);
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Get default permission settings for a project's environments.
|
|
430
|
+
* @param projectId - The project ID
|
|
431
|
+
* @returns Array of project default permissions
|
|
432
|
+
* @example
|
|
433
|
+
* ```ts
|
|
434
|
+
* const defaults = await client.getProjectDefaults('project-id');
|
|
435
|
+
* for (const def of defaults) {
|
|
436
|
+
* console.log(`${def.environment_name}: ${def.default_role}`);
|
|
437
|
+
* }
|
|
438
|
+
* ```
|
|
439
|
+
*/
|
|
440
|
+
async getProjectDefaults(projectId) {
|
|
441
|
+
const response = await this.request(
|
|
442
|
+
"GET",
|
|
443
|
+
`/api/v1/projects/${projectId}/permissions/defaults`
|
|
444
|
+
);
|
|
445
|
+
return response.data;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Set default permission settings for a project's environments.
|
|
449
|
+
* @param projectId - The project ID
|
|
450
|
+
* @param defaults - Array of default permissions to set
|
|
451
|
+
* @returns Array of updated project default permissions
|
|
452
|
+
* @example
|
|
453
|
+
* ```ts
|
|
454
|
+
* const defaults = await client.setProjectDefaults('project-id', [
|
|
455
|
+
* { environmentName: 'development', defaultRole: 'write' },
|
|
456
|
+
* { environmentName: 'production', defaultRole: 'read' },
|
|
457
|
+
* ]);
|
|
458
|
+
* ```
|
|
459
|
+
*/
|
|
460
|
+
async setProjectDefaults(projectId, defaults) {
|
|
461
|
+
const response = await this.request(
|
|
462
|
+
"PUT",
|
|
463
|
+
`/api/v1/projects/${projectId}/permissions/defaults`,
|
|
464
|
+
{ defaults: defaults.map((d) => ({ environment_name: d.environmentName, default_role: d.defaultRole })) }
|
|
465
|
+
);
|
|
466
|
+
return response.data;
|
|
467
|
+
}
|
|
279
468
|
};
|
|
280
469
|
// Annotate the CommonJS export names for ESM import in node:
|
|
281
470
|
0 && (module.exports = {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/client.ts"],"sourcesContent":["export { KeyEnv } from './client.js';\nexport { KeyEnvError } from './types.js';\nexport type {\n KeyEnvOptions,\n User,\n Project,\n ProjectWithEnvironments,\n Environment,\n Secret,\n SecretWithValue,\n SecretHistory,\n BulkSecretItem,\n BulkImportResult,\n} from './types.js';\n","/** KeyEnv client configuration options */\nexport interface KeyEnvOptions {\n /** Service token for authentication */\n token: string;\n /** Request timeout in milliseconds (default: 30000) */\n timeout?: number;\n}\n\n/** User or service token info */\nexport interface User {\n id: string;\n email?: string;\n name?: string;\n clerk_id?: string;\n avatar_url?: string;\n /** Present for service tokens */\n auth_type?: 'service_token' | 'user';\n /** Team ID (for service tokens) */\n team_id?: string;\n /** Project ID (for project-scoped service tokens) */\n project_id?: string;\n /** Token scopes (for service tokens) */\n scopes?: string[];\n created_at: string;\n}\n\n/** Project */\nexport interface Project {\n id: string;\n team_id: string;\n name: string;\n slug: string;\n description?: string;\n created_at: string;\n}\n\n/** Environment */\nexport interface Environment {\n id: string;\n project_id: string;\n name: string;\n inherits_from?: string;\n created_at: string;\n}\n\n/** Project with environments */\nexport interface ProjectWithEnvironments extends Project {\n environments: Environment[];\n}\n\n/** Secret (without value) */\nexport interface Secret {\n id: string;\n environment_id: string;\n key: string;\n type: string;\n description?: string;\n version: number;\n created_at: string;\n updated_at: string;\n}\n\n/** Secret with decrypted value */\nexport interface SecretWithValue extends Secret {\n value: string;\n inherited_from?: string;\n}\n\n/** Secret history entry */\nexport interface SecretHistory {\n id: string;\n secret_id: string;\n value: string;\n version: number;\n changed_by?: string;\n changed_at: string;\n}\n\n/** Bulk import request item */\nexport interface BulkSecretItem {\n key: string;\n value: string;\n description?: string;\n}\n\n/** Bulk import result */\nexport interface BulkImportResult {\n created: number;\n updated: number;\n skipped: number;\n}\n\n/** API error response */\nexport interface ApiError {\n error: string;\n code?: string;\n details?: Record<string, unknown>;\n}\n\n/** KeyEnv API error */\nexport class KeyEnvError extends Error {\n public readonly status: number;\n public readonly code?: string;\n public readonly details?: Record<string, unknown>;\n\n constructor(message: string, status: number, code?: string, details?: Record<string, unknown>) {\n super(message);\n this.name = 'KeyEnvError';\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n","import type {\n KeyEnvOptions,\n User,\n Project,\n ProjectWithEnvironments,\n Environment,\n Secret,\n SecretWithValue,\n SecretHistory,\n BulkSecretItem,\n BulkImportResult,\n ApiError,\n} from './types.js';\nimport { KeyEnvError } from './types.js';\n\nconst BASE_URL = 'https://api.keyenv.dev';\nconst DEFAULT_TIMEOUT = 30000;\n\n/**\n * KeyEnv API client for managing secrets\n *\n * @example\n * ```ts\n * import { KeyEnv } from 'keyenv';\n *\n * const client = new KeyEnv({ token: process.env.KEYENV_TOKEN });\n *\n * // Export all secrets for an environment\n * const secrets = await client.exportSecrets('project-id', 'production');\n * ```\n */\nexport class KeyEnv {\n private readonly token: string;\n private readonly timeout: number;\n\n constructor(options: KeyEnvOptions) {\n if (!options.token) {\n throw new Error('KeyEnv token is required');\n }\n this.token = options.token;\n this.timeout = options.timeout || DEFAULT_TIMEOUT;\n }\n\n private async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${BASE_URL}${path}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n 'User-Agent': 'keyenv-node/1.0.0',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n let errorData: ApiError = { error: 'Unknown error' };\n try {\n errorData = await response.json() as ApiError;\n } catch {\n errorData = { error: response.statusText };\n }\n throw new KeyEnvError(errorData.error, response.status, errorData.code, errorData.details);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return response.json() as Promise<T>;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof KeyEnvError) throw error;\n if (error instanceof Error && error.name === 'AbortError') {\n throw new KeyEnvError('Request timeout', 408);\n }\n throw new KeyEnvError(error instanceof Error ? error.message : 'Network error', 0);\n }\n }\n\n /** Get the current user or service token info */\n async getCurrentUser(): Promise<User> {\n return this.request<User>('GET', '/api/v1/users/me');\n }\n\n /** Validate the token and return user info */\n async validateToken(): Promise<User> {\n return this.getCurrentUser();\n }\n\n /** List all accessible projects */\n async listProjects(): Promise<Project[]> {\n const response = await this.request<{ projects: Project[] }>('GET', '/api/v1/projects');\n return response.projects;\n }\n\n /** Get a project by ID */\n async getProject(projectId: string): Promise<ProjectWithEnvironments> {\n return this.request<ProjectWithEnvironments>('GET', `/api/v1/projects/${projectId}`);\n }\n\n /** Create a new project */\n async createProject(teamId: string, name: string): Promise<Project> {\n return this.request<Project>('POST', '/api/v1/projects', { team_id: teamId, name });\n }\n\n /** Delete a project */\n async deleteProject(projectId: string): Promise<void> {\n await this.request<void>('DELETE', `/api/v1/projects/${projectId}`);\n }\n\n /** List environments in a project */\n async listEnvironments(projectId: string): Promise<Environment[]> {\n const response = await this.request<{ environments: Environment[] }>(\n 'GET', `/api/v1/projects/${projectId}/environments`\n );\n return response.environments;\n }\n\n /** Create a new environment */\n async createEnvironment(projectId: string, name: string, inheritsFrom?: string): Promise<Environment> {\n return this.request<Environment>(\n 'POST', `/api/v1/projects/${projectId}/environments`,\n { name, inherits_from: inheritsFrom }\n );\n }\n\n /** Delete an environment */\n async deleteEnvironment(projectId: string, environment: string): Promise<void> {\n await this.request<void>('DELETE', `/api/v1/projects/${projectId}/environments/${environment}`);\n }\n\n /** List secrets in an environment (keys and metadata only) */\n async listSecrets(projectId: string, environment: string): Promise<Secret[]> {\n const response = await this.request<{ secrets: Secret[] }>(\n 'GET', `/api/v1/projects/${projectId}/environments/${environment}/secrets`\n );\n return response.secrets;\n }\n\n /**\n * Export all secrets with their decrypted values\n * @example\n * ```ts\n * const secrets = await client.exportSecrets('project-id', 'production');\n * for (const secret of secrets) {\n * process.env[secret.key] = secret.value;\n * }\n * ```\n */\n async exportSecrets(projectId: string, environment: string): Promise<SecretWithValue[]> {\n const response = await this.request<{ secrets: SecretWithValue[] }>(\n 'GET', `/api/v1/projects/${projectId}/environments/${environment}/secrets/export`\n );\n return response.secrets;\n }\n\n /**\n * Export secrets as a key-value object\n * @example\n * ```ts\n * const env = await client.exportSecretsAsObject('project-id', 'production');\n * // { DATABASE_URL: '...', API_KEY: '...' }\n * ```\n */\n async exportSecretsAsObject(projectId: string, environment: string): Promise<Record<string, string>> {\n const secrets = await this.exportSecrets(projectId, environment);\n return Object.fromEntries(secrets.map((s) => [s.key, s.value]));\n }\n\n /** Get a single secret with its value */\n async getSecret(projectId: string, environment: string, key: string): Promise<SecretWithValue> {\n const response = await this.request<{ secret: SecretWithValue }>(\n 'GET', `/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`\n );\n return response.secret;\n }\n\n /** Create a new secret */\n async createSecret(\n projectId: string, environment: string, key: string, value: string, description?: string\n ): Promise<Secret> {\n const response = await this.request<{ secret: Secret }>(\n 'POST', `/api/v1/projects/${projectId}/environments/${environment}/secrets`,\n { key, value, description }\n );\n return response.secret;\n }\n\n /** Update a secret's value */\n async updateSecret(\n projectId: string, environment: string, key: string, value: string, description?: string\n ): Promise<Secret> {\n const response = await this.request<{ secret: Secret }>(\n 'PUT', `/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`,\n { value, description }\n );\n return response.secret;\n }\n\n /** Set a secret (create or update) */\n async setSecret(\n projectId: string, environment: string, key: string, value: string, description?: string\n ): Promise<Secret> {\n try {\n return await this.updateSecret(projectId, environment, key, value, description);\n } catch (error) {\n if (error instanceof KeyEnvError && error.status === 404) {\n return this.createSecret(projectId, environment, key, value, description);\n }\n throw error;\n }\n }\n\n /** Delete a secret */\n async deleteSecret(projectId: string, environment: string, key: string): Promise<void> {\n await this.request<void>(\n 'DELETE', `/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`\n );\n }\n\n /** Get secret version history */\n async getSecretHistory(projectId: string, environment: string, key: string): Promise<SecretHistory[]> {\n const response = await this.request<{ history: SecretHistory[] }>(\n 'GET', `/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}/history`\n );\n return response.history;\n }\n\n /**\n * Bulk import secrets\n * @example\n * ```ts\n * await client.bulkImport('project-id', 'development', [\n * { key: 'DATABASE_URL', value: 'postgres://...' },\n * { key: 'API_KEY', value: 'sk_...' },\n * ], { overwrite: true });\n * ```\n */\n async bulkImport(\n projectId: string, environment: string, secrets: BulkSecretItem[], options: { overwrite?: boolean } = {}\n ): Promise<BulkImportResult> {\n return this.request<BulkImportResult>(\n 'POST', `/api/v1/projects/${projectId}/environments/${environment}/secrets/bulk`,\n { secrets, overwrite: options.overwrite ?? false }\n );\n }\n\n /**\n * Load secrets into process.env\n * @example\n * ```ts\n * await client.loadEnv('project-id', 'production');\n * console.log(process.env.DATABASE_URL);\n * ```\n */\n async loadEnv(projectId: string, environment: string): Promise<number> {\n const secrets = await this.exportSecrets(projectId, environment);\n for (const secret of secrets) {\n process.env[secret.key] = secret.value;\n }\n return secrets.length;\n }\n\n /** Generate .env file content from secrets */\n async generateEnvFile(projectId: string, environment: string): Promise<string> {\n const secrets = await this.exportSecrets(projectId, environment);\n const lines = [\n '# Generated by KeyEnv',\n `# Environment: ${environment}`,\n `# Generated at: ${new Date().toISOString()}`,\n '',\n ];\n\n for (const secret of secrets) {\n const value = secret.value;\n if (value.includes('\\n') || value.includes('\"') || value.includes(\"'\") || value.includes(' ')) {\n const escaped = value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n lines.push(`${secret.key}=\"${escaped}\"`);\n } else {\n lines.push(`${secret.key}=${value}`);\n }\n }\n\n return lines.join('\\n') + '\\n';\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACoGO,IAAM,cAAN,cAA0B,MAAM;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EAEhB,YAAY,SAAiB,QAAgB,MAAe,SAAmC;AAC7F,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,EACjB;AACF;;;ACjGA,IAAM,WAAW;AACjB,IAAM,kBAAkB;AAejB,IAAM,SAAN,MAAa;AAAA,EACD;AAAA,EACA;AAAA,EAEjB,YAAY,SAAwB;AAClC,QAAI,CAAC,QAAQ,OAAO;AAClB,YAAM,IAAI,MAAM,0BAA0B;AAAA,IAC5C;AACA,SAAK,QAAQ,QAAQ;AACrB,SAAK,UAAU,QAAQ,WAAW;AAAA,EACpC;AAAA,EAEA,MAAc,QAAW,QAAgB,MAAc,MAA4B;AACjF,UAAM,MAAM,GAAG,QAAQ,GAAG,IAAI;AAC9B,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,OAAO;AAEnE,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC;AAAA,QACA,SAAS;AAAA,UACP,iBAAiB,UAAU,KAAK,KAAK;AAAA,UACrC,gBAAgB;AAAA,UAChB,cAAc;AAAA,QAChB;AAAA,QACA,MAAM,OAAO,KAAK,UAAU,IAAI,IAAI;AAAA,QACpC,QAAQ,WAAW;AAAA,MACrB,CAAC;AAED,mBAAa,SAAS;AAEtB,UAAI,CAAC,SAAS,IAAI;AAChB,YAAI,YAAsB,EAAE,OAAO,gBAAgB;AACnD,YAAI;AACF,sBAAY,MAAM,SAAS,KAAK;AAAA,QAClC,QAAQ;AACN,sBAAY,EAAE,OAAO,SAAS,WAAW;AAAA,QAC3C;AACA,cAAM,IAAI,YAAY,UAAU,OAAO,SAAS,QAAQ,UAAU,MAAM,UAAU,OAAO;AAAA,MAC3F;AAEA,UAAI,SAAS,WAAW,KAAK;AAC3B,eAAO;AAAA,MACT;AAEA,aAAO,SAAS,KAAK;AAAA,IACvB,SAAS,OAAO;AACd,mBAAa,SAAS;AACtB,UAAI,iBAAiB,YAAa,OAAM;AACxC,UAAI,iBAAiB,SAAS,MAAM,SAAS,cAAc;AACzD,cAAM,IAAI,YAAY,mBAAmB,GAAG;AAAA,MAC9C;AACA,YAAM,IAAI,YAAY,iBAAiB,QAAQ,MAAM,UAAU,iBAAiB,CAAC;AAAA,IACnF;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,iBAAgC;AACpC,WAAO,KAAK,QAAc,OAAO,kBAAkB;AAAA,EACrD;AAAA;AAAA,EAGA,MAAM,gBAA+B;AACnC,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA;AAAA,EAGA,MAAM,eAAmC;AACvC,UAAM,WAAW,MAAM,KAAK,QAAiC,OAAO,kBAAkB;AACtF,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,WAAW,WAAqD;AACpE,WAAO,KAAK,QAAiC,OAAO,oBAAoB,SAAS,EAAE;AAAA,EACrF;AAAA;AAAA,EAGA,MAAM,cAAc,QAAgB,MAAgC;AAClE,WAAO,KAAK,QAAiB,QAAQ,oBAAoB,EAAE,SAAS,QAAQ,KAAK,CAAC;AAAA,EACpF;AAAA;AAAA,EAGA,MAAM,cAAc,WAAkC;AACpD,UAAM,KAAK,QAAc,UAAU,oBAAoB,SAAS,EAAE;AAAA,EACpE;AAAA;AAAA,EAGA,MAAM,iBAAiB,WAA2C;AAChE,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MAAO,oBAAoB,SAAS;AAAA,IACtC;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,kBAAkB,WAAmB,MAAc,cAA6C;AACpG,WAAO,KAAK;AAAA,MACV;AAAA,MAAQ,oBAAoB,SAAS;AAAA,MACrC,EAAE,MAAM,eAAe,aAAa;AAAA,IACtC;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,kBAAkB,WAAmB,aAAoC;AAC7E,UAAM,KAAK,QAAc,UAAU,oBAAoB,SAAS,iBAAiB,WAAW,EAAE;AAAA,EAChG;AAAA;AAAA,EAGA,MAAM,YAAY,WAAmB,aAAwC;AAC3E,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MAAO,oBAAoB,SAAS,iBAAiB,WAAW;AAAA,IAClE;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,cAAc,WAAmB,aAAiD;AACtF,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MAAO,oBAAoB,SAAS,iBAAiB,WAAW;AAAA,IAClE;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,sBAAsB,WAAmB,aAAsD;AACnG,UAAM,UAAU,MAAM,KAAK,cAAc,WAAW,WAAW;AAC/D,WAAO,OAAO,YAAY,QAAQ,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAAA,EAChE;AAAA;AAAA,EAGA,MAAM,UAAU,WAAmB,aAAqB,KAAuC;AAC7F,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MAAO,oBAAoB,SAAS,iBAAiB,WAAW,YAAY,GAAG;AAAA,IACjF;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,aACJ,WAAmB,aAAqB,KAAa,OAAe,aACnD;AACjB,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MAAQ,oBAAoB,SAAS,iBAAiB,WAAW;AAAA,MACjE,EAAE,KAAK,OAAO,YAAY;AAAA,IAC5B;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,aACJ,WAAmB,aAAqB,KAAa,OAAe,aACnD;AACjB,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MAAO,oBAAoB,SAAS,iBAAiB,WAAW,YAAY,GAAG;AAAA,MAC/E,EAAE,OAAO,YAAY;AAAA,IACvB;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,UACJ,WAAmB,aAAqB,KAAa,OAAe,aACnD;AACjB,QAAI;AACF,aAAO,MAAM,KAAK,aAAa,WAAW,aAAa,KAAK,OAAO,WAAW;AAAA,IAChF,SAAS,OAAO;AACd,UAAI,iBAAiB,eAAe,MAAM,WAAW,KAAK;AACxD,eAAO,KAAK,aAAa,WAAW,aAAa,KAAK,OAAO,WAAW;AAAA,MAC1E;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,aAAa,WAAmB,aAAqB,KAA4B;AACrF,UAAM,KAAK;AAAA,MACT;AAAA,MAAU,oBAAoB,SAAS,iBAAiB,WAAW,YAAY,GAAG;AAAA,IACpF;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,iBAAiB,WAAmB,aAAqB,KAAuC;AACpG,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MAAO,oBAAoB,SAAS,iBAAiB,WAAW,YAAY,GAAG;AAAA,IACjF;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,WACJ,WAAmB,aAAqB,SAA2B,UAAmC,CAAC,GAC5E;AAC3B,WAAO,KAAK;AAAA,MACV;AAAA,MAAQ,oBAAoB,SAAS,iBAAiB,WAAW;AAAA,MACjE,EAAE,SAAS,WAAW,QAAQ,aAAa,MAAM;AAAA,IACnD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,QAAQ,WAAmB,aAAsC;AACrE,UAAM,UAAU,MAAM,KAAK,cAAc,WAAW,WAAW;AAC/D,eAAW,UAAU,SAAS;AAC5B,cAAQ,IAAI,OAAO,GAAG,IAAI,OAAO;AAAA,IACnC;AACA,WAAO,QAAQ;AAAA,EACjB;AAAA;AAAA,EAGA,MAAM,gBAAgB,WAAmB,aAAsC;AAC7E,UAAM,UAAU,MAAM,KAAK,cAAc,WAAW,WAAW;AAC/D,UAAM,QAAQ;AAAA,MACZ;AAAA,MACA,kBAAkB,WAAW;AAAA,MAC7B,oBAAmB,oBAAI,KAAK,GAAE,YAAY,CAAC;AAAA,MAC3C;AAAA,IACF;AAEA,eAAW,UAAU,SAAS;AAC5B,YAAM,QAAQ,OAAO;AACrB,UAAI,MAAM,SAAS,IAAI,KAAK,MAAM,SAAS,GAAG,KAAK,MAAM,SAAS,GAAG,KAAK,MAAM,SAAS,GAAG,GAAG;AAC7F,cAAM,UAAU,MAAM,QAAQ,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAK;AAChE,cAAM,KAAK,GAAG,OAAO,GAAG,KAAK,OAAO,GAAG;AAAA,MACzC,OAAO;AACL,cAAM,KAAK,GAAG,OAAO,GAAG,IAAI,KAAK,EAAE;AAAA,MACrC;AAAA,IACF;AAEA,WAAO,MAAM,KAAK,IAAI,IAAI;AAAA,EAC5B;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/client.ts"],"sourcesContent":["export { KeyEnv } from './client.js';\nexport { KeyEnvError } from './types.js';\nexport type {\n KeyEnvOptions,\n User,\n Project,\n ProjectWithEnvironments,\n Environment,\n Secret,\n SecretWithValue,\n SecretHistory,\n BulkSecretItem,\n BulkImportResult,\n EnvironmentRole,\n EnvironmentPermission,\n MyPermission,\n MyPermissionsResponse,\n ProjectDefault,\n} from './types.js';\n","/** KeyEnv client configuration options */\nexport interface KeyEnvOptions {\n /** Service token for authentication */\n token: string;\n /** Request timeout in milliseconds (default: 30000) */\n timeout?: number;\n /** Cache TTL in seconds for exportSecrets/loadEnv (default: 0 = disabled). Also configurable via KEYENV_CACHE_TTL env var. */\n cacheTtl?: number;\n /** Custom API base URL (default: https://api.keyenv.dev). Also configurable via KEYENV_API_URL env var. */\n baseUrl?: string;\n}\n\n/** User or service token info */\nexport interface User {\n id: string;\n email?: string;\n name?: string;\n clerk_id?: string;\n avatar_url?: string;\n /** Present for service tokens */\n auth_type?: 'service_token' | 'user';\n /** Team ID (for service tokens) */\n team_id?: string;\n /** Project IDs (for project-scoped service tokens) */\n project_ids?: string[];\n /** Token scopes (for service tokens) */\n scopes?: string[];\n created_at: string;\n}\n\n/** Project */\nexport interface Project {\n id: string;\n team_id: string;\n name: string;\n slug: string;\n description?: string;\n created_at: string;\n}\n\n/** Environment */\nexport interface Environment {\n id: string;\n project_id: string;\n name: string;\n inherits_from?: string;\n created_at: string;\n}\n\n/** Project with environments */\nexport interface ProjectWithEnvironments extends Project {\n environments: Environment[];\n}\n\n/** Secret (without value) */\nexport interface Secret {\n id: string;\n environment_id: string;\n key: string;\n type: string;\n description?: string;\n version: number;\n created_at: string;\n updated_at: string;\n}\n\n/** Secret with decrypted value */\nexport interface SecretWithValue extends Secret {\n value: string;\n inherited_from?: string;\n}\n\n/** Secret history entry */\nexport interface SecretHistory {\n id: string;\n secret_id: string;\n value: string;\n version: number;\n changed_by?: string;\n changed_at: string;\n}\n\n/** Bulk import request item */\nexport interface BulkSecretItem {\n key: string;\n value: string;\n description?: string;\n}\n\n/** Bulk import result */\nexport interface BulkImportResult {\n created: number;\n updated: number;\n skipped: number;\n}\n\n/** API error response */\nexport interface ApiError {\n error: string;\n code?: string;\n details?: Record<string, unknown>;\n}\n\n/** KeyEnv API error */\nexport class KeyEnvError extends Error {\n public readonly status: number;\n public readonly code?: string;\n public readonly details?: Record<string, unknown>;\n\n constructor(message: string, status: number, code?: string, details?: Record<string, unknown>) {\n super(message);\n this.name = 'KeyEnvError';\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n\n/** Environment permission role */\nexport type EnvironmentRole = 'none' | 'read' | 'write' | 'admin';\n\n/** Environment permission for a user */\nexport interface EnvironmentPermission {\n id: string;\n environment_id: string;\n user_id: string;\n role: EnvironmentRole;\n user_email?: string;\n user_name?: string;\n granted_by?: string;\n created_at: string;\n updated_at: string;\n}\n\n/** User's permission for an environment */\nexport interface MyPermission {\n environment_id: string;\n environment_name: string;\n role: EnvironmentRole;\n can_read: boolean;\n can_write: boolean;\n can_admin: boolean;\n}\n\n/** Response for getting user's permissions */\nexport interface MyPermissionsResponse {\n permissions: MyPermission[];\n is_team_admin: boolean;\n}\n\n/** Project default permission for an environment */\nexport interface ProjectDefault {\n id: string;\n project_id: string;\n environment_name: string;\n default_role: EnvironmentRole;\n created_at: string;\n}\n","import type {\n KeyEnvOptions,\n User,\n Project,\n ProjectWithEnvironments,\n Environment,\n Secret,\n SecretWithValue,\n SecretHistory,\n BulkSecretItem,\n BulkImportResult,\n ApiError,\n EnvironmentRole,\n EnvironmentPermission,\n MyPermissionsResponse,\n ProjectDefault,\n} from './types.js';\nimport { KeyEnvError } from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.keyenv.dev';\nconst DEFAULT_TIMEOUT = 30000;\n\nfunction getCacheKey(projectId: string, environment: string): string {\n return `${projectId}:${environment}`;\n}\n\n/**\n * KeyEnv API client for managing secrets\n *\n * @example\n * ```ts\n * import { KeyEnv } from 'keyenv';\n *\n * const client = new KeyEnv({ token: process.env.KEYENV_TOKEN });\n *\n * // Export all secrets for an environment\n * const secrets = await client.exportSecrets('project-id', 'production');\n * ```\n */\nexport class KeyEnv {\n private readonly token: string;\n private readonly baseUrl: string;\n private readonly timeout: number;\n private readonly cacheTtl: number;\n private readonly secretsCache = new Map<string, { secrets: SecretWithValue[]; expiresAt: number }>();\n\n constructor(options: KeyEnvOptions) {\n if (!options.token) {\n throw new Error('KeyEnv token is required');\n }\n this.token = options.token;\n // Base URL: constructor option → env var → default\n this.baseUrl = (options.baseUrl ?? process.env.KEYENV_API_URL ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n this.timeout = options.timeout || DEFAULT_TIMEOUT;\n // Cache TTL: constructor option → env var → 0 (disabled)\n this.cacheTtl = options.cacheTtl ??\n (process.env.KEYENV_CACHE_TTL ? parseInt(process.env.KEYENV_CACHE_TTL, 10) : 0);\n }\n\n private async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(url, {\n method,\n headers: {\n 'Authorization': `Bearer ${this.token}`,\n 'Content-Type': 'application/json',\n 'User-Agent': 'keyenv-node/1.0.0',\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n let errorData: ApiError = { error: 'Unknown error' };\n try {\n errorData = await response.json() as ApiError;\n } catch {\n errorData = { error: response.statusText };\n }\n throw new KeyEnvError(errorData.error, response.status, errorData.code, errorData.details);\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return response.json() as Promise<T>;\n } catch (error) {\n clearTimeout(timeoutId);\n if (error instanceof KeyEnvError) throw error;\n if (error instanceof Error && error.name === 'AbortError') {\n throw new KeyEnvError('Request timeout', 408);\n }\n throw new KeyEnvError(error instanceof Error ? error.message : 'Network error', 0);\n }\n }\n\n /** Get the current user or service token info */\n async getCurrentUser(): Promise<User> {\n const response = await this.request<{ data: User }>('GET', '/api/v1/users/me');\n return response.data;\n }\n\n /** Validate the token and return user info */\n async validateToken(): Promise<User> {\n return this.getCurrentUser();\n }\n\n /** List all accessible projects */\n async listProjects(): Promise<Project[]> {\n const response = await this.request<{ data: Project[] }>('GET', '/api/v1/projects');\n return response.data;\n }\n\n /** Get a project by ID */\n async getProject(projectId: string): Promise<ProjectWithEnvironments> {\n const response = await this.request<{ data: ProjectWithEnvironments }>('GET', `/api/v1/projects/${projectId}`);\n return response.data;\n }\n\n /** Create a new project */\n async createProject(teamId: string, name: string): Promise<Project> {\n const response = await this.request<{ data: Project }>('POST', '/api/v1/projects', { team_id: teamId, name });\n return response.data;\n }\n\n /** Delete a project */\n async deleteProject(projectId: string): Promise<void> {\n await this.request<void>('DELETE', `/api/v1/projects/${projectId}`);\n }\n\n /** List environments in a project */\n async listEnvironments(projectId: string): Promise<Environment[]> {\n const response = await this.request<{ data: Environment[] }>(\n 'GET', `/api/v1/projects/${projectId}/environments`\n );\n return response.data;\n }\n\n /** Create a new environment */\n async createEnvironment(projectId: string, name: string, inheritsFrom?: string): Promise<Environment> {\n const response = await this.request<{ data: Environment }>(\n 'POST', `/api/v1/projects/${projectId}/environments`,\n { name, inherits_from: inheritsFrom }\n );\n return response.data;\n }\n\n /** Delete an environment */\n async deleteEnvironment(projectId: string, environment: string): Promise<void> {\n await this.request<void>('DELETE', `/api/v1/projects/${projectId}/environments/${environment}`);\n }\n\n /** List secrets in an environment (keys and metadata only) */\n async listSecrets(projectId: string, environment: string): Promise<Secret[]> {\n const response = await this.request<{ data: Secret[] }>(\n 'GET', `/api/v1/projects/${projectId}/environments/${environment}/secrets`\n );\n return response.data;\n }\n\n /**\n * Export all secrets with their decrypted values.\n * Results are cached when cacheTtl > 0.\n * @example\n * ```ts\n * const secrets = await client.exportSecrets('project-id', 'production');\n * for (const secret of secrets) {\n * process.env[secret.key] = secret.value;\n * }\n * ```\n */\n async exportSecrets(projectId: string, environment: string): Promise<SecretWithValue[]> {\n const cacheKey = getCacheKey(projectId, environment);\n\n // Check cache if TTL > 0\n if (this.cacheTtl > 0) {\n const cached = this.secretsCache.get(cacheKey);\n if (cached && Date.now() < cached.expiresAt) {\n return cached.secrets;\n }\n // Delete expired entry to prevent memory leaks\n if (cached) {\n this.secretsCache.delete(cacheKey);\n }\n }\n\n const response = await this.request<{ data: SecretWithValue[] }>(\n 'GET', `/api/v1/projects/${projectId}/environments/${environment}/secrets/export`\n );\n\n // Store in cache if TTL > 0\n if (this.cacheTtl > 0) {\n this.secretsCache.set(cacheKey, {\n secrets: response.data,\n expiresAt: Date.now() + (this.cacheTtl * 1000),\n });\n }\n\n return response.data;\n }\n\n /**\n * Export secrets as a key-value object\n * @example\n * ```ts\n * const env = await client.exportSecretsAsObject('project-id', 'production');\n * // { DATABASE_URL: '...', API_KEY: '...' }\n * ```\n */\n async exportSecretsAsObject(projectId: string, environment: string): Promise<Record<string, string>> {\n const secrets = await this.exportSecrets(projectId, environment);\n return Object.fromEntries(secrets.map((s) => [s.key, s.value]));\n }\n\n /** Get a single secret with its value */\n async getSecret(projectId: string, environment: string, key: string): Promise<SecretWithValue> {\n const response = await this.request<{ data: SecretWithValue }>(\n 'GET', `/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`\n );\n return response.data;\n }\n\n /** Create a new secret */\n async createSecret(\n projectId: string, environment: string, key: string, value: string, description?: string\n ): Promise<Secret> {\n const response = await this.request<{ data: Secret }>(\n 'POST', `/api/v1/projects/${projectId}/environments/${environment}/secrets`,\n { key, value, description }\n );\n this.clearCache(projectId, environment);\n return response.data;\n }\n\n /** Update a secret's value */\n async updateSecret(\n projectId: string, environment: string, key: string, value: string, description?: string\n ): Promise<Secret> {\n const response = await this.request<{ data: Secret }>(\n 'PUT', `/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`,\n { value, description }\n );\n this.clearCache(projectId, environment);\n return response.data;\n }\n\n /** Set a secret (create or update) */\n async setSecret(\n projectId: string, environment: string, key: string, value: string, description?: string\n ): Promise<Secret> {\n try {\n return await this.updateSecret(projectId, environment, key, value, description);\n } catch (error) {\n if (error instanceof KeyEnvError && error.status === 404) {\n return this.createSecret(projectId, environment, key, value, description);\n }\n throw error;\n }\n }\n\n /** Delete a secret */\n async deleteSecret(projectId: string, environment: string, key: string): Promise<void> {\n await this.request<void>(\n 'DELETE', `/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`\n );\n this.clearCache(projectId, environment);\n }\n\n /** Get secret version history */\n async getSecretHistory(projectId: string, environment: string, key: string): Promise<SecretHistory[]> {\n const response = await this.request<{ data: SecretHistory[] }>(\n 'GET', `/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}/history`\n );\n return response.data;\n }\n\n /**\n * Bulk import secrets\n * @example\n * ```ts\n * await client.bulkImport('project-id', 'development', [\n * { key: 'DATABASE_URL', value: 'postgres://...' },\n * { key: 'API_KEY', value: 'sk_...' },\n * ], { overwrite: true });\n * ```\n */\n async bulkImport(\n projectId: string, environment: string, secrets: BulkSecretItem[], options: { overwrite?: boolean } = {}\n ): Promise<BulkImportResult> {\n const response = await this.request<{ data: BulkImportResult }>(\n 'POST', `/api/v1/projects/${projectId}/environments/${environment}/secrets/bulk`,\n { secrets, overwrite: options.overwrite ?? false }\n );\n this.clearCache(projectId, environment);\n return response.data;\n }\n\n /**\n * Load secrets into process.env\n * @example\n * ```ts\n * await client.loadEnv('project-id', 'production');\n * console.log(process.env.DATABASE_URL);\n * ```\n */\n async loadEnv(projectId: string, environment: string): Promise<number> {\n const secrets = await this.exportSecrets(projectId, environment);\n for (const secret of secrets) {\n process.env[secret.key] = secret.value;\n }\n return secrets.length;\n }\n\n /** Generate .env file content from secrets */\n async generateEnvFile(projectId: string, environment: string): Promise<string> {\n const secrets = await this.exportSecrets(projectId, environment);\n const lines = [\n '# Generated by KeyEnv',\n `# Environment: ${environment}`,\n `# Generated at: ${new Date().toISOString()}`,\n '',\n ];\n\n for (const secret of secrets) {\n const value = secret.value;\n if (value.includes('\\n') || value.includes('\"') || value.includes(\"'\") || value.includes(' ') || value.includes('$')) {\n const escaped = value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\n/g, '\\\\n').replace(/\\$/g, '\\\\$');\n lines.push(`${secret.key}=\"${escaped}\"`);\n } else {\n lines.push(`${secret.key}=${value}`);\n }\n }\n\n return lines.join('\\n') + '\\n';\n }\n\n /**\n * Clear the secrets cache.\n * @param projectId - Clear cache for specific project (optional)\n * @param environment - Clear cache for specific environment (requires projectId)\n */\n clearCache(projectId?: string, environment?: string): void {\n if (projectId && environment) {\n this.secretsCache.delete(getCacheKey(projectId, environment));\n } else if (projectId) {\n // Clear all environments for this project\n for (const key of this.secretsCache.keys()) {\n if (key.startsWith(`${projectId}:`)) {\n this.secretsCache.delete(key);\n }\n }\n } else {\n this.secretsCache.clear();\n }\n }\n\n // ============================================================================\n // Environment Permission Management\n // ============================================================================\n\n /**\n * List all permissions for an environment.\n * @param projectId - The project ID\n * @param environment - The environment name\n * @returns Array of environment permissions\n * @example\n * ```ts\n * const permissions = await client.listPermissions('project-id', 'production');\n * for (const perm of permissions) {\n * console.log(`${perm.user_email}: ${perm.role}`);\n * }\n * ```\n */\n async listPermissions(projectId: string, environment: string): Promise<EnvironmentPermission[]> {\n const response = await this.request<{ data: EnvironmentPermission[] }>(\n 'GET', `/api/v1/projects/${projectId}/environments/${environment}/permissions`\n );\n return response.data;\n }\n\n /**\n * Set a user's permission for an environment.\n * @param projectId - The project ID\n * @param environment - The environment name\n * @param userId - The user ID to set permission for\n * @param role - The permission role ('none', 'read', 'write', or 'admin')\n * @returns The created or updated permission\n * @example\n * ```ts\n * const permission = await client.setPermission('project-id', 'production', 'user-id', 'write');\n * console.log(`Set ${permission.user_email} to ${permission.role}`);\n * ```\n */\n async setPermission(\n projectId: string, environment: string, userId: string, role: EnvironmentRole\n ): Promise<EnvironmentPermission> {\n const response = await this.request<{ data: EnvironmentPermission }>(\n 'PUT', `/api/v1/projects/${projectId}/environments/${environment}/permissions/${userId}`,\n { role }\n );\n return response.data;\n }\n\n /**\n * Delete a user's permission for an environment.\n * @param projectId - The project ID\n * @param environment - The environment name\n * @param userId - The user ID to delete permission for\n * @example\n * ```ts\n * await client.deletePermission('project-id', 'production', 'user-id');\n * ```\n */\n async deletePermission(projectId: string, environment: string, userId: string): Promise<void> {\n await this.request<void>(\n 'DELETE', `/api/v1/projects/${projectId}/environments/${environment}/permissions/${userId}`\n );\n }\n\n /**\n * Bulk set permissions for multiple users in an environment.\n * @param projectId - The project ID\n * @param environment - The environment name\n * @param permissions - Array of user permissions to set\n * @returns Array of created or updated permissions\n * @example\n * ```ts\n * const permissions = await client.bulkSetPermissions('project-id', 'production', [\n * { userId: 'user-1', role: 'write' },\n * { userId: 'user-2', role: 'read' },\n * ]);\n * ```\n */\n async bulkSetPermissions(\n projectId: string, environment: string, permissions: Array<{ userId: string; role: EnvironmentRole }>\n ): Promise<EnvironmentPermission[]> {\n const response = await this.request<{ data: EnvironmentPermission[] }>(\n 'PUT', `/api/v1/projects/${projectId}/environments/${environment}/permissions`,\n { permissions: permissions.map(p => ({ user_id: p.userId, role: p.role })) }\n );\n return response.data;\n }\n\n /**\n * Get the current user's permissions for all environments in a project.\n * @param projectId - The project ID\n * @returns The user's permissions and team admin status\n * @example\n * ```ts\n * const { permissions, is_team_admin } = await client.getMyPermissions('project-id');\n * for (const perm of permissions) {\n * console.log(`${perm.environment_name}: ${perm.role} (can_write: ${perm.can_write})`);\n * }\n * ```\n */\n async getMyPermissions(projectId: string): Promise<MyPermissionsResponse> {\n return this.request<MyPermissionsResponse>('GET', `/api/v1/projects/${projectId}/my-permissions`);\n }\n\n /**\n * Get default permission settings for a project's environments.\n * @param projectId - The project ID\n * @returns Array of project default permissions\n * @example\n * ```ts\n * const defaults = await client.getProjectDefaults('project-id');\n * for (const def of defaults) {\n * console.log(`${def.environment_name}: ${def.default_role}`);\n * }\n * ```\n */\n async getProjectDefaults(projectId: string): Promise<ProjectDefault[]> {\n const response = await this.request<{ data: ProjectDefault[] }>(\n 'GET', `/api/v1/projects/${projectId}/permissions/defaults`\n );\n return response.data;\n }\n\n /**\n * Set default permission settings for a project's environments.\n * @param projectId - The project ID\n * @param defaults - Array of default permissions to set\n * @returns Array of updated project default permissions\n * @example\n * ```ts\n * const defaults = await client.setProjectDefaults('project-id', [\n * { environmentName: 'development', defaultRole: 'write' },\n * { environmentName: 'production', defaultRole: 'read' },\n * ]);\n * ```\n */\n async setProjectDefaults(\n projectId: string, defaults: Array<{ environmentName: string; defaultRole: EnvironmentRole }>\n ): Promise<ProjectDefault[]> {\n const response = await this.request<{ data: ProjectDefault[] }>(\n 'PUT', `/api/v1/projects/${projectId}/permissions/defaults`,\n { defaults: defaults.map(d => ({ environment_name: d.environmentName, default_role: d.defaultRole })) }\n );\n return response.data;\n }\n}\n"],"mappings":"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","names":[]}
|