learn-secrets-sdk 1.4.0 → 1.5.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/README.md +192 -72
- package/bin/learn-secrets.js +5 -2
- package/dist/chunk-AS6G7JYX.mjs +1 -0
- package/dist/cli/chunk-Y6FXYEAI.mjs +10 -0
- package/dist/cli/env-resolver-4ASC2IMR.mjs +66 -0
- package/dist/cli/{index.d.ts → index.d.mts} +0 -1
- package/dist/cli/index.mjs +838 -0
- package/dist/env-resolver-Y4SFGOKB.mjs +1 -0
- package/dist/index.d.mts +385 -0
- package/dist/index.d.ts +385 -5
- package/dist/index.global.js +7 -0
- package/dist/index.mjs +7 -0
- package/package.json +12 -5
- package/dist/cli/commands/init.d.ts +0 -11
- package/dist/cli/commands/init.js +0 -113
- package/dist/cli/commands/login.d.ts +0 -7
- package/dist/cli/commands/login.js +0 -22
- package/dist/cli/index.js +0 -35
- package/dist/cli/utils/env-parser.d.ts +0 -19
- package/dist/cli/utils/env-parser.js +0 -47
- package/dist/cli/utils/key-detector.d.ts +0 -33
- package/dist/cli/utils/key-detector.js +0 -153
- package/dist/client.d.ts +0 -65
- package/dist/client.js +0 -172
- package/dist/credentials.d.ts +0 -24
- package/dist/credentials.js +0 -86
- package/dist/env-resolver.d.ts +0 -23
- package/dist/env-resolver.js +0 -73
- package/dist/index.js +0 -4
- package/dist/management.d.ts +0 -98
- package/dist/management.js +0 -214
- package/dist/types.d.ts +0 -123
- package/dist/types.js +0 -29
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
export interface EnvVariable {
|
|
2
|
-
key: string;
|
|
3
|
-
value: string;
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Parse a .env file into key-value pairs
|
|
7
|
-
* Supports:
|
|
8
|
-
* - KEY=value
|
|
9
|
-
* - KEY="value"
|
|
10
|
-
* - KEY='value'
|
|
11
|
-
* - # comments
|
|
12
|
-
* - Empty lines
|
|
13
|
-
*/
|
|
14
|
-
export declare function parseEnvFile(filePath: string): EnvVariable[];
|
|
15
|
-
/**
|
|
16
|
-
* Load environment variables from a .env file
|
|
17
|
-
* Returns a Map for easy lookup
|
|
18
|
-
*/
|
|
19
|
-
export declare function loadEnvFile(filePath: string): Map<string, string>;
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { readFileSync, existsSync } from 'fs';
|
|
2
|
-
import { resolve } from 'path';
|
|
3
|
-
/**
|
|
4
|
-
* Parse a .env file into key-value pairs
|
|
5
|
-
* Supports:
|
|
6
|
-
* - KEY=value
|
|
7
|
-
* - KEY="value"
|
|
8
|
-
* - KEY='value'
|
|
9
|
-
* - # comments
|
|
10
|
-
* - Empty lines
|
|
11
|
-
*/
|
|
12
|
-
export function parseEnvFile(filePath) {
|
|
13
|
-
const resolvedPath = resolve(filePath);
|
|
14
|
-
if (!existsSync(resolvedPath)) {
|
|
15
|
-
throw new Error(`File not found: ${resolvedPath}`);
|
|
16
|
-
}
|
|
17
|
-
const content = readFileSync(resolvedPath, 'utf-8');
|
|
18
|
-
const lines = content.split('\n');
|
|
19
|
-
const variables = [];
|
|
20
|
-
for (const line of lines) {
|
|
21
|
-
const trimmed = line.trim();
|
|
22
|
-
// Skip empty lines and comments
|
|
23
|
-
if (!trimmed || trimmed.startsWith('#')) {
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
// Match KEY=value, KEY="value", or KEY='value'
|
|
27
|
-
const match = trimmed.match(/^([A-Z0-9_]+)\s*=\s*(['"]?)(.+?)\2$/i);
|
|
28
|
-
if (match) {
|
|
29
|
-
const key = match[1];
|
|
30
|
-
const value = match[3];
|
|
31
|
-
variables.push({ key, value });
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return variables;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Load environment variables from a .env file
|
|
38
|
-
* Returns a Map for easy lookup
|
|
39
|
-
*/
|
|
40
|
-
export function loadEnvFile(filePath) {
|
|
41
|
-
const variables = parseEnvFile(filePath);
|
|
42
|
-
const map = new Map();
|
|
43
|
-
for (const { key, value } of variables) {
|
|
44
|
-
map.set(key, value);
|
|
45
|
-
}
|
|
46
|
-
return map;
|
|
47
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { SecretConfig } from '../../types.js';
|
|
2
|
-
import type { EnvVariable } from './env-parser.js';
|
|
3
|
-
interface ProviderPattern {
|
|
4
|
-
pattern: RegExp;
|
|
5
|
-
provider: string;
|
|
6
|
-
baseUrl?: string;
|
|
7
|
-
authHeader?: string;
|
|
8
|
-
authPrefix?: string;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Detect if an environment variable is likely an API key
|
|
12
|
-
*/
|
|
13
|
-
export declare function isLikelyApiKey(key: string, value: string): boolean;
|
|
14
|
-
/**
|
|
15
|
-
* Detect provider from environment variable name
|
|
16
|
-
*/
|
|
17
|
-
export declare function detectProvider(key: string): ProviderPattern | null;
|
|
18
|
-
/**
|
|
19
|
-
* Convert environment variable to secret name
|
|
20
|
-
* OPENAI_API_KEY -> openai
|
|
21
|
-
* MY_API_KEY -> my-api
|
|
22
|
-
*/
|
|
23
|
-
export declare function envKeyToSecretName(key: string): string;
|
|
24
|
-
/**
|
|
25
|
-
* Detect API keys from environment variables
|
|
26
|
-
* Returns SecretConfig array ready for import
|
|
27
|
-
*/
|
|
28
|
-
export declare function detectApiKeys(envVars: EnvVariable[]): SecretConfig[];
|
|
29
|
-
/**
|
|
30
|
-
* Display detected secrets summary (for user confirmation)
|
|
31
|
-
*/
|
|
32
|
-
export declare function summarizeDetectedSecrets(secrets: SecretConfig[]): string;
|
|
33
|
-
export {};
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Common API key patterns and their providers
|
|
3
|
-
*/
|
|
4
|
-
const PROVIDER_PATTERNS = [
|
|
5
|
-
{
|
|
6
|
-
pattern: /^OPENAI_API_KEY$/i,
|
|
7
|
-
provider: 'openai',
|
|
8
|
-
baseUrl: 'https://api.openai.com',
|
|
9
|
-
authHeader: 'Authorization',
|
|
10
|
-
authPrefix: 'Bearer '
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
pattern: /^ANTHROPIC_API_KEY$/i,
|
|
14
|
-
provider: 'anthropic',
|
|
15
|
-
baseUrl: 'https://api.anthropic.com',
|
|
16
|
-
authHeader: 'x-api-key',
|
|
17
|
-
authPrefix: ''
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
pattern: /^STRIPE_(SECRET_)?KEY$/i,
|
|
21
|
-
provider: 'stripe',
|
|
22
|
-
baseUrl: 'https://api.stripe.com',
|
|
23
|
-
authHeader: 'Authorization',
|
|
24
|
-
authPrefix: 'Bearer '
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
pattern: /^GITHUB_TOKEN$/i,
|
|
28
|
-
provider: 'github',
|
|
29
|
-
baseUrl: 'https://api.github.com',
|
|
30
|
-
authHeader: 'Authorization',
|
|
31
|
-
authPrefix: 'Bearer '
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
pattern: /^GOOGLE_API_KEY$/i,
|
|
35
|
-
provider: 'google',
|
|
36
|
-
baseUrl: 'https://www.googleapis.com',
|
|
37
|
-
authHeader: 'Authorization',
|
|
38
|
-
authPrefix: 'Bearer '
|
|
39
|
-
}
|
|
40
|
-
];
|
|
41
|
-
/**
|
|
42
|
-
* Detect if an environment variable is likely an API key
|
|
43
|
-
*/
|
|
44
|
-
export function isLikelyApiKey(key, value) {
|
|
45
|
-
// Check common patterns
|
|
46
|
-
const keyPatterns = [
|
|
47
|
-
/_API_KEY$/i,
|
|
48
|
-
/_SECRET$/i,
|
|
49
|
-
/_TOKEN$/i,
|
|
50
|
-
/^API_KEY_/i,
|
|
51
|
-
/^SECRET_/i,
|
|
52
|
-
/^TOKEN_/i
|
|
53
|
-
];
|
|
54
|
-
for (const pattern of keyPatterns) {
|
|
55
|
-
if (pattern.test(key)) {
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
// Check value patterns (looks like a key/token)
|
|
60
|
-
const valuePatterns = [
|
|
61
|
-
/^sk-[a-zA-Z0-9_-]+$/, // OpenAI, Stripe
|
|
62
|
-
/^sk-ant-[a-zA-Z0-9_-]+$/, // Anthropic
|
|
63
|
-
/^ghp_[a-zA-Z0-9]+$/, // GitHub
|
|
64
|
-
/^ya29\.[a-zA-Z0-9_-]+$/, // Google OAuth
|
|
65
|
-
/^[a-f0-9]{32}$/, // 32-char hex
|
|
66
|
-
/^[a-f0-9]{40}$/, // 40-char hex (like GitHub)
|
|
67
|
-
/^[a-zA-Z0-9_-]{40,}$/ // Long random string
|
|
68
|
-
];
|
|
69
|
-
for (const pattern of valuePatterns) {
|
|
70
|
-
if (pattern.test(value)) {
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Detect provider from environment variable name
|
|
78
|
-
*/
|
|
79
|
-
export function detectProvider(key) {
|
|
80
|
-
for (const pattern of PROVIDER_PATTERNS) {
|
|
81
|
-
if (pattern.pattern.test(key)) {
|
|
82
|
-
return pattern;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Convert environment variable to secret name
|
|
89
|
-
* OPENAI_API_KEY -> openai
|
|
90
|
-
* MY_API_KEY -> my-api
|
|
91
|
-
*/
|
|
92
|
-
export function envKeyToSecretName(key) {
|
|
93
|
-
return key
|
|
94
|
-
.toLowerCase()
|
|
95
|
-
.replace(/_api_key$/i, '')
|
|
96
|
-
.replace(/_secret$/i, '')
|
|
97
|
-
.replace(/_token$/i, '')
|
|
98
|
-
.replace(/_key$/i, '')
|
|
99
|
-
.replace(/_/g, '-');
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Detect API keys from environment variables
|
|
103
|
-
* Returns SecretConfig array ready for import
|
|
104
|
-
*/
|
|
105
|
-
export function detectApiKeys(envVars) {
|
|
106
|
-
const secrets = [];
|
|
107
|
-
for (const { key, value } of envVars) {
|
|
108
|
-
// Skip if doesn't look like an API key
|
|
109
|
-
if (!isLikelyApiKey(key, value)) {
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
// Detect provider
|
|
113
|
-
const providerInfo = detectProvider(key);
|
|
114
|
-
const secretName = envKeyToSecretName(key);
|
|
115
|
-
if (providerInfo) {
|
|
116
|
-
// Known provider
|
|
117
|
-
secrets.push({
|
|
118
|
-
name: secretName,
|
|
119
|
-
provider: providerInfo.provider,
|
|
120
|
-
api_key: value,
|
|
121
|
-
base_url: providerInfo.baseUrl,
|
|
122
|
-
auth_header: providerInfo.authHeader,
|
|
123
|
-
auth_prefix: providerInfo.authPrefix
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
// Custom/unknown provider
|
|
128
|
-
secrets.push({
|
|
129
|
-
name: secretName,
|
|
130
|
-
provider: 'custom',
|
|
131
|
-
api_key: value,
|
|
132
|
-
base_url: '', // User must configure
|
|
133
|
-
auth_header: 'Authorization',
|
|
134
|
-
auth_prefix: 'Bearer '
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return secrets;
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Display detected secrets summary (for user confirmation)
|
|
142
|
-
*/
|
|
143
|
-
export function summarizeDetectedSecrets(secrets) {
|
|
144
|
-
if (secrets.length === 0) {
|
|
145
|
-
return 'No API keys detected in .env file';
|
|
146
|
-
}
|
|
147
|
-
const lines = ['Detected API keys:'];
|
|
148
|
-
for (const secret of secrets) {
|
|
149
|
-
const masked = secret.api_key.substring(0, 8) + '...';
|
|
150
|
-
lines.push(` - ${secret.name} (${secret.provider}): ${masked}`);
|
|
151
|
-
}
|
|
152
|
-
return lines.join('\n');
|
|
153
|
-
}
|
package/dist/client.d.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import type { SecretsSDKOptions, ProxyRequest, RateLimitInfo } from './types.js';
|
|
2
|
-
export declare class SecretsSDK {
|
|
3
|
-
private appId;
|
|
4
|
-
private token;
|
|
5
|
-
private baseUrl;
|
|
6
|
-
private timeout;
|
|
7
|
-
private retryOn429;
|
|
8
|
-
private rateLimitInfo;
|
|
9
|
-
private zeroConfigMode;
|
|
10
|
-
/**
|
|
11
|
-
* Create a new SecretsSDK instance
|
|
12
|
-
*
|
|
13
|
-
* Zero-config mode (recommended for static sites):
|
|
14
|
-
* const sdk = new SecretsSDK();
|
|
15
|
-
* // Origin header is used for authentication
|
|
16
|
-
*
|
|
17
|
-
* Token mode (for backward compatibility):
|
|
18
|
-
* const sdk = new SecretsSDK({ appId: '...', token: 'sk_live_...' });
|
|
19
|
-
*/
|
|
20
|
-
constructor(options?: SecretsSDKOptions);
|
|
21
|
-
/**
|
|
22
|
-
* Get current rate limit information
|
|
23
|
-
*/
|
|
24
|
-
getUsage(): RateLimitInfo | null;
|
|
25
|
-
/**
|
|
26
|
-
* Parse rate limit headers from response
|
|
27
|
-
*/
|
|
28
|
-
private parseRateLimitHeaders;
|
|
29
|
-
/**
|
|
30
|
-
* Sleep utility for retry backoff
|
|
31
|
-
*/
|
|
32
|
-
private sleep;
|
|
33
|
-
/**
|
|
34
|
-
* Make fetch request with timeout
|
|
35
|
-
*/
|
|
36
|
-
private fetchWithTimeout;
|
|
37
|
-
/**
|
|
38
|
-
* Call an external API securely through the proxy
|
|
39
|
-
* @param keyName - Name of the API key to use
|
|
40
|
-
* @param endpoint - API endpoint path (e.g., '/v1/chat/completions')
|
|
41
|
-
* @param options - Request options (method, body, headers)
|
|
42
|
-
* @returns Promise with the API response
|
|
43
|
-
*/
|
|
44
|
-
call<T = any>(keyName: string, endpoint: string, options?: Omit<ProxyRequest, 'keyName' | 'endpoint'>): Promise<T>;
|
|
45
|
-
/**
|
|
46
|
-
* Make a GET request
|
|
47
|
-
*/
|
|
48
|
-
get<T = any>(keyName: string, endpoint: string, headers?: Record<string, string>): Promise<T>;
|
|
49
|
-
/**
|
|
50
|
-
* Make a POST request
|
|
51
|
-
*/
|
|
52
|
-
post<T = any>(keyName: string, endpoint: string, body: any, headers?: Record<string, string>): Promise<T>;
|
|
53
|
-
/**
|
|
54
|
-
* Make a PUT request
|
|
55
|
-
*/
|
|
56
|
-
put<T = any>(keyName: string, endpoint: string, body: any, headers?: Record<string, string>): Promise<T>;
|
|
57
|
-
/**
|
|
58
|
-
* Make a DELETE request
|
|
59
|
-
*/
|
|
60
|
-
delete<T = any>(keyName: string, endpoint: string, headers?: Record<string, string>): Promise<T>;
|
|
61
|
-
/**
|
|
62
|
-
* Make a PATCH request
|
|
63
|
-
*/
|
|
64
|
-
patch<T = any>(keyName: string, endpoint: string, body: any, headers?: Record<string, string>): Promise<T>;
|
|
65
|
-
}
|
package/dist/client.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import { SecretsSDKError, OriginMismatchError, RateLimitError, InvalidTokenError } from './types.js';
|
|
2
|
-
export class SecretsSDK {
|
|
3
|
-
/**
|
|
4
|
-
* Create a new SecretsSDK instance
|
|
5
|
-
*
|
|
6
|
-
* Zero-config mode (recommended for static sites):
|
|
7
|
-
* const sdk = new SecretsSDK();
|
|
8
|
-
* // Origin header is used for authentication
|
|
9
|
-
*
|
|
10
|
-
* Token mode (for backward compatibility):
|
|
11
|
-
* const sdk = new SecretsSDK({ appId: '...', token: 'sk_live_...' });
|
|
12
|
-
*/
|
|
13
|
-
constructor(options = {}) {
|
|
14
|
-
this.rateLimitInfo = null;
|
|
15
|
-
this.appId = options.appId || null;
|
|
16
|
-
this.token = options.token || options.sessionToken || null;
|
|
17
|
-
this.baseUrl = options.baseUrl || 'https://ctklearn.carsontkempf.workers.dev';
|
|
18
|
-
this.timeout = options.timeout || 30000;
|
|
19
|
-
this.retryOn429 = options.retryOn429 !== undefined ? options.retryOn429 : true;
|
|
20
|
-
// Zero-config mode: no appId or token required
|
|
21
|
-
// Authentication is based on Origin header
|
|
22
|
-
this.zeroConfigMode = !this.appId && !this.token;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Get current rate limit information
|
|
26
|
-
*/
|
|
27
|
-
getUsage() {
|
|
28
|
-
return this.rateLimitInfo;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Parse rate limit headers from response
|
|
32
|
-
*/
|
|
33
|
-
parseRateLimitHeaders(headers) {
|
|
34
|
-
const limit = headers.get('X-RateLimit-Limit');
|
|
35
|
-
const remaining = headers.get('X-RateLimit-Remaining');
|
|
36
|
-
const reset = headers.get('X-RateLimit-Reset');
|
|
37
|
-
if (limit && remaining && reset) {
|
|
38
|
-
this.rateLimitInfo = {
|
|
39
|
-
limit: parseInt(limit),
|
|
40
|
-
remaining: parseInt(remaining),
|
|
41
|
-
reset: parseInt(reset)
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Sleep utility for retry backoff
|
|
47
|
-
*/
|
|
48
|
-
sleep(ms) {
|
|
49
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Make fetch request with timeout
|
|
53
|
-
*/
|
|
54
|
-
async fetchWithTimeout(url, options, timeout) {
|
|
55
|
-
const controller = new AbortController();
|
|
56
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
57
|
-
try {
|
|
58
|
-
const response = await fetch(url, {
|
|
59
|
-
...options,
|
|
60
|
-
signal: controller.signal
|
|
61
|
-
});
|
|
62
|
-
return response;
|
|
63
|
-
}
|
|
64
|
-
finally {
|
|
65
|
-
clearTimeout(timeoutId);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Call an external API securely through the proxy
|
|
70
|
-
* @param keyName - Name of the API key to use
|
|
71
|
-
* @param endpoint - API endpoint path (e.g., '/v1/chat/completions')
|
|
72
|
-
* @param options - Request options (method, body, headers)
|
|
73
|
-
* @returns Promise with the API response
|
|
74
|
-
*/
|
|
75
|
-
async call(keyName, endpoint, options = {}) {
|
|
76
|
-
let retries = 0;
|
|
77
|
-
const maxRetries = this.retryOn429 ? 3 : 0;
|
|
78
|
-
while (true) {
|
|
79
|
-
try {
|
|
80
|
-
// Build URL based on mode
|
|
81
|
-
const proxyUrl = this.zeroConfigMode
|
|
82
|
-
? `${this.baseUrl}/api/sdk/proxy`
|
|
83
|
-
: `${this.baseUrl}/api/sdk/${this.appId}/proxy`;
|
|
84
|
-
// Build headers based on mode
|
|
85
|
-
const requestHeaders = {
|
|
86
|
-
'Content-Type': 'application/json'
|
|
87
|
-
};
|
|
88
|
-
if (!this.zeroConfigMode && this.token) {
|
|
89
|
-
requestHeaders['Authorization'] = `Bearer ${this.token}`;
|
|
90
|
-
}
|
|
91
|
-
const response = await this.fetchWithTimeout(proxyUrl, {
|
|
92
|
-
method: 'POST',
|
|
93
|
-
headers: requestHeaders,
|
|
94
|
-
body: JSON.stringify({
|
|
95
|
-
keyName,
|
|
96
|
-
endpoint,
|
|
97
|
-
method: options.method || 'GET',
|
|
98
|
-
body: options.body,
|
|
99
|
-
headers: options.headers
|
|
100
|
-
})
|
|
101
|
-
}, this.timeout);
|
|
102
|
-
this.parseRateLimitHeaders(response.headers);
|
|
103
|
-
const result = await response.json();
|
|
104
|
-
if (!response.ok) {
|
|
105
|
-
const errorMessage = result.data?.message ||
|
|
106
|
-
result?.message ||
|
|
107
|
-
`Request failed with status ${response.status}`;
|
|
108
|
-
if (response.status === 403 && errorMessage.includes('Origin')) {
|
|
109
|
-
throw new OriginMismatchError(errorMessage);
|
|
110
|
-
}
|
|
111
|
-
if (response.status === 401) {
|
|
112
|
-
throw new InvalidTokenError(errorMessage);
|
|
113
|
-
}
|
|
114
|
-
if (response.status === 429) {
|
|
115
|
-
const retryAfter = this.rateLimitInfo
|
|
116
|
-
? this.rateLimitInfo.reset - Math.floor(Date.now() / 1000)
|
|
117
|
-
: 60;
|
|
118
|
-
const error = new RateLimitError(errorMessage, retryAfter, this.rateLimitInfo?.remaining || 0, this.rateLimitInfo?.limit || 100);
|
|
119
|
-
if (this.retryOn429 && retries < maxRetries) {
|
|
120
|
-
retries++;
|
|
121
|
-
const backoffMs = Math.min(1000 * Math.pow(2, retries - 1), 8000);
|
|
122
|
-
await this.sleep(backoffMs);
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
throw error;
|
|
126
|
-
}
|
|
127
|
-
throw new SecretsSDKError(errorMessage, response.status, result);
|
|
128
|
-
}
|
|
129
|
-
return result.data;
|
|
130
|
-
}
|
|
131
|
-
catch (err) {
|
|
132
|
-
if (err instanceof SecretsSDKError) {
|
|
133
|
-
throw err;
|
|
134
|
-
}
|
|
135
|
-
if (err instanceof Error && err.name === 'AbortError') {
|
|
136
|
-
throw new SecretsSDKError('Request timeout', 408);
|
|
137
|
-
}
|
|
138
|
-
throw new SecretsSDKError(err instanceof Error ? err.message : 'Unknown error occurred', 500);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Make a GET request
|
|
144
|
-
*/
|
|
145
|
-
async get(keyName, endpoint, headers) {
|
|
146
|
-
return this.call(keyName, endpoint, { method: 'GET', headers });
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Make a POST request
|
|
150
|
-
*/
|
|
151
|
-
async post(keyName, endpoint, body, headers) {
|
|
152
|
-
return this.call(keyName, endpoint, { method: 'POST', body, headers });
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Make a PUT request
|
|
156
|
-
*/
|
|
157
|
-
async put(keyName, endpoint, body, headers) {
|
|
158
|
-
return this.call(keyName, endpoint, { method: 'PUT', body, headers });
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Make a DELETE request
|
|
162
|
-
*/
|
|
163
|
-
async delete(keyName, endpoint, headers) {
|
|
164
|
-
return this.call(keyName, endpoint, { method: 'DELETE', headers });
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Make a PATCH request
|
|
168
|
-
*/
|
|
169
|
-
async patch(keyName, endpoint, body, headers) {
|
|
170
|
-
return this.call(keyName, endpoint, { method: 'PATCH', body, headers });
|
|
171
|
-
}
|
|
172
|
-
}
|
package/dist/credentials.d.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { CLICredentials } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Get the path to the credentials file
|
|
4
|
-
* Defaults to ~/.learn/credentials.json
|
|
5
|
-
*/
|
|
6
|
-
export declare function getCredentialsPath(): string;
|
|
7
|
-
/**
|
|
8
|
-
* Read credentials from file
|
|
9
|
-
* Returns null if file doesn't exist or is invalid
|
|
10
|
-
*/
|
|
11
|
-
export declare function readCredentials(): CLICredentials | null;
|
|
12
|
-
/**
|
|
13
|
-
* Write credentials to file
|
|
14
|
-
* Creates ~/.learn directory if it doesn't exist
|
|
15
|
-
*/
|
|
16
|
-
export declare function writeCredentials(creds: CLICredentials): void;
|
|
17
|
-
/**
|
|
18
|
-
* Delete credentials file
|
|
19
|
-
*/
|
|
20
|
-
export declare function deleteCredentials(): void;
|
|
21
|
-
/**
|
|
22
|
-
* Check if credentials exist and are not expired
|
|
23
|
-
*/
|
|
24
|
-
export declare function hasValidCredentials(): boolean;
|
package/dist/credentials.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import * as fs from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import * as os from 'os';
|
|
4
|
-
/**
|
|
5
|
-
* Get the path to the credentials file
|
|
6
|
-
* Defaults to ~/.learn/credentials.json
|
|
7
|
-
*/
|
|
8
|
-
export function getCredentialsPath() {
|
|
9
|
-
const homeDir = os.homedir();
|
|
10
|
-
const learnDir = path.join(homeDir, '.learn');
|
|
11
|
-
return path.join(learnDir, 'credentials.json');
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Ensure the ~/.learn directory exists
|
|
15
|
-
*/
|
|
16
|
-
function ensureLearnDir() {
|
|
17
|
-
const homeDir = os.homedir();
|
|
18
|
-
const learnDir = path.join(homeDir, '.learn');
|
|
19
|
-
if (!fs.existsSync(learnDir)) {
|
|
20
|
-
fs.mkdirSync(learnDir, { recursive: true, mode: 0o700 }); // Owner-only permissions
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Read credentials from file
|
|
25
|
-
* Returns null if file doesn't exist or is invalid
|
|
26
|
-
*/
|
|
27
|
-
export function readCredentials() {
|
|
28
|
-
try {
|
|
29
|
-
const credPath = getCredentialsPath();
|
|
30
|
-
if (!fs.existsSync(credPath)) {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
const data = fs.readFileSync(credPath, 'utf-8');
|
|
34
|
-
const creds = JSON.parse(data);
|
|
35
|
-
// Validate required fields
|
|
36
|
-
if (!creds.access_token ||
|
|
37
|
-
!creds.refresh_token ||
|
|
38
|
-
!creds.expires_at ||
|
|
39
|
-
!creds.user_id) {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
return creds;
|
|
43
|
-
}
|
|
44
|
-
catch (err) {
|
|
45
|
-
// Invalid JSON or read error
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Write credentials to file
|
|
51
|
-
* Creates ~/.learn directory if it doesn't exist
|
|
52
|
-
*/
|
|
53
|
-
export function writeCredentials(creds) {
|
|
54
|
-
ensureLearnDir();
|
|
55
|
-
const credPath = getCredentialsPath();
|
|
56
|
-
const data = JSON.stringify(creds, null, 2);
|
|
57
|
-
// Write with owner-only permissions
|
|
58
|
-
fs.writeFileSync(credPath, data, { mode: 0o600 });
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Delete credentials file
|
|
62
|
-
*/
|
|
63
|
-
export function deleteCredentials() {
|
|
64
|
-
try {
|
|
65
|
-
const credPath = getCredentialsPath();
|
|
66
|
-
if (fs.existsSync(credPath)) {
|
|
67
|
-
fs.unlinkSync(credPath);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
catch (err) {
|
|
71
|
-
// Ignore errors (file might not exist)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Check if credentials exist and are not expired
|
|
76
|
-
*/
|
|
77
|
-
export function hasValidCredentials() {
|
|
78
|
-
const creds = readCredentials();
|
|
79
|
-
if (!creds) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
// Check if expired
|
|
83
|
-
const expiresAt = new Date(creds.expires_at);
|
|
84
|
-
const now = new Date();
|
|
85
|
-
return expiresAt > now;
|
|
86
|
-
}
|
package/dist/env-resolver.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { SecretConfig } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Resolve environment variable references in a string
|
|
4
|
-
* Supports ${VAR} and $VAR syntax
|
|
5
|
-
*/
|
|
6
|
-
export declare function resolveEnvString(value: string): string;
|
|
7
|
-
/**
|
|
8
|
-
* Resolve environment variables in a single secret config
|
|
9
|
-
*/
|
|
10
|
-
export declare function resolveEnvInSecret(secret: SecretConfig): SecretConfig;
|
|
11
|
-
/**
|
|
12
|
-
* Resolve environment variables in an array of secrets
|
|
13
|
-
*/
|
|
14
|
-
export declare function resolveEnvInSecrets(secrets: SecretConfig[]): SecretConfig[];
|
|
15
|
-
/**
|
|
16
|
-
* Load and parse a secrets config file
|
|
17
|
-
* Resolves environment variables in the config
|
|
18
|
-
*/
|
|
19
|
-
export declare function loadSecretsConfig(configPath: string): {
|
|
20
|
-
version: string;
|
|
21
|
-
project: string;
|
|
22
|
-
secrets: SecretConfig[];
|
|
23
|
-
};
|