mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
* feat(sse): add live gRPC-web quota fetcher for grok-cli (#6844) * fix(sse): send gRPC-web request frame + decode real GetGrokCreditsConfig schema Live validation against grok.com (real bearer token, tier-4 account) proved the #6844 grok-cli quota fetcher was a silent no-op: - The POST to GetGrokCreditsConfig had no body. gRPC-web requires a request frame even for a no-argument RPC; without one the upstream returns `grpc-status: 13 "Missing request message."` with a 0-byte response. Fixed by sending the empty gRPC-web frame (flag 0x00 + 4-byte length 0). - The decoder's field mapping (top-level field 1 = double percent, field 2 = string resetAt) was reverse-engineered from a third-party doc and never matched the real response. The real shape is: top-level field 1 is a NESTED message whose subfield 1 is a fixed32 float usage ratio (0..1) and subfield 5 is a Timestamp{seconds,nanos} reset time. grokCliQuotaFrame.ts now decodes that nested shape; grokCliQuotaFetcher.ts's buildQuota() rescales the decoder's 0-100 percentUsed back to the 0-1 fraction the rest of the quota pipeline expects (quotaPreflight.ts::remainingPercentFrom). - The response's 2nd gRPC-web frame (trailer, flag 0x80) is now explicitly walked-and-skipped instead of relying on incidental length-bounding. Test fixtures in both files now encode the real captured wire structure (nested message, fixed32 ratio, Timestamp reset, trailer frame) instead of the old synthetic fixed64-double buffers, and the stale "Cloudflare non-blocking is an assumption" comment is corrected to reflect that it is now live-validated.
270 lines
11 KiB
TypeScript
270 lines
11 KiB
TypeScript
/**
|
|
* grokCliQuotaFrame.ts — gRPC-web frame decoder for xAI's
|
|
* `grok_api_v2.GrokBuildBilling/GetGrokCreditsConfig` response (#6844).
|
|
*
|
|
* No public `.proto` schema exists for this endpoint. The field mapping
|
|
* below was reverse-engineered from a LIVE capture against `grok.com` on
|
|
* 2026-07-20 (real bearer token, tier-4 account) — the original
|
|
* field-1-is-a-double / field-2-is-a-string guess (sourced from a
|
|
* third-party doc, steipete/CodexBar) turned out to be wrong: it always
|
|
* decoded the real response to `null`. It is intentionally defensive: any
|
|
* malformed or unrecognized buffer returns `null` rather than throwing, so
|
|
* `grokCliQuotaFetcher.ts` can fail open (same "unknown never disables the
|
|
* connection" convention as `antigravityCredits.ts`).
|
|
*
|
|
* Confirmed real response shape (119-byte capture):
|
|
* top-level field 1 (length-delimited, 92B) — nested "credits info" message
|
|
* subfield 1 (fixed32 float) — usage ratio, 0..1 (1.0 = fully used)
|
|
* subfield 4 (Timestamp{seconds,nanos}) — present in the wild, unused here
|
|
* subfield 5 (Timestamp{seconds,nanos}) — credit-pool reset time
|
|
* subfields 7/8/11/13 — present in the wild, ignored
|
|
*
|
|
* gRPC-web responses may arrive in one of two shapes:
|
|
* - "framed": one or more 5-byte-header frames (1 flag byte + 4-byte
|
|
* big-endian length). A unary call over plain `fetch()` gets the DATA
|
|
* frame (flag 0x00 uncompressed / 0x01 compressed) immediately followed
|
|
* by a TRAILER frame (flag 0x80 / 0x81 — high bit set, e.g.
|
|
* `grpc-status:0`, not protobuf) concatenated in the same response body.
|
|
* `findDataFramePayload()` walks frame-by-frame and returns only the
|
|
* first DATA frame's payload, skipping trailers — they are never handed
|
|
* to the protobuf walker.
|
|
* - "raw": just the protobuf message body, no frame header at all.
|
|
*
|
|
* `probeFrameHeader()` validates a single frame header at a given offset
|
|
* (flag byte must be 0x00/0x01/0x80/0x81 and the declared length must fit
|
|
* the buffer); `decodeGrokCreditsFrame()` falls back to raw parsing only
|
|
* when the buffer doesn't look framed at all.
|
|
*
|
|
* Per proto3 semantics, an *omitted* usage-ratio subfield means 0% used —
|
|
* we never synthesize a different default.
|
|
*/
|
|
|
|
const FIELD_CREDITS_INFO = 1; // top-level: nested message with ratio + timestamps
|
|
|
|
const CREDITS_FIELD_USAGE_RATIO = 1; // nested: fixed32 float, 0..1 fraction used
|
|
const CREDITS_FIELD_RESET_TIMESTAMP = 5; // nested: Timestamp{seconds,nanos} — reset time
|
|
|
|
const TIMESTAMP_FIELD_SECONDS = 1;
|
|
const TIMESTAMP_FIELD_NANOS = 2;
|
|
|
|
const WIRE_TYPE_VARINT = 0;
|
|
const WIRE_TYPE_FIXED64 = 1;
|
|
const WIRE_TYPE_LENGTH_DELIMITED = 2;
|
|
const WIRE_TYPE_FIXED32 = 5;
|
|
|
|
// gRPC-web frame flag byte: high bit set (0x80/0x81) marks a TRAILER frame
|
|
// (HTTP-trailer-style text, not protobuf); high bit unset (0x00/0x01) marks
|
|
// a DATA frame.
|
|
const GRPC_WEB_TRAILER_FLAG_BIT = 0x80;
|
|
|
|
const MAX_VARINT_SHIFT_BITS = 70n;
|
|
|
|
export interface GrokCreditsQuota {
|
|
/** Percent of the shared credit pool used, 0-100 (NOT a 0-1 fraction). */
|
|
percentUsed: number;
|
|
resetAt: string | null;
|
|
}
|
|
|
|
export interface FrameProbeResult {
|
|
flag: number;
|
|
payloadStart: number;
|
|
payloadLength: number;
|
|
}
|
|
|
|
type ProtoField =
|
|
| { wireType: typeof WIRE_TYPE_VARINT; value: number }
|
|
| { wireType: typeof WIRE_TYPE_FIXED64 | typeof WIRE_TYPE_FIXED32 | typeof WIRE_TYPE_LENGTH_DELIMITED; bytes: Buffer };
|
|
|
|
/**
|
|
* Validate a gRPC-web frame header at `offset` in `buffer`. Returns the
|
|
* flag byte plus the payload window when the header looks legitimate (flag
|
|
* is 0x00/0x01 data or 0x80/0x81 trailer, declared length fits inside the
|
|
* remaining buffer) or `null` when there is no valid frame header at that
|
|
* offset — the caller then treats the whole buffer as raw, unframed
|
|
* protobuf (when called at offset 0) or stops frame iteration.
|
|
*/
|
|
export function probeFrameHeader(buffer: Buffer, offset = 0): FrameProbeResult | null {
|
|
if (offset < 0 || buffer.length - offset < 5) return null;
|
|
const flag = buffer[offset];
|
|
if (flag !== 0x00 && flag !== 0x01 && flag !== 0x80 && flag !== 0x81) return null;
|
|
const payloadStart = offset + 5;
|
|
const payloadLength = buffer.readUInt32BE(offset + 1);
|
|
if (payloadLength > buffer.length - payloadStart) return null;
|
|
return { flag, payloadStart, payloadLength };
|
|
}
|
|
|
|
/** Read a protobuf varint starting at `offset`. Returns null past the buffer end. */
|
|
function readVarint(buffer: Buffer, offset: number): { value: number; next: number } | null {
|
|
let result = 0n;
|
|
let shift = 0n;
|
|
let pos = offset;
|
|
for (;;) {
|
|
if (pos >= buffer.length) return null;
|
|
const byte = buffer[pos];
|
|
result |= BigInt(byte & 0x7f) << shift;
|
|
pos += 1;
|
|
if ((byte & 0x80) === 0) break;
|
|
shift += 7n;
|
|
if (shift > MAX_VARINT_SHIFT_BITS) return null;
|
|
}
|
|
return { value: Number(result), next: pos };
|
|
}
|
|
|
|
function readLengthDelimitedField(
|
|
buffer: Buffer,
|
|
offset: number
|
|
): { field: ProtoField; next: number } | null {
|
|
const lengthResult = readVarint(buffer, offset);
|
|
if (!lengthResult) return null;
|
|
const { value: length, next: bodyStart } = lengthResult;
|
|
if (length < 0 || bodyStart + length > buffer.length) return null;
|
|
return {
|
|
field: { wireType: WIRE_TYPE_LENGTH_DELIMITED, bytes: buffer.subarray(bodyStart, bodyStart + length) },
|
|
next: bodyStart + length,
|
|
};
|
|
}
|
|
|
|
function readFixedWidthField(
|
|
buffer: Buffer,
|
|
offset: number,
|
|
width: 4 | 8,
|
|
wireType: typeof WIRE_TYPE_FIXED32 | typeof WIRE_TYPE_FIXED64
|
|
): { field: ProtoField; next: number } | null {
|
|
if (offset + width > buffer.length) return null;
|
|
return { field: { wireType, bytes: buffer.subarray(offset, offset + width) }, next: offset + width };
|
|
}
|
|
|
|
/** Read a single tagged field at `offset`. Returns null on any malformed/unsupported wire data. */
|
|
function readField(
|
|
buffer: Buffer,
|
|
offset: number
|
|
): { fieldNumber: number; field: ProtoField; next: number } | null {
|
|
const tagResult = readVarint(buffer, offset);
|
|
if (!tagResult) return null;
|
|
const fieldNumber = tagResult.value >>> 3;
|
|
const wireType = tagResult.value & 0x7;
|
|
if (fieldNumber === 0) return null;
|
|
|
|
if (wireType === WIRE_TYPE_VARINT) {
|
|
const valueResult = readVarint(buffer, tagResult.next);
|
|
if (!valueResult) return null;
|
|
return {
|
|
fieldNumber,
|
|
field: { wireType: WIRE_TYPE_VARINT, value: valueResult.value },
|
|
next: valueResult.next,
|
|
};
|
|
}
|
|
if (wireType === WIRE_TYPE_LENGTH_DELIMITED) {
|
|
const result = readLengthDelimitedField(buffer, tagResult.next);
|
|
return result ? { fieldNumber, field: result.field, next: result.next } : null;
|
|
}
|
|
if (wireType === WIRE_TYPE_FIXED64) {
|
|
const result = readFixedWidthField(buffer, tagResult.next, 8, WIRE_TYPE_FIXED64);
|
|
return result ? { fieldNumber, field: result.field, next: result.next } : null;
|
|
}
|
|
if (wireType === WIRE_TYPE_FIXED32) {
|
|
const result = readFixedWidthField(buffer, tagResult.next, 4, WIRE_TYPE_FIXED32);
|
|
return result ? { fieldNumber, field: result.field, next: result.next } : null;
|
|
}
|
|
// Deprecated group wire types (3/4) or any other unrecognized wire type — malformed.
|
|
return null;
|
|
}
|
|
|
|
/** Walk a protobuf message body into a field-number -> field map. Never throws. */
|
|
function decodeFields(buffer: Buffer): Map<number, ProtoField> | null {
|
|
const fields = new Map<number, ProtoField>();
|
|
let offset = 0;
|
|
while (offset < buffer.length) {
|
|
const result = readField(buffer, offset);
|
|
if (!result) return null;
|
|
fields.set(result.fieldNumber, result.field);
|
|
offset = result.next;
|
|
}
|
|
return fields;
|
|
}
|
|
|
|
/**
|
|
* Walk consecutive gRPC-web frames from the start of `buffer`, skipping
|
|
* TRAILER frames (flag high bit set — 0x80/0x81) and returning the first
|
|
* DATA frame's payload (flag high bit unset — 0x00/0x01). Returns `null`
|
|
* when no data frame is found before the walk runs out of valid frame
|
|
* headers (a trailer-only buffer, or a malformed frame mid-buffer).
|
|
*/
|
|
function findDataFramePayload(buffer: Buffer): Buffer | null {
|
|
let offset = 0;
|
|
while (offset < buffer.length) {
|
|
const frame = probeFrameHeader(buffer, offset);
|
|
if (!frame) return null;
|
|
const frameEnd = frame.payloadStart + frame.payloadLength;
|
|
const isTrailer = (frame.flag & GRPC_WEB_TRAILER_FLAG_BIT) !== 0;
|
|
if (!isTrailer) {
|
|
return buffer.subarray(frame.payloadStart, frameEnd);
|
|
}
|
|
offset = frameEnd;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/** Decode a length-delimited field's bytes as a nested protobuf message. */
|
|
function extractNestedMessage(field: ProtoField | undefined): Map<number, ProtoField> | null {
|
|
if (!field || field.wireType !== WIRE_TYPE_LENGTH_DELIMITED) return null;
|
|
return decodeFields(field.bytes);
|
|
}
|
|
|
|
/** Read the nested credits-info message's usage-ratio subfield (fixed32 float, 0..1). */
|
|
function extractUsageRatio(field: ProtoField | undefined): number | null {
|
|
if (!field) return 0; // proto3 omission means 0% used
|
|
if (field.wireType === WIRE_TYPE_FIXED32) return field.bytes.readFloatLE(0);
|
|
if (field.wireType === WIRE_TYPE_FIXED64) return field.bytes.readDoubleLE(0);
|
|
return null; // unexpected wire type for the usage-ratio field = malformed
|
|
}
|
|
|
|
/** Read a nested `Timestamp{seconds, nanos}` submessage field as an ISO string. */
|
|
function extractResetAt(field: ProtoField | undefined): string | null {
|
|
if (!field || field.wireType !== WIRE_TYPE_LENGTH_DELIMITED) return null;
|
|
|
|
const timestampFields = decodeFields(field.bytes);
|
|
if (!timestampFields) return null;
|
|
|
|
const secondsField = timestampFields.get(TIMESTAMP_FIELD_SECONDS);
|
|
const nanosField = timestampFields.get(TIMESTAMP_FIELD_NANOS);
|
|
const seconds = secondsField?.wireType === WIRE_TYPE_VARINT ? secondsField.value : 0;
|
|
const nanos = nanosField?.wireType === WIRE_TYPE_VARINT ? nanosField.value : 0;
|
|
|
|
const millis = seconds * 1000 + Math.round(nanos / 1_000_000);
|
|
const parsed = new Date(millis);
|
|
return Number.isNaN(parsed.getTime()) ? null : parsed.toISOString();
|
|
}
|
|
|
|
/**
|
|
* Decode a `GetGrokCreditsConfig` gRPC-web response buffer into
|
|
* `{ percentUsed, resetAt }` (percentUsed on a 0-100 scale), or `null` when
|
|
* the buffer is empty, truncated, trailer-only, or otherwise unparseable.
|
|
* Never throws.
|
|
*/
|
|
export function decodeGrokCreditsFrame(buffer: Buffer): GrokCreditsQuota | null {
|
|
if (!buffer || buffer.length === 0) return null;
|
|
|
|
try {
|
|
const framed = probeFrameHeader(buffer, 0) !== null;
|
|
const payload = framed ? findDataFramePayload(buffer) : buffer;
|
|
if (!payload) return null;
|
|
|
|
const topLevelFields = decodeFields(payload);
|
|
if (!topLevelFields) return null;
|
|
|
|
const creditsInfo = extractNestedMessage(topLevelFields.get(FIELD_CREDITS_INFO));
|
|
if (!creditsInfo) return null;
|
|
|
|
const usageRatio = extractUsageRatio(creditsInfo.get(CREDITS_FIELD_USAGE_RATIO));
|
|
if (usageRatio === null || !Number.isFinite(usageRatio) || usageRatio < 0) return null;
|
|
|
|
return {
|
|
percentUsed: Math.min(100, usageRatio * 100),
|
|
resetAt: extractResetAt(creditsInfo.get(CREDITS_FIELD_RESET_TIMESTAMP)),
|
|
};
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|