feat: add autonomous Surplus seller

This commit is contained in:
david
2026-08-27 12:48:18 +02:00
parent 2b8409a499
commit 732de817aa
17 changed files with 3074 additions and 2 deletions

View File

@@ -132,3 +132,28 @@ ADVERT_DETAIL_HASH=
# MAX_CHAT_SESSIONS=1 # concurrent session slots (default 1)
# CHAT_SETTLE_MODE=full # "full" (Claim/Submit) or "ticket" (no supplier
# # chain ops; buyer reclaims the Open escrow)
# ─── Autonomous Surplus seller (surplus:start) ────────────────────────────
# This service uses a seller-scoped Surplus key. It does not need a wallet
# private key. Keep both API keys in the host-only surplus-seller.env file.
SURPLUS_LIVE=
SURPLUS_API_URL=https://api.surplusintelligence.ai
SURPLUS_SELLER_API_KEY=si_seller_REPLACE_ME
SURPLUS_OPENROUTER_API_KEY=sk-or-v1-REPLACE_ME
SURPLUS_PROVIDER_BASE_URL=https://openrouter.ai/api/v1
OPENROUTER_CAPACITY_BASE_URL=https://openrouter.ai/api
SURPLUS_SELLER_WALLET=0x0000000000000000000000000000000000000000
SURPLUS_PAYOUT_ADDRESS=0x0000000000000000000000000000000000000000
# The controller discovers all fixed-price text models and selects one by
# current demand. It keeps only one active proof offer.
SURPLUS_PER_OFFER_CAP_USD=1.00
SURPLUS_AGGREGATE_CAP_USD=1.00
SURPLUS_OPENROUTER_RESERVE_USD=1.00
SURPLUS_OPENROUTER_MAX_LIMIT_USD=20.00
SURPLUS_MIN_RECOVERY_BPS=490
SURPLUS_UNDERCUT_BPS=10
SURPLUS_MAX_CANDIDATE_ORDER_BOOKS=10
SURPLUS_REPRICE_INTERVAL_MS=300000
SURPLUS_REQUEST_TIMEOUT_MS=120000
SURPLUS_STOP_AFTER_SETTLED_REQUESTS=1
SURPLUS_STATE_PATH=/var/lib/surplus-manager/state.json

View File

@@ -70,6 +70,9 @@ COPY --from=builder /repo /repo
# Drop privileges. The official node image ships a non-root `node` user.
RUN chown -R node:node /repo
RUN mkdir -p /var/lib/surplus-manager \
&& chown node:node /var/lib/surplus-manager \
&& chmod 700 /var/lib/surplus-manager
USER node
ENV NODE_ENV=production

View File

