@hashgrid/sdk 0.2.8 → 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/README.md +0 -3
- package/dist/client.d.ts +2 -1
- package/dist/client.js +51 -2
- package/dist/resources.d.ts +2 -2
- package/dist/resources.js +13 -24
- package/package.json +1 -1
- package/src/client.ts +70 -2
- package/src/resources.ts +17 -26
package/README.md
CHANGED
|
@@ -50,9 +50,6 @@ The SDK provides the following resources:
|
|
|
50
50
|
- **`User`** - User data model
|
|
51
51
|
- **`Quota`** - Quota data model
|
|
52
52
|
- **`Message`** - Message for recv/send operations
|
|
53
|
-
- Constructor: `new Message(peer_id, round, message = "", score = null)`
|
|
54
|
-
- **`Status`** - Status response from send operations
|
|
55
|
-
- Properties: `peer_id`, `round`, `success`
|
|
56
53
|
|
|
57
54
|
## Examples
|
|
58
55
|
|
package/dist/client.d.ts
CHANGED
|
@@ -6,7 +6,8 @@ export declare class Hashgrid {
|
|
|
6
6
|
private timeout;
|
|
7
7
|
constructor(api_key?: string, base_url?: string, timeout?: number);
|
|
8
8
|
private _getHeaders;
|
|
9
|
-
|
|
9
|
+
request(method: string, endpoint: string, params?: Record<string, any>, json_data?: any): Promise<any>;
|
|
10
10
|
_handleResponse(response: Response): Promise<any>;
|
|
11
|
+
stream(method: string, endpoint: string, params?: Record<string, any>, json_data?: any): AsyncGenerator<string>;
|
|
11
12
|
static connect(api_key?: string, base_url?: string, timeout?: number): Promise<Grid>;
|
|
12
13
|
}
|
package/dist/client.js
CHANGED
|
@@ -20,7 +20,7 @@ class Hashgrid {
|
|
|
20
20
|
}
|
|
21
21
|
return headers;
|
|
22
22
|
}
|
|
23
|
-
async
|
|
23
|
+
async request(method, endpoint, params, json_data) {
|
|
24
24
|
let url;
|
|
25
25
|
if (endpoint.startsWith("http://") || endpoint.startsWith("https://")) {
|
|
26
26
|
url = endpoint;
|
|
@@ -104,9 +104,58 @@ class Hashgrid {
|
|
|
104
104
|
throw new exceptions_1.HashgridAPIError(`Response handling failed: ${error}`);
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
+
async *stream(method, endpoint, params, json_data) {
|
|
108
|
+
const base = this.base_url.endsWith("/") ? this.base_url.slice(0, -1) : this.base_url;
|
|
109
|
+
const path = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
|
|
110
|
+
let url = `${base}${path}`;
|
|
111
|
+
if (params) {
|
|
112
|
+
const searchParams = new URLSearchParams();
|
|
113
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
114
|
+
searchParams.append(key, String(value));
|
|
115
|
+
});
|
|
116
|
+
url += `?${searchParams.toString()}`;
|
|
117
|
+
}
|
|
118
|
+
const headers = this._getHeaders();
|
|
119
|
+
headers["Accept"] = "text/event-stream";
|
|
120
|
+
const options = {
|
|
121
|
+
method,
|
|
122
|
+
headers,
|
|
123
|
+
};
|
|
124
|
+
if (json_data !== undefined) {
|
|
125
|
+
options.body = JSON.stringify(json_data);
|
|
126
|
+
}
|
|
127
|
+
const response = await fetch(url, options);
|
|
128
|
+
if (!response.ok) {
|
|
129
|
+
throw new exceptions_1.HashgridAPIError(`SSE connection failed: ${response.status}`);
|
|
130
|
+
}
|
|
131
|
+
const reader = response.body?.getReader();
|
|
132
|
+
const decoder = new TextDecoder();
|
|
133
|
+
let buffer = "";
|
|
134
|
+
if (!reader) {
|
|
135
|
+
throw new exceptions_1.HashgridAPIError("Response body is not readable");
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
while (true) {
|
|
139
|
+
const { done, value } = await reader.read();
|
|
140
|
+
if (done)
|
|
141
|
+
break;
|
|
142
|
+
buffer += decoder.decode(value, { stream: true });
|
|
143
|
+
const lines = buffer.split("\n\n");
|
|
144
|
+
buffer = lines.pop() || "";
|
|
145
|
+
for (const line of lines) {
|
|
146
|
+
if (line.startsWith("data: ")) {
|
|
147
|
+
yield line.slice(6).trim();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
reader.releaseLock();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
107
156
|
static async connect(api_key, base_url = "https://dna.hashgrid.ai", timeout = 30000) {
|
|
108
157
|
const client = new Hashgrid(api_key, base_url, timeout);
|
|
109
|
-
const data = await client.
|
|
158
|
+
const data = await client.request("GET", "/api/v1");
|
|
110
159
|
const grid = new resources_1.Grid(data.name, data.tick, client);
|
|
111
160
|
return grid;
|
|
112
161
|
}
|
package/dist/resources.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export declare class Grid {
|
|
|
40
40
|
tick: number;
|
|
41
41
|
private _client;
|
|
42
42
|
constructor(name: string, tick: number, client: Hashgrid);
|
|
43
|
-
listen(
|
|
43
|
+
listen(): AsyncGenerator<number>;
|
|
44
44
|
nodes(): AsyncGenerator<Node>;
|
|
45
45
|
create_node(name: string, message?: string, capacity?: number): Promise<Node>;
|
|
46
46
|
}
|
|
@@ -53,7 +53,7 @@ export declare class Node {
|
|
|
53
53
|
private _client;
|
|
54
54
|
constructor(node_id: string, owner_id: string, name: string, message: string, capacity: number, client: Hashgrid);
|
|
55
55
|
recv(): Promise<Message[]>;
|
|
56
|
-
send(replies: Message[]): Promise<
|
|
56
|
+
send(replies: Message[]): Promise<Message[]>;
|
|
57
57
|
update(name?: string, message?: string, capacity?: number): Promise<Node>;
|
|
58
58
|
delete(): Promise<void>;
|
|
59
59
|
}
|
package/dist/resources.js
CHANGED
|
@@ -53,35 +53,24 @@ class Grid {
|
|
|
53
53
|
this.tick = tick;
|
|
54
54
|
this._client = client;
|
|
55
55
|
}
|
|
56
|
-
async *listen(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this.tick = data.tick;
|
|
63
|
-
const current_tick = this.tick;
|
|
64
|
-
if (current_tick !== last_tick) {
|
|
65
|
-
yield current_tick;
|
|
66
|
-
last_tick = current_tick;
|
|
67
|
-
}
|
|
68
|
-
await new Promise((resolve) => setTimeout(resolve, poll_interval));
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
console.warn(`Error while listening for ticks: ${error}`);
|
|
72
|
-
await new Promise((resolve) => setTimeout(resolve, poll_interval * 2));
|
|
56
|
+
async *listen() {
|
|
57
|
+
for await (const data of this._client.stream("GET", "/api/v1/listen")) {
|
|
58
|
+
const tick = parseInt(data, 10);
|
|
59
|
+
if (!isNaN(tick) && tick !== this.tick) {
|
|
60
|
+
this.tick = tick;
|
|
61
|
+
yield tick;
|
|
73
62
|
}
|
|
74
63
|
}
|
|
75
64
|
}
|
|
76
65
|
async *nodes() {
|
|
77
|
-
const data = await this._client.
|
|
66
|
+
const data = await this._client.request("GET", "/api/v1/node");
|
|
78
67
|
for (const item of data) {
|
|
79
68
|
yield new Node(item.node_id, item.owner_id, item.name, item.message, item.capacity, this._client);
|
|
80
69
|
}
|
|
81
70
|
}
|
|
82
71
|
async create_node(name, message = "", capacity = 100) {
|
|
83
72
|
const json_data = { name, message, capacity };
|
|
84
|
-
const data = await this._client.
|
|
73
|
+
const data = await this._client.request("POST", "/api/v1/node", undefined, json_data);
|
|
85
74
|
return new Node(data.node_id, data.owner_id, data.name, data.message, data.capacity, this._client);
|
|
86
75
|
}
|
|
87
76
|
}
|
|
@@ -96,7 +85,7 @@ class Node {
|
|
|
96
85
|
this._client = client;
|
|
97
86
|
}
|
|
98
87
|
async recv() {
|
|
99
|
-
const data = await this._client.
|
|
88
|
+
const data = await this._client.request("GET", `/api/v1/node/${this.node_id}/recv`);
|
|
100
89
|
return data.map((item) => new Message(item.peer_id, item.round, item.message, item.score ?? null));
|
|
101
90
|
}
|
|
102
91
|
async send(replies) {
|
|
@@ -111,8 +100,8 @@ class Node {
|
|
|
111
100
|
}
|
|
112
101
|
return obj;
|
|
113
102
|
});
|
|
114
|
-
const data = await this._client.
|
|
115
|
-
return data.map((item) => new
|
|
103
|
+
const data = await this._client.request("POST", `/api/v1/node/${this.node_id}/send`, undefined, json_data);
|
|
104
|
+
return data.map((item) => new Message(item.peer_id, item.round, item.message, item.score ?? null));
|
|
116
105
|
}
|
|
117
106
|
async update(name, message, capacity) {
|
|
118
107
|
const json_data = {};
|
|
@@ -125,7 +114,7 @@ class Node {
|
|
|
125
114
|
if (Object.keys(json_data).length === 0) {
|
|
126
115
|
return this;
|
|
127
116
|
}
|
|
128
|
-
const data = await this._client.
|
|
117
|
+
const data = await this._client.request("PUT", `/api/v1/node/${this.node_id}`, undefined, json_data);
|
|
129
118
|
// Update local attributes
|
|
130
119
|
if (data.name !== undefined)
|
|
131
120
|
this.name = data.name;
|
|
@@ -136,7 +125,7 @@ class Node {
|
|
|
136
125
|
return this;
|
|
137
126
|
}
|
|
138
127
|
async delete() {
|
|
139
|
-
await this._client.
|
|
128
|
+
await this._client.request("DELETE", `/api/v1/node/${this.node_id}`);
|
|
140
129
|
}
|
|
141
130
|
}
|
|
142
131
|
exports.Node = Node;
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -34,7 +34,7 @@ export class Hashgrid {
|
|
|
34
34
|
return headers;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
async
|
|
37
|
+
async request(
|
|
38
38
|
method: string,
|
|
39
39
|
endpoint: string,
|
|
40
40
|
params?: Record<string, any>,
|
|
@@ -148,13 +148,81 @@ export class Hashgrid {
|
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
async *stream(
|
|
152
|
+
method: string,
|
|
153
|
+
endpoint: string,
|
|
154
|
+
params?: Record<string, any>,
|
|
155
|
+
json_data?: any
|
|
156
|
+
): AsyncGenerator<string> {
|
|
157
|
+
const base = this.base_url.endsWith("/") ? this.base_url.slice(0, -1) : this.base_url;
|
|
158
|
+
const path = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
|
|
159
|
+
let url = `${base}${path}`;
|
|
160
|
+
|
|
161
|
+
if (params) {
|
|
162
|
+
const searchParams = new URLSearchParams();
|
|
163
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
164
|
+
searchParams.append(key, String(value));
|
|
165
|
+
});
|
|
166
|
+
url += `?${searchParams.toString()}`;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const headers = this._getHeaders();
|
|
170
|
+
headers["Accept"] = "text/event-stream";
|
|
171
|
+
|
|
172
|
+
const options: {
|
|
173
|
+
method: string;
|
|
174
|
+
headers: Record<string, string>;
|
|
175
|
+
body?: string;
|
|
176
|
+
} = {
|
|
177
|
+
method,
|
|
178
|
+
headers,
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
if (json_data !== undefined) {
|
|
182
|
+
options.body = JSON.stringify(json_data);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const response = await fetch(url, options);
|
|
186
|
+
|
|
187
|
+
if (!response.ok) {
|
|
188
|
+
throw new HashgridAPIError(`SSE connection failed: ${response.status}`);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const reader = response.body?.getReader();
|
|
192
|
+
const decoder = new TextDecoder();
|
|
193
|
+
let buffer = "";
|
|
194
|
+
|
|
195
|
+
if (!reader) {
|
|
196
|
+
throw new HashgridAPIError("Response body is not readable");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
while (true) {
|
|
201
|
+
const { done, value } = await reader.read();
|
|
202
|
+
if (done) break;
|
|
203
|
+
|
|
204
|
+
buffer += decoder.decode(value, { stream: true });
|
|
205
|
+
const lines = buffer.split("\n\n");
|
|
206
|
+
buffer = lines.pop() || "";
|
|
207
|
+
|
|
208
|
+
for (const line of lines) {
|
|
209
|
+
if (line.startsWith("data: ")) {
|
|
210
|
+
yield line.slice(6).trim();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
} finally {
|
|
215
|
+
reader.releaseLock();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
151
219
|
static async connect(
|
|
152
220
|
api_key?: string,
|
|
153
221
|
base_url: string = "https://dna.hashgrid.ai",
|
|
154
222
|
timeout: number = 30000
|
|
155
223
|
): Promise<Grid> {
|
|
156
224
|
const client = new Hashgrid(api_key, base_url, timeout);
|
|
157
|
-
const data = await client.
|
|
225
|
+
const data = await client.request("GET", "/api/v1");
|
|
158
226
|
const grid = new Grid(data.name, data.tick, client);
|
|
159
227
|
return grid;
|
|
160
228
|
}
|
package/src/resources.ts
CHANGED
|
@@ -100,30 +100,18 @@ export class Grid {
|
|
|
100
100
|
this._client = client;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
async *listen(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
this.tick = data.tick;
|
|
110
|
-
const current_tick = this.tick;
|
|
111
|
-
|
|
112
|
-
if (current_tick !== last_tick) {
|
|
113
|
-
yield current_tick;
|
|
114
|
-
last_tick = current_tick;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
await new Promise((resolve) => setTimeout(resolve, poll_interval));
|
|
118
|
-
} catch (error) {
|
|
119
|
-
console.warn(`Error while listening for ticks: ${error}`);
|
|
120
|
-
await new Promise((resolve) => setTimeout(resolve, poll_interval * 2));
|
|
103
|
+
async *listen(): AsyncGenerator<number> {
|
|
104
|
+
for await (const data of this._client.stream("GET", "/api/v1/listen")) {
|
|
105
|
+
const tick = parseInt(data, 10);
|
|
106
|
+
if (!isNaN(tick) && tick !== this.tick) {
|
|
107
|
+
this.tick = tick;
|
|
108
|
+
yield tick;
|
|
121
109
|
}
|
|
122
110
|
}
|
|
123
111
|
}
|
|
124
112
|
|
|
125
113
|
async *nodes(): AsyncGenerator<Node> {
|
|
126
|
-
const data = await this._client.
|
|
114
|
+
const data = await this._client.request("GET", "/api/v1/node");
|
|
127
115
|
for (const item of data) {
|
|
128
116
|
yield new Node(
|
|
129
117
|
item.node_id,
|
|
@@ -142,7 +130,7 @@ export class Grid {
|
|
|
142
130
|
capacity: number = 100
|
|
143
131
|
): Promise<Node> {
|
|
144
132
|
const json_data = { name, message, capacity };
|
|
145
|
-
const data = await this._client.
|
|
133
|
+
const data = await this._client.request("POST", "/api/v1/node", undefined, json_data);
|
|
146
134
|
return new Node(
|
|
147
135
|
data.node_id,
|
|
148
136
|
data.owner_id,
|
|
@@ -179,7 +167,7 @@ export class Node {
|
|
|
179
167
|
}
|
|
180
168
|
|
|
181
169
|
async recv(): Promise<Message[]> {
|
|
182
|
-
const data = await this._client.
|
|
170
|
+
const data = await this._client.request(
|
|
183
171
|
"GET",
|
|
184
172
|
`/api/v1/node/${this.node_id}/recv`
|
|
185
173
|
);
|
|
@@ -189,7 +177,7 @@ export class Node {
|
|
|
189
177
|
);
|
|
190
178
|
}
|
|
191
179
|
|
|
192
|
-
async send(replies: Message[]): Promise<
|
|
180
|
+
async send(replies: Message[]): Promise<Message[]> {
|
|
193
181
|
const json_data = replies.map((msg) => {
|
|
194
182
|
const obj: any = {
|
|
195
183
|
peer_id: msg.peer_id,
|
|
@@ -201,13 +189,16 @@ export class Node {
|
|
|
201
189
|
}
|
|
202
190
|
return obj;
|
|
203
191
|
});
|
|
204
|
-
const data = await this._client.
|
|
192
|
+
const data = await this._client.request(
|
|
205
193
|
"POST",
|
|
206
194
|
`/api/v1/node/${this.node_id}/send`,
|
|
207
195
|
undefined,
|
|
208
196
|
json_data
|
|
209
197
|
);
|
|
210
|
-
return data.map(
|
|
198
|
+
return data.map(
|
|
199
|
+
(item: any) =>
|
|
200
|
+
new Message(item.peer_id, item.round, item.message, item.score ?? null)
|
|
201
|
+
);
|
|
211
202
|
}
|
|
212
203
|
|
|
213
204
|
async update(
|
|
@@ -224,7 +215,7 @@ export class Node {
|
|
|
224
215
|
return this;
|
|
225
216
|
}
|
|
226
217
|
|
|
227
|
-
const data = await this._client.
|
|
218
|
+
const data = await this._client.request(
|
|
228
219
|
"PUT",
|
|
229
220
|
`/api/v1/node/${this.node_id}`,
|
|
230
221
|
undefined,
|
|
@@ -240,7 +231,7 @@ export class Node {
|
|
|
240
231
|
}
|
|
241
232
|
|
|
242
233
|
async delete(): Promise<void> {
|
|
243
|
-
await this._client.
|
|
234
|
+
await this._client.request("DELETE", `/api/v1/node/${this.node_id}`);
|
|
244
235
|
}
|
|
245
236
|
}
|
|
246
237
|
|