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.
Files changed (2) hide show
  1. package/dist/index.js +336 -272
  2. 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.0" : "0.0.0-dev";
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: { "Content-Type": "application/json" }
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 fresh = await fetchProxyToken(syncUrl, motebitId);
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 token = await fetchProxyToken(syncUrl, motebitId);
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 HTTPException22 } from "hono/http-exception";
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 HTTPException22(400, { message: "MigrationRequest motebit_id does not match path" });
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 HTTPException22(404, { message: "Agent not found" });
83558
+ throw new HTTPException23(404, { message: "Agent not found" });
83521
83559
  if (agent.revoked)
83522
- throw new HTTPException22(403, { message: "Agent is revoked" });
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 HTTPException22(401, { message: "MigrationRequest signature invalid" });
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 HTTPException22(404, { message: "No active migration token" });
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 HTTPException22(404, { message: "No active migration token" });
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 HTTPException22(400, { message: "Migration token has expired" });
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 HTTPException22(400, { message: "Token motebit_id does not match" });
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 HTTPException22(400, {
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 HTTPException22(400, { message: "Migration token signature invalid" });
83724
+ throw new HTTPException23(400, { message: "Migration token signature invalid" });
83687
83725
  }
83688
83726
  if (!await verifyDepartureAttestation(departure_attestation, sourcePk)) {
83689
- throw new HTTPException22(400, { message: "Departure attestation signature invalid" });
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 HTTPException22(400, { message: "Credential bundle motebit_id does not match" });
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 HTTPException22(400, {
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 HTTPException22(400, { message: "Credential bundle signature invalid" });
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 HTTPException22(409, { message: "Migration token already accepted" });
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 HTTPException22(404, { message: "No active migration" });
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 HTTPException22(404, { message: "No active migration" });
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 HTTPException22(409, {
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 HTTPException22)
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 HTTPException22(400, {
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 HTTPException22(409, {
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 HTTPException22(400, {
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 HTTPException22(409, {
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 HTTPException22(400, {
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 HTTPException22(400, { message: "Balance waiver signature invalid" });
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 HTTPException22(409, {
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 HTTPException23 } from "hono/http-exception";
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 HTTPException23(503, {
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 HTTPException23(503, {
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 HTTPException23(500, {
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 HTTPException23(400, {
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 HTTPException23(401, {
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 HTTPException23(401, {
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 HTTPException23(409, { message: "Dispute with this dispute_id already exists" });
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 HTTPException23(404, { message: "Allocation not found" });
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 HTTPException23(429, {
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 HTTPException23(400, {
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 HTTPException23(404, { message: "Dispute not found" });
84587
+ throw new HTTPException24(404, { message: "Dispute not found" });
84550
84588
  if (dispute.state !== "evidence" && dispute.state !== "opened" && dispute.state !== "resolved") {
84551
- throw new HTTPException23(400, {
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 HTTPException23(500, {
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 HTTPException23(400, {
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 HTTPException23(400, { message: "Evidence window has closed" });
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 HTTPException23(403, { message: "Only dispute parties can submit evidence" });
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 HTTPException23(401, {
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 HTTPException23(401, {
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 HTTPException23(429, {
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 HTTPException23(404, { message: "Dispute not found" });
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 HTTPException23(400, {
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 HTTPException23(400, { message: "Rationale is required" });
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 HTTPException23(500, {
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 HTTPException23(400, {
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 HTTPException23(404, { message: "Dispute not found" });
84770
+ throw new HTTPException24(404, { message: "Dispute not found" });
84733
84771
  dispute = tryFinalizeIfWindowExpired(db, dispute);
84734
84772
  if (dispute.state !== "resolved") {
84735
- throw new HTTPException23(400, { message: "Can only appeal a resolved dispute" });
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 HTTPException23(400, { message: "Appeal window has expired" });
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 HTTPException23(403, { message: "Only dispute parties can appeal" });
84780
+ throw new HTTPException24(403, { message: "Only dispute parties can appeal" });
84743
84781
  }
84744
84782
  if (dispute.appealed_at != null) {
84745
- throw new HTTPException23(409, { message: "Dispute has already been appealed" });
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 HTTPException23(401, {
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 HTTPException23(401, {
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 HTTPException23(500, {
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 HTTPException23(404, { message: "Dispute not found" });
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 HTTPException23(404, { message: "Dispute not found" });
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 HTTPException24 } from "hono/http-exception";
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 HTTPException24(400, { message: "bad_request: malformed JSON body" });
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 HTTPException24(413, {
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 HTTPException24(400, {
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 HTTPException24(400, {
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 HTTPException24(400, {
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 HTTPException24(400, {
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 HTTPException24(400, {
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 HTTPException24(409, {
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 HTTPException24(404, {
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 HTTPException24(500, { message: "internal_error: stored bundle invalid" });
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
- headers
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
- headers,
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 HTTPException8 } from "hono/http-exception";
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 HTTPException8(503, {
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 HTTPException8(400, { message: "Invalid JSON body" });
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 HTTPException8(400, { message: "motebit_id is required" });
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 HTTPException8(400, {
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 HTTPException8(502, {
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 HTTPException9 } from "hono/http-exception";
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 HTTPException9(503, {
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 HTTPException9(400, { message: "Invalid JSON body" });
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 HTTPException9(400, { message: "motebit_id is required" });
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 HTTPException9(400, { message: "source_address is required" });
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 HTTPException9(400, {
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 HTTPException9(400, {
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 HTTPException9(400, {
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 HTTPException9(502, {
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 HTTPException10 } from "hono/http-exception";
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 HTTPException10(401, { message: "Signed device token required for pairing" });
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 HTTPException10(400, { message: "Invalid pairing code format" });
100837
+ throw new HTTPException11(400, { message: "Invalid pairing code format" });
100783
100838
  }
100784
100839
  if (!device_name || typeof device_name !== "string") {
100785
- throw new HTTPException10(400, { message: "Missing device_name" });
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 HTTPException10(400, { message: "Invalid public_key \u2014 must be 64-char hex string" });
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 HTTPException10(400, {
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 HTTPException10(404, { message: "Invalid pairing code" });
100854
+ throw new HTTPException11(404, { message: "Invalid pairing code" });
100800
100855
  }
100801
100856
  if (session.expires_at < Date.now()) {
100802
- throw new HTTPException10(410, { message: "Pairing code expired" });
100857
+ throw new HTTPException11(410, { message: "Pairing code expired" });
100803
100858
  }
100804
100859
  if (session.status !== "pending") {
100805
- throw new HTTPException10(409, { message: "Pairing code already used" });
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 HTTPException10(401, { message: "Signed device token required" });
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 HTTPException10(404, { message: "Pairing session not found" });
100877
+ throw new HTTPException11(404, { message: "Pairing session not found" });
100823
100878
  }
100824
100879
  if (session.motebit_id !== device.motebitId) {
100825
- throw new HTTPException10(403, { message: "Not authorized for this pairing session" });
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 HTTPException10(401, { message: "Signed device token required" });
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 HTTPException10(404, { message: "Pairing session not found" });
100907
+ throw new HTTPException11(404, { message: "Pairing session not found" });
100853
100908
  }
100854
100909
  if (session.motebit_id !== device.motebitId) {
100855
- throw new HTTPException10(403, { message: "Not authorized for this pairing session" });
100910
+ throw new HTTPException11(403, { message: "Not authorized for this pairing session" });
100856
100911
  }
100857
100912
  if (session.status !== "claimed") {
100858
- throw new HTTPException10(409, {
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 HTTPException10(401, { message: "Signed device token required" });
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 HTTPException10(404, { message: "Pairing session not found" });
100950
+ throw new HTTPException11(404, { message: "Pairing session not found" });
100896
100951
  }
100897
100952
  if (session.motebit_id !== device.motebitId) {
100898
- throw new HTTPException10(403, { message: "Not authorized for this pairing session" });
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 HTTPException10(404, { message: "Pairing session not found" });
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 HTTPException10(400, { message: "Invalid public_key \u2014 must be 64-char hex string" });
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 HTTPException10(404, { message: "Pairing session not found" });
100991
+ throw new HTTPException11(404, { message: "Pairing session not found" });
100937
100992
  }
100938
100993
  if (session.status !== "approved") {
100939
- throw new HTTPException10(409, { message: "Pairing session not approved" });
100994
+ throw new HTTPException11(409, { message: "Pairing session not approved" });
100940
100995
  }
100941
100996
  if (session.approved_device_id == null) {
100942
- throw new HTTPException10(409, { message: "No approved device" });
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 HTTPException10(404, { message: "Approved device not found in identity store" });
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 HTTPException11 } from "hono/http-exception";
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 HTTPException11(404, { message: "Plan not found" });
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 HTTPException11(403, {
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 HTTPException11(404, { message: "No plan found for goal" });
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 HTTPException12 } from "hono/http-exception";
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 HTTPException12(404, { message: "No trusted path found" });
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 HTTPException13 } from "hono/http-exception";
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 HTTPException13(403, { message: "Cannot modify another agent's listing" });
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 HTTPException13(404, { message: "No service listing found" });
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 HTTPException14 } from "hono/http-exception";
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 HTTPException14(400, { message: "Missing initiator_motebit_id" });
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 HTTPException14(400, { message: "Missing required fields" });
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 HTTPException14(404, { message: "Proposal not found" });
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 HTTPException14(400, { message: "Missing required fields" });
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 HTTPException14(404, { message: "Proposal not found" });
101683
+ throw new HTTPException15(404, { message: "Proposal not found" });
101629
101684
  if (proposal.status !== "pending")
101630
- throw new HTTPException14(409, {
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 HTTPException14(404, { message: "Proposal not found" });
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 HTTPException14(403, { message: "Only the initiator can withdraw a proposal" });
101743
+ throw new HTTPException15(403, { message: "Only the initiator can withdraw a proposal" });
101689
101744
  if (proposal.status !== "pending")
101690
- throw new HTTPException14(409, {
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 HTTPException14(400, { message: "Missing caller identity" });
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 HTTPException14(400, { message: "Missing required fields" });
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 HTTPException14(404, { message: "Proposal not found" });
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 HTTPException14(403, { message: "Caller is not a participant in this proposal" });
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 HTTPException15 } from "hono/http-exception";
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 HTTPException15(400, { message: "Missing required fields in key succession record" });
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 HTTPException15(400, { message: "Succession record timestamp is in the future" });
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 HTTPException15(400, {
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 HTTPException15(400, { message: "Guardian recovery requires guardian_signature" });
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 HTTPException15(400, {
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 HTTPException15(400, { message: "Invalid guardian recovery signatures" });
101892
+ throw new HTTPException16(400, { message: "Invalid guardian recovery signatures" });
101838
101893
  } else {
101839
101894
  if (!body.old_key_signature) {
101840
- throw new HTTPException15(400, { message: "Normal rotation requires old_key_signature" });
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 HTTPException15(400, { message: "Invalid key succession signatures" });
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 HTTPException15(400, {
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 HTTPException15(403, { message: "Cannot revoke tokens for another agent" });
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 HTTPException15(400, { message: "jtis must be a non-empty array" });
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 HTTPException15(403, { message: "Cannot revoke another agent" });
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 HTTPException15(400, { message: "Invalid JSON body" });
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 HTTPException15(400, {
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 HTTPException15(400, {
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 HTTPException15(409, {
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 HTTPException15(400, {
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 HTTPException15(404, { message: "Approval not found" });
102017
+ throw new HTTPException16(404, { message: "Approval not found" });
101963
102018
  if (!approval.quorum_hash)
101964
- throw new HTTPException15(500, {
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 HTTPException15(409, {
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 HTTPException15(409, {
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 HTTPException15(403, { message: "Approval does not belong to this agent" });
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 HTTPException15(403, { message: "Approver is not authorized for this quorum" });
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 HTTPException15(404, { message: "Approver agent not found" });
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 HTTPException15(403, { message: "Vote signature verification failed" });
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 HTTPException16 } from "hono/http-exception";
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 HTTPException16(401, {
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 HTTPException17 } from "hono/http-exception";
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 HTTPException17(400, {
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 HTTPException17(409, {
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 HTTPException17(400, { message: "amount must be a positive number" });
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 HTTPException17(402, { message: "Insufficient balance for withdrawal" });
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 HTTPException17(400, { message: "payout_reference is required" });
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 HTTPException17(404, { message: "Withdrawal not found or already completed/failed" });
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 HTTPException17(404, { message: "Withdrawal not found or already completed/failed" });
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 HTTPException17(400, { message: "reason is required" });
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 HTTPException17(404, { message: "Withdrawal not found or already completed/failed" });
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 HTTPException17(400, { message: "reason is required" });
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 HTTPException17(501, { message: "Stripe is not configured on this relay" });
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 HTTPException17(400, { message: "amount must be a positive number (in dollars)" });
102522
+ throw new HTTPException18(400, { message: "amount must be a positive number (in dollars)" });
102468
102523
  if (body.amount < 0.5)
102469
- throw new HTTPException17(400, { message: "Minimum deposit amount is $0.50" });
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 HTTPException17(501, { message: "Stripe is not configured on this relay" });
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 HTTPException17(400, { message: "Missing stripe-signature header" });
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 HTTPException17(400, { message: "Invalid webhook signature" });
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 HTTPException18 } from "hono/http-exception";
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 HTTPException18(404, { message: "Task not found or expired" });
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 HTTPException18(403, {
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 HTTPException20 } from "hono/http-exception";
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 HTTPException19 } from "hono/http-exception";
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 HTTPException19(400, { message: "Invalid JSON body" });
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 HTTPException19(400, {
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 HTTPException19(422, { message: "Revocation signature invalid" });
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 HTTPException19(400, { message: "Invalid `since` \u2014 expected non-negative ms" });
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 HTTPException20)
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 HTTPException20(404, {
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 HTTPException20(400, {
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 HTTPException20(400, {
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 HTTPException20(400, {
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 HTTPException20(400, {
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 HTTPException20(500, { message: "Fee split does not conserve budget" });
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 HTTPException20(503, {
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 HTTPException20(502, {
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 HTTPException20)
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 HTTPException20(502, {
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 HTTPException20(402, {
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 HTTPException20)
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 HTTPException21 } from "hono/http-exception";
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 HTTPException21(400, { message: "Missing 'command' field" });
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 HTTPException21(401, {
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 HTTPException21(401, { message: verdict.reason });
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 HTTPException21(500, { message: `Command failed: ${msg}` });
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 HTTPException21(500, { message: `Command failed: ${msg}` });
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 HTTPException21(400, { message: `Unknown command: ${command2}` });
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);