@@ -10,7 +10,8 @@
"tx:retire-advert": "tsx src/cli/retire-advert.ts",
"tx:publish-reference-scripts": "tsx src/cli/publish-reference-scripts.ts",
"tx:consolidate-wallet": "tsx src/cli/consolidate-wallet.ts",
"reseller:setup": "tsx src/cli/setup-reseller.ts"
"reseller:setup": "tsx src/cli/setup-reseller.ts",
"surplus:start": "tsx src/cli/surplus-seller.ts"
},
"dependencies": {
"@marketplace/shared": "workspace:*",

View File

@@ -0,0 +1,92 @@
import { createServer, type Server } from "node:http";
import { fileURLToPath } from "node:url";
import { resolve } from "node:path";
import { loadSurplusManagerConfig } from "../surplus/config.js";
import { SurplusClient } from "../surplus/client.js";
import { SurplusSellerController } from "../surplus/controller.js";
import { OpenRouterKeyClient } from "../surplus/openRouterKey.js";
import { FileSurplusStateStore } from "../surplus/state.js";
export async function runSurplusSeller(
env: Record<string, string | undefined>,
): Promise<{ server: Server; controller: SurplusSellerController }> {
const config = loadSurplusManagerConfig(env);
const client = new SurplusClient({
apiBaseUrl: config.apiBaseUrl,
sellerApiKey: config.sellerApiKey,
timeoutMs: config.requestTimeoutMs,
});
const allowance = new OpenRouterKeyClient({
baseUrl: config.capacityBaseUrl,
apiKey: config.providerApiKey,
timeoutMs: config.requestTimeoutMs,
});
const stateStore = new FileSurplusStateStore(config.statePath);
const controller = new SurplusSellerController({
config,
client,
allowance,
stateStore,
log: (message) => console.log(message),
});
const server = createStatusServer(controller);
await new Promise<void>((resolveListen, rejectListen) => {
server.once("error", rejectListen);
server.listen(config.port, "0.0.0.0", () => {
server.off("error", rejectListen);
resolveListen();
});
});
await controller.start();
return { server, controller };
}
function createStatusServer(controller: SurplusSellerController): Server {
return createServer((request, response) => {
const status = controller.snapshot();
if (request.method === "GET" && request.url === "/healthz") {
const healthy = controller.healthy();
response.statusCode = healthy ? 200 : 503;
response.setHeader("content-type", "application/json");
response.end(JSON.stringify({ ok: healthy, phase: status.phase }));
return;
}
if (request.method === "GET" && request.url === "/status") {
response.statusCode = 200;
response.setHeader("content-type", "application/json");
response.end(JSON.stringify(status));
return;
}
response.statusCode = 404;
response.setHeader("content-type", "application/json");
response.end(JSON.stringify({ error: "not_found" }));
});
}
export async function main(
env: Record<string, string | undefined> = process.env,
): Promise<void> {
const { server, controller } = await runSurplusSeller(env);
console.log("Surplus seller controller listening");
let shuttingDown = false;
const shutdown = async (signal: string): Promise<void> => {
if (shuttingDown) return;
shuttingDown = true;
console.log(`Surplus seller controller shutting down (${signal})`);
await controller.stop();
await new Promise<void>((resolveClose, rejectClose) => {
server.close((error) => error ? rejectClose(error) : resolveClose());
});
};
process.on("SIGINT", () => void shutdown("SIGINT"));
process.on("SIGTERM", () => void shutdown("SIGTERM"));
}
const invoked = fileURLToPath(import.meta.url) === resolve(process.argv[1] ?? "");
if (invoked) {
main().catch((error) => {
const detail = error instanceof Error ? error.message : String(error);
console.error(`Surplus seller controller failed: ${detail}`);
process.exitCode = 1;
});
}

View File

@@ -0,0 +1,508 @@
export interface SurplusOffer {
id: string;
model: string;
sellerBaseUrl: string;
status: "active" | "inactive";
capDailyUsd: number | null;
inputMicroUsdPer1m: number | null;
outputMicroUsdPer1m: number | null;
}
export interface SurplusDiscoveredModel {
model: string;
supported: boolean;
inputUsdPer1m: number;
outputUsdPer1m: number;
priceUnit: string;
priceVariable: boolean;
providerModelId: string;
modelType: string;
availabilityStatus: string;
}
export interface SurplusMarketSummary {
model: string;
requests24h: number;
volume24h: number;
bestInputMicroUsdPer1m: number;
bestOutputMicroUsdPer1m: number;
healthySellerCount: number;
}
export interface SurplusOrderBookOffer {
id: string;
seller: string;
sellerBaseUrl: string;
inputMicroUsdPer1m: number;
outputMicroUsdPer1m: number;
available: boolean;
healthy: boolean;
trusted: boolean;
trades24h: number;
}
export interface SurplusOrderBook {
model: string;
offers: SurplusOrderBookOffer[];
}
export interface SurplusOfferWrite {
model: string;
apiKey: string;
sellerBaseUrl: string;
inputUsdPer1m: number;
outputUsdPer1m: number;
dailyCapUsd: number;
payoutAddress: string;
idempotencyKey: string;
}
export interface SurplusOfferPatch {
inputUsdPer1m: number;
outputUsdPer1m: number;
dailyCapUsd: number;
idempotencyKey: string;
}
export interface SurplusSale {
model: string;
offerId: string | null;
settlementStatus: string;
createdAt: string | null;
sellerCostMicroUsd: number;
}
export interface SurplusEarnings {
totalEarnedMicroUsd: number;
pendingMicroUsd: number;
paidMicroUsd: number;
recentSales: SurplusSale[];
}
interface SurplusClientOptions {
apiBaseUrl: string;
sellerApiKey: string;
timeoutMs: number;
fetchFn?: typeof globalThis.fetch;
}
const MAX_RESPONSE_BYTES = 16 * 1024 * 1024;
export class SurplusHttpError extends Error {
readonly status: number | null;
readonly retryAfter: string | null;
constructor(message: string, status: number | null, retryAfter: string | null = null) {
super(message);
this.name = "SurplusHttpError";
this.status = status;
this.retryAfter = retryAfter;
}
get ambiguousMutation(): boolean {
return this.status === null || this.status >= 500;
}
}
export class SurplusClient {
private readonly apiBaseUrl: string;
private readonly sellerApiKey: string;
private readonly timeoutMs: number;
private readonly fetchFn: typeof globalThis.fetch;
constructor(options: SurplusClientOptions) {
this.apiBaseUrl = options.apiBaseUrl.replace(/\/+$/, "");
this.sellerApiKey = options.sellerApiKey;
this.timeoutMs = options.timeoutMs;
this.fetchFn = options.fetchFn ?? globalThis.fetch;
}
async listAllOffers(): Promise<SurplusOffer[]> {
const items: SurplusOffer[] = [];
const seenTokens = new Set<string>();
let nextToken: string | null = null;
for (;;) {
const params = new URLSearchParams();
if (nextToken !== null) params.set("next_token", nextToken);
const query = params.toString();
const body = await this.requestJson(`/v1/seller/offers${query ? `?${query}` : ""}`);
const root = record(body, "Surplus offers response");
if (!Array.isArray(root.items)) {
throw new Error("Surplus offers response.items must be an array");
}
items.push(...root.items.map((item, index) => parseOffer(item, items.length + index)));
const rawNext = root.next_token;
if (rawNext === undefined || rawNext === null || rawNext === "") break;
if (typeof rawNext !== "string") {
throw new Error("Surplus offers response.next_token must be a string or null");
}
if (seenTokens.has(rawNext)) {
throw new Error("Surplus offers pagination repeated a next_token");
}
seenTokens.add(rawNext);
nextToken = rawNext;
if (seenTokens.size > 10_000) {
throw new Error("Surplus offers pagination exceeded 10000 pages");
}
}
return items;
}
async discoverModels(apiKey: string, baseUrl: string): Promise<SurplusDiscoveredModel[]> {
const response = await this.requestText("/v1/seller/discover", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ api_key: apiKey, base_url: baseUrl }),
});
if (response.text.trim() === "") {
throw new Error("Surplus discovery returned an empty body");
}
return response.text
.split(/\r?\n/)
.filter((line) => line.trim() !== "")
.map((line, index) => {
let value: unknown;
try {
value = JSON.parse(line);
} catch {
throw new Error(`Surplus discovery line ${index + 1} was not complete JSON`);
}
return parseDiscoveredModel(value, index);
});
}
async getMarkets(): Promise<SurplusMarketSummary[]> {
const body = await this.requestJson("/api/markets", {}, false);
const root = record(body, "Surplus markets response");
if (!Array.isArray(root.markets)) {
throw new Error("Surplus markets response.markets must be an array");
}
return root.markets.map((item, index) => parseMarketSummary(item, index));
}
async getOrderBook(model: string): Promise<SurplusOrderBook> {
const body = await this.requestJson(
`/api/markets/${encodeURIComponent(model)}`,
{},
false,
);
const root = record(body, "Surplus order book response");
const returnedModel = string(root.model, "Surplus order book model");
if (returnedModel !== model) {
throw new Error(`Surplus order book returned model ${returnedModel} for ${model}`);
}
if (!Array.isArray(root.offers)) {
throw new Error("Surplus order book response.offers must be an array");
}
const ids = new Set<string>();
const offers = root.offers.map((item, index) => {
const offer = parseOrderBookOffer(item, index);
if (ids.has(offer.id)) throw new Error(`Surplus order book repeated offer ${offer.id}`);
ids.add(offer.id);
return offer;
});
return { model, offers };
}
async testConnection(apiKey: string, baseUrl: string, model: string): Promise<number> {
const body = await this.requestJson("/v1/seller/test-connection", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ api_key: apiKey, base_url: baseUrl, model }),
});
const root = record(body, "Surplus connection response");
if (root.ok !== true) throw new Error("Surplus provider connection test failed");
return nonNegativeNumber(root.latency_ms, "Surplus connection latency_ms");
}
async createOffer(input: SurplusOfferWrite): Promise<string> {
const body = await this.requestJson("/v1/seller/offers", {
method: "POST",
headers: mutationHeaders(input.idempotencyKey),
body: JSON.stringify({
model: input.model,
api_key: input.apiKey,
seller_base_url: input.sellerBaseUrl,
pricing_mode: "per_token",
price_input_per_1m: input.inputUsdPer1m,
price_output_per_1m: input.outputUsdPer1m,
cap_daily_usd: input.dailyCapUsd,
payout_address: input.payoutAddress,
}),
});
const root = record(body, "Surplus create offer response");
return offerId(root, "Surplus create offer response");
}
async updateOffer(id: string, patch: SurplusOfferPatch): Promise<void> {
await this.requestText(`/v1/seller/offers/${encodeURIComponent(id)}`, {
method: "PATCH",
headers: mutationHeaders(patch.idempotencyKey),
body: JSON.stringify({
pricing_mode: "per_token",
price_input_per_1m: patch.inputUsdPer1m,
price_output_per_1m: patch.outputUsdPer1m,
cap_daily_usd: patch.dailyCapUsd,
}),
});
}
async pauseOffer(id: string, idempotencyKey: string): Promise<void> {
await this.requestText(`/v1/seller/offers/${encodeURIComponent(id)}`, {
method: "PATCH",
headers: mutationHeaders(idempotencyKey),
body: JSON.stringify({ status: "paused" }),
});
}
async resumeOffer(id: string, idempotencyKey: string): Promise<void> {
await this.requestText(`/v1/seller/offers/${encodeURIComponent(id)}`, {
method: "PATCH",
headers: mutationHeaders(idempotencyKey),
body: JSON.stringify({ status: "active" }),
});
}
async getEarnings(): Promise<SurplusEarnings> {
const body = await this.requestJson("/v1/seller/earnings?range=lifetime");
const root = record(body, "Surplus earnings response");
const rawSales = root.recent_sales;
if (!Array.isArray(rawSales)) {
throw new Error("Surplus earnings response.recent_sales must be an array");
}
return {
totalEarnedMicroUsd: microUsd(root.total_earned_usdc, "total_earned_usdc"),
pendingMicroUsd: microUsd(root.pending_usdc, "pending_usdc"),
paidMicroUsd: microUsd(root.paid_usdc, "paid_usdc"),
recentSales: rawSales.map((sale, index) => parseSale(sale, index)),
};
}
private async requestJson(
path: string,
init: RequestInit = {},
authenticated = true,
): Promise<unknown> {
const response = await this.requestText(path, init, authenticated);
if (response.text === "") return {};
try {
return JSON.parse(response.text);
} catch {
throw new Error(`Surplus ${path} response was not JSON`);
}
}
private async requestText(
path: string,
init: RequestInit = {},
authenticated = true,
): Promise<{ status: number; text: string }> {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
const headers = new Headers(init.headers);
if (authenticated) headers.set("authorization", `Bearer ${this.sellerApiKey}`);
try {
const response = await this.fetchFn(`${this.apiBaseUrl}${path}`, {
...init,
headers,
redirect: "error",
signal: controller.signal,
});
const text = await readBoundedText(response, controller);
if (!response.ok) {
throw new SurplusHttpError(
`Surplus ${path} returned HTTP ${response.status}${
text ? `: ${sanitizedErrorSnippet(text)}` : ""
}`,
response.status,
response.headers.get("retry-after"),
);
}
return { status: response.status, text };
} catch (error) {
if (error instanceof SurplusHttpError) throw error;
const detail = error instanceof Error ? error.message : String(error);
throw new SurplusHttpError(`Surplus ${path} request failed: ${detail}`, null);
} finally {
clearTimeout(timer);
}
}
}
async function readBoundedText(
response: Response,
controller: AbortController,
): Promise<string> {
if (!response.body) return "";
const reader = response.body.getReader();
const decoder = new TextDecoder();
let bytes = 0;
let text = "";
try {
for (;;) {
const chunk = await reader.read();
if (chunk.done) break;
bytes += chunk.value.byteLength;
if (bytes > MAX_RESPONSE_BYTES) {
controller.abort();
throw new Error(`response exceeded ${MAX_RESPONSE_BYTES} bytes`);
}
text += decoder.decode(chunk.value, { stream: true });
}
return text + decoder.decode();
} finally {
reader.releaseLock();
}
}
function mutationHeaders(idempotencyKey: string): Headers {
const headers = new Headers({ "content-type": "application/json" });
headers.set("idempotency-key", idempotencyKey);
return headers;
}
function parseOffer(value: unknown, index: number): SurplusOffer {
const item = record(value, `Surplus offer ${index}`);
const statusRaw = item.status;
const status = statusRaw === "active" || item.active === true
? "active"
: statusRaw === "inactive" || statusRaw === "paused" || item.active === false
? "inactive"
: (() => { throw new Error(`Surplus offer ${index}.status was invalid`); })();
return {
id: offerId(item, `Surplus offer ${index}`),
model: string(item.model, `Surplus offer ${index}.model`),
sellerBaseUrl: string(item.seller_base_url, `Surplus offer ${index}.seller_base_url`),
status,
capDailyUsd: optionalNonNegativeNumber(item.cap_daily_usd, `Surplus offer ${index}.cap_daily_usd`),
inputMicroUsdPer1m: optionalMicroUsd(item.price_input_per_1m, `Surplus offer ${index}.price_input_per_1m`),
outputMicroUsdPer1m: optionalMicroUsd(item.price_output_per_1m, `Surplus offer ${index}.price_output_per_1m`),
};
}
function parseDiscoveredModel(value: unknown, index: number): SurplusDiscoveredModel {
const item = record(value, `Surplus discovery item ${index}`);
const pricing = record(item.pricing, `Surplus discovery item ${index}.pricing`);
const metadata = record(item.metadata, `Surplus discovery item ${index}.metadata`);
return {
model: string(item.model, `Surplus discovery item ${index}.model`),
supported: boolean(item.supported, `Surplus discovery item ${index}.supported`),
inputUsdPer1m: nonNegativeNumber(pricing.input_per_1m, `Surplus discovery item ${index}.pricing.input_per_1m`),
outputUsdPer1m: nonNegativeNumber(pricing.output_per_1m, `Surplus discovery item ${index}.pricing.output_per_1m`),
priceUnit: optionalString(pricing.price_unit) ?? "M",
priceVariable: pricing.price_variable === undefined ? false : boolean(pricing.price_variable, `Surplus discovery item ${index}.pricing.price_variable`),
providerModelId: string(metadata.provider_model_id, `Surplus discovery item ${index}.metadata.provider_model_id`),
modelType: string(metadata.model_type, `Surplus discovery item ${index}.metadata.model_type`),
availabilityStatus: string(metadata.availability_status, `Surplus discovery item ${index}.metadata.availability_status`),
};
}
function parseMarketSummary(value: unknown, index: number): SurplusMarketSummary {
const item = record(value, `Surplus market ${index}`);
return {
model: string(item.model, `Surplus market ${index}.model`),
requests24h: nonNegativeSafeInteger(item.requests_24h, `Surplus market ${index}.requests_24h`),
volume24h: nonNegativeSafeInteger(item.volume_24h, `Surplus market ${index}.volume_24h`),
bestInputMicroUsdPer1m: nonNegativeSafeInteger(item.best_input_per_1m, `Surplus market ${index}.best_input_per_1m`),
bestOutputMicroUsdPer1m: nonNegativeSafeInteger(item.best_output_per_1m, `Surplus market ${index}.best_output_per_1m`),
healthySellerCount: nonNegativeSafeInteger(item.healthy_seller_count, `Surplus market ${index}.healthy_seller_count`),
};
}
function parseOrderBookOffer(value: unknown, index: number): SurplusOrderBookOffer {
const item = record(value, `Surplus order book offer ${index}`);
return {
id: offerId(item, `Surplus order book offer ${index}`),
seller: string(item.seller, `Surplus order book offer ${index}.seller`).toLowerCase(),
sellerBaseUrl: string(item.seller_base_url, `Surplus order book offer ${index}.seller_base_url`),
inputMicroUsdPer1m: positiveSafeInteger(item.effective_input_per_1m, `Surplus order book offer ${index}.effective_input_per_1m`),
outputMicroUsdPer1m: positiveSafeInteger(item.effective_output_per_1m, `Surplus order book offer ${index}.effective_output_per_1m`),
available: boolean(item.available, `Surplus order book offer ${index}.available`),
healthy: boolean(item.healthy, `Surplus order book offer ${index}.healthy`),
trusted: boolean(item.trusted, `Surplus order book offer ${index}.trusted`),
trades24h: nonNegativeSafeInteger(item.trades_24h, `Surplus order book offer ${index}.trades_24h`),
};
}
function parseSale(value: unknown, index: number): SurplusSale {
const item = record(value, `Surplus sale ${index}`);
return {
model: string(item.model, `Surplus sale ${index}.model`),
offerId: optionalString(item.offer_id),
settlementStatus: string(item.settlement_status, `Surplus sale ${index}.settlement_status`),
createdAt: optionalString(item.created_at),
sellerCostMicroUsd: microUsd(item.seller_cost_usdc, `Surplus sale ${index}.seller_cost_usdc`),
};
}
function offerId(item: Record<string, unknown>, field: string): string {
const value = item.offer_id ?? item.id;
return string(value, `${field}.id`);
}
function record(value: unknown, field: string): Record<string, unknown> {
if (typeof value !== "object" || value === null || Array.isArray(value)) {
throw new Error(`${field} must be an object`);
}
return value as Record<string, unknown>;
}
function string(value: unknown, field: string): string {
if (typeof value !== "string" || value === "") throw new Error(`${field} must be a non-empty string`);
return value;
}
function optionalString(value: unknown): string | null {
return typeof value === "string" && value !== "" ? value : null;
}
function boolean(value: unknown, field: string): boolean {
if (typeof value !== "boolean") throw new Error(`${field} must be a boolean`);
return value;
}
function nonNegativeNumber(value: unknown, field: string): number {
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
throw new Error(`${field} must be a non-negative finite number`);
}
return value;
}
function optionalNonNegativeNumber(value: unknown, field: string): number | null {
if (value === null || value === undefined) return null;
return nonNegativeNumber(value, field);
}
function positiveSafeInteger(value: unknown, field: string): number {
if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) {
throw new Error(`${field} must be a positive safe integer`);
}
return value;
}
function nonNegativeSafeInteger(value: unknown, field: string): number {
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
throw new Error(`${field} must be a non-negative safe integer`);
}
return value;
}
function microUsd(value: unknown, field: string): number {
if (typeof value === "string" && /^(?:0|[1-9]\d*)$/.test(value)) {
const parsed = Number(value);
if (Number.isSafeInteger(parsed)) return parsed;
}
return nonNegativeSafeInteger(value, field);
}
function optionalMicroUsd(value: unknown, field: string): number | null {
if (value === null || value === undefined) return null;
return microUsd(value, field);
}
function sanitizedErrorSnippet(value: string): string {
return value
.slice(0, 300)
.replace(/(?:si_seller_|sk-or-v1-)[A-Za-z0-9_-]+/g, "[redacted]")
.replace(/[\r\n]+/g, " ");
}

