npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

learn-secrets-sdk

v1.11.1

Published

Secrets management SDK for static sites with Learn platform

Downloads

2,064

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-sdk

2. authenticate

learn-secrets login

3. initialize project

learn-secrets init --project YOUR_PROJECT_ID --origins yourdomain.com,localhost --env .env

auto-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-sdk

5. 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 Origin header 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 login

authenticate 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 file

reads .env, detects api keys, uploads to project, configures origins.

auto-detects:

  • OPENAI_API_KEY → openai provider
  • ANTHROPIC_API_KEY → anthropic provider
  • STRIPE_SECRET_KEY → stripe provider
  • GITHUB_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 timestamp

examples

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 browser

security:

  • 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 init with 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_KEYopenai)
  • re-run learn-secrets init to upload keys

429 rate limit:

  • 100 requests per minute per domain
  • implement throttling or caching in your app

license

mit