kestrel.markets
Version:
A typed, token-efficient language + runtime for agentic trading: agents author bounded plans, the runtime fires them at the tick. CLI + typed library + MCP server.
191 lines (186 loc) • 6.01 kB
JavaScript
import {
sha256
} from "./bin-8pchjxn2.js";
import {
asOfferResponse,
decodeTrialCapability,
isSseEventType,
isTerminalSseEvent
} from "./bin-2ywrx58g.js";
// src/client/sse-transport.ts
var MAX_RECONNECTS = 5;
class FailClosed {
cause;
constructor(cause) {
this.cause = cause;
}
}
async function consumeSseStream(opts) {
let cursor = opts.cursor;
const budget = opts.maxReconnects ?? MAX_RECONNECTS;
for (let attempt = 0;attempt < budget; attempt++) {
const q = new URLSearchParams({ cursor });
const res = await opts.fetch(`${opts.endpoint}?${q.toString()}`, {
headers: { ...opts.headers, accept: "text/event-stream", "last-event-id": cursor }
});
if (!res.ok)
throw opts.httpError(res.status, "event stream failed");
const stream = res.body;
if (!stream)
throw opts.httpError(500, "event stream had no body");
try {
for await (const f of parseSSE(stream)) {
if (f.id !== undefined)
cursor = f.id;
if (f.data === "" && f.event === undefined)
continue;
const type = f.event ?? "";
if (!opts.isEventType(type))
throw new FailClosed(opts.unknownEventError(type));
let out;
try {
out = opts.onFrame(type, f.data, cursor);
} catch (e) {
throw new FailClosed(e);
}
if (out.cursor)
cursor = out.cursor;
if (out.done)
return;
}
} catch (e) {
if (e instanceof FailClosed)
throw e.cause;
continue;
}
}
throw opts.httpError(504, "event stream did not reach a terminal state after retries");
}
async function* parseSSE(body) {
const reader = body.getReader();
const dec = new TextDecoder;
let buf = "";
for (;; ) {
const { value, done } = await reader.read();
if (done)
break;
buf += dec.decode(value, { stream: true });
let idx;
while ((idx = buf.indexOf(`
`)) >= 0) {
const frame = buf.slice(0, idx);
buf = buf.slice(idx + 2);
let event;
let data = "";
let id;
for (const line of frame.split(`
`)) {
if (line.startsWith(":"))
continue;
if (line.startsWith("event:"))
event = line.slice(6).trim();
else if (line.startsWith("data:"))
data += (data ? `
` : "") + line.slice(5).replace(/^ /, "");
else if (line.startsWith("id:"))
id = line.slice(3).trim();
}
yield { event, data, id };
}
}
}
// src/client/platform-wire.ts
var DEFAULT_API = "https://api.kestrel.markets";
function jsonHeaders() {
return { "content-type": "application/json", accept: "application/json" };
}
function bearerHeader(bearer) {
return bearer !== undefined ? { authorization: `Bearer ${bearer}` } : {};
}
function idemKey(method, path, body) {
return "idem_" + sha256(`${method} ${path}
${JSON.stringify(body)}`).slice(0, 40);
}
async function decodeOfferResponse(res, httpError) {
let body;
try {
body = await res.json();
} catch {
throw httpError(402, "402 body was not a structured OfferResponse");
}
const offer = asOfferResponse(body);
if (offer === null)
throw httpError(402, "402 body missing operation_id/offer{offer_id,scope,amount}/settlement_methods");
return offer;
}
async function parseValidateDiagnostics(res) {
try {
const body = await res.json();
return (body.diagnostics ?? []).map((d) => `${d.severity ?? "error"} ${d.code ?? ""}: ${d.message ?? ""}`.trim());
} catch {
return ["validation_failed"];
}
}
async function mintTrialCapability(opts) {
const body = {};
const res = await opts.fetch(`${opts.base}/capabilities/trial`, {
method: "POST",
headers: { ...jsonHeaders(), "idempotency-key": idemKey("POST", "/capabilities/trial", body) },
body: JSON.stringify(body)
});
if (!res.ok)
throw await opts.onHttpError(res, "trial capability mint failed");
const wire = await res.json();
return { capability: decodeTrialCapability(wire), bearer: wire.capability };
}
async function postEffectful(opts) {
const res = await opts.fetch(`${opts.base}${opts.path}`, {
method: "POST",
headers: { ...jsonHeaders(), ...opts.authHeaders, "idempotency-key": idemKey("POST", opts.path, opts.body) },
body: JSON.stringify(opts.body)
});
if (res.status === 402)
return { gated: true, payment: await decodeOfferResponse(res, opts.httpError) };
if (!res.ok)
throw await opts.onHttpError(res, `POST ${opts.path} failed`);
return { gated: false, value: await res.json() };
}
async function consumeOperationStream(opts) {
const payload = {};
await consumeSseStream({
fetch: opts.fetch,
endpoint: `${opts.base}/operations/${encodeURIComponent(opts.operationId)}/events`,
cursor: opts.cursor,
...opts.headers !== undefined ? { headers: opts.headers } : {},
isEventType: isSseEventType,
httpError: opts.httpError,
unknownEventError: opts.unknownEventError,
onFrame: (type, data, cursor) => {
let env;
if (data !== "") {
try {
env = JSON.parse(data);
} catch {
throw opts.httpError(502, `SSE ${type} carried non-JSON data`);
}
}
if (opts.onEvent)
opts.onEvent({
type,
operationId: env?.operation_id ?? opts.operationId,
cursor: env?.cursor ?? cursor,
...env?.data !== undefined ? { data: env.data } : {}
});
if ((type === "operation.artifact" || type === "operation.receipt") && env?.data)
Object.assign(payload, env.data);
if (isTerminalSseEvent(type)) {
if (type === "operation.failed")
throw opts.httpError(502, "operation failed");
return { done: true };
}
return env?.cursor ? { cursor: env.cursor } : {};
}
});
return { payload };
}
export { DEFAULT_API, jsonHeaders, bearerHeader, idemKey, parseValidateDiagnostics, mintTrialCapability, postEffectful, consumeOperationStream };