geonix 1.20.1 → 1.20.3

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/eslint.config.js CHANGED
@@ -14,7 +14,8 @@ export default [
14
14
  }
15
15
  },
16
16
  rules: {
17
- // "no-console": "error",
17
+ "curly": "error",
18
+ "no-console": "error",
18
19
  semi: "error",
19
20
  "no-unused-vars": ["error", { argsIgnorePattern: "^_.*" }],
20
21
  "no-constant-condition": ["error", { checkLoops: false }],
package/index.d.ts CHANGED
@@ -65,6 +65,14 @@ export class Gateway {
65
65
  constructor(opts: any);
66
66
  #private;
67
67
  }
68
+ export class Logger {
69
+ constructor(options: any);
70
+ info(...args: any[]): void;
71
+ error(...args: any[]): void;
72
+ debug(...args: any[]): void;
73
+ #private;
74
+ }
75
+ export const logger: Logger;
68
76
  export const registry: Registry;
69
77
  /**
70
78
  * Registry maintains a local list of available services and their versions.
@@ -138,6 +146,17 @@ export class Service {
138
146
  $getServiceInfo(): {};
139
147
  #private;
140
148
  }
149
+ export type ServiceOptions = {
150
+ middleware: {
151
+ json: boolean;
152
+ raw: boolean;
153
+ cookies: boolean;
154
+ };
155
+ /**
156
+ * Enable full beacon
157
+ */
158
+ fullBeacon: boolean;
159
+ };
141
160
  /**
142
161
  * Converts data to stream
143
162
  *
@@ -151,6 +170,7 @@ export function getReadable(object: any): Promise<any>;
151
170
  export function streamToBuffer(object: any): Promise<any>;
152
171
  export function streamToString(object: any): Promise<any>;
153
172
  export const stats: {};
173
+ export const activeStreams: {};
154
174
  /**
155
175
  * Parse nats:// URL
156
176
  * @param {string} url
@@ -158,6 +178,7 @@ export const stats: {};
158
178
  */
159
179
  export function parseURL(url: string): any;
160
180
  export function getFirstItemFromAsyncIterable(asyncIterable: any): Promise<any>;
181
+ export function getNetworkAddresses(): any[];
161
182
  export function sleep(delay: number): Promise<any>;
162
183
  export function picoid(size?: number): any;
163
184
  export function hash(data: string | Buffer): any;
@@ -176,7 +197,6 @@ export function ServeStatic(root: any, options?: {}): any;
176
197
  export const webserver: WebServer;
177
198
  declare class WebServer {
178
199
  start(): Promise<void>;
179
- getAddresses(): any[];
180
200
  getPort(): any;
181
201
  router(): any;
182
202
  waitUntilReady(): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geonix",
3
- "version": "1.20.1",
3
+ "version": "1.20.3",
4
4
  "type": "module",
5
5
  "description": "",
6
6
  "bin": {
@@ -10,6 +10,7 @@
10
10
  "scripts": {
11
11
  "test": "echo \"Error: no test specified\" && exit 1",
12
12
  "build": "npx tsc && cat build/* > index.d.ts && rm -rf build",
13
+ "lint": "npx eslint src",
13
14
  "deploy": "npm run build && npm publish"
14
15
  },
15
16
  "author": "Davor Tarandek <dtarandek@tria.hr>",
@@ -28,7 +29,7 @@
28
29
  "registry": "https://registry.npmjs.org/"
29
30
  },
30
31
  "devDependencies": {
31
- "eslint": "^9.9.1",
32
+ "eslint": "^9.10.0",
32
33
  "typescript": "^5.5.4"
33
34
  }
34
- }
35
+ }
package/src/Codec.js ADDED
@@ -0,0 +1,16 @@
1
+ import { JSONCodec } from "nats";
2
+
3
+ export const codec = JSONCodec();
4
+
5
+ export function encode(data) {
6
+ return codec.encode(data);
7
+ }
8
+
9
+ export function decode(data) {
10
+ // check if data is json
11
+ if (Buffer.isBuffer(data) && data.readUInt8(0) === "{".charCodeAt(0)) {
12
+ return codec.decode(data);
13
+ }
14
+
15
+ throw new Error("Codec.decode: unknown data type");
16
+ }
package/src/Connection.js CHANGED
@@ -1,7 +1,9 @@
1
- import { connect, JSONCodec } from "nats";
2
- import { parseURL, picoid, sleep } from "./Util.js";
1
+ import { connect } from "nats";
2
+ import { getFirstItemFromAsyncIterable, parseURL, picoid, sleep } from "./Util.js";
3
3
  import { Stream } from "./Stream.js";