View File

@@ -0,0 +1,202 @@
const USD_RE = /^(?:0|[1-9]\d*)(?:\.\d{1,6})?$/;
const EVM_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
const POSITIVE_INT_RE = /^[1-9]\d*$/;
const NON_NEGATIVE_INT_RE = /^(?:0|[1-9]\d*)$/;
export interface SurplusManagerConfig {
live: boolean;
apiBaseUrl: string;
sellerApiKey: string;
providerApiKey: string;
providerBaseUrl: string;
capacityBaseUrl: string;
perOfferCapUsd: string;
aggregateCapUsd: string;
sellerWallet: string;
payoutAddress: string;
maxCandidateOrderBooks: number;
reserveUsd: string;
maxProviderLimitUsd: string;
recoveryBps: number;
undercutBps: number;
pollIntervalMs: number;
requestTimeoutMs: number;
stopAfterTrades: number;
statePath: string;
port: number;
}
export function loadSurplusManagerConfig(
env: Record<string, string | undefined>,
): SurplusManagerConfig {
const liveRaw = env.SURPLUS_LIVE;
if (liveRaw !== undefined && liveRaw !== "" && liveRaw !== "1") {
throw new Error("SURPLUS_LIVE must be literal 1 or unset");
}
const apiBaseUrl = httpsUrl(
env.SURPLUS_API_URL ?? "https://api.surplusintelligence.ai",
"SURPLUS_API_URL",
"api.surplusintelligence.ai",
);
const providerBaseUrl = httpsUrl(
env.SURPLUS_PROVIDER_BASE_URL ?? "https://openrouter.ai/api/v1",
"SURPLUS_PROVIDER_BASE_URL",
"openrouter.ai",
);
const capacityBaseUrl = httpsUrl(
env.OPENROUTER_CAPACITY_BASE_URL ?? "https://openrouter.ai/api",
"OPENROUTER_CAPACITY_BASE_URL",
"openrouter.ai",
);
const sellerWallet = evmAddress(
required(env, "SURPLUS_SELLER_WALLET"),
"SURPLUS_SELLER_WALLET",
);
const payoutAddress = evmAddress(
env.SURPLUS_PAYOUT_ADDRESS ?? sellerWallet,
"SURPLUS_PAYOUT_ADDRESS",
);
return {
live: liveRaw === "1",
apiBaseUrl,
sellerApiKey: prefixedSecret(
required(env, "SURPLUS_SELLER_API_KEY"),
"SURPLUS_SELLER_API_KEY",
"si_seller_",
),
providerApiKey: required(env, "SURPLUS_OPENROUTER_API_KEY"),
providerBaseUrl,
capacityBaseUrl,
perOfferCapUsd: usd(
env.SURPLUS_PER_OFFER_CAP_USD ?? "1.00",
"SURPLUS_PER_OFFER_CAP_USD",
),
aggregateCapUsd: usd(
env.SURPLUS_AGGREGATE_CAP_USD ?? "1.00",
"SURPLUS_AGGREGATE_CAP_USD",
),
sellerWallet,
payoutAddress,
maxCandidateOrderBooks: boundedInteger(
env.SURPLUS_MAX_CANDIDATE_ORDER_BOOKS ?? "10",
"SURPLUS_MAX_CANDIDATE_ORDER_BOOKS",
1,
100,
),
reserveUsd: usd(
env.SURPLUS_OPENROUTER_RESERVE_USD ?? "1.00",
"SURPLUS_OPENROUTER_RESERVE_USD",
),
maxProviderLimitUsd: usd(
env.SURPLUS_OPENROUTER_MAX_LIMIT_USD ?? "20.00",
"SURPLUS_OPENROUTER_MAX_LIMIT_USD",
),
recoveryBps: boundedInteger(
env.SURPLUS_MIN_RECOVERY_BPS ?? "490",
"SURPLUS_MIN_RECOVERY_BPS",
1,
10_000,
),
undercutBps: boundedInteger(
env.SURPLUS_UNDERCUT_BPS ?? "10",
"SURPLUS_UNDERCUT_BPS",
0,
9_999,
),
pollIntervalMs: boundedInteger(
env.SURPLUS_REPRICE_INTERVAL_MS ?? "300000",
"SURPLUS_REPRICE_INTERVAL_MS",
60_000,
86_400_000,
),
requestTimeoutMs: boundedInteger(
env.SURPLUS_REQUEST_TIMEOUT_MS ?? "120000",
"SURPLUS_REQUEST_TIMEOUT_MS",
1_000,
300_000,
),
stopAfterTrades: boundedInteger(
env.SURPLUS_STOP_AFTER_SETTLED_REQUESTS ?? "1",
"SURPLUS_STOP_AFTER_SETTLED_REQUESTS",
1,
1,
),
statePath: requiredWithDefault(
env.SURPLUS_STATE_PATH,
"/var/lib/surplus-manager/state.json",
"SURPLUS_STATE_PATH",
),
port: boundedInteger(env.PORT ?? "8080", "PORT", 1, 65_535),
};
}
function required(
env: Record<string, string | undefined>,
name: string,
): string {
const value = env[name]?.trim();
if (!value) throw new Error(`${name} is required`);
return value;
}
function requiredWithDefault(
value: string | undefined,
fallback: string,
name: string,
): string {
const result = (value ?? fallback).trim();
if (!result) throw new Error(`${name} must not be empty`);
return result;
}
function prefixedSecret(value: string, name: string, prefix: string): string {
if (!value.startsWith(prefix) || value.length <= prefix.length) {
throw new Error(`${name} must start with ${prefix}`);
}
return value;
}
function usd(value: string, name: string): string {
if (!USD_RE.test(value)) {
throw new Error(`${name} must be a non-negative USD decimal with at most 6 places`);
}
return value;
}
function evmAddress(value: string, name: string): string {
if (!EVM_ADDRESS_RE.test(value)) {
throw new Error(`${name} must be a 20-byte 0x address`);
}
return value.toLowerCase();
}
function boundedInteger(
value: string,
name: string,
minimum: number,
maximum: number,
): number {
const pattern = minimum === 0 ? NON_NEGATIVE_INT_RE : POSITIVE_INT_RE;
if (!pattern.test(value)) throw new Error(`${name} must be an integer`);
const parsed = Number(value);
if (!Number.isSafeInteger(parsed) || parsed < minimum || parsed > maximum) {
throw new Error(`${name} must be from ${minimum} to ${maximum}`);
}
return parsed;
}
function httpsUrl(value: string, name: string, hostname: string): string {
let parsed: URL;
try {
parsed = new URL(value);
} catch {
throw new Error(`${name} must be a valid URL`);
}
if (parsed.protocol !== "https:" || parsed.hostname.toLowerCase() !== hostname) {
throw new Error(`${name} must use https://${hostname}`);
}
return value.replace(/\/+$/, "");
}

