(channel = 'evomap-hub', limit = 50)
| 59 | } |
| 60 | |
| 61 | async pull(channel = 'evomap-hub', limit = 50) { |
| 62 | const waitMs = this._hubUnreachableWaitMs(); |
| 63 | if (waitMs > 0) { |
| 64 | return { |
| 65 | received: 0, |
| 66 | error: 'hub_unreachable_backoff', |
| 67 | hubUnreachable: true, |
| 68 | retryAfterMs: waitMs, |
| 69 | }; |
| 70 | } |
| 71 | |
| 72 | const cursorKey = `${channel}:inbound_cursor`; |
| 73 | const cursor = this.store.getCursor(cursorKey); |
| 74 | |
| 75 | const endpoint = `${this.hubUrl}/a2a/mailbox/inbound`; |
| 76 | |
| 77 | try { |
| 78 | const senderId = this.store.getState('node_id'); |
| 79 | const res = await hubFetch(endpoint, { |
| 80 | method: 'POST', |
| 81 | headers: this.getHeaders(), |
| 82 | body: JSON.stringify({ sender_id: senderId, proxy_protocol_version: PROXY_PROTOCOL_VERSION, cursor, limit }), |
| 83 | signal: AbortSignal.timeout(35_000), |
| 84 | }); |
| 85 | |
| 86 | await throwIfHubUnreachableResponse(res, 'inbound pull'); |
| 87 | this._recordHubReachable(); |
| 88 | |
| 89 | if (res.status === 403 || res.status === 401) { |
| 90 | const errText = await readHubResponseText(res).catch(() => 'unknown'); |
| 91 | throw new AuthError(`Hub ${res.status}: ${sanitizeHubResponseForLog(errText)}`, res.status); |
| 92 | } |
| 93 | |
| 94 | if (!res.ok) { |
| 95 | const errText = await readHubResponseText(res).catch(() => 'unknown'); |
| 96 | throw new Error(`Hub returned ${res.status}: ${sanitizeHubResponseForLog(errText)}`); |
| 97 | } |
| 98 | |
| 99 | const data = await readHubResponseJson(res); |
| 100 | const messages = data.messages || []; |
| 101 | let stored = 0; |
| 102 | let dropped = 0; |
| 103 | |
| 104 | if (messages.length > 0) { |
| 105 | for (const m of messages) { |
| 106 | try { |
| 107 | this.store.writeInbound(toInboundStoreMessage(m, channel)); |
| 108 | stored++; |
| 109 | } catch (err) { |
| 110 | if (err && err.code === 'MAILBOX_JSONL_LINE_TOO_LARGE') { |
| 111 | dropped++; |
| 112 | const msgId = m && m.id ? String(m.id) : '(missing id)'; |
| 113 | this.logger.warn?.(`[inbound] dropped oversized inbound message ${msgId}: ${err.message}`); |
| 114 | continue; |
| 115 | } |
| 116 | throw err; |
| 117 | } |
| 118 | } |
no test coverage detected