geonix 1.12.3 → 1.20.1

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,25 @@
1
+ import globals from "globals";
2
+ import eslint from "@eslint/js";
3
+
4
+ export default [
5
+ eslint.configs.recommended,
6
+ {
7
+ files: ["**/*.js"],
8
+ languageOptions: {
9
+ ecmaVersion: 2022,
10
+ sourceType: "module",
11
+ globals: {
12
+ ...globals.node,
13
+ ...globals.browser,
14
+ }
15
+ },
16
+ rules: {
17
+ // "no-console": "error",
18
+ semi: "error",
19
+ "no-unused-vars": ["error", { argsIgnorePattern: "^_.*" }],
20
+ "no-constant-condition": ["error", { checkLoops: false }],
21
+ quotes: ["error", "double", { avoidEscape: true }],
22
+ "no-multiple-empty-lines": ["error", { max: 1 }]
23
+ },
24
+ }
25
+ ];
@@ -1,14 +1,14 @@
1
- import { Service } from 'geonix'
2
- import { ServeStatic } from 'geonix'
1
+ import { Service } from "geonix";
2
+ import { ServeStatic } from "geonix";
3
3
 
4
4
  class StaticServer extends Service {
5
5
 
6
6
  // simple version
7
- 'GET *' = ServeStatic('public')
7
+ "GET *" = ServeStatic("public");
8
8
 
9
9
  // in a folder
10
- 'GET /folder/*' = ServeStatic('public', { root: '/folder/' })
10
+ "GET /folder/*" = ServeStatic("public", { root: "/folder/" });
11
11
 
12
12
  }
13
13
 
14
- StaticServer.start()
14
+ StaticServer.start();
@@ -1,15 +1,15 @@
1
1
  {
2
- "name": "servicestatic",
3
- "version": "1.0.0",
4
- "description": "",
5
- "main": "index.js",
6
- "type": "module",
7
- "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1"
9
- },
10
- "author": "",
11
- "license": "ISC",
12
- "dependencies": {
13
- "geonix": "^1.0.13"
14
- }
15
- }
2
+ "name": "servicestatic",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "author": "",
11
+ "license": "ISC",
12
+ "dependencies": {
13
+ "geonix": "^1.0.13"
14
+ }
15
+ }
@@ -1,13 +1,13 @@
1
- import { Service } from 'geonix'
1
+ import { Service } from "geonix";
2
2
 