View File

@@ -0,0 +1,734 @@
import { randomUUID } from "node:crypto";
import { parseUsdDecimal, formatUsdNanos } from "../reseller/money.js";
import type { SurplusManagerConfig } from "./config.js";
import {
SurplusClient,
SurplusHttpError,
type SurplusDiscoveredModel,
type SurplusEarnings,
type SurplusOffer,
} from "./client.js";
import type {
OpenRouterKeyAllowance,
OpenRouterKeyClient,
} from "./openRouterKey.js";
import {
formatMicroUsd,
quoteSurplusPrice,
} from "./policy.js";
import {
eligibleCompetitors,
selectSurplusModelCandidates,
} from "./selection.js";
import type {
SurplusControllerState,
SurplusOfferIntent,
SurplusStateStore,
} from "./state.js";
export type SurplusControllerClient = Pick<
SurplusClient,
| "listAllOffers"
| "discoverModels"
| "getMarkets"
| "getOrderBook"
| "testConnection"
| "createOffer"
| "updateOffer"
| "pauseOffer"
| "resumeOffer"
| "getEarnings"
>;
export type OpenRouterAllowanceReader = Pick<OpenRouterKeyClient, "readAllowance">;
export interface SurplusControllerStatus {
ok: boolean;
phase: SurplusControllerState["phase"] | "error" | "planned" | "suspended";
live: boolean;
model: string | null;
providerModelId: string | null;
offerId: string | null;
inputUsdPer1m: string | null;
outputUsdPer1m: string | null;
competitorId: string | null;
remainingAllowanceUsd: string | null;
reserveThresholdUsd: string;
totalEarnedUsd: string | null;
lastCycleAt: string | null;
lastSuccessAt: string | null;
lastError: string | null;
}
interface SurplusControllerOptions {
config: SurplusManagerConfig;
client: SurplusControllerClient;
allowance: OpenRouterAllowanceReader;
stateStore: SurplusStateStore;
now?: () => number;
mutationId?: () => string;
log?: (message: string) => void;
}
const SETTLED_STATUSES: Record<string, true> = {
confirmed: true,
paid: true,
settled: true,
};
export class SurplusSellerController {
private readonly config: SurplusManagerConfig;
private readonly client: SurplusControllerClient;
private readonly allowance: OpenRouterAllowanceReader;
private readonly stateStore: SurplusStateStore;
private readonly now: () => number;
private readonly mutationId: () => string;
private readonly log: (message: string) => void;
private state: SurplusControllerState | null = null;
private inFlight: Promise<void> | null = null;
private timer: NodeJS.Timeout | null = null;
private stopped = false;
private status: SurplusControllerStatus;
constructor(options: SurplusControllerOptions) {
this.config = options.config;
this.client = options.client;
this.allowance = options.allowance;
this.stateStore = options.stateStore;
this.now = options.now ?? Date.now;
this.mutationId = options.mutationId ?? randomUUID;
this.log = options.log ?? (() => undefined);
const perOfferCap = parseUsdDecimal(this.config.perOfferCapUsd, "ceil");
const aggregateCap = parseUsdDecimal(this.config.aggregateCapUsd, "floor");
if (perOfferCap > aggregateCap) {
throw new Error("Surplus per-offer cap must not exceed the aggregate cap");
}
this.status = {
ok: false,
phase: "selecting",
live: this.config.live,
model: null,
providerModelId: null,
offerId: null,
inputUsdPer1m: null,
outputUsdPer1m: null,
competitorId: null,
remainingAllowanceUsd: null,
reserveThresholdUsd: this.config.reserveUsd,
totalEarnedUsd: null,
lastCycleAt: null,
lastSuccessAt: null,
lastError: null,
};
}
snapshot(): SurplusControllerStatus {
return { ...this.status };
}
healthy(): boolean {
if (this.state?.phase === "completed") return true;
if (!this.status.ok || this.status.lastSuccessAt === null) return false;
const freshnessLimit =
this.config.pollIntervalMs + this.config.requestTimeoutMs + 60_000;
return this.now() - Date.parse(this.status.lastSuccessAt) <= freshnessLimit;
}
async start(): Promise<void> {
if (this.state !== null) return;
this.state = await this.stateStore.load();
await this.runOnce();
this.schedule();
}
async stop(): Promise<void> {
this.stopped = true;
clearTimeout(this.timer ?? undefined);
this.timer = null;
if (this.inFlight) await this.inFlight;
}
async runOnce(): Promise<void> {
if (this.inFlight) return this.inFlight;
const cycle = this.performCycle();
this.inFlight = cycle;
try {
await cycle;
} finally {
this.inFlight = null;
}
}
private schedule(): void {
if (this.stopped || this.state?.phase === "completed") return;
this.timer = setTimeout(() => {
void this.runOnce().finally(() => this.schedule());
}, this.config.pollIntervalMs);
this.timer.unref();
}
private async performCycle(): Promise<void> {
if (this.state === null) this.state = await this.stateStore.load();
const cycleAt = new Date(this.now()).toISOString();
this.status = { ...this.status, lastCycleAt: cycleAt };
if (this.state.phase === "completed") {
this.markSuccess("completed", null, null);
return;
}
try {
if (this.state.phase === "selecting") await this.selectAndCreate();
else if (this.state.phase === "create_pending") await this.adoptPendingCreate();
else if (this.state.phase === "active") await this.manageActiveOffer();
else if (this.state.phase === "stopping") await this.finishStopping();
else await this.awaitSettlement();
} catch (error) {
const stateAtFailure = this.state;
let paused = false;
if (
this.config.live &&
stateAtFailure !== null &&
"offerId" in stateAtFailure
) {
try {
await this.client.pauseOffer(stateAtFailure.offerId, this.mutationId());
paused = true;
} catch {
paused = false;
}
}
const detail = this.safeError(error);
this.status = {
...this.status,
ok: false,
phase: "error",
lastError: paused ? `${detail}; managed offer paused` : detail,
};
this.log(`Surplus cycle failed: ${this.status.lastError}`);
}
}
private async selectAndCreate(): Promise<void> {
const offers = await this.client.listAllOffers();
const active = offers.filter((offer) => offer.status === "active");
if (active.length > 0) {
await this.pauseOffers(active);
this.markSuccess("suspended", null, null);
return;
}
const allowance = await this.allowance.readAllowance();
this.assertAllowance(allowance, parseUsdDecimal(this.config.aggregateCapUsd, "ceil"));
const [discovered, markets] = await Promise.all([
this.client.discoverModels(
this.config.providerApiKey,
this.config.providerBaseUrl,
),
this.client.getMarkets(),
]);
const candidates = selectSurplusModelCandidates(
discovered,
markets,
this.config.recoveryBps,
this.config.undercutBps,
);
const ownOfferIds = new Set(offers.map((offer) => offer.id));
let intent: SurplusOfferIntent | null = null;
let competitorId: string | null = null;
for (const candidate of candidates.slice(0, this.config.maxCandidateOrderBooks)) {
const book = await this.client.getOrderBook(candidate.model);
const competitors = eligibleCompetitors(
book.offers,
this.config.sellerWallet,
ownOfferIds,
);
const quote = quoteSurplusPrice({
upstreamInputMicroUsdPer1m: candidate.upstreamInputMicroUsdPer1m,
upstreamOutputMicroUsdPer1m: candidate.upstreamOutputMicroUsdPer1m,
recoveryBps: this.config.recoveryBps,
undercutBps: this.config.undercutBps,
competitors,
});
if (!quote.competitive) continue;
try {
await this.client.testConnection(
this.config.providerApiKey,
this.config.providerBaseUrl,
candidate.model,
);
} catch (error) {
this.log(
`Surplus candidate probe failed model=${candidate.model}: ${this.safeError(error)}`,
);
continue;
}
intent = {
model: candidate.model,
providerModelId: candidate.providerModelId,
inputMicroUsdPer1m: quote.inputMicroUsdPer1m,
outputMicroUsdPer1m: quote.outputMicroUsdPer1m,
dailyCapUsd: Number(this.config.perOfferCapUsd),
idempotencyKey: this.mutationId(),
createdAt: new Date(this.now()).toISOString(),
baselineTrades24h: 0,
};
competitorId = quote.competitorId;
break;
}
if (intent === null) {
throw new Error("No supported OpenRouter model has a safe competitive quote");
}
if (!this.config.live) {
this.markSuccess("planned", allowance, {
intent,
offerId: null,
competitorId,
totalEarnedMicroUsd: null,
});
return;
}
const pending: SurplusControllerState = {
version: 1,
phase: "create_pending",
intent,
};
await this.stateStore.save(pending);
this.state = pending;
let createdOfferId: string | null = null;
let postCreateActive: SurplusOffer[] = [];
try {
createdOfferId = await this.client.createOffer({
model: intent.model,
apiKey: this.config.providerApiKey,
sellerBaseUrl: this.config.providerBaseUrl,
inputUsdPer1m: intent.inputMicroUsdPer1m / 1_000_000,
outputUsdPer1m: intent.outputMicroUsdPer1m / 1_000_000,
dailyCapUsd: intent.dailyCapUsd,
payoutAddress: this.config.payoutAddress,
idempotencyKey: intent.idempotencyKey,
});
const postCreateOffers = await this.client.listAllOffers();
postCreateActive = postCreateOffers.filter(
(offer) => offer.status === "active",
);
const created = postCreateActive.find(
(offer) => offer.id === createdOfferId,
);
if (
!created ||
created.model !== intent.model ||
postCreateActive.length !== 1
) {
throw new Error(
"Surplus create verification did not find exactly one expected active offer",
);
}
this.assertAggregateCap(postCreateOffers);
const activeState: SurplusControllerState = {
version: 1,
phase: "active",
offerId: createdOfferId,
intent,
highestTrades24h: 0,
};
await this.stateStore.save(activeState);
this.state = activeState;
this.markSuccess("active", allowance, {
intent,
offerId: createdOfferId,
competitorId,
totalEarnedMicroUsd: null,
});
} catch (error) {
if (createdOfferId !== null) {
const ids = new Set(postCreateActive.map((offer) => offer.id));
ids.add(createdOfferId);
for (const id of ids) {
await this.client.pauseOffer(id, this.mutationId()).catch(() => undefined);
}
}
if (error instanceof SurplusHttpError && !error.ambiguousMutation) {
const selecting: SurplusControllerState = {
version: 1,
phase: "selecting",
};
await this.stateStore.save(selecting);
this.state = selecting;
}
throw error;
}
}
private async adoptPendingCreate(): Promise<void> {
if (this.state?.phase !== "create_pending") return;
const pending = this.state;
const offers = await this.client.listAllOffers();
const active = offers.filter((offer) => offer.status === "active");
const matches = active
.filter((offer) =>
offer.model === pending.intent.model &&
normalizeUrl(offer.sellerBaseUrl) ===
normalizeUrl(this.config.providerBaseUrl)
)
.sort((left, right) => left.id.localeCompare(right.id));
if (matches.length === 0) {
const inactiveMatch = offers.some((offer) =>
offer.status === "inactive" &&
offer.model === pending.intent.model &&
normalizeUrl(offer.sellerBaseUrl) ===
normalizeUrl(this.config.providerBaseUrl)
);
if (inactiveMatch && active.length === 0) {
const selecting: SurplusControllerState = {
version: 1,
phase: "selecting",
};
await this.stateStore.save(selecting);
this.state = selecting;
this.markSuccess("suspended", null, null);
return;
}
if (active.length > 0) await this.pauseOffers(active);
throw new Error(
"Create result is ambiguous and no matching offer is visible; refusing another POST",
);
}
const primary = matches[0];
await this.pauseOffers(active.filter((offer) => offer.id !== primary.id));
const confirmedOffers = await this.client.listAllOffers();
const confirmedActive = confirmedOffers.filter(
(offer) => offer.status === "active",
);
if (confirmedActive.length !== 1 || confirmedActive[0].id !== primary.id) {
await this.pauseOffers(confirmedActive);
throw new Error("Adopted Surplus create did not reconcile to one active offer");
}
this.assertAggregateCap(confirmedOffers);
const adopted: SurplusControllerState = {
version: 1,
phase: "active",
offerId: primary.id,
intent: pending.intent,
highestTrades24h: pending.intent.baselineTrades24h,
};
try {
await this.stateStore.save(adopted);
} catch (error) {
await this.client.pauseOffer(primary.id, this.mutationId()).catch(() => undefined);
throw error;
}
this.state = adopted;
this.markSuccess("active", null, {
intent: adopted.intent,
offerId: adopted.offerId,
competitorId: null,
totalEarnedMicroUsd: null,
});
}
private async manageActiveOffer(): Promise<void> {
if (this.state?.phase !== "active") return;
const currentState = this.state;
const offers = await this.client.listAllOffers();
const managed = offers.find((offer) => offer.id === currentState.offerId);
if (!managed) throw new Error(`Managed Surplus offer is missing: ${currentState.offerId}`);
const otherActive = offers.filter(
(offer) => offer.status === "active" && offer.id !== currentState.offerId,
);
if (otherActive.length > 0) {
await this.pauseOffers(otherActive);
this.markSuccess("suspended", null, null);
return;
}
this.assertAggregateCap(offers);
const allowance = await this.allowance.readAllowance();
this.assertAllowance(
allowance,
parseUsdDecimal(this.config.perOfferCapUsd, "ceil"),
);
const discovered = await this.client.discoverModels(
this.config.providerApiKey,
this.config.providerBaseUrl,
);
const selected = this.requireSelectedDiscovery(discovered, currentState.intent);
const book = await this.client.getOrderBook(currentState.intent.model);
const ownBookOffer = book.offers.find((offer) => offer.id === currentState.offerId);
if (
ownBookOffer &&
ownBookOffer.trades24h >=
currentState.highestTrades24h + this.config.stopAfterTrades
) {
const stopping: SurplusControllerState = {
version: 1,
phase: "stopping",
offerId: currentState.offerId,
intent: currentState.intent,
highestTrades24h: ownBookOffer.trades24h,
tradeObservedAt: new Date(this.now()).toISOString(),
pauseIdempotencyKey: this.mutationId(),
};
await this.stateStore.save(stopping);
this.state = stopping;
await this.finishStopping();
return;
}
const ownIds = new Set(offers.map((offer) => offer.id));
const competitors = eligibleCompetitors(
book.offers,
this.config.sellerWallet,
ownIds,
);
const quote = quoteSurplusPrice({
upstreamInputMicroUsdPer1m: Math.ceil(selected.inputUsdPer1m * 1_000_000),
upstreamOutputMicroUsdPer1m: Math.ceil(selected.outputUsdPer1m * 1_000_000),
recoveryBps: this.config.recoveryBps,
undercutBps: this.config.undercutBps,
competitors,
});
const nextIntent: SurplusOfferIntent = {
...currentState.intent,
inputMicroUsdPer1m: quote.inputMicroUsdPer1m,
outputMicroUsdPer1m: quote.outputMicroUsdPer1m,
};
const priceChanged = managed.inputMicroUsdPer1m !== quote.inputMicroUsdPer1m ||
managed.outputMicroUsdPer1m !== quote.outputMicroUsdPer1m ||
managed.capDailyUsd !== Number(this.config.perOfferCapUsd);
if (this.config.live && priceChanged) {
await this.client.updateOffer(currentState.offerId, {
inputUsdPer1m: quote.inputUsdPer1m,
outputUsdPer1m: quote.outputUsdPer1m,
dailyCapUsd: Number(this.config.perOfferCapUsd),
idempotencyKey: this.mutationId(),
});
}
if (this.config.live && managed.status === "inactive") {
await this.client.resumeOffer(currentState.offerId, this.mutationId());
}
const activeState: SurplusControllerState = {
...currentState,
intent: nextIntent,
highestTrades24h: ownBookOffer?.trades24h ?? currentState.highestTrades24h,
};
await this.stateStore.save(activeState);
this.state = activeState;
const earnings = await this.client.getEarnings();
this.markSuccess("active", allowance, {
intent: nextIntent,
offerId: currentState.offerId,
competitorId: quote.competitorId,
totalEarnedMicroUsd: earnings.totalEarnedMicroUsd,
});
}
private async finishStopping(): Promise<void> {
if (this.state?.phase !== "stopping") return;
const stopping = this.state;
const before = await this.client.listAllOffers();
const active = before.filter((offer) => offer.status === "active");
for (const offer of active) {
const key = offer.id === stopping.offerId
? stopping.pauseIdempotencyKey
: this.mutationId();
await this.client.pauseOffer(offer.id, key);
}
const after = await this.client.listAllOffers();
if (after.some((offer) => offer.status === "active")) {
throw new Error("Surplus proof stop could not confirm all offers inactive");
}
const awaiting: SurplusControllerState = {
version: 1,
phase: "awaiting_settlement",
offerId: stopping.offerId,
intent: stopping.intent,
tradeObservedAt: stopping.tradeObservedAt,
};
await this.stateStore.save(awaiting);
this.state = awaiting;
await this.awaitSettlement();
}
private async awaitSettlement(): Promise<void> {
if (this.state?.phase !== "awaiting_settlement") return;
const awaiting = this.state;
const offers = await this.client.listAllOffers();
const active = offers.filter((offer) => offer.status === "active");
if (active.length > 0) {
await this.pauseOffers(active);
this.markSuccess("suspended", null, null);
return;
}
const earnings = await this.client.getEarnings();
const sale = this.findSettledSale(earnings, awaiting);
if (!sale) {
this.markSuccess("awaiting_settlement", null, {
intent: awaiting.intent,
offerId: awaiting.offerId,
competitorId: null,
totalEarnedMicroUsd: earnings.totalEarnedMicroUsd,
});
return;
}
const completed: SurplusControllerState = {
version: 1,
phase: "completed",
offerId: awaiting.offerId,
model: awaiting.intent.model,
providerModelId: awaiting.intent.providerModelId,
tradeObservedAt: awaiting.tradeObservedAt,
completedAt: new Date(this.now()).toISOString(),
settlement: {
offerId: sale.offerId,
createdAt: sale.createdAt ?? awaiting.tradeObservedAt,
sellerCostMicroUsd: sale.sellerCostMicroUsd,
settlementStatus: sale.settlementStatus,
},
};
await this.stateStore.save(completed);
this.state = completed;
this.markSuccess("completed", null, {
intent: awaiting.intent,
offerId: awaiting.offerId,
competitorId: null,
totalEarnedMicroUsd: earnings.totalEarnedMicroUsd,
});
}
private findSettledSale(
earnings: SurplusEarnings,
state: Extract<SurplusControllerState, { phase: "awaiting_settlement" }>,
): SurplusEarnings["recentSales"][number] | null {
const tradeObservedAt = Date.parse(state.tradeObservedAt);
return earnings.recentSales.find((sale) => {
if (!SETTLED_STATUSES[sale.settlementStatus.toLowerCase()]) return false;
if (sale.model !== state.intent.model || sale.sellerCostMicroUsd <= 0) return false;
if (sale.offerId !== null) return sale.offerId === state.offerId;
return sale.createdAt !== null &&
Date.parse(sale.createdAt) >= tradeObservedAt;
}) ?? null;
}
private requireSelectedDiscovery(
discovered: SurplusDiscoveredModel[],
intent: SurplusOfferIntent,
): SurplusDiscoveredModel {
const selected = discovered.find((model) =>
model.model === intent.model && model.providerModelId === intent.providerModelId
);
if (
!selected ||
!selected.supported ||
selected.availabilityStatus !== "available" ||
selected.modelType !== "text" ||
selected.priceUnit !== "M" ||
selected.priceVariable ||
selected.inputUsdPer1m <= 0 ||
selected.outputUsdPer1m <= 0
) {
throw new Error(`Selected OpenRouter model is no longer safely sellable: ${intent.model}`);
}
return selected;
}
private assertAggregateCap(offers: SurplusOffer[]): void {
let activeCap = 0n;
for (const offer of offers) {
if (offer.status !== "active") continue;
if (offer.capDailyUsd === null) {
throw new Error(`Active Surplus offer has no daily cap: ${offer.id}`);
}
activeCap += parseUsdDecimal(offer.capDailyUsd.toFixed(6), "ceil");
}
const aggregateCap = parseUsdDecimal(this.config.aggregateCapUsd, "floor");
if (activeCap > aggregateCap) {
throw new Error("Active Surplus offer caps exceed the aggregate cap");
}
}
private assertAllowance(
allowance: OpenRouterKeyAllowance,
exposureUsdNanos: bigint,
): void {
const reserve = parseUsdDecimal(this.config.reserveUsd, "ceil");
const maxLimit = parseUsdDecimal(this.config.maxProviderLimitUsd, "floor");
if (
allowance.limitUsdNanos > maxLimit ||
allowance.remainingUsdNanos > allowance.limitUsdNanos
) {
throw new Error("OpenRouter key limit exceeds the configured containment limit");
}
if (allowance.remainingUsdNanos < reserve + exposureUsdNanos) {
throw new Error("OpenRouter allowance cannot cover reserve threshold plus exposure");
}
}
private async pauseOffers(offers: SurplusOffer[]): Promise<void> {
if (!this.config.live) return;
for (const offer of offers) {
await this.client.pauseOffer(offer.id, this.mutationId());
}
}
private safeError(error: unknown): string {
const detail = error instanceof Error ? error.message : String(error);
return detail
.replaceAll(this.config.sellerApiKey, "[redacted]")
.replaceAll(this.config.providerApiKey, "[redacted]")
.replace(/(?:si_seller_|sk-or-v1-)[A-Za-z0-9_-]+/g, "[redacted]")
.slice(0, 500);
}
private markSuccess(
phase: SurplusControllerStatus["phase"],
allowance: OpenRouterKeyAllowance | null,
details: {
intent: SurplusOfferIntent;
offerId: string | null;
competitorId: string | null;
totalEarnedMicroUsd: number | null;
} | null,
): void {
const successAt = new Date(this.now()).toISOString();
const state = this.state;
const stateModel = state && "intent" in state
? state.intent.model
: state?.phase === "completed"
? state.model
: null;
const stateProviderModel = state && "intent" in state
? state.intent.providerModelId
: state?.phase === "completed"
? state.providerModelId
: null;
const stateOfferId = state && "offerId" in state ? state.offerId : null;
this.status = {
...this.status,
ok: true,
phase,
model: details?.intent.model ?? stateModel,
providerModelId: details?.intent.providerModelId ?? stateProviderModel,
offerId: details?.offerId ?? stateOfferId,
inputUsdPer1m: details
? formatMicroUsd(details.intent.inputMicroUsdPer1m)
: this.status.inputUsdPer1m,
outputUsdPer1m: details
? formatMicroUsd(details.intent.outputMicroUsdPer1m)
: this.status.outputUsdPer1m,
competitorId: details?.competitorId ?? null,
remainingAllowanceUsd: allowance
? formatUsdNanos(allowance.remainingUsdNanos, 6)
: this.status.remainingAllowanceUsd,
totalEarnedUsd: details?.totalEarnedMicroUsd === null || details === null
? this.status.totalEarnedUsd
: formatMicroUsd(details.totalEarnedMicroUsd),
lastSuccessAt: successAt,
lastError: null,
};
this.log(`Surplus controller phase=${phase} model=${this.status.model ?? "none"}`);
}
}
function normalizeUrl(value: string): string {
return value.replace(/\/+$/, "").toLowerCase();
}

