gennet.js 0.1.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/index.mjs ADDED
@@ -0,0 +1,301 @@
1
+ class RpcError extends Error {
2
+ code;
3
+ data;
4
+ constructor(message, code, data) {
5
+ super(message);
6
+ this.name = "RpcError";
7
+ this.code = code;
8
+ this.data = data;
9
+ }
10
+ }
11
+
12
+ let requestId = 0;
13
+ class HttpProvider {
14
+ url;
15
+ constructor(url) {
16
+ this.url = url;
17
+ }
18
+ get connected() {
19
+ return true;
20
+ }
21
+ async request(method, params) {
22
+ const id = ++requestId;
23
+ const body = JSON.stringify({ jsonrpc: "2.0", id, method, params });
24
+ const res = await fetch(this.url, {
25
+ method: "POST",
26
+ headers: { "Content-Type": "application/json" },
27
+ body
28
+ });
29
+ if (!res.ok) {
30
+ throw new RpcError(`HTTP ${res.status}: ${res.statusText}`, -32e3);
31
+ }
32
+ const json = await res.json();
33
+ if ("error" in json) {
34
+ const err = json.error;
35
+ throw new RpcError(err.message, err.code, err.data);
36
+ }
37
+ return json.result;
38
+ }
39
+ // HTTP unterstützt keine Push-Notifications
40
+ on(_event, _listener) {
41
+ }
42
+ off(_event, _listener) {
43
+ }
44
+ disconnect() {
45
+ }
46
+ }
47
+
48
+ const DEFAULT_TIMEOUT = 3e4;
49
+ class WebSocketProvider {
50
+ url;
51
+ timeout;
52
+ ws = null;
53
+ requestId = 0;
54
+ pending = /* @__PURE__ */ new Map();
55
+ listeners = /* @__PURE__ */ new Set();
56
+ connectPromise = null;
57
+ constructor(url, timeout = DEFAULT_TIMEOUT) {
58
+ this.url = url;
59
+ this.timeout = timeout;
60
+ }
61
+ get connected() {
62
+ return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
63
+ }
64
+ async connect() {
65
+ if (this.connected) return;
66
+ if (this.connectPromise) return this.connectPromise;
67
+ this.connectPromise = new Promise((resolve, reject) => {
68
+ this.ws = new WebSocket(this.url);
69
+ this.ws.onopen = () => {
70
+ this.connectPromise = null;
71
+ resolve();
72
+ };
73
+ this.ws.onerror = (ev) => {
74
+ this.connectPromise = null;
75
+ reject(new Error(`WebSocket-Verbindung fehlgeschlagen: ${this.url} (${ev})`));
76
+ };
77
+ this.ws.onmessage = (ev) => {
78
+ this.handleMessage(typeof ev.data === "string" ? ev.data : String(ev.data));
79
+ };
80
+ this.ws.onclose = () => {
81
+ this.connectPromise = null;
82
+ for (const [id, req] of this.pending) {
83
+ clearTimeout(req.timer);
84
+ req.reject(new Error("WebSocket-Verbindung geschlossen"));
85
+ this.pending.delete(id);
86
+ }
87
+ };
88
+ });
89
+ return this.connectPromise;
90
+ }
91
+ async request(method, params) {
92
+ if (!this.connected) {
93
+ await this.connect();
94
+ }
95
+ const id = ++this.requestId;
96
+ const payload = JSON.stringify({ jsonrpc: "2.0", id, method, params });
97
+ return new Promise((resolve, reject) => {
98
+ const timer = setTimeout(() => {
99
+ this.pending.delete(id);
100
+ reject(new RpcError(`Timeout nach ${this.timeout}ms f\xFCr ${method}`, -32e3));
101
+ }, this.timeout);
102
+ this.pending.set(id, { resolve, reject, timer });
103
+ this.ws.send(payload);
104
+ });
105
+ }
106
+ on(_event, listener) {
107
+ this.listeners.add(listener);
108
+ }
109
+ off(_event, listener) {
110
+ this.listeners.delete(listener);
111
+ }
112
+ disconnect() {
113
+ if (this.ws) {
114
+ this.ws.close();
115
+ this.ws = null;
116
+ }
117
+ }
118
+ // ── Private ────────────────────────────────────────────────
119
+ handleMessage(raw) {
120
+ let msg;
121
+ try {
122
+ msg = JSON.parse(raw);
123
+ } catch {
124
+ return;
125
+ }
126
+ if (msg.id !== void 0 && ("result" in msg || "error" in msg)) {
127
+ const response = msg;
128
+ const pending = this.pending.get(response.id);
129
+ if (pending) {
130
+ clearTimeout(pending.timer);
131
+ this.pending.delete(response.id);
132
+ if ("error" in response) {
133
+ const err = response.error;
134
+ pending.reject(new RpcError(err.message, err.code, err.data));
135
+ } else {
136
+ pending.resolve(response.result);
137
+ }
138
+ }
139
+ return;
140
+ }
141
+ if ("method" in msg && "params" in msg) {
142
+ const notification = msg;
143
+ for (const listener of this.listeners) {
144
+ listener(notification);
145
+ }
146
+ }
147
+ }
148
+ }
149
+
150
+ class Admin {
151
+ constructor(provider) {
152
+ this.provider = provider;
153
+ }
154
+ /** Node-Info: Status, PeerId, Adresse, Peers, Uptime, Module. */
155
+ async nodeInfo() {
156
+ return await this.provider.request("admin_nodeInfo");
157
+ }
158
+ /** Gateway herunterfahren. */
159
+ async shutdown() {
160
+ return await this.provider.request("admin_shutdown");
161
+ }
162
+ /** Alle Module und ihren Status auflisten. */
163
+ async modules() {
164
+ return await this.provider.request("admin_modules");
165
+ }
166
+ /** Ein Modul starten. */
167
+ async startModule(name) {
168
+ return await this.provider.request("admin_startModule", { name });
169
+ }
170
+ /** Ein Modul stoppen. */
171
+ async stopModule(name) {
172
+ return await this.provider.request("admin_stopModule", { name });
173
+ }
174
+ }
175
+
176
+ class Net {
177
+ constructor(provider) {
178
+ this.provider = provider;
179
+ }
180
+ /** Alle bekannten Peers auflisten. */
181
+ async peers() {
182
+ return await this.provider.request("net_peers");
183
+ }
184
+ /** Mit einem Peer über Multiaddr verbinden. */
185
+ async connect(multiaddr) {
186
+ return await this.provider.request("net_connect", { multiaddr });
187
+ }
188
+ /** Verschlüsselte Nachricht an einen Peer senden. */
189
+ async send(address, text) {
190
+ return await this.provider.request("net_send", { address, text });
191
+ }
192
+ /** Agent-Prompt auf einem Remote-Peer ausführen (ECIES-verschlüsselt). */
193
+ async peerAgent(address, prompt) {
194
+ return await this.provider.request("net_peerAgent", { address, prompt });
195
+ }
196
+ }
197
+
198
+ class Personal {
199
+ constructor(provider) {
200
+ this.provider = provider;
201
+ }
202
+ /** Neue Identität erstellen und im Keystore speichern. */
203
+ async newIdentity(password) {
204
+ return await this.provider.request("personal_newIdentity", { password });
205
+ }
206
+ /** Alle Identitäten im Keystore auflisten. */
207
+ async listIdentities() {
208
+ return await this.provider.request("personal_listIdentities");
209
+ }
210
+ }
211
+
212
+ class Agent {
213
+ constructor(provider) {
214
+ this.provider = provider;
215
+ }
216
+ /** Agent-Loop mit einem Prompt ausführen. */
217
+ async run(input) {
218
+ return await this.provider.request("agent_run", { input });
219
+ }
220
+ }
221
+
222
+ class Mempool {
223
+ constructor(provider) {
224
+ this.provider = provider;
225
+ }
226
+ /** Nachricht ans Netzwerk broadcasten (GossipSub). */
227
+ async broadcast(message) {
228
+ return await this.provider.request("mempool_broadcast", { message });
229
+ }
230
+ }
231
+
232
+ class GenNet {
233
+ admin;
234
+ net;
235
+ personal;
236
+ agent;
237
+ mempool;
238
+ provider;
239
+ constructor(providerOrUrl) {
240
+ if (typeof providerOrUrl === "string") {
241
+ this.provider = GenNet.createProvider(providerOrUrl);
242
+ } else {
243
+ this.provider = providerOrUrl;
244
+ }
245
+ this.admin = new Admin(this.provider);
246
+ this.net = new Net(this.provider);
247
+ this.personal = new Personal(this.provider);
248
+ this.agent = new Agent(this.provider);
249
+ this.mempool = new Mempool(this.provider);
250
+ }
251
+ /** Verbindung herstellen (nur bei WebSocket nötig). */
252
+ async connect() {
253
+ if (this.provider.connect) {
254
+ await this.provider.connect();
255
+ }
256
+ }
257
+ /** Verbindung schließen. */
258
+ disconnect() {
259
+ this.provider.disconnect();
260
+ }
261
+ /** Ob eine aktive Verbindung besteht. */
262
+ get connected() {
263
+ return this.provider.connected;
264
+ }
265
+ /**
266
+ * Subscription starten (nur WebSocket).
267
+ * Topics: 'logs', 'messages', 'mempool'.
268
+ */
269
+ async subscribe(topic, callback) {
270
+ const subId = await this.provider.request("gennet_subscribe", [topic]);
271
+ const listener = (notification) => {
272
+ if (notification.method === "gennet_subscription" && notification.params.subscription === subId) {
273
+ callback(notification.params.result);
274
+ }
275
+ };
276
+ this.provider.on("notification", listener);
277
+ return {
278
+ id: subId,
279
+ unsubscribe: async () => {
280
+ this.provider.off("notification", listener);
281
+ return await this.provider.request("gennet_unsubscribe", [subId]);
282
+ }
283
+ };
284
+ }
285
+ /** Raw JSON-RPC Request (für erweiterte Nutzung). */
286
+ async request(method, params) {
287
+ return this.provider.request(method, params);
288
+ }
289
+ // ── Private ────────────────────────────────────────────────
290
+ static createProvider(url) {
291
+ if (url.startsWith("ws://") || url.startsWith("wss://")) {
292
+ return new WebSocketProvider(url);
293
+ }
294
+ if (url.startsWith("http://") || url.startsWith("https://")) {
295
+ return new HttpProvider(url);
296
+ }
297
+ throw new Error(`Unbekanntes URL-Schema: ${url} (erwartet: ws://, wss://, http://, https://)`);
298
+ }
299
+ }
300
+
301
+ export { Admin, Agent, GenNet, HttpProvider, Mempool, Net, Personal, RpcError, WebSocketProvider };
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "gennet.js",
3
+ "version": "0.1.0",
4
+ "description": "Client Library for GenNet — interact with GenNet nodes via JSON-RPC",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "import": {
10
+ "types": "./dist/index.d.mts",
11
+ "default": "./dist/index.mjs"
12
+ },
13
+ "require": {
14
+ "types": "./dist/index.d.cts",
15
+ "default": "./dist/index.cjs"
16
+ }
17
+ }
18
+ },
19
+ "main": "./dist/index.cjs",
20
+ "module": "./dist/index.mjs",
21
+ "types": "./dist/index.d.ts",
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "scripts": {
26
+ "build": "unbuild",
27
+ "dev": "unbuild --stub",
28
+ "test": "vitest",
29
+ "lint": "eslint src/",
30
+ "check": "publint && attw --pack",
31
+ "prepublishOnly": "npm run build && npm run check"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/cryptagoEU/gennet.js.git"
36
+ },
37
+ "keywords": [
38
+ "gennet",
39
+ "p2p",
40
+ "json-rpc",
41
+ "websocket",
42
+ "typescript",
43
+ "network",
44
+ "agentic",
45
+ "web3"
46
+ ],
47
+ "author": "Alexander Garber",
48
+ "license": "MIT",
49
+ "bugs": {
50
+ "url": "https://github.com/cryptagoEU/gennet.js/issues"
51
+ },
52
+ "homepage": "https://github.com/cryptagoEU/gennet.js#readme",
53
+ "devDependencies": {
54
+ "@arethetypeswrong/cli": "^0.17.0",
55
+ "publint": "^0.3.0",
56
+ "typescript": "^5.4.0",
57
+ "unbuild": "^3.0.0",
58
+ "vitest": "^3.0.0"
59
+ }
60
+ }