@holochain/client 0.14.1 → 0.15.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/lib/api/admin/websocket.d.ts +1 -1
- package/lib/api/admin/websocket.js +1 -1
- package/lib/api/app/websocket.d.ts +1 -1
- package/lib/api/app/websocket.js +1 -1
- package/lib/api/app-agent/websocket.d.ts +1 -1
- package/lib/api/client.d.ts +10 -10
- package/lib/api/client.js +41 -19
- package/lib/api/common.d.ts +8 -0
- package/lib/api/common.js +21 -5
- package/package.json +1 -1
|
@@ -25,7 +25,7 @@ export declare class AdminWebsocket implements AdminApi {
|
|
|
25
25
|
* @param defaultTimeout - The default timeout for any request.
|
|
26
26
|
* @returns A promise for a new connected instance.
|
|
27
27
|
*/
|
|
28
|
-
static connect(url:
|
|
28
|
+
static connect(url: URL, defaultTimeout?: number): Promise<AdminWebsocket>;
|
|
29
29
|
_requester<ReqI, ReqO, ResI, ResO>(tag: string, transformer?: Transformer<ReqI, ReqO, ResI, ResO>): (req: ReqI, timeout?: number | undefined) => Promise<ResO>;
|
|
30
30
|
/**
|
|
31
31
|
* Send a request to open the given port for {@link AppWebsocket} connections.
|
|
@@ -34,7 +34,7 @@ export class AdminWebsocket {
|
|
|
34
34
|
// Check if we are in the launcher's environment, and if so, redirect the url to connect to
|
|
35
35
|
const env = getLauncherEnvironment();
|
|
36
36
|
if (env?.ADMIN_INTERFACE_PORT) {
|
|
37
|
-
url = `ws://127.0.0.1:${env.ADMIN_INTERFACE_PORT}
|
|
37
|
+
url = new URL(`ws://127.0.0.1:${env.ADMIN_INTERFACE_PORT}`);
|
|
38
38
|
}
|
|
39
39
|
const wsClient = await WsClient.connect(url);
|
|
40
40
|
return new AdminWebsocket(wsClient, defaultTimeout);
|
|
@@ -23,7 +23,7 @@ export declare class AppWebsocket extends Emittery implements AppApi {
|
|
|
23
23
|
* @param defaultTimeout - Timeout to default to for all operations.
|
|
24
24
|
* @returns A new instance of an AppWebsocket.
|
|
25
25
|
*/
|
|
26
|
-
static connect(url:
|
|
26
|
+
static connect(url: URL, defaultTimeout?: number): Promise<AppWebsocket>;
|
|
27
27
|
_requester<ReqI, ReqO, ResI, ResO>(tag: string, transformer?: Transformer<ReqI, ReqO, ResI, ResO>): (req: ReqI, timeout?: number | undefined) => Promise<ResO>;
|
|
28
28
|
/**
|
|
29
29
|
* Request the app's info, including all cell infos.
|
package/lib/api/app/websocket.js
CHANGED
|
@@ -35,7 +35,7 @@ export class AppWebsocket extends Emittery {
|
|
|
35
35
|
// Check if we are in the launcher's environment, and if so, redirect the url to connect to
|
|
36
36
|
const env = getLauncherEnvironment();
|
|
37
37
|
if (env?.APP_INTERFACE_PORT) {
|
|
38
|
-
url = `ws://127.0.0.1:${env.APP_INTERFACE_PORT}
|
|
38
|
+
url = new URL(`ws://127.0.0.1:${env.APP_INTERFACE_PORT}`);
|
|
39
39
|
}
|
|
40
40
|
const wsClient = await WsClient.connect(url);
|
|
41
41
|
const appWebsocket = new AppWebsocket(wsClient, defaultTimeout, env?.INSTALLED_APP_ID);
|
|
@@ -31,7 +31,7 @@ export declare class AppAgentWebsocket implements AppAgentClient {
|
|
|
31
31
|
* @param defaultTimeout - Timeout to default to for all operations.
|
|
32
32
|
* @returns A new instance of an AppAgentWebsocket.
|
|
33
33
|
*/
|
|
34
|
-
static connect(url:
|
|
34
|
+
static connect(url: URL, installed_app_id: InstalledAppId, defaultTimeout?: number): Promise<AppAgentWebsocket>;
|
|
35
35
|
/**
|
|
36
36
|
* Get a cell id by its role name or clone id.
|
|
37
37
|
*
|
package/lib/api/client.d.ts
CHANGED
|
@@ -1,30 +1,29 @@
|
|
|
1
1
|
/// <reference types="ws" />
|
|
2
|
-
import { decode } from "@msgpack/msgpack";
|
|
3
2
|
import Emittery from "emittery";
|
|
4
3
|
import IsoWebSocket from "isomorphic-ws";
|
|
5
4
|
/**
|
|
6
5
|
* A WebSocket client which can make requests and receive responses,
|
|
7
6
|
* as well as send and receive signals.
|
|
8
7
|
*
|
|
9
|
-
* Uses Holochain's
|
|
8
|
+
* Uses Holochain's WireMessage for communication.
|
|
10
9
|
*
|
|
11
10
|
* @public
|
|
12
11
|
*/
|
|
13
12
|
export declare class WsClient extends Emittery {
|
|
14
13
|
socket: IsoWebSocket;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
reject: (error: Error) => void;
|
|
18
|
-
}>;
|
|
14
|
+
url: URL | undefined;
|
|
15
|
+
private pendingRequests;
|
|
19
16
|
index: number;
|
|
20
|
-
|
|
17
|
+
private connectRetries;
|
|
18
|
+
constructor(socket: IsoWebSocket, url: URL);
|
|
19
|
+
private setupSocket;
|
|
21
20
|
/**
|
|
22
21
|
* Instance factory for creating WsClients.
|
|
23
22
|
*
|
|
24
|
-
* @param url - The
|
|
23
|
+
* @param url - The WebSocket URL to connect to.
|
|
25
24
|
* @returns An new instance of the WsClient.
|
|
26
25
|
*/
|
|
27
|
-
static connect(url:
|
|
26
|
+
static connect(url: URL): Promise<WsClient>;
|
|
28
27
|
/**
|
|
29
28
|
* Sends data as a signal.
|
|
30
29
|
*
|
|
@@ -37,7 +36,8 @@ export declare class WsClient extends Emittery {
|
|
|
37
36
|
* @param request - The request to send over the websocket.
|
|
38
37
|
* @returns
|
|
39
38
|
*/
|
|
40
|
-
request<
|
|
39
|
+
request<Response>(request: unknown): Promise<Response>;
|
|
40
|
+
private sendMessage;
|
|
41
41
|
private handleResponse;
|
|
42
42
|
/**
|
|
43
43
|
* Close the websocket connection.
|
package/lib/api/client.js
CHANGED
|
@@ -6,20 +6,27 @@ import { SignalType } from "./app/types.js";
|
|
|
6
6
|
* A WebSocket client which can make requests and receive responses,
|
|
7
7
|
* as well as send and receive signals.
|
|
8
8
|
*
|
|
9
|
-
* Uses Holochain's
|
|
9
|
+
* Uses Holochain's WireMessage for communication.
|
|
10
10
|
*
|
|
11
11
|
* @public
|
|
12
12
|
*/
|
|
13
13
|
export class WsClient extends Emittery {
|
|
14
14
|
socket;
|
|
15
|
+
url;
|
|
15
16
|
pendingRequests;
|
|
16
17
|
index;
|
|
17
|
-
|
|
18
|
+
connectRetries;
|
|
19
|
+
constructor(socket, url) {
|
|
18
20
|
super();
|
|
19
21
|
this.socket = socket;
|
|
22
|
+
this.url = url;
|
|
20
23
|
this.pendingRequests = {};
|
|
21
24
|
this.index = 0;
|
|
22
|
-
|
|
25
|
+
this.connectRetries = 0;
|
|
26
|
+
this.setupSocket();
|
|
27
|
+
}
|
|
28
|
+
setupSocket() {
|
|
29
|
+
this.socket.onmessage = async (serializedMessage) => {
|
|
23
30
|
// If data is not a buffer (nodejs), it will be a blob (browser)
|
|
24
31
|
let deserializedData;
|
|
25
32
|
if (globalThis.window &&
|
|
@@ -64,7 +71,7 @@ export class WsClient extends Emittery {
|
|
|
64
71
|
console.error(`Got unrecognized Websocket message type: ${message.type}`);
|
|
65
72
|
}
|
|
66
73
|
};
|
|
67
|
-
socket.onclose = (event) => {
|
|
74
|
+
this.socket.onclose = (event) => {
|
|
68
75
|
const pendingRequestIds = Object.keys(this.pendingRequests).map((id) => parseInt(id));
|
|
69
76
|
if (pendingRequestIds.length) {
|
|
70
77
|
pendingRequestIds.forEach((id) => {
|
|
@@ -78,20 +85,17 @@ export class WsClient extends Emittery {
|
|
|
78
85
|
/**
|
|
79
86
|
* Instance factory for creating WsClients.
|
|
80
87
|
*
|
|
81
|
-
* @param url - The
|
|
88
|
+
* @param url - The WebSocket URL to connect to.
|
|
82
89
|
* @returns An new instance of the WsClient.
|
|
83
90
|
*/
|
|
84
91
|
static connect(url) {
|
|
85
92
|
return new Promise((resolve, reject) => {
|
|
86
93
|
const socket = new IsoWebSocket(url);
|
|
87
|
-
// make sure that there are no uncaught connection
|
|
88
|
-
// errors because that causes nodejs thread to crash
|
|
89
|
-
// with uncaught exception
|
|
90
94
|
socket.onerror = () => {
|
|
91
95
|
reject(new Error(`could not connect to holochain conductor, please check that a conductor service is running and available at ${url}`));
|
|
92
96
|
};
|
|
93
97
|
socket.onopen = () => {
|
|
94
|
-
const client = new WsClient(socket);
|
|
98
|
+
const client = new WsClient(socket, url);
|
|
95
99
|
resolve(client);
|
|
96
100
|
};
|
|
97
101
|
});
|
|
@@ -114,25 +118,43 @@ export class WsClient extends Emittery {
|
|
|
114
118
|
* @param request - The request to send over the websocket.
|
|
115
119
|
* @returns
|
|
116
120
|
*/
|
|
117
|
-
request(request) {
|
|
121
|
+
async request(request) {
|
|
118
122
|
if (this.socket.readyState === this.socket.OPEN) {
|
|
119
|
-
const id = this.index;
|
|
120
|
-
const encodedMsg = encode({
|
|
121
|
-
id,
|
|
122
|
-
type: "request",
|
|
123
|
-
data: encode(request),
|
|
124
|
-
});
|
|
125
123
|
const promise = new Promise((resolve, reject) => {
|
|
126
|
-
this.
|
|
124
|
+
this.sendMessage(request, resolve, reject);
|
|
127
125
|
});
|
|
128
|
-
this.socket.send(encodedMsg);
|
|
129
|
-
this.index += 1;
|
|
130
126
|
return promise;
|
|
131
127
|
}
|
|
128
|
+
else if (this.url) {
|
|
129
|
+
const response = new Promise((resolve, reject) => {
|
|
130
|
+
// typescript forgets in this promise scope that this.url is not undefined
|
|
131
|
+
const socket = new IsoWebSocket(this.url);
|
|
132
|
+
this.socket = socket;
|
|
133
|
+
socket.onerror = () => {
|
|
134
|
+
reject(new Error(`could not connect to Holochain conductor, please check that a conductor service is running and available at ${this.url}`));
|
|
135
|
+
};
|
|
136
|
+
socket.onopen = () => {
|
|
137
|
+
this.sendMessage(request, resolve, reject);
|
|
138
|
+
};
|
|
139
|
+
this.setupSocket();
|
|
140
|
+
});
|
|
141
|
+
return response;
|
|
142
|
+
}
|
|
132
143
|
else {
|
|
133
144
|
return Promise.reject(new Error("Socket is not open"));
|
|
134
145
|
}
|
|
135
146
|
}
|
|
147
|
+
sendMessage(request, resolve, reject) {
|
|
148
|
+
const id = this.index;
|
|
149
|
+
const encodedMsg = encode({
|
|
150
|
+
id,
|
|
151
|
+
type: "request",
|
|
152
|
+
data: encode(request),
|
|
153
|
+
});
|
|
154
|
+
this.socket.send(encodedMsg);
|
|
155
|
+
this.pendingRequests[id] = { resolve, reject };
|
|
156
|
+
this.index += 1;
|
|
157
|
+
}
|
|
136
158
|
handleResponse(msg) {
|
|
137
159
|
const id = msg.id;
|
|
138
160
|
if (this.pendingRequests[id]) {
|
package/lib/api/common.d.ts
CHANGED
|
@@ -30,6 +30,14 @@ export type Tagged<T> = {
|
|
|
30
30
|
* @public
|
|
31
31
|
*/
|
|
32
32
|
export declare const requesterTransformer: <ReqI, ReqO, ResI, ResO>(requester: Requester<Tagged<ReqO>, Tagged<ResI>>, tag: string, transform?: Transformer<ReqI, ReqO, ResI, ResO>) => (req: ReqI, timeout?: number) => Promise<ResO>;
|
|
33
|
+
/**
|
|
34
|
+
* Error thrown when response from Holochain is an error.
|
|
35
|
+
*
|
|
36
|
+
* @public
|
|
37
|
+
*/
|
|
38
|
+
export declare class HolochainError extends Error {
|
|
39
|
+
constructor(name: string, message: string);
|
|
40
|
+
}
|
|
33
41
|
export declare const catchError: (res: any) => Promise<any>;
|
|
34
42
|
export declare const promiseTimeout: (promise: Promise<unknown>, tag: string, ms: number) => Promise<unknown>;
|
|
35
43
|
/**
|
package/lib/api/common.js
CHANGED
|
@@ -19,16 +19,32 @@ const identityTransformer = {
|
|
|
19
19
|
input: identity,
|
|
20
20
|
output: identity,
|
|
21
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* Error thrown when response from Holochain is an error.
|
|
24
|
+
*
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export class HolochainError extends Error {
|
|
28
|
+
constructor(name, message) {
|
|
29
|
+
super();
|
|
30
|
+
this.name = name;
|
|
31
|
+
this.message = message;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// this determines the error format of all error responses
|
|
22
35
|
export const catchError = (res) => {
|
|
23
|
-
|
|
36
|
+
if (res.type === ERROR_TYPE) {
|
|
37
|
+
const error = new HolochainError(res.data.type, res.data.data);
|
|
38
|
+
return Promise.reject(error);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
return Promise.resolve(res);
|
|
42
|
+
}
|
|
24
43
|
};
|
|
25
44
|
export const promiseTimeout = (promise, tag, ms) => {
|
|
26
45
|
let id;
|
|
27
46
|
const timeout = new Promise((_, reject) => {
|
|
28
|
-
id = setTimeout(() => {
|
|
29
|
-
clearTimeout(id);
|
|
30
|
-
reject(new Error(`Timed out in ${ms}ms: ${tag}`));
|
|
31
|
-
}, ms);
|
|
47
|
+
id = setTimeout(() => reject(new Error(`Timed out in ${ms}ms: ${tag}`)), ms);
|
|
32
48
|
});
|
|
33
49
|
return new Promise((res, rej) => {
|
|
34
50
|
Promise.race([promise, timeout])
|
package/package.json
CHANGED