View File

@@ -0,0 +1,129 @@
import { parseUsdDecimal } from "../reseller/money.js";
const MAX_KEY_RESPONSE_BYTES = 1024 * 1024;
export interface OpenRouterKeyAllowance {
limitUsdNanos: bigint;
remainingUsdNanos: bigint;
reset: string | null;
checkedAtMs: number;
}
interface OpenRouterKeyClientOptions {
baseUrl: string;
apiKey: string;
timeoutMs: number;
fetchFn?: typeof globalThis.fetch;
now?: () => number;
}
export class OpenRouterKeyClient {
private readonly url: string;
private readonly apiKey: string;
private readonly timeoutMs: number;
private readonly fetchFn: typeof globalThis.fetch;
private readonly now: () => number;
constructor(options: OpenRouterKeyClientOptions) {
this.url = `${options.baseUrl.replace(/\/+$/, "")}/v1/auth/key`;
this.apiKey = options.apiKey;
this.timeoutMs = options.timeoutMs;
this.fetchFn = options.fetchFn ?? globalThis.fetch;
this.now = options.now ?? Date.now;
}
async readAllowance(): Promise<OpenRouterKeyAllowance> {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
try {
const response = await this.fetchFn(this.url, {
headers: { authorization: `Bearer ${this.apiKey}` },
redirect: "error",
signal: controller.signal,
});
const text = await readBoundedText(response, controller);
if (!response.ok) {
throw new Error(
`OpenRouter key endpoint returned HTTP ${response.status}${
text ? `: ${text.slice(0, 200).replace(/[\r\n]+/g, " ")}` : ""
}`,
);
}
let body: unknown;
try {
body = JSON.parse(text);
} catch {
throw new Error("OpenRouter key endpoint response was not JSON");
}
const root = object(body, "OpenRouter key response");
const data = object(root.data, "OpenRouter key response.data");
if (data.limit === null || data.limit_remaining === null) {
throw new Error("OpenRouter resale key must have a finite spending limit");
}
const limit = usdNumberToNanos(data.limit, "OpenRouter key limit");
const remaining = usdNumberToNanos(
data.limit_remaining,
"OpenRouter key limit_remaining",
);
const reset = data.limit_reset;
if (reset !== null && reset !== undefined && typeof reset !== "string") {
throw new Error("OpenRouter key limit_reset must be a string or null");
}
return {
limitUsdNanos: limit,
remainingUsdNanos: remaining,
reset: typeof reset === "string" ? reset : null,
checkedAtMs: this.now(),
};
} catch (error) {
const detail = error instanceof Error ? error.message : String(error);
throw new Error(
`OpenRouter allowance check failed: ${detail.replaceAll(this.apiKey, "[redacted]")}`,
);
} finally {
clearTimeout(timer);
}
}
}
async function readBoundedText(
response: Response,
controller: AbortController,
): Promise<string> {
if (!response.body) return "";
const reader = response.body.getReader();
const decoder = new TextDecoder();
let bytes = 0;
let text = "";
try {
for (;;) {
const chunk = await reader.read();
if (chunk.done) break;
bytes += chunk.value.byteLength;
if (bytes > MAX_KEY_RESPONSE_BYTES) {
controller.abort();
throw new Error(
`OpenRouter key response exceeded ${MAX_KEY_RESPONSE_BYTES} bytes`,
);
}
text += decoder.decode(chunk.value, { stream: true });
}
return text + decoder.decode();
} finally {
reader.releaseLock();
}
}
function usdNumberToNanos(value: unknown, field: string): bigint {
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
throw new Error(`${field} must be a non-negative finite number`);
}
return parseUsdDecimal(value.toFixed(9), "floor");
}
function object(value: unknown, field: string): Record<string, unknown> {
if (typeof value !== "object" || value === null || Array.isArray(value)) {
throw new Error(`${field} must be an object`);
}
return value as Record<string, unknown>;
}

