learn-secrets-sdk 1.11.11 → 1.11.13

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.
@@ -1 +0,0 @@
1
- var f=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(r,t)=>(typeof require<"u"?require:r)[t]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});function i(e){return e.replace(/\$\{([A-Z0-9_]+)\}|\$([A-Z0-9_]+)/g,(r,t,o)=>{let s=t||o,n=process.env[s];if(n===void 0)throw new Error(`Environment variable ${s} is not defined`);return n})}function c(e){let r={name:i(e.name),provider:i(e.provider),api_key:i(e.api_key)};return e.base_url&&(r.base_url=i(e.base_url)),e.auth_header&&(r.auth_header=i(e.auth_header)),e.auth_prefix&&(r.auth_prefix=i(e.auth_prefix)),r}function p(e){return e.map(c)}function g(e){let r=f("fs"),o=f("path").resolve(e);if(!r.existsSync(o))throw new Error(`Config file not found: ${o}`);let s=r.readFileSync(o,"utf-8"),n=JSON.parse(s);if(!n.version)throw new Error('Config file missing "version" field');if(!n.project)throw new Error('Config file missing "project" field');if(!Array.isArray(n.secrets))throw new Error('Config file missing "secrets" array');let a=p(n.secrets);return{version:n.version,project:n.project,secrets:a}}export{i as a,c as b,p as c,g as d};
@@ -1 +0,0 @@
1
- import{a,b,c,d}from"./chunk-AS6G7JYX.mjs";export{d as loadSecretsConfig,b as resolveEnvInSecret,c as resolveEnvInSecrets,a as resolveEnvString};
package/dist/index.d.ts DELETED
@@ -1,542 +0,0 @@
1
- interface SecretsSDKOptions {
2
- /**
3
- * App ID from dashboard (optional in zero-config mode)
4
- * If omitted, SDK uses origin-based authentication
5
- */
6
- appId?: string;
7
- /**
8
- * SDK token (optional in zero-config mode)
9
- * If omitted, SDK uses origin-based authentication
10
- */
11
- token?: string;
12
- sessionToken?: string;
13
- /**
14
- * Base URL of the proxy server
15
- * Default: https://cloudprototype.org
16
- */
17
- baseUrl?: string;
18
- timeout?: number;
19
- retryOn429?: boolean;
20
- }
21
- interface ProxyRequest$1 {
22
- keyName: string;
23
- endpoint: string;
24
- method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
25
- body?: any;
26
- headers?: Record<string, string>;
27
- }
28
- interface ProxyResponse$1<T = any> {
29
- success: boolean;
30
- status: number;
31
- data: T;
32
- }
33
- interface RateLimitInfo {
34
- limit: number;
35
- remaining: number;
36
- reset: number;
37
- }
38
- declare class SecretsSDKError extends Error {
39
- status: number;
40
- response?: any | undefined;
41
- constructor(message: string, status: number, response?: any | undefined);
42
- }
43
- declare class OriginMismatchError extends SecretsSDKError {
44
- constructor(message?: string);
45
- }
46
- declare class RateLimitError extends SecretsSDKError {
47
- retryAfter: number;
48
- remaining: number;
49
- limit: number;
50
- constructor(message?: string, retryAfter?: number, remaining?: number, limit?: number);
51
- }
52
- declare class InvalidTokenError extends SecretsSDKError {
53
- constructor(message?: string);
54
- }
55
- interface SecretsManagementOptions {
56
- appId: string;
57
- baseUrl?: string;
58
- timeout?: number;
59
- }
60
- interface SecretConfig {
61
- name: string;
62
- provider: string;
63
- api_key: string;
64
- base_url?: string;
65
- auth_header?: string;
66
- auth_prefix?: string;
67
- }
68
- interface MaskedSecret {
69
- id: string;
70
- name: string;
71
- provider: string;
72
- api_key: string;
73
- base_url?: string;
74
- auth_header?: string;
75
- auth_prefix?: string;
76
- created?: string;
77
- updated?: string;
78
- }
79
- interface SyncOptions {
80
- deleteMissing?: boolean;
81
- dryRun?: boolean;
82
- }
83
- interface SyncDiffItem {
84
- name: string;
85
- provider?: string;
86
- changes?: string[];
87
- }
88
- interface SyncResult {
89
- success: boolean;
90
- diff: {
91
- created: SyncDiffItem[];
92
- updated: SyncDiffItem[];
93
- deleted: SyncDiffItem[];
94
- unchanged: SyncDiffItem[];
95
- };
96
- summary: {
97
- created: number;
98
- updated: number;
99
- deleted: number;
100
- unchanged: number;
101
- };
102
- }
103
- interface CLICredentials {
104
- access_token: string;
105
- refresh_token: string | null;
106
- expires_at: string | null;
107
- user_id: string;
108
- machine_id?: string;
109
- sdk_name?: string;
110
- authorized_at?: string;
111
- }
112
- interface SDKCredentialsStore {
113
- 'learn-secrets-sdk'?: CLICredentials;
114
- 'learn-auth-sdk'?: CLICredentials;
115
- }
116
- type SDKName = 'learn-secrets-sdk' | 'learn-auth-sdk';
117
-
118
- declare class SecretsSDK {
119
- private appId;
120
- private token;
121
- private baseUrl;
122
- private timeout;
123
- private retryOn429;
124
- private rateLimitInfo;
125
- private zeroConfigMode;
126
- /**
127
- * Create a new SecretsSDK instance
128
- *
129
- * Zero-config mode (recommended for static sites):
130
- * const sdk = new SecretsSDK();
131
- * // Origin header is used for authentication
132
- *
133
- * Token mode (for backward compatibility):
134
- * const sdk = new SecretsSDK({ appId: '...', token: 'sk_live_...' });
135
- */
136
- constructor(options?: SecretsSDKOptions);
137
- /**
138
- * Get current rate limit information
139
- */
140
- getUsage(): RateLimitInfo | null;
141
- /**
142
- * Parse rate limit headers from response
143
- */
144
- private parseRateLimitHeaders;
145
- /**
146
- * Sleep utility for retry backoff
147
- */
148
- private sleep;
149
- /**
150
- * Make fetch request with timeout
151
- */
152
- private fetchWithTimeout;
153
- /**
154
- * Call an external API securely through the proxy
155
- * @param keyName - Name of the API key to use
156
- * @param endpoint - API endpoint path (e.g., '/v1/chat/completions')
157
- * @param options - Request options (method, body, headers)
158
- * @returns Promise with the API response
159
- */
160
- call<T = any>(keyName: string, endpoint: string, options?: Omit<ProxyRequest$1, 'keyName' | 'endpoint'>): Promise<T>;
161
- /**
162
- * Make a GET request
163
- */
164
- get<T = any>(keyName: string, endpoint: string, headers?: Record<string, string>): Promise<T>;
165
- /**
166
- * Make a POST request
167
- */
168
- post<T = any>(keyName: string, endpoint: string, body: any, headers?: Record<string, string>): Promise<T>;
169
- /**
170
- * Make a PUT request
171
- */
172
- put<T = any>(keyName: string, endpoint: string, body: any, headers?: Record<string, string>): Promise<T>;
173
- /**
174
- * Make a DELETE request
175
- */
176
- delete<T = any>(keyName: string, endpoint: string, headers?: Record<string, string>): Promise<T>;
177
- /**
178
- * Make a PATCH request
179
- */
180
- patch<T = any>(keyName: string, endpoint: string, body: any, headers?: Record<string, string>): Promise<T>;
181
- /**
182
- * Secrets Management API (zero-config mode)
183
- * These methods allow programmatic CRUD operations on project secrets
184
- * Requires appId to be set (can be set in constructor or via setAppId)
185
- */
186
- /**
187
- * Set App ID for secrets management
188
- * Required before calling secrets management methods
189
- */
190
- setAppId(appId: string): void;
191
- /**
192
- * Make authenticated request to secrets management API
193
- */
194
- private secretsRequest;
195
- /**
196
- * List all secrets for the project
197
- * Returns secret metadata (no API keys)
198
- */
199
- listSecrets(): Promise<{
200
- success: boolean;
201
- secrets: Array<{
202
- name: string;
203
- provider: string;
204
- base_url: string;
205
- auth_header: string;
206
- auth_prefix: string;
207
- created: string;
208
- updated: string;
209
- }>;
210
- count: number;
211
- }>;
212
- /**
213
- * Create a new secret
214
- */
215
- createSecret(secret: {
216
- name: string;
217
- provider: string;
218
- api_key: string;
219
- base_url?: string;
220
- auth_header?: string;
221
- auth_prefix?: string;
222
- }): Promise<{
223
- success: boolean;
224
- message: string;
225
- secret: any;
226
- }>;
227
- /**
228
- * Update an existing secret
229
- */
230
- updateSecret(update: {
231
- name: string;
232
- api_key?: string;
233
- provider?: string;
234
- base_url?: string;
235
- auth_header?: string;
236
- auth_prefix?: string;
237
- }): Promise<{
238
- success: boolean;
239
- message: string;
240
- secret: any;
241
- }>;
242
- /**
243
- * Delete a secret
244
- */
245
- deleteSecret(name: string): Promise<{
246
- success: boolean;
247
- message: string;
248
- }>;
249
- /**
250
- * Sync secrets from .env file format
251
- * Bulk upload/update secrets
252
- */
253
- syncEnv(secrets: Record<string, string>, provider?: string): Promise<{
254
- success: boolean;
255
- message: string;
256
- results: {
257
- created: number;
258
- updated: number;
259
- failed: number;
260
- details: {
261
- created: string[];
262
- updated: string[];
263
- failed: Array<{
264
- name: string;
265
- error: string;
266
- }>;
267
- };
268
- };
269
- }>;
270
- }
271
-
272
- /**
273
- * SecretsManagement class for CLI authentication and secrets management
274
- */
275
- declare class SecretsManagement {
276
- private appId;
277
- private baseUrl;
278
- private timeout;
279
- constructor(options: SecretsManagementOptions);
280
- /**
281
- * Open a URL in the default browser
282
- */
283
- private openBrowser;
284
- /**
285
- * Sleep for specified milliseconds
286
- */
287
- private sleep;
288
- /**
289
- * Browser OAuth login flow with 2FA
290
- * Opens browser for user to authorize, then prompts for 2FA code
291
- */
292
- login(): Promise<{
293
- success: boolean;
294
- user: string;
295
- }>;
296
- /**
297
- * Check if user is authenticated
298
- */
299
- isAuthenticated(): Promise<boolean>;
300
- /**
301
- * Logout - clear stored credentials
302
- */
303
- logout(): void;
304
- /**
305
- * Get access token from stored credentials
306
- * Throws error if not authenticated
307
- */
308
- private getAccessToken;
309
- /**
310
- * Make authenticated request
311
- */
312
- private request;
313
- /**
314
- * List all secrets (with masked API keys)
315
- */
316
- list(): Promise<MaskedSecret[]>;
317
- /**
318
- * Sync secrets from config
319
- */
320
- sync(secrets: SecretConfig[], options?: SyncOptions): Promise<SyncResult>;
321
- /**
322
- * Import secrets from a config object (bulk import)
323
- * Also creates SDK token if origins are provided
324
- *
325
- * @param config - The secrets configuration
326
- * @returns Import results including created/updated counts and optional SDK token
327
- */
328
- importSecrets(config: {
329
- version?: string;
330
- origins?: string[];
331
- secrets: SecretConfig[];
332
- }): Promise<{
333
- success: boolean;
334
- results: {
335
- created: number;
336
- updated: number;
337
- failed: number;
338
- details: {
339
- created: string[];
340
- updated: string[];
341
- failed: {
342
- name: string;
343
- error: string;
344
- }[];
345
- };
346
- };
347
- sdkToken?: {
348
- token: string;
349
- message: string;
350
- };
351
- }>;
352
- /**
353
- * Import secrets from a JSON file path
354
- * Resolves environment variables in the config
355
- */
356
- importFromFile(configPath: string): Promise<{
357
- success: boolean;
358
- results: {
359
- created: number;
360
- updated: number;
361
- failed: number;
362
- };
363
- sdkToken?: {
364
- token: string;
365
- message: string;
366
- };
367
- }>;
368
- }
369
-
370
- /**
371
- * Worker Client - Frontend SDK for calling Learn Secrets Worker
372
- *
373
- * Use this client to call your deployed Cloudflare Worker from static sites
374
- */
375
- interface WorkerClientOptions {
376
- workerUrl: string;
377
- }
378
- interface ProxyRequest {
379
- secret: string;
380
- url: string;
381
- method?: string;
382
- headers?: Record<string, string>;
383
- body?: any;
384
- authHeader?: string;
385
- authPrefix?: string;
386
- }
387
- interface ProxyResponse<T = any> {
388
- success: boolean;
389
- status: number;
390
- data: T;
391
- }
392
- interface PublicConfig {
393
- [key: string]: string;
394
- }
395
- interface AppleJwtRequest {
396
- teamId?: string;
397
- keyId?: string;
398
- privateKey: string;
399
- }
400
- interface OAuthExchangeRequest {
401
- provider: string;
402
- code: string;
403
- redirectUri: string;
404
- }
405
- /**
406
- * Worker Client for calling Learn Secrets Worker
407
- *
408
- * SECURITY:
409
- * - All requests include Origin header (automatically added by browser)
410
- * - Worker validates origin before processing
411
- * - Secrets never exposed to frontend
412
- * - Only public config returned to frontend
413
- *
414
- * Example:
415
- * ```typescript
416
- * const client = new WorkerClient({
417
- * workerUrl: 'https://learn-secrets-myapp.myaccount.workers.dev'
418
- * });
419
- *
420
- * // Get public config
421
- * const config = await client.getConfig();
422
- *
423
- * // Make API call with secret
424
- * const response = await client.proxy({
425
- * secret: 'openai-api-key',
426
- * url: 'https://api.openai.com/v1/chat/completions',
427
- * method: 'POST',
428
- * body: { model: 'gpt-4', messages: [...] }
429
- * });
430
- * ```
431
- */
432
- declare class WorkerClient {
433
- private workerUrl;
434
- constructor(options: WorkerClientOptions);
435
- /**
436
- * Get public configuration
437
- *
438
- * Returns only PUBLIC_* environment variables from Worker
439
- * Safe for frontend use
440
- */
441
- getConfig(): Promise<PublicConfig>;
442
- /**
443
- * Proxy API request with secret injection
444
- *
445
- * Makes API call through Worker which injects secret server-side
446
- * Secret never reaches browser
447
- *
448
- * @param request - Proxy request configuration
449
- * @returns API response data
450
- */
451
- proxy<T = any>(request: ProxyRequest): Promise<ProxyResponse<T>>;
452
- /**
453
- * Generate Apple Music JWT
454
- *
455
- * Private key stays in Worker, only JWT returned to frontend
456
- *
457
- * @param request - Apple JWT request with secret name
458
- * @returns JWT token
459
- */
460
- generateAppleJwt(request: AppleJwtRequest): Promise<string>;
461
- /**
462
- * Exchange OAuth authorization code for access token
463
- *
464
- * Client secret stays in Worker, tokens returned to frontend
465
- *
466
- * @param request - OAuth exchange request
467
- * @returns OAuth token response
468
- */
469
- exchangeOAuthCode(request: OAuthExchangeRequest): Promise<any>;
470
- /**
471
- * Health check
472
- */
473
- health(): Promise<{
474
- status: string;
475
- version: string;
476
- timestamp: string;
477
- }>;
478
- }
479
-
480
- /**
481
- * Resolve environment variable references in a string
482
- * Supports ${VAR} and $VAR syntax
483
- */
484
- declare function resolveEnvString(value: string): string;
485
- /**
486
- * Resolve environment variables in a single secret config
487
- */
488
- declare function resolveEnvInSecret(secret: SecretConfig): SecretConfig;
489
- /**
490
- * Resolve environment variables in an array of secrets
491
- */
492
- declare function resolveEnvInSecrets(secrets: SecretConfig[]): SecretConfig[];
493
- /**
494
- * Load and parse a secrets config file
495
- * Resolves environment variables in the config
496
- */
497
- declare function loadSecretsConfig(configPath: string): {
498
- version: string;
499
- project: string;
500
- secrets: SecretConfig[];
501
- };
502
-
503
- /**
504
- * Machine ID Generation
505
- * Cross-platform machine identification for CLI authentication
506
- */
507
- interface MachineInfo {
508
- machineId: string;
509
- fingerprint: string;
510
- }
511
- /**
512
- * Get a unique machine identifier
513
- * This ID persists across reboots and SDK reinstalls
514
- */
515
- declare function getMachineId(): Promise<MachineInfo>;
516
-
517
- /**
518
- * Read all credentials from file (SDK-keyed format)
519
- */
520
- declare function readAllCredentials(): SDKCredentialsStore | null;
521
- /**
522
- * Write all credentials to file (SDK-keyed format)
523
- */
524
- declare function writeAllCredentials(store: SDKCredentialsStore): void;
525
- /**
526
- * Read credentials for a specific SDK
527
- */
528
- declare function readSDKCredentials(sdkName: SDKName): CLICredentials | null;
529
- /**
530
- * Write credentials for a specific SDK
531
- */
532
- declare function writeSDKCredentials(sdkName: SDKName, creds: CLICredentials): void;
533
- /**
534
- * Delete credentials for a specific SDK
535
- */
536
- declare function deleteSDKCredentials(sdkName: SDKName): void;
537
- /**
538
- * Check if credentials exist for a specific SDK
539
- */
540
- declare function hasSDKCredentials(sdkName: SDKName): boolean;
541
-
542
- export { type CLICredentials, InvalidTokenError, type MachineInfo, type MaskedSecret, OriginMismatchError, type ProxyRequest$1 as ProxyRequest, type ProxyResponse$1 as ProxyResponse, RateLimitError, type RateLimitInfo, type SDKCredentialsStore, type SDKName, type SecretConfig, SecretsManagement, type SecretsManagementOptions, SecretsSDK, SecretsSDKError, type SecretsSDKOptions, type SyncOptions, type SyncResult, WorkerClient, deleteSDKCredentials, getMachineId, hasSDKCredentials, loadSecretsConfig, readAllCredentials, readSDKCredentials, resolveEnvInSecret, resolveEnvInSecrets, resolveEnvString, writeAllCredentials, writeSDKCredentials };
@@ -1,10 +0,0 @@
1
- "use strict";var SecretsSDK=(()=>{var Z=Object.create;var T=Object.defineProperty;var Q=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var ee=Object.getPrototypeOf,te=Object.prototype.hasOwnProperty;var l=(r=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+r+'" is not supported')});var re=(r,e)=>()=>(r&&(e=r(r=0)),e);var z=(r,e)=>{for(var t in e)T(r,t,{get:e[t],enumerable:!0})},F=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Y(e))!te.call(r,n)&&n!==t&&T(r,n,{get:()=>e[n],enumerable:!(s=Q(e,n))||s.enumerable});return r};var y=(r,e,t)=>(t=r!=null?Z(ee(r)):{},F(e||!r||!r.__esModule?T(t,"default",{value:r,enumerable:!0}):t,r)),se=r=>F(T({},"__esModule",{value:!0}),r);var X={};z(X,{loadSecretsConfig:()=>N,resolveEnvInSecret:()=>E,resolveEnvInSecrets:()=>$,resolveEnvString:()=>p});function p(r){return r.replace(/\$\{([A-Z0-9_]+)\}|\$([A-Z0-9_]+)/g,(e,t,s)=>{let n=t||s,i=process.env[n];if(i===void 0)throw new Error(`Environment variable ${n} is not defined`);return i})}function E(r){let e={name:p(r.name),provider:p(r.provider),api_key:p(r.api_key)};return r.base_url&&(e.base_url=p(r.base_url)),r.auth_header&&(e.auth_header=p(r.auth_header)),r.auth_prefix&&(e.auth_prefix=p(r.auth_prefix)),e}function $(r){return r.map(E)}function N(r){let e=l("fs"),s=l("path").resolve(r);if(!e.existsSync(s))throw new Error(`Config file not found: ${s}`);let n=e.readFileSync(s,"utf-8"),i=JSON.parse(n);if(!i.version)throw new Error('Config file missing "version" field');if(!i.project)throw new Error('Config file missing "project" field');if(!Array.isArray(i.secrets))throw new Error('Config file missing "secrets" array');let a=$(i.secrets);return{version:i.version,project:i.project,secrets:a}}var J=re(()=>{"use strict"});var ce={};z(ce,{InvalidTokenError:()=>b,OriginMismatchError:()=>S,RateLimitError:()=>x,SecretsManagement:()=>j,SecretsSDK:()=>_,SecretsSDKError:()=>o,WorkerClient:()=>A,deleteSDKCredentials:()=>H,getMachineId:()=>O,hasSDKCredentials:()=>W,loadSecretsConfig:()=>N,readAllCredentials:()=>v,readSDKCredentials:()=>k,resolveEnvInSecret:()=>E,resolveEnvInSecrets:()=>$,resolveEnvString:()=>p,writeAllCredentials:()=>R,writeSDKCredentials:()=>D});var o=class extends Error{constructor(t,s,n){super(t);this.status=s;this.response=n;this.name="SecretsSDKError"}},S=class extends o{constructor(e="Origin not allowed for this token"){super(e,403),this.name="OriginMismatchError"}},x=class extends o{constructor(e="Rate limit exceeded",t=60,s=0,n=100){super(e,429),this.name="RateLimitError",this.retryAfter=t,this.remaining=s,this.limit=n}},b=class extends o{constructor(e="Invalid or expired token"){super(e,401),this.name="InvalidTokenError"}};var _=class{constructor(e={}){this.rateLimitInfo=null;this.appId=e.appId||null,this.token=e.token||e.sessionToken||null,this.baseUrl=e.baseUrl||"https://cloudprototype.org",this.timeout=e.timeout||3e4,this.retryOn429=e.retryOn429!==void 0?e.retryOn429:!0,this.zeroConfigMode=!this.appId&&!this.token}getUsage(){return this.rateLimitInfo}parseRateLimitHeaders(e){let t=e.get("X-RateLimit-Limit"),s=e.get("X-RateLimit-Remaining"),n=e.get("X-RateLimit-Reset");t&&s&&n&&(this.rateLimitInfo={limit:parseInt(t),remaining:parseInt(s),reset:parseInt(n)})}sleep(e){return new Promise(t=>setTimeout(t,e))}async fetchWithTimeout(e,t,s){let n=new AbortController,i=setTimeout(()=>n.abort(),s);try{return await fetch(e,{...t,signal:n.signal})}finally{clearTimeout(i)}}async call(e,t,s={}){let n=0,i=this.retryOn429?3:0;for(;;)try{let a=this.zeroConfigMode?`${this.baseUrl}/api/sdk/proxy`:`${this.baseUrl}/api/sdk/${this.appId}/proxy`,m={"Content-Type":"application/json"};!this.zeroConfigMode&&this.token&&(m.Authorization=`Bearer ${this.token}`);let c=await this.fetchWithTimeout(a,{method:"POST",headers:m,body:JSON.stringify({keyName:e,endpoint:t,method:s.method||"GET",body:s.body,headers:s.headers})},this.timeout);this.parseRateLimitHeaders(c.headers);let w=await c.json();if(!c.ok){let h=w.data?.message||w?.message||`Request failed with status ${c.status}`;if(c.status===403&&h.includes("Origin"))throw new S(h);if(c.status===401)throw new b(h);if(c.status===429){let I=this.rateLimitInfo?this.rateLimitInfo.reset-Math.floor(Date.now()/1e3):60,u=new x(h,I,this.rateLimitInfo?.remaining||0,this.rateLimitInfo?.limit||100);if(this.retryOn429&&n<i){n++;let f=Math.min(1e3*Math.pow(2,n-1),8e3);await this.sleep(f);continue}throw u}throw new o(h,c.status,w)}return w.data}catch(a){throw a instanceof o?a:a instanceof Error&&a.name==="AbortError"?new o("Request timeout",408):new o(a instanceof Error?a.message:"Unknown error occurred",500)}}async get(e,t,s){return this.call(e,t,{method:"GET",headers:s})}async post(e,t,s,n){return this.call(e,t,{method:"POST",body:s,headers:n})}async put(e,t,s,n){return this.call(e,t,{method:"PUT",body:s,headers:n})}async delete(e,t,s){return this.call(e,t,{method:"DELETE",headers:s})}async patch(e,t,s,n){return this.call(e,t,{method:"PATCH",body:s,headers:n})}setAppId(e){this.appId=e}async secretsRequest(e,t){if(!this.appId)throw new o("App ID required for secrets management. Call setAppId() first.",400);let s=await this.fetchWithTimeout(`${this.baseUrl}/api/projects/${this.appId}/secrets/manage?action=${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:t?JSON.stringify(t):void 0},this.timeout);if(!s.ok){let n=await s.json().catch(()=>({}));throw new o(n.message||`Secrets management failed: ${s.statusText}`,s.status,n)}return s.json()}async listSecrets(){return this.secretsRequest("list")}async createSecret(e){return this.secretsRequest("create",e)}async updateSecret(e){return this.secretsRequest("update",e)}async deleteSecret(e){return this.secretsRequest("delete",{name:e})}async syncEnv(e,t){return this.secretsRequest("sync",{secrets:e,provider:t})}};var d=y(l("fs")),P=y(l("path")),L=y(l("os"));function U(){let r=L.homedir(),e=P.join(r,".learn");return P.join(e,"credentials.json")}function ne(){let r=L.homedir(),e=P.join(r,".learn");d.existsSync(e)||d.mkdirSync(e,{recursive:!0,mode:448})}function v(){try{let r=U();if(!d.existsSync(r))return null;let e=d.readFileSync(r,"utf-8"),t=JSON.parse(e);return t.access_token&&!t["learn-secrets-sdk"]&&!t["learn-auth-sdk"]?{"learn-secrets-sdk":t}:t}catch{return null}}function R(r){ne();let e=U(),t=JSON.stringify(r,null,2);d.writeFileSync(e,t,{mode:384})}function k(r){let e=v();return e&&e[r]||null}function D(r,e){let t=v()||{};t[r]=e,R(t)}function H(r){let e=v();e&&(delete e[r],Object.keys(e).length===0?K():R(e))}function M(){return k("learn-secrets-sdk")}function K(){try{let r=U();d.existsSync(r)&&d.unlinkSync(r)}catch{}}function W(r){let e=k(r);return e!==null&&!!e.access_token}function G(){let r=M();return r?r.expires_at?new Date(r.expires_at)>new Date:!0:!1}var B=l("child_process"),V=l("util"),q=l("crypto"),g=y(l("os")),C=(0,V.promisify)(B.exec);async function O(){let r=process.platform;try{let e;if(r==="darwin")e=await ie();else if(r==="linux")e=await oe();else if(r==="win32")e=await ae();else throw new Error(`Unsupported platform: ${r}`);let t=(0,q.createHash)("sha256").update(e).digest("hex").substring(0,32),s=JSON.stringify({machineId:t,cpus:g.cpus().length,arch:g.arch(),platform:g.platform(),homedir:g.homedir()}),n=(0,q.createHash)("sha256").update(s).digest("hex");return{machineId:t,fingerprint:n}}catch(e){throw new Error(`Failed to get machine ID: ${e.message}`)}}async function ie(){try{let{stdout:r}=await C(`ioreg -l | grep IOPlatformSerialNumber | awk '{print $4}' | sed 's/"//g'`),{stdout:e}=await C("hostname"),t=r.trim(),s=e.trim();if(t&&s)return`${t}-${s}`;let{stdout:n}=await C(`ioreg -rd1 -c IOPlatformExpertDevice | grep IOPlatformUUID | awk '{print $3}' | sed 's/"//g'`);return n.trim()}catch{throw new Error("Failed to get macOS machine ID")}}async function oe(){try{let{stdout:r}=await C("cat /etc/machine-id 2>/dev/null || cat /var/lib/dbus/machine-id 2>/dev/null"),e=r.trim();if(e)return e;throw new Error("Machine ID file not found")}catch{throw new Error("Failed to get Linux machine ID")}}async function ae(){try{let{stdout:r}=await C("wmic csproduct get uuid"),t=r.split(`
2
- `).map(s=>s.trim()).find(s=>s&&s!=="UUID");if(t)return t;throw new Error("Failed to parse machine UUID from WMIC")}catch{throw new Error("Failed to get Windows machine ID")}}var j=class{constructor(e){this.appId=e.appId,this.baseUrl=e.baseUrl||"https://cloudprototype.org",this.timeout=e.timeout||3e4}async openBrowser(e){let{exec:t}=await import("child_process"),{promisify:s}=await import("util"),n=s(t),i=process.platform;try{i==="darwin"?await n(`open "${e}"`):i==="win32"?await n(`start "${e}"`):await n(`xdg-open "${e}"`)}catch(a){throw console.error("Failed to open browser:",a),new o("Failed to open browser",500)}}sleep(e){return new Promise(t=>setTimeout(t,e))}async login(){let e="learn-secrets-sdk";try{console.log(`Authenticating with Learn (${e})...
3
- `);let t=await O(),s=k(e);if(s&&s.access_token){let u=await fetch(`${this.baseUrl}/api/auth/cli/check-authorization`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({machine_id:t.machineId,sdk_name:e})});if(u.ok){let f=await u.json();if(f.authorized)return console.log("This machine is already authorized."),console.log(`Logged in as: ${f.user_email||f.user_id}`),{success:!0,user:f.user_email||f.user_id}}}let n=await fetch(`${this.baseUrl}/api/auth/cli/device`,{method:"POST",headers:{"Content-Type":"application/json"}});if(!n.ok)throw new o("Failed to generate device code",n.status);let i=await n.json();console.log(`
4
- Log in on ${this.baseUrl}`),console.log("Login at:"),console.log(i.verification_uri_complete),console.log(`
5
- Press ENTER to open in the browser...`);let m=(await import("readline")).createInterface({input:process.stdin,output:process.stdout});await new Promise(u=>{m.question("",()=>{m.close(),u()})}),console.log(`Opening browser...
6
- `),await this.openBrowser(i.verification_uri_complete);let c=null,w=i.interval*1e3,h=Math.ceil(i.expires_in/i.interval),I=0;for(;I<h;){await this.sleep(w),I++;let u=await fetch(`${this.baseUrl}/api/auth/cli/token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({device_code:i.device_code})});if(u.status===202){process.stdout.write(".");continue}if(u.ok){c=await u.json();break}}if(!c)throw new o("Device authorization timeout",408);return console.log(`
7
-
8
- Device authorized! Retrieving access token...`),D(e,{access_token:c.access_token,refresh_token:null,expires_at:null,user_id:c.user_id,machine_id:t.machineId,sdk_name:e,authorized_at:new Date().toISOString()}),console.log(`
9
- Authentication successful!`),console.log(`Logged in as: ${c.user_email||c.user_id}`),console.log(`This machine is now permanently authorized.
10
- `),{success:!0,user:c.user_email||c.user_id}}catch(t){throw t instanceof o?t:new o(t.message||"Login failed",t.status||500)}}async isAuthenticated(){return G()}logout(){K(),console.log("Logged out successfully")}getAccessToken(){let e=M();if(!e)throw new o("Not authenticated. Run login() first.",401);if(e.expires_at&&new Date(e.expires_at)<=new Date)throw new o("Token expired. Run login() again.",401);return e.access_token}async request(e,t,s){let n=this.getAccessToken(),i={method:e,headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`}};s&&(i.body=JSON.stringify(s));let a=await fetch(`${this.baseUrl}${t}`,i);if(!a.ok){let m=await a.json().catch(()=>({}));throw new o(m.message||`Request failed: ${a.statusText}`,a.status,m)}return a.json()}async list(){return(await this.request("GET",`/api/projects/${this.appId}/secrets`)).secrets}async sync(e,t){return await this.request("POST",`/api/projects/${this.appId}/secrets/sync`,{secrets:e,options:{deleteMissing:t?.deleteMissing??!1,dryRun:t?.dryRun??!1}})}async importSecrets(e){return this.request("POST",`/api/projects/${this.appId}/import-secrets`,{version:e.version||"1.0",origins:e.origins,secrets:e.secrets})}async importFromFile(e){let{loadSecretsConfig:t}=await Promise.resolve().then(()=>(J(),X)),s=t(e);return this.importSecrets(s)}};var A=class{constructor(e){this.workerUrl=e.workerUrl.replace(/\/$/,"")}async getConfig(){let e=await fetch(`${this.workerUrl}/config`,{method:"GET",credentials:"include"});if(!e.ok)throw new Error(`Failed to get config: ${e.status} ${e.statusText}`);return(await e.json()).public||{}}async proxy(e){let t=await fetch(`${this.workerUrl}/proxy`,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(e)});if(!t.ok){let s=await t.json().catch(()=>({error:"Unknown error"}));throw new Error(s.error||`Proxy request failed: ${t.status}`)}return t.json()}async generateAppleJwt(e){let t=await fetch(`${this.workerUrl}/auth/apple-jwt`,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(e)});if(!t.ok){let n=await t.json().catch(()=>({error:"Unknown error"}));throw new Error(n.error||`Apple JWT generation failed: ${t.status}`)}return(await t.json()).token}async exchangeOAuthCode(e){let t=await fetch(`${this.workerUrl}/auth/oauth`,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(e)});if(!t.ok){let s=await t.json().catch(()=>({error:"Unknown error"}));throw new Error(s.error||`OAuth exchange failed: ${t.status}`)}return t.json()}async health(){let e=await fetch(`${this.workerUrl}/health`,{method:"GET"});if(!e.ok)throw new Error(`Health check failed: ${e.status}`);return e.json()}};J();return se(ce);})();