colonies-ts 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.js ADDED
@@ -0,0 +1,976 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ColoniesClient: () => ColoniesClient,
24
+ Crypto: () => Crypto,
25
+ ProcessState: () => ProcessState,
26
+ deriveId: () => deriveId,
27
+ generatePrivateKey: () => generatePrivateKey,
28
+ sign: () => sign
29
+ });
30
+ module.exports = __toCommonJS(index_exports);
31
+
32
+ // src/crypto.ts
33
+ var import_sha3 = require("@noble/hashes/sha3");
34
+ var import_sha256 = require("@noble/hashes/sha256");
35
+ var import_hmac = require("@noble/hashes/hmac");
36
+ var import_utils = require("@noble/hashes/utils");
37
+ var A = 0n;
38
+ var N = 115792089237316195423570985008687907852837564279074904382605163141518161494337n;
39
+ var Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240n;
40
+ var Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424n;
41
+ var G = [Gx, Gy];
42
+ var P = 2n ** 256n - 2n ** 32n - 977n;
43
+ function pad32(value) {
44
+ if (value.length >= 32) return value.slice(0, 32);
45
+ const padded = new Uint8Array(32);
46
+ padded.set(value, 32 - value.length);
47
+ return padded;
48
+ }
49
+ function intToBigEndian(value) {
50
+ if (value === 0n) return new Uint8Array([0]);
51
+ const hex = value.toString(16);
52
+ const paddedHex = hex.length % 2 ? "0" + hex : hex;
53
+ return (0, import_utils.hexToBytes)(paddedHex);
54
+ }
55
+ function bigEndianToInt(value) {
56
+ if (value.length === 0) return 0n;
57
+ return BigInt("0x" + (0, import_utils.bytesToHex)(value));
58
+ }
59
+ function inv(a, n) {
60
+ if (a === 0n) return 0n;
61
+ let lm = 1n, hm = 0n;
62
+ let low = (a % n + n) % n, high = n;
63
+ while (low > 1n) {
64
+ const r = high / low;
65
+ const nm = hm - lm * r;
66
+ const newVal = high - low * r;
67
+ hm = lm;
68
+ high = low;
69
+ lm = nm;
70
+ low = newVal;
71
+ }
72
+ return (lm % n + n) % n;
73
+ }
74
+ function toJacobian(p) {
75
+ return [p[0], p[1], 1n];
76
+ }
77
+ function fromJacobian(p) {
78
+ const z = inv(p[2], P);
79
+ const z2 = z * z % P;
80
+ const z3 = z2 * z % P;
81
+ return [(p[0] * z2 % P + P) % P, (p[1] * z3 % P + P) % P];
82
+ }
83
+ function jacobianDouble(p) {
84
+ if (p[1] === 0n) return [0n, 0n, 0n];
85
+ const ysq = p[1] ** 2n % P;
86
+ const S = 4n * p[0] * ysq % P;
87
+ const M = (3n * p[0] ** 2n + A * p[2] ** 4n) % P;
88
+ const nx = ((M ** 2n - 2n * S) % P + P) % P;
89
+ const ny = ((M * (S - nx) - 8n * ysq ** 2n) % P + P) % P;
90
+ const nz = 2n * p[1] * p[2] % P;
91
+ return [nx, ny, nz];
92
+ }
93
+ function jacobianAdd(p, q) {
94
+ if (p[1] === 0n) return q;
95
+ if (q[1] === 0n) return p;
96
+ const U1 = p[0] * q[2] ** 2n % P;
97
+ const U2 = q[0] * p[2] ** 2n % P;
98
+ const S1 = p[1] * q[2] ** 3n % P;
99
+ const S2 = q[1] * p[2] ** 3n % P;
100
+ if (U1 === U2) {
101
+ if (S1 !== S2) return [0n, 0n, 1n];
102
+ return jacobianDouble(p);
103
+ }
104
+ const H = ((U2 - U1) % P + P) % P;
105
+ const R = ((S2 - S1) % P + P) % P;
106
+ const H2 = H * H % P;
107
+ const H3 = H * H2 % P;
108
+ const U1H2 = U1 * H2 % P;
109
+ const nx = ((R ** 2n - H3 - 2n * U1H2) % P + P) % P;
110
+ const ny = ((R * (U1H2 - nx) - S1 * H3) % P + P) % P;
111
+ const nz = H * p[2] * q[2] % P;
112
+ return [nx, ny, nz];
113
+ }
114
+ function jacobianMultiply(a, n) {
115
+ if (a[1] === 0n || n === 0n) return [0n, 0n, 1n];
116
+ if (n === 1n) return a;
117
+ if (n < 0n || n >= N) return jacobianMultiply(a, (n % N + N) % N);
118
+ if (n % 2n === 0n) {
119
+ return jacobianDouble(jacobianMultiply(a, n / 2n));
120
+ } else {
121
+ return jacobianAdd(jacobianDouble(jacobianMultiply(a, n / 2n)), a);
122
+ }
123
+ }
124
+ function fastMultiply(a, n) {
125
+ return fromJacobian(jacobianMultiply(toJacobian(a), n));
126
+ }
127
+ function encodeRawPublicKey(rawPublicKey) {
128
+ const left = pad32(intToBigEndian(rawPublicKey[0]));
129
+ const right = pad32(intToBigEndian(rawPublicKey[1]));
130
+ const result = new Uint8Array(64);
131
+ result.set(left, 0);
132
+ result.set(right, 32);
133
+ return result;
134
+ }
135
+ function privateKeyToPublicKey(privateKeyBytes) {
136
+ const privateKeyAsNum = bigEndianToInt(privateKeyBytes);
137
+ if (privateKeyAsNum >= N) {
138
+ throw new Error("Invalid private key");
139
+ }
140
+ const rawPublicKey = fastMultiply(G, privateKeyAsNum);
141
+ return encodeRawPublicKey(rawPublicKey);
142
+ }
143
+ function deterministicGenerateK(msgHash, privateKeyBytes) {
144
+ const v0 = new Uint8Array(32).fill(1);
145
+ const k0 = new Uint8Array(32).fill(0);
146
+ const data1 = new Uint8Array(v0.length + 1 + privateKeyBytes.length + msgHash.length);
147
+ data1.set(v0, 0);
148
+ data1[v0.length] = 0;
149
+ data1.set(privateKeyBytes, v0.length + 1);
150
+ data1.set(msgHash, v0.length + 1 + privateKeyBytes.length);
151
+ const k1 = (0, import_hmac.hmac)(import_sha256.sha256, k0, data1);
152
+ const v1 = (0, import_hmac.hmac)(import_sha256.sha256, k1, v0);
153
+ const data2 = new Uint8Array(v1.length + 1 + privateKeyBytes.length + msgHash.length);
154
+ data2.set(v1, 0);
155
+ data2[v1.length] = 1;
156
+ data2.set(privateKeyBytes, v1.length + 1);
157
+ data2.set(msgHash, v1.length + 1 + privateKeyBytes.length);
158
+ const k2 = (0, import_hmac.hmac)(import_sha256.sha256, k1, data2);
159
+ const v2 = (0, import_hmac.hmac)(import_sha256.sha256, k2, v1);
160
+ const kb = (0, import_hmac.hmac)(import_sha256.sha256, k2, v2);
161
+ return bigEndianToInt(kb);
162
+ }
163
+ function ecdsaRawSign(msgHash, privateKeyBytes) {
164
+ const z = bigEndianToInt(msgHash);
165
+ const k = deterministicGenerateK(msgHash, privateKeyBytes);
166
+ const [r, y] = fastMultiply(G, k);
167
+ const privKeyNum = bigEndianToInt(privateKeyBytes);
168
+ const sRaw = inv(k, N) * (z + r * privKeyNum) % N;
169
+ const v = 27 + Number(y % 2n ^ (sRaw * 2n < N ? 0n : 1n));
170
+ const s = sRaw * 2n < N ? sRaw : N - sRaw;
171
+ return [v - 27, r, s];
172
+ }
173
+ function generatePrivateKey() {
174
+ const randomData = (0, import_utils.randomBytes)(32);
175
+ const hash = (0, import_sha3.sha3_256)(randomData);
176
+ return (0, import_utils.bytesToHex)(hash);
177
+ }
178
+ function deriveId(privateKey) {
179
+ const privateKeyBytes = (0, import_utils.hexToBytes)(privateKey);
180
+ const publicKey = privateKeyToPublicKey(privateKeyBytes);
181
+ const publicKeyHex = "04" + (0, import_utils.bytesToHex)(publicKey);
182
+ const encoder = new TextEncoder();
183
+ const hash = (0, import_sha3.sha3_256)(encoder.encode(publicKeyHex));
184
+ return (0, import_utils.bytesToHex)(hash);
185
+ }
186
+ function sign(message, privateKey) {
187
+ const privateKeyBytes = (0, import_utils.hexToBytes)(privateKey);
188
+ const encoder = new TextEncoder();
189
+ const msgHash = (0, import_sha3.sha3_256)(encoder.encode(message));
190
+ const [v, r, s] = ecdsaRawSign(msgHash, privateKeyBytes);
191
+ const vBytes = new Uint8Array([v]);
192
+ const rBytes = pad32(intToBigEndian(r));
193
+ const sBytes = pad32(intToBigEndian(s));
194
+ const signature = new Uint8Array(65);
195
+ signature.set(rBytes, 0);
196
+ signature.set(sBytes, 32);
197
+ signature.set(vBytes, 64);
198
+ return (0, import_utils.bytesToHex)(signature);
199
+ }
200
+ var Crypto = class {
201
+ generatePrivateKey() {
202
+ return generatePrivateKey();
203
+ }
204
+ id(privateKey) {
205
+ return deriveId(privateKey);
206
+ }
207
+ sign(message, privateKey) {
208
+ return sign(message, privateKey);
209
+ }
210
+ };
211
+
212
+ // src/client.ts
213
+ function decodeBase64Utf8(base64) {
214
+ const binaryStr = atob(base64);
215
+ const bytes = new Uint8Array(binaryStr.length);
216
+ for (let i = 0; i < binaryStr.length; i++) {
217
+ bytes[i] = binaryStr.charCodeAt(i);
218
+ }
219
+ return new TextDecoder("utf-8").decode(bytes);
220
+ }
221
+ function encodeBase64Utf8(str) {
222
+ const utf8Bytes = new TextEncoder().encode(str);
223
+ const binaryStr = String.fromCharCode(...utf8Bytes);
224
+ return btoa(binaryStr);
225
+ }
226
+ var ProcessState = /* @__PURE__ */ ((ProcessState2) => {
227
+ ProcessState2[ProcessState2["WAITING"] = 0] = "WAITING";
228
+ ProcessState2[ProcessState2["RUNNING"] = 1] = "RUNNING";
229
+ ProcessState2[ProcessState2["SUCCESS"] = 2] = "SUCCESS";
230
+ ProcessState2[ProcessState2["FAILED"] = 3] = "FAILED";
231
+ return ProcessState2;
232
+ })(ProcessState || {});
233
+ var ColoniesClient = class {
234
+ constructor(config) {
235
+ this.privateKey = null;
236
+ this.host = config.host;
237
+ this.port = config.port;
238
+ this.tls = config.tls ?? false;
239
+ this.crypto = new Crypto();
240
+ }
241
+ setPrivateKey(privateKey) {
242
+ this.privateKey = privateKey;
243
+ }
244
+ getBaseUrl() {
245
+ const protocol = this.tls ? "https" : "http";
246
+ return `${protocol}://${this.host}:${this.port}/api`;
247
+ }
248
+ createRPCMsg(msg) {
249
+ if (!this.privateKey) {
250
+ throw new Error("Private key not set. Call setPrivateKey() first.");
251
+ }
252
+ const payload = encodeBase64Utf8(JSON.stringify(msg));
253
+ const signature = this.crypto.sign(payload, this.privateKey);
254
+ return {
255
+ payloadtype: msg.msgtype,
256
+ payload,
257
+ signature
258
+ };
259
+ }
260
+ async sendRPC(rpcMessage) {
261
+ const url = this.getBaseUrl();
262
+ const response = await fetch(url, {
263
+ method: "POST",
264
+ headers: {
265
+ "Content-Type": "application/json"
266
+ },
267
+ body: JSON.stringify(rpcMessage)
268
+ });
269
+ if (!response.ok) {
270
+ const errorText = await response.text();
271
+ let errorObj;
272
+ try {
273
+ errorObj = JSON.parse(errorText);
274
+ } catch {
275
+ throw new Error(`Request failed with status ${response.status}: ${response.statusText}`);
276
+ }
277
+ if (errorObj.payload) {
278
+ try {
279
+ const decodedPayload = decodeBase64Utf8(errorObj.payload);
280
+ const decodedError = JSON.parse(decodedPayload);
281
+ throw new Error(decodedError.message || JSON.stringify(decodedError));
282
+ } catch (e) {
283
+ if (e instanceof Error && e.message !== "Request failed") {
284
+ throw e;
285
+ }
286
+ }
287
+ }
288
+ throw new Error(JSON.stringify(errorObj));
289
+ }
290
+ const responseText = await response.text();
291
+ if (!responseText || responseText.trim() === "") {
292
+ throw new Error("Server returned empty response");
293
+ }
294
+ const rpcReplyMsg = JSON.parse(responseText);
295
+ const msg = JSON.parse(decodeBase64Utf8(rpcReplyMsg.payload));
296
+ if (rpcReplyMsg.error === true) {
297
+ const errorMessage = typeof msg === "object" && msg.message ? msg.message : JSON.stringify(msg);
298
+ throw new Error(errorMessage);
299
+ }
300
+ return msg;
301
+ }
302
+ // ==================== Colony Methods ====================
303
+ async getColonies() {
304
+ const msg = { msgtype: "getcoloniesmsg" };
305
+ return this.sendRPC(this.createRPCMsg(msg));
306
+ }
307
+ async getStatistics() {
308
+ const msg = { msgtype: "getstatisticsmsg" };
309
+ return this.sendRPC(this.createRPCMsg(msg));
310
+ }
311
+ /**
312
+ * Add a new colony (requires server private key)
313
+ * @param colony - Colony object with colonyid and name
314
+ */
315
+ async addColony(colony) {
316
+ const msg = {
317
+ msgtype: "addcolonymsg",
318
+ colony
319
+ };
320
+ return this.sendRPC(this.createRPCMsg(msg));
321
+ }
322
+ /**
323
+ * Remove a colony (requires server private key)
324
+ * @param colonyName - Name of the colony to remove
325
+ */
326
+ async removeColony(colonyName) {
327
+ const msg = {
328
+ msgtype: "removecolonymsg",
329
+ colonyname: colonyName
330
+ };
331
+ return this.sendRPC(this.createRPCMsg(msg));
332
+ }
333
+ // ==================== Executor Methods ====================
334
+ async getExecutors(colonyName) {
335
+ const msg = {
336
+ msgtype: "getexecutorsmsg",
337
+ colonyname: colonyName
338
+ };
339
+ return this.sendRPC(this.createRPCMsg(msg));
340
+ }
341
+ async getExecutor(colonyName, executorName) {
342
+ const msg = {
343
+ msgtype: "getexecutormsg",
344
+ colonyname: colonyName,
345
+ executorname: executorName
346
+ };
347
+ return this.sendRPC(this.createRPCMsg(msg));
348
+ }
349
+ async addExecutor(executor) {
350
+ const msg = {
351
+ msgtype: "addexecutormsg",
352
+ executor
353
+ };
354
+ return this.sendRPC(this.createRPCMsg(msg));
355
+ }
356
+ async approveExecutor(colonyName, executorName) {
357
+ const msg = {
358
+ msgtype: "approveexecutormsg",
359
+ colonyname: colonyName,
360
+ executorname: executorName
361
+ };
362
+ return this.sendRPC(this.createRPCMsg(msg));
363
+ }
364
+ async removeExecutor(colonyName, executorName) {
365
+ const msg = {
366
+ msgtype: "removeexecutormsg",
367
+ colonyname: colonyName,
368
+ executorname: executorName
369
+ };
370
+ return this.sendRPC(this.createRPCMsg(msg));
371
+ }
372
+ // ==================== Process Methods ====================
373
+ async submitFunctionSpec(spec) {
374
+ const msg = {
375
+ msgtype: "submitfuncspecmsg",
376
+ spec
377
+ };
378
+ return this.sendRPC(this.createRPCMsg(msg));
379
+ }
380
+ async getProcess(processId) {
381
+ const msg = {
382
+ msgtype: "getprocessmsg",
383
+ processid: processId
384
+ };
385
+ return this.sendRPC(this.createRPCMsg(msg));
386
+ }
387
+ async getProcesses(colonyName, count, state) {
388
+ const msg = {
389
+ msgtype: "getprocessesmsg",
390
+ colonyname: colonyName,
391
+ count,
392
+ state
393
+ };
394
+ return this.sendRPC(this.createRPCMsg(msg));
395
+ }
396
+ async removeProcess(processId) {
397
+ const msg = {
398
+ msgtype: "removeprocessmsg",
399
+ processid: processId,
400
+ all: false
401
+ };
402
+ return this.sendRPC(this.createRPCMsg(msg));
403
+ }
404
+ async removeAllProcesses(colonyName, state = -1) {
405
+ const msg = {
406
+ msgtype: "removeallprocessesmsg",
407
+ colonyname: colonyName,
408
+ state
409
+ };
410
+ return this.sendRPC(this.createRPCMsg(msg));
411
+ }
412
+ async assign(colonyName, timeout, executorPrvKey) {
413
+ const originalKey = this.privateKey;
414
+ this.setPrivateKey(executorPrvKey);
415
+ try {
416
+ const msg = {
417
+ msgtype: "assignprocessmsg",
418
+ colonyname: colonyName,
419
+ timeout
420
+ };
421
+ return this.sendRPC(this.createRPCMsg(msg));
422
+ } finally {
423
+ if (originalKey) {
424
+ this.setPrivateKey(originalKey);
425
+ }
426
+ }
427
+ }
428
+ async closeProcess(processId, output) {
429
+ const msg = {
430
+ msgtype: "closesuccessfulmsg",
431
+ processid: processId,
432
+ out: output
433
+ };
434
+ return this.sendRPC(this.createRPCMsg(msg));
435
+ }
436
+ async failProcess(processId, errors) {
437
+ const msg = {
438
+ msgtype: "closefailedmsg",
439
+ processid: processId,
440
+ errors
441
+ };
442
+ return this.sendRPC(this.createRPCMsg(msg));
443
+ }
444
+ // ==================== Workflow Methods ====================
445
+ async submitWorkflowSpec(workflowSpec) {
446
+ const msg = {
447
+ msgtype: "submitworkflowspecmsg",
448
+ spec: workflowSpec
449
+ };
450
+ return this.sendRPC(this.createRPCMsg(msg));
451
+ }
452
+ async getProcessGraph(processGraphId) {
453
+ const msg = {
454
+ msgtype: "getprocessgraphmsg",
455
+ processgraphid: processGraphId
456
+ };
457
+ return this.sendRPC(this.createRPCMsg(msg));
458
+ }
459
+ async getProcessGraphs(colonyName, count, state) {
460
+ const msg = {
461
+ msgtype: "getprocessgraphsmsg",
462
+ colonyname: colonyName,
463
+ count
464
+ };
465
+ if (state !== void 0) {
466
+ msg.state = state;
467
+ }
468
+ return this.sendRPC(this.createRPCMsg(msg));
469
+ }
470
+ async removeProcessGraph(processGraphId) {
471
+ const msg = {
472
+ msgtype: "removeprocessgraphmsg",
473
+ processgraphid: processGraphId
474
+ };
475
+ return this.sendRPC(this.createRPCMsg(msg));
476
+ }
477
+ async removeAllProcessGraphs(colonyName, state) {
478
+ const msg = {
479
+ msgtype: "removeallprocessgraphsmsg",
480
+ colonyname: colonyName
481
+ };
482
+ if (state !== void 0) {
483
+ msg.state = state;
484
+ }
485
+ return this.sendRPC(this.createRPCMsg(msg));
486
+ }
487
+ // ==================== Log Methods ====================
488
+ async addLog(processId, message, executorPrvKey) {
489
+ const originalKey = this.privateKey;
490
+ this.setPrivateKey(executorPrvKey);
491
+ try {
492
+ const msg = {
493
+ msgtype: "addlogmsg",
494
+ processid: processId,
495
+ message
496
+ };
497
+ return this.sendRPC(this.createRPCMsg(msg));
498
+ } finally {
499
+ if (originalKey) {
500
+ this.setPrivateKey(originalKey);
501
+ }
502
+ }
503
+ }
504
+ async getLogs(colonyName, processId, executorName, count = 100, since = 0) {
505
+ const msg = {
506
+ msgtype: "getlogsmsg",
507
+ colonyname: colonyName,
508
+ processid: processId,
509
+ executorname: executorName,
510
+ count,
511
+ since
512
+ };
513
+ return this.sendRPC(this.createRPCMsg(msg));
514
+ }
515
+ // ==================== Function Methods ====================
516
+ async getFunctions(executorName, colonyName) {
517
+ const msg = {
518
+ msgtype: "getfunctionsmsg",
519
+ executorname: executorName,
520
+ colonyname: colonyName
521
+ };
522
+ return this.sendRPC(this.createRPCMsg(msg));
523
+ }
524
+ // ==================== Cron Methods ====================
525
+ async getCrons(colonyName, count = 100) {
526
+ const msg = {
527
+ msgtype: "getcronsmsg",
528
+ colonyname: colonyName,
529
+ count
530
+ };
531
+ return this.sendRPC(this.createRPCMsg(msg));
532
+ }
533
+ async getCron(cronId) {
534
+ const msg = {
535
+ msgtype: "getcronmsg",
536
+ cronid: cronId
537
+ };
538
+ return this.sendRPC(this.createRPCMsg(msg));
539
+ }
540
+ async addCron(cronSpec) {
541
+ const msg = {
542
+ msgtype: "addcronmsg",
543
+ cron: cronSpec
544
+ };
545
+ return this.sendRPC(this.createRPCMsg(msg));
546
+ }
547
+ async removeCron(cronId) {
548
+ const msg = {
549
+ msgtype: "removecronmsg",
550
+ cronid: cronId
551
+ };
552
+ return this.sendRPC(this.createRPCMsg(msg));
553
+ }
554
+ // ==================== Generator Methods ====================
555
+ async getGenerators(colonyName, count = 100) {
556
+ const msg = {
557
+ msgtype: "getgeneratorsmsg",
558
+ colonyname: colonyName,
559
+ count
560
+ };
561
+ return this.sendRPC(this.createRPCMsg(msg));
562
+ }
563
+ async getGenerator(generatorId) {
564
+ const msg = {
565
+ msgtype: "getgeneratormsg",
566
+ generatorid: generatorId
567
+ };
568
+ return this.sendRPC(this.createRPCMsg(msg));
569
+ }
570
+ async addGenerator(generatorSpec) {
571
+ const msg = {
572
+ msgtype: "addgeneratormsg",
573
+ generator: generatorSpec
574
+ };
575
+ return this.sendRPC(this.createRPCMsg(msg));
576
+ }
577
+ // ==================== User Methods ====================
578
+ async getUsers(colonyName) {
579
+ const msg = {
580
+ msgtype: "getusersmsg",
581
+ colonyname: colonyName
582
+ };
583
+ return this.sendRPC(this.createRPCMsg(msg));
584
+ }
585
+ async addUser(user) {
586
+ const msg = {
587
+ msgtype: "addusermsg",
588
+ user
589
+ };
590
+ return this.sendRPC(this.createRPCMsg(msg));
591
+ }
592
+ async removeUser(colonyName, name) {
593
+ const msg = {
594
+ msgtype: "removeusermsg",
595
+ colonyname: colonyName,
596
+ name
597
+ };
598
+ return this.sendRPC(this.createRPCMsg(msg));
599
+ }
600
+ // ==================== File Methods ====================
601
+ async getFileLabels(colonyName, name = "", exact = false) {
602
+ const msg = {
603
+ msgtype: "getfilelabelsmsg",
604
+ colonyname: colonyName,
605
+ name,
606
+ exact
607
+ };
608
+ return this.sendRPC(this.createRPCMsg(msg));
609
+ }
610
+ async getFiles(colonyName, label) {
611
+ const msg = {
612
+ msgtype: "getfilesmsg",
613
+ colonyname: colonyName,
614
+ label
615
+ };
616
+ return this.sendRPC(this.createRPCMsg(msg));
617
+ }
618
+ // ==================== Attribute Methods ====================
619
+ async addAttribute(attribute) {
620
+ const msg = {
621
+ msgtype: "addattributemsg",
622
+ attribute
623
+ };
624
+ return this.sendRPC(this.createRPCMsg(msg));
625
+ }
626
+ async getAttribute(attributeId) {
627
+ const msg = {
628
+ msgtype: "getattributemsg",
629
+ attributeid: attributeId
630
+ };
631
+ return this.sendRPC(this.createRPCMsg(msg));
632
+ }
633
+ // ==================== Channel Methods ====================
634
+ /**
635
+ * Append a message to a process channel
636
+ * @param processId - ID of the process
637
+ * @param channelName - Name of the channel
638
+ * @param sequence - Client-assigned sequence number
639
+ * @param inReplyTo - Sequence number this message is replying to (0 if not a reply)
640
+ * @param payload - Message content (string or Uint8Array)
641
+ */
642
+ async channelAppend(processId, channelName, sequence, inReplyTo, payload) {
643
+ let payloadBytes;
644
+ if (typeof payload === "string") {
645
+ const encoder = new TextEncoder();
646
+ payloadBytes = Array.from(encoder.encode(payload));
647
+ } else {
648
+ payloadBytes = Array.from(payload);
649
+ }
650
+ const msg = {
651
+ msgtype: "channelappendmsg",
652
+ processid: processId,
653
+ name: channelName,
654
+ sequence,
655
+ inreplyto: inReplyTo,
656
+ payload: payloadBytes
657
+ };
658
+ return this.sendRPC(this.createRPCMsg(msg));
659
+ }
660
+ /**
661
+ * Read messages from a process channel
662
+ * @param processId - ID of the process
663
+ * @param channelName - Name of the channel
664
+ * @param afterSeq - Read messages after this sequence number (use 0 for all)
665
+ * @param limit - Maximum number of messages to return (0 for no limit)
666
+ */
667
+ async channelRead(processId, channelName, afterSeq, limit) {
668
+ const msg = {
669
+ msgtype: "channelreadmsg",
670
+ processid: processId,
671
+ name: channelName,
672
+ afterseq: afterSeq,
673
+ limit
674
+ };
675
+ const response = await this.sendRPC(this.createRPCMsg(msg));
676
+ if (Array.isArray(response)) {
677
+ return response.map((entry) => ({
678
+ ...entry,
679
+ payload: typeof entry.payload === "string" ? (() => {
680
+ try {
681
+ const binaryStr = atob(entry.payload);
682
+ const bytes = new Uint8Array(binaryStr.length);
683
+ for (let i = 0; i < binaryStr.length; i++) {
684
+ bytes[i] = binaryStr.charCodeAt(i);
685
+ }
686
+ return new TextDecoder("utf-8").decode(bytes);
687
+ } catch {
688
+ return entry.payload;
689
+ }
690
+ })() : Array.isArray(entry.payload) ? new TextDecoder("utf-8").decode(new Uint8Array(entry.payload)) : entry.payload
691
+ }));
692
+ }
693
+ return response || [];
694
+ }
695
+ /**
696
+ * Subscribe to a channel using WebSocket for real-time updates
697
+ * @param processId - ID of the process
698
+ * @param channelName - Name of the channel
699
+ * @param afterSeq - Start reading after this sequence number
700
+ * @param timeout - Timeout in seconds for the subscription
701
+ * @param onMessage - Callback for new messages
702
+ * @param onError - Callback for errors
703
+ * @param onClose - Callback when connection closes
704
+ * @returns WebSocket instance for cleanup
705
+ */
706
+ subscribeChannel(processId, channelName, afterSeq, timeout, onMessage, onError, onClose) {
707
+ if (!this.privateKey) {
708
+ throw new Error("Private key not set. Call setPrivateKey() first.");
709
+ }
710
+ const wsProtocol = this.tls ? "wss" : "ws";
711
+ const wsUrl = `${wsProtocol}://${this.host}:${this.port}/pubsub`;
712
+ const ws = new WebSocket(wsUrl);
713
+ ws.onopen = () => {
714
+ const msg = {
715
+ msgtype: "subscribechannelmsg",
716
+ processid: processId,
717
+ name: channelName,
718
+ afterseq: afterSeq,
719
+ timeout
720
+ };
721
+ const rpcMsg = this.createRPCMsg(msg);
722
+ ws.send(JSON.stringify(rpcMsg));
723
+ };
724
+ ws.onmessage = (event) => {
725
+ try {
726
+ const rpcReply = JSON.parse(event.data);
727
+ if (rpcReply.error) {
728
+ const errorPayload = JSON.parse(decodeBase64Utf8(rpcReply.payload));
729
+ onError(new Error(errorPayload.message || "WebSocket error"));
730
+ return;
731
+ }
732
+ const data = JSON.parse(decodeBase64Utf8(rpcReply.payload));
733
+ if (Array.isArray(data)) {
734
+ const entries = data.map((entry) => ({
735
+ ...entry,
736
+ payload: typeof entry.payload === "string" ? (() => {
737
+ try {
738
+ const binaryStr = atob(entry.payload);
739
+ const bytes = new Uint8Array(binaryStr.length);
740
+ for (let i = 0; i < binaryStr.length; i++) {
741
+ bytes[i] = binaryStr.charCodeAt(i);
742
+ }
743
+ return new TextDecoder("utf-8").decode(bytes);
744
+ } catch {
745
+ return entry.payload;
746
+ }
747
+ })() : Array.isArray(entry.payload) ? new TextDecoder("utf-8").decode(new Uint8Array(entry.payload)) : entry.payload
748
+ }));
749
+ const errorEntry = entries.find((e) => e.error);
750
+ if (errorEntry) {
751
+ onError(new Error(errorEntry.error));
752
+ return;
753
+ }
754
+ onMessage(entries);
755
+ }
756
+ } catch (err) {
757
+ onError(err instanceof Error ? err : new Error(String(err)));
758
+ }
759
+ };
760
+ ws.onerror = () => {
761
+ onError(new Error("WebSocket connection error"));
762
+ };
763
+ ws.onclose = () => {
764
+ onClose();
765
+ };
766
+ return ws;
767
+ }
768
+ // ==================== Blueprint Definition Methods ====================
769
+ /**
770
+ * Add a blueprint definition
771
+ * @param definition - Blueprint definition object
772
+ */
773
+ async addBlueprintDefinition(definition) {
774
+ const msg = {
775
+ msgtype: "addblueprintdefinitionmsg",
776
+ blueprintdefinition: definition
777
+ };
778
+ return this.sendRPC(this.createRPCMsg(msg));
779
+ }
780
+ /**
781
+ * Get a blueprint definition by name
782
+ * @param colonyName - Name of the colony
783
+ * @param name - Name of the blueprint definition
784
+ */
785
+ async getBlueprintDefinition(colonyName, name) {
786
+ const msg = {
787
+ msgtype: "getblueprintdefinitionmsg",
788
+ colonyname: colonyName,
789
+ name
790
+ };
791
+ return this.sendRPC(this.createRPCMsg(msg));
792
+ }
793
+ /**
794
+ * Get all blueprint definitions in a colony
795
+ * @param colonyName - Name of the colony
796
+ */
797
+ async getBlueprintDefinitions(colonyName) {
798
+ const msg = {
799
+ msgtype: "getblueprintdefinitionsmsg",
800
+ colonyname: colonyName
801
+ };
802
+ return this.sendRPC(this.createRPCMsg(msg));
803
+ }
804
+ /**
805
+ * Remove a blueprint definition
806
+ * @param colonyName - Name of the colony (namespace)
807
+ * @param name - Name of the blueprint definition to remove
808
+ */
809
+ async removeBlueprintDefinition(colonyName, name) {
810
+ const msg = {
811
+ msgtype: "removeblueprintdefinitionmsg",
812
+ namespace: colonyName,
813
+ name
814
+ };
815
+ await this.sendRPC(this.createRPCMsg(msg));
816
+ }
817
+ // ==================== Blueprint Methods ====================
818
+ /**
819
+ * Add a blueprint instance
820
+ * @param blueprint - Blueprint object
821
+ */
822
+ async addBlueprint(blueprint) {
823
+ const msg = {
824
+ msgtype: "addblueprintmsg",
825
+ blueprint
826
+ };
827
+ return this.sendRPC(this.createRPCMsg(msg));
828
+ }
829
+ /**
830
+ * Get a blueprint by name
831
+ * @param colonyName - Name of the colony (namespace)
832
+ * @param name - Name of the blueprint
833
+ */
834
+ async getBlueprint(colonyName, name) {
835
+ const msg = {
836
+ msgtype: "getblueprintmsg",
837
+ namespace: colonyName,
838
+ name
839
+ };
840
+ return this.sendRPC(this.createRPCMsg(msg));
841
+ }
842
+ /**
843
+ * Get blueprints in a colony, optionally filtered by kind and location
844
+ * @param colonyName - Name of the colony (namespace)
845
+ * @param kind - Optional kind filter
846
+ * @param location - Optional location filter
847
+ */
848
+ async getBlueprints(colonyName, kind, location) {
849
+ const msg = {
850
+ msgtype: "getblueprintsmsg",
851
+ namespace: colonyName
852
+ };
853
+ if (kind) msg.kind = kind;
854
+ if (location) msg.locationname = location;
855
+ return this.sendRPC(this.createRPCMsg(msg));
856
+ }
857
+ /**
858
+ * Update an existing blueprint
859
+ * @param blueprint - Updated blueprint object
860
+ * @param forceGeneration - Force generation bump even if spec unchanged
861
+ */
862
+ async updateBlueprint(blueprint, forceGeneration = false) {
863
+ const msg = {
864
+ msgtype: "updateblueprintmsg",
865
+ blueprint,
866
+ forcegeneration: forceGeneration
867
+ };
868
+ return this.sendRPC(this.createRPCMsg(msg));
869
+ }
870
+ /**
871
+ * Remove a blueprint
872
+ * @param colonyName - Name of the colony (namespace)
873
+ * @param name - Name of the blueprint to remove
874
+ */
875
+ async removeBlueprint(colonyName, name) {
876
+ const msg = {
877
+ msgtype: "removeblueprintmsg",
878
+ namespace: colonyName,
879
+ name
880
+ };
881
+ await this.sendRPC(this.createRPCMsg(msg));
882
+ }
883
+ /**
884
+ * Update blueprint status (current state)
885
+ * @param colonyName - Name of the colony
886
+ * @param name - Name of the blueprint
887
+ * @param status - Status object representing current state
888
+ */
889
+ async updateBlueprintStatus(colonyName, name, status) {
890
+ const msg = {
891
+ msgtype: "updateblueprintstatusmsg",
892
+ colonyname: colonyName,
893
+ blueprintname: name,
894
+ status
895
+ };
896
+ await this.sendRPC(this.createRPCMsg(msg));
897
+ }
898
+ /**
899
+ * Trigger reconciliation for a blueprint
900
+ * @param colonyName - Name of the colony (namespace)
901
+ * @param name - Name of the blueprint
902
+ * @param force - Force reconciliation even if no changes detected
903
+ */
904
+ async reconcileBlueprint(colonyName, name, force = false) {
905
+ const msg = {
906
+ msgtype: "reconcileblueprintmsg",
907
+ namespace: colonyName,
908
+ name,
909
+ force
910
+ };
911
+ return this.sendRPC(this.createRPCMsg(msg));
912
+ }
913
+ /**
914
+ * Subscribe to process state changes using WebSocket
915
+ * Use this to wait for a process to be assigned (RUNNING state) before subscribing to channels
916
+ * @param colonyName - Name of the colony
917
+ * @param processId - ID of the process to watch
918
+ * @param state - Target state to wait for (0=WAITING, 1=RUNNING, 2=SUCCESS, 3=FAILED)
919
+ * @param timeout - Timeout in seconds for the subscription
920
+ * @param onProcess - Callback when process reaches the target state
921
+ * @param onError - Callback for errors
922
+ * @param onClose - Callback when connection closes
923
+ * @returns WebSocket instance for cleanup
924
+ */
925
+ subscribeProcess(colonyName, processId, state, timeout, onProcess, onError, onClose) {
926
+ if (!this.privateKey) {
927
+ throw new Error("Private key not set. Call setPrivateKey() first.");
928
+ }
929
+ const wsProtocol = this.tls ? "wss" : "ws";
930
+ const wsUrl = `${wsProtocol}://${this.host}:${this.port}/pubsub`;
931
+ const ws = new WebSocket(wsUrl);
932
+ ws.onopen = () => {
933
+ const msg = {
934
+ msgtype: "subscribeprocessmsg",
935
+ colonyname: colonyName,
936
+ processid: processId,
937
+ executortype: "",
938
+ state,
939
+ timeout
940
+ };
941
+ const rpcMsg = this.createRPCMsg(msg);
942
+ ws.send(JSON.stringify(rpcMsg));
943
+ };
944
+ ws.onmessage = (event) => {
945
+ try {
946
+ const rpcReply = JSON.parse(event.data);
947
+ if (rpcReply.error) {
948
+ const errorPayload = JSON.parse(decodeBase64Utf8(rpcReply.payload));
949
+ onError(new Error(errorPayload.message || "WebSocket error"));
950
+ return;
951
+ }
952
+ const process = JSON.parse(decodeBase64Utf8(rpcReply.payload));
953
+ onProcess(process);
954
+ } catch (err) {
955
+ onError(err instanceof Error ? err : new Error(String(err)));
956
+ }
957
+ };
958
+ ws.onerror = () => {
959
+ onError(new Error("WebSocket connection error"));
960
+ };
961
+ ws.onclose = () => {
962
+ onClose();
963
+ };
964
+ return ws;
965
+ }
966
+ };
967
+ // Annotate the CommonJS export names for ESM import in node:
968
+ 0 && (module.exports = {
969
+ ColoniesClient,
970
+ Crypto,
971
+ ProcessState,
972
+ deriveId,
973
+ generatePrivateKey,
974
+ sign
975
+ });
976
+ //# sourceMappingURL=index.js.map