Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: commitlint
on: pull_request
jobs:
commitlint:
uses: ScrawnDotDev/.github/.github/workflows/commitlint.yml@master
name: commitlint

on: pull_request

jobs:
commitlint:
uses: ScrawnDotDev/.github/.github/workflows/commitlint.yml@master
17 changes: 17 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always",
"proseWrap": "preserve",
"htmlWhitespaceSensitivity": "css",
"endOfLine": "lf",
"embeddedLanguageFormatting": "auto"
}
81 changes: 40 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,40 @@
# Scrawn SDK

## What is Scrawn.js?

Scrawn.js is the official TypeScript SDK for integrating Scrawn's usage-based billing into your applications. It provides a simple, type-safe interface for tracking usage events and collecting payments via gRPC.

[View Docs](https://scrawn.vercel.app/docs/scrawn-js)

## Key Features

- **Simple API** - Track usage with a single function call
- **Type-Safe** - Full TypeScript support with auto-completion
- **gRPC-Powered** - Built on Connect-RPC for efficient communication
- **Framework Agnostic** - Works with any JavaScript framework
- **Middleware Support** - Built-in middleware with whitelist/blacklist patterns

## Installation

Install Scrawn.js in your project:


```bash
bun add @scrawn/core
```

## Quick Example

```typescript
import { Scrawn } from '@scrawn/core';

const scrawn = new Scrawn({
apiKey: process.env.SCRAWN_KEY as `scrn_${string}`,
baseURL: process.env.SCRAWN_BASE_URL || 'http://localhost:8069',
});

// Track a billable event
await scrawn.sdkCallEventConsumer({
userId: 'user-123',
debitAmount: 100,
});
```
# Scrawn SDK

## What is Scrawn.js?

Scrawn.js is the official TypeScript SDK for integrating Scrawn's usage-based billing into your applications. It provides a simple, type-safe interface for tracking usage events and collecting payments via gRPC.

[View Docs](https://scrawn.vercel.app/docs/scrawn-js)

## Key Features

- **Simple API** - Track usage with a single function call
- **Type-Safe** - Full TypeScript support with auto-completion
- **gRPC-Powered** - Built on Connect-RPC for efficient communication
- **Framework Agnostic** - Works with any JavaScript framework
- **Middleware Support** - Built-in middleware with whitelist/blacklist patterns

## Installation

Install Scrawn.js in your project:

```bash
bun add @scrawn/core
```

## Quick Example

```typescript
import { Scrawn } from "@scrawn/core";

const scrawn = new Scrawn({
apiKey: process.env.SCRAWN_KEY as `scrn_${string}`,
baseURL: process.env.SCRAWN_BASE_URL || "http://localhost:8069",
});

// Track a billable event
await scrawn.sdkCallEventConsumer({
userId: "user-123",
debitAmount: 100,
});
```
36 changes: 19 additions & 17 deletions examples/ai-token-stream-usage.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { Scrawn, type AITokenUsagePayload } from '@scrawn/core';
import { config } from 'dotenv';
config({ path: '.env.local' });
import { Scrawn, type AITokenUsagePayload } from "@scrawn/core";
import { config } from "dotenv";
config({ path: ".env.local" });

const scrawn = new Scrawn({
apiKey: (process.env.SCRAWN_KEY || '') as `scrn_${string}`,
baseURL: process.env.SCRAWN_BASE_URL || 'http://localhost:8069',
apiKey: (process.env.SCRAWN_KEY || "") as `scrn_${string}`,
baseURL: process.env.SCRAWN_BASE_URL || "http://localhost:8069",
});

// Simulate what your AI provider wrapper would do:
// As tokens stream from OpenAI/Anthropic/etc, you yield usage events
async function* tokenUsageFromAIStream(): AsyncGenerator<AITokenUsagePayload> {
const userId = 'c0971bcb-b901-4c3e-a191-c9a97871c39f';
const userId = "c0971bcb-b901-4c3e-a191-c9a97871c39f";

// Initial prompt tokens
yield {
userId,
model: 'gpt-4',
model: "gpt-4",
inputTokens: 150,
outputTokens: 0,
inputDebit: { amount: 0.0045 },
Expand All @@ -25,7 +25,7 @@ async function* tokenUsageFromAIStream(): AsyncGenerator<AITokenUsagePayload> {
// Output tokens as they stream
yield {
userId,
model: 'gpt-4',
model: "gpt-4",
inputTokens: 0,
outputTokens: 75,
inputDebit: { amount: 0 },
Expand All @@ -36,28 +36,30 @@ async function* tokenUsageFromAIStream(): AsyncGenerator<AITokenUsagePayload> {
// Example 1: Fire-and-forget mode (default)
// The stream is consumed and sent to backend, you just await the final response
async function fireAndForgetExample() {
console.log('--- Fire-and-forget mode ---');
console.log("--- Fire-and-forget mode ---");

const response = await scrawn.aiTokenStreamConsumer(tokenUsageFromAIStream());

console.log(`Streamed ${response.eventsProcessed} token usage events`);
}

// Example 2: Return mode
// The stream is forked - one fork goes to billing (non-blocking),
// The stream is forked - one fork goes to billing (non-blocking),
// the other is returned to you for streaming to the user
async function returnModeExample() {
console.log('\n--- Return mode (with stream passthrough) ---');
console.log("\n--- Return mode (with stream passthrough) ---");

const { response, stream } = await scrawn.aiTokenStreamConsumer(
tokenUsageFromAIStream(),
{ return: true }
);

// Stream tokens to user while billing happens in background
console.log('Streaming tokens to user:');
console.log("Streaming tokens to user:");
for await (const token of stream) {
console.log(` -> ${token.model}: input=${token.inputTokens}, output=${token.outputTokens}`);
console.log(
` -> ${token.model}: input=${token.inputTokens}, output=${token.outputTokens}`
);
}

// Billing completes after stream is consumed
Expand Down
Loading
Loading