View File

@@ -0,0 +1,150 @@
export interface SurplusCompetitor {
id: string;
inputMicroUsdPer1m: number;
outputMicroUsdPer1m: number;
}
export interface SurplusPricePolicyInput {
upstreamInputMicroUsdPer1m: number;
upstreamOutputMicroUsdPer1m: number;
recoveryBps: number;
undercutBps: number;
competitors: SurplusCompetitor[];
}
export interface SurplusPriceQuote {
inputMicroUsdPer1m: number;
outputMicroUsdPer1m: number;
inputUsdPer1m: number;
outputUsdPer1m: number;
floorInputMicroUsdPer1m: number;
floorOutputMicroUsdPer1m: number;
competitorId: string | null;
competitive: boolean;
}
const BPS_SCALE = 10_000n;
const MICRO_USD = 1_000_000;
export function quoteSurplusPrice(
input: SurplusPricePolicyInput,
): SurplusPriceQuote {
positiveSafeInteger(
input.upstreamInputMicroUsdPer1m,
"upstream input price",
);
positiveSafeInteger(
input.upstreamOutputMicroUsdPer1m,
"upstream output price",
);
boundedBps(input.recoveryBps, "recoveryBps", 1, 10_000);
boundedBps(input.undercutBps, "undercutBps", 0, 9_999);
const floorInput = multiplyBpsCeil(
input.upstreamInputMicroUsdPer1m,
input.recoveryBps,
);
const floorOutput = multiplyBpsCeil(
input.upstreamOutputMicroUsdPer1m,
input.recoveryBps,
);
const competitor = cheapestCompetitor(input.competitors);
const candidateInput = competitor
? undercut(competitor.inputMicroUsdPer1m, input.undercutBps)
: floorInput;
const candidateOutput = competitor
? undercut(competitor.outputMicroUsdPer1m, input.undercutBps)
: floorOutput;
const quotedInput = Math.max(floorInput, candidateInput);
const quotedOutput = Math.max(floorOutput, candidateOutput);
return {
inputMicroUsdPer1m: quotedInput,
outputMicroUsdPer1m: quotedOutput,
inputUsdPer1m: quotedInput / MICRO_USD,
outputUsdPer1m: quotedOutput / MICRO_USD,
floorInputMicroUsdPer1m: floorInput,
floorOutputMicroUsdPer1m: floorOutput,
competitorId: competitor?.id ?? null,
competitive: competitor === null || (
quotedInput < competitor.inputMicroUsdPer1m &&
quotedOutput < competitor.outputMicroUsdPer1m
),
};
}
export function usdPer1mToMicroUsd(value: unknown, field: string): number {
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
throw new Error(`${field} must be a positive finite number`);
}
const result = Math.ceil(value * MICRO_USD);
positiveSafeInteger(result, field);
return result;
}
export function formatMicroUsd(value: number): string {
if (!Number.isSafeInteger(value) || value < 0) {
throw new Error("micro-USD value must be a non-negative safe integer");
}
const whole = Math.floor(value / MICRO_USD);
const fraction = (value % MICRO_USD).toString().padStart(6, "0");
return `${whole}.${fraction}`;
}
function cheapestCompetitor(
competitors: SurplusCompetitor[],
): SurplusCompetitor | null {
let result: SurplusCompetitor | null = null;
for (const competitor of competitors) {
positiveSafeInteger(competitor.inputMicroUsdPer1m, "competitor input price");
positiveSafeInteger(competitor.outputMicroUsdPer1m, "competitor output price");
if (result === null || compareCompetitors(competitor, result) < 0) {
result = competitor;
}
}
return result;
}
function compareCompetitors(
left: SurplusCompetitor,
right: SurplusCompetitor,
): number {
return (
left.inputMicroUsdPer1m + left.outputMicroUsdPer1m -
(right.inputMicroUsdPer1m + right.outputMicroUsdPer1m) ||
left.inputMicroUsdPer1m - right.inputMicroUsdPer1m ||
left.outputMicroUsdPer1m - right.outputMicroUsdPer1m ||
left.id.localeCompare(right.id)
);
}
function undercut(value: number, bps: number): number {
const discounted = Number(
(BigInt(value) * BigInt(10_000 - bps)) / BPS_SCALE,
);
if (discounted >= value && value > 1) return value - 1;
return Math.max(1, discounted);
}
function multiplyBpsCeil(value: number, bps: number): number {
const numerator = BigInt(value) * BigInt(bps);
return Number((numerator + BPS_SCALE - 1n) / BPS_SCALE);
}
function positiveSafeInteger(value: number, field: string): void {
if (!Number.isSafeInteger(value) || value <= 0) {
throw new Error(`${field} must be a positive safe integer`);
}
}
function boundedBps(
value: number,
field: string,
minimum: number,
maximum: number,
): void {
if (!Number.isInteger(value) || value < minimum || value > maximum) {
throw new Error(`${field} must be from ${minimum} to ${maximum}`);
}
}

