learn-secrets-sdk 1.11.7 → 1.11.11
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/dist/browser-global.global.js +288 -1
- package/dist/cli/index.mjs +5 -5
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +2 -2
- package/package.json +2 -2
|
@@ -1 +1,288 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
(() => {
|
|
3
|
+
// src/types.ts
|
|
4
|
+
var SecretsSDKError = class extends Error {
|
|
5
|
+
constructor(message, status, response) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.response = response;
|
|
9
|
+
this.name = "SecretsSDKError";
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var OriginMismatchError = class extends SecretsSDKError {
|
|
13
|
+
constructor(message = "Origin not allowed for this token") {
|
|
14
|
+
super(message, 403);
|
|
15
|
+
this.name = "OriginMismatchError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var RateLimitError = class extends SecretsSDKError {
|
|
19
|
+
constructor(message = "Rate limit exceeded", retryAfter = 60, remaining = 0, limit = 100) {
|
|
20
|
+
super(message, 429);
|
|
21
|
+
this.name = "RateLimitError";
|
|
22
|
+
this.retryAfter = retryAfter;
|
|
23
|
+
this.remaining = remaining;
|
|
24
|
+
this.limit = limit;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
var InvalidTokenError = class extends SecretsSDKError {
|
|
28
|
+
constructor(message = "Invalid or expired token") {
|
|
29
|
+
super(message, 401);
|
|
30
|
+
this.name = "InvalidTokenError";
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// src/client.ts
|
|
35
|
+
var SecretsSDK = class {
|
|
36
|
+
/**
|
|
37
|
+
* Create a new SecretsSDK instance
|
|
38
|
+
*
|
|
39
|
+
* Zero-config mode (recommended for static sites):
|
|
40
|
+
* const sdk = new SecretsSDK();
|
|
41
|
+
* // Origin header is used for authentication
|
|
42
|
+
*
|
|
43
|
+
* Token mode (for backward compatibility):
|
|
44
|
+
* const sdk = new SecretsSDK({ appId: '...', token: 'sk_live_...' });
|
|
45
|
+
*/
|
|
46
|
+
constructor(options = {}) {
|
|
47
|
+
this.rateLimitInfo = null;
|
|
48
|
+
this.appId = options.appId || null;
|
|
49
|
+
this.token = options.token || options.sessionToken || null;
|
|
50
|
+
this.baseUrl = options.baseUrl || "https://ctklearn.carsontkempf.workers.dev";
|
|
51
|
+
this.timeout = options.timeout || 3e4;
|
|
52
|
+
this.retryOn429 = options.retryOn429 !== void 0 ? options.retryOn429 : true;
|
|
53
|
+
this.zeroConfigMode = !this.appId && !this.token;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get current rate limit information
|
|
57
|
+
*/
|
|
58
|
+
getUsage() {
|
|
59
|
+
return this.rateLimitInfo;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse rate limit headers from response
|
|
63
|
+
*/
|
|
64
|
+
parseRateLimitHeaders(headers) {
|
|
65
|
+
const limit = headers.get("X-RateLimit-Limit");
|
|
66
|
+
const remaining = headers.get("X-RateLimit-Remaining");
|
|
67
|
+
const reset = headers.get("X-RateLimit-Reset");
|
|
68
|
+
if (limit && remaining && reset) {
|
|
69
|
+
this.rateLimitInfo = {
|
|
70
|
+
limit: parseInt(limit),
|
|
71
|
+
remaining: parseInt(remaining),
|
|
72
|
+
reset: parseInt(reset)
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Sleep utility for retry backoff
|
|
78
|
+
*/
|
|
79
|
+
sleep(ms) {
|
|
80
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Make fetch request with timeout
|
|
84
|
+
*/
|
|
85
|
+
async fetchWithTimeout(url, options, timeout) {
|
|
86
|
+
const controller = new AbortController();
|
|
87
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
88
|
+
try {
|
|
89
|
+
const response = await fetch(url, {
|
|
90
|
+
...options,
|
|
91
|
+
signal: controller.signal
|
|
92
|
+
});
|
|
93
|
+
return response;
|
|
94
|
+
} finally {
|
|
95
|
+
clearTimeout(timeoutId);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Call an external API securely through the proxy
|
|
100
|
+
* @param keyName - Name of the API key to use
|
|
101
|
+
* @param endpoint - API endpoint path (e.g., '/v1/chat/completions')
|
|
102
|
+
* @param options - Request options (method, body, headers)
|
|
103
|
+
* @returns Promise with the API response
|
|
104
|
+
*/
|
|
105
|
+
async call(keyName, endpoint, options = {}) {
|
|
106
|
+
let retries = 0;
|
|
107
|
+
const maxRetries = this.retryOn429 ? 3 : 0;
|
|
108
|
+
while (true) {
|
|
109
|
+
try {
|
|
110
|
+
const proxyUrl = this.zeroConfigMode ? `${this.baseUrl}/api/sdk/proxy` : `${this.baseUrl}/api/sdk/${this.appId}/proxy`;
|
|
111
|
+
const requestHeaders = {
|
|
112
|
+
"Content-Type": "application/json"
|
|
113
|
+
};
|
|
114
|
+
if (!this.zeroConfigMode && this.token) {
|
|
115
|
+
requestHeaders["Authorization"] = `Bearer ${this.token}`;
|
|
116
|
+
}
|
|
117
|
+
const response = await this.fetchWithTimeout(
|
|
118
|
+
proxyUrl,
|
|
119
|
+
{
|
|
120
|
+
method: "POST",
|
|
121
|
+
headers: requestHeaders,
|
|
122
|
+
body: JSON.stringify({
|
|
123
|
+
keyName,
|
|
124
|
+
endpoint,
|
|
125
|
+
method: options.method || "GET",
|
|
126
|
+
body: options.body,
|
|
127
|
+
headers: options.headers
|
|
128
|
+
})
|
|
129
|
+
},
|
|
130
|
+
this.timeout
|
|
131
|
+
);
|
|
132
|
+
this.parseRateLimitHeaders(response.headers);
|
|
133
|
+
const result = await response.json();
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
const errorMessage = result.data?.message || result?.message || `Request failed with status ${response.status}`;
|
|
136
|
+
if (response.status === 403 && errorMessage.includes("Origin")) {
|
|
137
|
+
throw new OriginMismatchError(errorMessage);
|
|
138
|
+
}
|
|
139
|
+
if (response.status === 401) {
|
|
140
|
+
throw new InvalidTokenError(errorMessage);
|
|
141
|
+
}
|
|
142
|
+
if (response.status === 429) {
|
|
143
|
+
const retryAfter = this.rateLimitInfo ? this.rateLimitInfo.reset - Math.floor(Date.now() / 1e3) : 60;
|
|
144
|
+
const error = new RateLimitError(
|
|
145
|
+
errorMessage,
|
|
146
|
+
retryAfter,
|
|
147
|
+
this.rateLimitInfo?.remaining || 0,
|
|
148
|
+
this.rateLimitInfo?.limit || 100
|
|
149
|
+
);
|
|
150
|
+
if (this.retryOn429 && retries < maxRetries) {
|
|
151
|
+
retries++;
|
|
152
|
+
const backoffMs = Math.min(1e3 * Math.pow(2, retries - 1), 8e3);
|
|
153
|
+
await this.sleep(backoffMs);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
throw new SecretsSDKError(errorMessage, response.status, result);
|
|
159
|
+
}
|
|
160
|
+
return result.data;
|
|
161
|
+
} catch (err) {
|
|
162
|
+
if (err instanceof SecretsSDKError) {
|
|
163
|
+
throw err;
|
|
164
|
+
}
|
|
165
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
166
|
+
throw new SecretsSDKError("Request timeout", 408);
|
|
167
|
+
}
|
|
168
|
+
throw new SecretsSDKError(
|
|
169
|
+
err instanceof Error ? err.message : "Unknown error occurred",
|
|
170
|
+
500
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Make a GET request
|
|
177
|
+
*/
|
|
178
|
+
async get(keyName, endpoint, headers) {
|
|
179
|
+
return this.call(keyName, endpoint, { method: "GET", headers });
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Make a POST request
|
|
183
|
+
*/
|
|
184
|
+
async post(keyName, endpoint, body, headers) {
|
|
185
|
+
return this.call(keyName, endpoint, { method: "POST", body, headers });
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Make a PUT request
|
|
189
|
+
*/
|
|
190
|
+
async put(keyName, endpoint, body, headers) {
|
|
191
|
+
return this.call(keyName, endpoint, { method: "PUT", body, headers });
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Make a DELETE request
|
|
195
|
+
*/
|
|
196
|
+
async delete(keyName, endpoint, headers) {
|
|
197
|
+
return this.call(keyName, endpoint, { method: "DELETE", headers });
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Make a PATCH request
|
|
201
|
+
*/
|
|
202
|
+
async patch(keyName, endpoint, body, headers) {
|
|
203
|
+
return this.call(keyName, endpoint, { method: "PATCH", body, headers });
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Secrets Management API (zero-config mode)
|
|
207
|
+
* These methods allow programmatic CRUD operations on project secrets
|
|
208
|
+
* Requires appId to be set (can be set in constructor or via setAppId)
|
|
209
|
+
*/
|
|
210
|
+
/**
|
|
211
|
+
* Set App ID for secrets management
|
|
212
|
+
* Required before calling secrets management methods
|
|
213
|
+
*/
|
|
214
|
+
setAppId(appId) {
|
|
215
|
+
this.appId = appId;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Make authenticated request to secrets management API
|
|
219
|
+
*/
|
|
220
|
+
async secretsRequest(action, body) {
|
|
221
|
+
if (!this.appId) {
|
|
222
|
+
throw new SecretsSDKError("App ID required for secrets management. Call setAppId() first.", 400);
|
|
223
|
+
}
|
|
224
|
+
const response = await this.fetchWithTimeout(
|
|
225
|
+
`${this.baseUrl}/api/projects/${this.appId}/secrets/manage?action=${action}`,
|
|
226
|
+
{
|
|
227
|
+
method: "POST",
|
|
228
|
+
headers: {
|
|
229
|
+
"Content-Type": "application/json"
|
|
230
|
+
},
|
|
231
|
+
body: body ? JSON.stringify(body) : void 0
|
|
232
|
+
},
|
|
233
|
+
this.timeout
|
|
234
|
+
);
|
|
235
|
+
if (!response.ok) {
|
|
236
|
+
const errorData = await response.json().catch(() => ({}));
|
|
237
|
+
throw new SecretsSDKError(
|
|
238
|
+
errorData.message || `Secrets management failed: ${response.statusText}`,
|
|
239
|
+
response.status,
|
|
240
|
+
errorData
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
return response.json();
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* List all secrets for the project
|
|
247
|
+
* Returns secret metadata (no API keys)
|
|
248
|
+
*/
|
|
249
|
+
async listSecrets() {
|
|
250
|
+
return this.secretsRequest("list");
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Create a new secret
|
|
254
|
+
*/
|
|
255
|
+
async createSecret(secret) {
|
|
256
|
+
return this.secretsRequest("create", secret);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Update an existing secret
|
|
260
|
+
*/
|
|
261
|
+
async updateSecret(update) {
|
|
262
|
+
return this.secretsRequest("update", update);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Delete a secret
|
|
266
|
+
*/
|
|
267
|
+
async deleteSecret(name) {
|
|
268
|
+
return this.secretsRequest("delete", { name });
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Sync secrets from .env file format
|
|
272
|
+
* Bulk upload/update secrets
|
|
273
|
+
*/
|
|
274
|
+
async syncEnv(secrets, provider) {
|
|
275
|
+
return this.secretsRequest("sync", { secrets, provider });
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// src/browser-global.ts
|
|
280
|
+
if (typeof window !== "undefined") {
|
|
281
|
+
console.log("[SecretsSDK] Setting window.SecretsSDK, typeof:", typeof SecretsSDK);
|
|
282
|
+
window.SecretsSDK = SecretsSDK;
|
|
283
|
+
console.log("[SecretsSDK] Set complete, window.SecretsSDK:", typeof window.SecretsSDK);
|
|
284
|
+
} else {
|
|
285
|
+
console.log("[SecretsSDK] window is undefined, not in browser?");
|
|
286
|
+
}
|
|
287
|
+
var browser_global_default = SecretsSDK;
|
|
288
|
+
})();
|
package/dist/cli/index.mjs
CHANGED
|
@@ -178,7 +178,7 @@ async function getWindowsId() {
|
|
|
178
178
|
var SecretsManagement = class {
|
|
179
179
|
constructor(options) {
|
|
180
180
|
this.appId = options.appId;
|
|
181
|
-
this.baseUrl = options.baseUrl || "https://
|
|
181
|
+
this.baseUrl = options.baseUrl || "https://ctklearn.carsontkempf.workers.dev";
|
|
182
182
|
this.timeout = options.timeout || 3e4;
|
|
183
183
|
}
|
|
184
184
|
/**
|
|
@@ -444,7 +444,7 @@ Log in on ${this.baseUrl}`);
|
|
|
444
444
|
// src/cli/commands/login.ts
|
|
445
445
|
async function loginCommand(options = {}) {
|
|
446
446
|
console.log("Authenticating with Learn Secrets...\n");
|
|
447
|
-
const baseUrl = options.baseUrl || "https://
|
|
447
|
+
const baseUrl = options.baseUrl || "https://ctklearn.carsontkempf.workers.dev";
|
|
448
448
|
const mgmt = new SecretsManagement({
|
|
449
449
|
appId: "temp",
|
|
450
450
|
// Will be set after login
|
|
@@ -471,7 +471,7 @@ Logged in as: ${result.user}`);
|
|
|
471
471
|
const { projects } = await projectsResponse.json();
|
|
472
472
|
if (projects.length === 0) {
|
|
473
473
|
console.log("\nNo projects found.");
|
|
474
|
-
console.log("Create a project at: https://
|
|
474
|
+
console.log("Create a project at: https://ctklearn.carsontkempf.workers.dev/dashboard");
|
|
475
475
|
console.log("\nAfter creating a project, run: learn-secrets login");
|
|
476
476
|
return;
|
|
477
477
|
}
|
|
@@ -764,7 +764,7 @@ Onboarding site for project: ${projectId}`);
|
|
|
764
764
|
console.log(` - ${failure.name}: ${failure.error}`);
|
|
765
765
|
}
|
|
766
766
|
}
|
|
767
|
-
const dashboardUrl = options.baseUrl || "https://
|
|
767
|
+
const dashboardUrl = options.baseUrl || "https://ctklearn.carsontkempf.workers.dev";
|
|
768
768
|
console.log("\nYour site is ready!");
|
|
769
769
|
console.log("\nAdd to your static site code:");
|
|
770
770
|
console.log(" const sdk = new SecretsSDK();");
|
|
@@ -930,7 +930,7 @@ Deploying secrets to project: ${config.project}`);
|
|
|
930
930
|
console.log(` - ${failure.name}: ${failure.error}`);
|
|
931
931
|
}
|
|
932
932
|
}
|
|
933
|
-
const dashboardUrl = options.baseUrl || "https://
|
|
933
|
+
const dashboardUrl = options.baseUrl || "https://ctklearn.carsontkempf.workers.dev";
|
|
934
934
|
console.log("\nSecrets deployed successfully!");
|
|
935
935
|
console.log(`
|
|
936
936
|
View your secrets in the dashboard:`);
|
package/dist/index.d.mts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -52,7 +52,7 @@ var SecretsSDK = class {
|
|
|
52
52
|
this.rateLimitInfo = null;
|
|
53
53
|
this.appId = options.appId || null;
|
|
54
54
|
this.token = options.token || options.sessionToken || null;
|
|
55
|
-
this.baseUrl = options.baseUrl || "https://
|
|
55
|
+
this.baseUrl = options.baseUrl || "https://ctklearn.carsontkempf.workers.dev";
|
|
56
56
|
this.timeout = options.timeout || 3e4;
|
|
57
57
|
this.retryOn429 = options.retryOn429 !== void 0 ? options.retryOn429 : true;
|
|
58
58
|
this.zeroConfigMode = !this.appId && !this.token;
|
|
@@ -458,7 +458,7 @@ async function getWindowsId() {
|
|
|
458
458
|
var SecretsManagement = class {
|
|
459
459
|
constructor(options) {
|
|
460
460
|
this.appId = options.appId;
|
|
461
|
-
this.baseUrl = options.baseUrl || "https://
|
|
461
|
+
this.baseUrl = options.baseUrl || "https://ctklearn.carsontkempf.workers.dev";
|
|
462
462
|
this.timeout = options.timeout || 3e4;
|
|
463
463
|
}
|
|
464
464
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "learn-secrets-sdk",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.11",
|
|
4
4
|
"description": "Secrets management SDK for static sites with Learn platform",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"typescript": "^5.0.0"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
|
-
"build": "tsup src/index.ts --format esm --dts && tsup src/browser-global.ts --format iife --
|
|
42
|
+
"build": "tsup src/index.ts --format esm --dts && tsup src/browser-global.ts --format iife --no-splitting && tsup src/cli/index.ts --format esm --dts --out-dir dist/cli --external commander",
|
|
43
43
|
"prepublishOnly": "npm run build"
|
|
44
44
|
}
|
|
45
45
|
}
|