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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ const biller = scrawn({
// Track a billable event
await biller.sdkCallEventConsumer({
userId: "user-123",
debitAmount: 100,
debit: 100,
});
```
4 changes: 2 additions & 2 deletions examples/ai-sdk-wrapper-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ config({ path: ".env.local" });

async function main() {
const aii = biller.ai(ai, {
inputDebit: { tag: "PREMIUM_CALL" },
outputDebit: { tag: "EXTRA_FEE" },
inputDebit: biller.tag("PREMIUM_CALL"),
outputDebit: biller.expr("COMPLEX_FEE"),
});

const result = await aii.streamText({
Expand Down
14 changes: 4 additions & 10 deletions examples/ai-token-stream-expr-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,17 @@ async function* tokenUsageFromAIStream(): AsyncGenerator<
model: "gpt-4",
inputTokens: 150,
outputTokens: 0,
inputDebit: { expr: biller.expr("PER_TOKEN_INPUT") },
outputDebit: {
expr: biller.expr(mul(biller.tag("EXTRA_FEE"), outputTokens())),
},
inputDebit: biller.expr("PER_TOKEN_INPUT"),
outputDebit: mul(biller.tag("EXTRA_FEE"), outputTokens()),
};

yield {
userId,
model: "gpt-4",
inputTokens: 0,
outputTokens: 75,
inputDebit: {
expr: biller.expr(mul(biller.tag("PREMIUM_CALL"), inputTokens())),
},
outputDebit: {
expr: biller.expr(mul(biller.tag("EXTRA_FEE"), outputTokens())),
},
inputDebit: mul(biller.tag("PREMIUM_CALL"), inputTokens()),
outputDebit: mul(biller.tag("EXTRA_FEE"), outputTokens()),
};
}

Expand Down
8 changes: 4 additions & 4 deletions examples/ai-token-stream-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ async function* tokenUsageFromAIStream() {
model: "gpt-4",
inputTokens: 150,
outputTokens: 0,
inputDebit: { amount: 1 },
outputDebit: { amount: 0 },
inputDebit: 1,
outputDebit: 0,
};

// Output tokens as they stream
Expand All @@ -19,8 +19,8 @@ async function* tokenUsageFromAIStream() {
model: "gpt-4",
inputTokens: 0,
outputTokens: 75,
inputDebit: { amount: 0 },
outputDebit: { amount: 1 },
inputDebit: 0,
outputDebit: 1,
};
}

Expand Down
8 changes: 3 additions & 5 deletions examples/basic-usage-expr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,17 @@ config({ path: ".env.local" });
async function main() {
await biller.basicUsageEventConsumer({
userId: "c0971bcb-b901-4c3e-a191-c9a97871c39f",
debitExpr: biller.expr(mul(biller.tag("PREMIUM_CALL"), 3)),
debit: mul(biller.tag("PREMIUM_CALL"), 3),
});

await biller.basicUsageEventConsumer({
userId: "c0971bcb-b901-4c3e-a191-c9a97871c39f",
debitExpr: biller.expr(mul(biller.tag("EXTRA_FEE"), 3)),
debit: mul(biller.tag("EXTRA_FEE"), 3),
});

await biller.basicUsageEventConsumer({
userId: "c0971bcb-b901-4c3e-a191-c9a97871c39f",
debitExpr: biller.expr(
add(biller.expr("COMPLEX_FEE"), mul(biller.tag("PREMIUM_CALL"), 5))
),
debit: add(biller.expr("COMPLEX_FEE"), mul(biller.tag("PREMIUM_CALL"), 5)),
});

console.log("Basic usage expression events consumed successfully");
Expand Down
4 changes: 2 additions & 2 deletions examples/basic-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { biller } from "./scrawn/biller.ts";
async function main() {
await biller.basicUsageEventConsumer({
userId: "c0971bcb-b901-4c3e-a191-c9a97871c39f",
debitAmount: 3000,
debit: 3000,
});

await biller.basicUsageEventConsumer({
userId: "c0971bcb-b901-4c3e-a191-c9a97871c39f",
debitTag: "PREMIUM_CALL",
debit: biller.tag("PREMIUM_CALL"),
});

console.log("Basic usage events consumed successfully");
Expand Down
2 changes: 1 addition & 1 deletion examples/middleware-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ app.use(
biller.middlewareEventConsumer({
extractor: (req) => ({
userId: (req.headers?.["x-user-id"] as string) || "anonymous",
debitAmount: req.body?.cost || 1,
debit: req.body?.cost || 1,
}),
blacklist: ["/api/collect-payment", "/api/status"],
})
Expand Down
2 changes: 1 addition & 1 deletion packages/scrawn/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ const biller = scrawn({
// Track a billable event
await biller.sdkCallEventConsumer({
userId: "user-123",
debitAmount: 100,
debit: 100,
});
```
10 changes: 5 additions & 5 deletions packages/scrawn/src/core/ai/track.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { AITokenUsagePayload, DebitField } from "../types/event.js";
import type { AITokenUsagePayload, Debit } from "../types/event.js";
import type {
BillableCallParams,
LanguageModelUsage,
Expand All @@ -15,10 +15,10 @@ export function buildAIPayload<TTag extends string = string>(
usage: LanguageModelUsage,
overrides: BillableCallParams<TTag>,
defaults: {
inputDebit: DebitField<TTag>;
outputDebit: DebitField<TTag>;
inputCacheDebit: DebitField<TTag>;
outputCacheDebit: DebitField<TTag>;
inputDebit: Debit<TTag>;
outputDebit: Debit<TTag>;
inputCacheDebit: Debit<TTag>;
outputCacheDebit: Debit<TTag>;
provider?: string;
}
): AITokenUsagePayload<TTag> {
Expand Down
18 changes: 9 additions & 9 deletions packages/scrawn/src/core/ai/types.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import type { DebitField } from "../types/event.js";
import type { Debit } from "../types/event.js";

/**
* Configuration for the biller.ai() wrapper.
* Default billing settings applied automatically to all AI SDK calls.
*/
export interface BillableAIOptions<TTag extends string = string> {
/** Default billing for input tokens (required). */
inputDebit: DebitField<TTag>;
inputDebit: Debit<TTag>;
/** Default billing for output tokens (required). */
outputDebit: DebitField<TTag>;
outputDebit: Debit<TTag>;
/** Default billing for cached input tokens. Falls back to inputDebit if not set. */
inputCacheDebit?: DebitField<TTag>;
inputCacheDebit?: Debit<TTag>;
/** Default billing for cached output tokens. Falls back to outputDebit if not set. */
outputCacheDebit?: DebitField<TTag>;
outputCacheDebit?: Debit<TTag>;
/** Default provider override. If not set, auto-detected from the model's provider. */
provider?: string;
}
Expand All @@ -25,13 +25,13 @@ export interface BillableCallParams<TTag extends string = string> {
/** The user ID to bill against. If omitted, billing is skipped. */
userId?: string;
/** Override input token billing for this specific call. */
inputDebit?: DebitField<TTag>;
inputDebit?: Debit<TTag>;
/** Override output token billing for this specific call. */
outputDebit?: DebitField<TTag>;
outputDebit?: Debit<TTag>;
/** Override cached input token billing for this specific call. */
inputCacheDebit?: DebitField<TTag>;
inputCacheDebit?: Debit<TTag>;
/** Override cached output token billing for this specific call. */
outputCacheDebit?: DebitField<TTag>;
outputCacheDebit?: Debit<TTag>;
/** Override provider for this specific call. */
provider?: string;
}
Expand Down
6 changes: 1 addition & 5 deletions packages/scrawn/src/core/pricing/builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import type {
PriceExpr,
ExprInput,
ExprRef,
ScrawnExpr,
} from "./types.js";
import { validateExpr } from "./validate.js";

Expand All @@ -37,10 +36,7 @@ function toExpr<TTag extends string = string>(
if (typeof input === "number") {
return { kind: "amount", value: input } as const;
}
if ("_expr" in (input as unknown as Record<string, unknown>)) {
return (input as ScrawnExpr<TTag>)._expr as PriceExpr<TTag>;
}
return input as PriceExpr<TTag>;
return input;
}

/**
Expand Down
1 change: 0 additions & 1 deletion packages/scrawn/src/core/pricing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export type {
InputTokensExpr,
OutputTokensExpr,
ExprRef,
ScrawnExpr,
PriceExpr,
ExprInput,
} from "./types.js";
Expand Down
27 changes: 1 addition & 26 deletions packages/scrawn/src/core/pricing/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,28 +82,6 @@ export interface ExprRef {
readonly name: string;
}

/**
* A wrapped pricing expression — the only type accepted by `debitExpr` fields.
*
* Created exclusively via `biller.expr()`. This wrapper ensures all expressions
* flow through a consistent entry point that provides type-safety for both
* inline expressions and persisted expression references.
*
* @typeParam TTag - The tag name type flowing through the expression tree
*
* @example
* ```typescript
* // inline expression
* const expr = biller.expr(mul(biller.tag("PREMIUM_CALL"), 3));
*
* // persisted expression reference
* const expr = biller.expr("MY_EXPR");
* ```
*/
export interface ScrawnExpr<TTag extends string = string> {
readonly _expr: PriceExpr<TTag> | ExprRef;
}

/**
* A pricing expression - can be a literal amount, a tag reference, an operation,
* a token placeholder (inputTokens/outputTokens), or a persisted expression reference.
Expand All @@ -124,7 +102,4 @@ export type PriceExpr<TTag extends string = string> =
*
* @typeParam TTag - The tag name type flowing through the expression tree
*/
export type ExprInput<TTag extends string = string> =
| PriceExpr<TTag>
| ScrawnExpr<TTag>
| number;
export type ExprInput<TTag extends string = string> = PriceExpr<TTag> | number;
Loading
Loading