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

@potion5/sdk

v1.0.0

Published

Official TypeScript SDK for the Potion API - AI-powered beverage formulation platform

Downloads

121

Readme

Potion TypeScript/Node.js SDK

Official TypeScript SDK for the Potion API - AI-powered beverage formulation platform.

Installation

npm install @potion/sdk
# or
yarn add @potion/sdk
# or
pnpm add @potion/sdk

Quick Start

import { Potion } from '@potion/sdk';

// Initialize the client
const client = new Potion({ apiKey: 'pk_live_your_key_here' });

// Generate a formulation
const formulation = await client.formulations.generate({
  prompt: 'A refreshing citrus energy drink with natural caffeine',
  category: 'nonalc',
  subcategory: 'csd.energy_drink',
  constraints: ['natural', 'under-100-calories'],
});

console.log(`Created: ${formulation.name}`);
console.log(`Calories: ${formulation.nutrition.calories}`);

Features

  • Full TypeScript support - Complete type definitions
  • Promise-based - Async/await ready
  • Automatic retries - Built-in retry logic with exponential backoff
  • Streaming - Support for SSE streaming responses
  • Rate limiting - Automatic rate limit handling
  • Tree-shakeable - Import only what you need

Usage

Formulations

import { Potion } from '@potion/sdk';

const client = new Potion({ apiKey: 'pk_live_your_key_here' });

// List formulations
const { data: formulations } = await client.formulations.list({
  limit: 20,
  status: 'active',
});

// Get a specific formulation
const formulation = await client.formulations.get('formulation-uuid');

// Generate with AI
const generated = await client.formulations.generate({
  prompt: 'Low-sugar probiotic kombucha',
  category: 'nonalc',
  subcategory: 'functional.kombucha',
});

// Create variations
const variations = await client.formulations.createVariations(
  'formulation-uuid',
  {
    variationType: 'flavor',
    count: 3,
  }
);

// Get substitutions
const substitutions = await client.formulations.getSubstitutions(
  'formulation-uuid',
  {
    ingredientName: 'Organic Cane Sugar',
    reason: 'cost',
  }
);

Ingredients

// List ingredients
const { data: ingredients } = await client.ingredients.list({
  category: 'sweetener',
});

// Search ingredients
const results = await client.ingredients.search('natural caffeine');

// Augment ingredient with AI
const augmented = await client.ingredients.augment({
  ingredientName: 'Guarana Extract',
  physicalState: 'solid',
});

// Batch augment
const batchResults = await client.ingredients.augmentBatch({
  ingredients: ['Stevia', 'Monk Fruit Extract', 'Erythritol'],
});

// Check compatibility
const compatibility = await client.ingredients.checkCompatibility(
  'Citric Acid',
  {
    withIngredients: ['Sodium Benzoate', 'Potassium Sorbate'],
  }
);

SOP Generation

// Generate SOP for a formulation
const sop = await client.sop.generate('formulation-uuid', {
  productionScale: 'commercial',
  includeHaccp: true,
});

// Get SOP profiles
const profiles = await client.sop.listProfiles();

// Retrieve existing SOP
const existing = await client.sop.get('sop-uuid');

Labeling

// Generate labeling requirements
const labeling = await client.labeling.generate('formulation-uuid', {
  containerSizeMl: 355,
  servingSizeMl: 355,
  targetMarkets: ['US', 'CA'],
});

// Check claims eligibility
const claims = await client.labeling.checkClaims({
  formulationId: 'formulation-uuid',
  claims: ['organic', 'non_gmo', 'low_calorie', 'natural'],
});

Assistant

// Chat with the assistant
const response = await client.assistant.chat({
  message: "What's the best natural sweetener for an energy drink?",
  formulationId: 'formulation-uuid', // Optional context
});

// Streaming response
const stream = await client.assistant.chatStream({
  message: 'Explain the FDA requirements for caffeine labeling',
});

for await (const chunk of stream) {
  process.stdout.write(chunk.content);
}

// List conversations
const conversations = await client.assistant.listConversations();

// Get conversation history
const conversation = await client.assistant.getConversation('conversation-uuid');

Supply Chain

// Search copackers
const copackers = await client.supplyChain.searchCopackers({
  capabilities: ['hot_fill', 'aseptic'],
  state: 'CA',
  certifications: ['SQF', 'Organic'],
});

