learn-secrets-sdk
v1.11.1
Published
Secrets management SDK for static sites with Learn platform
Downloads
2,064
Maintainers
Readme
learn-secrets-sdk
secure api proxy for static sites. call external apis (openai, anthropic, stripe, etc.) without exposing api keys.
zero-config: no tokens or credentials in your code. authentication via origin header.
quick start (cli)
1. install cli
npm install -g learn-secrets-sdk2. authenticate
learn-secrets login3. initialize project
learn-secrets init --project YOUR_PROJECT_ID --origins yourdomain.com,localhost --env .envauto-detects api keys from .env and uploads them. configures origins for your site.
get project id: visit ctklearn.carsontkempf.workers.dev → copy from sidebar
4. install sdk in project
npm install learn-secrets-sdk5. use in code
import { SecretsSDK } from 'learn-secrets-sdk';
// zero-config - no credentials needed
const sdk = new SecretsSDK();
// call openai securely
const response = await sdk.post('openai', '/v1/chat/completions', {
model: 'gpt-4',
messages: [{ role: 'user', content: 'hello' }]
});how it works:
- browser sends
Originheader automatically - proxy validates origin matches configured domains
- api key injected server-side
- no tokens or credentials in client code
features
- zero-config - no tokens, appid, or credentials in code
- origin-based auth - automatic browser security via origin header
- api keys secured - stored server-side, never exposed to clients
- auto-detection - cli detects openai, anthropic, stripe, github, google
- works anywhere - cloudflare pages, netlify, vercel, any static host
- rate limiting - 100 req/min per domain built-in
- typescript - full type definitions included
cli commands
login
learn-secrets loginauthenticate via browser oauth. credentials saved to ~/.learn/credentials.json.
init
learn-secrets init \
--project abc123xyz \ # your project id
--origins example.com,localhost \ # allowed domains
--env .env # path to .env filereads .env, detects api keys, uploads to project, configures origins.
auto-detects:
OPENAI_API_KEY→ openai providerANTHROPIC_API_KEY→ anthropic providerSTRIPE_SECRET_KEY→ stripe providerGITHUB_TOKEN→ github provider*_API_KEY→ custom provider
full cli docs: cli reference
api methods
const sdk = new SecretsSDK();
// http methods
await sdk.get(keyName, endpoint, headers?)
await sdk.post(keyName, endpoint, body, headers?)
await sdk.put(keyName, endpoint, body, headers?)
await sdk.delete(keyName, endpoint, headers?)
await sdk.patch(keyName, endpoint, body, headers?)
// custom request
await sdk.call(keyName, endpoint, {
method: 'POST',
body: { },
headers: { }
})constructor options
zero-config (recommended):
const sdk = new SecretsSDK();uses origin header for authentication. no credentials needed.
advanced options:
const sdk = new SecretsSDK({
baseUrl?: string, // custom proxy url (default: production)
timeout?: number, // request timeout ms (default: 30000)
retryOn429?: boolean // auto-retry on rate limit (default: true)
});error handling
import { SecretsSDK, SecretsSDKError, OriginMismatchError, RateLimitError } from 'learn-secrets-sdk';
const sdk = new SecretsSDK();
try {
const response = await sdk.post('openai', '/v1/chat/completions', data);
} catch (error) {
if (error instanceof OriginMismatchError) {
// domain not configured in allowed origins
console.error('add domain to origins in dashboard');
} else if (error instanceof RateLimitError) {
// exceeded 100 req/min
console.log('retry after:', error.retryAfter, 'seconds');
} else if (error instanceof SecretsSDKError) {
// other api errors
console.log('status:', error.status);
console.log('message:', error.message);
}
}usage tracking
const sdk = new SecretsSDK();
await sdk.post('openai', '/v1/chat/completions', data);
// check rate limit status
const usage = sdk.getUsage();
console.log('remaining:', usage.remaining); // requests left this minute
console.log('limit:', usage.limit); // 100
console.log('resets at:', usage.reset); // unix timestampexamples
vanilla javascript
<!DOCTYPE html>
<html>
<body>
<button onclick="callAPI()">call ai</button>
<div id="response"></div>
<script type="module">
import { SecretsSDK } from './node_modules/learn-secrets-sdk/dist/index.js';
// zero-config
const sdk = new SecretsSDK();
window.callAPI = async function() {
const result = await sdk.post('openai', '/v1/chat/completions', {
model: 'gpt-4',
messages: [{ role: 'user', content: 'hello' }]
});
document.getElementById('response').textContent =
result.choices[0].message.content;
};
</script>
</body>
</html>react
import { useMemo } from 'react';
import { SecretsSDK } from 'learn-secrets-sdk';
function App() {
// zero-config sdk
const sdk = useMemo(() => new SecretsSDK(), []);
const handleClick = async () => {
const result = await sdk.post('openai', '/v1/chat/completions', {
model: 'gpt-4',
messages: [{ role: 'user', content: 'hello' }]
});
console.log(result.choices[0].message.content);
};
return <button onClick={handleClick}>call ai</button>;
}vue
import { ref } from 'vue';
import { SecretsSDK } from 'learn-secrets-sdk';
// zero-config sdk
const sdk = new SecretsSDK();
const response = ref('');
async function callAPI() {
const result = await sdk.post('openai', '/v1/chat/completions', {
model: 'gpt-4',
messages: [{ role: 'user', content: 'hello' }]
});
response.value = result.choices[0].message.content;
}next.js
'use client';
import { useCallback, useMemo } from 'react';
import { SecretsSDK } from 'learn-secrets-sdk';
export default function ChatPage() {
// zero-config sdk
const sdk = useMemo(() => new SecretsSDK(), []);
const chat = useCallback(async (message: string) => {
const result = await sdk.post('openai', '/v1/chat/completions', {
model: 'gpt-4',
messages: [{ role: 'user', content: message }]
});
return result.choices[0].message.content;
}, [sdk]);
// ... rest of component
}supported providers
auto-configured base urls when using cli:
- openai (
OPENAI_API_KEY) - anthropic (
ANTHROPIC_API_KEY) - stripe (
STRIPE_SECRET_KEY) - github (
GITHUB_TOKEN) - google (
GOOGLE_API_KEY)
custom providers supported - configure base url in dashboard.
how it works
1. cli uploads api keys to proxy server
2. cli configures allowed origins (yourdomain.com, localhost, etc.)
3. your static site imports sdk: new SecretsSDK()
4. browser automatically sends Origin header
5. proxy validates origin matches configured list
6. proxy injects api key server-side
7. external api called with key
8. response returned to browsersecurity:
- api keys never sent to browser
- origin header enforced by browser (cannot be spoofed)
- stolen code useless from unauthorized domains
security
- api keys never exposed - stored and injected server-side only
- origin-based auth - browser origin header enforced, can't be faked
- no credentials in code - zero-config means no tokens to leak
- rate limiting - 100 req/min per domain prevents abuse
- instant updates - change origins in dashboard anytime
documentation
troubleshooting
403 origin not allowed:
- run
learn-secrets initwith correct--origins - or update origins in dashboard: settings → sdk tokens
404 api key not found:
- verify key name matches .env variable (e.g.,
OPENAI_API_KEY→openai) - re-run
learn-secrets initto upload keys
429 rate limit:
- 100 requests per minute per domain
- implement throttling or caching in your app
license
mit