4
4
  import { webserver } from "./WebServer.js";
5
+ import { logger } from "./Logger.js";
6
+ import { decode, encode } from "./Codec.js";
5
7
 
6
8
  // -------------------------------------------------------------------------------------------------
7
9
  const CONNECTION_TIMEOUT = 10000;
@@ -9,6 +11,16 @@ const CONNECTION_TIMEOUT = 10000;
9
11
  const defaultRequestOptions = {
10
12
  timeout: 300000
11
13
  };
14
+
15
+ const defaultConnectionOptions = {
16
+ timeout: CONNECTION_TIMEOUT,
17
+ reconnect: true,
18
+ debug: process.env.TRANSPORT_DEBUG === "true",
19
+ maxReconnectAttempts: 30,
20
+ pingInterval: 30000,
21
+ waitOnFirstConnect: true,
22
+ connections: 1
23
+ };
12
24
  // -------------------------------------------------------------------------------------------------
13
25
 
14
26
  /**
@@ -36,17 +48,8 @@ class Connection {
36
48
  * @param {string} transport
37
49
  */
38
50
  async start(transport = process.env.TRANSPORT || "nats://localhost") {
39
- const defaults = {
40
- timeout: CONNECTION_TIMEOUT,
41
- reconnect: true,
42
- debug: process.env.TRANSPORT_DEBUG === "true",
43
- maxReconnectAttempts: 30,
44
- pingInterval: 30000,
45
- waitOnFirstConnect: true,
46
- connections: 1
47
- };
48
51
  const options = {
49
- ...defaults,
52
+ ...defaultConnectionOptions,
50
53
  ...parseURL(transport)
51
54
  };
52
55
 
@@ -54,7 +57,7 @@ class Connection {
54
57
  this.#connections.push(await connect(options));
55
58
  }
56
59
 
57
- console.log("gx.connection.connected");
60
+ logger.info("gx.connection.connected");
58
61
 
59
62
  this.#ready = true;
60
63
 
@@ -64,7 +67,7 @@ class Connection {
64
67
 
65
68
  async monitorStatus() {
66
69
  for await (const event of this.#getConnection().status()) {
67
- console.log("gx.connection.status", JSON.stringify(event));
70
+ logger.info("gx.connection.status", JSON.stringify(event));
68
71
  }
69
72
  }
70
73
 
@@ -76,13 +79,13 @@ class Connection {
76
79
  await Promise.all(this.#connections.map(connection => connection.closed()));
77
80
 
78
81
  this.#closed = true;
79
- console.log("gx.connection.closed");
82
+ logger.info("gx.connection.closed");
80
83
 
81
84
  webserver.stop();
82
85
 
83
86
  await sleep(5000);
84
87
 
85
- console.log("gx.terminate");
88
+ logger.info("gx.terminate");
86
89
  process.exit(1);
87
90
  }
88
91
 
@@ -90,8 +93,9 @@ class Connection {
90
93
  * Wait for the connection to be fully established
91
94
  */
92
95
  async waitUntilReady() {
93
- while (!this.#ready)
96
+ while (!this.#ready) {
94
97
  await sleep(100);
98
+ }
95
99
  }
96
100
 
97
101
  /**
@@ -102,14 +106,16 @@ class Connection {
102
106
  * @returns void
103
107
  */
104
108
  async publish(subject, json) {
105
- if (this.#draining || this.#closed)
109
+ if (this.#draining || this.#closed) {
106
110
  return;
111
+ }
107
112
 
108
- let payload = codec.encode(json);
113
+ let payload = encode(json);
109
114
 
110
115
  // if payload is too big, convert it to Stream
111
- if (payload.length > this.getMaxPayloadSize())
112
- payload = codec.encode(Stream(JSON.stringify(json)));
116
+ if (payload.length > this.getMaxPayloadSize()) {
117
+ payload = encode(Stream(JSON.stringify(json)));
118
+ }
113
119
 
114
120
  await this.#getConnection().publish(subject, payload);
115
121
  }
@@ -122,8 +128,9 @@ class Connection {
122
128
  * @returns void
123
129
  */
124
130
  async publishRaw(subject, data) {
125
- if (this.#draining || this.#closed)
131
+ if (this.#draining || this.#closed) {
126
132
  return;
133
+ }
127
134
 
128
135
  await this.#getConnection().publish(subject, data);
129
136
  }
@@ -144,19 +151,20 @@ class Connection {
144
151
 
145
152
  const respondTo = `gx2.r.${picoid(16)}`;
146
153
 
147
- let payload = codec.encode({ $r: respondTo, p: json });
154
+ let payload = encode({ $r: respondTo, p: json });
148
155
 
149
156
  // if payload is too big, convert it to Stream
150
- if (payload.length > this.getMaxPayloadSize())
151
- payload = codec.encode(Stream(JSON.stringify({ $r: respondTo, p: json })));
157
+ if (payload.length > this.getMaxPayloadSize()) {
158
+ payload = encode(Stream(JSON.stringify({ $r: respondTo, p: json })));
159
+ }
152
160
 
153
161
  const nc = this.#getConnection();
154
162
  let response = await nc.subscribe(respondTo, { max: 1, ...options });
155
163
 
156
164
  await nc.publish(subject, payload);
157
165
 
158
- for await (let event of response)
159
- return codec.decode(event.data);
166
+ const event = await getFirstItemFromAsyncIterable(response);
167
+ return decode(event.data);
160
168
  }
161
169
 
162
170
  async subscribe(subject, options) {
@@ -188,14 +196,13 @@ class Connection {
188
196
 
189
197
  }
190
198
 
191
- export const codec = JSONCodec();
192
-
193
199
  export const connection = new Connection();
194
200
  connection.start();
195
201
 
196
202
  export const stopConnection = () => {
197
- if (!connection)
203
+ if (!connection) {
198
204
  return;
205
+ }
199
206
 
200
207
  connection.drain();
201
208
  };
package/src/Gateway.js CHANGED
@@ -8,14 +8,15 @@ import expressWs from "express-ws";
8
8
  import querystring from "querystring";
9
9
  import semver from "semver";
10
10
  import { WebSocket } from "ws";
11
+ import { logger } from "./Logger.js";
11
12
 
12
13
  const raw = express.raw({ limit: "100mb" });
13
14
 
14
15
  const DEBUG_ENDPOINT = "/lZ6jD2eC3iP0zB3jJ1yJ9pM8gG3yI3vS";
15
16
  const endpointMatcher = /^((?<options>.+)\|)?(?<verb>WS|GET|POST|PATCH|PUT|DELETE|HEAD|OPTIONS|ALL)\s(?<url>.*)/;
16
17
 
17
- const logger = (req, res, next) => {
18
- console.info(`HTTP ${req.method} ${req.url}`);
18
+ const requestLogger = (req, res, next) => {
19
+ logger.info(`HTTP ${req.method} ${req.url}`);
19
20
 
20
21
  next();
21
22
  };
@@ -63,10 +64,10 @@ export class Gateway {
63
64
  this.#port = process.env.PORT || port;
64
65
  this.#api.listen(this.#port);
65
66
 
66
- console.debug(`geonix.gateway: listening on http://0.0.0.0:${this.#port}`);
67
+ logger.debug(`geonix.gateway: listening on http://0.0.0.0:${this.#port}`);
67
68
 
68
69
  // logging
69
- this.#api.use(logger);
70
+ this.#api.use(requestLogger);
70
71
 
71
72
  // cors
72
73
  this.#api.use((req, res, next) => {
@@ -86,8 +87,9 @@ export class Gateway {
86
87
  });
87
88
 
88
89
  // debug router (only available in non-production environments)
89
- if (process.env.NODE_ENV !== "production")
90
+ if (process.env.NODE_ENV !== "production") {
90
91
  this.#api.use(DEBUG_ENDPOINT, this.#debugRouter());
92
+ }
91
93
 
92
94
  this.#api.use((req, res, next) => {
93
95
  if (this.#opts.beforeRequest) {
@@ -100,10 +102,8 @@ export class Gateway {
100
102
  this.#api.use(raw, (req, res, next) => {
101
103
  stats.requests++;
102
104
 
103
- if (this.#router)
104
- this.#router(req, res, next);
105
- else
106
- next();
105
+ if (this.#router) { this.#router(req, res, next); }
106
+ else { next(); }
107
107
  });
108
108
 
109
109
  this.#api.use((req, res, next) => {
@@ -126,8 +126,9 @@ export class Gateway {
126
126
  });
127
127
 
128
128
  setInterval(() => {
129
- if (this.#rebuildRouter)
129
+ if (this.#rebuildRouter) {
130
130
  this.#buildRouter();
131
+ }
131
132
  }, 1000);
132
133
 
133
134
  while (true) {
@@ -143,12 +144,12 @@ export class Gateway {
143
144
  break;
144
145
  }
145
146
  } catch (e) {
146
- console.error(e);
147
+ logger.error(e);
147
148
  }
148
149
  }
149
150
 
150
151
  // terminate process
151
- console.debug("geonix.gateway: stopped");
152
+ logger.debug("geonix.gateway: stopped");
152
153
  process.exit(0);
153
154
  }
154
155
 
@@ -156,15 +157,14 @@ export class Gateway {
156
157
  let entries = Object.values(registry.getEntries());
157
158
 
158
159
  const processEntry = async (entry) => {
159
- if (this.#registry[entry.i] !== undefined)
160
- return false;
160
+ if (this.#registry[entry.i] !== undefined) { return false; }
161
161
 
162
- console.log(`gateway.onServiceAdded: ${entry.n}@${entry.v} (#${entry.i})`);
162
+ logger.info(`gateway.onServiceAdded: ${entry.n}@${entry.v} (#${entry.i})`);
163
163
 
164
164
  // figure out if endpoints is reachable via direct http call
165
165
  let backend;
166
166
  if (entry.a) {
167
- for (let address of entry.a)
167
+ for (let address of entry.a) {
168
168
  try {
169
169
  const ac = new AbortController();
170
170
  const timeout = setTimeout(() => ac.abort(), 500);
@@ -172,12 +172,13 @@ export class Gateway {
172
172
  clearTimeout(timeout);
173
173
  if (result.status === "healthy" && result.services?.includes(entry.n)) {
174
174
  backend = address;
175
- console.log(`${entry.n}@${entry.v} (#${entry.i}) directly reachable @ ${address}`);
175
+ logger.info(`${entry.n}@${entry.v} (#${entry.i}) directly reachable @ ${address}`);
176
176
  break;
177
177
  }
178
178
  } catch {
179
179
  // silently ignore errors
180
180
  }
181
+ }
181
182
  }
182
183
 
183
184
  let proxy;
@@ -190,7 +191,7 @@ export class Gateway {
190
191
  try {
191
192
  await this.#proxyHttpOverNats(streamId, entry, client);
192
193
  } catch (e) {
193
- console.error("nats.proxy.error", e);
194
+ logger.error("nats.proxy.error", e);
194
195
  client.destroy();
195
196
  }
196
197
  }, 50000, 10000);
@@ -204,8 +205,9 @@ export class Gateway {
204
205
 
205
206
  entries = (await Promise.all(entries.map(processEntry))).filter(result => result === true);
206
207
 
207
- if (entries.length > 0)
208
+ if (entries.length > 0) {
208
209
  this.#rebuildRouter = true;
210
+ }
209
211
  }
210
212
 
211
213
  async #handleRemovedServices() {
@@ -215,7 +217,7 @@ export class Gateway {
215
217
  for (let { entry, proxy } of localEntries) {
216
218
  if (registryEntries[entry.i] === undefined) {
217
219
  proxy?.server?.close();
218
- console.log(`gateway.onServiceRemoved: ${entry.n}@${entry.v}`);
220
+ logger.info(`gateway.onServiceRemoved: ${entry.n}@${entry.v}`);
219
221
  delete this.#registry[entry.i];
220
222
 
221
223
  this.#rebuildRouter = true;
@@ -290,8 +292,7 @@ export class Gateway {
290
292
  });
291
293
 
292
294
  const dataLoop = async () => {
293
- for await (const event of ingress)
294
- client.write(event.data);
295
+ for await (const event of ingress) { client.write(event.data); }
295
296
  };
296
297
 
297
298
  dataLoop();
@@ -321,15 +322,16 @@ export class Gateway {
321
322
  inbound.on("close", () => backend.close());
322
323
  });
323
324
  } catch (e) {
324
- console.error(e);
325
+ logger.error(e);
325
326
  }
326
327
  }
327
328
 
328
329
  async #buildRouter() {
329
- if (this.#buildRouterRunning)
330
+ if (this.#buildRouterRunning) {
330
331
  return;
332
+ }
331
333
 
332
- console.debug("gateway.buildRouter");
334
+ logger.debug("gateway.buildRouter");
333
335
 
334
336
  this.#rebuildRouter = false;
335
337
  this.#buildRouterRunning = true;
@@ -359,8 +361,8 @@ export class Gateway {
359
361
  backend: [backend]
360
362
  });
361
363
  } catch (e) {
362
- console.error("gateway.buildRouter.error:", entry);
363
- console.error("gateway.buildRouter.error:", e);
364
+ logger.error("gateway.buildRouter.error:", entry);
365
+ logger.error("gateway.buildRouter.error:", e);
364
366
  }
365
367
  }
366
368
  }
@@ -372,12 +374,13 @@ export class Gateway {
372
374
  const version = endpoints[index].version;
373
375
  const url = `${endpoints[index].endpoint.verb} ${endpoints[index].endpoint.url}`;
374
376
 
375
- for (let n = 0; n < index; n++)
377
+ for (let n = 0; n < index; n++) {
376
378
  if (`${endpoints[n].endpoint.verb} ${endpoints[n].endpoint.url}` === url && endpoints[n].version === version) {
377
379
  endpoints[n].backend = endpoints[n].backend.concat(endpoints[index].backend);
378
380
  endpoints.splice(index, 1);
379
381
  break;
380
382
  }
383
+ }
381
384
  }
382
385
 
383
386
  // sort endpoints by order, if there is one
@@ -397,21 +400,22 @@ export class Gateway {
397
400
  router.ws(uri, (ws, req) => {
398
401
  const url = req.originalUrl.replace(/\/\.websocket$/, "");
399
402
 
400
- console.debug("proxy.web.ws.to:", backend + req.originalUrl);
403
+ logger.debug("proxy.web.ws.to:", backend + req.originalUrl);
401
404
  this.#proxyWebsocketOverNats(`ws://${backend}${url}`, ws, req);
402
405
  });
403
- } else
406
+ } else {
404
407
  router[verb](uri, async (req, res, _next) => {
405
408
  stats.proxied++;
406
409
  backend = endpoint.backend[endpoint.requests++ % endpoint.backend.length];
407
410
 
408
411
  try {
409
- console.debug("proxy.web.to:", backend + req.originalUrl);
412
+ logger.debug("proxy.web.to:", backend + req.originalUrl);
410
413
  await proxyHttp(`http://${backend}`, req, res);
411
414
  } catch (e) {
412
- console.error("proxy.web.error:", e);
415
+ logger.error("proxy.web.error:", e);
413
416
  }
414
417
  });
418
+ }
415
419
  }
416
420
 
417
421
  this.#router = router;
package/src/Logger.js ADDED
@@ -0,0 +1,34 @@
1
+ const defaultLoggerOptions = {
2
+ timestamp: true
3
+ };
4
+
5
+ export class Logger {
6
+
7
+ #options = defaultLoggerOptions;
8
+
9
+ constructor(options) {
10
+ this.#options = { ...this.#options, ...options };
11
+ }
12
+
13
+ #log(...args) {
14
+ const ts = this.#options.timestamp ? new Date().toISOString() : undefined;
15
+
16
+ // eslint-disable-next-line no-console
17
+ console.log(...[ts, ...args].filter($ => $));
18
+ }
19
+
20
+ info(...args) {
21
+ this.#log("INF", ...args);
22
+ }
23
+
24
+ error(...args) {
25
+ this.#log("ERR", ...args);
26
+ }
27
+
28
+ debug(...args) {
29
+ this.#log("DBG", ...args);
30
+ }
31
+
32
+ }
33
+
34
+ export const logger = new Logger();
package/src/Registry.js CHANGED
@@ -1,8 +1,9 @@
1
- import { connection, codec } from "./Connection.js";
1
+ import { connection } from "./Connection.js";
2
2
  import { sleep } from "./Util.js";
3
3
  import semver from "semver";
4
4
  import EventEmitter from "events";
5
5
  import { directRequest } from "./Request.js";
6
+ import { decode } from "./Codec.js";
6
7
 
7
8
  const REGISTRY_ENTRY_TIMEOUT = 5000;
8
9
 
@@ -30,7 +31,7 @@ class Registry extends EventEmitter {
30
31
  const subscription = await connection.subscribe("gx2.beacon");
31
32
 
32
33
  for await (const event of subscription) {
33
- let data = codec.decode(event.data);
34
+ let data = decode(event.data);
34
35
 
35
36
  const exists = this.#registry[data.i] !== undefined;
36
37
 
@@ -44,8 +45,9 @@ class Registry extends EventEmitter {
44
45
  timeout: Date.now() + REGISTRY_ENTRY_TIMEOUT
45
46
  };
46
47
 
47
- if (!exists)
48
+ if (!exists) {
48
49
  this.emit("added", this.#registry[data.i]);
50
+ }
49
51
  }
50
52
  }
51
53
 
@@ -83,14 +85,16 @@ class Registry extends EventEmitter {
83
85
  let matchVersion = version ? semver.satisfies(entry.v, version) : true;
84
86
  let matchId = id ? entry.id === id : true;
85
87
 
86
- if (matchName && matchVersion && matchId)
88
+ if (matchName && matchVersion && matchId) {
87
89
  matches.push(entry);
90
+ }
88
91
  }
89
92
 
90
93
  if (matches.length > 0) {
91
94
  // return instance id in case of id matching
92
- if (id)
95
+ if (id) {
93
96
  return matches[0].i;
97
+ }
94
98
 
95
99
  // sort matched services in the registry by version
96
100
  matches.sort((a, b) => semver.rcompare(a.v, b.v));
package/src/Request.js CHANGED
@@ -5,6 +5,7 @@ import { hash, sleep } from "./Util.js";
5
5
  import { RequestOptionsClass } from "./RequestOptions.js";
6
6
  import { isStream, streamToString } from "./Stream.js";
7
7
  import { inspect } from "node:util";
8
+ import { logger } from "./Logger.js";
8
9
 
9
10
  const REGISTRY_TIMEOUT = 300000;
10
11
 
@@ -44,8 +45,9 @@ function getOriginator() {
44
45
  for (const item of stack) {
45
46
  const typeName = item.getTypeName();
46
47
 
47
- if (Service.serviceClasses.includes(typeName))
48
+ if (Service.serviceClasses.includes(typeName)) {
48
49
  return `${typeName}.${item.getMethodName()}`;
50
+ }
49
51
  }
50
52
  }
51
53
 
@@ -64,8 +66,9 @@ export async function Request(service, method, args, context, options) {
64
66
  const { name, version, id } = match.groups;
65
67
 
66
68
  // allow passing RequestOptions as first arg
67
- if (args?.length > 0 && args[0] instanceof RequestOptionsClass)
69
+ if (args?.length > 0 && args[0] instanceof RequestOptionsClass) {
68
70
  options = (args.shift())?.options;
71
+ }
69
72
 
70
73
  let identifier = null;
71
74
 
@@ -75,8 +78,9 @@ export async function Request(service, method, args, context, options) {
75
78
  let retries = Math.floor(registryTimeout / delay);
76
79
  while (identifier == null && retries-- > 0) {
77
80
  identifier = registry.getIdentifier(name, version, id);
78
- if (!identifier)
81
+ if (!identifier) {
79
82
  await sleep(delay);
83
+ }
80
84
  }
81
85
 
82
86
  return directRequest(identifier, method, args, context, options, service);
@@ -108,10 +112,11 @@ export async function directRequest(identifier, method, args, context, options,
108
112
  options);
109
113
 
110
114
  // automatically process streamed response
111
- if (isStream(response))
115
+ if (isStream(response)) {
112
116
  response = JSON.parse(await streamToString(response));
117
+ }
113
118
  } catch (e) {
114
- console.debug("GxError: directRequest", inspect({
119
+ logger.debug("GxError: directRequest", inspect({
115
120
  originator, service: service ?? identifier, method, args, context, options,
116
121
  error: e, duration: Date.now() - requestBegin
117
122
  }));
@@ -119,12 +124,14 @@ export async function directRequest(identifier, method, args, context, options,
119
124
  throw e;
120
125
  }
121
126
 
122
- if (!response)
127
+ if (!response) {
123
128
  throw Error("Request: invalid response");
129
+ }
124
130
 
125
131
  // got error?
126
- if (response.e)
132
+ if (response.e) {
127
133
  throw Error(`Request: remote error: ${response.e}`);
134
+ }
128
135
 
129
136
  return response.r;
130
137
  }
@@ -147,10 +154,12 @@ export async function Publish(subject, payload) {
147
154
  * @returns
148
155
  */
149
156
  export async function Subscribe(subject, callback) {
150
- if (typeof callback !== "function")
157
+ if (typeof callback !== "function") {
151
158
  return;
159
+ }
152
160
 
153
161
  const subscription = await connection.subscribe(`gx.sub.${subject}`);
154
- for await (const event of subscription)
162
+ for await (const event of subscription) {
155
163
  callback(event.data);
164
+ }
156
165
  }
@@ -1,5 +1,6 @@
1
1
  export class RequestOptionsClass {
2
2
  options;
3
+
3
4
  constructor(options) {
4
5
  this.options = options;
5
6
  }