motebit 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +336 -272
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -1091,6 +1091,7 @@ var init_audience = __esm({
|
|
|
1091
1091
|
"account:withdraw",
|
|
1092
1092
|
"account:withdrawals",
|
|
1093
1093
|
"account:checkout",
|
|
1094
|
+
"proxy:token",
|
|
1094
1095
|
"browser-sandbox-grant",
|
|
1095
1096
|
"browser-sandbox",
|
|
1096
1097
|
"runtime:attach"
|
|
@@ -20907,7 +20908,7 @@ var init_config2 = __esm({
|
|
|
20907
20908
|
"src/config.ts"() {
|
|
20908
20909
|
"use strict";
|
|
20909
20910
|
init_esm_shims();
|
|
20910
|
-
VERSION = true ? "1.8.
|
|
20911
|
+
VERSION = true ? "1.8.1" : "0.0.0-dev";
|
|
20911
20912
|
CONFIG_DIR = process.env["MOTEBIT_CONFIG_DIR"] ?? path2.join(os.homedir(), ".motebit");
|
|
20912
20913
|
CONFIG_PATH = path2.join(CONFIG_DIR, "config.json");
|
|
20913
20914
|
RELAY_DIR = path2.join(CONFIG_DIR, "relay");
|
|
@@ -25247,11 +25248,14 @@ var init_migration_client = __esm({
|
|
|
25247
25248
|
});
|
|
25248
25249
|
|
|
25249
25250
|
// ../../packages/runtime/dist/proxy-session.js
|
|
25250
|
-
async function fetchProxyToken(syncUrl, motebitId) {
|
|
25251
|
+
async function fetchProxyToken(syncUrl, motebitId, authToken) {
|
|
25251
25252
|
try {
|
|
25252
25253
|
const res = await fetch(`${syncUrl}/api/v1/agents/${motebitId}/proxy-token`, {
|
|
25253
25254
|
method: "POST",
|
|
25254
|
-
headers: {
|
|
25255
|
+
headers: {
|
|
25256
|
+
"Content-Type": "application/json",
|
|
25257
|
+
...authToken != null && authToken !== "" ? { Authorization: `Bearer ${authToken}` } : {}
|
|
25258
|
+
}
|
|
25255
25259
|
});
|
|
25256
25260
|
if (!res.ok)
|
|
25257
25261
|
return null;
|
|
@@ -25301,7 +25305,8 @@ var init_proxy_session = __esm({
|
|
|
25301
25305
|
return false;
|
|
25302
25306
|
let token = this.adapter.loadToken();
|
|
25303
25307
|
if (!token || token.expiresAt < Date.now() + 6e4) {
|
|
25304
|
-
const
|
|
25308
|
+
const authToken = this.adapter.mintAuthToken ? await this.adapter.mintAuthToken() : null;
|
|
25309
|
+
const fresh = await fetchProxyToken(syncUrl, motebitId, authToken);
|
|
25305
25310
|
if (fresh) {
|
|
25306
25311
|
token = fresh;
|
|
25307
25312
|
this.adapter.saveToken(token);
|
|
@@ -25328,7 +25333,8 @@ var init_proxy_session = __esm({
|
|
|
25328
25333
|
const motebitId = this.adapter.getMotebitId();
|
|
25329
25334
|
if (!syncUrl || !motebitId)
|
|
25330
25335
|
return;
|
|
25331
|
-
const
|
|
25336
|
+
const authToken = this.adapter.mintAuthToken ? await this.adapter.mintAuthToken() : null;
|
|
25337
|
+
const token = await fetchProxyToken(syncUrl, motebitId, authToken);
|
|
25332
25338
|
if (!token)
|
|
25333
25339
|
return;
|
|
25334
25340
|
this.adapter.saveToken(token);
|
|
@@ -78849,6 +78855,52 @@ function enrichWithLatencyStats(agents, db) {
|
|
|
78849
78855
|
return { ...a3, latency_stats: projection };
|
|
78850
78856
|
});
|
|
78851
78857
|
}
|
|
78858
|
+
function registerAgentAuthMiddleware(deps) {
|
|
78859
|
+
const { app, apiToken, identityManager, parseTokenPayloadUnsafe: parseTokenPayloadUnsafe2, verifySignedTokenForDevice: verifySignedTokenForDevice2, isTokenBlacklisted, isAgentRevoked } = deps;
|
|
78860
|
+
app.use("/api/v1/agents/*", async (c3, next) => {
|
|
78861
|
+
const path19 = c3.req.path;
|
|
78862
|
+
const method = c3.req.method;
|
|
78863
|
+
if (PUBLIC_AGENT_ROUTES.some((r2) => r2.match(path19, method))) {
|
|
78864
|
+
await next();
|
|
78865
|
+
return;
|
|
78866
|
+
}
|
|
78867
|
+
const authHeader = c3.req.header("authorization");
|
|
78868
|
+
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
|
78869
|
+
throw new HTTPException5(401, { message: "Missing auth token" });
|
|
78870
|
+
}
|
|
78871
|
+
const token = authHeader.slice(7);
|
|
78872
|
+
if (apiToken != null && apiToken !== "" && token === apiToken) {
|
|
78873
|
+
await next();
|
|
78874
|
+
return;
|
|
78875
|
+
}
|
|
78876
|
+
const claims = parseTokenPayloadUnsafe2(token);
|
|
78877
|
+
if (!claims?.mid) {
|
|
78878
|
+
throw new HTTPException5(401, { message: "Invalid token" });
|
|
78879
|
+
}
|
|
78880
|
+
let agentAudience;
|
|
78881
|
+
if (path19.includes("/p2p-eligibility")) {
|
|
78882
|
+
agentAudience = "market:listing";
|
|
78883
|
+
} else if (path19.includes("/listing")) {
|
|
78884
|
+
agentAudience = "market:listing";
|
|
78885
|
+
} else if (path19.includes("/credentials")) {
|
|
78886
|
+
agentAudience = "credentials";
|
|
78887
|
+
} else if (path19.includes("/presentation")) {
|
|
78888
|
+
agentAudience = "credentials:present";
|
|
78889
|
+
} else if (path19.includes("/proxy-token")) {
|
|
78890
|
+
agentAudience = "proxy:token";
|
|
78891
|
+
} else if (path19.includes("/receipts")) {
|
|
78892
|
+
agentAudience = "receipts:read";
|
|
78893
|
+
} else {
|
|
78894
|
+
agentAudience = "admin:query";
|
|
78895
|
+
}
|
|
78896
|
+
const valid = await verifySignedTokenForDevice2(token, claims.mid, identityManager, agentAudience, isTokenBlacklisted, isAgentRevoked);
|
|
78897
|
+
if (!valid) {
|
|
78898
|
+
throw new HTTPException5(401, { message: "Token verification failed" });
|
|
78899
|
+
}
|
|
78900
|
+
c3.set("callerMotebitId", claims.mid);
|
|
78901
|
+
await next();
|
|
78902
|
+
});
|
|
78903
|
+
}
|
|
78852
78904
|
function registerAgentRoutes(deps) {
|
|
78853
78905
|
const { app, moteDb, identityManager, relayIdentity, connections, taskRouter, apiToken, federationConfig, federationQueryCache, parseTokenPayloadUnsafe: parseTokenPayloadUnsafe2, verifySignedTokenForDevice: verifySignedTokenForDevice2, isTokenBlacklisted, isAgentRevoked } = deps;
|
|
78854
78906
|
app.get("/agent/:motebitId/settlements", (c3) => {
|
|
@@ -79025,58 +79077,6 @@ function registerAgentRoutes(deps) {
|
|
|
79025
79077
|
}
|
|
79026
79078
|
return c3.json(JSON.parse(row.manifest_json));
|
|
79027
79079
|
});
|
|
79028
|
-
app.use("/api/v1/agents/*", async (c3, next) => {
|
|
79029
|
-
if (c3.req.path === "/api/v1/agents/bootstrap") {
|
|
79030
|
-
await next();
|
|
79031
|
-
return;
|
|
79032
|
-
}
|
|
79033
|
-
if (c3.req.path.endsWith("/succession") && c3.req.method === "GET") {
|
|
79034
|
-
await next();
|
|
79035
|
-
return;
|
|
79036
|
-
}
|
|
79037
|
-
if (c3.req.path === "/api/v1/agents/discover" && c3.req.method === "GET") {
|
|
79038
|
-
await next();
|
|
79039
|
-
return;
|
|
79040
|
-
}
|
|
79041
|
-
if (c3.req.path === "/api/v1/agents/revocations" && c3.req.method === "GET") {
|
|
79042
|
-
await next();
|
|
79043
|
-
return;
|
|
79044
|
-
}
|
|
79045
|
-
const authHeader = c3.req.header("authorization");
|
|
79046
|
-
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
|
79047
|
-
throw new HTTPException5(401, { message: "Missing auth token" });
|
|
79048
|
-
}
|
|
79049
|
-
const token = authHeader.slice(7);
|
|
79050
|
-
if (apiToken != null && apiToken !== "" && token === apiToken) {
|
|
79051
|
-
await next();
|
|
79052
|
-
return;
|
|
79053
|
-
}
|
|
79054
|
-
const claims = parseTokenPayloadUnsafe2(token);
|
|
79055
|
-
if (!claims?.mid) {
|
|
79056
|
-
throw new HTTPException5(401, { message: "Invalid token" });
|
|
79057
|
-
}
|
|
79058
|
-
const path19 = c3.req.path;
|
|
79059
|
-
let agentAudience;
|
|
79060
|
-
if (path19.includes("/p2p-eligibility")) {
|
|
79061
|
-
agentAudience = "market:listing";
|
|
79062
|
-
} else if (path19.includes("/listing")) {
|
|
79063
|
-
agentAudience = "market:listing";
|
|
79064
|
-
} else if (path19.includes("/credentials")) {
|
|
79065
|
-
agentAudience = "credentials";
|
|
79066
|
-
} else if (path19.includes("/presentation")) {
|
|
79067
|
-
agentAudience = "credentials:present";
|
|
79068
|
-
} else if (path19.includes("/receipts")) {
|
|
79069
|
-
agentAudience = "receipts:read";
|
|
79070
|
-
} else {
|
|
79071
|
-
agentAudience = "admin:query";
|
|
79072
|
-
}
|
|
79073
|
-
const valid = await verifySignedTokenForDevice2(token, claims.mid, identityManager, agentAudience, isTokenBlacklisted, isAgentRevoked);
|
|
79074
|
-
if (!valid) {
|
|
79075
|
-
throw new HTTPException5(401, { message: "Token verification failed" });
|
|
79076
|
-
}
|
|
79077
|
-
c3.set("callerMotebitId", claims.mid);
|
|
79078
|
-
await next();
|
|
79079
|
-
});
|
|
79080
79080
|
app.get("/api/v1/agents/:motebitId/receipts", (c3) => {
|
|
79081
79081
|
const motebitId = c3.req.param("motebitId");
|
|
79082
79082
|
const caller = c3.get("callerMotebitId");
|
|
@@ -79648,7 +79648,7 @@ function registerAgentRoutes(deps) {
|
|
|
79648
79648
|
return c3.json({ ok: true });
|
|
79649
79649
|
});
|
|
79650
79650
|
}
|
|
79651
|
-
var logger17, SOLVENCY_TTL_MS;
|
|
79651
|
+
var logger17, SOLVENCY_TTL_MS, PUBLIC_AGENT_ROUTES;
|
|
79652
79652
|
var init_agents = __esm({
|
|
79653
79653
|
"../../services/relay/dist/agents.js"() {
|
|
79654
79654
|
"use strict";
|
|
@@ -79668,6 +79668,44 @@ var init_agents = __esm({
|
|
|
79668
79668
|
init_logger();
|
|
79669
79669
|
logger17 = createLogger({ service: "agents" });
|
|
79670
79670
|
SOLVENCY_TTL_MS = 5 * 60 * 1e3;
|
|
79671
|
+
PUBLIC_AGENT_ROUTES = [
|
|
79672
|
+
{
|
|
79673
|
+
match: (p5) => p5 === "/api/v1/agents/bootstrap",
|
|
79674
|
+
reason: "bootstrap: fresh-identity registration, own rate limiter"
|
|
79675
|
+
},
|
|
79676
|
+
{
|
|
79677
|
+
match: (p5, m3) => p5.endsWith("/succession") && m3 === "GET",
|
|
79678
|
+
reason: "succession: public key-lineage verification (CLAUDE.md rule 6)"
|
|
79679
|
+
},
|
|
79680
|
+
{
|
|
79681
|
+
match: (p5, m3) => p5 === "/api/v1/agents/discover" && m3 === "GET",
|
|
79682
|
+
reason: "discover: agents must find each other without pre-existing auth"
|
|
79683
|
+
},
|
|
79684
|
+
{
|
|
79685
|
+
match: (p5, m3) => p5 === "/api/v1/agents/revocations" && m3 === "GET",
|
|
79686
|
+
reason: "revocations: operator's signed, verifiable moderation history"
|
|
79687
|
+
},
|
|
79688
|
+
{
|
|
79689
|
+
match: (p5) => p5.endsWith("/credentials/submit"),
|
|
79690
|
+
reason: "credentials/submit: permissive-by-signature \u2014 the self-verifying envelope IS the auth (spec/credential-v1.md); no bearer token by design"
|
|
79691
|
+
},
|
|
79692
|
+
{
|
|
79693
|
+
match: (p5, m3) => /\/devices\/[^/]+\/hardware-attestation$/.test(p5) && m3 === "POST",
|
|
79694
|
+
reason: "hardware-attestation: self-authenticating \u2014 the request is signed under the device's identity key and verified in-handler (sibling of credentials/submit + register-self); no bearer token by design"
|
|
79695
|
+
},
|
|
79696
|
+
{
|
|
79697
|
+
match: (p5, m3) => p5.endsWith("/debit") && m3 === "POST",
|
|
79698
|
+
reason: "debit: internal service-to-service auth via the x-relay-secret header (subscriptions.ts), verified in-handler \u2014 not a user bearer token. Correct permanent carve-out."
|
|
79699
|
+
},
|
|
79700
|
+
{
|
|
79701
|
+
match: (p5, m3) => p5.endsWith("/solvency-proof") && m3 === "GET",
|
|
79702
|
+
reason: "solvency-proof: public verification primitive by design \u2014 a counterparty checks an agent can cover an amount BEFORE transacting, which requires no pre-existing auth (sibling of succession)."
|
|
79703
|
+
},
|
|
79704
|
+
{
|
|
79705
|
+
match: (p5, m3) => p5.endsWith("/settlements") && m3 === "GET",
|
|
79706
|
+
reason: "settlements (GET): owner-private financial history, but enforced by its OWN dedicated dualAuth(account:balance) in middleware.ts (same class as /balance) + the handler's first-person own-id check. This agent-middleware carve-out DEFERS to that dualAuth \u2014 removing it would double-wrap the route (admin:query here vs account:balance there) and conflict. Not public: account:balance-authed, caller===:motebitId."
|
|
79707
|
+
}
|
|
79708
|
+
];
|
|
79671
79709
|
}
|
|
79672
79710
|
});
|
|
79673
79711
|
|
|
@@ -83450,7 +83488,7 @@ __export(migration_exports, {
|
|
|
83450
83488
|
createMigrationTables: () => createMigrationTables,
|
|
83451
83489
|
registerMigrationRoutes: () => registerMigrationRoutes
|
|
83452
83490
|
});
|
|
83453
|
-
import { HTTPException as
|
|
83491
|
+
import { HTTPException as HTTPException23 } from "hono/http-exception";
|
|
83454
83492
|
function createMigrationTables(db) {
|
|
83455
83493
|
db.exec(`
|
|
83456
83494
|
CREATE TABLE IF NOT EXISTS relay_migrations (
|
|
@@ -83513,15 +83551,15 @@ function registerMigrationRoutes(deps) {
|
|
|
83513
83551
|
}
|
|
83514
83552
|
const request = parsed.data;
|
|
83515
83553
|
if (request.motebit_id !== motebitId) {
|
|
83516
|
-
throw new
|
|
83554
|
+
throw new HTTPException23(400, { message: "MigrationRequest motebit_id does not match path" });
|
|
83517
83555
|
}
|
|
83518
83556
|
const agent = db.prepare("SELECT motebit_id, public_key, revoked FROM agent_registry WHERE motebit_id = ?").get(motebitId);
|
|
83519
83557
|
if (!agent)
|
|
83520
|
-
throw new
|
|
83558
|
+
throw new HTTPException23(404, { message: "Agent not found" });
|
|
83521
83559
|
if (agent.revoked)
|
|
83522
|
-
throw new
|
|
83560
|
+
throw new HTTPException23(403, { message: "Agent is revoked" });
|
|
83523
83561
|
if (!agent.public_key || !await verifyMigrationRequest(request, hexToBytes5(agent.public_key))) {
|
|
83524
|
-
throw new
|
|
83562
|
+
throw new HTTPException23(401, { message: "MigrationRequest signature invalid" });
|
|
83525
83563
|
}
|
|
83526
83564
|
const existing = getActiveMigration(db, motebitId);
|
|
83527
83565
|
if (existing) {
|
|
@@ -83553,7 +83591,7 @@ function registerMigrationRoutes(deps) {
|
|
|
83553
83591
|
const motebitId = c3.req.param("motebitId");
|
|
83554
83592
|
const migration = getActiveMigration(db, motebitId);
|
|
83555
83593
|
if (!migration) {
|
|
83556
|
-
throw new
|
|
83594
|
+
throw new HTTPException23(404, { message: "No active migration token" });
|
|
83557
83595
|
}
|
|
83558
83596
|
updateMigrationState(db, migration.token_id, "attesting");
|
|
83559
83597
|
const agent = db.prepare("SELECT public_key, registered_at, last_heartbeat FROM agent_registry WHERE motebit_id = ?").get(motebitId);
|
|
@@ -83605,7 +83643,7 @@ function registerMigrationRoutes(deps) {
|
|
|
83605
83643
|
const motebitId = c3.req.param("motebitId");
|
|
83606
83644
|
const migration = getActiveMigration(db, motebitId);
|
|
83607
83645
|
if (!migration) {
|
|
83608
|
-
throw new
|
|
83646
|
+
throw new HTTPException23(404, { message: "No active migration token" });
|
|
83609
83647
|
}
|
|
83610
83648
|
updateMigrationState(db, migration.token_id, "exporting");
|
|
83611
83649
|
const credentials = db.prepare("SELECT credential_id, credential_json FROM relay_credentials WHERE subject_motebit_id = ? ORDER BY issued_at ASC").all(motebitId);
|
|
@@ -83656,10 +83694,10 @@ function registerMigrationRoutes(deps) {
|
|
|
83656
83694
|
}
|
|
83657
83695
|
const { migration_token, departure_attestation, credential_bundle } = body;
|
|
83658
83696
|
if (migration_token.expires_at < Date.now()) {
|
|
83659
|
-
throw new
|
|
83697
|
+
throw new HTTPException23(400, { message: "Migration token has expired" });
|
|
83660
83698
|
}
|
|
83661
83699
|
if (migration_token.motebit_id !== body.motebit_id) {
|
|
83662
|
-
throw new
|
|
83700
|
+
throw new HTTPException23(400, { message: "Token motebit_id does not match" });
|
|
83663
83701
|
}
|
|
83664
83702
|
let sourcePk = null;
|
|
83665
83703
|
const pinnedPeer = db.prepare("SELECT public_key FROM relay_peers WHERE peer_relay_id = ? AND state IN ('active', 'suspended')").get(migration_token.source_relay_id);
|
|
@@ -83678,30 +83716,30 @@ function registerMigrationRoutes(deps) {
|
|
|
83678
83716
|
}
|
|
83679
83717
|
}
|
|
83680
83718
|
if (!sourcePk) {
|
|
83681
|
-
throw new
|
|
83719
|
+
throw new HTTPException23(400, {
|
|
83682
83720
|
message: "Cannot establish source relay identity \u2014 migration rejected"
|
|
83683
83721
|
});
|
|
83684
83722
|
}
|
|
83685
83723
|
if (!await verifyMigrationToken(migration_token, sourcePk)) {
|
|
83686
|
-
throw new
|
|
83724
|
+
throw new HTTPException23(400, { message: "Migration token signature invalid" });
|
|
83687
83725
|
}
|
|
83688
83726
|
if (!await verifyDepartureAttestation(departure_attestation, sourcePk)) {
|
|
83689
|
-
throw new
|
|
83727
|
+
throw new HTTPException23(400, { message: "Departure attestation signature invalid" });
|
|
83690
83728
|
}
|
|
83691
83729
|
if (credential_bundle.motebit_id !== body.motebit_id) {
|
|
83692
|
-
throw new
|
|
83730
|
+
throw new HTTPException23(400, { message: "Credential bundle motebit_id does not match" });
|
|
83693
83731
|
}
|
|
83694
83732
|
if (!await verifyMigratingKeyBinding(body.motebit_id, body.public_key, body.identity_file)) {
|
|
83695
|
-
throw new
|
|
83733
|
+
throw new HTTPException23(400, {
|
|
83696
83734
|
message: "Migrating identity is not bound to the presented key"
|
|
83697
83735
|
});
|
|
83698
83736
|
}
|
|
83699
83737
|
if (!await verifyCredentialBundle(credential_bundle, hexToBytes5(body.public_key))) {
|
|
83700
|
-
throw new
|
|
83738
|
+
throw new HTTPException23(400, { message: "Credential bundle signature invalid" });
|
|
83701
83739
|
}
|
|
83702
83740
|
const existing = db.prepare("SELECT token_id FROM relay_accepted_migrations WHERE token_id = ?").get(migration_token.token_id);
|
|
83703
83741
|
if (existing) {
|
|
83704
|
-
throw new
|
|
83742
|
+
throw new HTTPException23(409, { message: "Migration token already accepted" });
|
|
83705
83743
|
}
|
|
83706
83744
|
const now = Date.now();
|
|
83707
83745
|
db.prepare(`INSERT OR REPLACE INTO agent_registry
|
|
@@ -83731,7 +83769,7 @@ function registerMigrationRoutes(deps) {
|
|
|
83731
83769
|
const motebitId = c3.req.param("motebitId");
|
|
83732
83770
|
const migration = getActiveMigration(db, motebitId);
|
|
83733
83771
|
if (!migration) {
|
|
83734
|
-
throw new
|
|
83772
|
+
throw new HTTPException23(404, { message: "No active migration" });
|
|
83735
83773
|
}
|
|
83736
83774
|
updateMigrationState(db, migration.token_id, "cancelled");
|
|
83737
83775
|
logger36.info("migration.cancelled", { motebitId, tokenId: migration.token_id });
|
|
@@ -83741,17 +83779,17 @@ function registerMigrationRoutes(deps) {
|
|
|
83741
83779
|
const motebitId = c3.req.param("motebitId");
|
|
83742
83780
|
const migration = getActiveMigration(db, motebitId);
|
|
83743
83781
|
if (!migration) {
|
|
83744
|
-
throw new
|
|
83782
|
+
throw new HTTPException23(404, { message: "No active migration" });
|
|
83745
83783
|
}
|
|
83746
83784
|
try {
|
|
83747
83785
|
const activeTasks = db.prepare("SELECT COUNT(*) as cnt FROM task_results WHERE (worker_id = ? OR submitted_by = ?) AND status IN ('pending', 'running')").get(motebitId, motebitId);
|
|
83748
83786
|
if (activeTasks && activeTasks.cnt > 0) {
|
|
83749
|
-
throw new
|
|
83787
|
+
throw new HTTPException23(409, {
|
|
83750
83788
|
message: `Cannot depart: ${activeTasks.cnt} active task(s) must complete first`
|
|
83751
83789
|
});
|
|
83752
83790
|
}
|
|
83753
83791
|
} catch (err2) {
|
|
83754
|
-
if (err2 instanceof
|
|
83792
|
+
if (err2 instanceof HTTPException23)
|
|
83755
83793
|
throw err2;
|
|
83756
83794
|
}
|
|
83757
83795
|
let balanceWaiver;
|
|
@@ -83760,7 +83798,7 @@ function registerMigrationRoutes(deps) {
|
|
|
83760
83798
|
if (candidate !== void 0) {
|
|
83761
83799
|
const parsed = BalanceWaiverSchema.safeParse(candidate);
|
|
83762
83800
|
if (!parsed.success) {
|
|
83763
|
-
throw new
|
|
83801
|
+
throw new HTTPException23(400, {
|
|
83764
83802
|
message: `Invalid balance_waiver: ${parsed.error.issues.map((i3) => i3.message).join("; ")}`
|
|
83765
83803
|
});
|
|
83766
83804
|
}
|
|
@@ -83776,17 +83814,17 @@ function registerMigrationRoutes(deps) {
|
|
|
83776
83814
|
let persistedWaiverJson = null;
|
|
83777
83815
|
if (currentBalance > 0) {
|
|
83778
83816
|
if (!balanceWaiver) {
|
|
83779
|
-
throw new
|
|
83817
|
+
throw new HTTPException23(409, {
|
|
83780
83818
|
message: "Cannot depart: balance must be withdrawn or waived first (POST { balance_waiver } per spec/migration-v1.md \xA77.2)"
|
|
83781
83819
|
});
|
|
83782
83820
|
}
|
|
83783
83821
|
if (balanceWaiver.motebit_id !== motebitId) {
|
|
83784
|
-
throw new
|
|
83822
|
+
throw new HTTPException23(400, {
|
|
83785
83823
|
message: "Balance waiver motebit_id does not match path parameter"
|
|
83786
83824
|
});
|
|
83787
83825
|
}
|
|
83788
83826
|
if (balanceWaiver.waived_amount < currentBalance) {
|
|
83789
|
-
throw new
|
|
83827
|
+
throw new HTTPException23(409, {
|
|
83790
83828
|
message: `Balance waiver covers ${balanceWaiver.waived_amount} but current balance is ${currentBalance} \u2014 re-sign and retry`
|
|
83791
83829
|
});
|
|
83792
83830
|
}
|
|
@@ -83799,18 +83837,18 @@ function registerMigrationRoutes(deps) {
|
|
|
83799
83837
|
pubKeyHex = device?.public_key;
|
|
83800
83838
|
}
|
|
83801
83839
|
if (!pubKeyHex) {
|
|
83802
|
-
throw new
|
|
83840
|
+
throw new HTTPException23(400, {
|
|
83803
83841
|
message: "No public key on file for this agent \u2014 cannot verify balance waiver"
|
|
83804
83842
|
});
|
|
83805
83843
|
}
|
|
83806
83844
|
const waiverValid = await verifyBalanceWaiver(balanceWaiver, hexToBytes5(pubKeyHex));
|
|
83807
83845
|
if (!waiverValid) {
|
|
83808
|
-
throw new
|
|
83846
|
+
throw new HTTPException23(400, { message: "Balance waiver signature invalid" });
|
|
83809
83847
|
}
|
|
83810
83848
|
const store = sqliteAccountStoreFor(db);
|
|
83811
83849
|
const debitResult = store.debit(motebitId, currentBalance, "waiver", migration.token_id, `migration waiver: ${migration.token_id}`);
|
|
83812
83850
|
if (debitResult === null) {
|
|
83813
|
-
throw new
|
|
83851
|
+
throw new HTTPException23(409, {
|
|
83814
83852
|
message: "Balance changed during depart; re-check balance and retry"
|
|
83815
83853
|
});
|
|
83816
83854
|
}
|
|
@@ -83964,7 +84002,7 @@ __export(disputes_exports, {
|
|
|
83964
84002
|
runDeferredOrchestrationCycle: () => runDeferredOrchestrationCycle,
|
|
83965
84003
|
startDeferredOrchestrationWorker: () => startDeferredOrchestrationWorker
|
|
83966
84004
|
});
|
|
83967
|
-
import { HTTPException as
|
|
84005
|
+
import { HTTPException as HTTPException24 } from "hono/http-exception";
|
|
83968
84006
|
function createDisputeTables(db) {
|
|
83969
84007
|
db.exec(`
|
|
83970
84008
|
CREATE TABLE IF NOT EXISTS relay_disputes (
|
|
@@ -84249,7 +84287,7 @@ async function orchestrateFederationResolution(dispute, round, deps) {
|
|
|
84249
84287
|
return aggregateVotes(persistedVotes, peers.length, dispute.filer_role);
|
|
84250
84288
|
}
|
|
84251
84289
|
if (peers.length < FEDERATION_QUORUM_MIN) {
|
|
84252
|
-
throw new
|
|
84290
|
+
throw new HTTPException24(503, {
|
|
84253
84291
|
message: JSON.stringify({
|
|
84254
84292
|
error_code: "insufficient_federation_peers",
|
|
84255
84293
|
message: `Federation adjudication requires \u2265${FEDERATION_QUORUM_MIN} OTHER active peers (spec/dispute-v1.md \xA76.2 + \xA76.5 + \xA76.6). Active peer count: ${peers.length}.`
|
|
@@ -84257,7 +84295,7 @@ async function orchestrateFederationResolution(dispute, round, deps) {
|
|
|
84257
84295
|
});
|
|
84258
84296
|
}
|
|
84259
84297
|
if (!dispute.body_json) {
|
|
84260
|
-
throw new
|
|
84298
|
+
throw new HTTPException24(503, {
|
|
84261
84299
|
message: JSON.stringify({
|
|
84262
84300
|
error_code: "legacy_dispute_no_signed_body",
|
|
84263
84301
|
message: "Dispute predates the \xA76.2 body_json migration; federation adjudication unavailable for this dispute."
|
|
@@ -84268,7 +84306,7 @@ async function orchestrateFederationResolution(dispute, round, deps) {
|
|
|
84268
84306
|
try {
|
|
84269
84307
|
parsedDisputeRequest = JSON.parse(dispute.body_json);
|
|
84270
84308
|
} catch (err2) {
|
|
84271
|
-
throw new
|
|
84309
|
+
throw new HTTPException24(500, {
|
|
84272
84310
|
message: `Failed to parse dispute body_json: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
84273
84311
|
});
|
|
84274
84312
|
}
|
|
@@ -84443,26 +84481,26 @@ function registerDisputeRoutes(deps) {
|
|
|
84443
84481
|
}
|
|
84444
84482
|
const req = parsed.data;
|
|
84445
84483
|
if (req.allocation_id !== allocationId) {
|
|
84446
|
-
throw new
|
|
84484
|
+
throw new HTTPException24(400, {
|
|
84447
84485
|
message: "DisputeRequest.allocation_id does not match path parameter"
|
|
84448
84486
|
});
|
|
84449
84487
|
}
|
|
84450
84488
|
const filerRow = db.prepare("SELECT public_key FROM agent_registry WHERE motebit_id = ?").get(req.filed_by);
|
|
84451
84489
|
if (!filerRow?.public_key) {
|
|
84452
|
-
throw new
|
|
84490
|
+
throw new HTTPException24(401, {
|
|
84453
84491
|
message: "Filing party is not registered; cannot verify DisputeRequest signature"
|
|
84454
84492
|
});
|
|
84455
84493
|
}
|
|
84456
84494
|
const filerPubKey = hexToBytes5(filerRow.public_key);
|
|
84457
84495
|
const sigValid = await verifyDisputeRequest(req, filerPubKey);
|
|
84458
84496
|
if (!sigValid) {
|
|
84459
|
-
throw new
|
|
84497
|
+
throw new HTTPException24(401, {
|
|
84460
84498
|
message: "DisputeRequest signature verification failed"
|
|
84461
84499
|
});
|
|
84462
84500
|
}
|
|
84463
84501
|
const existing = getDispute(db, req.dispute_id);
|
|
84464
84502
|
if (existing) {
|
|
84465
|
-
throw new
|
|
84503
|
+
throw new HTTPException24(409, { message: "Dispute with this dispute_id already exists" });
|
|
84466
84504
|
}
|
|
84467
84505
|
const allocation = db.prepare("SELECT allocation_id, task_id, motebit_id, amount_locked, status FROM relay_allocations WHERE allocation_id = ?").get(allocationId);
|
|
84468
84506
|
let isP2pDispute = false;
|
|
@@ -84472,7 +84510,7 @@ function registerDisputeRoutes(deps) {
|
|
|
84472
84510
|
} else {
|
|
84473
84511
|
const p2pSettlement = db.prepare("SELECT settlement_id, task_id, motebit_id FROM relay_settlements WHERE task_id = ? AND settlement_mode = 'p2p'").get(req.task_id);
|
|
84474
84512
|
if (!p2pSettlement) {
|
|
84475
|
-
throw new
|
|
84513
|
+
throw new HTTPException24(404, { message: "Allocation not found" });
|
|
84476
84514
|
}
|
|
84477
84515
|
isP2pDispute = true;
|
|
84478
84516
|
workerId = p2pSettlement.motebit_id;
|
|
@@ -84480,7 +84518,7 @@ function registerDisputeRoutes(deps) {
|
|
|
84480
84518
|
const filerRole = req.filed_by === workerId ? "worker" : "delegator";
|
|
84481
84519
|
const activeCount = db.prepare("SELECT COUNT(*) as cnt FROM relay_disputes WHERE filed_by = ? AND state NOT IN ('final', 'expired')").get(req.filed_by);
|
|
84482
84520
|
if (activeCount.cnt >= MAX_ACTIVE_DISPUTES_PER_AGENT) {
|
|
84483
|
-
throw new
|
|
84521
|
+
throw new HTTPException24(429, {
|
|
84484
84522
|
message: `Maximum ${MAX_ACTIVE_DISPUTES_PER_AGENT} active disputes per agent`
|
|
84485
84523
|
});
|
|
84486
84524
|
}
|
|
@@ -84540,15 +84578,15 @@ function registerDisputeRoutes(deps) {
|
|
|
84540
84578
|
}
|
|
84541
84579
|
const ev = parsed.data;
|
|
84542
84580
|
if (ev.dispute_id !== disputeId) {
|
|
84543
|
-
throw new
|
|
84581
|
+
throw new HTTPException24(400, {
|
|
84544
84582
|
message: "DisputeEvidence.dispute_id does not match path parameter"
|
|
84545
84583
|
});
|
|
84546
84584
|
}
|
|
84547
84585
|
const dispute = getDispute(db, disputeId);
|
|
84548
84586
|
if (!dispute)
|
|
84549
|
-
throw new
|
|
84587
|
+
throw new HTTPException24(404, { message: "Dispute not found" });
|
|
84550
84588
|
if (dispute.state !== "evidence" && dispute.state !== "opened" && dispute.state !== "resolved") {
|
|
84551
|
-
throw new
|
|
84589
|
+
throw new HTTPException24(400, {
|
|
84552
84590
|
message: `Cannot submit evidence in state: ${String(dispute.state)}`
|
|
84553
84591
|
});
|
|
84554
84592
|
}
|
|
@@ -84556,36 +84594,36 @@ function registerDisputeRoutes(deps) {
|
|
|
84556
84594
|
if (dispute.state === "resolved") {
|
|
84557
84595
|
const resolvedAt = dispute.resolved_at;
|
|
84558
84596
|
if (resolvedAt == null) {
|
|
84559
|
-
throw new
|
|
84597
|
+
throw new HTTPException24(500, {
|
|
84560
84598
|
message: "Dispute in resolved state without resolved_at \u2014 schema invariant violated"
|
|
84561
84599
|
});
|
|
84562
84600
|
}
|
|
84563
84601
|
if (now > resolvedAt + APPEAL_WINDOW_MS) {
|
|
84564
|
-
throw new
|
|
84602
|
+
throw new HTTPException24(400, {
|
|
84565
84603
|
message: "Appeal window has closed; no further evidence"
|
|
84566
84604
|
});
|
|
84567
84605
|
}
|
|
84568
84606
|
} else if (now > dispute.evidence_deadline) {
|
|
84569
|
-
throw new
|
|
84607
|
+
throw new HTTPException24(400, { message: "Evidence window has closed" });
|
|
84570
84608
|
}
|
|
84571
84609
|
if (ev.submitted_by !== dispute.filed_by && ev.submitted_by !== dispute.respondent) {
|
|
84572
|
-
throw new
|
|
84610
|
+
throw new HTTPException24(403, { message: "Only dispute parties can submit evidence" });
|
|
84573
84611
|
}
|
|
84574
84612
|
const submitterRow = db.prepare("SELECT public_key FROM agent_registry WHERE motebit_id = ?").get(ev.submitted_by);
|
|
84575
84613
|
if (!submitterRow?.public_key) {
|
|
84576
|
-
throw new
|
|
84614
|
+
throw new HTTPException24(401, {
|
|
84577
84615
|
message: "Submitting party is not registered; cannot verify DisputeEvidence signature"
|
|
84578
84616
|
});
|
|
84579
84617
|
}
|
|
84580
84618
|
const sigValid = await verifyDisputeEvidence(ev, hexToBytes5(submitterRow.public_key));
|
|
84581
84619
|
if (!sigValid) {
|
|
84582
|
-
throw new
|
|
84620
|
+
throw new HTTPException24(401, {
|
|
84583
84621
|
message: "DisputeEvidence signature verification failed"
|
|
84584
84622
|
});
|
|
84585
84623
|
}
|
|
84586
84624
|
const evidenceCount = db.prepare("SELECT COUNT(*) as cnt FROM relay_dispute_evidence WHERE dispute_id = ? AND submitted_by = ?").get(disputeId, ev.submitted_by);
|
|
84587
84625
|
if (evidenceCount.cnt >= MAX_EVIDENCE_PER_PARTY) {
|
|
84588
|
-
throw new
|
|
84626
|
+
throw new HTTPException24(429, {
|
|
84589
84627
|
message: `Maximum ${MAX_EVIDENCE_PER_PARTY} evidence submissions per party`
|
|
84590
84628
|
});
|
|
84591
84629
|
}
|
|
@@ -84604,7 +84642,7 @@ function registerDisputeRoutes(deps) {
|
|
|
84604
84642
|
const body = await c3.req.json();
|
|
84605
84643
|
let dispute = getDispute(db, disputeId);
|
|
84606
84644
|
if (!dispute)
|
|
84607
|
-
throw new
|
|
84645
|
+
throw new HTTPException24(404, { message: "Dispute not found" });
|
|
84608
84646
|
dispute = tryFinalizeIfWindowExpired(db, dispute);
|
|
84609
84647
|
const existing = db.prepare(
|
|
84610
84648
|
// ORDER BY round DESC LIMIT 1: if round 2 exists (post-appeal),
|
|
@@ -84625,7 +84663,7 @@ function registerDisputeRoutes(deps) {
|
|
|
84625
84663
|
});
|
|
84626
84664
|
}
|
|
84627
84665
|
if (dispute.state !== "evidence" && dispute.state !== "arbitration") {
|
|
84628
|
-
throw new
|
|
84666
|
+
throw new HTTPException24(400, {
|
|
84629
84667
|
message: `Cannot resolve in state: ${String(dispute.state)}`
|
|
84630
84668
|
});
|
|
84631
84669
|
}
|
|
@@ -84661,7 +84699,7 @@ function registerDisputeRoutes(deps) {
|
|
|
84661
84699
|
adjudicatorVotes = attempt.result.adjudicator_votes;
|
|
84662
84700
|
} else {
|
|
84663
84701
|
if (!body.rationale) {
|
|
84664
|
-
throw new
|
|
84702
|
+
throw new HTTPException24(400, { message: "Rationale is required" });
|
|
84665
84703
|
}
|
|
84666
84704
|
resolutionOutcome = body.resolution;
|
|
84667
84705
|
resolutionRationale = body.rationale;
|
|
@@ -84682,7 +84720,7 @@ function registerDisputeRoutes(deps) {
|
|
|
84682
84720
|
resolvedAt
|
|
84683
84721
|
}, { db, relayIdentity });
|
|
84684
84722
|
} catch (err2) {
|
|
84685
|
-
throw new
|
|
84723
|
+
throw new HTTPException24(500, {
|
|
84686
84724
|
message: `Dispute resolution persistence failed: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
84687
84725
|
});
|
|
84688
84726
|
}
|
|
@@ -84723,36 +84761,36 @@ function registerDisputeRoutes(deps) {
|
|
|
84723
84761
|
}
|
|
84724
84762
|
const ap = parsed.data;
|
|
84725
84763
|
if (ap.dispute_id !== disputeId) {
|
|
84726
|
-
throw new
|
|
84764
|
+
throw new HTTPException24(400, {
|
|
84727
84765
|
message: "DisputeAppeal.dispute_id does not match path parameter"
|
|
84728
84766
|
});
|
|
84729
84767
|
}
|
|
84730
84768
|
let dispute = getDispute(db, disputeId);
|
|
84731
84769
|
if (!dispute)
|
|
84732
|
-
throw new
|
|
84770
|
+
throw new HTTPException24(404, { message: "Dispute not found" });
|
|
84733
84771
|
dispute = tryFinalizeIfWindowExpired(db, dispute);
|
|
84734
84772
|
if (dispute.state !== "resolved") {
|
|
84735
|
-
throw new
|
|
84773
|
+
throw new HTTPException24(400, { message: "Can only appeal a resolved dispute" });
|
|
84736
84774
|
}
|
|
84737
84775
|
const resolvedAt = dispute.resolved_at;
|
|
84738
84776
|
if (Date.now() > resolvedAt + APPEAL_WINDOW_MS) {
|
|
84739
|
-
throw new
|
|
84777
|
+
throw new HTTPException24(400, { message: "Appeal window has expired" });
|
|
84740
84778
|
}
|
|
84741
84779
|
if (ap.appealed_by !== dispute.filed_by && ap.appealed_by !== dispute.respondent) {
|
|
84742
|
-
throw new
|
|
84780
|
+
throw new HTTPException24(403, { message: "Only dispute parties can appeal" });
|
|
84743
84781
|
}
|
|
84744
84782
|
if (dispute.appealed_at != null) {
|
|
84745
|
-
throw new
|
|
84783
|
+
throw new HTTPException24(409, { message: "Dispute has already been appealed" });
|
|
84746
84784
|
}
|
|
84747
84785
|
const appealerRow = db.prepare("SELECT public_key FROM agent_registry WHERE motebit_id = ?").get(ap.appealed_by);
|
|
84748
84786
|
if (!appealerRow?.public_key) {
|
|
84749
|
-
throw new
|
|
84787
|
+
throw new HTTPException24(401, {
|
|
84750
84788
|
message: "Appealing party is not registered; cannot verify DisputeAppeal signature"
|
|
84751
84789
|
});
|
|
84752
84790
|
}
|
|
84753
84791
|
const sigValid = await verifyDisputeAppeal(ap, hexToBytes5(appealerRow.public_key));
|
|
84754
84792
|
if (!sigValid) {
|
|
84755
|
-
throw new
|
|
84793
|
+
throw new HTTPException24(401, {
|
|
84756
84794
|
message: "DisputeAppeal signature verification failed"
|
|
84757
84795
|
});
|
|
84758
84796
|
}
|
|
@@ -84799,7 +84837,7 @@ function registerDisputeRoutes(deps) {
|
|
|
84799
84837
|
db.exec("COMMIT");
|
|
84800
84838
|
} catch (err2) {
|
|
84801
84839
|
db.exec("ROLLBACK");
|
|
84802
|
-
throw new
|
|
84840
|
+
throw new HTTPException24(500, {
|
|
84803
84841
|
message: `Round-2 finalization failed: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
84804
84842
|
});
|
|
84805
84843
|
}
|
|
@@ -84827,7 +84865,7 @@ function registerDisputeRoutes(deps) {
|
|
|
84827
84865
|
const disputeId = c3.req.param("disputeId");
|
|
84828
84866
|
let dispute = getDispute(db, disputeId);
|
|
84829
84867
|
if (!dispute)
|
|
84830
|
-
throw new
|
|
84868
|
+
throw new HTTPException24(404, { message: "Dispute not found" });
|
|
84831
84869
|
if (dispute.state === "opened" && Date.now() > dispute.filed_at + OPENED_EXPIRE_MS) {
|
|
84832
84870
|
db.prepare("UPDATE relay_disputes SET state = 'expired', expired_at = ? WHERE dispute_id = ?").run(Date.now(), disputeId);
|
|
84833
84871
|
dispute.state = "expired";
|
|
@@ -84846,7 +84884,7 @@ function registerDisputeRoutes(deps) {
|
|
|
84846
84884
|
const disputeId = c3.req.param("disputeId");
|
|
84847
84885
|
const dispute = getDispute(db, disputeId);
|
|
84848
84886
|
if (!dispute)
|
|
84849
|
-
throw new
|
|
84887
|
+
throw new HTTPException24(404, { message: "Dispute not found" });
|
|
84850
84888
|
const resolutions = db.prepare("SELECT * FROM relay_dispute_resolutions WHERE dispute_id = ? ORDER BY round ASC").all(disputeId);
|
|
84851
84889
|
return c3.json({ dispute_id: disputeId, resolutions });
|
|
84852
84890
|
});
|
|
@@ -85673,7 +85711,7 @@ __export(skill_registry_exports, {
|
|
|
85673
85711
|
parseFeaturedSubmitters: () => parseFeaturedSubmitters,
|
|
85674
85712
|
registerSkillRegistryRoutes: () => registerSkillRegistryRoutes
|
|
85675
85713
|
});
|
|
85676
|
-
import { HTTPException as
|
|
85714
|
+
import { HTTPException as HTTPException25 } from "hono/http-exception";
|
|
85677
85715
|
function createSkillRegistryTables(db) {
|
|
85678
85716
|
db.exec(`
|
|
85679
85717
|
CREATE TABLE IF NOT EXISTS relay_skill_registry (
|
|
@@ -85737,17 +85775,17 @@ function registerSkillRegistryRoutes(deps) {
|
|
|
85737
85775
|
try {
|
|
85738
85776
|
raw = await c3.req.json();
|
|
85739
85777
|
} catch {
|
|
85740
|
-
throw new
|
|
85778
|
+
throw new HTTPException25(400, { message: "bad_request: malformed JSON body" });
|
|
85741
85779
|
}
|
|
85742
85780
|
const approxSize = JSON.stringify(raw).length;
|
|
85743
85781
|
if (approxSize > MAX_PAYLOAD_BYTES) {
|
|
85744
|
-
throw new
|
|
85782
|
+
throw new HTTPException25(413, {
|
|
85745
85783
|
message: `payload_too_large: ${approxSize} bytes exceeds ${MAX_PAYLOAD_BYTES}`
|
|
85746
85784
|
});
|
|
85747
85785
|
}
|
|
85748
85786
|
const parsed = SkillRegistrySubmitRequestSchema.safeParse(raw);
|
|
85749
85787
|
if (!parsed.success) {
|
|
85750
|
-
throw new
|
|
85788
|
+
throw new HTTPException25(400, {
|
|
85751
85789
|
message: `bad_request: ${parsed.error.issues.map((i3) => `${i3.path.join(".")}: ${i3.message}`).join("; ")}`
|
|
85752
85790
|
});
|
|
85753
85791
|
}
|
|
@@ -85756,14 +85794,14 @@ function registerSkillRegistryRoutes(deps) {
|
|
|
85756
85794
|
const publicKey = decodeSkillSignaturePublicKey(envelope.signature);
|
|
85757
85795
|
const verifyDetail = await verifySkillEnvelopeDetailed(envelope, publicKey);
|
|
85758
85796
|
if (!verifyDetail.valid) {
|
|
85759
|
-
throw new
|
|
85797
|
+
throw new HTTPException25(400, {
|
|
85760
85798
|
message: `verification_failed: ${verifyDetail.reason}`
|
|
85761
85799
|
});
|
|
85762
85800
|
}
|
|
85763
85801
|
const bodyBytes = base64Decode(submission.body);
|
|
85764
85802
|
const bodyDigest = bytesToHex4(await sha2562(bodyBytes));
|
|
85765
85803
|
if (bodyDigest !== envelope.body_hash) {
|
|
85766
|
-
throw new
|
|
85804
|
+
throw new HTTPException25(400, {
|
|
85767
85805
|
message: `body_hash_mismatch: submitted body hashes to ${bodyDigest}, envelope pins ${envelope.body_hash}`
|
|
85768
85806
|
});
|
|
85769
85807
|
}
|
|
@@ -85771,14 +85809,14 @@ function registerSkillRegistryRoutes(deps) {
|
|
|
85771
85809
|
for (const fileSpec of envelope.files) {
|
|
85772
85810
|
const b64 = fileBytes[fileSpec.path];
|
|
85773
85811
|
if (b64 === void 0) {
|
|
85774
|
-
throw new
|
|
85812
|
+
throw new HTTPException25(400, {
|
|
85775
85813
|
message: `file_hash_mismatch: envelope pins ${fileSpec.path} but submission omits it`
|
|
85776
85814
|
});
|
|
85777
85815
|
}
|
|
85778
85816
|
const decoded = base64Decode(b64);
|
|
85779
85817
|
const digest = bytesToHex4(await sha2562(decoded));
|
|
85780
85818
|
if (digest !== fileSpec.hash) {
|
|
85781
|
-
throw new
|
|
85819
|
+
throw new HTTPException25(400, {
|
|
85782
85820
|
message: `file_hash_mismatch: ${fileSpec.path} hashes to ${digest}, envelope pins ${fileSpec.hash}`
|
|
85783
85821
|
});
|
|
85784
85822
|
}
|
|
@@ -85786,7 +85824,7 @@ function registerSkillRegistryRoutes(deps) {
|
|
|
85786
85824
|
const submitterMotebitId = publicKeyToDidKey(hexToBytes5(envelope.signature.public_key));
|
|
85787
85825
|
const existing = db.prepare("SELECT content_hash, submitted_at FROM relay_skill_registry WHERE submitter_motebit_id = ? AND name = ? AND version = ?").get(submitterMotebitId, envelope.skill.name, envelope.skill.version);
|
|
85788
85826
|
if (existing && existing.content_hash !== envelope.skill.content_hash) {
|
|
85789
|
-
throw new
|
|
85827
|
+
throw new HTTPException25(409, {
|
|
85790
85828
|
message: `version_immutable: ${submitterMotebitId}/${envelope.skill.name}@${envelope.skill.version} already exists with content_hash ${existing.content_hash}`
|
|
85791
85829
|
});
|
|
85792
85830
|
}
|
|
@@ -85869,7 +85907,7 @@ function registerSkillRegistryRoutes(deps) {
|
|
|
85869
85907
|
const version = c3.req.param("version");
|
|
85870
85908
|
const row = db.prepare("SELECT bundle_json FROM relay_skill_registry WHERE submitter_motebit_id = ? AND name = ? AND version = ?").get(submitter, name, version);
|
|
85871
85909
|
if (!row) {
|
|
85872
|
-
throw new
|
|
85910
|
+
throw new HTTPException25(404, {
|
|
85873
85911
|
message: `not_found: ${submitter}/${name}@${version}`
|
|
85874
85912
|
});
|
|
85875
85913
|
}
|
|
@@ -85881,7 +85919,7 @@ function registerSkillRegistryRoutes(deps) {
|
|
|
85881
85919
|
version,
|
|
85882
85920
|
issues: parsed.error.issues
|
|
85883
85921
|
});
|
|
85884
|
-
throw new
|
|
85922
|
+
throw new HTTPException25(500, { message: "internal_error: stored bundle invalid" });
|
|
85885
85923
|
}
|
|
85886
85924
|
return c3.json(parsed.data);
|
|
85887
85925
|
});
|
|
@@ -92879,7 +92917,9 @@ init_runtime_factory();
|
|
|
92879
92917
|
async function handleCredentials(config) {
|
|
92880
92918
|
const motebitId = requireMotebitId(loadFullConfig());
|
|
92881
92919
|
const syncUrl = config.syncUrl ?? process.env["MOTEBIT_SYNC_URL"];
|
|
92882
|
-
const headers = await getRelayAuthHeaders(config
|
|
92920
|
+
const headers = await getRelayAuthHeaders(config, {
|
|
92921
|
+
aud: config.presentation ? "credentials:present" : "credentials"
|
|
92922
|
+
});
|
|
92883
92923
|
let localCreds = [];
|
|
92884
92924
|
try {
|
|
92885
92925
|
const dbPath = getDbPath(config.dbPath);
|
|
@@ -93878,6 +93918,8 @@ async function handleExport(config) {
|
|
|
93878
93918
|
}
|
|
93879
93919
|
moteDb.close();
|
|
93880
93920
|
const syncUrl = config.syncUrl ?? process.env["MOTEBIT_SYNC_URL"];
|
|
93921
|
+
const credHeaders = await getRelayAuthHeaders(config, { aud: "credentials" });
|
|
93922
|
+
const vpHeaders = await getRelayAuthHeaders(config, { aud: "credentials:present" });
|
|
93881
93923
|
const headers = await getRelayAuthHeaders(config);
|
|
93882
93924
|
const baseUrl = syncUrl ? syncUrl.replace(/\/$/, "") : null;
|
|
93883
93925
|
if (!baseUrl) {
|
|
@@ -93887,7 +93929,7 @@ async function handleExport(config) {
|
|
|
93887
93929
|
} else {
|
|
93888
93930
|
const credResult = await fetchRelayJson(
|
|
93889
93931
|
`${baseUrl}/api/v1/agents/${motebitId}/credentials`,
|
|
93890
|
-
|
|
93932
|
+
credHeaders
|
|
93891
93933
|
);
|
|
93892
93934
|
if (credResult.ok) {
|
|
93893
93935
|
const credBody = credResult.data;
|
|
@@ -93900,7 +93942,7 @@ async function handleExport(config) {
|
|
|
93900
93942
|
}
|
|
93901
93943
|
const vpResult = await fetchRelayJson(
|
|
93902
93944
|
`${baseUrl}/api/v1/agents/${motebitId}/presentation`,
|
|
93903
|
-
|
|
93945
|
+
vpHeaders,
|
|
93904
93946
|
"POST"
|
|
93905
93947
|
);
|
|
93906
93948
|
if (vpResult.ok) {
|
|
@@ -99456,6 +99498,10 @@ function registerCredentialRoutes(deps) {
|
|
|
99456
99498
|
});
|
|
99457
99499
|
app.get("/api/v1/agents/:motebitId/credentials", (c3) => {
|
|
99458
99500
|
const mid = asMotebitId(c3.req.param("motebitId"));
|
|
99501
|
+
const callerMotebitId = c3.get("callerMotebitId");
|
|
99502
|
+
if (callerMotebitId !== void 0 && callerMotebitId !== mid) {
|
|
99503
|
+
throw new HTTPException7(403, { message: "Cannot read another agent's credentials" });
|
|
99504
|
+
}
|
|
99459
99505
|
const typeFilter = c3.req.query("type");
|
|
99460
99506
|
const limit = Math.min(parseInt(c3.req.query("limit") ?? "50", 10) || 50, 200);
|
|
99461
99507
|
let rows;
|
|
@@ -99474,6 +99520,10 @@ function registerCredentialRoutes(deps) {
|
|
|
99474
99520
|
});
|
|
99475
99521
|
app.post("/api/v1/agents/:motebitId/presentation", async (c3) => {
|
|
99476
99522
|
const mid = asMotebitId(c3.req.param("motebitId"));
|
|
99523
|
+
const callerMotebitId = c3.get("callerMotebitId");
|
|
99524
|
+
if (callerMotebitId !== void 0 && callerMotebitId !== mid) {
|
|
99525
|
+
throw new HTTPException7(403, { message: "Cannot present another agent's credentials" });
|
|
99526
|
+
}
|
|
99477
99527
|
const typeFilter = c3.req.query("type");
|
|
99478
99528
|
const limit = Math.min(parseInt(c3.req.query("limit") ?? "100", 10) || 100, 500);
|
|
99479
99529
|
let rows;
|
|
@@ -99554,6 +99604,7 @@ function registerCredentialRoutes(deps) {
|
|
|
99554
99604
|
init_esm_shims();
|
|
99555
99605
|
init_dist6();
|
|
99556
99606
|
init_logger();
|
|
99607
|
+
import { HTTPException as HTTPException8 } from "hono/http-exception";
|
|
99557
99608
|
import Stripe from "stripe";
|
|
99558
99609
|
|
|
99559
99610
|
// ../../services/relay/dist/free-credit.js
|
|
@@ -99697,6 +99748,10 @@ async function issueProxyToken(motebitId, balanceMicro, relayIdentity) {
|
|
|
99697
99748
|
function registerProxyTokenRoutes(app, db, relayIdentity, subscriptionEventAdapter = null) {
|
|
99698
99749
|
app.post("/api/v1/agents/:motebitId/proxy-token", async (c3) => {
|
|
99699
99750
|
const motebitId = c3.req.param("motebitId");
|
|
99751
|
+
const callerMotebitId = c3.get("callerMotebitId");
|
|
99752
|
+
if (callerMotebitId !== void 0 && callerMotebitId !== motebitId) {
|
|
99753
|
+
throw new HTTPException8(403, { message: "Cannot mint another agent's proxy token" });
|
|
99754
|
+
}
|
|
99700
99755
|
grantFreeCreditIfEligible(db, motebitId, getClientIp(c3));
|
|
99701
99756
|
const account = getAccountBalance(db, motebitId);
|
|
99702
99757
|
const balance = account?.balance ?? 0;
|
|
@@ -100434,7 +100489,7 @@ init_receipts_store();
|
|
|
100434
100489
|
|
|
100435
100490
|
// ../../services/relay/dist/onramp.js
|
|
100436
100491
|
init_esm_shims();
|
|
100437
|
-
import { HTTPException as
|
|
100492
|
+
import { HTTPException as HTTPException9 } from "hono/http-exception";
|
|
100438
100493
|
|
|
100439
100494
|
// ../../services/relay/dist/onramp/stripe-crypto-adapter.js
|
|
100440
100495
|
init_esm_shims();
|
|
@@ -100543,7 +100598,7 @@ async function hasGas(address, rpcUrl = DEFAULT_RPC) {
|
|
|
100543
100598
|
function registerOnrampRoutes(app, adapter, solanaRpcUrl) {
|
|
100544
100599
|
app.post("/api/v1/onramp/session", async (c3) => {
|
|
100545
100600
|
if (!adapter) {
|
|
100546
|
-
throw new
|
|
100601
|
+
throw new HTTPException9(503, {
|
|
100547
100602
|
message: "On-ramp is not configured on this relay"
|
|
100548
100603
|
});
|
|
100549
100604
|
}
|
|
@@ -100551,13 +100606,13 @@ function registerOnrampRoutes(app, adapter, solanaRpcUrl) {
|
|
|
100551
100606
|
try {
|
|
100552
100607
|
body = await c3.req.json();
|
|
100553
100608
|
} catch {
|
|
100554
|
-
throw new
|
|
100609
|
+
throw new HTTPException9(400, { message: "Invalid JSON body" });
|
|
100555
100610
|
}
|
|
100556
100611
|
if (typeof body.motebit_id !== "string" || body.motebit_id === "") {
|
|
100557
|
-
throw new
|
|
100612
|
+
throw new HTTPException9(400, { message: "motebit_id is required" });
|
|
100558
100613
|
}
|
|
100559
100614
|
if (typeof body.destination_address !== "string" || body.destination_address === "") {
|
|
100560
|
-
throw new
|
|
100615
|
+
throw new HTTPException9(400, {
|
|
100561
100616
|
message: "destination_address is required"
|
|
100562
100617
|
});
|
|
100563
100618
|
}
|
|
@@ -100582,7 +100637,7 @@ function registerOnrampRoutes(app, adapter, solanaRpcUrl) {
|
|
|
100582
100637
|
});
|
|
100583
100638
|
} catch (err2) {
|
|
100584
100639
|
const message2 = err2 instanceof Error ? err2.message : String(err2);
|
|
100585
|
-
throw new
|
|
100640
|
+
throw new HTTPException9(502, {
|
|
100586
100641
|
message: `Onramp provider error: ${message2}`
|
|
100587
100642
|
});
|
|
100588
100643
|
}
|
|
@@ -100591,7 +100646,7 @@ function registerOnrampRoutes(app, adapter, solanaRpcUrl) {
|
|
|
100591
100646
|
|
|
100592
100647
|
// ../../services/relay/dist/offramp.js
|
|
100593
100648
|
init_esm_shims();
|
|
100594
|
-
import { HTTPException as
|
|
100649
|
+
import { HTTPException as HTTPException10 } from "hono/http-exception";
|
|
100595
100650
|
var BridgeOfframpAdapter = class {
|
|
100596
100651
|
provider = "bridge";
|
|
100597
100652
|
apiKey;
|
|
@@ -100651,7 +100706,7 @@ var BridgeOfframpAdapter = class {
|
|
|
100651
100706
|
function registerOfframpRoutes(app, adapter) {
|
|
100652
100707
|
app.post("/api/v1/offramp/session", async (c3) => {
|
|
100653
100708
|
if (!adapter) {
|
|
100654
|
-
throw new
|
|
100709
|
+
throw new HTTPException10(503, {
|
|
100655
100710
|
message: "Off-ramp is not configured on this relay"
|
|
100656
100711
|
});
|
|
100657
100712
|
}
|
|
@@ -100659,26 +100714,26 @@ function registerOfframpRoutes(app, adapter) {
|
|
|
100659
100714
|
try {
|
|
100660
100715
|
body = await c3.req.json();
|
|
100661
100716
|
} catch {
|
|
100662
|
-
throw new
|
|
100717
|
+
throw new HTTPException10(400, { message: "Invalid JSON body" });
|
|
100663
100718
|
}
|
|
100664
100719
|
if (typeof body.motebit_id !== "string" || body.motebit_id === "") {
|
|
100665
|
-
throw new
|
|
100720
|
+
throw new HTTPException10(400, { message: "motebit_id is required" });
|
|
100666
100721
|
}
|
|
100667
100722
|
if (typeof body.source_address !== "string" || body.source_address === "") {
|
|
100668
|
-
throw new
|
|
100723
|
+
throw new HTTPException10(400, { message: "source_address is required" });
|
|
100669
100724
|
}
|
|
100670
100725
|
if (typeof body.amount_usd !== "number" || body.amount_usd <= 0) {
|
|
100671
|
-
throw new
|
|
100726
|
+
throw new HTTPException10(400, {
|
|
100672
100727
|
message: "amount_usd must be a positive number"
|
|
100673
100728
|
});
|
|
100674
100729
|
}
|
|
100675
100730
|
if (typeof body.bridge_customer_id !== "string" || body.bridge_customer_id === "") {
|
|
100676
|
-
throw new
|
|
100731
|
+
throw new HTTPException10(400, {
|
|
100677
100732
|
message: "bridge_customer_id is required"
|
|
100678
100733
|
});
|
|
100679
100734
|
}
|
|
100680
100735
|
if (typeof body.external_account_id !== "string" || body.external_account_id === "") {
|
|
100681
|
-
throw new
|
|
100736
|
+
throw new HTTPException10(400, {
|
|
100682
100737
|
message: "external_account_id is required"
|
|
100683
100738
|
});
|
|
100684
100739
|
}
|
|
@@ -100700,7 +100755,7 @@ function registerOfframpRoutes(app, adapter) {
|
|
|
100700
100755
|
});
|
|
100701
100756
|
} catch (err2) {
|
|
100702
100757
|
const message2 = err2 instanceof Error ? err2.message : String(err2);
|
|
100703
|
-
throw new
|
|
100758
|
+
throw new HTTPException10(502, {
|
|
100704
100759
|
message: `Offramp provider error: ${message2}`
|
|
100705
100760
|
});
|
|
100706
100761
|
}
|
|
@@ -100713,7 +100768,7 @@ init_accounts();
|
|
|
100713
100768
|
|
|
100714
100769
|
// ../../services/relay/dist/pairing.js
|
|
100715
100770
|
init_esm_shims();
|
|
100716
|
-
import { HTTPException as
|
|
100771
|
+
import { HTTPException as HTTPException11 } from "hono/http-exception";
|
|
100717
100772
|
var PAIRING_ALPHABET = "ABCDEFGHJKMNPQRSTUVWXYZ23456789";
|
|
100718
100773
|
var PAIRING_CODE_LENGTH = 6;
|
|
100719
100774
|
var PAIRING_TTL_MS = 5 * 60 * 1e3;
|
|
@@ -100763,7 +100818,7 @@ function registerPairingRoutes(deps) {
|
|
|
100763
100818
|
app.post("/pairing/initiate", async (c3) => {
|
|
100764
100819
|
const device = await verifyPairingAuth(c3.req.header("authorization"));
|
|
100765
100820
|
if (!device) {
|
|
100766
|
-
throw new
|
|
100821
|
+
throw new HTTPException11(401, { message: "Signed device token required for pairing" });
|
|
100767
100822
|
}
|
|
100768
100823
|
const pairingId = crypto.randomUUID();
|
|
100769
100824
|
const pairingCode = generatePairingCode();
|
|
@@ -100779,16 +100834,16 @@ function registerPairingRoutes(deps) {
|
|
|
100779
100834
|
const body = await c3.req.json();
|
|
100780
100835
|
const { pairing_code, device_name, public_key, x25519_pubkey } = body;
|
|
100781
100836
|
if (!pairing_code || typeof pairing_code !== "string" || !/^[A-Z2-9]{6}$/.test(pairing_code)) {
|
|
100782
|
-
throw new
|
|
100837
|
+
throw new HTTPException11(400, { message: "Invalid pairing code format" });
|
|
100783
100838
|
}
|
|
100784
100839
|
if (!device_name || typeof device_name !== "string") {
|
|
100785
|
-
throw new
|
|
100840
|
+
throw new HTTPException11(400, { message: "Missing device_name" });
|
|
100786
100841
|
}
|
|
100787
100842
|
if (!public_key || typeof public_key !== "string" || !/^[0-9a-f]{64}$/i.test(public_key)) {
|
|
100788
|
-
throw new
|
|
100843
|
+
throw new HTTPException11(400, { message: "Invalid public_key \u2014 must be 64-char hex string" });
|
|
100789
100844
|
}
|
|
100790
100845
|
if (x25519_pubkey != null && (typeof x25519_pubkey !== "string" || !/^[0-9a-f]{64}$/i.test(x25519_pubkey))) {
|
|
100791
|
-
throw new
|
|
100846
|
+
throw new HTTPException11(400, {
|
|
100792
100847
|
message: "Invalid x25519_pubkey \u2014 must be 64-char hex string"
|
|
100793
100848
|
});
|
|
100794
100849
|
}
|
|
@@ -100796,13 +100851,13 @@ function registerPairingRoutes(deps) {
|
|
|
100796
100851
|
SELECT * FROM pairing_sessions WHERE pairing_code = ?
|
|
100797
100852
|
`).get(pairing_code);
|
|
100798
100853
|
if (!session) {
|
|
100799
|
-
throw new
|
|
100854
|
+
throw new HTTPException11(404, { message: "Invalid pairing code" });
|
|
100800
100855
|
}
|
|
100801
100856
|
if (session.expires_at < Date.now()) {
|
|
100802
|
-
throw new
|
|
100857
|
+
throw new HTTPException11(410, { message: "Pairing code expired" });
|
|
100803
100858
|
}
|
|
100804
100859
|
if (session.status !== "pending") {
|
|
100805
|
-
throw new
|
|
100860
|
+
throw new HTTPException11(409, { message: "Pairing code already used" });
|
|
100806
100861
|
}
|
|
100807
100862
|
db.prepare(`
|
|
100808
100863
|
UPDATE pairing_sessions SET status = 'claimed', claiming_device_name = ?, claiming_public_key = ?, claiming_x25519_pubkey = ? WHERE pairing_id = ?
|
|
@@ -100812,17 +100867,17 @@ function registerPairingRoutes(deps) {
|
|
|
100812
100867
|
app.get("/pairing/:pairingId", async (c3) => {
|
|
100813
100868
|
const device = await verifyPairingAuth(c3.req.header("authorization"));
|
|
100814
100869
|
if (!device) {
|
|
100815
|
-
throw new
|
|
100870
|
+
throw new HTTPException11(401, { message: "Signed device token required" });
|
|
100816
100871
|
}
|
|
100817
100872
|
const pairingId = c3.req.param("pairingId");
|
|
100818
100873
|
const session = db.prepare(`
|
|
100819
100874
|
SELECT * FROM pairing_sessions WHERE pairing_id = ?
|
|
100820
100875
|
`).get(pairingId);
|
|
100821
100876
|
if (!session) {
|
|
100822
|
-
throw new
|
|
100877
|
+
throw new HTTPException11(404, { message: "Pairing session not found" });
|
|
100823
100878
|
}
|
|
100824
100879
|
if (session.motebit_id !== device.motebitId) {
|
|
100825
|
-
throw new
|
|
100880
|
+
throw new HTTPException11(403, { message: "Not authorized for this pairing session" });
|
|
100826
100881
|
}
|
|
100827
100882
|
const result = {
|
|
100828
100883
|
pairing_id: session.pairing_id,
|
|
@@ -100842,20 +100897,20 @@ function registerPairingRoutes(deps) {
|
|
|
100842
100897
|
app.post("/pairing/:pairingId/approve", async (c3) => {
|
|
100843
100898
|
const device = await verifyPairingAuth(c3.req.header("authorization"));
|
|
100844
100899
|
if (!device) {
|
|
100845
|
-
throw new
|
|
100900
|
+
throw new HTTPException11(401, { message: "Signed device token required" });
|
|
100846
100901
|
}
|
|
100847
100902
|
const pairingId = c3.req.param("pairingId");
|
|
100848
100903
|
const session = db.prepare(`
|
|
100849
100904
|
SELECT * FROM pairing_sessions WHERE pairing_id = ?
|
|
100850
100905
|
`).get(pairingId);
|
|
100851
100906
|
if (!session) {
|
|
100852
|
-
throw new
|
|
100907
|
+
throw new HTTPException11(404, { message: "Pairing session not found" });
|
|
100853
100908
|
}
|
|
100854
100909
|
if (session.motebit_id !== device.motebitId) {
|
|
100855
|
-
throw new
|
|
100910
|
+
throw new HTTPException11(403, { message: "Not authorized for this pairing session" });
|
|
100856
100911
|
}
|
|
100857
100912
|
if (session.status !== "claimed") {
|
|
100858
|
-
throw new
|
|
100913
|
+
throw new HTTPException11(409, {
|
|
100859
100914
|
message: `Cannot approve \u2014 status is '${String(session.status)}'`
|
|
100860
100915
|
});
|
|
100861
100916
|
}
|
|
@@ -100885,17 +100940,17 @@ function registerPairingRoutes(deps) {
|
|
|
100885
100940
|
app.post("/pairing/:pairingId/deny", async (c3) => {
|
|
100886
100941
|
const device = await verifyPairingAuth(c3.req.header("authorization"));
|
|
100887
100942
|
if (!device) {
|
|
100888
|
-
throw new
|
|
100943
|
+
throw new HTTPException11(401, { message: "Signed device token required" });
|
|
100889
100944
|
}
|
|
100890
100945
|
const pairingId = c3.req.param("pairingId");
|
|
100891
100946
|
const session = db.prepare(`
|
|
100892
100947
|
SELECT * FROM pairing_sessions WHERE pairing_id = ?
|
|
100893
100948
|
`).get(pairingId);
|
|
100894
100949
|
if (!session) {
|
|
100895
|
-
throw new
|
|
100950
|
+
throw new HTTPException11(404, { message: "Pairing session not found" });
|
|
100896
100951
|
}
|
|
100897
100952
|
if (session.motebit_id !== device.motebitId) {
|
|
100898
|
-
throw new
|
|
100953
|
+
throw new HTTPException11(403, { message: "Not authorized for this pairing session" });
|
|
100899
100954
|
}
|
|
100900
100955
|
db.prepare(`
|
|
100901
100956
|
UPDATE pairing_sessions SET status = 'denied' WHERE pairing_id = ?
|
|
@@ -100908,7 +100963,7 @@ function registerPairingRoutes(deps) {
|
|
|
100908
100963
|
SELECT status, motebit_id, approved_device_id, key_transfer_payload FROM pairing_sessions WHERE pairing_id = ?
|
|
100909
100964
|
`).get(pairingId);
|
|
100910
100965
|
if (!session) {
|
|
100911
|
-
throw new
|
|
100966
|
+
throw new HTTPException11(404, { message: "Pairing session not found" });
|
|
100912
100967
|
}
|
|
100913
100968
|
const result = { status: session.status };
|
|
100914
100969
|
if (session.status === "approved") {
|
|
@@ -100927,24 +100982,24 @@ function registerPairingRoutes(deps) {
|
|
|
100927
100982
|
const pairingId = c3.req.param("pairingId");
|
|
100928
100983
|
const body = await c3.req.json();
|
|
100929
100984
|
if (!body.public_key || typeof body.public_key !== "string" || !/^[0-9a-f]{64}$/i.test(body.public_key)) {
|
|
100930
|
-
throw new
|
|
100985
|
+
throw new HTTPException11(400, { message: "Invalid public_key \u2014 must be 64-char hex string" });
|
|
100931
100986
|
}
|
|
100932
100987
|
const session = db.prepare(`
|
|
100933
100988
|
SELECT pairing_id, status, approved_device_id, motebit_id FROM pairing_sessions WHERE pairing_id = ?
|
|
100934
100989
|
`).get(pairingId);
|
|
100935
100990
|
if (!session) {
|
|
100936
|
-
throw new
|
|
100991
|
+
throw new HTTPException11(404, { message: "Pairing session not found" });
|
|
100937
100992
|
}
|
|
100938
100993
|
if (session.status !== "approved") {
|
|
100939
|
-
throw new
|
|
100994
|
+
throw new HTTPException11(409, { message: "Pairing session not approved" });
|
|
100940
100995
|
}
|
|
100941
100996
|
if (session.approved_device_id == null) {
|
|
100942
|
-
throw new
|
|
100997
|
+
throw new HTTPException11(409, { message: "No approved device" });
|
|
100943
100998
|
}
|
|
100944
100999
|
const deviceId = session.approved_device_id;
|
|
100945
101000
|
const device = await identityManager.getDevice(deviceId);
|
|
100946
101001
|
if (!device) {
|
|
100947
|
-
throw new
|
|
101002
|
+
throw new HTTPException11(404, { message: "Approved device not found in identity store" });
|
|
100948
101003
|
}
|
|
100949
101004
|
await identityManager.updateDevicePublicKey(deviceId, body.public_key);
|
|
100950
101005
|
return c3.json({ ok: true });
|
|
@@ -100956,7 +101011,7 @@ init_esm_shims();
|
|
|
100956
101011
|
init_dist2();
|
|
100957
101012
|
init_dist6();
|
|
100958
101013
|
init_dist5();
|
|
100959
|
-
import { HTTPException as
|
|
101014
|
+
import { HTTPException as HTTPException12 } from "hono/http-exception";
|
|
100960
101015
|
init_receipts_store();
|
|
100961
101016
|
var MOTEBIT_RELAY_CLAIM_GENERATOR = "motebit-relay/0.5.2";
|
|
100962
101017
|
function registerStateExportRoutes(deps) {
|
|
@@ -101074,7 +101129,7 @@ function registerStateExportRoutes(deps) {
|
|
|
101074
101129
|
const planId = asPlanId(c3.req.param("planId"));
|
|
101075
101130
|
const plan = moteDb.planStore.getPlan(planId);
|
|
101076
101131
|
if (!plan || plan.motebit_id !== motebitId) {
|
|
101077
|
-
throw new
|
|
101132
|
+
throw new HTTPException12(404, { message: "Plan not found" });
|
|
101078
101133
|
}
|
|
101079
101134
|
const steps = moteDb.planStore.getStepsForPlan(planId);
|
|
101080
101135
|
return emitSignedExport(c3, "plan-detail", {
|
|
@@ -101100,7 +101155,7 @@ function registerStateExportRoutes(deps) {
|
|
|
101100
101155
|
const motebitId = asMotebitId(c3.req.param("motebitId"));
|
|
101101
101156
|
const callerMotebitId = c3.get("callerMotebitId");
|
|
101102
101157
|
if (callerMotebitId != null && callerMotebitId !== "" && callerMotebitId !== motebitId) {
|
|
101103
|
-
throw new
|
|
101158
|
+
throw new HTTPException12(403, {
|
|
101104
101159
|
message: "settlement history is first-person: a device token may read only its own motebit's history"
|
|
101105
101160
|
});
|
|
101106
101161
|
}
|
|
@@ -101186,7 +101241,7 @@ function registerStateExportRoutes(deps) {
|
|
|
101186
101241
|
const goalId = c3.req.param("goalId");
|
|
101187
101242
|
const plan = moteDb.planStore.getPlanForGoal(goalId);
|
|
101188
101243
|
if (!plan || plan.motebit_id !== motebitId) {
|
|
101189
|
-
throw new
|
|
101244
|
+
throw new HTTPException12(404, { message: "No plan found for goal" });
|
|
101190
101245
|
}
|
|
101191
101246
|
const steps = moteDb.planStore.getStepsForPlan(plan.plan_id);
|
|
101192
101247
|
const planEventTypes = [
|
|
@@ -101384,7 +101439,7 @@ function registerStateExportRoutes(deps) {
|
|
|
101384
101439
|
init_esm_shims();
|
|
101385
101440
|
init_dist2();
|
|
101386
101441
|
init_dist35();
|
|
101387
|
-
import { HTTPException as
|
|
101442
|
+
import { HTTPException as HTTPException13 } from "hono/http-exception";
|
|
101388
101443
|
function registerTrustGraphRoutes(deps) {
|
|
101389
101444
|
const { app, moteDb, taskRouter } = deps;
|
|
101390
101445
|
app.get("/api/v1/agent-trust/:motebitId", async (c3) => {
|
|
@@ -101405,7 +101460,7 @@ function registerTrustGraphRoutes(deps) {
|
|
|
101405
101460
|
const { profiles } = taskRouter.buildCandidateProfiles(void 0, void 0, 100, motebitId);
|
|
101406
101461
|
const route = findTrustedRoute(asMotebitId(motebitId), asMotebitId(targetId), profiles);
|
|
101407
101462
|
if (!route) {
|
|
101408
|
-
throw new
|
|
101463
|
+
throw new HTTPException13(404, { message: "No trusted path found" });
|
|
101409
101464
|
}
|
|
101410
101465
|
return c3.json({ source: motebitId, target: targetId, trust: route.trust, path: route.path });
|
|
101411
101466
|
});
|
|
@@ -101444,14 +101499,14 @@ init_esm_shims();
|
|
|
101444
101499
|
init_dist2();
|
|
101445
101500
|
init_dist35();
|
|
101446
101501
|
init_accounts();
|
|
101447
|
-
import { HTTPException as
|
|
101502
|
+
import { HTTPException as HTTPException14 } from "hono/http-exception";
|
|
101448
101503
|
function registerListingsRoutes(deps) {
|
|
101449
101504
|
const { app, moteDb, taskRouter } = deps;
|
|
101450
101505
|
app.post("/api/v1/agents/:motebitId/listing", async (c3) => {
|
|
101451
101506
|
const motebitId = asMotebitId(c3.req.param("motebitId"));
|
|
101452
101507
|
const callerMotebitId = c3.get("callerMotebitId");
|
|
101453
101508
|
if (callerMotebitId && callerMotebitId !== motebitId) {
|
|
101454
|
-
throw new
|
|
101509
|
+
throw new HTTPException14(403, { message: "Cannot modify another agent's listing" });
|
|
101455
101510
|
}
|
|
101456
101511
|
const body = await c3.req.json();
|
|
101457
101512
|
const now = Date.now();
|
|
@@ -101466,7 +101521,7 @@ function registerListingsRoutes(deps) {
|
|
|
101466
101521
|
const motebitId = asMotebitId(c3.req.param("motebitId"));
|
|
101467
101522
|
const row = moteDb.db.prepare(`SELECT * FROM relay_service_listings WHERE motebit_id = ?`).get(motebitId);
|
|
101468
101523
|
if (!row) {
|
|
101469
|
-
throw new
|
|
101524
|
+
throw new HTTPException14(404, { message: "No service listing found" });
|
|
101470
101525
|
}
|
|
101471
101526
|
return c3.json({
|
|
101472
101527
|
listing_id: row.listing_id,
|
|
@@ -101552,7 +101607,7 @@ function registerListingsRoutes(deps) {
|
|
|
101552
101607
|
|
|
101553
101608
|
// ../../services/relay/dist/proposals.js
|
|
101554
101609
|
init_esm_shims();
|
|
101555
|
-
import { HTTPException as
|
|
101610
|
+
import { HTTPException as HTTPException15 } from "hono/http-exception";
|
|
101556
101611
|
function registerProposalRoutes(deps) {
|
|
101557
101612
|
const { app, moteDb, connections } = deps;
|
|
101558
101613
|
app.post("/api/v1/proposals", async (c3) => {
|
|
@@ -101560,10 +101615,10 @@ function registerProposalRoutes(deps) {
|
|
|
101560
101615
|
const body = await c3.req.json();
|
|
101561
101616
|
const initiatorId = callerMotebitId ?? body.initiator_motebit_id;
|
|
101562
101617
|
if (!initiatorId) {
|
|
101563
|
-
throw new
|
|
101618
|
+
throw new HTTPException15(400, { message: "Missing initiator_motebit_id" });
|
|
101564
101619
|
}
|
|
101565
101620
|
if (!body.proposal_id || !body.plan_id || !Array.isArray(body.participants)) {
|
|
101566
|
-
throw new
|
|
101621
|
+
throw new HTTPException15(400, { message: "Missing required fields" });
|
|
101567
101622
|
}
|
|
101568
101623
|
const now = Date.now();
|
|
101569
101624
|
const expiresAt = now + (body.expires_in_ms ?? 10 * 60 * 1e3);
|
|
@@ -101593,7 +101648,7 @@ function registerProposalRoutes(deps) {
|
|
|
101593
101648
|
const proposalId = c3.req.param("proposalId");
|
|
101594
101649
|
const proposal = moteDb.db.prepare("SELECT * FROM relay_proposals WHERE proposal_id = ?").get(proposalId);
|
|
101595
101650
|
if (!proposal)
|
|
101596
|
-
throw new
|
|
101651
|
+
throw new HTTPException15(404, { message: "Proposal not found" });
|
|
101597
101652
|
const participants = moteDb.db.prepare("SELECT * FROM relay_proposal_participants WHERE proposal_id = ?").all(proposalId);
|
|
101598
101653
|
return c3.json({
|
|
101599
101654
|
proposal_id: proposal.proposal_id,
|
|
@@ -101622,12 +101677,12 @@ function registerProposalRoutes(deps) {
|
|
|
101622
101677
|
const body = await c3.req.json();
|
|
101623
101678
|
const responderId = callerMotebitId ?? body.responder_motebit_id;
|
|
101624
101679
|
if (!responderId || !body.response)
|
|
101625
|
-
throw new
|
|
101680
|
+
throw new HTTPException15(400, { message: "Missing required fields" });
|
|
101626
101681
|
const proposal = moteDb.db.prepare("SELECT * FROM relay_proposals WHERE proposal_id = ?").get(proposalId);
|
|
101627
101682
|
if (!proposal)
|
|
101628
|
-
throw new
|
|
101683
|
+
throw new HTTPException15(404, { message: "Proposal not found" });
|
|
101629
101684
|
if (proposal.status !== "pending")
|
|
101630
|
-
throw new
|
|
101685
|
+
throw new HTTPException15(409, {
|
|
101631
101686
|
message: `Proposal is ${proposal.status}, cannot respond`
|
|
101632
101687
|
});
|
|
101633
101688
|
const now = Date.now();
|
|
@@ -101682,12 +101737,12 @@ function registerProposalRoutes(deps) {
|
|
|
101682
101737
|
const proposalId = c3.req.param("proposalId");
|
|
101683
101738
|
const proposal = moteDb.db.prepare("SELECT * FROM relay_proposals WHERE proposal_id = ?").get(proposalId);
|
|
101684
101739
|
if (!proposal)
|
|
101685
|
-
throw new
|
|
101740
|
+
throw new HTTPException15(404, { message: "Proposal not found" });
|
|
101686
101741
|
const callerMotebitId = c3.get("callerMotebitId");
|
|
101687
101742
|
if (callerMotebitId && callerMotebitId !== proposal.initiator_motebit_id)
|
|
101688
|
-
throw new
|
|
101743
|
+
throw new HTTPException15(403, { message: "Only the initiator can withdraw a proposal" });
|
|
101689
101744
|
if (proposal.status !== "pending")
|
|
101690
|
-
throw new
|
|
101745
|
+
throw new HTTPException15(409, {
|
|
101691
101746
|
message: `Proposal is ${proposal.status}, cannot withdraw`
|
|
101692
101747
|
});
|
|
101693
101748
|
moteDb.db.prepare("UPDATE relay_proposals SET status = 'withdrawn', updated_at = ? WHERE proposal_id = ?").run(Date.now(), proposalId);
|
|
@@ -101700,7 +101755,7 @@ function registerProposalRoutes(deps) {
|
|
|
101700
101755
|
const limit = Math.min(Math.max(parseInt(limitStr ?? "50", 10) || 50, 1), 200);
|
|
101701
101756
|
const scopeId = callerMotebitId ?? c3.req.query("motebit_id");
|
|
101702
101757
|
if (!scopeId)
|
|
101703
|
-
throw new
|
|
101758
|
+
throw new HTTPException15(400, { message: "Missing caller identity" });
|
|
101704
101759
|
let sql = "SELECT * FROM relay_proposals WHERE (initiator_motebit_id = ? OR proposal_id IN (SELECT proposal_id FROM relay_proposal_participants WHERE motebit_id = ?))";
|
|
101705
101760
|
const params = [scopeId, scopeId];
|
|
101706
101761
|
if (status) {
|
|
@@ -101728,13 +101783,13 @@ function registerProposalRoutes(deps) {
|
|
|
101728
101783
|
const body = await c3.req.json();
|
|
101729
101784
|
const motebitId = callerMotebitId ?? body.motebit_id;
|
|
101730
101785
|
if (!motebitId || !body.step_id || !body.status)
|
|
101731
|
-
throw new
|
|
101786
|
+
throw new HTTPException15(400, { message: "Missing required fields" });
|
|
101732
101787
|
const stepProposal = moteDb.db.prepare("SELECT initiator_motebit_id FROM relay_proposals WHERE proposal_id = ?").get(proposalId);
|
|
101733
101788
|
if (!stepProposal)
|
|
101734
|
-
throw new
|
|
101789
|
+
throw new HTTPException15(404, { message: "Proposal not found" });
|
|
101735
101790
|
const isParticipant = moteDb.db.prepare("SELECT 1 FROM relay_proposal_participants WHERE proposal_id = ? AND motebit_id = ?").get(proposalId, motebitId);
|
|
101736
101791
|
if (!isParticipant && motebitId !== stepProposal.initiator_motebit_id)
|
|
101737
|
-
throw new
|
|
101792
|
+
throw new HTTPException15(403, { message: "Caller is not a participant in this proposal" });
|
|
101738
101793
|
const now = Date.now();
|
|
101739
101794
|
moteDb.db.prepare(`INSERT OR REPLACE INTO relay_collaborative_step_results (proposal_id, step_id, motebit_id, status, result_summary, receipt, completed_at) VALUES (?, ?, ?, ?, ?, ?, ?)`).run(proposalId, body.step_id, motebitId, body.status, body.result_summary ?? null, body.receipt != null ? JSON.stringify(body.receipt) : null, now);
|
|
101740
101795
|
const participants = moteDb.db.prepare("SELECT motebit_id FROM relay_proposal_participants WHERE proposal_id = ?").all(proposalId);
|
|
@@ -101767,7 +101822,7 @@ init_esm_shims();
|
|
|
101767
101822
|
init_dist6();
|
|
101768
101823
|
init_federation();
|
|
101769
101824
|
init_logger();
|
|
101770
|
-
import { HTTPException as
|
|
101825
|
+
import { HTTPException as HTTPException16 } from "hono/http-exception";
|
|
101771
101826
|
var logger25 = createLogger({ service: "key-rotation" });
|
|
101772
101827
|
function registerKeyRotationRoutes(deps) {
|
|
101773
101828
|
const { app, moteDb, relayIdentity } = deps;
|
|
@@ -101809,43 +101864,43 @@ function registerKeyRotationRoutes(deps) {
|
|
|
101809
101864
|
const motebitId = c3.req.param("motebitId");
|
|
101810
101865
|
const body = await c3.req.json();
|
|
101811
101866
|
if (!body.old_public_key || !body.new_public_key || !body.timestamp || !body.new_key_signature) {
|
|
101812
|
-
throw new
|
|
101867
|
+
throw new HTTPException16(400, { message: "Missing required fields in key succession record" });
|
|
101813
101868
|
}
|
|
101814
101869
|
const MAX_ROTATION_AGE_MS = 15 * 60 * 1e3;
|
|
101815
101870
|
const age = Date.now() - body.timestamp;
|
|
101816
101871
|
if (age < -6e4) {
|
|
101817
|
-
throw new
|
|
101872
|
+
throw new HTTPException16(400, { message: "Succession record timestamp is in the future" });
|
|
101818
101873
|
}
|
|
101819
101874
|
if (age > MAX_ROTATION_AGE_MS) {
|
|
101820
|
-
throw new
|
|
101875
|
+
throw new HTTPException16(400, {
|
|
101821
101876
|
message: "Succession record timestamp is too old (>15 minutes)"
|
|
101822
101877
|
});
|
|
101823
101878
|
}
|
|
101824
101879
|
if (body.recovery) {
|
|
101825
101880
|
if (!body.guardian_signature) {
|
|
101826
|
-
throw new
|
|
101881
|
+
throw new HTTPException16(400, { message: "Guardian recovery requires guardian_signature" });
|
|
101827
101882
|
}
|
|
101828
101883
|
const agentGuardian = moteDb.db.prepare("SELECT guardian_public_key FROM agent_registry WHERE motebit_id = ?").get(motebitId);
|
|
101829
101884
|
const guardianPubKey = agentGuardian?.guardian_public_key;
|
|
101830
101885
|
if (!guardianPubKey) {
|
|
101831
|
-
throw new
|
|
101886
|
+
throw new HTTPException16(400, {
|
|
101832
101887
|
message: "Agent has no guardian registered \u2014 cannot use guardian recovery"
|
|
101833
101888
|
});
|
|
101834
101889
|
}
|
|
101835
101890
|
const valid = await verifyKeySuccession(body, guardianPubKey);
|
|
101836
101891
|
if (!valid)
|
|
101837
|
-
throw new
|
|
101892
|
+
throw new HTTPException16(400, { message: "Invalid guardian recovery signatures" });
|
|
101838
101893
|
} else {
|
|
101839
101894
|
if (!body.old_key_signature) {
|
|
101840
|
-
throw new
|
|
101895
|
+
throw new HTTPException16(400, { message: "Normal rotation requires old_key_signature" });
|
|
101841
101896
|
}
|
|
101842
101897
|
const valid = await verifyKeySuccession(body);
|
|
101843
101898
|
if (!valid)
|
|
101844
|
-
throw new
|
|
101899
|
+
throw new HTTPException16(400, { message: "Invalid key succession signatures" });
|
|
101845
101900
|
}
|
|
101846
101901
|
const storedAgent = moteDb.db.prepare("SELECT public_key FROM agent_registry WHERE motebit_id = ?").get(motebitId);
|
|
101847
101902
|
if (storedAgent && storedAgent.public_key && storedAgent.public_key !== body.old_public_key) {
|
|
101848
|
-
throw new
|
|
101903
|
+
throw new HTTPException16(400, {
|
|
101849
101904
|
message: "Succession old_public_key does not match stored public key"
|
|
101850
101905
|
});
|
|
101851
101906
|
}
|
|
@@ -101877,10 +101932,10 @@ function registerKeyRotationRoutes(deps) {
|
|
|
101877
101932
|
const motebitId = c3.req.param("motebitId");
|
|
101878
101933
|
const callerMotebitId = c3.get("callerMotebitId");
|
|
101879
101934
|
if (callerMotebitId && callerMotebitId !== motebitId)
|
|
101880
|
-
throw new
|
|
101935
|
+
throw new HTTPException16(403, { message: "Cannot revoke tokens for another agent" });
|
|
101881
101936
|
const body = await c3.req.json();
|
|
101882
101937
|
if (!Array.isArray(body.jtis) || body.jtis.length === 0)
|
|
101883
|
-
throw new
|
|
101938
|
+
throw new HTTPException16(400, { message: "jtis must be a non-empty array" });
|
|
101884
101939
|
const expiresAt = Date.now() + 6 * 60 * 1e3;
|
|
101885
101940
|
const stmt = moteDb.db.prepare("INSERT OR IGNORE INTO relay_token_blacklist (jti, motebit_id, expires_at) VALUES (?, ?, ?)");
|
|
101886
101941
|
for (const jti of body.jtis) {
|
|
@@ -101892,7 +101947,7 @@ function registerKeyRotationRoutes(deps) {
|
|
|
101892
101947
|
const motebitId = c3.req.param("motebitId");
|
|
101893
101948
|
const callerMotebitId = c3.get("callerMotebitId");
|
|
101894
101949
|
if (callerMotebitId && callerMotebitId !== motebitId)
|
|
101895
|
-
throw new
|
|
101950
|
+
throw new HTTPException16(403, { message: "Cannot revoke another agent" });
|
|
101896
101951
|
let compromisedAt;
|
|
101897
101952
|
const raw = await c3.req.text();
|
|
101898
101953
|
if (raw.trim().length > 0) {
|
|
@@ -101900,12 +101955,12 @@ function registerKeyRotationRoutes(deps) {
|
|
|
101900
101955
|
try {
|
|
101901
101956
|
parsed = JSON.parse(raw);
|
|
101902
101957
|
} catch {
|
|
101903
|
-
throw new
|
|
101958
|
+
throw new HTTPException16(400, { message: "Invalid JSON body" });
|
|
101904
101959
|
}
|
|
101905
101960
|
const ca = parsed.compromised_at;
|
|
101906
101961
|
if (ca !== void 0) {
|
|
101907
101962
|
if (typeof ca !== "number" || !Number.isFinite(ca) || ca <= 0 || ca > Date.now())
|
|
101908
|
-
throw new
|
|
101963
|
+
throw new HTTPException16(400, {
|
|
101909
101964
|
message: "compromised_at must be a positive past epoch-ms timestamp"
|
|
101910
101965
|
});
|
|
101911
101966
|
compromisedAt = ca;
|
|
@@ -101926,7 +101981,7 @@ function registerKeyRotationRoutes(deps) {
|
|
|
101926
101981
|
const motebitId = c3.req.param("motebitId");
|
|
101927
101982
|
const body = await c3.req.json();
|
|
101928
101983
|
if (!body.approval_id || !body.tool_name || !body.args_hash)
|
|
101929
|
-
throw new
|
|
101984
|
+
throw new HTTPException16(400, {
|
|
101930
101985
|
message: "approval_id, tool_name, and args_hash are required"
|
|
101931
101986
|
});
|
|
101932
101987
|
const quorumRequired = body.quorum_required ?? 1;
|
|
@@ -101941,7 +101996,7 @@ function registerKeyRotationRoutes(deps) {
|
|
|
101941
101996
|
idempotent: true
|
|
101942
101997
|
});
|
|
101943
101998
|
}
|
|
101944
|
-
throw new
|
|
101999
|
+
throw new HTTPException16(409, {
|
|
101945
102000
|
message: "Approval already exists with different configuration \u2014 approval metadata is immutable after creation"
|
|
101946
102001
|
});
|
|
101947
102002
|
}
|
|
@@ -101954,29 +102009,29 @@ function registerKeyRotationRoutes(deps) {
|
|
|
101954
102009
|
const approvalId = c3.req.param("approvalId");
|
|
101955
102010
|
const body = await c3.req.json();
|
|
101956
102011
|
if (!body.approver_id || body.approved == null || !body.signature)
|
|
101957
|
-
throw new
|
|
102012
|
+
throw new HTTPException16(400, {
|
|
101958
102013
|
message: "approver_id, approved, and signature are required"
|
|
101959
102014
|
});
|
|
101960
102015
|
const approval = moteDb.db.prepare("SELECT * FROM relay_approval_metadata WHERE approval_id = ?").get(approvalId);
|
|
101961
102016
|
if (!approval)
|
|
101962
|
-
throw new
|
|
102017
|
+
throw new HTTPException16(404, { message: "Approval not found" });
|
|
101963
102018
|
if (!approval.quorum_hash)
|
|
101964
|
-
throw new
|
|
102019
|
+
throw new HTTPException16(500, {
|
|
101965
102020
|
message: "Approval missing quorum_hash \u2014 created before migration. Re-register to fix."
|
|
101966
102021
|
});
|
|
101967
102022
|
if (approval.status === "denied")
|
|
101968
|
-
throw new
|
|
102023
|
+
throw new HTTPException16(409, {
|
|
101969
102024
|
message: "Approval already denied \u2014 no further votes accepted"
|
|
101970
102025
|
});
|
|
101971
102026
|
if (approval.status === "approved")
|
|
101972
|
-
throw new
|
|
102027
|
+
throw new HTTPException16(409, {
|
|
101973
102028
|
message: "Approval already met quorum \u2014 no further votes needed"
|
|
101974
102029
|
});
|
|
101975
102030
|
if (approval.motebit_id !== motebitId)
|
|
101976
|
-
throw new
|
|
102031
|
+
throw new HTTPException16(403, { message: "Approval does not belong to this agent" });
|
|
101977
102032
|
const authorizedApprovers = JSON.parse(approval.quorum_approvers);
|
|
101978
102033
|
if (authorizedApprovers.length > 0 && !authorizedApprovers.includes(body.approver_id))
|
|
101979
|
-
throw new
|
|
102034
|
+
throw new HTTPException16(403, { message: "Approver is not authorized for this quorum" });
|
|
101980
102035
|
const encoder2 = new TextEncoder();
|
|
101981
102036
|
const votePayload = canonicalJson({
|
|
101982
102037
|
type: "approval_vote",
|
|
@@ -101989,10 +102044,10 @@ function registerKeyRotationRoutes(deps) {
|
|
|
101989
102044
|
});
|
|
101990
102045
|
const approverAgent = moteDb.db.prepare("SELECT public_key FROM agent_registry WHERE motebit_id = ?").get(body.approver_id);
|
|
101991
102046
|
if (!approverAgent)
|
|
101992
|
-
throw new
|
|
102047
|
+
throw new HTTPException16(404, { message: "Approver agent not found" });
|
|
101993
102048
|
const sigValid = await ed25519Verify(hexToBytes5(body.signature), encoder2.encode(votePayload), hexToBytes5(approverAgent.public_key));
|
|
101994
102049
|
if (!sigValid)
|
|
101995
|
-
throw new
|
|
102050
|
+
throw new HTTPException16(403, { message: "Vote signature verification failed" });
|
|
101996
102051
|
const existingVote = moteDb.db.prepare("SELECT 1 FROM relay_approval_votes WHERE approval_id = ? AND approver_id = ?").get(approvalId, body.approver_id);
|
|
101997
102052
|
if (existingVote != null)
|
|
101998
102053
|
return c3.json({ ok: true, duplicate: true, approval_id: approvalId });
|
|
@@ -102047,7 +102102,7 @@ init_esm_shims();
|
|
|
102047
102102
|
init_dist6();
|
|
102048
102103
|
init_dist();
|
|
102049
102104
|
init_logger();
|
|
102050
|
-
import { HTTPException as
|
|
102105
|
+
import { HTTPException as HTTPException17 } from "hono/http-exception";
|
|
102051
102106
|
var logger26 = createLogger({ service: "browser-sandbox" });
|
|
102052
102107
|
var DEFAULT_SANDBOX_TOKEN_TTL_SEC = 300;
|
|
102053
102108
|
async function mintBrowserSandboxToken(relayIdentity, motebitId, ttlSec = DEFAULT_SANDBOX_TOKEN_TTL_SEC) {
|
|
@@ -102069,7 +102124,7 @@ function registerBrowserSandboxRoutes(deps) {
|
|
|
102069
102124
|
app.post("/api/v1/browser-sandbox/token", async (c3) => {
|
|
102070
102125
|
const callerMotebitId = c3.get("callerMotebitId");
|
|
102071
102126
|
if (!callerMotebitId) {
|
|
102072
|
-
throw new
|
|
102127
|
+
throw new HTTPException17(401, {
|
|
102073
102128
|
message: "Authentication required \u2014 dualAuth did not set callerMotebitId"
|
|
102074
102129
|
});
|
|
102075
102130
|
}
|
|
@@ -102093,7 +102148,7 @@ init_esm_shims();
|
|
|
102093
102148
|
init_dist();
|
|
102094
102149
|
init_dist6();
|
|
102095
102150
|
init_logger();
|
|
102096
|
-
import { HTTPException as
|
|
102151
|
+
import { HTTPException as HTTPException18 } from "hono/http-exception";
|
|
102097
102152
|
init_accounts();
|
|
102098
102153
|
init_idempotency();
|
|
102099
102154
|
var logger27 = createLogger({ service: "budget" });
|
|
@@ -102183,7 +102238,7 @@ function registerBudgetRoutes(deps) {
|
|
|
102183
102238
|
const correlationId = c3.get("correlationId");
|
|
102184
102239
|
const idempotencyKeyHeader = c3.req.header("Idempotency-Key");
|
|
102185
102240
|
if (!idempotencyKeyHeader) {
|
|
102186
|
-
throw new
|
|
102241
|
+
throw new HTTPException18(400, {
|
|
102187
102242
|
message: "Idempotency-Key header is required for financial operations"
|
|
102188
102243
|
});
|
|
102189
102244
|
}
|
|
@@ -102192,7 +102247,7 @@ function registerBudgetRoutes(deps) {
|
|
|
102192
102247
|
return c3.json(JSON.parse(idempCheck.body), idempCheck.status);
|
|
102193
102248
|
}
|
|
102194
102249
|
if (idempCheck.action === "conflict") {
|
|
102195
|
-
throw new
|
|
102250
|
+
throw new HTTPException18(409, {
|
|
102196
102251
|
message: "A request with this idempotency key is already being processed"
|
|
102197
102252
|
});
|
|
102198
102253
|
}
|
|
@@ -102200,7 +102255,7 @@ function registerBudgetRoutes(deps) {
|
|
|
102200
102255
|
if (typeof body.amount !== "number" || body.amount <= 0) {
|
|
102201
102256
|
const errBody = JSON.stringify({ error: "amount must be a positive number", status: 400 });
|
|
102202
102257
|
completeIdempotency(moteDb.db, idempotencyKeyHeader, motebitId, 400, errBody);
|
|
102203
|
-
throw new
|
|
102258
|
+
throw new HTTPException18(400, { message: "amount must be a positive number" });
|
|
102204
102259
|
}
|
|
102205
102260
|
const amountMicro = toMicro(body.amount);
|
|
102206
102261
|
const idempotencyKey = body.idempotency_key ?? idempotencyKeyHeader;
|
|
@@ -102208,7 +102263,7 @@ function registerBudgetRoutes(deps) {
|
|
|
102208
102263
|
if (result === null) {
|
|
102209
102264
|
const errBody = JSON.stringify({ error: "Insufficient balance for withdrawal", status: 402 });
|
|
102210
102265
|
completeIdempotency(moteDb.db, idempotencyKeyHeader, motebitId, 402, errBody);
|
|
102211
|
-
throw new
|
|
102266
|
+
throw new HTTPException18(402, { message: "Insufficient balance for withdrawal" });
|
|
102212
102267
|
}
|
|
102213
102268
|
if ("existing" in result) {
|
|
102214
102269
|
logger27.info("withdrawal.endpoint.idempotent", {
|
|
@@ -102348,10 +102403,10 @@ function registerBudgetRoutes(deps) {
|
|
|
102348
102403
|
const correlationId = c3.get("correlationId");
|
|
102349
102404
|
const body = await c3.req.json();
|
|
102350
102405
|
if (!body.payout_reference || typeof body.payout_reference !== "string")
|
|
102351
|
-
throw new
|
|
102406
|
+
throw new HTTPException18(400, { message: "payout_reference is required" });
|
|
102352
102407
|
const withdrawal = moteDb.db.prepare("SELECT * FROM relay_withdrawals WHERE withdrawal_id = ? AND status IN ('pending', 'processing')").get(withdrawalId);
|
|
102353
102408
|
if (!withdrawal)
|
|
102354
|
-
throw new
|
|
102409
|
+
throw new HTTPException18(404, { message: "Withdrawal not found or already completed/failed" });
|
|
102355
102410
|
const completedAt = Date.now();
|
|
102356
102411
|
const relayPublicKeyHex = bytesToHex4(relayIdentity.publicKey);
|
|
102357
102412
|
const signature = await signWithdrawalReceipt2({
|
|
@@ -102366,7 +102421,7 @@ function registerBudgetRoutes(deps) {
|
|
|
102366
102421
|
}, relayIdentity.privateKey);
|
|
102367
102422
|
const success2 = completeWithdrawal2(moteDb.db, withdrawalId, body.payout_reference, signature, relayPublicKeyHex, completedAt);
|
|
102368
102423
|
if (!success2)
|
|
102369
|
-
throw new
|
|
102424
|
+
throw new HTTPException18(404, { message: "Withdrawal not found or already completed/failed" });
|
|
102370
102425
|
if (body.rail && railRegistry) {
|
|
102371
102426
|
const rail = railRegistry.get(body.rail);
|
|
102372
102427
|
if (rail) {
|
|
@@ -102410,10 +102465,10 @@ function registerBudgetRoutes(deps) {
|
|
|
102410
102465
|
const correlationId = c3.get("correlationId");
|
|
102411
102466
|
const body = await c3.req.json();
|
|
102412
102467
|
if (!body.reason || typeof body.reason !== "string")
|
|
102413
|
-
throw new
|
|
102468
|
+
throw new HTTPException18(400, { message: "reason is required" });
|
|
102414
102469
|
const success2 = failWithdrawal2(moteDb.db, withdrawalId, body.reason);
|
|
102415
102470
|
if (!success2)
|
|
102416
|
-
throw new
|
|
102471
|
+
throw new HTTPException18(404, { message: "Withdrawal not found or already completed/failed" });
|
|
102417
102472
|
logger27.info("withdrawal.admin.failed", { correlationId, withdrawalId, reason: body.reason });
|
|
102418
102473
|
return c3.json({ withdrawal_id: withdrawalId, status: "failed", refunded: true });
|
|
102419
102474
|
});
|
|
@@ -102434,7 +102489,7 @@ function registerBudgetRoutes(deps) {
|
|
|
102434
102489
|
const body = await c3.req.json().catch(() => ({}));
|
|
102435
102490
|
const reason = typeof body.reason === "string" ? body.reason.trim() : "";
|
|
102436
102491
|
if (!reason)
|
|
102437
|
-
throw new
|
|
102492
|
+
throw new HTTPException18(400, { message: "reason is required" });
|
|
102438
102493
|
persistFreeze(moteDb.db, freezeState, true, reason);
|
|
102439
102494
|
const authHeader = c3.req.header("authorization") ?? "";
|
|
102440
102495
|
const tokenHash = (await hash(new TextEncoder().encode(authHeader))).slice(0, 12);
|
|
@@ -102459,14 +102514,14 @@ function registerBudgetRoutes(deps) {
|
|
|
102459
102514
|
});
|
|
102460
102515
|
app.post("/api/v1/agents/:motebitId/checkout", async (c3) => {
|
|
102461
102516
|
if (!stripeRail && (!stripeClient || !stripeConfig))
|
|
102462
|
-
throw new
|
|
102517
|
+
throw new HTTPException18(501, { message: "Stripe is not configured on this relay" });
|
|
102463
102518
|
const motebitId = c3.req.param("motebitId");
|
|
102464
102519
|
const correlationId = c3.get("correlationId");
|
|
102465
102520
|
const body = await c3.req.json();
|
|
102466
102521
|
if (typeof body.amount !== "number" || body.amount <= 0)
|
|
102467
|
-
throw new
|
|
102522
|
+
throw new HTTPException18(400, { message: "amount must be a positive number (in dollars)" });
|
|
102468
102523
|
if (body.amount < 0.5)
|
|
102469
|
-
throw new
|
|
102524
|
+
throw new HTTPException18(400, { message: "Minimum deposit amount is $0.50" });
|
|
102470
102525
|
let returnUrl;
|
|
102471
102526
|
if (typeof body.return_url === "string" && body.return_url.length > 0) {
|
|
102472
102527
|
try {
|
|
@@ -102527,10 +102582,10 @@ function registerBudgetRoutes(deps) {
|
|
|
102527
102582
|
});
|
|
102528
102583
|
app.post("/api/v1/stripe/webhook", async (c3) => {
|
|
102529
102584
|
if (!stripeRail && (!stripeClient || !stripeConfig))
|
|
102530
|
-
throw new
|
|
102585
|
+
throw new HTTPException18(501, { message: "Stripe is not configured on this relay" });
|
|
102531
102586
|
const sig = c3.req.header("stripe-signature");
|
|
102532
102587
|
if (!sig)
|
|
102533
|
-
throw new
|
|
102588
|
+
throw new HTTPException18(400, { message: "Missing stripe-signature header" });
|
|
102534
102589
|
const rawBody = await c3.req.text();
|
|
102535
102590
|
let event;
|
|
102536
102591
|
try {
|
|
@@ -102543,7 +102598,7 @@ function registerBudgetRoutes(deps) {
|
|
|
102543
102598
|
logger27.info("stripe.webhook.signature_failed", {
|
|
102544
102599
|
error: err2 instanceof Error ? err2.message : String(err2)
|
|
102545
102600
|
});
|
|
102546
|
-
throw new
|
|
102601
|
+
throw new HTTPException18(400, { message: "Invalid webhook signature" });
|
|
102547
102602
|
}
|
|
102548
102603
|
logger27.info("stripe.webhook.received", { type: event.type, id: event.id });
|
|
102549
102604
|
if (event.type === "checkout.session.completed") {
|
|
@@ -102946,7 +103001,7 @@ init_dist2();
|
|
|
102946
103001
|
init_dist35();
|
|
102947
103002
|
init_dist6();
|
|
102948
103003
|
init_dist5();
|
|
102949
|
-
import { HTTPException as
|
|
103004
|
+
import { HTTPException as HTTPException19 } from "hono/http-exception";
|
|
102950
103005
|
init_accounts();
|
|
102951
103006
|
init_logger();
|
|
102952
103007
|
var logger30 = createLogger({ service: "federation-callbacks" });
|
|
@@ -103013,7 +103068,7 @@ function createFederationCallbacks(deps) {
|
|
|
103013
103068
|
async onTaskResultReceived(verified) {
|
|
103014
103069
|
const entry = taskQueue.get(verified.taskId);
|
|
103015
103070
|
if (!entry)
|
|
103016
|
-
throw new
|
|
103071
|
+
throw new HTTPException19(404, { message: "Task not found or expired" });
|
|
103017
103072
|
if (verified.receipt.signature) {
|
|
103018
103073
|
let pubKeyHex;
|
|
103019
103074
|
let keySource;
|
|
@@ -103042,7 +103097,7 @@ function createFederationCallbacks(deps) {
|
|
|
103042
103097
|
originRelay: verified.originRelay,
|
|
103043
103098
|
keySource
|
|
103044
103099
|
});
|
|
103045
|
-
throw new
|
|
103100
|
+
throw new HTTPException19(403, {
|
|
103046
103101
|
message: "Federated receipt signature verification failed"
|
|
103047
103102
|
});
|
|
103048
103103
|
}
|
|
@@ -103279,7 +103334,7 @@ init_dist6();
|
|
|
103279
103334
|
init_dist35();
|
|
103280
103335
|
init_dist();
|
|
103281
103336
|
init_accounts();
|
|
103282
|
-
import { HTTPException as
|
|
103337
|
+
import { HTTPException as HTTPException21 } from "hono/http-exception";
|
|
103283
103338
|
|
|
103284
103339
|
// ../../services/relay/dist/push-adapter.js
|
|
103285
103340
|
init_esm_shims();
|
|
@@ -103444,7 +103499,7 @@ init_dist6();
|
|
|
103444
103499
|
init_dist5();
|
|
103445
103500
|
init_dist31();
|
|
103446
103501
|
init_logger();
|
|
103447
|
-
import { HTTPException as
|
|
103502
|
+
import { HTTPException as HTTPException20 } from "hono/http-exception";
|
|
103448
103503
|
var logger32 = createLogger({ service: "delegation-revocations" });
|
|
103449
103504
|
function insertDelegationRevocation(db, revocation, receivedAt = Date.now()) {
|
|
103450
103505
|
const result = db.prepare(`INSERT OR IGNORE INTO relay_delegation_revocations
|
|
@@ -103472,17 +103527,17 @@ function registerDelegationRevocationRoutes(deps) {
|
|
|
103472
103527
|
try {
|
|
103473
103528
|
raw = await c3.req.json();
|
|
103474
103529
|
} catch {
|
|
103475
|
-
throw new
|
|
103530
|
+
throw new HTTPException20(400, { message: "Invalid JSON body" });
|
|
103476
103531
|
}
|
|
103477
103532
|
const parsed = DelegationRevocationSchema.safeParse(raw);
|
|
103478
103533
|
if (!parsed.success) {
|
|
103479
|
-
throw new
|
|
103534
|
+
throw new HTTPException20(400, {
|
|
103480
103535
|
message: "Body is not a well-formed DelegationRevocation"
|
|
103481
103536
|
});
|
|
103482
103537
|
}
|
|
103483
103538
|
const revocation = parsed.data;
|
|
103484
103539
|
if (!await verifyDelegationRevocation(revocation)) {
|
|
103485
|
-
throw new
|
|
103540
|
+
throw new HTTPException20(422, { message: "Revocation signature invalid" });
|
|
103486
103541
|
}
|
|
103487
103542
|
const recorded = insertDelegationRevocation(db, revocation);
|
|
103488
103543
|
if (recorded) {
|
|
@@ -103501,7 +103556,7 @@ function registerDelegationRevocationRoutes(deps) {
|
|
|
103501
103556
|
const sinceRaw = c3.req.query("since");
|
|
103502
103557
|
const since = sinceRaw !== void 0 ? Number(sinceRaw) : 0;
|
|
103503
103558
|
if (!Number.isFinite(since) || since < 0) {
|
|
103504
|
-
throw new
|
|
103559
|
+
throw new HTTPException20(400, { message: "Invalid `since` \u2014 expected non-negative ms" });
|
|
103505
103560
|
}
|
|
103506
103561
|
const { records, nextSince } = listDelegationRevocations(db, since);
|
|
103507
103562
|
return c3.json({ generated_at: Date.now(), next_since: nextSince, records });
|
|
@@ -104604,7 +104659,7 @@ async function registerTaskRoutes(deps) {
|
|
|
104604
104659
|
moteDb.db.prepare("INSERT OR IGNORE INTO relay_allocations (allocation_id, task_id, motebit_id, amount_locked, status, created_at) VALUES (?, ?, ?, ?, 'locked', ?)").run(`x402-${taskId}`, taskId, motebitId, priceSnapshot, now);
|
|
104605
104660
|
}
|
|
104606
104661
|
} catch (err2) {
|
|
104607
|
-
if (err2 instanceof RelayError || err2 instanceof
|
|
104662
|
+
if (err2 instanceof RelayError || err2 instanceof HTTPException21)
|
|
104608
104663
|
throw err2;
|
|
104609
104664
|
if (requiresPayment) {
|
|
104610
104665
|
logger33.error("task.budget_hold_failed", {
|
|
@@ -104651,7 +104706,7 @@ async function registerTaskRoutes(deps) {
|
|
|
104651
104706
|
const targetId = body.target_agent;
|
|
104652
104707
|
const fc = federatedCandidates.find((c4) => c4.profile.motebit_id === targetId);
|
|
104653
104708
|
if (fc == null || !remoteAgentRelay.has(targetId)) {
|
|
104654
|
-
throw new
|
|
104709
|
+
throw new HTTPException21(404, {
|
|
104655
104710
|
message: "Pinned remote worker not discoverable on any active peer \u2014 cannot place the paid federated task"
|
|
104656
104711
|
});
|
|
104657
104712
|
}
|
|
@@ -104659,12 +104714,12 @@ async function registerTaskRoutes(deps) {
|
|
|
104659
104714
|
const workerAddr = fc._settlement_address;
|
|
104660
104715
|
const fedPrice = fc.profile.listing?.pricing.find((p5) => requiredCaps.includes(p5.capability));
|
|
104661
104716
|
if (!workerAddr) {
|
|
104662
|
-
throw new
|
|
104717
|
+
throw new HTTPException21(400, {
|
|
104663
104718
|
message: "Discovered remote worker has no settlement_address"
|
|
104664
104719
|
});
|
|
104665
104720
|
}
|
|
104666
104721
|
if (fedPrice == null || fedPrice.unit_cost <= 0) {
|
|
104667
|
-
throw new
|
|
104722
|
+
throw new HTTPException21(400, {
|
|
104668
104723
|
message: "Remote worker has no priced listing for the requested capability"
|
|
104669
104724
|
});
|
|
104670
104725
|
}
|
|
@@ -104674,19 +104729,19 @@ async function registerTaskRoutes(deps) {
|
|
|
104674
104729
|
const aTreasury = deriveSolanaAddress2(relayIdentity.publicKey);
|
|
104675
104730
|
const peerRow = moteDb.db.prepare("SELECT public_key FROM relay_peers WHERE endpoint_url = ? AND state = 'active'").get(peerEndpoint);
|
|
104676
104731
|
if (!peerRow?.public_key) {
|
|
104677
|
-
throw new
|
|
104732
|
+
throw new HTTPException21(400, {
|
|
104678
104733
|
message: "Cannot resolve executor relay treasury (peer public key missing)"
|
|
104679
104734
|
});
|
|
104680
104735
|
}
|
|
104681
104736
|
const bTreasury = deriveSolanaAddress2(hexToBytes5(peerRow.public_key));
|
|
104682
104737
|
const legErr = proof.to_address !== workerAddr ? "worker leg address" : proof.amount_micro !== workerNetMicro ? `worker leg amount (${proof.amount_micro} \u2260 ${workerNetMicro})` : proof.fee_to_address !== aTreasury ? "origin-fee leg address" : proof.fee_amount_micro !== aFeeMicro ? `origin-fee leg amount (${proof.fee_amount_micro} \u2260 ${aFeeMicro})` : proof.b_fee_to_address !== bTreasury ? "executor-fee leg address" : proof.b_fee_amount_micro !== bFeeMicro ? `executor-fee leg amount (${proof.b_fee_amount_micro} \u2260 ${bFeeMicro})` : null;
|
|
104683
104738
|
if (legErr) {
|
|
104684
|
-
throw new
|
|
104739
|
+
throw new HTTPException21(400, {
|
|
104685
104740
|
message: `Federated P2P payment_proof leg mismatch: ${legErr}`
|
|
104686
104741
|
});
|
|
104687
104742
|
}
|
|
104688
104743
|
if (workerNetMicro + aFeeMicro + bFeeMicro !== budgetMicro) {
|
|
104689
|
-
throw new
|
|
104744
|
+
throw new HTTPException21(500, { message: "Fee split does not conserve budget" });
|
|
104690
104745
|
}
|
|
104691
104746
|
const p2pEntry = taskQueue.get(taskId);
|
|
104692
104747
|
if (p2pEntry) {
|
|
@@ -104694,7 +104749,7 @@ async function registerTaskRoutes(deps) {
|
|
|
104694
104749
|
taskQueue.set(taskId, p2pEntry);
|
|
104695
104750
|
}
|
|
104696
104751
|
if (!taskRouter.canForward(peerEndpoint)) {
|
|
104697
|
-
throw new
|
|
104752
|
+
throw new HTTPException21(503, {
|
|
104698
104753
|
message: "Executor relay temporarily unavailable (circuit open) \u2014 retry shortly"
|
|
104699
104754
|
});
|
|
104700
104755
|
}
|
|
@@ -104745,12 +104800,12 @@ async function registerTaskRoutes(deps) {
|
|
|
104745
104800
|
});
|
|
104746
104801
|
} else {
|
|
104747
104802
|
taskRouter.recordPeerForwardResult(peerEndpoint, false);
|
|
104748
|
-
throw new
|
|
104803
|
+
throw new HTTPException21(502, {
|
|
104749
104804
|
message: `Executor relay rejected the forwarded task (HTTP ${resp.status}) \u2014 retryable: resubmit the same payment_proof`
|
|
104750
104805
|
});
|
|
104751
104806
|
}
|
|
104752
104807
|
} catch (fwdErr) {
|
|
104753
|
-
if (fwdErr instanceof
|
|
104808
|
+
if (fwdErr instanceof HTTPException21)
|
|
104754
104809
|
throw fwdErr;
|
|
104755
104810
|
taskRouter.recordPeerForwardResult(peerEndpoint, false);
|
|
104756
104811
|
logger33.warn("task.federated_p2p_forward_failed", {
|
|
@@ -104759,7 +104814,7 @@ async function registerTaskRoutes(deps) {
|
|
|
104759
104814
|
targetAgent: targetId,
|
|
104760
104815
|
error: fwdErr instanceof Error ? fwdErr.message : String(fwdErr)
|
|
104761
104816
|
});
|
|
104762
|
-
throw new
|
|
104817
|
+
throw new HTTPException21(502, {
|
|
104763
104818
|
message: "Failed to forward federated P2P task to the executor relay \u2014 retryable: resubmit the same payment_proof"
|
|
104764
104819
|
});
|
|
104765
104820
|
}
|
|
@@ -104821,7 +104876,7 @@ async function registerTaskRoutes(deps) {
|
|
|
104821
104876
|
const fedProfile = federatedCandidates.find((fc) => fc.profile.motebit_id === selId)?.profile;
|
|
104822
104877
|
const fedPrice = fedProfile?.listing?.pricing.find((p5) => requiredCaps.includes(p5.capability));
|
|
104823
104878
|
if (fedPrice != null && fedPrice.unit_cost > 0) {
|
|
104824
|
-
throw new
|
|
104879
|
+
throw new HTTPException21(402, {
|
|
104825
104880
|
message: "Paid federated delegation requires a 3-leg P2P payment_proof (submit with target_agent + payment_proof). Deposit-funded cross-operator settlement is closed. See off-ramp-as-user-action.md."
|
|
104826
104881
|
});
|
|
104827
104882
|
}
|
|
@@ -104894,7 +104949,7 @@ async function registerTaskRoutes(deps) {
|
|
|
104894
104949
|
}
|
|
104895
104950
|
}
|
|
104896
104951
|
} catch (err2) {
|
|
104897
|
-
if (err2 instanceof
|
|
104952
|
+
if (err2 instanceof HTTPException21)
|
|
104898
104953
|
throw err2;
|
|
104899
104954
|
}
|
|
104900
104955
|
}
|
|
@@ -105273,7 +105328,7 @@ var TaskQueue = class {
|
|
|
105273
105328
|
// ../../services/relay/dist/command-route.js
|
|
105274
105329
|
init_esm_shims();
|
|
105275
105330
|
init_dist5();
|
|
105276
|
-
import { HTTPException as
|
|
105331
|
+
import { HTTPException as HTTPException22 } from "hono/http-exception";
|
|
105277
105332
|
var RELAY_SIDE_COMMANDS = /* @__PURE__ */ new Set(["balance", "deposits", "discover", "proposals"]);
|
|
105278
105333
|
var RUNTIME_SIDE_COMMANDS = /* @__PURE__ */ new Set([
|
|
105279
105334
|
"state",
|
|
@@ -105303,13 +105358,13 @@ function registerCommandRoutes(deps) {
|
|
|
105303
105358
|
const motebitId = c3.req.param("motebitId");
|
|
105304
105359
|
const body = await c3.req.json();
|
|
105305
105360
|
if (typeof body.command !== "string" || body.command === "") {
|
|
105306
|
-
throw new
|
|
105361
|
+
throw new HTTPException22(400, { message: "Missing 'command' field" });
|
|
105307
105362
|
}
|
|
105308
105363
|
const command2 = body.command;
|
|
105309
105364
|
const args = typeof body.args === "string" ? body.args : void 0;
|
|
105310
105365
|
const registered = db.prepare("SELECT public_key FROM agent_registry WHERE motebit_id = ?").get(motebitId);
|
|
105311
105366
|
if (!registered || registered.public_key === "") {
|
|
105312
|
-
throw new
|
|
105367
|
+
throw new HTTPException22(401, {
|
|
105313
105368
|
message: "Unknown agent identity \u2014 no registered public key to verify the command against"
|
|
105314
105369
|
});
|
|
105315
105370
|
}
|
|
@@ -105321,7 +105376,7 @@ function registerCommandRoutes(deps) {
|
|
|
105321
105376
|
identityPublicKey: registered.public_key
|
|
105322
105377
|
});
|
|
105323
105378
|
if (!verdict.ok) {
|
|
105324
|
-
throw new
|
|
105379
|
+
throw new HTTPException22(401, { message: verdict.reason });
|
|
105325
105380
|
}
|
|
105326
105381
|
if (command2 in INFO_COMMANDS) {
|
|
105327
105382
|
return c3.json({ summary: INFO_COMMANDS[command2] });
|
|
@@ -105332,7 +105387,7 @@ function registerCommandRoutes(deps) {
|
|
|
105332
105387
|
return c3.json(result);
|
|
105333
105388
|
} catch (err2) {
|
|
105334
105389
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
105335
|
-
throw new
|
|
105390
|
+
throw new HTTPException22(500, { message: `Command failed: ${msg}` });
|
|
105336
105391
|
}
|
|
105337
105392
|
}
|
|
105338
105393
|
if (RUNTIME_SIDE_COMMANDS.has(command2)) {
|
|
@@ -105348,7 +105403,7 @@ function registerCommandRoutes(deps) {
|
|
|
105348
105403
|
if (msg === "Command timed out") {
|
|
105349
105404
|
return c3.json({ summary: "Agent did not respond in time." }, 504);
|
|
105350
105405
|
}
|
|
105351
|
-
throw new
|
|
105406
|
+
throw new HTTPException22(500, { message: `Command failed: ${msg}` });
|
|
105352
105407
|
}
|
|
105353
105408
|
}
|
|
105354
105409
|
if (command2 === "mcp") {
|
|
@@ -105356,7 +105411,7 @@ function registerCommandRoutes(deps) {
|
|
|
105356
105411
|
summary: "MCP server listing is surface-specific and not available remotely."
|
|
105357
105412
|
});
|
|
105358
105413
|
}
|
|
105359
|
-
throw new
|
|
105414
|
+
throw new HTTPException22(400, { message: `Unknown command: ${command2}` });
|
|
105360
105415
|
});
|
|
105361
105416
|
app.get("/__internal/noop", (c3) => c3.text("ok"));
|
|
105362
105417
|
}
|
|
@@ -106066,6 +106121,15 @@ async function createSyncRelay(config) {
|
|
|
106066
106121
|
onCommandResponse: handleCommandResponse,
|
|
106067
106122
|
isDraining: () => draining
|
|
106068
106123
|
});
|
|
106124
|
+
registerAgentAuthMiddleware({
|
|
106125
|
+
app,
|
|
106126
|
+
apiToken,
|
|
106127
|
+
identityManager,
|
|
106128
|
+
parseTokenPayloadUnsafe,
|
|
106129
|
+
verifySignedTokenForDevice,
|
|
106130
|
+
isTokenBlacklisted,
|
|
106131
|
+
isAgentRevoked
|
|
106132
|
+
});
|
|
106069
106133
|
registerSyncRoutes({ app, moteDb, eventStore, identityManager, connections });
|
|
106070
106134
|
registerIntakeRoutes({ app, moteDb, relayIdentity });
|
|
106071
106135
|
registerAuthMiddleware({
|
|
@@ -106299,7 +106363,6 @@ async function createSyncRelay(config) {
|
|
|
106299
106363
|
redactSensitiveEvents
|
|
106300
106364
|
});
|
|
106301
106365
|
registerTrustGraphRoutes({ app, moteDb, taskRouter });
|
|
106302
|
-
registerListingsRoutes({ app, moteDb, taskRouter });
|
|
106303
106366
|
registerProposalRoutes({ app, moteDb, connections });
|
|
106304
106367
|
registerKeyRotationRoutes({ app, moteDb, relayIdentity });
|
|
106305
106368
|
registerBrowserSandboxRoutes({ app, relayIdentity });
|
|
@@ -106355,6 +106418,7 @@ async function createSyncRelay(config) {
|
|
|
106355
106418
|
isTokenBlacklisted,
|
|
106356
106419
|
isAgentRevoked
|
|
106357
106420
|
});
|
|
106421
|
+
registerListingsRoutes({ app, moteDb, taskRouter });
|
|
106358
106422
|
registerCommandRoutes({ app, db: moteDb.db, connections, logger: logger43 });
|
|
106359
106423
|
registerDelegationRevocationRoutes({ app, db: moteDb.db });
|
|
106360
106424
|
const heartbeatInterval = startHeartbeatLoop(moteDb.db, relayIdentity, 6e4, () => getEmergencyFreeze(), loopSupervisor);
|