3
3
  class SimpleService extends Service {
4
4
 
5
5
  reverseString(input) {
6
- return input.split('').reverse().join('')
6
+ return input.split("").reverse().join("");
7
7
  }
8
8
 
9
- 'GET /simpleservice/reversestring'(req, res) {
10
- res.send(this.reverseString(req.query.q))
9
+ "GET /simpleservice/reversestring"(req, res) {
10
+ res.send(this.reverseString(req.query.q));
11
11
  }
12
12
 
13
13
  }
@@ -16,12 +16,12 @@ class SimpleService extends Service {
16
16
 
17
17
  class TestService extends Service {
18
18
 
19
- 'GET /test'(req, res) {
20
- console.log('rawr')
19
+ "GET /test"(req, res) {
20
+ console.log("rawr");
21
21
 
22
- res.send('ok')
22
+ res.send("ok");
23
23
  }
24
24
 
25
25
  }
26
26
 
27
- TestService.start()
27
+ TestService.start();
@@ -1,15 +1,15 @@
1
1
  {
2
- "name": "simpleservice",
3
- "version": "1.0.0",
4
- "description": "",
5
- "main": "index.js",
6
- "type": "module",
7
- "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1"
9
- },
10
- "author": "",
11
- "license": "ISC",
12
- "dependencies": {
13
- "geonix": "^1.0.16"
14
- }
15
- }
2
+ "name": "simpleservice",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "author": "",
11
+ "license": "ISC",
12
+ "dependencies": {
13
+ "geonix": "^1.0.16"
14
+ }
15
+ }
package/exports.js CHANGED
@@ -1,43 +1,14 @@
1
- import { readFile } from 'fs/promises'
2
- import semver from 'semver'
3
- import { URL, fileURLToPath } from 'url'
4
- import { join } from 'path'
5
-
6
- try {
7
- const __dirname = fileURLToPath(new URL('.', import.meta.url));
8
- const local = JSON.parse(await readFile(join(__dirname, 'package.json')))
9
- let remote = await (await fetch('https://registry.npmjs.com/-/v1/search?text=geonix')).json()
10
-
11
- if (remote?.objects?.length > 0) {
12
- remote = remote.objects[0].package
13
-
14
- _geonix_version = local.version
15
-
16
- if (semver.lt(local.version, remote.version)) {
17
- let line = `${local.version} → ${remote.version}`
18
- line = ' '.repeat(Math.floor((39 - line.length) / 2)) + line + ' '.repeat(Math.ceil((39 - line.length) / 2))
19
-
20
- console.log(`╭───────────────────────────────────────╮`)
21
- console.log(`│ Geonix update available │`)
22
- console.log(`│${line}│`)
23
- console.log(`╰───────────────────────────────────────╯`)
24
- }
25
- }
26
- } catch (e) {
27
- // silently ignore version check
28
- }
29
-
30
- export * from './src/Service.js'
31
- export * from './src/Stream.js'
32
- export * from './src/Remote.js'
33
-
34
- export { ServeStatic } from './src/WebServer.js'
35
- export { Gateway } from './src/Gateway.js'
36
- export { GeonixVersion } from './src/Util.js'
37
- export { connection, stopConnection } from './src/Connection.js'
38
- export { registry } from './src/Registry.js'
39
- export { Request, Subscribe, Publish } from './src/Request.js'
40
- export { RequestOptions } from './src/RequestOptions.js'
41
- export { picoid as randomID } from './src/Util.js'
42
-
43
- export { stats as StreamStats } from './src/Stream.js'
1
+ export * from "./src/Service.js";
2
+ export * from "./src/Stream.js";
3
+ export * from "./src/Remote.js";
4
+
5
+ export { ServeStatic } from "./src/WebServer.js";
6
+ export { Gateway } from "./src/Gateway.js";
7
+ export { GeonixVersion } from "./src/Util.js";
8
+ export { connection, stopConnection } from "./src/Connection.js";
9
+ export { registry } from "./src/Registry.js";
10
+ export { Request, Subscribe, Publish } from "./src/Request.js";
11
+ export { RequestOptions } from "./src/RequestOptions.js";
12
+ export { picoid as randomID } from "./src/Util.js";
13
+
14
+ export { stats as StreamStats } from "./src/Stream.js";
package/index.d.ts CHANGED
@@ -47,7 +47,7 @@ declare class Connection {
47
47
  * @param {object} options
48
48
  * @returns any
49
49
  */
50
- request(subject: string, json: object, options?: object): Promise<unknown>;
50
+ request(subject: string, json: object, opts?: {}): Promise<unknown>;
51
51
  subscribe(subject: any, options: any): Promise<any>;
52
52
  unsubscribe(subscription: any): Promise<void>;
53
53
  /**
@@ -77,13 +77,27 @@ declare class Registry {
77
77
  export {};
78
78
  export function Remote(service: string, ...context: (string | Stream | Object)[]): string | Stream | Object;
79
79
  /**
80
+ * Send a request to a service
80
81
  *
81
- * @param {*} service
82
- * @param {*} method
83
- * @param {*} args
82
+ * @param {string} service
83
+ * @param {string} method
84
+ * @param {any[]} args
85
+ * @param {any[]} context
86
+ * @param {object} options
84
87
  * @returns
85
88
  */
86
- export function Request(service: any, method: any, args: any, context: any[] | undefined, options: any): Promise<any>;
89
+ export function Request(service: string, method: string, args: any[], context: any[], options: object): Promise<any>;
90
+ /**
91
+ * Send a request to a service
92
+ *
93
+ * @param {string} identifier
94
+ * @param {string} method
95
+ * @param {any[]} args
96
+ * @param {any[]} context
97
+ * @param {object} options
98
+ * @returns
99
+ */
100
+ export function directRequest(identifier: string, method: string, args: any[], context: any[], options: object, service: any): Promise<any>;
87
101
  /**
88
102
  * Publish payload to a subject
89
103
  *
@@ -107,10 +121,9 @@ export function RequestOptions(options: any): RequestOptionsClass;
107
121
  export class Service {
108
122
  static serviceClasses: any[];
109
123
  static start(options?: {}): void;
110
- static static(): void;
111
124
  connections: Map<any, any>;
112
- SYS_createConnection(streamId: any): Promise<boolean>;
113
- SYS_getEnv(): Promise<{
125
+ $createConnection(streamId: any): Promise<boolean>;
126
+ $getEnv(): {
114
127
  geonix: string;
115
128
  node: {
116
129
  version: any;
@@ -121,11 +134,12 @@ export class Service {
121
134
  mem: any;
122
135
  rss: any;
123
136
  cpu: any;
124
- }>;
137
+ };
138
+ $getServiceInfo(): {};
125
139
  #private;
126
140
  }
127
141
  /**
128
- * Converts input data to stream
142
+ * Converts data to stream
129
143
  *
130
144
  * @param {*} data
131
145
  * @param {*} automated
@@ -133,10 +147,8 @@ export class Service {
133
147
  */
134
148
  export function Stream(data: any, tag?: string): any;
135
149
  export function isStream(object: any): any;
136
- export function getReadable(object: any, forceNats?: boolean): Promise<any>;
137
- export function getReadableOverHTTP(object: any): Promise<any>;
138
- export function getReadableOverNATS(object: any): Promise<any>;
139
- export function streamToBuffer(object: any, forceNats?: boolean): Promise<any>;
150
+ export function getReadable(object: any): Promise<any>;
151
+ export function streamToBuffer(object: any): Promise<any>;
140
152
  export function streamToString(object: any): Promise<any>;
141
153
  export const stats: {};
142
154
  /**
@@ -144,16 +156,8 @@ export const stats: {};
144
156
  * @param {string} url
145
157
  * @returns
146
158
  */
147
- export function parseURL(url: string): {
148
- servers: string;
149
- user: any;
150
- pass: any;
151
- token: any;
152
- };
153
- export function timeoutAsyncGenerator(target: any, ms: any): {};
154
- export function waitForAbort(abortSignal: any, result: any): Promise<any>;
155
- export function abortableAsyncGenerator(target: any, abortSignal: any): {};
156
- export function getNetworkAddresses(): any[];
159
+ export function parseURL(url: string): any;
160
+ export function getFirstItemFromAsyncIterable(asyncIterable: any): Promise<any>;
157
161
  export function sleep(delay: number): Promise<any>;
158
162
  export function picoid(size?: number): any;
159
163
  export function hash(data: string | Buffer): any;
@@ -172,6 +176,7 @@ export function ServeStatic(root: any, options?: {}): any;
172
176
  export const webserver: WebServer;
173
177
  declare class WebServer {
174
178
  start(): Promise<void>;
179
+ getAddresses(): any[];
175
180
  getPort(): any;
176
181
  router(): any;
177
182
  waitUntilReady(): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geonix",
3
- "version": "1.12.3",
3
+ "version": "1.20.1",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "bin": {
@@ -9,22 +9,26 @@
9
9
  "main": "exports.js",
10
10
  "scripts": {
11
11
  "test": "echo \"Error: no test specified\" && exit 1",
12
- "build": "tsc && cat build/* > index.d.ts && rm -rf build",
12
+ "build": "npx tsc && cat build/* > index.d.ts && rm -rf build",
13
13
  "deploy": "npm run build && npm publish"
14
14
  },
15
15
  "author": "Davor Tarandek <dtarandek@tria.hr>",
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
18
  "cookie-parser": "^1.4.6",
19
- "express": "^4.18.2",
19
+ "express": "^4.19.2",
20
20
  "express-async-errors": "^3.1.1",
21
21
  "express-ws": "^5.0.2",
22
22
  "multer": "^1.4.5-lts.1",
23
- "nats": "^2.19.0",
24
- "semver": "^7.5.4",
25
- "ws": "^8.16.0"
23
+ "nats": "^2.28.2",
24
+ "semver": "^7.6.3",
25
+ "ws": "^8.18.0"
26
26
  },
27
27
  "publishConfig": {
28
28
  "registry": "https://registry.npmjs.org/"
29
+ },
30
+ "devDependencies": {
31
+ "eslint": "^9.9.1",
32
+ "typescript": "^5.5.4"
29
33
  }
30
34
  }
package/src/Connection.js CHANGED
@@ -1,11 +1,14 @@
1
- import { connect, JSONCodec } from 'nats'
2
- import { parseURL, picoid, sleep } from './Util.js'
3
- import { Stream } from './Stream.js'
4
- import { webserver } from './WebServer.js'
1
+ import { connect, JSONCodec } from "nats";
2
+ import { parseURL, picoid, sleep } from "./Util.js";
3
+ import { Stream } from "./Stream.js";
4
+ import { webserver } from "./WebServer.js";
5
5
 
6
6
  // -------------------------------------------------------------------------------------------------
7
- const REQUEST_TIMEOUT = 30000
8
- const CONNECTION_TIMEOUT = 10000
7
+ const CONNECTION_TIMEOUT = 10000;
8
+
9
+ const defaultRequestOptions = {
10
+ timeout: 300000
11
+ };
9
12
  // -------------------------------------------------------------------------------------------------
10
13
 
11
14
  /**
@@ -17,58 +20,70 @@ const CONNECTION_TIMEOUT = 10000
17
20
  */
18
21
  class Connection {
19
22
 
20
- #draining = false
21
- #closed = false
22
- #ready = false
23
- #nc
23
+ #draining = false;
24
+ #closed = false;
25
+ #ready = false;
26
+ #connections = [];
27
+ #connectionRoundRobin = 0;
28
+
29
+ #getConnection() {
30
+ this.#connectionRoundRobin = ++this.#connectionRoundRobin % this.#connections.length;
31
+ return this.#connections[this.#connectionRoundRobin];
32
+ }
24
33
 
25
34
  /**
26
35
  * Initiates connection to transport
27
36
  * @param {string} transport
28
37
  */
29
- async start(transport = process.env.TRANSPORT || 'nats://localhost') {
38
+ async start(transport = process.env.TRANSPORT || "nats://localhost") {
30
39
  const defaults = {
31
40
  timeout: CONNECTION_TIMEOUT,
32
41
  reconnect: true,
33
- debug: process.env.TRANSPORT_DEBUG === 'true',
42
+ debug: process.env.TRANSPORT_DEBUG === "true",
34
43
  maxReconnectAttempts: 30,
35
44
  pingInterval: 30000,
36
- waitOnFirstConnect: true
37
- }
45
+ waitOnFirstConnect: true,
46
+ connections: 1
47
+ };
38
48
  const options = {
39
49
  ...defaults,
40
50
  ...parseURL(transport)
41
- }
51
+ };
42
52
 
43
- this.#nc = await connect(options)
53
+ for (let i = 0; i < options.connections; i++) {
54
+ this.#connections.push(await connect(options));
55
+ }
44
56
 
45
- console.log('gx.connection.connected')
57
+ console.log("gx.connection.connected");
46
58
 
47
- this.#ready = true
59
+ this.#ready = true;
48
60
 
49
- this.monitorStatus()
50
- this.waitUntilClosed()
61
+ this.monitorStatus();
62
+ this.waitUntilClosed();
51
63
  }
52
64
 
53
65
  async monitorStatus() {
54
- for await (const event of this.#nc.status())
55
- console.log('gx.connection.status', JSON.stringify(event))
66
+ for await (const event of this.#getConnection().status()) {
67
+ console.log("gx.connection.status", JSON.stringify(event));
68
+ }
56
69
  }
57
70
 
58
71
  /**
59
72
  * Wait for the connection to be safely closed
60
73
  */
61
74
  async waitUntilClosed() {
62
- await this.#nc.closed()
63
- this.#closed = true
64
- console.log('gx.connection.closed')
75
+ // wait for all connections to be closed
76
+ await Promise.all(this.#connections.map(connection => connection.closed()));
77
+
78
+ this.#closed = true;
79
+ console.log("gx.connection.closed");
65
80
 
66
- webserver.stop()
81
+ webserver.stop();
67
82
 
68
- await sleep(5000)
83
+ await sleep(5000);
69
84
 
70
- console.log('gx.terminate')
71
- process.exit(1)
85
+ console.log("gx.terminate");
86
+ process.exit(1);
72
87
  }
73
88
 
74
89
  /**
@@ -76,7 +91,7 @@ class Connection {
76
91
  */
77
92
  async waitUntilReady() {
78
93
  while (!this.#ready)
79
- await sleep(100)
94
+ await sleep(100);
80
95
  }
81
96
 
82
97
  /**
@@ -88,15 +103,15 @@ class Connection {
88
103
  */
89
104
  async publish(subject, json) {
90
105
  if (this.#draining || this.#closed)
91
- return
106
+ return;
92
107
 
93
- let payload = codec.encode(json)
108
+ let payload = codec.encode(json);
94
109
 
95
110
  // if payload is too big, convert it to Stream
96
111
  if (payload.length > this.getMaxPayloadSize())
97
- payload = codec.encode(Stream(JSON.stringify(json)))
112
+ payload = codec.encode(Stream(JSON.stringify(json)));
98
113
 
99
- await this.#nc.publish(subject, payload)
114
+ await this.#getConnection().publish(subject, payload);
100
115
  }
101
116
 
102
117
  /**
@@ -108,9 +123,9 @@ class Connection {
108
123
  */
109
124
  async publishRaw(subject, data) {
110
125
  if (this.#draining || this.#closed)
111
- return
126
+ return;
112
127
 
113
- await this.#nc.publish(subject, data)
128
+ await this.#getConnection().publish(subject, data);
114
129
  }
115
130
 
116
131
  /**
@@ -121,29 +136,35 @@ class Connection {
121
136
  * @param {object} options
122
137
  * @returns any
123
138
  */
124
- async request(subject, json, options = { timeout: 300000 }) {
125
- const respondTo = `gx2.r.${picoid(16)}`
139
+ async request(subject, json, opts = {}) {
140
+ const options = {
141
+ ...defaultRequestOptions,
142
+ ...opts
143
+ };
126
144
 
127
- let payload = codec.encode({ $r: respondTo, p: json })
145
+ const respondTo = `gx2.r.${picoid(16)}`;
146
+
147
+ let payload = codec.encode({ $r: respondTo, p: json });
128
148
 
129
149
  // if payload is too big, convert it to Stream
130
150
  if (payload.length > this.getMaxPayloadSize())
131
- payload = codec.encode(Stream(JSON.stringify({ $r: respondTo, p: json })))
151
+ payload = codec.encode(Stream(JSON.stringify({ $r: respondTo, p: json })));
132
152
 
133
- let response = await this.#nc.subscribe(respondTo, { max: 1, ...options })
153
+ const nc = this.#getConnection();
154
+ let response = await nc.subscribe(respondTo, { max: 1, ...options });
134
155
 
135
- await this.#nc.publish(subject, payload)
156
+ await nc.publish(subject, payload);
136
157
 
137
158
  for await (let event of response)
138
- return codec.decode(event.data)
159
+ return codec.decode(event.data);
139
160
  }
140
161
 
141
162
  async subscribe(subject, options) {
142
- return this.#nc.subscribe(subject, options)
163
+ return this.#getConnection().subscribe(subject, options);
143
164
  }
144
165
 
145
166
  async unsubscribe(subscription) {
146
- subscription.unsubscribe()
167
+ subscription.unsubscribe();
147
168
  }
148
169
 
149
170
  /**
@@ -151,28 +172,30 @@ class Connection {
151
172
  * @returns {number}
152
173
  */
153
174
  getMaxPayloadSize() {
154
- return this.#nc?.info?.max_payload || 1024 * 512
175
+ const nc = this.#getConnection();
176
+ return nc?.info?.max_payload || 1024 * 512;
155
177
  }
156
178
 
157
179
  isClosed() {
158
- return this.#closed
180
+ return this.#closed;
159
181
  }
160
182
 
161
183
  async drain() {
162
- this.#draining = true
163
- await this.#nc.drain()
184
+ this.#draining = true;
185
+
186
+ await Promise.all(this.#connections.map(connection => connection.drain()));
164
187
  }
165
188
 
166
189
  }
167
190
 
168
- export const codec = JSONCodec()
191
+ export const codec = JSONCodec();
169
192
 
170
- export const connection = new Connection()
171
- connection.start()
193
+ export const connection = new Connection();
194
+ connection.start();
172
195
 
173
196
  export const stopConnection = () => {
174
197
  if (!connection)
175
- return
198
+ return;
176
199
 
177
- connection.drain()
178
- }
200
+ connection.drain();
201
+ };