From 070d4e289fa50a3b890cf808fb59bbd81f6cc083 Mon Sep 17 00:00:00 2001 From: Devyash Saini Date: Thu, 28 May 2026 11:39:21 +0530 Subject: [PATCH] feat: rename createScrawn() to scrawn(), export Scrawn as type-only --- README.md | 6 +-- examples/scrawn/biller.ts | 4 +- packages/scrawn/README.md | 6 +-- packages/scrawn/src/core/scrawn.ts | 16 ++++---- packages/scrawn/src/index.ts | 6 ++- .../tests/unit/scrawn/middleware.test.ts | 37 +++++++++--------- .../scrawn/tests/unit/scrawn/scrawn.test.ts | 39 ++++++++++--------- 7 files changed, 59 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 07f0630..d9515bc 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,10 @@ bun add @scrawn/core ## Quick Example ```typescript -import { Scrawn } from "@scrawn/core"; +import { scrawn } from "@scrawn/core"; import * as grpc from "@grpc/grpc-js"; -const scrawn = new Scrawn({ +const biller = scrawn({ apiKey: process.env.SCRAWN_KEY as `scrn_${string}`, baseURL: process.env.SCRAWN_BASE_URL || "http://localhost:8069", // secure: false, // optional: allow insecure connections for local dev @@ -36,7 +36,7 @@ const scrawn = new Scrawn({ }); // Track a billable event -await scrawn.sdkCallEventConsumer({ +await biller.sdkCallEventConsumer({ userId: "user-123", debitAmount: 100, }); diff --git a/examples/scrawn/biller.ts b/examples/scrawn/biller.ts index 1c51e6a..19a8c6d 100644 --- a/examples/scrawn/biller.ts +++ b/examples/scrawn/biller.ts @@ -1,7 +1,7 @@ -import { createScrawn } from "@scrawn/core"; +import { scrawn } from "@scrawn/core"; import { TAGS, EXPRESSIONS } from "./pricerefs.ts"; -export const biller = createScrawn({ +export const biller = scrawn({ apiKey: process.env.SCRAWN_KEY as string, baseURL: process.env.SCRAWN_BASE_URL as string, secure: process.env.SCRAWN_BASE_URL?.startsWith("https") ?? false, diff --git a/packages/scrawn/README.md b/packages/scrawn/README.md index 428e420..8268f1e 100644 --- a/packages/scrawn/README.md +++ b/packages/scrawn/README.md @@ -25,15 +25,15 @@ bun add @scrawn/core ## Quick Example ```typescript -import { Scrawn } from "@scrawn/core"; +import { scrawn } from "@scrawn/core"; -const scrawn = new Scrawn({ +const biller = 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({ +await biller.sdkCallEventConsumer({ userId: "user-123", debitAmount: 100, }); diff --git a/packages/scrawn/src/core/scrawn.ts b/packages/scrawn/src/core/scrawn.ts index 7ed87be..707e4ec 100644 --- a/packages/scrawn/src/core/scrawn.ts +++ b/packages/scrawn/src/core/scrawn.ts @@ -84,9 +84,9 @@ const log = new ScrawnLogger("Scrawn"); * * @example * ```typescript - * import { createScrawn } from '@scrawn/core'; + * import { scrawn } from '@scrawn/core'; * - * const biller = createScrawn({ + * const biller = scrawn({ * apiKey: process.env.SCRAWN_KEY, * baseURL: 'http://localhost:8069', * tags: ["PREMIUM_CALL", "EXTRA_FEE"] as const, @@ -1280,7 +1280,7 @@ export class Scrawn< } /** - * Configuration for creating a Scrawn instance via {@link createScrawn}. + * Configuration for creating a Scrawn instance via {@link scrawn}. */ export interface ScrawnInitConfig { apiKey: string; @@ -1306,9 +1306,9 @@ export interface ScrawnInitConfig { * * @example * ```typescript - * import { createScrawn, mul, inputTokens } from '@scrawn/core'; + * import { scrawn, mul, inputTokens } from '@scrawn/core'; * - * const biller = createScrawn({ + * const biller = scrawn({ * apiKey: process.env.SCRAWN_KEY, * baseURL: process.env.SCRAWN_BASE_URL, * tags: ["PREMIUM_CALL", "EXTRA_FEE"] as const, @@ -1325,14 +1325,14 @@ export interface ScrawnInitConfig { * }); * ``` */ -export function createScrawn< +export function scrawn< const TTags extends readonly string[], const TExprs extends readonly string[] >( config: ScrawnInitConfig & { tags: TTags; expressions: TExprs } ): Scrawn; -export function createScrawn(config: ScrawnInitConfig): Scrawn; -export function createScrawn( +export function scrawn(config: ScrawnInitConfig): Scrawn; +export function scrawn( config: ScrawnInitConfig & { tags?: readonly string[]; expressions?: readonly string[]; diff --git a/packages/scrawn/src/index.ts b/packages/scrawn/src/index.ts index f938db8..f3974a1 100644 --- a/packages/scrawn/src/index.ts +++ b/packages/scrawn/src/index.ts @@ -1,4 +1,6 @@ -export * from "./core/scrawn.js"; +export { scrawn } from "./core/scrawn.js"; +export type { Scrawn } from "./core/scrawn.js"; +export type { ScrawnInitConfig } from "./core/scrawn.js"; export * from "./core/types/event.js"; export * from "./core/types/auth.js"; @@ -69,4 +71,4 @@ export type { LanguageModelUsage, ModelInfo, WithUserId, -} from "./core/ai/types.ts"; +} from "./core/ai/types.js"; diff --git a/packages/scrawn/tests/unit/scrawn/middleware.test.ts b/packages/scrawn/tests/unit/scrawn/middleware.test.ts index 969957d..6ef5637 100644 --- a/packages/scrawn/tests/unit/scrawn/middleware.test.ts +++ b/packages/scrawn/tests/unit/scrawn/middleware.test.ts @@ -1,5 +1,6 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { Scrawn } from "../../../src/core/scrawn.js"; +import { scrawn } from "../../../src/core/scrawn.js"; +import type { Scrawn } from "../../../src/core/scrawn.js"; import { ScrawnError, ScrawnValidationError, @@ -24,8 +25,8 @@ const addMetadataMock = vi.fn(function ( }); let requestError: Error | null = null; -function attachMockClient(scrawn: Scrawn): void { - (scrawn as unknown as { grpcClient: unknown }).grpcClient = { +function attachMockClient(s: Scrawn): void { + (s as unknown as { grpcClient: unknown }).grpcClient = { newCall: () => ({ addMetadata: addMetadataMock, addPayload: addPayloadMock, @@ -50,12 +51,12 @@ describe("middlewareEventConsumer", () => { }); it("tracks events for matching paths", async () => { - const scrawn = new Scrawn({ + const biller = scrawn({ apiKey: validKey, baseURL: "https://api.example", }); - attachMockClient(scrawn); - const middleware = scrawn.middlewareEventConsumer({ + attachMockClient(biller); + const middleware = biller.middlewareEventConsumer({ extractor: () => ({ userId: "user_1", debitAmount: 2 }), whitelist: ["/api/**"], }); @@ -69,12 +70,12 @@ describe("middlewareEventConsumer", () => { }); it("skips events for non-whitelisted paths", async () => { - const scrawn = new Scrawn({ + const biller = scrawn({ apiKey: validKey, baseURL: "https://api.example", }); - attachMockClient(scrawn); - const middleware = scrawn.middlewareEventConsumer({ + attachMockClient(biller); + const middleware = biller.middlewareEventConsumer({ extractor: () => ({ userId: "user_1", debitAmount: 2 }), whitelist: ["/billing/**"], }); @@ -88,12 +89,12 @@ describe("middlewareEventConsumer", () => { }); it("skips events when extractor returns null", async () => { - const scrawn = new Scrawn({ + const biller = scrawn({ apiKey: validKey, baseURL: "https://api.example", }); - attachMockClient(scrawn); - const middleware = scrawn.middlewareEventConsumer({ + attachMockClient(biller); + const middleware = biller.middlewareEventConsumer({ extractor: () => null, }); @@ -106,16 +107,16 @@ describe("middlewareEventConsumer", () => { }); it("calls onError when middleware tracking fails", async () => { - const scrawn = new Scrawn({ + const biller = scrawn({ apiKey: validKey, baseURL: "https://api.example", retryCount: 0, }); - attachMockClient(scrawn); + attachMockClient(biller); const onError = vi.fn(); requestError = new Error("grpc down"); - const middleware = scrawn.middlewareEventConsumer({ + const middleware = biller.middlewareEventConsumer({ extractor: () => ({ userId: "user_1", debitAmount: 2 }), onError, }); @@ -131,14 +132,14 @@ describe("middlewareEventConsumer", () => { }); it("calls onError when extracted payload is invalid", async () => { - const scrawn = new Scrawn({ + const biller = scrawn({ apiKey: validKey, baseURL: "https://api.example", }); - attachMockClient(scrawn); + attachMockClient(biller); const onError = vi.fn(); - const middleware = scrawn.middlewareEventConsumer({ + const middleware = biller.middlewareEventConsumer({ extractor: () => ({ userId: "", debitAmount: 2 }), onError, }); diff --git a/packages/scrawn/tests/unit/scrawn/scrawn.test.ts b/packages/scrawn/tests/unit/scrawn/scrawn.test.ts index c0c105e..93004d9 100644 --- a/packages/scrawn/tests/unit/scrawn/scrawn.test.ts +++ b/packages/scrawn/tests/unit/scrawn/scrawn.test.ts @@ -1,5 +1,6 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { Scrawn } from "../../../src/core/scrawn.js"; +import { scrawn } from "../../../src/core/scrawn.js"; +import type { Scrawn } from "../../../src/core/scrawn.js"; import { BasicUsageType } from "../../../src/gen/event/v1/event.js"; import { ScrawnConfigError, @@ -23,8 +24,8 @@ const addMetadataMock = vi.fn(function ( const unaryResponseMock = vi.fn(); let requestError: Error | null = null; -function attachMockClient(scrawn: Scrawn): void { - (scrawn as unknown as { grpcClient: unknown }).grpcClient = { +function attachMockClient(s: Scrawn): void { + (s as unknown as { grpcClient: unknown }).grpcClient = { newCall: (_client: unknown, method: string) => ({ addMetadata: addMetadataMock, addPayload: addPayloadMock, @@ -55,13 +56,13 @@ describe("Scrawn", () => { }); it("tracks basic usage events", async () => { - const scrawn = new Scrawn({ + const biller = scrawn({ apiKey: validKey, baseURL: "https://api.example", }); - attachMockClient(scrawn); + attachMockClient(biller); - await scrawn.basicUsageEventConsumer({ userId: "user_1", debitAmount: 5 }); + await biller.basicUsageEventConsumer({ userId: "user_1", debitAmount: 5 }); const request = requestMock.mock.calls[0][0] as any; expect(request.userId).toBe("user_1"); @@ -73,15 +74,15 @@ describe("Scrawn", () => { }); it("rejects invalid event payloads", async () => { - const scrawn = new Scrawn({ + const biller = scrawn({ apiKey: validKey, baseURL: "https://api.example", }); - attachMockClient(scrawn); + attachMockClient(biller); const onError = vi.fn(); - await scrawn.basicUsageEventConsumer( + await biller.basicUsageEventConsumer( { userId: "", debitAmount: 5 }, { onError } ); @@ -92,12 +93,12 @@ describe("Scrawn", () => { }); it("collects payment links", async () => { - const scrawn = new Scrawn({ + const biller = scrawn({ apiKey: validKey, baseURL: "https://api.example", }); - attachMockClient(scrawn); - const link = await scrawn.collectPayment("user_1"); + attachMockClient(biller); + const link = await biller.collectPayment("user_1"); const request = requestMock.mock.calls[0][0] as any; expect(request.userId).toBe("user_1"); @@ -105,34 +106,34 @@ describe("Scrawn", () => { }); it("validates constructor config", () => { - expect(() => new Scrawn({ apiKey: "", baseURL: "" })).toThrow( + expect(() => scrawn({ apiKey: "", baseURL: "" })).toThrow( ScrawnConfigError ); }); it("validates collectPayment input", async () => { - const scrawn = new Scrawn({ + const biller = scrawn({ apiKey: validKey, baseURL: "https://api.example", }); - attachMockClient(scrawn); + attachMockClient(biller); - await expect(scrawn.collectPayment("")).rejects.toBeInstanceOf( + await expect(biller.collectPayment("")).rejects.toBeInstanceOf( ScrawnValidationError ); }); it("calls onError with retry context when basicUsageEventConsumer fails", async () => { - const scrawn = new Scrawn({ + const biller = scrawn({ apiKey: validKey, baseURL: "https://api.example", retryCount: 0, }); const onError = vi.fn(); requestError = new Error("grpc down"); - attachMockClient(scrawn); + attachMockClient(biller); - await scrawn.basicUsageEventConsumer( + await biller.basicUsageEventConsumer( { userId: "user_1", debitAmount: 5 }, { onError } );