relayx-js 1.0.18 → 1.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/.claude/settings.local.json +19 -0
- package/LICENSE +9 -0
- package/README.md +121 -183
- package/examples/example_chat.js +95 -9
- package/examples/example_send_data_on_connect.js +6 -3
- package/package.json +6 -3
- package/realtime/kv_storage.js +196 -0
- package/realtime/models/message.js +26 -0
- package/realtime/queue.js +653 -0
- package/realtime/realtime.js +196 -143
- package/realtime/utils.js +114 -0
- package/tests/test_kv.js +679 -0
- package/tests/test_queue.js +568 -0
- package/tests/test.js +0 -685
package/realtime/realtime.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { connect, JSONCodec, Events, DebugEvents, AckPolicy, ReplayPolicy, credsAuthenticator } from "nats";
|
|
2
|
-
import { DeliverPolicy, jetstream } from "@nats-io/jetstream";
|
|
2
|
+
import { DeliverPolicy, jetstream, jetstreamManager } from "@nats-io/jetstream";
|
|
3
3
|
import { encode, decode } from "@msgpack/msgpack";
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
5
|
import { initDNSSpoof } from "./dns_change.js";
|
|
6
|
+
import { Queue } from "./queue.js";
|
|
7
|
+
import { ErrorLogging } from "./utils.js";
|
|
8
|
+
import { KVStore } from "./kv_storage.js";
|
|
6
9
|
|
|
7
10
|
export class Realtime {
|
|
8
11
|
|
|
@@ -11,11 +14,16 @@ export class Realtime {
|
|
|
11
14
|
#natsClient = null;
|
|
12
15
|
#codec = JSONCodec();
|
|
13
16
|
#jetstream = null;
|
|
17
|
+
#jetStreamManager = null;
|
|
14
18
|
#consumerMap = {};
|
|
15
19
|
|
|
20
|
+
#kvStore = null;
|
|
21
|
+
|
|
16
22
|
#event_func = {};
|
|
17
23
|
#topicMap = [];
|
|
18
24
|
|
|
25
|
+
#errorLogging = null;
|
|
26
|
+
|
|
19
27
|
// Status Codes
|
|
20
28
|
#RECONNECTING = "RECONNECTING";
|
|
21
29
|
#RECONNECTED = "RECONNECTED";
|
|
@@ -71,56 +79,17 @@ export class Realtime {
|
|
|
71
79
|
/*
|
|
72
80
|
Initializes library with configuration options.
|
|
73
81
|
*/
|
|
74
|
-
async init(
|
|
75
|
-
|
|
76
|
-
* Method can take in 2 variables
|
|
77
|
-
* @param{boolean} staging - Sets URL to staging or production URL
|
|
78
|
-
* @param{Object} opts - Library configuration options
|
|
79
|
-
*/
|
|
80
|
-
var len = arguments.length;
|
|
81
|
-
|
|
82
|
-
if (len > 2){
|
|
83
|
-
new Error("Method takes only 2 variables, " + len + " given");
|
|
84
|
-
}
|
|
82
|
+
async init(data){
|
|
83
|
+
this.#errorLogging = new ErrorLogging();
|
|
85
84
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
staging = arguments[0];
|
|
89
|
-
}else{
|
|
90
|
-
staging = false;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if(arguments[1] instanceof Object){
|
|
94
|
-
opts = arguments[1];
|
|
95
|
-
}else{
|
|
96
|
-
opts = {};
|
|
97
|
-
}
|
|
98
|
-
}else if(len == 1){
|
|
99
|
-
if(arguments[0] instanceof Object){
|
|
100
|
-
opts = arguments[0];
|
|
101
|
-
staging = false;
|
|
102
|
-
}else if(typeof arguments[0] == "boolean"){
|
|
103
|
-
opts = {};
|
|
104
|
-
staging = arguments[0];
|
|
105
|
-
this.#log(staging)
|
|
106
|
-
}else{
|
|
107
|
-
opts = {};
|
|
108
|
-
staging = false
|
|
109
|
-
}
|
|
110
|
-
}else{
|
|
111
|
-
staging = false;
|
|
112
|
-
opts = {};
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
this.staging = staging;
|
|
116
|
-
this.opts = opts;
|
|
85
|
+
this.staging = this.#checkVarOk(data.staging) && typeof data.staging == "boolean" ? data.staging : false;
|
|
86
|
+
this.opts = data.opts;
|
|
117
87
|
|
|
118
88
|
if(process.env.PROXY){
|
|
119
89
|
this.#baseUrl = ["tls://api2.relay-x.io:8666"];
|
|
120
90
|
initDNSSpoof();
|
|
121
91
|
}else{
|
|
122
|
-
|
|
123
|
-
this.#baseUrl = staging ? [
|
|
92
|
+
this.#baseUrl = this.staging ? [
|
|
124
93
|
"nats://0.0.0.0:4221",
|
|
125
94
|
"nats://0.0.0.0:4222",
|
|
126
95
|
"nats://0.0.0.0:4223",
|
|
@@ -130,17 +99,10 @@ export class Realtime {
|
|
|
130
99
|
`tls://api.relay-x.io:4222`,
|
|
131
100
|
`tls://api.relay-x.io:4223`
|
|
132
101
|
];
|
|
133
|
-
}else{
|
|
134
|
-
this.#baseUrl = [
|
|
135
|
-
`tls://api.relay-x.io:4221`,
|
|
136
|
-
`tls://api.relay-x.io:4222`,
|
|
137
|
-
`tls://api.relay-x.io:4223`
|
|
138
|
-
];
|
|
139
|
-
}
|
|
140
102
|
}
|
|
141
103
|
|
|
142
104
|
this.#log(this.#baseUrl);
|
|
143
|
-
this.#log(opts);
|
|
105
|
+
this.#log(this.opts);
|
|
144
106
|
}
|
|
145
107
|
|
|
146
108
|
/**
|
|
@@ -199,14 +161,23 @@ export class Realtime {
|
|
|
199
161
|
});
|
|
200
162
|
|
|
201
163
|
this.#jetstream = await jetstream(this.#natsClient);
|
|
164
|
+
this.#jetStreamManager = await jetstreamManager(this.#natsClient)
|
|
202
165
|
|
|
203
166
|
await this.#getNameSpace()
|
|
204
167
|
|
|
205
168
|
this.connected = true;
|
|
206
169
|
this.#connectCalled = true;
|
|
207
170
|
}catch(err){
|
|
208
|
-
this.#
|
|
209
|
-
|
|
171
|
+
this.#errorLogging.logError({
|
|
172
|
+
err: err
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
// Callback on client side
|
|
176
|
+
if (CONNECTED in this.#event_func){
|
|
177
|
+
if (this.#event_func[CONNECTED] !== null || this.#event_func[CONNECTED] !== undefined){
|
|
178
|
+
this.#event_func[CONNECTED](false)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
210
181
|
|
|
211
182
|
this.connected = false;
|
|
212
183
|
}
|
|
@@ -231,54 +202,56 @@ export class Realtime {
|
|
|
231
202
|
|
|
232
203
|
(async () => {
|
|
233
204
|
for await (const s of this.#natsClient.status()) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
205
|
+
switch (s.type) {
|
|
206
|
+
case Events.Disconnect:
|
|
207
|
+
this.#log(`client disconnected - ${s.data}`);
|
|
208
|
+
|
|
209
|
+
this.connected = false;
|
|
210
|
+
break;
|
|
211
|
+
case Events.LDM:
|
|
212
|
+
this.#log("client has been requested to reconnect");
|
|
213
|
+
break;
|
|
214
|
+
case Events.Update:
|
|
215
|
+
this.#log(`client received a cluster update - `);
|
|
216
|
+
this.#log(s.data)
|
|
217
|
+
break;
|
|
218
|
+
case Events.Reconnect:
|
|
219
|
+
this.#log(`client reconnected -`);
|
|
220
|
+
this.#log(s.data)
|
|
221
|
+
|
|
222
|
+
this.reconnecting = false;
|
|
223
|
+
this.connected = true;
|
|
224
|
+
|
|
225
|
+
if(RECONNECT in this.#event_func){
|
|
226
|
+
this.#event_func[RECONNECT](this.#RECONNECTED);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Resend any messages sent while client was offline
|
|
230
|
+
this.#publishMessagesOnReconnect();
|
|
231
|
+
break;
|
|
232
|
+
case Events.Error:
|
|
233
|
+
if(s.data == "NATS_PROTOCOL_ERR"){
|
|
234
|
+
console.log("User kicked off network by account admin!")
|
|
235
|
+
|
|
236
|
+
await this.#natsClient.close();
|
|
237
|
+
}
|
|
238
|
+
break;
|
|
239
|
+
case DebugEvents.Reconnecting:
|
|
240
|
+
this.#log("client is attempting to reconnect");
|
|
241
|
+
|
|
242
|
+
this.reconnecting = true;
|
|
243
|
+
this.connected = false;
|
|
244
|
+
|
|
245
|
+
if(RECONNECT in this.#event_func && this.reconnecting){
|
|
246
|
+
this.#event_func[RECONNECT](this.#RECONNECTING);
|
|
247
|
+
}
|
|
248
|
+
break;
|
|
249
|
+
case DebugEvents.StaleConnection:
|
|
250
|
+
this.#log("client has a stale connection");
|
|
251
|
+
break;
|
|
252
|
+
// default:
|
|
253
|
+
// this.#log(`got an unknown status ${s.type}`);
|
|
254
|
+
}
|
|
282
255
|
}
|
|
283
256
|
})().then();
|
|
284
257
|
|
|
@@ -289,7 +262,7 @@ export class Realtime {
|
|
|
289
262
|
// Callback on client side
|
|
290
263
|
if (CONNECTED in this.#event_func){
|
|
291
264
|
if (this.#event_func[CONNECTED] !== null || this.#event_func[CONNECTED] !== undefined){
|
|
292
|
-
this.#event_func[CONNECTED]()
|
|
265
|
+
this.#event_func[CONNECTED](true)
|
|
293
266
|
}
|
|
294
267
|
}
|
|
295
268
|
}
|
|
@@ -320,7 +293,15 @@ export class Realtime {
|
|
|
320
293
|
async #subscribeToTopics(){
|
|
321
294
|
this.#topicMap.forEach(async (topic) => {
|
|
322
295
|
// Subscribe to stream
|
|
323
|
-
|
|
296
|
+
try{
|
|
297
|
+
await this.#startConsumer(topic);
|
|
298
|
+
}catch(err){
|
|
299
|
+
this.#errorLogging.logError({
|
|
300
|
+
err: err,
|
|
301
|
+
topic: topic,
|
|
302
|
+
op: "subscribe"
|
|
303
|
+
})
|
|
304
|
+
}
|
|
324
305
|
});
|
|
325
306
|
}
|
|
326
307
|
|
|
@@ -395,7 +376,15 @@ export class Realtime {
|
|
|
395
376
|
|
|
396
377
|
if(this.connected){
|
|
397
378
|
// Connected we need to create a topic in a stream
|
|
398
|
-
|
|
379
|
+
try{
|
|
380
|
+
await this.#startConsumer(topic);
|
|
381
|
+
}catch(err){
|
|
382
|
+
this.#errorLogging.logError({
|
|
383
|
+
err: err,
|
|
384
|
+
topic: topic,
|
|
385
|
+
op: "subscribe"
|
|
386
|
+
})
|
|
387
|
+
}
|
|
399
388
|
}
|
|
400
389
|
}
|
|
401
390
|
|
|
@@ -434,7 +423,6 @@ export class Realtime {
|
|
|
434
423
|
var messageId = crypto.randomUUID();
|
|
435
424
|
|
|
436
425
|
var message = {
|
|
437
|
-
"client_id": this.#getClientId(),
|
|
438
426
|
"id": messageId,
|
|
439
427
|
"room": topic,
|
|
440
428
|
"message": data,
|
|
@@ -447,12 +435,22 @@ export class Realtime {
|
|
|
447
435
|
|
|
448
436
|
this.#log(`Publishing to topic => ${this.#getStreamTopic(topic)}`)
|
|
449
437
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
438
|
+
var ack = null;
|
|
439
|
+
|
|
440
|
+
try{
|
|
441
|
+
ack = await this.#jetstream.publish(this.#getStreamTopic(topic), encodedMessage);
|
|
442
|
+
this.#log(`Publish Ack =>`)
|
|
443
|
+
this.#log(ack)
|
|
444
|
+
|
|
445
|
+
var latency = Date.now() - start;
|
|
446
|
+
this.#log(`Latency => ${latency} ms`);
|
|
447
|
+
}catch(err){
|
|
448
|
+
this.#errorLogging.logError({
|
|
449
|
+
err: err,
|
|
450
|
+
topic: topic,
|
|
451
|
+
op: "publish"
|
|
452
|
+
})
|
|
453
|
+
}
|
|
456
454
|
|
|
457
455
|
return ack !== null && ack !== undefined;
|
|
458
456
|
}else{
|
|
@@ -511,7 +509,7 @@ export class Realtime {
|
|
|
511
509
|
}
|
|
512
510
|
|
|
513
511
|
var opts = {
|
|
514
|
-
name:
|
|
512
|
+
name: `nodejs_${topic}_${uuidv4()}_history_consumer`,
|
|
515
513
|
filter_subjects: [this.#getStreamTopic(topic)],
|
|
516
514
|
replay_policy: ReplayPolicy.Instant,
|
|
517
515
|
opt_start_time: start,
|
|
@@ -597,11 +595,11 @@ export class Realtime {
|
|
|
597
595
|
* @param {string} topic
|
|
598
596
|
*/
|
|
599
597
|
async #startConsumer(topic){
|
|
600
|
-
const consumerName =
|
|
598
|
+
const consumerName = `nodejs_${uuidv4()}_consumer`;
|
|
601
599
|
|
|
602
600
|
var opts = {
|
|
603
601
|
name: consumerName,
|
|
604
|
-
filter_subjects:
|
|
602
|
+
filter_subjects: this.#getStreamTopic(topic),
|
|
605
603
|
replay_policy: ReplayPolicy.Instant,
|
|
606
604
|
opt_start_time: new Date(),
|
|
607
605
|
ack_policy: AckPolicy.Explicit,
|
|
@@ -609,7 +607,6 @@ export class Realtime {
|
|
|
609
607
|
}
|
|
610
608
|
|
|
611
609
|
const consumer = await this.#jetstream.consumers.get(this.#getStreamName(), opts);
|
|
612
|
-
this.#log(this.#topicMap)
|
|
613
610
|
|
|
614
611
|
this.#consumerMap[topic] = consumer;
|
|
615
612
|
|
|
@@ -626,16 +623,14 @@ export class Realtime {
|
|
|
626
623
|
this.#log(data);
|
|
627
624
|
|
|
628
625
|
// Push topic message to main thread
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
});
|
|
638
|
-
}
|
|
626
|
+
var topicMatch = this.#topicPatternMatcher(topic, msgTopic)
|
|
627
|
+
|
|
628
|
+
if(topicMatch){
|
|
629
|
+
this.#event_func[topic]({
|
|
630
|
+
"id": data.id,
|
|
631
|
+
"topic": msgTopic,
|
|
632
|
+
"data": data.message
|
|
633
|
+
});
|
|
639
634
|
}
|
|
640
635
|
|
|
641
636
|
msg.ack();
|
|
@@ -647,7 +642,8 @@ export class Realtime {
|
|
|
647
642
|
}
|
|
648
643
|
}
|
|
649
644
|
});
|
|
650
|
-
|
|
645
|
+
|
|
646
|
+
this.#log("Consumer is consuming => " + topic);
|
|
651
647
|
}
|
|
652
648
|
|
|
653
649
|
async #deleteConsumer(topic){
|
|
@@ -711,6 +707,51 @@ export class Realtime {
|
|
|
711
707
|
}
|
|
712
708
|
}
|
|
713
709
|
|
|
710
|
+
// Queue Functions
|
|
711
|
+
async initQueue(queueID){
|
|
712
|
+
if(!this.connected){
|
|
713
|
+
this.#log("Not connected to relayX network. Skipping queue init")
|
|
714
|
+
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
this.#log("Validating queue ID...")
|
|
719
|
+
if(queueID == undefined || queueID == null || queueID == ""){
|
|
720
|
+
throw new Error("$queueID cannot be null / undefined / empty!")
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
var queue = new Queue({
|
|
724
|
+
jetstream: this.#jetstream,
|
|
725
|
+
nats_client: this.#natsClient,
|
|
726
|
+
api_key: this.api_key,
|
|
727
|
+
debug: this.opts?.debug ? this.opts?.debug : false
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
var initResult = await queue.init(queueID);
|
|
731
|
+
|
|
732
|
+
return initResult ? queue : null;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// KV Functions
|
|
736
|
+
async initKVStore(){
|
|
737
|
+
|
|
738
|
+
if(this.#kvStore == null){
|
|
739
|
+
var debugCheck = this.opts.debug !== null && this.opts.debug !== undefined && typeof this.opts.debug == "boolean"
|
|
740
|
+
|
|
741
|
+
this.#kvStore = new KVStore({
|
|
742
|
+
namespace: this.namespace,
|
|
743
|
+
jetstream: this.#jetstream,
|
|
744
|
+
debug: debugCheck ? this.opts.debug : false
|
|
745
|
+
})
|
|
746
|
+
|
|
747
|
+
var init = await this.#kvStore.init()
|
|
748
|
+
|
|
749
|
+
return init ? this.#kvStore : null;
|
|
750
|
+
}else{
|
|
751
|
+
return this.#kvStore
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
714
755
|
// Utility functions
|
|
715
756
|
#getClientId(){
|
|
716
757
|
return this.#natsClient?.info?.client_id
|
|
@@ -801,7 +842,7 @@ export class Realtime {
|
|
|
801
842
|
|
|
802
843
|
#getStreamName(){
|
|
803
844
|
if(this.namespace != null){
|
|
804
|
-
return this.namespace
|
|
845
|
+
return `${this.namespace}_stream`
|
|
805
846
|
}else{
|
|
806
847
|
this.close();
|
|
807
848
|
throw new Error("$namespace is null. Cannot initialize program with null $namespace")
|
|
@@ -856,19 +897,6 @@ export class Realtime {
|
|
|
856
897
|
const tokA = a[i];
|
|
857
898
|
const tokB = b[j];
|
|
858
899
|
|
|
859
|
-
/*──────────── literal match or single‑token wildcard on either side ────────────*/
|
|
860
|
-
const singleWildcard =
|
|
861
|
-
(tokA === "*" && j < b.length) ||
|
|
862
|
-
(tokB === "*" && i < a.length);
|
|
863
|
-
|
|
864
|
-
if (
|
|
865
|
-
(tokA !== undefined && tokA === tokB) ||
|
|
866
|
-
singleWildcard
|
|
867
|
-
) {
|
|
868
|
-
i++; j++;
|
|
869
|
-
continue;
|
|
870
|
-
}
|
|
871
|
-
|
|
872
900
|
/*────────────────── multi‑token wildcard ">" — must be **final** ───────────────*/
|
|
873
901
|
if (tokA === ">") {
|
|
874
902
|
if (i !== a.length - 1) return false; // '>' not in last position → invalid
|
|
@@ -885,6 +913,19 @@ export class Realtime {
|
|
|
885
913
|
continue;
|
|
886
914
|
}
|
|
887
915
|
|
|
916
|
+
/*──────────── literal match or single‑token wildcard on either side ────────────*/
|
|
917
|
+
const singleWildcard =
|
|
918
|
+
(tokA === "*" && j < b.length) ||
|
|
919
|
+
(tokB === "*" && i < a.length);
|
|
920
|
+
|
|
921
|
+
if (
|
|
922
|
+
(tokA !== undefined && tokA === tokB) ||
|
|
923
|
+
singleWildcard
|
|
924
|
+
) {
|
|
925
|
+
i++; j++;
|
|
926
|
+
continue;
|
|
927
|
+
}
|
|
928
|
+
|
|
888
929
|
/*───────────────────────────── back‑track using last '>' ───────────────────────*/
|
|
889
930
|
if (starAi !== -1) { // let patternA's '>' absorb one more token of B
|
|
890
931
|
j = ++starAj;
|
|
@@ -899,7 +940,7 @@ export class Realtime {
|
|
|
899
940
|
return false;
|
|
900
941
|
}
|
|
901
942
|
|
|
902
|
-
return true;
|
|
943
|
+
return true;
|
|
903
944
|
}
|
|
904
945
|
|
|
905
946
|
sleep(ms) {
|
|
@@ -984,6 +1025,10 @@ ${secret}
|
|
|
984
1025
|
*************************************************************`
|
|
985
1026
|
}
|
|
986
1027
|
|
|
1028
|
+
#checkVarOk(variable){
|
|
1029
|
+
return variable !== null && variable !== undefined
|
|
1030
|
+
}
|
|
1031
|
+
|
|
987
1032
|
// Exposure for tests
|
|
988
1033
|
testRetryTillSuccess(){
|
|
989
1034
|
if(process.env.NODE_ENV == "test"){
|
|
@@ -1048,6 +1093,14 @@ ${secret}
|
|
|
1048
1093
|
return null;
|
|
1049
1094
|
}
|
|
1050
1095
|
}
|
|
1096
|
+
|
|
1097
|
+
testGetJetstream(){
|
|
1098
|
+
if(process.env.NODE_ENV == "test"){
|
|
1099
|
+
return this.#jetstream;
|
|
1100
|
+
}else{
|
|
1101
|
+
return null;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1051
1104
|
}
|
|
1052
1105
|
|
|
1053
1106
|
export const CONNECTED = "CONNECTED";
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { JetStreamApiError, JetStreamError } from "@nats-io/jetstream";
|
|
2
|
+
import NatsError from "nats"
|
|
3
|
+
|
|
4
|
+
export class ErrorLogging {
|
|
5
|
+
|
|
6
|
+
logError(data){
|
|
7
|
+
var err = data.err;
|
|
8
|
+
|
|
9
|
+
if(err instanceof JetStreamApiError){
|
|
10
|
+
var code = err.code;
|
|
11
|
+
|
|
12
|
+
if(code == 10077){
|
|
13
|
+
// Code 10077 is for message limit exceeded
|
|
14
|
+
console.table({
|
|
15
|
+
Event: "Message Limit Exceeded",
|
|
16
|
+
Description: "Current message count for account exceeds plan defined limits. Upgrade plan to remove limits",
|
|
17
|
+
Link: "https://console.relay-x.io/billing"
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
throw new Error("Message limit exceeded!")
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if(err instanceof JetStreamError){
|
|
25
|
+
var code = err.code;
|
|
26
|
+
|
|
27
|
+
if(code == 409){
|
|
28
|
+
// Consumer deleted
|
|
29
|
+
|
|
30
|
+
console.table({
|
|
31
|
+
Event: "Consumer Manually Deleted!",
|
|
32
|
+
Description: "Consumer was manually deleted by user using deleteConsumer() or the library equivalent",
|
|
33
|
+
"Docs to Solve Issue": "https://docs.relay-x.io/docs/detailed_doc/NodeJS/queue_consume#deleting-a-consumer"
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if(err.name == "NatsError"){
|
|
39
|
+
var code = err.code;
|
|
40
|
+
var chainedError = err.chainedError;
|
|
41
|
+
var permissionContext = err.permissionContext;
|
|
42
|
+
var userOp = data.op;
|
|
43
|
+
|
|
44
|
+
if(code == "PERMISSIONS_VIOLATION"){
|
|
45
|
+
if(userOp == "publish"){
|
|
46
|
+
console.table({
|
|
47
|
+
Event: "Publish Permissions Violation",
|
|
48
|
+
Description: `User is not permitted to publish on '${data.topic}'`,
|
|
49
|
+
Topic: data.topic,
|
|
50
|
+
"Docs to Solve Issue": "https://docs.relay-x.io/docs/setup/api_key_permissions#messaging--publish-permissions"
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
throw new Error(`User is not permitted to publish on '${data.topic}'`)
|
|
54
|
+
}else if(userOp == "subscribe"){
|
|
55
|
+
console.table({
|
|
56
|
+
Event: "Subscribe Permissions Violation",
|
|
57
|
+
Description: `User is not permitted to subscribe to '${data.topic}'`,
|
|
58
|
+
Topic: data.topic,
|
|
59
|
+
"Docs to Solve Issue": "https://docs.relay-x.io/docs/setup/api_key_permissions#messaging--subscribe-permissions"
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
throw new Error(`User is not permitted to subscribe to '${data.topic}'`)
|
|
63
|
+
}else if(userOp == "kv_write"){
|
|
64
|
+
console.table({
|
|
65
|
+
Event: "KV Write Failure",
|
|
66
|
+
Description: `User is not permitted to write to KV Store`,
|
|
67
|
+
"Docs to Solve Issue": "https://docs.relay-x.io/docs/setup/api_key_permissions#write-permission"
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
throw new Error(`User is not permitted to write to KV Store`)
|
|
71
|
+
}else if(userOp == "kv_read"){
|
|
72
|
+
console.table({
|
|
73
|
+
Event: "KV Read Failure",
|
|
74
|
+
Description: `User is not permitted to read from KV Store`,
|
|
75
|
+
"Docs to Solve Issue": "https://docs.relay-x.io/docs/setup/api_key_permissions#read-permission"
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
throw new Error(`User is not permitted to read from KV Store`)
|
|
79
|
+
}else if(userOp == "kv_delete"){
|
|
80
|
+
console.table({
|
|
81
|
+
Event: "KV Key Delete Failure",
|
|
82
|
+
Description: `User is not permitted to delete key from KV Store`,
|
|
83
|
+
"Docs to Solve Issue": "https://docs.relay-x.io/docs/setup/api_key_permissions#write-permission"
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
throw new Error(`User is not permitted to delete key from KV Store`)
|
|
87
|
+
}
|
|
88
|
+
}else if(code == "AUTHORIZATION_VIOLATION"){
|
|
89
|
+
console.table({
|
|
90
|
+
Event: "Authentication Failure",
|
|
91
|
+
Description: `User failed to authenticate. Check if API key exists & if it is enabled`,
|
|
92
|
+
"Docs to Solve Issue": "https://docs.relay-x.io/docs/setup/api_key_permissions#enabling-and-disabling-keys"
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export class Logging {
|
|
101
|
+
|
|
102
|
+
#debug = false;
|
|
103
|
+
|
|
104
|
+
constructor(debug){
|
|
105
|
+
this.#debug = debug !== null && debug !== undefined && typeof debug == "boolean" ? debug : false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
log(...msg){
|
|
109
|
+
if(this.#debug){
|
|
110
|
+
console.log(...msg)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
}
|