relayx-js 1.0.14 → 1.0.15

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.
@@ -0,0 +1,51 @@
1
+ # Sample workflow for building and deploying a Jekyll site to GitHub Pages
2
+ name: Deploy Jekyll with GitHub Pages dependencies preinstalled
3
+
4
+ on:
5
+ # Runs on pushes targeting the default branch
6
+ push:
7
+ branches: ["main"]
8
+
9
+ # Allows you to run this workflow manually from the Actions tab
10
+ workflow_dispatch:
11
+
12
+ # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
13
+ permissions:
14
+ contents: read
15
+ pages: write
16
+ id-token: write
17
+
18
+ # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
19
+ # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
20
+ concurrency:
21
+ group: "pages"
22
+ cancel-in-progress: false
23
+
24
+ jobs:
25
+ # Build job
26
+ build:
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - name: Checkout
30
+ uses: actions/checkout@v4
31
+ - name: Setup Pages
32
+ uses: actions/configure-pages@v5
33
+ - name: Build with Jekyll
34
+ uses: actions/jekyll-build-pages@v1
35
+ with:
36
+ source: ./
37
+ destination: ./_site
38
+ - name: Upload artifact
39
+ uses: actions/upload-pages-artifact@v3
40
+
41
+ # Deployment job
42
+ deploy:
43
+ environment:
44
+ name: github-pages
45
+ url: ${{ steps.deployment.outputs.page_url }}
46
+ runs-on: ubuntu-latest
47
+ needs: build
48
+ steps:
49
+ - name: Deploy to GitHub Pages
50
+ id: deployment
51
+ uses: actions/deploy-pages@v4
package/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ V1.0.15
2
+ - Wildcard topic pub / sub
3
+ - Message replay on reconnect
4
+
1
5
  V1.0.8
2
6
  - History API fetch() to consume()
3
7
 
@@ -11,7 +11,7 @@ async function run(){
11
11
  api_key: process.env.AUTH_JWT,
12
12
  secret: process.env.AUTH_SECRET
13
13
  });