// Get AI recommendations
const recommendations = await client.supplyChain.recommendCopackers({
  formulationId: 'formulation-uuid',
  requirements: {
    minVolume: 10000,
    certifications: ['Organic'],
  },
});

// Search distributors
const distributors = await client.supplyChain.searchDistributors({
  region: 'West Coast',
  channels: ['natural_grocery', 'specialty'],
});

Compliance

// Run compliance check
const compliance = await client.compliance.check({
  formulationId: 'formulation-uuid',
  targetStates: ['CA', 'NY', 'TX'],
});

// Get DTC shipping rules
const dtcRules = await client.compliance.getDtcShipping({
  states: ['CA', 'NY'],
  productType: 'non_alcoholic_beverage',
});

// Get regulatory updates
const updates = await client.compliance.getUpdates({
  category: 'fda',
  since: '2024-01-01',
});

Webhooks

// Create webhook
const webhook = await client.webhooks.create({
  url: 'https://your-server.com/webhook',
  events: ['formulation.created', 'formulation.updated'],
  secret: 'your-webhook-secret',
});

// List webhooks
const webhooks = await client.webhooks.list();

// Test webhook
const result = await client.webhooks.test('webhook-uuid', {
  eventType: 'formulation.created',
});

// Get delivery history
const deliveries = await client.webhooks.getDeliveries('webhook-uuid');

Idempotency

Prevent duplicate operations on retries using idempotency keys:

import { Potion, generateIdempotencyKey } from '@potion/sdk';

const client = new Potion({ apiKey: 'pk_live_your_key_here' });

// Generate a unique idempotency key
const idempotencyKey = generateIdempotencyKey();

// Use the key for mutation operations
const formulation = await client.formulations.generate(
  {
    prompt: 'A refreshing citrus energy drink',
    category: 'nonalc',
    subcategory: 'csd.energy_drink',
  },
  { idempotencyKey }
);

// If you retry with the same key, you'll get the cached response
// This prevents duplicate formulations from being created

Idempotency keys:

  • Must be 10-255 characters (alphanumeric, hyphens, underscores)
  • Are retained for 24 hours
  • Only apply to mutation operations (POST, PUT, PATCH, DELETE)

Error Handling

import { Potion, PotionError, RateLimitError, NotFoundError } from '@potion/sdk';

const client = new Potion({ apiKey: 'pk_live_your_key_here' });

try {
  const formulation = await client.formulations.get('invalid-uuid');
} catch (error) {
  if (error instanceof NotFoundError) {
    console.log(`Formulation not found: ${error.message}`);
  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${error.retryAfter} seconds`);
  } else if (error instanceof PotionError) {
    console.log(`API error: ${error.code} - ${error.message}`);
  } else {
    throw error;
  }
}

Configuration

import { Potion } from '@potion/sdk';

const client = new Potion({
  apiKey: 'pk_live_your_key_here',

  // Optional configuration
  baseUrl: 'https://api.potion.com', // Custom base URL
  timeout: 30000,                     // Request timeout in milliseconds
  maxRetries: 3,                      // Max retry attempts
});

Sandbox Mode

Use sandbox keys for development and testing:

import { Potion } from '@potion/sdk';

// Use sandbox key
const client = new Potion({ apiKey: 'pk_sandbox_your_key_here' });

// Check if in sandbox mode
console.log(client.isSandbox); // true

// Check sandbox status
const status = await client.sandbox.getStatus();
console.log(`Requests remaining: ${status.usage.requestsLimit - status.usage.requestsToday}`);

// Reset sandbox data
await client.sandbox.reset();

// Load test scenario
await client.sandbox.loadScenario('energy-drink-launch');

TypeScript Types

All types are exported for your convenience:

import type {
  Formulation,
  Ingredient,
  SOPDocument,
  LabelingRequirements,
  Copacker,
  Distributor,
  Webhook,
  Conversation,
  ComplianceCheck,
  NutritionInfo,
} from '@potion/sdk';

Requirements

  • Node.js 18+ (or compatible runtime)
  • TypeScript 4.7+ (for TypeScript users)

License

MIT License - see LICENSE file for details.

Support

  • Documentation: https://potion.com/documentation
  • API Reference: https://potion.com/api/v1/docs
  • Email: [email protected]