@floatonnear/float-adapter 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/blocked-scan.d.ts +78 -0
- package/dist/blocked-scan.js +162 -8
- package/dist/env-file.d.ts +16 -0
- package/dist/env-file.js +16 -0
- package/dist/gate.d.ts +9 -5
- package/dist/gate.js +32 -5
- package/dist/handlers.d.ts +176 -3
- package/dist/handlers.js +262 -29
- package/dist/keyring.d.ts +81 -2
- package/dist/keyring.js +80 -10
- package/dist/map.d.ts +56 -11
- package/dist/map.js +43 -21
- package/dist/owner-plan.d.ts +112 -0
- package/dist/owner-plan.js +112 -0
- package/dist/server.d.ts +10 -1
- package/dist/server.js +461 -53
- package/dist/unavailable.d.ts +31 -0
- package/dist/unavailable.js +90 -0
- package/package.json +2 -2
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Could we not ASK the chain, or did the chain ANSWER?
|
|
3
|
+
*
|
|
4
|
+
* These are different facts and they must never share a code path. `/v1/resolve`
|
|
5
|
+
* ended both of its reads with `.catch(() => null)` / `.catch(() => false)`,
|
|
6
|
+
* so a transient RPC failure was reported as a statement about the user's
|
|
7
|
+
* account:
|
|
8
|
+
*
|
|
9
|
+
* vault_id_for threw -> "No legal vault id for that account. An implicit
|
|
10
|
+
* account (64 hex characters) cannot have one."
|
|
11
|
+
* accountExists threw -> "you do not have a vault yet"
|
|
12
|
+
*
|
|
13
|
+
* Both with HTTP 200, so the dashboard proxy — which deliberately does not
|
|
14
|
+
* cache a failure — cached them as answers for the life of the process.
|
|
15
|
+
*
|
|
16
|
+
* MEASURED, NOT IMAGINED. Six identical calls against a running adapter gave
|
|
17
|
+
* four correct answers and two nulls, because the adapter's own background
|
|
18
|
+
* refusal-follower saturates its RPC budget and competes with request
|
|
19
|
+
* handling. The user-visible result is the worst available one: somebody who
|
|
20
|
+
* owns a populated vault is shown the create-one empty state and invited to
|
|
21
|
+
* create a vault that already exists.
|
|
22
|
+
*
|
|
23
|
+
* MESSAGE MATCHING, AND WHY THAT IS ACCEPTABLE HERE. `viewFunction` throws a
|
|
24
|
+
* plain `Error` with a constructed string, and `fetch` throws `TypeError` with
|
|
25
|
+
* a platform string, so there is no status code or error class to branch on
|
|
26
|
+
* without changing both. The strings are pinned by tests, and the failure
|
|
27
|
+
* direction is chosen deliberately: an unrecognised error is treated as an
|
|
28
|
+
* ANSWER, so a new transport failure shows up as a visible wrong answer rather
|
|
29
|
+
* than as a silent infinite retry.
|
|
30
|
+
*/
|
|
31
|
+
/** Substrings that mean the request never got a verdict from the chain. */
|
|
32
|
+
const TRANSPORT = [
|
|
33
|
+
"fetch failed",
|
|
34
|
+
"enotfound",
|
|
35
|
+
"econnrefused",
|
|
36
|
+
"econnreset",
|
|
37
|
+
"etimedout",
|
|
38
|
+
"epipe",
|
|
39
|
+
"socket hang up",
|
|
40
|
+
"aborted",
|
|
41
|
+
"timeout",
|
|
42
|
+
"network",
|
|
43
|
+
"endpoint is deprecated",
|
|
44
|
+
/**
|
|
45
|
+
* THE ONE THAT ACTUALLY BIT US, twice, and the second time in this very
|
|
46
|
+
* file. fastnear answers a throttle with HTTP **200** and a JSON error
|
|
47
|
+
* body, so `r.ok` is true and nothing downstream looks like a transport
|
|
48
|
+
* failure. `accountExists` correctly refuses to guess and throws
|
|
49
|
+
*
|
|
50
|
+
* could not determine whether X exists: Rate limits exceeded. For higher
|
|
51
|
+
* rate limits get a subscription at https://fastnear.com
|
|
52
|
+
*
|
|
53
|
+
* which matched NONE of the patterns above — no status code, no "fetch
|
|
54
|
+
* failed" — so it was classified as an ANSWER and became `exists: false`.
|
|
55
|
+
* The live dashboard told the owner of a vault holding 42.25 USDC that they
|
|
56
|
+
* had none, and offered to create one.
|
|
57
|
+
*/
|
|
58
|
+
"rate limit",
|
|
59
|
+
"rate limits exceeded",
|
|
60
|
+
"too many requests",
|
|
61
|
+
"429",
|
|
62
|
+
/**
|
|
63
|
+
* The phrase `accountExists` uses when it cannot tell. It only throws when
|
|
64
|
+
* it genuinely does not know — a real absence returns false without
|
|
65
|
+
* throwing — so this wording is always uncertainty, never a verdict.
|
|
66
|
+
*/
|
|
67
|
+
"could not determine whether",
|
|
68
|
+
];
|
|
69
|
+
/**
|
|
70
|
+
* HTTP statuses that mean "ask again later" rather than "your request is
|
|
71
|
+
* wrong". 429 is the one that actually bit us; 5xx is the same category.
|
|
72
|
+
*
|
|
73
|
+
* 400/404 are NOT here on purpose: retrying resends the same bad request, and
|
|
74
|
+
* calling that "unavailable" would hide a real bug behind a retry loop.
|
|
75
|
+
*/
|
|
76
|
+
const RETRYABLE_HTTP = /returned http (408|425|429|5\d\d)\b/;
|
|
77
|
+
export function isUnavailable(e) {
|
|
78
|
+
const msg = e instanceof Error ? e.message : typeof e === "string" ? e : "";
|
|
79
|
+
if (!msg)
|
|
80
|
+
return false;
|
|
81
|
+
const m = msg.toLowerCase();
|
|
82
|
+
if (RETRYABLE_HTTP.test(m))
|
|
83
|
+
return true;
|
|
84
|
+
// A contract that PANICKED gave us an answer, even though it is an error.
|
|
85
|
+
// Checked before the transport list because a panic message can contain a
|
|
86
|
+
// word like "timeout" from the contract's own text.
|
|
87
|
+
if (m.includes("panicked") || m.includes("wasm execution failed"))
|
|
88
|
+
return false;
|
|
89
|
+
return TRANSPORT.some((t) => m.includes(t));
|
|
90
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@floatonnear/float-adapter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Serves the existing Float dashboard's /v1 API from NEAR vault views, so the Float UI runs unchanged against the NEAR hierarchical vault.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@floatonnear/mcp": "^0.
|
|
21
|
+
"@floatonnear/mcp": "^0.9.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^24.0.0",
|