14
- await realtime.init(true, {
14
+ await realtime.init(false, {
15
15
  max_retries: 2,
16
16
  debug: true
17
17
  });
@@ -32,8 +32,8 @@ async function run(){
32
32
  console.log("power-telemetry", data);
33
33
  });
34
34
 
35
- await realtime.on("test232", (data) => {
36
- console.log("test232", data);
35
+ await realtime.on("hello.*", (data) => {
36
+ console.log("hello.*", data);
37
37
  });
38
38
 
39
39
  realtime.on(MESSAGE_RESEND, (data) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relayx-js",
3
- "version": "1.0.14",
3
+ "version": "1.0.15",
4
4
  "main": "realtime/realtime.js",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -0,0 +1,20 @@
1
+ import dns from 'node:dns';
2
+
3
+ export function initDNSSpoof(){
4
+ const originalLookup = dns.lookup;
5
+
6
+ // Override for the whole process
7
+ dns.lookup = function patchedLookup(hostname, options, callback) {
8
+
9
+ // ── Our one special case ──────────────────────────────────
10
+ if (hostname === 'api2.relay-x.io') {
11
+ // Map to loop‑back; family 4 avoids ::1
12
+ return process.nextTick(() =>
13
+ callback(null, [{address: '127.0.0.1', family: 4}])
14
+ );
15
+ }
16
+
17
+ // Anything else → real DNS
18
+ return originalLookup.call(dns, hostname, options, callback);
19
+ };
20
+ }
@@ -2,6 +2,7 @@ import { connect, JSONCodec, Events, DebugEvents, AckPolicy, ReplayPolicy, creds
2
2
  import { DeliverPolicy, jetstream } from "@nats-io/jetstream";
3
3
  import { encode, decode } from "@msgpack/msgpack";
4
4
  import { v4 as uuidv4 } from 'uuid';
5
+ import { initDNSSpoof } from "./dns_change.js";
5
6
 
6
7
  export class Realtime {
7
8
 
@@ -109,23 +110,28 @@ export class Realtime {
109
110
  this.staging = staging;
110
111
  this.opts = opts;
111
112
 
112
- if (staging !== undefined || staging !== null){
113
- this.#baseUrl = staging ? [
114
- "nats://0.0.0.0:4221",
115
- "nats://0.0.0.0:4222",
116
- "nats://0.0.0.0:4223"
117
- ] :
118
- [
113
+ if(process.env.PROXY){
114
+ this.#baseUrl = ["tls://api2.relay-x.io:8666"];
115
+ initDNSSpoof();
116
+ }else{
117
+ if (staging !== undefined || staging !== null){
118
+ this.#baseUrl = staging ? [
119
+ "nats://0.0.0.0:4221",
120
+ "nats://0.0.0.0:4222",
121
+ "nats://0.0.0.0:4223",
122
+ ] :
123
+ [
124
+ `tls://api2.relay-x.io:4221`,
125
+ `tls://api2.relay-x.io:4222`,
126
+ `tls://api2.relay-x.io:4223`
127
+ ];
128
+ }else{
129
+ this.#baseUrl = [
119
130
  `tls://api.relay-x.io:4221`,
120
131
  `tls://api.relay-x.io:4222`,
121
132
  `tls://api.relay-x.io:4223`
122
133
  ];
123
- }else{
124
- this.#baseUrl = [
125
- `tls://api.relay-x.io:4221`,
126
- `tls://api.relay-x.io:4222`,
127
- `tls://api.relay-x.io:4223`
128
- ];
134
+ }
129
135
  }
130
136
 
131
137
  this.#log(this.#baseUrl);
@@ -180,6 +186,7 @@ export class Realtime {
180
186
  reconnectTimeWait: 1000,
181
187
  authenticator: credsAuth,
182
188
  token: this.api_key,
189
+ resolve: process.env.PROXY ? false : true
183
190
  });
184
191
 
185
192
  this.#jetstream = await jetstream(this.#natsClient);
@@ -574,7 +581,7 @@ export class Realtime {
574
581
 
575
582
  var opts = {
576
583
  name: `${topic}_${uuidv4()}`,
577
- filter_subjects: [this.#getStreamTopic(topic), this.#getStreamTopic(topic) + "_presence"],
584
+ filter_subjects: [this.#getStreamTopic(topic)],
578
585
  replay_policy: ReplayPolicy.Instant,
579
586
  opt_start_time: new Date(),
580
587
  ack_policy: AckPolicy.Explicit,
@@ -664,7 +671,7 @@ export class Realtime {
664
671
  this.#latencyPush = setTimeout(async () => {
665
672
  this.#log("setTimeout called");
666
673
 
667
- if(this.#latency.length > 0){
674
+ if(this.#latency.length > 0 && this.connected){
668
675
  this.#log("Push from setTimeout")
669
676
  await this.#pushLatencyData({
670
677
  timezone: timeZone,
@@ -736,7 +743,9 @@ export class Realtime {
736
743
  var arrayCheck = ![CONNECTED, DISCONNECTED, RECONNECT, this.#RECONNECTED,
737
744
  this.#RECONNECTING, this.#RECONN_FAIL, MESSAGE_RESEND, SERVER_DISCONNECT].includes(topic);
738
745
 
739
- var spaceStarCheck = !topic.includes(" ") && !topic.includes("*") && !topic.includes(".");
746
+ const TOPIC_REGEX = /^(?!\$)[A-Za-z0-9_,.*>\$-]+$/;
747
+
748
+ var spaceStarCheck = !topic.includes(" ") && TOPIC_REGEX.test(topic);
740
749
 
741
750
  return arrayCheck && spaceStarCheck;
742
751
  }else{
package/tests/test.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { Realtime, CONNECTED, RECONNECT, DISCONNECTED, MESSAGE_RESEND } from "../realtime/realtime.js";
2
- import axios from "axios";
3
2
  import { test, before, after } from 'node:test';
4
3
  import assert from 'node:assert';
5
4
 
@@ -8,10 +7,10 @@ let realTimeEnabled;
8
7
  before(async () => {
9
8
  // Start server for testing. Run local server!!
10
9
  realTimeEnabled = new Realtime({
11
- api_key: process.env.user_key,
12
- secret: process.env.secret
10
+ api_key: process.env.AUTH_JWT,
11
+ secret: process.env.AUTH_SECRET
13
12
  });
14
- await realTimeEnabled.init(true, {
13
+ await realTimeEnabled.init(false, {
15
14
  debug: true
16
15
  });
17
16
  await realTimeEnabled.connect();
@@ -55,8 +54,8 @@ test("No creds in constructor", async () => {
55
54
 
56
55
  test('init() function test', async () => {
57
56
  var realtime = new Realtime({
58
- api_key: process.env.user_key,
59
- secret: process.env.secret
57
+ api_key: process.env.AUTH_JWT,
58
+ secret: process.env.AUTH_SECRET
60
59
  });
61
60
  await realtime.init(true);
62
61
 
@@ -119,37 +118,10 @@ test("Namespace check test", async () => {
119
118
  assert.strictEqual(realTimeEnabled.topicHash.length > 0, true)
120
119
  });
121
120
 
122
- test("Retry method test", async () => {
123
- var retryMethod = realTimeEnabled.testRetryTillSuccess();
124
-
125
- assert.notStrictEqual(retryMethod, null, "Obj != null")
126
-
127
- function testMethod1(arg){
128
- return {
129
- success: true,
130
- output: arg
131
- }
132
- }
133
-
134
- var output = await retryMethod(testMethod1, 5, 1, "test_output")
135
-
136
- assert.strictEqual(output, "test_output");
137
-
138
- function testMethod2(){
139
- return {
140
- success: false,
141
- output: null
142
- }
143
- }
144
-
145
- output = await retryMethod(testMethod2, 5, 1);
146
- assert.strictEqual(output, null);
147
- });
148
-
149
121
  test("get publish retry count test based in init()", async () => {
150
122
  var realtime = new Realtime({
151
- api_key: process.env.user_key,
152
- secret: process.env.secret
123
+ api_key: process.env.AUTH_JWT,
124
+ secret: process.env.AUTH_SECRET
153
125
  });
154
126
 
155
127
  await realtime.init({
@@ -199,6 +171,60 @@ test("Testing publish(topic, data) method", async () => {
199
171
  });
200
172
 
201
173
  assert.strictEqual(response, true);
174
+
175
+ response = await realTimeEnabled.publish("hello.hey", {
176
+ message: "Hello World!"
177
+ });
178
+
179
+ assert.strictEqual(response, true);
180
+
181
+ response = await realTimeEnabled.publish("hello.*", {
182
+ message: "Hello World!"
183
+ });
184
+
185
+ assert.strictEqual(response, true);
186
+
187
+ response = await realTimeEnabled.publish("hello.>", {
188
+ message: "Hello World!"
189
+ });
190
+
191
+ assert.strictEqual(response, true);
192
+
193
+ response = await realTimeEnabled.publish("test-room", {
194
+ message: "Hello World!"
195
+ });
196
+
197
+ assert.strictEqual(response, true);
198
+
199
+ response = await realTimeEnabled.publish("test-room.*", {
200
+ message: "Hello World!"
201
+ });
202
+
203
+ assert.strictEqual(response, true);
204
+
205
+ response = await realTimeEnabled.publish("test-room.>", {
206
+ message: "Hello World!"
207
+ });
208
+
209
+ assert.strictEqual(response, true);
210
+
211
+ response = await realTimeEnabled.publish("test_room", {
212
+ message: "Hello World!"
213
+ });
214
+
215
+ assert.strictEqual(response, true);
216
+
217
+ response = await realTimeEnabled.publish("test_room.*", {
218
+ message: "Hello World!"
219
+ });
220
+
221
+ assert.strictEqual(response, true);
222
+
223
+ response = await realTimeEnabled.publish("test_room.>", {
224
+ message: "Hello World!"
225
+ });
226
+
227
+ assert.strictEqual(response, true);
202
228
  });
203
229
 
204
230
  test("Testing publish(topic, data) with invalid inputs", async () => {
@@ -271,8 +297,8 @@ test("Testing publish(topic, data) with invalid inputs", async () => {
271
297
 
272
298
  test("on() test", async () => {
273
299
  var realtime = new Realtime({
274
- api_key: process.env.user_key,
275
- secret: process.env.secret
300
+ api_key: process.env.AUTH_JWT,
301
+ secret: process.env.AUTH_SECRET
276
302
  });
277
303
 
278
304
  await assert.rejects(async () => {
@@ -349,8 +375,8 @@ test("on() test", async () => {
349
375
 
350
376
  test("off() test", async () => {
351
377
  var realtime = new Realtime({
352
- api_key: process.env.user_key,
353
- secret: process.env.secret
378
+ api_key: process.env.AUTH_JWT,
379
+ secret: process.env.AUTH_SECRET
354
380
  });
355
381
 
356
382
  await assert.rejects(async () => {
@@ -397,8 +423,8 @@ test("off() test", async () => {
397
423
 
398
424
  test("Get stream name test", () => {
399
425
  var realtime = new Realtime({
400
- api_key: process.env.user_key,
401
- secret: process.env.secret
426
+ api_key: process.env.AUTH_JWT,
427
+ secret: process.env.AUTH_SECRET
402
428
  });
403
429
 
404
430
  realtime.namespace = "spacex-dragon-program"
@@ -449,7 +475,14 @@ test("Test isTopicValidMethod()", () => {
449
475
  assert.strictEqual(valid, false);
450
476
  });
451
477
 
452
- var unreservedValidTopics = ["hello", "test-room", "heyyyyy", "room-connect"];
478
+ unreservedInvalidTopics = ["$hey.hey", "orders created", ""];
479
+
480
+ unreservedInvalidTopics.forEach(topic => {
481
+ var valid = realTimeEnabled.isTopicValid(topic);
482
+ assert.strictEqual(valid, false);
483
+ });
484
+
485
+ var unreservedValidTopics = ["hello", "test-room", "heyyyyy", "room-connect", "hey$"];
453
486
 
454
487
  unreservedValidTopics.forEach(topic => {
455
488
  var valid = realTimeEnabled.isTopicValid(topic);
@@ -1,160 +0,0 @@
1
- import axios from 'axios';
2
-
3
- /**
4
- * Class responsible for getting messages stored in the DB
5
- */
6
- export class History{
7
-
8
- #api_key = null;
9
- #staging = null;
10
- #baseUrl = null;
11
- #debug = null;
12
-
13
- constructor(api_key){
14
- this.#api_key = api_key;
15
- }
16
-
17
- init(staging, debug){
18
- this.#staging = staging;
19
- this.#debug = debug;
20
-
21
- this.#setBaseUrl();
22
- }
23
-
24
- /**
25
- * Get message from DB since a $timestamp
26
- * @param {number} timestamp - unix timestamp
27
- * @param {number} page - page number of pagination
28
- * @param {number} limit - limit per page
29
- * @returns - Message array
30
- */
31
- async getMessagesSince(topic, timestamp, page, limit){
32
- if(topic == null || topic == undefined){
33
- return new Error("$topic variable missing in getMessagesSince()");
34
- }else{
35
- if(typeof topic !== "string"){
36
- return new Error("$topic is not a string");
37
- }
38
- }
39
-
40
- if(timestamp == null || timestamp == undefined){
41
- return new Error("$timestamp variable missing in getMessagesSince()");
42
- }else{
43
- if(!Number.isInteger(timestamp) && !Number.isNaN(timestamp)){
44
- return new Error("$timestamp is either NaN or not an invalid integer");
45
- }
46
- }
47
-
48
- if(page == null || page == undefined){
49
- return new Error("$page variable missing in getMessagesSince()");
50
- }else{
51
- if(!Number.isInteger(page) && !Number.isNaN(page)){
52
- return new Error("$page is either NaN or not an invalid integer");
53
- }
54
- }
55
-
56
- if(limit == null || limit == undefined){
57
- return new Error("$limit variable missing in getMessagesSince()");
58
- }else{
59
- if(!Number.isInteger(limit) && !Number.isNaN(limit)){
60
- console.log("$limit is either NaN or not an invalid integer")
61
- return new Error("$limit is either NaN or not an invalid integer");
62
- }
63
- }
64
-
65
- try{
66
- var startTime = Date.now();
67
- var urlPart = `/history/since?topic=${topic}&timestamp=${timestamp}&page=${page}&limit=${limit}`
68
-
69
- var response = await axios.get(this.#baseUrl + urlPart,{
70
- headers: {
71
- "Authorization": `Bearer ${this.#api_key}`
72
- }
73
- });
74
-
75
- var data = response.data
76
- this.#log(data);
77
-
78
- this.#logResponseTime(startTime, urlPart);
79
-
80
- if (data?.status === "SUCCESS"){
81
- return data.data;
82
- }else{
83
- return null;
84
- }
85
- }catch(err){
86
- throw Error(err.message);
87
- }
88
- }
89
-
90
- /**
91
- * Get message from DB by ID
92
- * @param {string} id - ID of the message
93
- * @returns - Message object
94
- */
95
- async getMessageById(id){
96
- var startTime = Date.now();
97
- var urlPart = `/history/message-by-id?id=${id}`;
98
-
99
- if(id !== null && id !== undefined){
100
- try{
101
- var response = await axios.get(this.#baseUrl + urlPart,{
102
- headers: {
103
- "Authorization": `Bearer ${this.#api_key}`
104
- }
105
- });
106
-
107
- var data = response.data
108
- this.#log(data);
109
-
110
- this.#logResponseTime(startTime, urlPart);
111
-
112
- if (data?.status === "SUCCESS"){
113
- return data.data;
114
- }else{
115
- return null;
116
- }
117
- }catch(err){
118
- throw new Error(err.message);
119
- }
120
- }else{
121
- return null;
122
- }
123
- }
124
-
125
- // Utility Functions
126
- /**
127
- * Constructs base url based on staging flag
128
- */
129
- #setBaseUrl(){
130
- if (this.#staging !== undefined || this.#staging !== null){
131
- this.#baseUrl = this.#staging ? "http://127.0.0.1:3000" : "http://128.199.176.185:3000";
132
- }else{
133
- this.#baseUrl = "http://128.199.176.185:3000";
134
- }
135
- }
136
-
137
- #log(msg){
138
- if(this.#debug !== null && this.#debug !== undefined && (typeof this.#debug == "boolean")){
139
- if(this.#debug){
140
- console.log(msg);
141
- }
142
- }
143
- }
144
-
145
- async #logResponseTime(startTime, url){
146
- var responseTime = Date.now() - startTime;
147
-
148
- var data = {
149
- "url": url,
150
- "response_time": responseTime
151
- }
152
-
153
- await axios.post(this.#baseUrl + "/metrics/log", data, {
154
- headers: {
155
- "Authorization": `Bearer ${this.#api_key}`
156
- }
157
- });
158
- }
159
-
160
- }
package/realtime/http.js DELETED
File without changes