keyenv 0.1.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.
- package/LICENSE +21 -0
- package/README.md +162 -0
- package/dist/index.d.mts +187 -0
- package/dist/index.d.ts +187 -0
- package/dist/index.js +285 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +257 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 KeyEnv
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# KeyEnv Node.js SDK
|
|
2
|
+
|
|
3
|
+
Official Node.js SDK for [KeyEnv](https://keyenv.dev) - Secure secrets management for development teams.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install keyenv
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { KeyEnv } from 'keyenv';
|
|
15
|
+
|
|
16
|
+
const client = new KeyEnv({
|
|
17
|
+
token: process.env.KEYENV_TOKEN!,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Load secrets into process.env
|
|
21
|
+
await client.loadEnv('your-project-id', 'production');
|
|
22
|
+
console.log(process.env.DATABASE_URL);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
### Initialize the Client
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { KeyEnv } from 'keyenv';
|
|
31
|
+
|
|
32
|
+
const client = new KeyEnv({
|
|
33
|
+
token: 'your-service-token',
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Export Secrets
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
// Get all secrets as an array
|
|
41
|
+
const secrets = await client.exportSecrets('project-id', 'production');
|
|
42
|
+
for (const secret of secrets) {
|
|
43
|
+
console.log(`${secret.key}=${secret.value}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Get secrets as a key-value object
|
|
47
|
+
const env = await client.exportSecretsAsObject('project-id', 'production');
|
|
48
|
+
console.log(env.DATABASE_URL);
|
|
49
|
+
|
|
50
|
+
// Load directly into process.env
|
|
51
|
+
const count = await client.loadEnv('project-id', 'production');
|
|
52
|
+
console.log(`Loaded ${count} secrets`);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Manage Secrets
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// Get a single secret
|
|
59
|
+
const secret = await client.getSecret('project-id', 'production', 'DATABASE_URL');
|
|
60
|
+
console.log(secret.value);
|
|
61
|
+
|
|
62
|
+
// Set a secret (creates or updates)
|
|
63
|
+
await client.setSecret('project-id', 'production', 'API_KEY', 'sk_live_...');
|
|
64
|
+
|
|
65
|
+
// Delete a secret
|
|
66
|
+
await client.deleteSecret('project-id', 'production', 'OLD_KEY');
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Bulk Import
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
const result = await client.bulkImport('project-id', 'development', [
|
|
73
|
+
{ key: 'DATABASE_URL', value: 'postgres://localhost/mydb' },
|
|
74
|
+
{ key: 'REDIS_URL', value: 'redis://localhost:6379' },
|
|
75
|
+
{ key: 'API_KEY', value: 'sk_test_...', description: 'Test API key' },
|
|
76
|
+
], { overwrite: true });
|
|
77
|
+
|
|
78
|
+
console.log(`Created: ${result.created}, Updated: ${result.updated}`);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Generate .env File
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { writeFileSync } from 'fs';
|
|
85
|
+
|
|
86
|
+
const envContent = await client.generateEnvFile('project-id', 'production');
|
|
87
|
+
writeFileSync('.env', envContent);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### List Projects and Environments
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// List all projects
|
|
94
|
+
const projects = await client.listProjects();
|
|
95
|
+
for (const project of projects) {
|
|
96
|
+
console.log(`${project.name} (${project.id})`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Get project with environments
|
|
100
|
+
const project = await client.getProject('project-id');
|
|
101
|
+
for (const env of project.environments) {
|
|
102
|
+
console.log(` - ${env.name}`);
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Error Handling
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { KeyEnv, KeyEnvError } from 'keyenv';
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
await client.getSecret('project-id', 'production', 'MISSING_KEY');
|
|
113
|
+
} catch (error) {
|
|
114
|
+
if (error instanceof KeyEnvError) {
|
|
115
|
+
console.error(`Error ${error.status}: ${error.message}`);
|
|
116
|
+
if (error.status === 404) {
|
|
117
|
+
console.error('Secret not found');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## TypeScript Support
|
|
124
|
+
|
|
125
|
+
The SDK is written in TypeScript and includes full type definitions:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import type { Secret, SecretWithValue, Project } from 'keyenv';
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## API Reference
|
|
132
|
+
|
|
133
|
+
### `new KeyEnv(options)`
|
|
134
|
+
|
|
135
|
+
Create a new KeyEnv client.
|
|
136
|
+
|
|
137
|
+
| Option | Type | Required | Default | Description |
|
|
138
|
+
|--------|------|----------|---------|-------------|
|
|
139
|
+
| `token` | `string` | Yes | - | Service token |
|
|
140
|
+
| `timeout` | `number` | No | `30000` | Request timeout (ms) |
|
|
141
|
+
|
|
142
|
+
### Methods
|
|
143
|
+
|
|
144
|
+
| Method | Description |
|
|
145
|
+
|--------|-------------|
|
|
146
|
+
| `getCurrentUser()` | Get current user/token info |
|
|
147
|
+
| `listProjects()` | List all accessible projects |
|
|
148
|
+
| `getProject(id)` | Get project with environments |
|
|
149
|
+
| `listEnvironments(projectId)` | List environments in a project |
|
|
150
|
+
| `listSecrets(projectId, env)` | List secret keys (no values) |
|
|
151
|
+
| `exportSecrets(projectId, env)` | Export secrets with values |
|
|
152
|
+
| `exportSecretsAsObject(projectId, env)` | Export as key-value object |
|
|
153
|
+
| `getSecret(projectId, env, key)` | Get single secret |
|
|
154
|
+
| `setSecret(projectId, env, key, value)` | Create or update secret |
|
|
155
|
+
| `deleteSecret(projectId, env, key)` | Delete secret |
|
|
156
|
+
| `bulkImport(projectId, env, secrets)` | Bulk import secrets |
|
|
157
|
+
| `loadEnv(projectId, env)` | Load secrets into process.env |
|
|
158
|
+
| `generateEnvFile(projectId, env)` | Generate .env file content |
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/** KeyEnv client configuration options */
|
|
2
|
+
interface KeyEnvOptions {
|
|
3
|
+
/** Service token for authentication */
|
|
4
|
+
token: string;
|
|
5
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
6
|
+
timeout?: number;
|
|
7
|
+
}
|
|
8
|
+
/** User or service token info */
|
|
9
|
+
interface User {
|
|
10
|
+
id: string;
|
|
11
|
+
email?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
clerk_id?: string;
|
|
14
|
+
avatar_url?: string;
|
|
15
|
+
/** Present for service tokens */
|
|
16
|
+
auth_type?: 'service_token' | 'user';
|
|
17
|
+
/** Team ID (for service tokens) */
|
|
18
|
+
team_id?: string;
|
|
19
|
+
/** Project ID (for project-scoped service tokens) */
|
|
20
|
+
project_id?: string;
|
|
21
|
+
/** Token scopes (for service tokens) */
|
|
22
|
+
scopes?: string[];
|
|
23
|
+
created_at: string;
|
|
24
|
+
}
|
|
25
|
+
/** Project */
|
|
26
|
+
interface Project {
|
|
27
|
+
id: string;
|
|
28
|
+
team_id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
slug: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
created_at: string;
|
|
33
|
+
}
|
|
34
|
+
/** Environment */
|
|
35
|
+
interface Environment {
|
|
36
|
+
id: string;
|
|
37
|
+
project_id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
inherits_from?: string;
|
|
40
|
+
created_at: string;
|
|
41
|
+
}
|
|
42
|
+
/** Project with environments */
|
|
43
|
+
interface ProjectWithEnvironments extends Project {
|
|
44
|
+
environments: Environment[];
|
|
45
|
+
}
|
|
46
|
+
/** Secret (without value) */
|
|
47
|
+
interface Secret {
|
|
48
|
+
id: string;
|
|
49
|
+
environment_id: string;
|
|
50
|
+
key: string;
|
|
51
|
+
type: string;
|
|
52
|
+
description?: string;
|
|
53
|
+
version: number;
|
|
54
|
+
created_at: string;
|
|
55
|
+
updated_at: string;
|
|
56
|
+
}
|
|
57
|
+
/** Secret with decrypted value */
|
|
58
|
+
interface SecretWithValue extends Secret {
|
|
59
|
+
value: string;
|
|
60
|
+
inherited_from?: string;
|
|
61
|
+
}
|
|
62
|
+
/** Secret history entry */
|
|
63
|
+
interface SecretHistory {
|
|
64
|
+
id: string;
|
|
65
|
+
secret_id: string;
|
|
66
|
+
value: string;
|
|
67
|
+
version: number;
|
|
68
|
+
changed_by?: string;
|
|
69
|
+
changed_at: string;
|
|
70
|
+
}
|
|
71
|
+
/** Bulk import request item */
|
|
72
|
+
interface BulkSecretItem {
|
|
73
|
+
key: string;
|
|
74
|
+
value: string;
|
|
75
|
+
description?: string;
|
|
76
|
+
}
|
|
77
|
+
/** Bulk import result */
|
|
78
|
+
interface BulkImportResult {
|
|
79
|
+
created: number;
|
|
80
|
+
updated: number;
|
|
81
|
+
skipped: number;
|
|
82
|
+
}
|
|
83
|
+
/** KeyEnv API error */
|
|
84
|
+
declare class KeyEnvError extends Error {
|
|
85
|
+
readonly status: number;
|
|
86
|
+
readonly code?: string;
|
|
87
|
+
readonly details?: Record<string, unknown>;
|
|
88
|
+
constructor(message: string, status: number, code?: string, details?: Record<string, unknown>);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* KeyEnv API client for managing secrets
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* import { KeyEnv } from 'keyenv';
|
|
97
|
+
*
|
|
98
|
+
* const client = new KeyEnv({ token: process.env.KEYENV_TOKEN });
|
|
99
|
+
*
|
|
100
|
+
* // Export all secrets for an environment
|
|
101
|
+
* const secrets = await client.exportSecrets('project-id', 'production');
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
declare class KeyEnv {
|
|
105
|
+
private readonly token;
|
|
106
|
+
private readonly timeout;
|
|
107
|
+
constructor(options: KeyEnvOptions);
|
|
108
|
+
private request;
|
|
109
|
+
/** Get the current user or service token info */
|
|
110
|
+
getCurrentUser(): Promise<User>;
|
|
111
|
+
/** Validate the token and return user info */
|
|
112
|
+
validateToken(): Promise<User>;
|
|
113
|
+
/** List all accessible projects */
|
|
114
|
+
listProjects(): Promise<Project[]>;
|
|
115
|
+
/** Get a project by ID */
|
|
116
|
+
getProject(projectId: string): Promise<ProjectWithEnvironments>;
|
|
117
|
+
/** Create a new project */
|
|
118
|
+
createProject(teamId: string, name: string): Promise<Project>;
|
|
119
|
+
/** Delete a project */
|
|
120
|
+
deleteProject(projectId: string): Promise<void>;
|
|
121
|
+
/** List environments in a project */
|
|
122
|
+
listEnvironments(projectId: string): Promise<Environment[]>;
|
|
123
|
+
/** Create a new environment */
|
|
124
|
+
createEnvironment(projectId: string, name: string, inheritsFrom?: string): Promise<Environment>;
|
|
125
|
+
/** Delete an environment */
|
|
126
|
+
deleteEnvironment(projectId: string, environment: string): Promise<void>;
|
|
127
|
+
/** List secrets in an environment (keys and metadata only) */
|
|
128
|
+
listSecrets(projectId: string, environment: string): Promise<Secret[]>;
|
|
129
|
+
/**
|
|
130
|
+
* Export all secrets with their decrypted values
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* const secrets = await client.exportSecrets('project-id', 'production');
|
|
134
|
+
* for (const secret of secrets) {
|
|
135
|
+
* process.env[secret.key] = secret.value;
|
|
136
|
+
* }
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
exportSecrets(projectId: string, environment: string): Promise<SecretWithValue[]>;
|
|
140
|
+
/**
|
|
141
|
+
* Export secrets as a key-value object
|
|
142
|
+
* @example
|
|
143
|
+
* ```ts
|
|
144
|
+
* const env = await client.exportSecretsAsObject('project-id', 'production');
|
|
145
|
+
* // { DATABASE_URL: '...', API_KEY: '...' }
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
exportSecretsAsObject(projectId: string, environment: string): Promise<Record<string, string>>;
|
|
149
|
+
/** Get a single secret with its value */
|
|
150
|
+
getSecret(projectId: string, environment: string, key: string): Promise<SecretWithValue>;
|
|
151
|
+
/** Create a new secret */
|
|
152
|
+
createSecret(projectId: string, environment: string, key: string, value: string, description?: string): Promise<Secret>;
|
|
153
|
+
/** Update a secret's value */
|
|
154
|
+
updateSecret(projectId: string, environment: string, key: string, value: string, description?: string): Promise<Secret>;
|
|
155
|
+
/** Set a secret (create or update) */
|
|
156
|
+
setSecret(projectId: string, environment: string, key: string, value: string, description?: string): Promise<Secret>;
|
|
157
|
+
/** Delete a secret */
|
|
158
|
+
deleteSecret(projectId: string, environment: string, key: string): Promise<void>;
|
|
159
|
+
/** Get secret version history */
|
|
160
|
+
getSecretHistory(projectId: string, environment: string, key: string): Promise<SecretHistory[]>;
|
|
161
|
+
/**
|
|
162
|
+
* Bulk import secrets
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* await client.bulkImport('project-id', 'development', [
|
|
166
|
+
* { key: 'DATABASE_URL', value: 'postgres://...' },
|
|
167
|
+
* { key: 'API_KEY', value: 'sk_...' },
|
|
168
|
+
* ], { overwrite: true });
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
bulkImport(projectId: string, environment: string, secrets: BulkSecretItem[], options?: {
|
|
172
|
+
overwrite?: boolean;
|
|
173
|
+
}): Promise<BulkImportResult>;
|
|
174
|
+
/**
|
|
175
|
+
* Load secrets into process.env
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* await client.loadEnv('project-id', 'production');
|
|
179
|
+
* console.log(process.env.DATABASE_URL);
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
loadEnv(projectId: string, environment: string): Promise<number>;
|
|
183
|
+
/** Generate .env file content from secrets */
|
|
184
|
+
generateEnvFile(projectId: string, environment: string): Promise<string>;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export { type BulkImportResult, type BulkSecretItem, type Environment, KeyEnv, KeyEnvError, type KeyEnvOptions, type Project, type ProjectWithEnvironments, type Secret, type SecretHistory, type SecretWithValue, type User };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/** KeyEnv client configuration options */
|
|
2
|
+
interface KeyEnvOptions {
|
|
3
|
+
/** Service token for authentication */
|
|
4
|
+
token: string;
|
|
5
|
+
/** Request timeout in milliseconds (default: 30000) */
|
|
6
|
+
timeout?: number;
|
|
7
|
+
}
|
|
8
|
+
/** User or service token info */
|
|
9
|
+
interface User {
|
|
10
|
+
id: string;
|
|
11
|
+
email?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
clerk_id?: string;
|
|
14
|
+
avatar_url?: string;
|
|
15
|
+
/** Present for service tokens */
|
|
16
|
+
auth_type?: 'service_token' | 'user';
|
|
17
|
+
/** Team ID (for service tokens) */
|
|
18
|
+
team_id?: string;
|
|
19
|
+
/** Project ID (for project-scoped service tokens) */
|
|
20
|
+
project_id?: string;
|
|
21
|
+
/** Token scopes (for service tokens) */
|
|
22
|
+
scopes?: string[];
|
|
23
|
+
created_at: string;
|
|
24
|
+
}
|
|
25
|
+
/** Project */
|
|
26
|
+
interface Project {
|
|
27
|
+
id: string;
|
|
28
|
+
team_id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
slug: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
created_at: string;
|
|
33
|
+
}
|
|
34
|
+
/** Environment */
|
|
35
|
+
interface Environment {
|
|
36
|
+
id: string;
|
|
37
|
+
project_id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
inherits_from?: string;
|
|
40
|
+
created_at: string;
|
|
41
|
+
}
|
|
42
|
+
/** Project with environments */
|
|
43
|
+
interface ProjectWithEnvironments extends Project {
|
|
44
|
+
environments: Environment[];
|
|
45
|
+
}
|
|
46
|
+
/** Secret (without value) */
|
|
47
|
+
interface Secret {
|
|
48
|
+
id: string;
|
|
49
|
+
environment_id: string;
|
|
50
|
+
key: string;
|
|
51
|
+
type: string;
|
|
52
|
+
description?: string;
|
|
53
|
+
version: number;
|
|
54
|
+
created_at: string;
|
|
55
|
+
updated_at: string;
|
|
56
|
+
}
|
|
57
|
+
/** Secret with decrypted value */
|
|
58
|
+
interface SecretWithValue extends Secret {
|
|
59
|
+
value: string;
|
|
60
|
+
inherited_from?: string;
|
|
61
|
+
}
|
|
62
|
+
/** Secret history entry */
|
|
63
|
+
interface SecretHistory {
|
|
64
|
+
id: string;
|
|
65
|
+
secret_id: string;
|
|
66
|
+
value: string;
|
|
67
|
+
version: number;
|
|
68
|
+
changed_by?: string;
|
|
69
|
+
changed_at: string;
|
|
70
|
+
}
|
|
71
|
+
/** Bulk import request item */
|
|
72
|
+
interface BulkSecretItem {
|
|
73
|
+
key: string;
|
|
74
|
+
value: string;
|
|
75
|
+
description?: string;
|
|
76
|
+
}
|
|
77
|
+
/** Bulk import result */
|
|
78
|
+
interface BulkImportResult {
|
|
79
|
+
created: number;
|
|
80
|
+
updated: number;
|
|
81
|
+
skipped: number;
|
|
82
|
+
}
|
|
83
|
+
/** KeyEnv API error */
|
|
84
|
+
declare class KeyEnvError extends Error {
|
|
85
|
+
readonly status: number;
|
|
86
|
+
readonly code?: string;
|
|
87
|
+
readonly details?: Record<string, unknown>;
|
|
88
|
+
constructor(message: string, status: number, code?: string, details?: Record<string, unknown>);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* KeyEnv API client for managing secrets
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* import { KeyEnv } from 'keyenv';
|
|
97
|
+
*
|
|
98
|
+
* const client = new KeyEnv({ token: process.env.KEYENV_TOKEN });
|
|
99
|
+
*
|
|
100
|
+
* // Export all secrets for an environment
|
|
101
|
+
* const secrets = await client.exportSecrets('project-id', 'production');
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
declare class KeyEnv {
|
|
105
|
+
private readonly token;
|
|
106
|
+
private readonly timeout;
|
|
107
|
+
constructor(options: KeyEnvOptions);
|
|
108
|
+
private request;
|
|
109
|
+
/** Get the current user or service token info */
|
|
110
|
+
getCurrentUser(): Promise<User>;
|
|
111
|
+
/** Validate the token and return user info */
|
|
112
|
+
validateToken(): Promise<User>;
|
|
113
|
+
/** List all accessible projects */
|
|
114
|
+
listProjects(): Promise<Project[]>;
|
|
115
|
+
/** Get a project by ID */
|
|
116
|
+
getProject(projectId: string): Promise<ProjectWithEnvironments>;
|
|
117
|
+
/** Create a new project */
|
|
118
|
+
createProject(teamId: string, name: string): Promise<Project>;
|
|
119
|
+
/** Delete a project */
|
|
120
|
+
deleteProject(projectId: string): Promise<void>;
|
|
121
|
+
/** List environments in a project */
|
|
122
|
+
listEnvironments(projectId: string): Promise<Environment[]>;
|
|
123
|
+
/** Create a new environment */
|
|
124
|
+
createEnvironment(projectId: string, name: string, inheritsFrom?: string): Promise<Environment>;
|
|
125
|
+
/** Delete an environment */
|
|
126
|
+
deleteEnvironment(projectId: string, environment: string): Promise<void>;
|
|
127
|
+
/** List secrets in an environment (keys and metadata only) */
|
|
128
|
+
listSecrets(projectId: string, environment: string): Promise<Secret[]>;
|
|
129
|
+
/**
|
|
130
|
+
* Export all secrets with their decrypted values
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* const secrets = await client.exportSecrets('project-id', 'production');
|
|
134
|
+
* for (const secret of secrets) {
|
|
135
|
+
* process.env[secret.key] = secret.value;
|
|
136
|
+
* }
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
exportSecrets(projectId: string, environment: string): Promise<SecretWithValue[]>;
|
|
140
|
+
/**
|
|
141
|
+
* Export secrets as a key-value object
|
|
142
|
+
* @example
|
|
143
|
+
* ```ts
|
|
144
|
+
* const env = await client.exportSecretsAsObject('project-id', 'production');
|
|
145
|
+
* // { DATABASE_URL: '...', API_KEY: '...' }
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
exportSecretsAsObject(projectId: string, environment: string): Promise<Record<string, string>>;
|
|
149
|
+
/** Get a single secret with its value */
|
|
150
|
+
getSecret(projectId: string, environment: string, key: string): Promise<SecretWithValue>;
|
|
151
|
+
/** Create a new secret */
|
|
152
|
+
createSecret(projectId: string, environment: string, key: string, value: string, description?: string): Promise<Secret>;
|
|
153
|
+
/** Update a secret's value */
|
|
154
|
+
updateSecret(projectId: string, environment: string, key: string, value: string, description?: string): Promise<Secret>;
|
|
155
|
+
/** Set a secret (create or update) */
|
|
156
|
+
setSecret(projectId: string, environment: string, key: string, value: string, description?: string): Promise<Secret>;
|
|
157
|
+
/** Delete a secret */
|
|
158
|
+
deleteSecret(projectId: string, environment: string, key: string): Promise<void>;
|
|
159
|
+
/** Get secret version history */
|
|
160
|
+
getSecretHistory(projectId: string, environment: string, key: string): Promise<SecretHistory[]>;
|
|
161
|
+
/**
|
|
162
|
+
* Bulk import secrets
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* await client.bulkImport('project-id', 'development', [
|
|
166
|
+
* { key: 'DATABASE_URL', value: 'postgres://...' },
|
|
167
|
+
* { key: 'API_KEY', value: 'sk_...' },
|
|
168
|
+
* ], { overwrite: true });
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
bulkImport(projectId: string, environment: string, secrets: BulkSecretItem[], options?: {
|
|
172
|
+
overwrite?: boolean;
|
|
173
|
+
}): Promise<BulkImportResult>;
|
|
174
|
+
/**
|
|
175
|
+
* Load secrets into process.env
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* await client.loadEnv('project-id', 'production');
|
|
179
|
+
* console.log(process.env.DATABASE_URL);
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
loadEnv(projectId: string, environment: string): Promise<number>;
|
|
183
|
+
/** Generate .env file content from secrets */
|
|
184
|
+
generateEnvFile(projectId: string, environment: string): Promise<string>;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export { type BulkImportResult, type BulkSecretItem, type Environment, KeyEnv, KeyEnvError, type KeyEnvOptions, type Project, type ProjectWithEnvironments, type Secret, type SecretHistory, type SecretWithValue, type User };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
KeyEnv: () => KeyEnv,
|
|
24
|
+
KeyEnvError: () => KeyEnvError
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/types.ts
|
|
29
|
+
var KeyEnvError = class extends Error {
|
|
30
|
+
status;
|
|
31
|
+
code;
|
|
32
|
+
details;
|
|
33
|
+
constructor(message, status, code, details) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.name = "KeyEnvError";
|
|
36
|
+
this.status = status;
|
|
37
|
+
this.code = code;
|
|
38
|
+
this.details = details;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// src/client.ts
|
|
43
|
+
var BASE_URL = "https://api.keyenv.dev";
|
|
44
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
45
|
+
var KeyEnv = class {
|
|
46
|
+
token;
|
|
47
|
+
timeout;
|
|
48
|
+
constructor(options) {
|
|
49
|
+
if (!options.token) {
|
|
50
|
+
throw new Error("KeyEnv token is required");
|
|
51
|
+
}
|
|
52
|
+
this.token = options.token;
|
|
53
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT;
|
|
54
|
+
}
|
|
55
|
+
async request(method, path, body) {
|
|
56
|
+
const url = `${BASE_URL}${path}`;
|
|
57
|
+
const controller = new AbortController();
|
|
58
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
59
|
+
try {
|
|
60
|
+
const response = await fetch(url, {
|
|
61
|
+
method,
|
|
62
|
+
headers: {
|
|
63
|
+
"Authorization": `Bearer ${this.token}`,
|
|
64
|
+
"Content-Type": "application/json",
|
|
65
|
+
"User-Agent": "keyenv-node/1.0.0"
|
|
66
|
+
},
|
|
67
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
68
|
+
signal: controller.signal
|
|
69
|
+
});
|
|
70
|
+
clearTimeout(timeoutId);
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
let errorData = { error: "Unknown error" };
|
|
73
|
+
try {
|
|
74
|
+
errorData = await response.json();
|
|
75
|
+
} catch {
|
|
76
|
+
errorData = { error: response.statusText };
|
|
77
|
+
}
|
|
78
|
+
throw new KeyEnvError(errorData.error, response.status, errorData.code, errorData.details);
|
|
79
|
+
}
|
|
80
|
+
if (response.status === 204) {
|
|
81
|
+
return void 0;
|
|
82
|
+
}
|
|
83
|
+
return response.json();
|
|
84
|
+
} catch (error) {
|
|
85
|
+
clearTimeout(timeoutId);
|
|
86
|
+
if (error instanceof KeyEnvError) throw error;
|
|
87
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
88
|
+
throw new KeyEnvError("Request timeout", 408);
|
|
89
|
+
}
|
|
90
|
+
throw new KeyEnvError(error instanceof Error ? error.message : "Network error", 0);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** Get the current user or service token info */
|
|
94
|
+
async getCurrentUser() {
|
|
95
|
+
return this.request("GET", "/api/v1/users/me");
|
|
96
|
+
}
|
|
97
|
+
/** Validate the token and return user info */
|
|
98
|
+
async validateToken() {
|
|
99
|
+
return this.getCurrentUser();
|
|
100
|
+
}
|
|
101
|
+
/** List all accessible projects */
|
|
102
|
+
async listProjects() {
|
|
103
|
+
const response = await this.request("GET", "/api/v1/projects");
|
|
104
|
+
return response.projects;
|
|
105
|
+
}
|
|
106
|
+
/** Get a project by ID */
|
|
107
|
+
async getProject(projectId) {
|
|
108
|
+
return this.request("GET", `/api/v1/projects/${projectId}`);
|
|
109
|
+
}
|
|
110
|
+
/** Create a new project */
|
|
111
|
+
async createProject(teamId, name) {
|
|
112
|
+
return this.request("POST", "/api/v1/projects", { team_id: teamId, name });
|
|
113
|
+
}
|
|
114
|
+
/** Delete a project */
|
|
115
|
+
async deleteProject(projectId) {
|
|
116
|
+
await this.request("DELETE", `/api/v1/projects/${projectId}`);
|
|
117
|
+
}
|
|
118
|
+
/** List environments in a project */
|
|
119
|
+
async listEnvironments(projectId) {
|
|
120
|
+
const response = await this.request(
|
|
121
|
+
"GET",
|
|
122
|
+
`/api/v1/projects/${projectId}/environments`
|
|
123
|
+
);
|
|
124
|
+
return response.environments;
|
|
125
|
+
}
|
|
126
|
+
/** Create a new environment */
|
|
127
|
+
async createEnvironment(projectId, name, inheritsFrom) {
|
|
128
|
+
return this.request(
|
|
129
|
+
"POST",
|
|
130
|
+
`/api/v1/projects/${projectId}/environments`,
|
|
131
|
+
{ name, inherits_from: inheritsFrom }
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
/** Delete an environment */
|
|
135
|
+
async deleteEnvironment(projectId, environment) {
|
|
136
|
+
await this.request("DELETE", `/api/v1/projects/${projectId}/environments/${environment}`);
|
|
137
|
+
}
|
|
138
|
+
/** List secrets in an environment (keys and metadata only) */
|
|
139
|
+
async listSecrets(projectId, environment) {
|
|
140
|
+
const response = await this.request(
|
|
141
|
+
"GET",
|
|
142
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets`
|
|
143
|
+
);
|
|
144
|
+
return response.secrets;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Export all secrets with their decrypted values
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* const secrets = await client.exportSecrets('project-id', 'production');
|
|
151
|
+
* for (const secret of secrets) {
|
|
152
|
+
* process.env[secret.key] = secret.value;
|
|
153
|
+
* }
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
async exportSecrets(projectId, environment) {
|
|
157
|
+
const response = await this.request(
|
|
158
|
+
"GET",
|
|
159
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets/export`
|
|
160
|
+
);
|
|
161
|
+
return response.secrets;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Export secrets as a key-value object
|
|
165
|
+
* @example
|
|
166
|
+
* ```ts
|
|
167
|
+
* const env = await client.exportSecretsAsObject('project-id', 'production');
|
|
168
|
+
* // { DATABASE_URL: '...', API_KEY: '...' }
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
async exportSecretsAsObject(projectId, environment) {
|
|
172
|
+
const secrets = await this.exportSecrets(projectId, environment);
|
|
173
|
+
return Object.fromEntries(secrets.map((s) => [s.key, s.value]));
|
|
174
|
+
}
|
|
175
|
+
/** Get a single secret with its value */
|
|
176
|
+
async getSecret(projectId, environment, key) {
|
|
177
|
+
const response = await this.request(
|
|
178
|
+
"GET",
|
|
179
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`
|
|
180
|
+
);
|
|
181
|
+
return response.secret;
|
|
182
|
+
}
|
|
183
|
+
/** Create a new secret */
|
|
184
|
+
async createSecret(projectId, environment, key, value, description) {
|
|
185
|
+
const response = await this.request(
|
|
186
|
+
"POST",
|
|
187
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets`,
|
|
188
|
+
{ key, value, description }
|
|
189
|
+
);
|
|
190
|
+
return response.secret;
|
|
191
|
+
}
|
|
192
|
+
/** Update a secret's value */
|
|
193
|
+
async updateSecret(projectId, environment, key, value, description) {
|
|
194
|
+
const response = await this.request(
|
|
195
|
+
"PUT",
|
|
196
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`,
|
|
197
|
+
{ value, description }
|
|
198
|
+
);
|
|
199
|
+
return response.secret;
|
|
200
|
+
}
|
|
201
|
+
/** Set a secret (create or update) */
|
|
202
|
+
async setSecret(projectId, environment, key, value, description) {
|
|
203
|
+
try {
|
|
204
|
+
return await this.updateSecret(projectId, environment, key, value, description);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if (error instanceof KeyEnvError && error.status === 404) {
|
|
207
|
+
return this.createSecret(projectId, environment, key, value, description);
|
|
208
|
+
}
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/** Delete a secret */
|
|
213
|
+
async deleteSecret(projectId, environment, key) {
|
|
214
|
+
await this.request(
|
|
215
|
+
"DELETE",
|
|
216
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
/** Get secret version history */
|
|
220
|
+
async getSecretHistory(projectId, environment, key) {
|
|
221
|
+
const response = await this.request(
|
|
222
|
+
"GET",
|
|
223
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}/history`
|
|
224
|
+
);
|
|
225
|
+
return response.history;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Bulk import secrets
|
|
229
|
+
* @example
|
|
230
|
+
* ```ts
|
|
231
|
+
* await client.bulkImport('project-id', 'development', [
|
|
232
|
+
* { key: 'DATABASE_URL', value: 'postgres://...' },
|
|
233
|
+
* { key: 'API_KEY', value: 'sk_...' },
|
|
234
|
+
* ], { overwrite: true });
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
async bulkImport(projectId, environment, secrets, options = {}) {
|
|
238
|
+
return this.request(
|
|
239
|
+
"POST",
|
|
240
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets/bulk`,
|
|
241
|
+
{ secrets, overwrite: options.overwrite ?? false }
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Load secrets into process.env
|
|
246
|
+
* @example
|
|
247
|
+
* ```ts
|
|
248
|
+
* await client.loadEnv('project-id', 'production');
|
|
249
|
+
* console.log(process.env.DATABASE_URL);
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
async loadEnv(projectId, environment) {
|
|
253
|
+
const secrets = await this.exportSecrets(projectId, environment);
|
|
254
|
+
for (const secret of secrets) {
|
|
255
|
+
process.env[secret.key] = secret.value;
|
|
256
|
+
}
|
|
257
|
+
return secrets.length;
|
|
258
|
+
}
|
|
259
|
+
/** Generate .env file content from secrets */
|
|
260
|
+
async generateEnvFile(projectId, environment) {
|
|
261
|
+
const secrets = await this.exportSecrets(projectId, environment);
|
|
262
|
+
const lines = [
|
|
263
|
+
"# Generated by KeyEnv",
|
|
264
|
+
`# Environment: ${environment}`,
|
|
265
|
+
`# Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
266
|
+
""
|
|
267
|
+
];
|
|
268
|
+
for (const secret of secrets) {
|
|
269
|
+
const value = secret.value;
|
|
270
|
+
if (value.includes("\n") || value.includes('"') || value.includes("'") || value.includes(" ")) {
|
|
271
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
272
|
+
lines.push(`${secret.key}="${escaped}"`);
|
|
273
|
+
} else {
|
|
274
|
+
lines.push(`${secret.key}=${value}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return lines.join("\n") + "\n";
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
281
|
+
0 && (module.exports = {
|
|
282
|
+
KeyEnv,
|
|
283
|
+
KeyEnvError
|
|
284
|
+
});
|
|
285
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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":"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","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// src/types.ts
|
|
2
|
+
var KeyEnvError = class extends Error {
|
|
3
|
+
status;
|
|
4
|
+
code;
|
|
5
|
+
details;
|
|
6
|
+
constructor(message, status, code, details) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "KeyEnvError";
|
|
9
|
+
this.status = status;
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.details = details;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// src/client.ts
|
|
16
|
+
var BASE_URL = "https://api.keyenv.dev";
|
|
17
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
18
|
+
var KeyEnv = class {
|
|
19
|
+
token;
|
|
20
|
+
timeout;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
if (!options.token) {
|
|
23
|
+
throw new Error("KeyEnv token is required");
|
|
24
|
+
}
|
|
25
|
+
this.token = options.token;
|
|
26
|
+
this.timeout = options.timeout || DEFAULT_TIMEOUT;
|
|
27
|
+
}
|
|
28
|
+
async request(method, path, body) {
|
|
29
|
+
const url = `${BASE_URL}${path}`;
|
|
30
|
+
const controller = new AbortController();
|
|
31
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
32
|
+
try {
|
|
33
|
+
const response = await fetch(url, {
|
|
34
|
+
method,
|
|
35
|
+
headers: {
|
|
36
|
+
"Authorization": `Bearer ${this.token}`,
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
"User-Agent": "keyenv-node/1.0.0"
|
|
39
|
+
},
|
|
40
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
41
|
+
signal: controller.signal
|
|
42
|
+
});
|
|
43
|
+
clearTimeout(timeoutId);
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
let errorData = { error: "Unknown error" };
|
|
46
|
+
try {
|
|
47
|
+
errorData = await response.json();
|
|
48
|
+
} catch {
|
|
49
|
+
errorData = { error: response.statusText };
|
|
50
|
+
}
|
|
51
|
+
throw new KeyEnvError(errorData.error, response.status, errorData.code, errorData.details);
|
|
52
|
+
}
|
|
53
|
+
if (response.status === 204) {
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
return response.json();
|
|
57
|
+
} catch (error) {
|
|
58
|
+
clearTimeout(timeoutId);
|
|
59
|
+
if (error instanceof KeyEnvError) throw error;
|
|
60
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
61
|
+
throw new KeyEnvError("Request timeout", 408);
|
|
62
|
+
}
|
|
63
|
+
throw new KeyEnvError(error instanceof Error ? error.message : "Network error", 0);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Get the current user or service token info */
|
|
67
|
+
async getCurrentUser() {
|
|
68
|
+
return this.request("GET", "/api/v1/users/me");
|
|
69
|
+
}
|
|
70
|
+
/** Validate the token and return user info */
|
|
71
|
+
async validateToken() {
|
|
72
|
+
return this.getCurrentUser();
|
|
73
|
+
}
|
|
74
|
+
/** List all accessible projects */
|
|
75
|
+
async listProjects() {
|
|
76
|
+
const response = await this.request("GET", "/api/v1/projects");
|
|
77
|
+
return response.projects;
|
|
78
|
+
}
|
|
79
|
+
/** Get a project by ID */
|
|
80
|
+
async getProject(projectId) {
|
|
81
|
+
return this.request("GET", `/api/v1/projects/${projectId}`);
|
|
82
|
+
}
|
|
83
|
+
/** Create a new project */
|
|
84
|
+
async createProject(teamId, name) {
|
|
85
|
+
return this.request("POST", "/api/v1/projects", { team_id: teamId, name });
|
|
86
|
+
}
|
|
87
|
+
/** Delete a project */
|
|
88
|
+
async deleteProject(projectId) {
|
|
89
|
+
await this.request("DELETE", `/api/v1/projects/${projectId}`);
|
|
90
|
+
}
|
|
91
|
+
/** List environments in a project */
|
|
92
|
+
async listEnvironments(projectId) {
|
|
93
|
+
const response = await this.request(
|
|
94
|
+
"GET",
|
|
95
|
+
`/api/v1/projects/${projectId}/environments`
|
|
96
|
+
);
|
|
97
|
+
return response.environments;
|
|
98
|
+
}
|
|
99
|
+
/** Create a new environment */
|
|
100
|
+
async createEnvironment(projectId, name, inheritsFrom) {
|
|
101
|
+
return this.request(
|
|
102
|
+
"POST",
|
|
103
|
+
`/api/v1/projects/${projectId}/environments`,
|
|
104
|
+
{ name, inherits_from: inheritsFrom }
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
/** Delete an environment */
|
|
108
|
+
async deleteEnvironment(projectId, environment) {
|
|
109
|
+
await this.request("DELETE", `/api/v1/projects/${projectId}/environments/${environment}`);
|
|
110
|
+
}
|
|
111
|
+
/** List secrets in an environment (keys and metadata only) */
|
|
112
|
+
async listSecrets(projectId, environment) {
|
|
113
|
+
const response = await this.request(
|
|
114
|
+
"GET",
|
|
115
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets`
|
|
116
|
+
);
|
|
117
|
+
return response.secrets;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Export all secrets with their decrypted values
|
|
121
|
+
* @example
|
|
122
|
+
* ```ts
|
|
123
|
+
* const secrets = await client.exportSecrets('project-id', 'production');
|
|
124
|
+
* for (const secret of secrets) {
|
|
125
|
+
* process.env[secret.key] = secret.value;
|
|
126
|
+
* }
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
async exportSecrets(projectId, environment) {
|
|
130
|
+
const response = await this.request(
|
|
131
|
+
"GET",
|
|
132
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets/export`
|
|
133
|
+
);
|
|
134
|
+
return response.secrets;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Export secrets as a key-value object
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* const env = await client.exportSecretsAsObject('project-id', 'production');
|
|
141
|
+
* // { DATABASE_URL: '...', API_KEY: '...' }
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
async exportSecretsAsObject(projectId, environment) {
|
|
145
|
+
const secrets = await this.exportSecrets(projectId, environment);
|
|
146
|
+
return Object.fromEntries(secrets.map((s) => [s.key, s.value]));
|
|
147
|
+
}
|
|
148
|
+
/** Get a single secret with its value */
|
|
149
|
+
async getSecret(projectId, environment, key) {
|
|
150
|
+
const response = await this.request(
|
|
151
|
+
"GET",
|
|
152
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`
|
|
153
|
+
);
|
|
154
|
+
return response.secret;
|
|
155
|
+
}
|
|
156
|
+
/** Create a new secret */
|
|
157
|
+
async createSecret(projectId, environment, key, value, description) {
|
|
158
|
+
const response = await this.request(
|
|
159
|
+
"POST",
|
|
160
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets`,
|
|
161
|
+
{ key, value, description }
|
|
162
|
+
);
|
|
163
|
+
return response.secret;
|
|
164
|
+
}
|
|
165
|
+
/** Update a secret's value */
|
|
166
|
+
async updateSecret(projectId, environment, key, value, description) {
|
|
167
|
+
const response = await this.request(
|
|
168
|
+
"PUT",
|
|
169
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`,
|
|
170
|
+
{ value, description }
|
|
171
|
+
);
|
|
172
|
+
return response.secret;
|
|
173
|
+
}
|
|
174
|
+
/** Set a secret (create or update) */
|
|
175
|
+
async setSecret(projectId, environment, key, value, description) {
|
|
176
|
+
try {
|
|
177
|
+
return await this.updateSecret(projectId, environment, key, value, description);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
if (error instanceof KeyEnvError && error.status === 404) {
|
|
180
|
+
return this.createSecret(projectId, environment, key, value, description);
|
|
181
|
+
}
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Delete a secret */
|
|
186
|
+
async deleteSecret(projectId, environment, key) {
|
|
187
|
+
await this.request(
|
|
188
|
+
"DELETE",
|
|
189
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
/** Get secret version history */
|
|
193
|
+
async getSecretHistory(projectId, environment, key) {
|
|
194
|
+
const response = await this.request(
|
|
195
|
+
"GET",
|
|
196
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets/${key}/history`
|
|
197
|
+
);
|
|
198
|
+
return response.history;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Bulk import secrets
|
|
202
|
+
* @example
|
|
203
|
+
* ```ts
|
|
204
|
+
* await client.bulkImport('project-id', 'development', [
|
|
205
|
+
* { key: 'DATABASE_URL', value: 'postgres://...' },
|
|
206
|
+
* { key: 'API_KEY', value: 'sk_...' },
|
|
207
|
+
* ], { overwrite: true });
|
|
208
|
+
* ```
|
|
209
|
+
*/
|
|
210
|
+
async bulkImport(projectId, environment, secrets, options = {}) {
|
|
211
|
+
return this.request(
|
|
212
|
+
"POST",
|
|
213
|
+
`/api/v1/projects/${projectId}/environments/${environment}/secrets/bulk`,
|
|
214
|
+
{ secrets, overwrite: options.overwrite ?? false }
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Load secrets into process.env
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* await client.loadEnv('project-id', 'production');
|
|
222
|
+
* console.log(process.env.DATABASE_URL);
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
async loadEnv(projectId, environment) {
|
|
226
|
+
const secrets = await this.exportSecrets(projectId, environment);
|
|
227
|
+
for (const secret of secrets) {
|
|
228
|
+
process.env[secret.key] = secret.value;
|
|
229
|
+
}
|
|
230
|
+
return secrets.length;
|
|
231
|
+
}
|
|
232
|
+
/** Generate .env file content from secrets */
|
|
233
|
+
async generateEnvFile(projectId, environment) {
|
|
234
|
+
const secrets = await this.exportSecrets(projectId, environment);
|
|
235
|
+
const lines = [
|
|
236
|
+
"# Generated by KeyEnv",
|
|
237
|
+
`# Environment: ${environment}`,
|
|
238
|
+
`# Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
239
|
+
""
|
|
240
|
+
];
|
|
241
|
+
for (const secret of secrets) {
|
|
242
|
+
const value = secret.value;
|
|
243
|
+
if (value.includes("\n") || value.includes('"') || value.includes("'") || value.includes(" ")) {
|
|
244
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
245
|
+
lines.push(`${secret.key}="${escaped}"`);
|
|
246
|
+
} else {
|
|
247
|
+
lines.push(`${secret.key}=${value}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return lines.join("\n") + "\n";
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
export {
|
|
254
|
+
KeyEnv,
|
|
255
|
+
KeyEnvError
|
|
256
|
+
};
|
|
257
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/client.ts"],"sourcesContent":["/** 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":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "keyenv",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official Node.js SDK for KeyEnv - Secure secrets management",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:watch": "vitest",
|
|
22
|
+
"lint": "eslint src --ext .ts",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"keyenv",
|
|
28
|
+
"secrets",
|
|
29
|
+
"environment",
|
|
30
|
+
"env",
|
|
31
|
+
"dotenv",
|
|
32
|
+
"secrets-management",
|
|
33
|
+
"configuration"
|
|
34
|
+
],
|
|
35
|
+
"author": "KeyEnv",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/keyenv/node-sdk.git"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://keyenv.dev",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/keyenv/node-sdk/issues"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^22.0.0",
|
|
50
|
+
"tsup": "^8.0.0",
|
|
51
|
+
"typescript": "^5.0.0",
|
|
52
|
+
"vitest": "^2.0.0"
|
|
53
|
+
}
|
|
54
|
+
}
|