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

@@ -82,13 +82,14 @@ project_re() {
docker-compose.buyer.yml) echo "^buyer/|$SHARED_RE" ;; docker-compose.buyer.yml) echo "^buyer/|$SHARED_RE" ;;
docker-compose.gateway.yml) echo "^gateway/|$SHARED_RE" ;; docker-compose.gateway.yml) echo "^gateway/|$SHARED_RE" ;;
docker-compose.wallet-monitor.yml) echo "^wallet-monitor/|$SHARED_RE" ;; docker-compose.wallet-monitor.yml) echo "^wallet-monitor/|$SHARED_RE" ;;
docker-compose.surplus-seller.yml) echo "^supplier/|$SHARED_RE" ;;
docker-compose.supplier*.yml) echo "^supplier/|$SHARED_RE" ;; docker-compose.supplier*.yml) echo "^supplier/|$SHARED_RE" ;;
*) echo "" ;; *) echo "" ;;
esac esac
} }
# Restart order: infra first, suppliers last (each supplier drains first). # Restart order: infra first, suppliers last (each supplier drains first).
ORDERED_NON_SUPPLIER="docker-compose.indexer.yml docker-compose.buyer.yml docker-compose.gateway.yml docker-compose.wallet-monitor.yml docker-compose.ollama.yml docker-compose.chatmock.yml docker-compose.tts-piper.yml" ORDERED_NON_SUPPLIER="docker-compose.indexer.yml docker-compose.buyer.yml docker-compose.gateway.yml docker-compose.wallet-monitor.yml docker-compose.surplus-seller.yml docker-compose.ollama.yml docker-compose.chatmock.yml docker-compose.tts-piper.yml"
SUPPLIERS=$(cd "$COMPOSE_DIR" && ls docker-compose.supplier*.yml) SUPPLIERS=$(cd "$COMPOSE_DIR" && ls docker-compose.supplier*.yml)
AFFECTED=() AFFECTED=()

View File

@@ -0,0 +1,39 @@
name: marketplace-mainnet-surplus-seller
services:
surplus-seller:
build:
context: ../..
dockerfile: supplier/Dockerfile
container_name: marketplace-mainnet-surplus-seller
restart: unless-stopped
command:
- node_modules/.bin/tsx
- supplier/src/cli/surplus-seller.ts
env_file:
- path: /var/lib/agents-marketplace/surplus-seller.env
required: true
read_only: true
tmpfs:
- /tmp:size=64m,mode=1777
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
volumes:
- surplus-seller-state:/var/lib/surplus-manager
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:8080/healthz >/dev/null || exit 1"]
interval: 20s
timeout: 5s
retries: 3
start_period: 60s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
volumes:
surplus-seller-state:
name: marketplace-mainnet-surplus-seller-state

View File

@@ -132,3 +132,28 @@ ADVERT_DETAIL_HASH=
# MAX_CHAT_SESSIONS=1 # concurrent session slots (default 1) # MAX_CHAT_SESSIONS=1 # concurrent session slots (default 1)
# CHAT_SETTLE_MODE=full # "full" (Claim/Submit) or "ticket" (no supplier # CHAT_SETTLE_MODE=full # "full" (Claim/Submit) or "ticket" (no supplier
# # chain ops; buyer reclaims the Open escrow) # # 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. # Drop privileges. The official node image ships a non-root `node` user.
RUN chown -R node:node /repo 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 USER node
ENV NODE_ENV=production ENV NODE_ENV=production

View File

