@holochain/client 0.20.4-rc.0 → 0.20.5
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/lib/api/client.d.ts +15 -1
- package/lib/api/client.js +36 -5
- package/lib/api/zome-call-signing.d.ts +12 -1
- package/lib/api/zome-call-signing.js +4 -0
- package/lib/hdk/validation-receipts.d.ts +1 -1
- package/lib/tsdoc-metadata.json +1 -1
- package/lib/utils/holo-hash-map.d.ts +1 -1
- package/package.json +2 -2
package/lib/api/client.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export declare class WsClient extends Emittery {
|
|
|
23
23
|
private pendingRequests;
|
|
24
24
|
private index;
|
|
25
25
|
private authenticationToken;
|
|
26
|
+
private reconnectPromise;
|
|
26
27
|
constructor(socket: IsoWebSocket, url?: URL, options?: WsClientOptions);
|
|
27
28
|
/**
|
|
28
29
|
* Instance factory for creating WsClients.
|
|
@@ -53,8 +54,21 @@ export declare class WsClient extends Emittery {
|
|
|
53
54
|
/**
|
|
54
55
|
* Send requests to the connected websocket.
|
|
55
56
|
*
|
|
57
|
+
* If the underlying socket is closed when this method is called, the
|
|
58
|
+
* client transparently reconnects and re-authenticates using the cached
|
|
59
|
+
* token. Transient reconnect errors are surfaced as a `ConnectionError`
|
|
60
|
+
* and the cached token is retained, so a subsequent call can retry the
|
|
61
|
+
* reconnect.
|
|
62
|
+
*
|
|
63
|
+
* If the conductor rejects the cached token during the reconnect
|
|
64
|
+
* (signalled by an immediate close after the `authenticate` handshake),
|
|
65
|
+
* the cached token is cleared and the call rejects with an
|
|
66
|
+
* `InvalidTokenError`. The consumer must rebuild the `AppWebsocket`
|
|
67
|
+
* with a fresh token; further calls on this client will reject with
|
|
68
|
+
* `WebsocketClosedError`.
|
|
69
|
+
*
|
|
56
70
|
* @param request - The request to send over the websocket.
|
|
57
|
-
* @returns
|
|
71
|
+
* @returns The decoded response payload.
|
|
58
72
|
*/
|
|
59
73
|
request<Response>(request: unknown): Promise<Response>;
|
|
60
74
|
private exchange;
|
package/lib/api/client.js
CHANGED
|
@@ -19,6 +19,7 @@ export class WsClient extends Emittery {
|
|
|
19
19
|
pendingRequests;
|
|
20
20
|
index;
|
|
21
21
|
authenticationToken;
|
|
22
|
+
reconnectPromise;
|
|
22
23
|
constructor(socket, url, options) {
|
|
23
24
|
super();
|
|
24
25
|
this.registerMessageListener(socket);
|
|
@@ -100,8 +101,21 @@ export class WsClient extends Emittery {
|
|
|
100
101
|
/**
|
|
101
102
|
* Send requests to the connected websocket.
|
|
102
103
|
*
|
|
104
|
+
* If the underlying socket is closed when this method is called, the
|
|
105
|
+
* client transparently reconnects and re-authenticates using the cached
|
|
106
|
+
* token. Transient reconnect errors are surfaced as a `ConnectionError`
|
|
107
|
+
* and the cached token is retained, so a subsequent call can retry the
|
|
108
|
+
* reconnect.
|
|
109
|
+
*
|
|
110
|
+
* If the conductor rejects the cached token during the reconnect
|
|
111
|
+
* (signalled by an immediate close after the `authenticate` handshake),
|
|
112
|
+
* the cached token is cleared and the call rejects with an
|
|
113
|
+
* `InvalidTokenError`. The consumer must rebuild the `AppWebsocket`
|
|
114
|
+
* with a fresh token; further calls on this client will reject with
|
|
115
|
+
* `WebsocketClosedError`.
|
|
116
|
+
*
|
|
103
117
|
* @param request - The request to send over the websocket.
|
|
104
|
-
* @returns
|
|
118
|
+
* @returns The decoded response payload.
|
|
105
119
|
*/
|
|
106
120
|
async request(request) {
|
|
107
121
|
return this.exchange(request, this.sendMessage.bind(this));
|
|
@@ -114,7 +128,15 @@ export class WsClient extends Emittery {
|
|
|
114
128
|
return promise;
|
|
115
129
|
}
|
|
116
130
|
else if (this.url && this.authenticationToken) {
|
|
117
|
-
|
|
131
|
+
// Dedupe concurrent reconnect attempts. The first caller into this
|
|
132
|
+
// branch starts a single reconnect; further callers await the same
|
|
133
|
+
// promise so we never create multiple sockets in parallel.
|
|
134
|
+
if (!this.reconnectPromise) {
|
|
135
|
+
this.reconnectPromise = this.reconnectWebsocket(this.url, this.authenticationToken).finally(() => {
|
|
136
|
+
this.reconnectPromise = undefined;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
await this.reconnectPromise;
|
|
118
140
|
this.registerMessageListener(this.socket);
|
|
119
141
|
this.registerCloseListener(this.socket);
|
|
120
142
|
const promise = new Promise((resolve, reject) => sendHandler(request, resolve, reject));
|
|
@@ -204,19 +226,28 @@ export class WsClient extends Emittery {
|
|
|
204
226
|
async reconnectWebsocket(url, token) {
|
|
205
227
|
return new Promise((resolve, reject) => {
|
|
206
228
|
this.socket = new IsoWebSocket(url, this.options);
|
|
229
|
+
// Track whether the "open" event has fired. The invalidTokenCloseListener
|
|
230
|
+
// must only clear the token when the connection did open and the conductor
|
|
231
|
+
// then closed it quickly.
|
|
232
|
+
let openFired = false;
|
|
207
233
|
// This error event never occurs in tests. Could be removed?
|
|
208
234
|
this.socket.addEventListener("error", (errorEvent) => {
|
|
209
|
-
this.authenticationToken = undefined;
|
|
210
235
|
reject(new HolochainError("ConnectionError", `could not connect to Holochain Conductor API at ${url} - ${errorEvent.message}`));
|
|
211
236
|
}, { once: true });
|
|
212
237
|
const invalidTokenCloseListener = (closeEvent) => {
|
|
213
|
-
|
|
214
|
-
|
|
238
|
+
if (openFired) {
|
|
239
|
+
this.authenticationToken = undefined;
|
|
240
|
+
reject(new HolochainError("InvalidTokenError", `could not connect to ${this.url} due to an invalid app authentication token - close code ${closeEvent.code}`));
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
reject(new HolochainError("ConnectionError", `could not connect to Holochain Conductor API at ${url} - close code ${closeEvent.code}`));
|
|
244
|
+
}
|
|
215
245
|
};
|
|
216
246
|
this.socket.addEventListener("close", invalidTokenCloseListener, {
|
|
217
247
|
once: true,
|
|
218
248
|
});
|
|
219
249
|
this.socket.addEventListener("open", async () => {
|
|
250
|
+
openFired = true;
|
|
220
251
|
const encodedMsg = encode({
|
|
221
252
|
type: "authenticate",
|
|
222
253
|
data: encode({ token }),
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import { type KeyPair } from "libsodium-wrappers";
|
|
2
1
|
import type { CapSecret } from "../hdk/capabilities.js";
|
|
3
2
|
import type { AgentPubKey, CellId } from "../types.js";
|
|
4
3
|
/**
|
|
5
4
|
* @public
|
|
6
5
|
*/
|
|
7
6
|
export type Nonce256Bit = Uint8Array;
|
|
7
|
+
/**
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export declare const _kp: () => {
|
|
11
|
+
publicKey: Uint8Array;
|
|
12
|
+
privateKey: Uint8Array;
|
|
13
|
+
keyType: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export type KeyPair = ReturnType<typeof _kp>;
|
|
8
19
|
/**
|
|
9
20
|
* @public
|
|
10
21
|
*/
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import _sodium from "libsodium-wrappers";
|
|
2
2
|
import { encodeHashToBase64 } from "../utils/base64.js";
|
|
3
|
+
/**
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export const _kp = () => _sodium.crypto_sign_keypair();
|
|
3
7
|
const signingCredentials = new Map();
|
|
4
8
|
/**
|
|
5
9
|
* Get credentials for signing zome calls.
|
package/lib/tsdoc-metadata.json
CHANGED
|
@@ -122,7 +122,7 @@ export declare class HoloHashMap<K extends HoloHash, V> implements Map<K, V> {
|
|
|
122
122
|
* @param thisArg - Optional value to use as 'this' when executing the callback
|
|
123
123
|
*/
|
|
124
124
|
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
|
|
125
|
-
[Symbol.iterator]():
|
|
125
|
+
[Symbol.iterator](): MapIterator<[K, V]>;
|
|
126
126
|
get [Symbol.toStringTag](): string;
|
|
127
127
|
/**
|
|
128
128
|
* The number of entries in the map.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holochain/client",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.5",
|
|
4
4
|
"description": "A JavaScript client for the Holochain Conductor API",
|
|
5
5
|
"author": "Holochain Foundation <info@holochain.org> (https://holochain.org)",
|
|
6
6
|
"license": "CAL-1.0",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"isomorphic-ws": "^5.0.0",
|
|
49
49
|
"js-base64": "^3.7.8",
|
|
50
50
|
"js-sha512": "^0.9.0",
|
|
51
|
-
"libsodium-wrappers": "^0.8",
|
|
51
|
+
"libsodium-wrappers": "^0.8.4",
|
|
52
52
|
"lodash-es": "^4.17.21",
|
|
53
53
|
"ws": "^8.18.3"
|
|
54
54
|
},
|