libp2r2p 0.11.15 → 0.11.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -4
- package/package.json +1 -1
- package/relay/helpers/error.js +5 -7
- package/relay/helpers/retry-advice.js +18 -0
- package/relay/index.js +1 -0
package/README.md
CHANGED
|
@@ -936,9 +936,22 @@ also admits relay policy refusals (`blocked:`, `restricted:`, `auth-required:`,
|
|
|
936
936
|
Local authentication denials, invalid events and unknown errors qualify for
|
|
937
937
|
neither policy. Predicates classify individual native errors; callers decide
|
|
938
938
|
how to handle mixed per-relay outcomes and application-specific aggregates.
|
|
939
|
-
|
|
940
|
-
`
|
|
941
|
-
|
|
939
|
+
`parseRelayRetryAdvice(reason, extra, { now = Date.now() })`, exported by
|
|
940
|
+
`libp2r2p/relay`, returns `{ retryAt, retryAfterMs? }` or `null`. It only interprets
|
|
941
|
+
leading `rate-limited:` refusals. Optional `retry_at` is a Unix timestamp in
|
|
942
|
+
seconds (fractions allowed), converted to milliseconds. Finite positive absolute
|
|
943
|
+
advice takes precedence over `retry_after`, including when already expired;
|
|
944
|
+
expired advice does not restart a relative wait. Future waits are capped at five
|
|
945
|
+
minutes from processing. Missing/invalid absolute advice falls back to finite
|
|
946
|
+
positive relative seconds, capped at 300. A valid relative value is retained as
|
|
947
|
+
`retryAfterMs` even when the absolute deadline wins. Schedulers wait until
|
|
948
|
+
max(local backoff deadline, retryAt), never sum the two or renew the deadline on
|
|
949
|
+
online notifications.
|
|
950
|
+
|
|
951
|
+
The optional Nostr extension works with older relays that only send
|
|
952
|
+
`retry_after` and older consumers that ignore `retry_at`. Neither field supplies
|
|
953
|
+
provenance or retry eligibility: `local`, `origin`, `retryable`, category and code
|
|
954
|
+
claims in extras are ignored. Native messages, causes and codes remain intact.
|
|
942
955
|
|
|
943
956
|
## Binary encodings
|
|
944
957
|
|
|
@@ -1059,7 +1072,7 @@ user-facing send error.
|
|
|
1059
1072
|
|
|
1060
1073
|
### Relay backpressure and bounded synchronization (0.11.7)
|
|
1061
1074
|
|
|
1062
|
-
Optional numeric `retry_after` seconds on relay `CLOSED` and rejected `OK`
|
|
1075
|
+
Optional `retry_at` Unix seconds or numeric `retry_after` seconds on relay `CLOSED` and rejected `OK`
|
|
1063
1076
|
responses are preserved as `retryAfterMs` and `retryAt` on native relay errors.
|
|
1064
1077
|
Only `rate-limited:` responses apply this advice; invalid values are ignored
|
|
1065
1078
|
and delays are capped at five minutes. New operations on that connection wait
|
package/package.json
CHANGED
package/relay/helpers/error.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { parseRelayRetryAdvice } from './retry-advice.js'
|
|
2
|
+
|
|
1
3
|
// Adds transport context without replacing native messages, codes or causes.
|
|
2
4
|
export function categorizeRelayError (reason, category, fallback = 'RELAY_OPERATION_FAILED') {
|
|
3
5
|
const error = reason instanceof Error ? reason : new Error(String(reason || fallback))
|
|
@@ -29,14 +31,10 @@ export function relayCloseError (event, category, cause) {
|
|
|
29
31
|
return categorizeRelayError(error, category)
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
+
// Keep native diagnostics and attach only bounded timing advice. An absolute
|
|
35
|
+
// deadline survives delayed delivery through a launcher-owned relay bridge.
|
|
34
36
|
export function relayRejectionError (reason, extra, fallback) {
|
|
35
37
|
const error = categorizeRelayError(reason, 'relay', fallback)
|
|
36
|
-
|
|
37
|
-
if (error.message.startsWith('rate-limited:') && typeof seconds === 'number' && Number.isFinite(seconds) && seconds > 0) {
|
|
38
|
-
error.retryAfterMs = Math.min(seconds, 300) * 1000
|
|
39
|
-
error.retryAt = Date.now() + error.retryAfterMs
|
|
40
|
-
}
|
|
38
|
+
Object.assign(error, parseRelayRetryAdvice(error.message, extra))
|
|
41
39
|
return error
|
|
42
40
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Nostr transport extensions, in seconds. Timing advice is bounded and never
|
|
2
|
+
// supplies an error category, provenance or a routing/retry policy.
|
|
3
|
+
export function parseRelayRetryAdvice (reason, extra, { now = Date.now() } = {}) {
|
|
4
|
+
if (typeof reason !== 'string' || !reason.startsWith('rate-limited:') ||
|
|
5
|
+
!extra || typeof extra !== 'object' || Array.isArray(extra) || !Number.isFinite(now)) return null
|
|
6
|
+
|
|
7
|
+
const after = extra.retry_after
|
|
8
|
+
const retryAfterMs = typeof after === 'number' && Number.isFinite(after) && after > 0
|
|
9
|
+
? Math.min(after, 300) * 1000
|
|
10
|
+
: undefined
|
|
11
|
+
const at = extra.retry_at
|
|
12
|
+
const absolute = typeof at === 'number' && Number.isFinite(at) && at > 0 && Number.isFinite(at * 1000)
|
|
13
|
+
? Math.min(at * 1000, now + 300000)
|
|
14
|
+
: undefined
|
|
15
|
+
const retryAt = absolute ?? (retryAfterMs === undefined ? undefined : now + retryAfterMs)
|
|
16
|
+
if (retryAt === undefined) return null
|
|
17
|
+
return { ...(retryAfterMs === undefined ? {} : { retryAfterMs }), retryAt }
|
|
18
|
+
}
|
package/relay/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { freeRelays, nappRelays, seedRelays } from './constants/index.js'
|
|
2
2
|
export { isRetryableRelayFailure, isReplaceableRelayFailure } from './helpers/failure.js'
|
|
3
|
+
export { parseRelayRetryAdvice } from './helpers/retry-advice.js'
|
|
3
4
|
export { pickRelaysForPubkeys } from './helpers/routing.js'
|
|
4
5
|
export { RelayPool, relayPool } from './services/relay-pool.js'
|
|
5
6
|
export { getLatestEventsByPubkey } from './services/events.js'
|