@calimero-network/mero-js 13.0.0 → 13.2.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/account/index.d.ts +43 -0
- package/dist/account/index.js +139 -0
- package/dist/ephemeral/codec.d.ts +4 -0
- package/dist/ephemeral/codec.js +12 -0
- package/dist/ephemeral/index.d.ts +51 -0
- package/dist/ephemeral/index.js +81 -0
- package/dist/ephemeral/types.d.ts +22 -0
- package/dist/ephemeral/types.js +1 -0
- package/dist/events/sse.js +23 -2
- package/dist/index.browser.mjs +2 -2
- package/dist/index.browser.mjs.map +4 -4
- package/dist/index.cjs +216 -25
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/index.mjs +216 -25
- package/dist/index.mjs.map +4 -4
- package/dist/mero-js.d.ts +9 -0
- package/dist/mero-js.js +16 -0
- package/dist/rpc/index.d.ts +8 -0
- package/dist/rpc/index.js +28 -20
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -25,6 +25,7 @@ __export(index_exports, {
|
|
|
25
25
|
CAPABILITIES: () => CAPABILITIES,
|
|
26
26
|
CloudClient: () => CloudClient,
|
|
27
27
|
DEFAULT_LOCAL_NODE_PORTS: () => DEFAULT_LOCAL_NODE_PORTS,
|
|
28
|
+
EphemeralClient: () => EphemeralClient,
|
|
28
29
|
HTTPError: () => HTTPError,
|
|
29
30
|
LocalStorageTokenStore: () => LocalStorageTokenStore,
|
|
30
31
|
MemoryTokenStore: () => MemoryTokenStore,
|
|
@@ -54,10 +55,14 @@ __export(index_exports, {
|
|
|
54
55
|
createUniversalHttpClient: () => createUniversalHttpClient,
|
|
55
56
|
discoverLocalNodes: () => discoverLocalNodes,
|
|
56
57
|
hasCap: () => hasCap,
|
|
58
|
+
jsonCodec: () => jsonCodec,
|
|
57
59
|
localNodeUrl: () => localNodeUrl,
|
|
58
60
|
nodeEndpoint: () => nodeEndpoint,
|
|
59
61
|
parseAuthCallback: () => parseAuthCallback,
|
|
60
62
|
probeNodeHealth: () => probeNodeHealth,
|
|
63
|
+
sameAccount: () => sameAccount,
|
|
64
|
+
toAccountBase58: () => toAccountBase58,
|
|
65
|
+
toAccountHex: () => toAccountHex,
|
|
61
66
|
withCap: () => withCap,
|
|
62
67
|
withRetry: () => withRetry,
|
|
63
68
|
withoutCap: () => withoutCap
|
|
@@ -1538,35 +1543,33 @@ var RpcError = class extends Error {
|
|
|
1538
1543
|
this.type = type;
|
|
1539
1544
|
}
|
|
1540
1545
|
};
|
|
1546
|
+
async function jsonRpcCall(httpClient, method, params) {
|
|
1547
|
+
const response = await httpClient.post("/jsonrpc", {
|
|
1548
|
+
jsonrpc: "2.0",
|
|
1549
|
+
id: 1,
|
|
1550
|
+
method,
|
|
1551
|
+
params
|
|
1552
|
+
});
|
|
1553
|
+
if (response.error) {
|
|
1554
|
+
const err = response.error;
|
|
1555
|
+
throw new RpcError(err.code ?? -1, err.message ?? err.type ?? "RPC error", err.data, err.type);
|
|
1556
|
+
}
|
|
1557
|
+
return response.result;
|
|
1558
|
+
}
|
|
1541
1559
|
var RpcClient = class {
|
|
1542
1560
|
constructor(opts) {
|
|
1543
1561
|
this.httpClient = opts.httpClient;
|
|
1544
1562
|
}
|
|
1545
1563
|
async execute(params) {
|
|
1546
|
-
const
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
argsJson: params.argsJson ?? {}
|
|
1554
|
-
}
|
|
1555
|
-
};
|
|
1556
|
-
const response = await this.httpClient.post(
|
|
1557
|
-
"/jsonrpc",
|
|
1558
|
-
body
|
|
1559
|
-
);
|
|
1560
|
-
if (response.error) {
|
|
1561
|
-
const err = response.error;
|
|
1562
|
-
const code = err.code ?? -1;
|
|
1563
|
-
const message = err.message ?? err.type ?? "RPC error";
|
|
1564
|
-
throw new RpcError(code, message, err.data, err.type);
|
|
1565
|
-
}
|
|
1566
|
-
if (response.result && "output" in response.result) {
|
|
1567
|
-
return response.result.output;
|
|
1564
|
+
const result = await jsonRpcCall(this.httpClient, "execute", {
|
|
1565
|
+
contextId: params.contextId,
|
|
1566
|
+
method: params.method,
|
|
1567
|
+
argsJson: params.argsJson ?? {}
|
|
1568
|
+
});
|
|
1569
|
+
if (result && "output" in result) {
|
|
1570
|
+
return result.output;
|
|
1568
1571
|
}
|
|
1569
|
-
return
|
|
1572
|
+
return result;
|
|
1570
1573
|
}
|
|
1571
1574
|
/**
|
|
1572
1575
|
* One-tap owner-driven convert: re-signs the caller's identity-gated entries
|
|
@@ -1595,6 +1598,7 @@ function isGroupMigrationEvent(event) {
|
|
|
1595
1598
|
}
|
|
1596
1599
|
|
|
1597
1600
|
// src/events/sse.ts
|
|
1601
|
+
var TERMINAL_AUTH_ERRORS2 = /* @__PURE__ */ new Set(["token_reuse", "token_revoked"]);
|
|
1598
1602
|
var SseClient = class {
|
|
1599
1603
|
constructor(opts) {
|
|
1600
1604
|
this.sessionId = null;
|
|
@@ -1672,7 +1676,8 @@ var SseClient = class {
|
|
|
1672
1676
|
this.abortController = new AbortController();
|
|
1673
1677
|
try {
|
|
1674
1678
|
const token = await this.getAuthToken();
|
|
1675
|
-
const
|
|
1679
|
+
const url = `${this.baseUrl}/sse`;
|
|
1680
|
+
const response = await fetch(url, {
|
|
1676
1681
|
headers: {
|
|
1677
1682
|
"Authorization": `Bearer ${token}`,
|
|
1678
1683
|
"Accept": "text/event-stream"
|
|
@@ -1680,7 +1685,25 @@ var SseClient = class {
|
|
|
1680
1685
|
signal: this.abortController.signal
|
|
1681
1686
|
});
|
|
1682
1687
|
if (!response.ok) {
|
|
1683
|
-
|
|
1688
|
+
const authError = response.headers.get("x-auth-error");
|
|
1689
|
+
const bodyText = await response.text().catch(() => void 0);
|
|
1690
|
+
if (response.status === 401 && authError && TERMINAL_AUTH_ERRORS2.has(authError)) {
|
|
1691
|
+
throw new AuthRevokedError(
|
|
1692
|
+
authError,
|
|
1693
|
+
response.status,
|
|
1694
|
+
response.statusText,
|
|
1695
|
+
url,
|
|
1696
|
+
response.headers,
|
|
1697
|
+
bodyText
|
|
1698
|
+
);
|
|
1699
|
+
}
|
|
1700
|
+
throw new HTTPError(
|
|
1701
|
+
response.status,
|
|
1702
|
+
response.statusText,
|
|
1703
|
+
url,
|
|
1704
|
+
response.headers,
|
|
1705
|
+
bodyText
|
|
1706
|
+
);
|
|
1684
1707
|
}
|
|
1685
1708
|
if (!response.body) {
|
|
1686
1709
|
throw new Error("SSE response has no body");
|
|
@@ -2057,6 +2080,72 @@ var _WsClient = class _WsClient {
|
|
|
2057
2080
|
_WsClient.MAX_BACKOFF_MS = 3e4;
|
|
2058
2081
|
var WsClient = _WsClient;
|
|
2059
2082
|
|
|
2083
|
+
// src/ephemeral/codec.ts
|
|
2084
|
+
function jsonCodec() {
|
|
2085
|
+
return {
|
|
2086
|
+
encode(value) {
|
|
2087
|
+
return Array.from(new TextEncoder().encode(JSON.stringify(value)));
|
|
2088
|
+
},
|
|
2089
|
+
decode(bytes) {
|
|
2090
|
+
return JSON.parse(new TextDecoder().decode(new Uint8Array(bytes)));
|
|
2091
|
+
}
|
|
2092
|
+
};
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
// src/ephemeral/index.ts
|
|
2096
|
+
var EphemeralClient = class {
|
|
2097
|
+
constructor(opts) {
|
|
2098
|
+
this.httpClient = opts.httpClient;
|
|
2099
|
+
this.sse = opts.sse;
|
|
2100
|
+
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Publish your own presence slice, replacing it wholesale.
|
|
2103
|
+
*
|
|
2104
|
+
* Rejects with an `RpcError` (not a bare `Error`), so a typed failure such as
|
|
2105
|
+
* an oversized slice keeps its `type` and `data` — e.g. `SliceTooLarge` with
|
|
2106
|
+
* the offending size — and is `instanceof RpcError` like every other RPC in
|
|
2107
|
+
* this SDK.
|
|
2108
|
+
*/
|
|
2109
|
+
async set(contextId, state, codec = jsonCodec()) {
|
|
2110
|
+
await jsonRpcCall(this.httpClient, "set_ephemeral", {
|
|
2111
|
+
contextId,
|
|
2112
|
+
state: codec.encode(state)
|
|
2113
|
+
});
|
|
2114
|
+
}
|
|
2115
|
+
/**
|
|
2116
|
+
* Observe presence changes for a context.
|
|
2117
|
+
*
|
|
2118
|
+
* This adds NO transport — it is a typed filter over the existing SSE event
|
|
2119
|
+
* stream, which already carries `{ contextId, type, data }`. On subscribing,
|
|
2120
|
+
* the node replays that context's current presence to this connection as
|
|
2121
|
+
* ordinary `Ephemeral` events before any live deltas; a replayed entry
|
|
2122
|
+
* carries `ageMs`, a live delta does not (never synthesized as `0` — absent
|
|
2123
|
+
* and zero mean different things). Returns an unsubscribe function.
|
|
2124
|
+
*/
|
|
2125
|
+
subscribe(contextId, handler, codec = jsonCodec()) {
|
|
2126
|
+
const listener = (event) => {
|
|
2127
|
+
const e = event;
|
|
2128
|
+
if (e.type !== "Ephemeral" || e.contextId !== contextId) return;
|
|
2129
|
+
const data = e.data;
|
|
2130
|
+
if (!data?.author) return;
|
|
2131
|
+
const removed = Boolean(data.removed);
|
|
2132
|
+
const entry = {
|
|
2133
|
+
author: data.author,
|
|
2134
|
+
state: removed || data.state === void 0 ? void 0 : codec.decode(data.state),
|
|
2135
|
+
removed
|
|
2136
|
+
};
|
|
2137
|
+
if (data.ageMs !== void 0) entry.ageMs = data.ageMs;
|
|
2138
|
+
handler(entry);
|
|
2139
|
+
};
|
|
2140
|
+
this.sse.on("event", listener);
|
|
2141
|
+
void this.sse.connect().catch(() => void 0);
|
|
2142
|
+
void this.sse.subscribe([contextId]).catch(() => void 0);
|
|
2143
|
+
return () => {
|
|
2144
|
+
this.sse.off("event", listener);
|
|
2145
|
+
};
|
|
2146
|
+
}
|
|
2147
|
+
};
|
|
2148
|
+
|
|
2060
2149
|
// src/mero-js.ts
|
|
2061
2150
|
var REFRESH_LOCK_NAME = "mero-js:token-refresh";
|
|
2062
2151
|
function getLockManager() {
|
|
@@ -2175,6 +2264,21 @@ var MeroJs = class {
|
|
|
2175
2264
|
}
|
|
2176
2265
|
return this.sseClient;
|
|
2177
2266
|
}
|
|
2267
|
+
/**
|
|
2268
|
+
* Get the ephemeral-presence client (lazy initialized).
|
|
2269
|
+
*
|
|
2270
|
+
* Shares this instance's SSE client, so `subscribe` reuses the one event
|
|
2271
|
+
* stream rather than opening a second connection.
|
|
2272
|
+
*/
|
|
2273
|
+
get ephemeral() {
|
|
2274
|
+
if (!this.ephemeralClient) {
|
|
2275
|
+
this.ephemeralClient = new EphemeralClient({
|
|
2276
|
+
httpClient: this.httpClient,
|
|
2277
|
+
sse: this.events
|
|
2278
|
+
});
|
|
2279
|
+
}
|
|
2280
|
+
return this.ephemeralClient;
|
|
2281
|
+
}
|
|
2178
2282
|
/**
|
|
2179
2283
|
* Get the WebSocket event client (lazy initialized).
|
|
2180
2284
|
* @experimental Use `events` (SSE) for production. WsClient is experimental.
|
|
@@ -2365,6 +2469,93 @@ function createMeroJs(config) {
|
|
|
2365
2469
|
return new MeroJs(config);
|
|
2366
2470
|
}
|
|
2367
2471
|
|
|
2472
|
+
// src/account/index.ts
|
|
2473
|
+
var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
2474
|
+
var HEX_ACCOUNT = /^[0-9a-f]{64}$/i;
|
|
2475
|
+
function encodeBase58(bytes) {
|
|
2476
|
+
if (bytes.length === 0) return "";
|
|
2477
|
+
const digits = [0];
|
|
2478
|
+
for (const byte of bytes) {
|
|
2479
|
+
let carry = byte;
|
|
2480
|
+
for (let i = 0; i < digits.length; i++) {
|
|
2481
|
+
carry += digits[i] << 8;
|
|
2482
|
+
digits[i] = carry % 58;
|
|
2483
|
+
carry = carry / 58 | 0;
|
|
2484
|
+
}
|
|
2485
|
+
while (carry > 0) {
|
|
2486
|
+
digits.push(carry % 58);
|
|
2487
|
+
carry = carry / 58 | 0;
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
let out = "";
|
|
2491
|
+
for (const byte of bytes) {
|
|
2492
|
+
if (byte !== 0) break;
|
|
2493
|
+
out += BASE58_ALPHABET[0];
|
|
2494
|
+
}
|
|
2495
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
2496
|
+
out += BASE58_ALPHABET[digits[i]];
|
|
2497
|
+
}
|
|
2498
|
+
return out;
|
|
2499
|
+
}
|
|
2500
|
+
function decodeBase58(value) {
|
|
2501
|
+
if (value.length === 0) return null;
|
|
2502
|
+
const bytes = [0];
|
|
2503
|
+
for (const char of value) {
|
|
2504
|
+
const index = BASE58_ALPHABET.indexOf(char);
|
|
2505
|
+
if (index < 0) return null;
|
|
2506
|
+
let carry = index;
|
|
2507
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
2508
|
+
carry += bytes[i] * 58;
|
|
2509
|
+
bytes[i] = carry & 255;
|
|
2510
|
+
carry >>= 8;
|
|
2511
|
+
}
|
|
2512
|
+
while (carry > 0) {
|
|
2513
|
+
bytes.push(carry & 255);
|
|
2514
|
+
carry >>= 8;
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
let leadingZeros = 0;
|
|
2518
|
+
for (const char of value) {
|
|
2519
|
+
if (char !== BASE58_ALPHABET[0]) break;
|
|
2520
|
+
leadingZeros++;
|
|
2521
|
+
}
|
|
2522
|
+
return Uint8Array.from([
|
|
2523
|
+
...new Array(leadingZeros).fill(0),
|
|
2524
|
+
...bytes.reverse()
|
|
2525
|
+
]);
|
|
2526
|
+
}
|
|
2527
|
+
function toHex(bytes) {
|
|
2528
|
+
let out = "";
|
|
2529
|
+
for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
|
|
2530
|
+
return out;
|
|
2531
|
+
}
|
|
2532
|
+
function fromHex(hex) {
|
|
2533
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
2534
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
2535
|
+
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
2536
|
+
}
|
|
2537
|
+
return bytes;
|
|
2538
|
+
}
|
|
2539
|
+
function toAccountHex(id) {
|
|
2540
|
+
const trimmed = (id ?? "").trim();
|
|
2541
|
+
if (!trimmed) return "";
|
|
2542
|
+
if (HEX_ACCOUNT.test(trimmed)) return trimmed.toLowerCase();
|
|
2543
|
+
const decoded = decodeBase58(trimmed);
|
|
2544
|
+
if (!decoded || decoded.length !== 32) return trimmed;
|
|
2545
|
+
return toHex(decoded);
|
|
2546
|
+
}
|
|
2547
|
+
function toAccountBase58(id) {
|
|
2548
|
+
const trimmed = (id ?? "").trim();
|
|
2549
|
+
if (!trimmed) return "";
|
|
2550
|
+
if (!HEX_ACCOUNT.test(trimmed)) return trimmed;
|
|
2551
|
+
return encodeBase58(fromHex(trimmed));
|
|
2552
|
+
}
|
|
2553
|
+
function sameAccount(a, b) {
|
|
2554
|
+
const left = toAccountHex(a);
|
|
2555
|
+
const right = toAccountHex(b);
|
|
2556
|
+
return HEX_ACCOUNT.test(left) && left === right;
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2368
2559
|
// src/token-store/index.ts
|
|
2369
2560
|
var MemoryTokenStore = class {
|
|
2370
2561
|
constructor() {
|