@@ -10,7 +10,8 @@
"tx:retire-advert": "tsx src/cli/retire-advert.ts", "tx:retire-advert": "tsx src/cli/retire-advert.ts",
"tx:publish-reference-scripts": "tsx src/cli/publish-reference-scripts.ts", "tx:publish-reference-scripts": "tsx src/cli/publish-reference-scripts.ts",
"tx:consolidate-wallet": "tsx src/cli/consolidate-wallet.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": { "dependencies": {
"@marketplace/shared": "workspace:*", "@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;
}

View File

@@ -0,0 +1,225 @@
import { describe, expect, it, vi } from "vitest";
import { SurplusClient } from "../../supplier/src/surplus/client.js";
const SELLER_KEY = "si_seller_test_only";
const PROVIDER_KEY = "sk-or-v1-test-only";
function ndjsonResponse(chunks: string[]): Response {
const encoder = new TextEncoder();
const body = new ReadableStream<Uint8Array>({
start(controller) {
for (const chunk of chunks) controller.enqueue(encoder.encode(chunk));
controller.close();
},
});
return new Response(body, {
status: 200,
headers: { "content-type": "application/x-ndjson" },
});
}
function discoveryRow(model: string, providerModelId: string): string {
return JSON.stringify({
model,
supported: true,
pricing: {
input_per_1m: 0.07952,
output_per_1m: 0.15904,
price_unit: "M",
price_variable: false,
},
metadata: {
provider_model_id: providerModelId,
model_type: "text",
availability_status: "available",
},
});
}
describe("SurplusClient", () => {
it("authenticates and parses fragmented NDJSON discovery", async () => {
const first = discoveryRow("alpha", "vendor/alpha");
const second = discoveryRow("beta", "vendor/beta");
const fetchFn = vi.fn(async (_url: string | URL | Request, init?: RequestInit) => {
const headers = new Headers(init?.headers);
expect(headers.get("authorization")).toBe(`Bearer ${SELLER_KEY}`);
expect(JSON.parse(String(init?.body))).toEqual({
api_key: PROVIDER_KEY,
base_url: "https://openrouter.ai/api/v1",
});
return ndjsonResponse([
first.slice(0, 25),
`${first.slice(25)}\r\n\r\n${second.slice(0, 11)}`,
second.slice(11),
]);
});
const client = new SurplusClient({
apiBaseUrl: "https://api.surplusintelligence.ai",
sellerApiKey: SELLER_KEY,
timeoutMs: 1_000,
fetchFn,
});
const result = await client.discoverModels(
PROVIDER_KEY,
"https://openrouter.ai/api/v1",
);
expect(result.map((model) => [model.model, model.providerModelId])).toEqual([
["alpha", "vendor/alpha"],
["beta", "vendor/beta"],
]);
});
it("rejects one malformed discovery line without returning a partial catalog", async () => {
const client = new SurplusClient({
apiBaseUrl: "https://api.surplusintelligence.ai",
sellerApiKey: SELLER_KEY,
timeoutMs: 1_000,
fetchFn: async () => ndjsonResponse([
`${discoveryRow("alpha", "vendor/alpha")}\n`,
'{"model":"truncated"',
]),
});
await expect(client.discoverModels(PROVIDER_KEY, "https://openrouter.ai/api/v1"))
.rejects.toThrow("line 2 was not complete JSON");
});
it("follows every seller-offer page and normalizes micro-USD prices", async () => {
const requested: string[] = [];
const fetchFn = vi.fn(async (url: string | URL | Request) => {
const value = String(url);
requested.push(value);
if (value.includes("next_token=page-2")) {
return Response.json({
items: [{
offer_id: "offer-2",
model: "beta",
seller_base_url: "https://openrouter.ai/api/v1",
status: "inactive",
cap_daily_usd: 1,
price_input_per_1m: 4_100,
price_output_per_1m: 8_200,
}],
next_token: null,
});
}
return Response.json({
items: [{
id: "offer-1",
model: "alpha",
seller_base_url: "https://openrouter.ai/api/v1",
status: "active",
cap_daily_usd: 1,
price_input_per_1m: 3_972,
price_output_per_1m: 7_944,
}],
next_token: "page-2",
});
});
const client = new SurplusClient({
apiBaseUrl: "https://api.surplusintelligence.ai",
sellerApiKey: SELLER_KEY,
timeoutMs: 1_000,
fetchFn,
});
const result = await client.listAllOffers();
expect(result).toHaveLength(2);
expect(result[0]).toMatchObject({
id: "offer-1",
status: "active",
inputMicroUsdPer1m: 3_972,
outputMicroUsdPer1m: 7_944,
});
expect(requested[1]).toContain("next_token=page-2");
});
it("fails closed when offer pagination repeats a token", async () => {
const client = new SurplusClient({
apiBaseUrl: "https://api.surplusintelligence.ai",
sellerApiKey: SELLER_KEY,
timeoutMs: 1_000,
fetchFn: async () => Response.json({ items: [], next_token: "same" }),
});
await expect(client.listAllOffers()).rejects.toThrow("repeated a next_token");
});
it("normalizes live market envelopes and effective micro-USD fields", async () => {
const fetchFn = vi.fn(async (url: string | URL | Request) => {
if (String(url).endsWith("/api/markets")) {
return Response.json({ markets: [{
model: "alpha:model",
requests_24h: 100,
volume_24h: 1_000,
best_input_per_1m: 3_976,
best_output_per_1m: 7_952,
healthy_seller_count: 2,
}] });
}
return Response.json({
model: "alpha:model",
offers: [{
id: "external",
seller: "0x2222222222222222222222222222222222222222",
seller_base_url: "https://openrouter.ai/api/v1",
effective_input_per_1m: 3_976,
effective_output_per_1m: 7_952,
available: true,
healthy: true,
trusted: true,
trades_24h: 7,
}],
});
});
const client = new SurplusClient({
apiBaseUrl: "https://api.surplusintelligence.ai",
sellerApiKey: SELLER_KEY,
timeoutMs: 1_000,
fetchFn,
});
expect(await client.getMarkets()).toEqual([expect.objectContaining({
model: "alpha:model",
bestInputMicroUsdPer1m: 3_976,
})]);
expect(await client.getOrderBook("alpha:model")).toEqual({
model: "alpha:model",
offers: [expect.objectContaining({ id: "external", trades24h: 7 })],
});
expect(String(fetchFn.mock.calls[1][0])).toContain("alpha%3Amodel");
});
it("sends one absolute PATCH with plain USD prices and the cap", async () => {
let request: RequestInit | undefined;
const client = new SurplusClient({
apiBaseUrl: "https://api.surplusintelligence.ai",
sellerApiKey: SELLER_KEY,
timeoutMs: 1_000,
fetchFn: async (_url, init) => {
request = init;
return Response.json({ ok: true });
},
});
await client.updateOffer("offer/one", {
inputUsdPer1m: 0.003972,
outputUsdPer1m: 0.007944,
dailyCapUsd: 1,
idempotencyKey: "mutation-1",
});
expect(request?.method).toBe("PATCH");
expect(JSON.parse(String(request?.body))).toEqual({
pricing_mode: "per_token",
price_input_per_1m: 0.003972,
price_output_per_1m: 0.007944,
cap_daily_usd: 1,
});
const headers = new Headers(request?.headers);
expect(headers.get("idempotency-key")).toBe("mutation-1");
});
});

View File

@@ -0,0 +1,283 @@
import { describe, expect, it } from "vitest";
import type { SurplusManagerConfig } from "../../supplier/src/surplus/config.js";
import {
SurplusSellerController,
type SurplusControllerClient,
} from "../../supplier/src/surplus/controller.js";
import {
SurplusHttpError,
type SurplusDiscoveredModel,
type SurplusOffer,
type SurplusOfferPatch,
type SurplusOfferWrite,
} from "../../supplier/src/surplus/client.js";
import type { OpenRouterKeyAllowance } from "../../supplier/src/surplus/openRouterKey.js";
import type {
SurplusControllerState,
SurplusStateStore,
} from "../../supplier/src/surplus/state.js";
const SELLER_WALLET = "0x1111111111111111111111111111111111111111";
function config(): SurplusManagerConfig {
return {
live: true,
apiBaseUrl: "https://api.surplusintelligence.ai",
sellerApiKey: "si_seller_test",
providerApiKey: "sk-or-v1-test",
providerBaseUrl: "https://openrouter.ai/api/v1",
capacityBaseUrl: "https://openrouter.ai/api",
perOfferCapUsd: "1.00",
aggregateCapUsd: "1.00",
sellerWallet: SELLER_WALLET,
payoutAddress: SELLER_WALLET,
maxCandidateOrderBooks: 10,
reserveUsd: "1.00",
maxProviderLimitUsd: "20.00",
recoveryBps: 490,
undercutBps: 10,
pollIntervalMs: 300_000,
requestTimeoutMs: 120_000,
stopAfterTrades: 1,
statePath: "/tmp/surplus-test-state.json",
port: 8080,
};
}
class MemoryStateStore implements SurplusStateStore {
state: SurplusControllerState = { version: 1, phase: "selecting" };
async load(): Promise<SurplusControllerState> {
return structuredClone(this.state);
}
async save(state: SurplusControllerState): Promise<void> {
this.state = structuredClone(state);
}
}
class FakeSurplusClient implements SurplusControllerClient {
offer: SurplusOffer | null = null;
trades24h = 0;
settled = false;
createCalls = 0;
pauseCalls = 0;
externalCalls = 0;
createError: Error | null = null;
discoveryError: Error | null = null;
createdPayload: SurplusOfferWrite | null = null;
patchPayload: SurplusOfferPatch | null = null;
async listAllOffers(): Promise<SurplusOffer[]> {
this.externalCalls += 1;
return this.offer ? [{ ...this.offer }] : [];
}
async discoverModels(): Promise<SurplusDiscoveredModel[]> {
this.externalCalls += 1;
if (this.discoveryError) throw this.discoveryError;
return [{
model: "beta-model",
providerModelId: "vendor/beta-model",
supported: true,
inputUsdPer1m: 0.07952,
outputUsdPer1m: 0.15904,
priceUnit: "M",
priceVariable: false,
modelType: "text",
availabilityStatus: "available",
}];
}
async getMarkets() {
this.externalCalls += 1;
return [{
model: "beta-model",
requests24h: 100,
volume24h: 1_000,
bestInputMicroUsdPer1m: 3_976,
bestOutputMicroUsdPer1m: 7_952,
healthySellerCount: 1,
}];
}
async getOrderBook(model: string) {
this.externalCalls += 1;
const offers = [{
id: "external",
seller: "0x2222222222222222222222222222222222222222",
sellerBaseUrl: "https://openrouter.ai/api/v1",
inputMicroUsdPer1m: 3_976,
outputMicroUsdPer1m: 7_952,
available: true,
healthy: true,
trusted: true,
trades24h: 0,
}];
if (this.offer) {
offers.push({
id: this.offer.id,
seller: SELLER_WALLET,
sellerBaseUrl: this.offer.sellerBaseUrl,
inputMicroUsdPer1m: this.offer.inputMicroUsdPer1m ?? 3_972,
outputMicroUsdPer1m: this.offer.outputMicroUsdPer1m ?? 7_944,
available: this.offer.status === "active",
healthy: true,
trusted: true,
trades24h: this.trades24h,
});
}
return { model, offers };
}
async testConnection(): Promise<number> {
this.externalCalls += 1;
return 10;
}
async createOffer(input: SurplusOfferWrite): Promise<string> {
this.externalCalls += 1;
this.createCalls += 1;
this.createdPayload = input;
if (this.createError) throw this.createError;
this.offer = {
id: "managed-offer",
model: input.model,
sellerBaseUrl: input.sellerBaseUrl,
status: "active",
capDailyUsd: input.dailyCapUsd,
inputMicroUsdPer1m: Math.round(input.inputUsdPer1m * 1_000_000),
outputMicroUsdPer1m: Math.round(input.outputUsdPer1m * 1_000_000),
};
return this.offer.id;
}
async updateOffer(_id: string, patch: SurplusOfferPatch): Promise<void> {
this.externalCalls += 1;
this.patchPayload = patch;
if (!this.offer) throw new Error("missing fake offer");
this.offer.inputMicroUsdPer1m = Math.round(patch.inputUsdPer1m * 1_000_000);
this.offer.outputMicroUsdPer1m = Math.round(patch.outputUsdPer1m * 1_000_000);
this.offer.capDailyUsd = patch.dailyCapUsd;
}
async pauseOffer(): Promise<void> {
this.externalCalls += 1;
this.pauseCalls += 1;
if (this.offer) this.offer.status = "inactive";
}
async resumeOffer(): Promise<void> {
this.externalCalls += 1;
if (this.offer) this.offer.status = "active";
}
async getEarnings() {
this.externalCalls += 1;
return {
totalEarnedMicroUsd: this.settled ? 100 : 0,
pendingMicroUsd: 0,
paidMicroUsd: this.settled ? 100 : 0,
recentSales: this.settled ? [{
model: "beta-model",
offerId: "managed-offer",
settlementStatus: "confirmed",
createdAt: "2026-08-27T10:00:01.000Z",
sellerCostMicroUsd: 100,
}] : [],
};
}
}
const ALLOWANCE: OpenRouterKeyAllowance = {
limitUsdNanos: 20_000_000_000n,
remainingUsdNanos: 20_000_000_000n,
reset: null,
checkedAtMs: Date.parse("2026-08-27T10:00:00.000Z"),
};
function controller(
client: FakeSurplusClient,
store: MemoryStateStore,
): SurplusSellerController {
let mutation = 0;
return new SurplusSellerController({
config: config(),
client,
allowance: { readAllowance: async () => ALLOWANCE },
stateStore: store,
now: () => Date.parse("2026-08-27T10:00:00.000Z"),
mutationId: () => `mutation-${++mutation}`,
});
}
describe("SurplusSellerController", () => {
it("selects a discovered model, creates one bounded offer, and stops after settlement", async () => {
const client = new FakeSurplusClient();
const store = new MemoryStateStore();
const activeController = controller(client, store);
await activeController.runOnce();
expect(client.createCalls).toBe(1);
expect(client.createdPayload).toMatchObject({
model: "beta-model",
inputUsdPer1m: 0.003972,
outputUsdPer1m: 0.007944,
dailyCapUsd: 1,
payoutAddress: SELLER_WALLET,
});
expect(store.state.phase).toBe("active");
expect(activeController.snapshot()).toMatchObject({
ok: true,
phase: "active",
model: "beta-model",
providerModelId: "vendor/beta-model",
});
client.trades24h = 1;
client.settled = true;
await activeController.runOnce();
expect(client.pauseCalls).toBeGreaterThan(0);
expect(client.offer?.status).toBe("inactive");
expect(store.state.phase).toBe("completed");
expect(activeController.snapshot()).toMatchObject({ ok: true, phase: "completed" });
const callsBeforeRestart = client.externalCalls;
const restarted = controller(client, store);
await restarted.start();
expect(client.externalCalls).toBe(callsBeforeRestart);
expect(restarted.snapshot()).toMatchObject({ ok: true, phase: "completed" });
await restarted.stop();
});
it("never retries an ambiguous create when no matching offer is visible", async () => {
const client = new FakeSurplusClient();
client.createError = new SurplusHttpError("network lost", null);
const store = new MemoryStateStore();
const activeController = controller(client, store);
await activeController.runOnce();
expect(client.createCalls).toBe(1);
expect(store.state.phase).toBe("create_pending");
await activeController.runOnce();
expect(client.createCalls).toBe(1);
expect(activeController.snapshot()).toMatchObject({ ok: false, phase: "error" });
});
it("pauses the managed offer when a required pricing snapshot fails", async () => {
const client = new FakeSurplusClient();
const store = new MemoryStateStore();
const activeController = controller(client, store);
await activeController.runOnce();
expect(client.offer?.status).toBe("active");
client.discoveryError = new Error("discovery unavailable");
await activeController.runOnce();
expect(client.offer?.status).toBe("inactive");
expect(activeController.snapshot()).toMatchObject({ ok: false, phase: "error" });
});
});

View File

@@ -0,0 +1,155 @@
import { describe, expect, it } from "vitest";
import {
quoteSurplusPrice,
} from "../../supplier/src/surplus/policy.js";
import {
eligibleCompetitors,
selectSurplusModelCandidates,
} from "../../supplier/src/surplus/selection.js";
import type {
SurplusDiscoveredModel,
SurplusMarketSummary,
SurplusOrderBookOffer,
} from "../../supplier/src/surplus/client.js";
function discovered(
model: string,
providerModelId: string,
): SurplusDiscoveredModel {
return {
model,
providerModelId,
supported: true,
inputUsdPer1m: 0.07952,
outputUsdPer1m: 0.15904,
priceUnit: "M",
priceVariable: false,
modelType: "text",
availabilityStatus: "available",
};
}
function market(model: string, requests24h: number): SurplusMarketSummary {
return {
model,
requests24h,
volume24h: 1_000,
bestInputMicroUsdPer1m: 4_052,
bestOutputMicroUsdPer1m: 8_104,
healthySellerCount: 1,
};
}
describe("Surplus bounded price policy", () => {
it("uses exact recovery floors and undercuts in integer micro-USD", () => {
const quote = quoteSurplusPrice({
upstreamInputMicroUsdPer1m: 79_520,
upstreamOutputMicroUsdPer1m: 159_040,
recoveryBps: 490,
undercutBps: 10,
competitors: [{
id: "external",
inputMicroUsdPer1m: 3_976,
outputMicroUsdPer1m: 7_952,
}],
});
expect(quote.floorInputMicroUsdPer1m).toBe(3_897);
expect(quote.floorOutputMicroUsdPer1m).toBe(7_793);
expect(quote.inputMicroUsdPer1m).toBe(3_972);
expect(quote.outputMicroUsdPer1m).toBe(7_944);
expect(quote.inputUsdPer1m).toBe(0.003972);
expect(quote.outputUsdPer1m).toBe(0.007944);
expect(quote.competitive).toBe(true);
});
it("keeps the recovery floor when the cheapest offer is too low", () => {
const quote = quoteSurplusPrice({
upstreamInputMicroUsdPer1m: 79_520,
upstreamOutputMicroUsdPer1m: 159_040,
recoveryBps: 490,
undercutBps: 10,
competitors: [{
id: "below-floor",
inputMicroUsdPer1m: 1_000,
outputMicroUsdPer1m: 2_000,
}],
});
expect(quote.inputMicroUsdPer1m).toBe(3_897);
expect(quote.outputMicroUsdPer1m).toBe(7_793);
expect(quote.competitive).toBe(false);
});
it("selects equal-price competitors with a stable total order", () => {
const input = {
upstreamInputMicroUsdPer1m: 100,
upstreamOutputMicroUsdPer1m: 100,
recoveryBps: 100,
undercutBps: 10,
};
const left = { id: "left", inputMicroUsdPer1m: 100, outputMicroUsdPer1m: 300 };
const right = { id: "right", inputMicroUsdPer1m: 200, outputMicroUsdPer1m: 200 };
expect(quoteSurplusPrice({ ...input, competitors: [right, left] }).competitorId)
.toBe("left");
expect(quoteSurplusPrice({ ...input, competitors: [left, right] }).competitorId)
.toBe("left");
});
});
describe("Surplus multi-model selection", () => {
it("selects any eligible OpenRouter model by demand, not a hardcoded model", () => {
const discovery = [
discovered("beta-model", "vendor/beta"),
discovered("alpha-model", "vendor/alpha"),
{ ...discovered("deepseek-v4-flash", "deepseek/deepseek-v4-flash"), supported: false },
];
const markets = [market("alpha-model", 50), market("beta-model", 100)];
const result = selectSurplusModelCandidates(discovery, markets, 490, 10);
expect(result.map((candidate) => candidate.model)).toEqual([
"beta-model",
"alpha-model",
]);
expect(result[0].providerModelId).toBe("vendor/beta");
});
it("resolves equal demand independently of discovery order", () => {
const alpha = discovered("alpha-model", "vendor/alpha");
const beta = discovered("beta-model", "vendor/beta");
const markets = [market("alpha-model", 100), market("beta-model", 100)];
expect(selectSurplusModelCandidates([beta, alpha], markets, 490, 10)[0].model)
.toBe("alpha-model");
expect(selectSurplusModelCandidates([alpha, beta], markets, 490, 10)[0].model)
.toBe("alpha-model");
});
it("excludes unhealthy, untrusted, unavailable, and self offers", () => {
const base: SurplusOrderBookOffer = {
id: "external",
seller: "0x2222222222222222222222222222222222222222",
sellerBaseUrl: "https://openrouter.ai/api/v1",
inputMicroUsdPer1m: 4_000,
outputMicroUsdPer1m: 8_000,
available: true,
healthy: true,
trusted: true,
trades24h: 0,
};
const seller = "0x1111111111111111111111111111111111111111";
const offers = [
base,
{ ...base, id: "self-id", seller },
{ ...base, id: "managed-id" },
{ ...base, id: "unhealthy", healthy: false },
{ ...base, id: "untrusted", trusted: false },
{ ...base, id: "unavailable", available: false },
];
expect(eligibleCompetitors(offers, seller, new Set(["managed-id"])))
.toEqual([{ id: "external", inputMicroUsdPer1m: 4_000, outputMicroUsdPer1m: 8_000 }]);
});
});

View File

@@ -0,0 +1,77 @@
import { afterEach, describe, expect, it } from "vitest";
import {
chmod,
mkdtemp,
rm,
stat,
symlink,
writeFile,
} from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import {
FileSurplusStateStore,
type SurplusControllerState,
} from "../../supplier/src/surplus/state.js";
const directories: string[] = [];
async function temporaryDirectory(): Promise<string> {
const directory = await mkdtemp(join(tmpdir(), "surplus-state-"));
directories.push(directory);
return directory;
}
afterEach(async () => {
await Promise.all(directories.splice(0).map((path) =>
rm(path, { recursive: true, force: true })
));
});
describe("FileSurplusStateStore", () => {
it("writes a private durable completion record and reloads its sale evidence", async () => {
const directory = await temporaryDirectory();
const path = join(directory, "state.json");
const store = new FileSurplusStateStore(path);
const state: SurplusControllerState = {
version: 1,
phase: "completed",
offerId: "offer-1",
model: "alpha-model",
providerModelId: "vendor/alpha-model",
tradeObservedAt: "2026-08-27T10:00:00.000Z",
completedAt: "2026-08-27T10:00:05.000Z",
settlement: {
offerId: "offer-1",
createdAt: "2026-08-27T10:00:03.000Z",
sellerCostMicroUsd: 100,
settlementStatus: "confirmed",
},
};
await store.save(state);
expect((await stat(path)).mode & 0o777).toBe(0o600);
await expect(store.load()).resolves.toEqual(state);
});
it("rejects a state symlink instead of following it", async () => {
const directory = await temporaryDirectory();
const target = join(directory, "target.json");
const path = join(directory, "state.json");
await writeFile(target, '{"version":1,"phase":"selecting"}\n', { mode: 0o600 });
await symlink(target, path);
await expect(new FileSurplusStateStore(path).load()).rejects.toThrow();
});
it("rejects an existing state file with broad permissions", async () => {
const directory = await temporaryDirectory();
const path = join(directory, "state.json");
await writeFile(path, '{"version":1,"phase":"selecting"}\n', { mode: 0o600 });
await chmod(path, 0o644);
await expect(new FileSurplusStateStore(path).load())
.rejects.toThrow("must not allow group or other access");
});
});