View File

@@ -0,0 +1,110 @@
import type {
SurplusDiscoveredModel,
SurplusMarketSummary,
SurplusOrderBookOffer,
} from "./client.js";
import {
quoteSurplusPrice,
usdPer1mToMicroUsd,
type SurplusCompetitor,
type SurplusPriceQuote,
} from "./policy.js";
export interface SurplusModelCandidate {
model: string;
providerModelId: string;
upstreamInputMicroUsdPer1m: number;
upstreamOutputMicroUsdPer1m: number;
requests24h: number;
volume24h: number;
summaryQuote: SurplusPriceQuote;
}
export function selectSurplusModelCandidates(
discovered: SurplusDiscoveredModel[],
markets: SurplusMarketSummary[],
recoveryBps: number,
undercutBps: number,
): SurplusModelCandidate[] {
const marketByModel = new Map(markets.map((market) => [market.model, market]));
const candidates: SurplusModelCandidate[] = [];
for (const model of discovered) {
const market = marketByModel.get(model.model);
if (
!market ||
!model.supported ||
model.availabilityStatus !== "available" ||
model.modelType !== "text" ||
model.priceUnit !== "M" ||
model.priceVariable ||
model.inputUsdPer1m <= 0 ||
model.outputUsdPer1m <= 0 ||
market.healthySellerCount <= 0 ||
market.bestInputMicroUsdPer1m <= 0 ||
market.bestOutputMicroUsdPer1m <= 0
) {
continue;
}
const inputPrice = usdPer1mToMicroUsd(
model.inputUsdPer1m,
`${model.model} discovery input price`,
);
const outputPrice = usdPer1mToMicroUsd(
model.outputUsdPer1m,
`${model.model} discovery output price`,
);
const quote = quoteSurplusPrice({
upstreamInputMicroUsdPer1m: inputPrice,
upstreamOutputMicroUsdPer1m: outputPrice,
recoveryBps,
undercutBps,
competitors: [{
id: `summary:${model.model}`,
inputMicroUsdPer1m: market.bestInputMicroUsdPer1m,
outputMicroUsdPer1m: market.bestOutputMicroUsdPer1m,
}],
});
if (!quote.competitive) continue;
candidates.push({
model: model.model,
providerModelId: model.providerModelId,
upstreamInputMicroUsdPer1m: inputPrice,
upstreamOutputMicroUsdPer1m: outputPrice,
requests24h: market.requests24h,
volume24h: market.volume24h,
summaryQuote: quote,
});
}
return candidates.sort(compareCandidates);
}
export function eligibleCompetitors(
offers: SurplusOrderBookOffer[],
sellerWallet: string,
ownOfferIds: ReadonlySet<string>,
): SurplusCompetitor[] {
const normalizedWallet = sellerWallet.toLowerCase();
return offers
.filter((offer) =>
offer.available &&
offer.healthy &&
offer.trusted &&
offer.seller !== normalizedWallet &&
!ownOfferIds.has(offer.id)
)
.map((offer) => ({
id: offer.id,
inputMicroUsdPer1m: offer.inputMicroUsdPer1m,
outputMicroUsdPer1m: offer.outputMicroUsdPer1m,
}));
}
function compareCandidates(
left: SurplusModelCandidate,
right: SurplusModelCandidate,
): number {
return right.requests24h - left.requests24h ||
right.volume24h - left.volume24h ||
left.model.localeCompare(right.model) ||
left.providerModelId.localeCompare(right.providerModelId);
}

