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
3 changes: 0 additions & 3 deletions packages/scrawn/proto/event/v1/event.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ message SDKCall {
oneof debit {
float amount = 2;
string tag = 3;
string expr = 4; // Pricing expression (e.g., "add(mul(tag('PREMIUM'),3),250)")
}
}

Expand All @@ -61,13 +60,11 @@ message AITokenUsage {
oneof inputDebit {
float inputAmount = 4;
string inputTag = 5;
string inputExpr = 8; // Pricing expression for input tokens
}

oneof outputDebit {
float outputAmount = 6;
string outputTag = 7;
string outputExpr = 9; // Pricing expression for output tokens
}
}

Expand Down
19 changes: 6 additions & 13 deletions packages/scrawn/src/core/grpc/requestBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import type {
MethodInput,
MethodOutput,
RequestState,
UnaryMethodFn,
} from './types.js';
import type { GrpcCallContext } from './callContext.js';

Expand Down Expand Up @@ -153,20 +152,14 @@ export class RequestBuilder<
this.ctx.logCallStart();
this.ctx.log.debug(`Payload: ${JSON.stringify(this.payload)}`);

// The actual gRPC call.
// Type assertion is required because TypeScript cannot track the relationship
// between a dynamic key access and the resulting function signature in mapped types.
// This is safe because:
// 1. methodName is constrained to ServiceMethodNames<S>
// 2. MethodInput/MethodOutput are derived from the same service definition
const method = this.ctx.client[this.ctx.methodName] as UnaryMethodFn<
MethodInput<S, M>,
MethodOutput<S, M>
>;
const response = await method(this.payload, { headers: this.ctx.getHeaders() });
// The actual gRPC call - fully type-safe!
const response = await (this.ctx.client[this.ctx.methodName] as any)(
this.payload,
{ headers: this.ctx.getHeaders() }
);

this.ctx.logCallSuccess();
return response;
return response as MethodOutput<S, M>;
} catch (error) {
this.ctx.logCallError(error);
throw error;
Expand Down
18 changes: 4 additions & 14 deletions packages/scrawn/src/core/grpc/streamRequestBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import type {
ServiceMethodNames,
MethodInput,
MethodOutput,
ClientStreamingMethodFn,
} from './types.js';
import type { GrpcCallContext } from './callContext.js';

Expand Down Expand Up @@ -102,23 +101,14 @@ export class StreamRequestBuilder<
try {
this.ctx.logCallStart();

// The actual client-streaming gRPC call.
// Type assertion is required because TypeScript cannot track the relationship
// between a dynamic key access and the resulting function signature in mapped types.
// This is safe because:
// 1. methodName is constrained to ServiceMethodNames<S>
// 2. MethodInput/MethodOutput are derived from the same service definition
const method = this.ctx.client[this.ctx.methodName] as ClientStreamingMethodFn<
MethodInput<S, M>,
MethodOutput<S, M>
>;
const response = await method(
iterable as AsyncIterable<Partial<MethodInput<S, M>>>,
// The actual client-streaming gRPC call
const response = await (this.ctx.client[this.ctx.methodName] as any)(
iterable,
{ headers: this.ctx.getHeaders() }
);

this.ctx.logCallSuccess();
return response;
return response as MethodOutput<S, M>;
} catch (error) {
this.ctx.logCallError(error);
throw error;
Expand Down
58 changes: 0 additions & 58 deletions packages/scrawn/src/core/grpc/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,61 +115,3 @@ export type ServerStreamingMethodNames<S extends ServiceType> = MethodsOfKind<S,
* Bidi-streaming methods accept a stream of requests and return a stream of responses.
*/
export type BidiStreamingMethodNames<S extends ServiceType> = MethodsOfKind<S, 'bidi_streaming'>;

/**
* Options passed to gRPC method calls.
* Matches CallOptions from @connectrpc/connect.
*/
export interface GrpcCallOptions {
headers?: Headers;
signal?: AbortSignal;
timeoutMs?: number;
onHeader?: (headers: globalThis.Headers) => void;
onTrailer?: (trailers: globalThis.Headers) => void;
}

/**
* Function signature for a unary gRPC method.
* Takes a partial message and options, returns a promise of the response.
*
* @template I - Input message type
* @template O - Output message type
*/
export type UnaryMethodFn<I, O> = (
request: Partial<I>,
options?: GrpcCallOptions
) => Promise<O>;

/**
* Function signature for a client-streaming gRPC method.
* Takes an async iterable of partial messages and options, returns a promise of the response.
*
* @template I - Input message type
* @template O - Output message type
*/
export type ClientStreamingMethodFn<I, O> = (
request: AsyncIterable<Partial<I>>,
options?: GrpcCallOptions
) => Promise<O>;

/**
* Get the method function type from a Client for a specific method.
* This properly extracts the callable type for dynamic method access.
*
* Note: Due to TypeScript limitations with mapped types and dynamic keys,
* this type is used with type assertions when accessing client methods
* via computed property names. The assertion is safe because:
* 1. The method name M is constrained to ServiceMethodNames<S>
* 2. The input/output types are derived from the same service definition
*
* @template S - The gRPC service type
* @template M - The method name on the service
*/
export type ClientMethod<
S extends ServiceType,
M extends ServiceMethodNames<S>
> = S['methods'][M] extends { kind: 'unary' }
? UnaryMethodFn<MethodInput<S, M>, MethodOutput<S, M>>
: S['methods'][M] extends { kind: 'client_streaming' }
? ClientStreamingMethodFn<MethodInput<S, M>, MethodOutput<S, M>>
: never;
167 changes: 0 additions & 167 deletions packages/scrawn/src/core/pricing/builders.ts

This file was deleted.

42 changes: 0 additions & 42 deletions packages/scrawn/src/core/pricing/index.ts

This file was deleted.

Loading
Loading