View File

@@ -0,0 +1,338 @@
import { constants, type Stats } from "node:fs";
import {
chmod,
lstat,
mkdir,
open,
rename,
unlink,
type FileHandle,
} from "node:fs/promises";
import { dirname, basename, join } from "node:path";
import { randomUUID } from "node:crypto";
export interface SurplusOfferIntent {
model: string;
providerModelId: string;
inputMicroUsdPer1m: number;
outputMicroUsdPer1m: number;
dailyCapUsd: number;
idempotencyKey: string;
createdAt: string;
baselineTrades24h: number;
}
export interface SurplusSettlementEvidence {
offerId: string | null;
createdAt: string;
sellerCostMicroUsd: number;
settlementStatus: string;
}
export type SurplusControllerState =
| { version: 1; phase: "selecting" }
| { version: 1; phase: "create_pending"; intent: SurplusOfferIntent }
| {
version: 1;
phase: "active";
offerId: string;
intent: SurplusOfferIntent;
highestTrades24h: number;
}
| {
version: 1;
phase: "stopping";
offerId: string;
intent: SurplusOfferIntent;
highestTrades24h: number;
tradeObservedAt: string;
pauseIdempotencyKey: string;
}
| {
version: 1;
phase: "awaiting_settlement";
offerId: string;
intent: SurplusOfferIntent;
tradeObservedAt: string;
}
| {
version: 1;
phase: "completed";
offerId: string;
model: string;
providerModelId: string;
tradeObservedAt: string;
completedAt: string;
settlement: SurplusSettlementEvidence;
};
export interface SurplusStateStore {
load(): Promise<SurplusControllerState>;
save(state: SurplusControllerState): Promise<void>;
}
export class FileSurplusStateStore implements SurplusStateStore {
private readonly path: string;
constructor(path: string) {
this.path = path;
}
async load(): Promise<SurplusControllerState> {
let handle: FileHandle;
try {
handle = await open(
this.path,
constants.O_RDONLY | constants.O_NOFOLLOW,
);
} catch (error) {
if (isNodeError(error, "ENOENT")) return { version: 1, phase: "selecting" };
throw error;
}
try {
const info = await handle.stat();
assertSecureOwner(info, false, "Surplus state file");
const text = await handle.readFile("utf8");
let value: unknown;
try {
value = JSON.parse(text);
} catch {
throw new Error("Surplus state file is not valid JSON");
}
return parseState(value);
} finally {
await handle.close();
}
}
async save(state: SurplusControllerState): Promise<void> {
const directory = dirname(this.path);
await mkdir(directory, { recursive: true, mode: 0o700 });
await chmod(directory, 0o700);
const directoryInfo = await lstat(directory);
assertSecureOwner(directoryInfo, true, "Surplus state directory");
const tempPath = join(directory, `.${basename(this.path)}.${randomUUID()}.tmp`);
const body = `${JSON.stringify(state)}\n`;
let handle: FileHandle | null = null;
try {
handle = await open(
tempPath,
constants.O_WRONLY |
constants.O_CREAT |
constants.O_EXCL |
constants.O_NOFOLLOW,
0o600,
);
await handle.writeFile(body, "utf8");
await handle.sync();
await handle.close();
handle = null;
await rename(tempPath, this.path);
const directoryHandle = await open(
directory,
constants.O_RDONLY | constants.O_DIRECTORY,
);
try {
await directoryHandle.sync();
} finally {
await directoryHandle.close();
}
} finally {
if (handle !== null) await handle.close().catch(() => undefined);
await unlink(tempPath).catch((error) => {
if (!isNodeError(error, "ENOENT")) throw error;
});
}
}
}
function assertSecureOwner(
info: Stats,
directory: boolean,
field: string,
): void {
if (directory ? !info.isDirectory() : !info.isFile()) {
throw new Error(`${field} has the wrong file type`);
}
if (typeof process.getuid === "function" && info.uid !== process.getuid()) {
throw new Error(`${field} must be owned by the service user`);
}
if ((info.mode & 0o077) !== 0) {
throw new Error(`${field} must not allow group or other access`);
}
}
function parseState(value: unknown): SurplusControllerState {
const root = object(value, "Surplus state");
if (root.version !== 1) throw new Error("Surplus state version must be 1");
const phase = nonEmptyString(root.phase, "Surplus state phase");
if (phase === "selecting") return { version: 1, phase };
if (phase === "create_pending") {
return { version: 1, phase, intent: parseIntent(root.intent) };
}
if (phase === "active") {
return {
version: 1,
phase,
offerId: nonEmptyString(root.offerId, "Surplus state offerId"),
intent: parseIntent(root.intent),
highestTrades24h: nonNegativeInteger(
root.highestTrades24h,
"Surplus state highestTrades24h",
),
};
}
if (phase === "stopping") {
return {
version: 1,
phase,
offerId: nonEmptyString(root.offerId, "Surplus state offerId"),
intent: parseIntent(root.intent),
highestTrades24h: nonNegativeInteger(
root.highestTrades24h,
"Surplus state highestTrades24h",
),
tradeObservedAt: isoTimestamp(
root.tradeObservedAt,
"Surplus state tradeObservedAt",
),
pauseIdempotencyKey: nonEmptyString(
root.pauseIdempotencyKey,
"Surplus state pauseIdempotencyKey",
),
};
}
if (phase === "awaiting_settlement") {
return {
version: 1,
phase,
offerId: nonEmptyString(root.offerId, "Surplus state offerId"),
intent: parseIntent(root.intent),
tradeObservedAt: isoTimestamp(
root.tradeObservedAt,
"Surplus state tradeObservedAt",
),
};
}
if (phase === "completed") {
return {
version: 1,
phase,
offerId: nonEmptyString(root.offerId, "Surplus state offerId"),
model: nonEmptyString(root.model, "Surplus state model"),
providerModelId: nonEmptyString(
root.providerModelId,
"Surplus state providerModelId",
),
tradeObservedAt: isoTimestamp(
root.tradeObservedAt,
"Surplus state tradeObservedAt",
),
completedAt: isoTimestamp(root.completedAt, "Surplus state completedAt"),
settlement: parseSettlement(root.settlement),
};
}
throw new Error(`Surplus state phase is unsupported: ${phase}`);
}
function parseSettlement(value: unknown): SurplusSettlementEvidence {
const settlement = object(value, "Surplus state settlement");
const offerId = settlement.offerId;
if (offerId !== null && (typeof offerId !== "string" || offerId === "")) {
throw new Error("Surplus state settlement.offerId must be a string or null");
}
return {
offerId,
createdAt: isoTimestamp(
settlement.createdAt,
"Surplus state settlement.createdAt",
),
sellerCostMicroUsd: positiveInteger(
settlement.sellerCostMicroUsd,
"Surplus state settlement.sellerCostMicroUsd",
),
settlementStatus: nonEmptyString(
settlement.settlementStatus,
"Surplus state settlement.settlementStatus",
),
};
}
function parseIntent(value: unknown): SurplusOfferIntent {
const intent = object(value, "Surplus state intent");
return {
model: nonEmptyString(intent.model, "Surplus state intent.model"),
providerModelId: nonEmptyString(
intent.providerModelId,
"Surplus state intent.providerModelId",
),
inputMicroUsdPer1m: positiveInteger(
intent.inputMicroUsdPer1m,
"Surplus state intent.inputMicroUsdPer1m",
),
outputMicroUsdPer1m: positiveInteger(
intent.outputMicroUsdPer1m,
"Surplus state intent.outputMicroUsdPer1m",
),
dailyCapUsd: positiveNumber(
intent.dailyCapUsd,
"Surplus state intent.dailyCapUsd",
),
idempotencyKey: nonEmptyString(
intent.idempotencyKey,
"Surplus state intent.idempotencyKey",
),
createdAt: isoTimestamp(intent.createdAt, "Surplus state intent.createdAt"),
baselineTrades24h: nonNegativeInteger(
intent.baselineTrades24h,
"Surplus state intent.baselineTrades24h",
),
};
}
function object(value: unknown, field: string): Record<string, unknown> {
if (typeof value !== "object" || value === null || Array.isArray(value)) {
throw new Error(`${field} must be an object`);
}
return value as Record<string, unknown>;
}
function nonEmptyString(value: unknown, field: string): string {
if (typeof value !== "string" || value === "") {
throw new Error(`${field} must be a non-empty string`);
}
return value;
}
function isoTimestamp(value: unknown, field: string): string {
const timestamp = nonEmptyString(value, field);
if (!Number.isFinite(Date.parse(timestamp))) {
throw new Error(`${field} must be an ISO timestamp`);
}
return timestamp;
}
function positiveInteger(value: unknown, field: string): number {
if (!Number.isSafeInteger(value) || (value as number) <= 0) {
throw new Error(`${field} must be a positive safe integer`);
}
return value as number;
}
function nonNegativeInteger(value: unknown, field: string): number {
if (!Number.isSafeInteger(value) || (value as number) < 0) {
throw new Error(`${field} must be a non-negative safe integer`);
}
return value as number;
}
function positiveNumber(value: unknown, field: string): number {
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
throw new Error(`${field} must be a positive finite number`);
}
return value;
}
function isNodeError(error: unknown, code: string): boolean {
return error instanceof Error && "code" in error && error.code === code;
}