@interopio/gateway-server 0.23.0 → 0.24.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.
@@ -8,90 +8,216 @@ const { configure } = require('@interopio/gateway/logging/core');
8
8
  // import { GatewayServer } from './src/index.ts';
9
9
  // import { mkcert, argon2, manage } from './src/tools/index.ts';
10
10
 
11
- const { mkcert, argon2, manage } = require('@interopio/gateway-server/tools');
11
+ const { mkcert, argon2, manage, build } = require('@interopio/gateway-server/tools');
12
12
  const { GatewayServer } = require('@interopio/gateway-server');
13
13
 
14
+ // ---------------------------------------------------------------------------
15
+ // Declarative command registry — drives both help text and parseArgs calls
16
+ // ---------------------------------------------------------------------------
17
+
18
+ const commands = {
19
+ run: {
20
+ description: 'Start the gateway server',
21
+ options: {
22
+ port: { type: 'string', short: 'p', help: 'Port or port range (default: 0 i.e. random)', example: '8385, 8000-8100, 3000,4000-4050' },
23
+ host: { type: 'string', short: 'H', help: 'Network address to bind to', example: 'localhost, 127.0.0.1, 0.0.0.0, ::1' },
24
+ user: { type: 'string', short: 'u', help: 'Enable basic auth and set admin username' },
25
+ auth: { type: 'boolean', help: 'Enable/disable authentication (--no-auth overrides config)' },
26
+ ssl: { type: 'boolean', short: 'S', help: 'Enable HTTPS (auto-generates certs if needed)' },
27
+ tls: { type: 'boolean', help: 'Alias for --ssl' },
28
+ cert: { type: 'string', help: 'SSL/TLS certificate file (default: ./gateway-server.crt)' },
29
+ key: { type: 'string', help: 'SSL/TLS private key file (default: ./gateway-server.key)' },
30
+ ca: { type: 'string', help: 'CA certificate file (default: ./gateway-ca.crt)' },
31
+ 'ca-key': { type: 'string', help: 'CA private key file (default: ./gateway-ca.key)' },
32
+ gateway: { type: 'boolean', short: 'g', help: 'Enable/disable gateway endpoint (--no-gateway)' },
33
+ static: { type: 'string', short: 's', multiple: true, help: 'Serve static files from location' },
34
+ config: { type: 'string', short: 'c', help: 'Server configuration file (JSON)' },
35
+ debug: { type: 'boolean', help: 'Enable debug logging (default: info)' },
36
+ },
37
+ allowNegative: true,
38
+ examples: [
39
+ 'gateway-server run -p 3000',
40
+ 'gateway-server run -u admin --port 8385,8388 --debug',
41
+ 'gateway-server run -p 8443 --ssl --user admin --gateway',
42
+ 'gateway-server run --port 42443 --tls --ca-key ./ssl/ca.key --host example.com --gateway',
43
+ 'gateway-server run -p 3000 --static ./public --config ./server-config.json',
44
+ 'gateway-server run --config ./server-config.json --no-gateway --no-ssl --no-auth',
45
+ ],
46
+ },
47
+ build: {
48
+ description: 'Build a Single Executable Application (SEA)',
49
+ positionals: '[entryPoints...]',
50
+ options: {
51
+ 'app-name': { type: 'string', help: 'Base name for the executable (default: package.json name)' },
52
+ 'app-version': { type: 'string', help: 'App version in output dir name (default: package.json version)' },
53
+ executable: { type: 'string', help: 'Path to the Node.js binary (default: current node)' },
54
+ outdir: { type: 'string', short: 'o', help: 'Output directory for build artifacts (default: ./build)' },
55
+ },
56
+ examples: [
57
+ 'gateway-server build',
58
+ 'gateway-server build --app-version 1.2.3',
59
+ 'gateway-server build ./src/main.cjs --app-name io-bridge --executable /usr/local/bin/node22 --app-version 2.0.0',
60
+ ],
61
+ },
62
+ manage: {
63
+ description: 'Send management commands to a running gateway server',
64
+ positionals: '<command> [key=value... or json]',
65
+ options: {
66
+ path: { type: 'string', help: 'Gateway control socket (named pipe / Unix socket)', example: '\\\\\\\\.\\\\pipe\\\\glue42-gateway-xxx, /tmp/gateway.sock' },
67
+ port: { type: 'string', short: 'p', help: 'TCP port of the management server' },
68
+ timeout: { type: 'string', help: 'Connection timeout in ms (default: 5000)' },
69
+ },
70
+ examples: [
71
+ 'gateway-server manage --path \\\\.\\pipe\\glue42-gateway-xxx info',
72
+ 'gateway-server manage --path \\\\.\\pipe\\glue42-gateway-xxx shutdown',
73
+ 'gateway-server manage --path \\\\.\\pipe\\glue42-gateway-xxx custom-cmd key1=value1 count=42',
74
+ 'gateway-server manage --path \\\\.\\pipe\\glue42-gateway-xxx \'{"command":"update-auth","type":"basic"}\'',
75
+ ],
76
+ },
77
+ passwd: {
78
+ description: 'Generate password hash (default: Argon2)',
79
+ options: {
80
+ stdin: { type: 'boolean', help: 'Read password from stdin (for piping)' },
81
+ },
82
+ examples: [
83
+ 'gateway-server passwd',
84
+ 'echo "mySecret123" | gateway-server passwd --stdin',
85
+ ],
86
+ },
87
+ mkcert: {
88
+ description: 'Generate client/server certificate signed by Dev CA',
89
+ positionals: '[name...]',
90
+ options: {
91
+ client: { type: 'boolean', help: 'Generate client certificate (default: server)' },
92
+ user: { type: 'string', short: 'u', help: 'Common Name (default: dev-user, --client only)' },
93
+ ca: { type: 'string', help: 'CA certificate file (default: ./gateway-ca.crt)' },
94
+ 'ca-key': { type: 'string', help: 'CA private key file (default: ./gateway-ca.key)' },
95
+ key: { type: 'string', help: 'Output private key file' },
96
+ cert: { type: 'string', help: 'Output certificate file' },
97
+ },
98
+ examples: [
99
+ 'gateway-server mkcert',
100
+ 'gateway-server mkcert localhost 127.0.0.1 IP:192.168.1.100',
101
+ 'gateway-server mkcert --client EMAIL:john.doe@example.com',
102
+ 'gateway-server mkcert example.com *.example.com --key ./gateway-server.key --cert ./gateway-server.crt',
103
+ ],
104
+ },
105
+ };
106
+
107
+ // ---------------------------------------------------------------------------
108
+ // Help text generator
109
+ // ---------------------------------------------------------------------------
110
+
111
+ function formatOption(name, opt, negatable, col) {
112
+ const shortFlag = opt.short ? `-${opt.short}, ` : ' ';
113
+ const flag = (opt.type === 'boolean' && negatable) ? `--[no-]${name}` : `--${name}`;
114
+ const argHint = opt.type === 'string' ? ` <${name.replace(/-/g, '_')}>` : '';
115
+ const left = ` ${shortFlag}${flag}${argHint}`;
116
+ const pad = Math.max(2, col - left.length);
117
+ let line = left + ' '.repeat(pad) + (opt.help || '');
118
+ if (opt.example) {
119
+ line += `\n${' '.repeat(col)}examples: ${opt.example}`;
120
+ }
121
+ return line;
122
+ }
123
+
124
+ /** Compute column width from a set of options. */
125
+ function optionColumnWidth(options, negatable) {
126
+ let max = 0;
127
+ for (const [name, opt] of Object.entries(options)) {
128
+ const shortFlag = opt.short ? `-X, ` : ' ';
129
+ const flag = (opt.type === 'boolean' && negatable) ? `--[no-]${name}` : `--${name}`;
130
+ const argHint = opt.type === 'string' ? ` <${name.replace(/-/g, '_')}>` : '';
131
+ max = Math.max(max, ` ${shortFlag}${flag}${argHint}`.length);
132
+ }
133
+ return max + 2; // 2 chars minimum padding
134
+ }
135
+
14
136
  function showHelp() {
15
- console.log(`
16
- Usage: npx @interopio/gateway-server <command> [options]
17
-
18
- Commands:
19
- run Start the gateway server
20
- manage Send management commands to a running gateway server
21
- passwd Generate password hash (default using Argon2)
22
- mkcert Generate client and/or server certificate signed by Dev CA
23
-
24
- run options:
25
- -p, --port <port> Specify port or port range to bind the server to (default: 0 i.e. random)
26
- examples: 8385, 8000-8100, 3000,4000-4050
27
- -H, --host <host> Network address to bind to (default: unspecified, listens on all)
28
- examples: localhost, 127.0.0.1, 0.0.0.0, ::1
29
- -u, --user <name> Enables basic authentication and sets the admin username
30
- --no-auth Disable authentication (overrides config, sets auth type to 'none')
31
- -S, --ssl, --tls Enable HTTPS. Auto-generates Dev CA and/or server certificates if not
32
- present. Enables x509 client cert auth if --user not specified.
33
- --cert <file> File with SSL/TLS certificate (default: ./gateway-server.crt)
34
- --key <file> File with SSL/TLS private key (default: ./gateway-server.key)
35
- --ca <file> File with CA certificates (default: ./gateway-ca.crt)
36
- --ca-key <file> File with CA private key (default: ./gateway-ca.key)
37
- --no-ssl, --no-tls Disable SSL/TLS (overrides config)
38
- -g, --gateway Enable gateway endpoint (default route: /)
39
- --no-gateway Disable gateway endpoint (overrides config)
40
- -s, --static <location> Serve static files from specified location (e.g., ./public)
41
- -c, --config <file> Server configuration file (JSON format)
42
- --debug Enable debug logging (default: info level)
43
-
44
- manage options:
45
- --path <path> Path to the gateway control socket (named pipe on Windows, Unix socket)
46
- examples: \\\\.\\pipe\\glue42-gateway-xxx, /tmp/gateway.sock
47
- -p, --port <port> TCP port of the management server
48
- --timeout <ms> Connection timeout in milliseconds (default: 5000)
49
- <command> Management command to execute: info, shutdown
50
- [key=value...] Additional command parameters as key=value pairs
51
- Values are parsed as JSON (numbers, booleans, arrays, objects)
52
- or kept as strings if not valid JSON
53
- <json> Alternatively, pass entire command as a JSON object
54
- example: '{"command":"update-auth","type":"basic"}'
55
-
56
- passwd options:
57
- (no args) Prompt for password interactively (masked input)
58
- --stdin Read password from stdin (for piping, e.g., echo "pass" | ...)
59
-
60
- mkcert options:
61
- --client Generate client certificate (default: server certificate)
62
- -u, --user <name> Common Name for the certificate (default: dev-user for client certs)
63
- (--client only)
64
- --ca <file> File with CA certificate (default: ./gateway-ca.crt)
65
- --ca-key <file> File with CA private key (default: ./gateway-ca.key)
66
- --key <file> Output file for private key (default: ./gateway-server.key for server,
67
- ./gateway-client.key for client)
68
- --cert <file> Output file for certificate (default: ./gateway-server.crt for server,
69
- ./gateway-client.crt for client)
70
- [name...] DNS names, IP addresses, or email addresses for subjectAltName
71
- (DNS by default, prefix with 'IP:' or 'EMAIL:' for other types)
72
-
73
- Global Options:
74
- -v, --version Show version information and exit
75
- --help Show this help message and exit
76
-
77
- Examples:
78
- gateway-server run -p 3000
79
- gateway-server run -u admin --port 8385,8388 --debug
80
- gateway-server run -p 8443 --ssl --user admin --gateway
81
- gateway-server run --port 42443 --tls --ca-key ./ssl/ca.key --host example.com --gateway
82
- gateway-server run -p 3000 --static ./public --config ./server-config.json
83
- gateway-server run --config ./server-config.json --no-gateway --no-ssl --no-auth
84
- gateway-server manage --path \\\\.\\pipe\\glue42-gateway-xxx info
85
- gateway-server manage --path \\\\.\\pipe\\glue42-gateway-xxx shutdown
86
- gateway-server manage --path \\\\.\\pipe\\glue42-gateway-xxx custom-cmd key1=value1 count=42 'data={"user":"test"}' --timeout 10000
87
- gateway-server manage --path \\\\.\\pipe\\glue42-gateway-xxx '{"command":"update-auth","auth":{"token":"my-token"}}}'
88
- gateway-server passwd
89
- echo "mySecret123" | gateway-server passwd --stdin
90
- gateway-server mkcert
91
- gateway-server mkcert localhost 127.0.0.1 IP:192.168.1.100
92
- gateway-server mkcert --client EMAIL:john.doe@example.com
93
- gateway-server mkcert example.com *.example.com --key ./gateway-server.key --cert ./gateway-server.crt
94
- `);
137
+ const lines = [
138
+ '',
139
+ 'Usage: gateway-server <command> [options]',
140
+ '',
141
+ 'Commands:',
142
+ ];
143
+
144
+ // Command list
145
+ for (const [name, cmd] of Object.entries(commands)) {
146
+ lines.push(` ${name.padEnd(24)} ${cmd.description}`);
147
+ }
148
+
149
+ // Per-command options
150
+ for (const [name, cmd] of Object.entries(commands)) {
151
+ lines.push('');
152
+ const positionals = cmd.positionals ? ` ${cmd.positionals}` : '';
153
+ lines.push(`${name}${positionals} options:`);
154
+ const col = optionColumnWidth(cmd.options, cmd.allowNegative);
155
+ for (const [optName, opt] of Object.entries(cmd.options)) {
156
+ lines.push(formatOption(optName, opt, cmd.allowNegative, col));
157
+ }
158
+ }
159
+
160
+ // Global options
161
+ lines.push('');
162
+ lines.push('Global options:');
163
+ lines.push(' -v, --version Show version information and exit');
164
+ lines.push(' -h, --help Show this help message and exit');
165
+
166
+ // Examples
167
+ lines.push('');
168
+ lines.push('Examples:');
169
+ for (const cmd of Object.values(commands)) {
170
+ for (const ex of (cmd.examples || [])) {
171
+ lines.push(` ${ex}`);
172
+ }
173
+ }
174
+
175
+ console.log(lines.join('\n'));
176
+ process.exit(0);
177
+ }
178
+
179
+ /** Extract parseArgs-compatible options from a command definition (strips help/example). */
180
+ function argsOptions(name) {
181
+ const cmd = commands[name];
182
+ const opts = { help: { type: 'boolean', short: 'h' } };
183
+ for (const [k, v] of Object.entries(cmd.options)) {
184
+ const o = { type: v.type };
185
+ if (v.short) o.short = v.short;
186
+ if (v.multiple) o.multiple = true;
187
+ opts[k] = o;
188
+ }
189
+ return opts;
190
+ }
191
+
192
+ /** Show help for a single command and exit. */
193
+ function showCommandHelp(name) {
194
+ const cmd = commands[name];
195
+ const positionals = cmd.positionals ? ` ${cmd.positionals}` : '';
196
+ const lines = [
197
+ '',
198
+ `Usage: gateway-server ${name}${positionals} [options]`,
199
+ '',
200
+ cmd.description,
201
+ '',
202
+ 'Options:',
203
+ ];
204
+
205
+ const col = optionColumnWidth(cmd.options, cmd.allowNegative);
206
+ for (const [optName, opt] of Object.entries(cmd.options)) {
207
+ lines.push(formatOption(optName, opt, cmd.allowNegative, col));
208
+ }
209
+ const helpLeft = ' -h, --help';
210
+ lines.push(helpLeft + ' '.repeat(Math.max(2, col - helpLeft.length)) + 'Show this help message');
211
+
212
+ if (cmd.examples && cmd.examples.length > 0) {
213
+ lines.push('');
214
+ lines.push('Examples:');
215
+ for (const ex of cmd.examples) {
216
+ lines.push(` ${ex}`);
217
+ }
218
+ }
219
+
220
+ console.log(lines.join('\n'));
95
221
  process.exit(0);
96
222
  }
97
223
 
@@ -100,6 +226,22 @@ function showVersion() {
100
226
  process.exit(0);
101
227
  }
102
228
 
229
+ /** Read the nearest package.json starting from cwd, walking up. */
230
+ function readPackageJson() {
231
+ const { readFileSync } = require('node:fs');
232
+ const { join, dirname } = require('node:path');
233
+ let dir = process.cwd();
234
+ while (true) {
235
+ try {
236
+ return JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'));
237
+ } catch {
238
+ const parent = dirname(dir);
239
+ if (parent === dir) return {};
240
+ dir = parent;
241
+ }
242
+ }
243
+ }
244
+
103
245
  // Parse command-line arguments
104
246
  const { values: globalValues, positionals } = parseArgs({
105
247
  args: process.argv.slice(2),
@@ -115,7 +257,7 @@ const { values: globalValues, positionals } = parseArgs({
115
257
  if (globalValues.version) {
116
258
  showVersion();
117
259
  }
118
- if (globalValues.help) {
260
+ if (globalValues.help && positionals.length === 0) {
119
261
  showHelp();
120
262
  }
121
263
 
@@ -133,6 +275,9 @@ switch (command) {
133
275
  case 'run':
134
276
  runServer().catch(e => {console.error(e); process.exit(1);});
135
277
  break;
278
+ case 'build':
279
+ buildCommand().catch(e => {console.error(e); process.exit(1);});
280
+ break;
136
281
  case 'manage':
137
282
  manageCommand().catch(e => {console.error(e); process.exit(1);});
138
283
  break;
@@ -148,18 +293,65 @@ switch (command) {
148
293
  process.exit(1);
149
294
  }
150
295
 
296
+ // Command: build - Build a Single Executable Application (SEA)
297
+ async function buildCommand() {
298
+ const { values, positionals } = parseArgs({
299
+ args: process.argv.slice(3),
300
+ options: argsOptions('build'),
301
+ strict: true,
302
+ allowPositionals: true,
303
+ });
304
+ if (values.help) showCommandHelp('build');
305
+
306
+ // Default app-name and app-version from the nearest package.json
307
+ const pkg = readPackageJson();
308
+ const name = values['app-name'] || (pkg.name ? pkg.name.replace(/^@.*\//, '') : 'gateway-server');
309
+ const entryPoints = positionals.length > 0 ? positionals : [`./bin/${name}.cjs`];
310
+ const executable = values.executable;
311
+
312
+ if (!executable) {
313
+ try {
314
+ if (require('node:sea').isSea()) {
315
+ console.error('Error: --executable is required when running from a single executable application.');
316
+ console.error('Provide the path to a Node.js binary, e.g. --executable /usr/local/bin/node');
317
+ process.exit(1);
318
+ }
319
+ } catch {
320
+ // not a SEA build
321
+ }
322
+ }
323
+
324
+ const targetPath = await build.buildSea(name, {
325
+ version: values['app-version'] || pkg.version,
326
+ outDir: values.outdir,
327
+ esbuild: {
328
+ entryPoints,
329
+ define: {
330
+ 'process.env.NODE_ENV': '"production"',
331
+ 'process.env.WS_NO_UTF_8_VALIDATE': 'true',
332
+ 'process.env.WS_NO_BUFFER_UTIL': 'true'
333
+ },
334
+ },
335
+ config: {
336
+ executable,
337
+ execArgv: ['--experimental-websocket'],
338
+ execArgvExtension: 'cli',
339
+ },
340
+ });
341
+
342
+ console.log(`SEA executable built: ${targetPath}`);
343
+ process.exit(0);
344
+ }
345
+
151
346
  // Command: manage - Send management commands to a running gateway server
152
347
  async function manageCommand() {
153
348
  const { values, positionals } = parseArgs({
154
- args: process.argv.slice(3), // Skip 'node', 'gateway-server', and 'manage'
155
- options: {
156
- path: { type: 'string' },
157
- port: { type: 'string', short: 'p' },
158
- timeout: { type: 'string' },
159
- },
349
+ args: process.argv.slice(3),
350
+ options: argsOptions('manage'),
160
351
  strict: true,
161
352
  allowPositionals: true,
162
353
  });
354
+ if (values.help) showCommandHelp('manage');
163
355
 
164
356
  const socketPath = values.path;
165
357
  const port = values.port ? parseInt(values.port, 10) : undefined;
@@ -241,13 +433,12 @@ async function manageCommand() {
241
433
  // Command: passwd - Generate password hash
242
434
  async function passwdCommand() {
243
435
  const { values } = parseArgs({
244
- args: process.argv.slice(3), // Skip 'node', 'gateway-server', and 'passwd'
245
- options: {
246
- stdin: { type: 'boolean' },
247
- },
436
+ args: process.argv.slice(3),
437
+ options: argsOptions('passwd'),
248
438
  strict: true,
249
439
  allowPositionals: false,
250
440
  });
441
+ if (values.help) showCommandHelp('passwd');
251
442
 
252
443
  let password/*: string = undefined!*/;
253
444
 
@@ -349,18 +540,12 @@ async function promptPassword(prompt/*: string*/) {
349
540
  // Command: mkcert - Generate client or server certificate
350
541
  async function mkcertCommand() {
351
542
  const { values, positionals } = parseArgs({
352
- args: process.argv.slice(3), // Skip 'node', 'gateway-server', and 'mkcert'
353
- options: {
354
- client: { type: 'boolean' },
355
- user: { type: 'string', short: 'u' },
356
- ca: { type: 'string' },
357
- 'ca-key': { type: 'string' },
358
- key: { type: 'string' },
359
- cert: { type: 'string' },
360
- },
543
+ args: process.argv.slice(3),
544
+ options: argsOptions('mkcert'),
361
545
  strict: true,
362
546
  allowPositionals: true,
363
547
  });
548
+ if (values.help) showCommandHelp('mkcert');
364
549
 
365
550
  const isClientCert = values.client || false;
366
551
  const user = values.user || 'dev-user';
@@ -471,27 +656,13 @@ async function mkcertCommand() {
471
656
  // Command: run - Start the server
472
657
  async function runServer() {
473
658
  const { values } = parseArgs({
474
- args: process.argv.slice(3), // Skip 'node', 'gateway-server', and 'run'
475
- options: {
476
- port: { type: 'string', short: 'p' },
477
- host: { type: 'string', short: 'H' },
478
- user: { type: 'string', short: 'u' },
479
- debug: { type: 'boolean' },
480
- ssl: { type: 'boolean', short: 'S' },
481
- tls: { type: 'boolean' },
482
- cert: { type: 'string' },
483
- key: { type: 'string' },
484
- ca: { type: 'string' },
485
- 'ca-key': { type: 'string' },
486
- config: { type: 'string', short: 'c' },
487
- gateway: { type: 'boolean', short: 'g' },
488
- static: { type: 'string', short: 's', multiple: true },
489
- auth: { type: 'boolean' }
490
- },
659
+ args: process.argv.slice(3),
660
+ options: argsOptions('run'),
491
661
  strict: true,
492
662
  allowNegative: true,
493
663
  allowPositionals: false,
494
664
  });
665
+ if (values.help) showCommandHelp('run');
495
666
 
496
667
  const options = {
497
668
  port: values.port,
package/changelog.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  # Change Log
4
4
 
5
+ ## 0.24.0 (2026-03-22)
6
+ ### Added
7
+ - feat: move build sea as part of the cli (npx @interopio/gateway-server build)###
8
+ ### Changed
9
+ - chore: bump @interopio/gateway to 0.25.1
10
+ - chore: bump undici to 7.24.4
11
+
12
+ ## 0.23.1 (2026-03-13)
13
+ ### Fixed
14
+ - fix: legacy config token-ttl
15
+ - fix: cleanup Unix domain socket on shutdown
16
+ ### Changed
17
+ - chore: bump tough-cookie to 6.0.1
18
+ - chore: bump undici to 7.24.0
19
+
5
20
  ## 0.23.0 (2026-02-23)
6
21
 
7
22
  ### Fixed
@@ -1,3 +1,3 @@
1
1
  "use strict";var $=Object.create;var c=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var P=Object.getOwnPropertyNames;var z=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var p=(e,t)=>()=>(e&&(t=e(e=0)),t);var m=(e,t)=>{for(var r in t)c(e,r,{get:t[r],enumerable:!0})},h=(e,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of P(t))!A.call(e,n)&&n!==r&&c(e,n,{get:()=>t[n],enumerable:!(i=E(t,n))||i.enumerable});return e};var R=(e,t,r)=>(r=e!=null?$(z(e)):{},h(t||!e||!e.__esModule?c(r,"default",{value:e,enumerable:!0}):r,e)),F=e=>h(c({},"__esModule",{value:!0}),e);function l(e){return v.getLogger(`gateway.server.${e}`)}var v,C=p(()=>{"use strict";v=R(require("@interopio/gateway/logging/core"),1)});var S={};m(S,{default:()=>q});function T(e,t,r){Object.entries(e.nodes).forEach(([i,n])=>{i!==r&&(t.send(d.encode({type:"node-added","node-id":r,"new-node":i})),n.send(d.encode({type:"node-added","node-id":i,"new-node":r})))})}function k(e,t){Object.entries(e.nodes).forEach(([r,i])=>{r!==t&&i.send(d.encode({type:"node-removed","node-id":r,"removed-node":t}))})}function j(e,t){a.info(`${t}connection accepted`)}function B(e,t,r,i){a.info(`${t}connection closed [${r}](${i})`);let n=e.sockets[t];if(n){delete e.sockets[t];for(let s of n)delete e.nodes[s];for(let s of n)k(e,s)}}function N(e,t,r,i){switch(i.type){case"hello":{let n=i["node-id"];e.nodes[n]=t,e.sockets[r]=e.sockets[r]??[],e.sockets[r].push(n),a.info(`[${r}] node ${n} added.`),T(e,t,n);break}case"bye":{let n=i["node-id"];delete e[n],a.info(`[${r}] node ${n} removed.`),k(e,n);break}case"data":{let n=i.from,s=i.to;if(s==="all")Object.entries(e.nodes).forEach(([o,x])=>{o!==n&&x.send(d.encode(i))});else{let o=e.nodes[s];o?o.send(d.encode(i)):a.warn(`unable to send to node ${s} message ${JSON.stringify(i)}`)}break}default:{a.warn(`[${r}] ignoring unknown message ${JSON.stringify(i)}`);break}}}function D(e,t,r,i){try{let n=d.decode(i);a.enabledFor("debug")&&a.debug(`${r}processing msg ${JSON.stringify(n)}`),N(e,t,r,n)}catch(n){a.error(`${r}unable to process message`,n)}}async function J(e){let t={nodes:{},sockets:{}};return a.info("mesh server is listening"),async({socket:r,handshake:i})=>{let n=i.logPrefix;j(t,n),r.on("error",s=>{a.error(`${n}websocket error: ${s}`,s)}),r.on("message",(s,o)=>{Array.isArray(s)&&(s=Buffer.concat(s)),D(t,r,n,s)}),r.on("close",(s,o)=>{B(t,n,s,o)})}}var G,W,a,d,q,L=p(()=>{"use strict";C();G=require("@interopio/gateway"),W=G.IOGateway.Encoding,a=l("mesh.ws.broker");d=W.transit({keywordize:new Map([["/type","*"],["/message/body/type","*"],["/message/origin","*"],["/message/receiver/type","*"],["/message/source/type","*"],["/message/body/type","*"]])});q=J});var Z={};m(Z,{configure_logging:()=>Y,create:()=>X});module.exports=F(Z);var y=require("node:util"),f=class{#e;#t;#r;#i;constructor(t){this.#e=t}parsed(){if(this.#t===void 0){let t,r=this.#e.data;this.#e.data[0]instanceof Error&&(t=this.#e.data[0],r=r.slice(1));let i=(0,y.format)(this.#e.message,...r);this.#t={err:t,msg:i}}return this.#t}get time(){return this.#e.time}get level(){return this.#e.level}get namespace(){return this.#e.name}get file(){}get line(){}get message(){return this.parsed().msg}get stacktrace(){return this.parsed().err}get timestamp(){return this.#r===void 0&&(this.#r=this.time.toISOString()),this.#r}get output(){if(this.#i===void 0){let t=this.parsed().err,r=t?`
2
- ${t.stack??t}`:"";this.#i=`${this.timestamp} ${this.level.toUpperCase()} [${this.namespace}] - ${this.message}${r}`}return this.#i}};function w(e){let t="info";e?.level&&(e.level==="fatal"?t="error":e.level!=="report"&&(t=e.level));let r={level:typeof t=="string"?{gateway:t}:t};e?.disabled_action_groups&&e.disabled_action_groups.forEach(n=>{r.level[`gateway.action.${n}`]="off"});let i=e?.appender;return i&&(r.appender=n=>{i(new f(n))}),r}var b=require("@interopio/gateway-server"),u=class{constructor(t){this.config=t}server;async connect(t){if(!this.server)throw new Error("not started");return await this.server.gateway.connect((i,n)=>t(i,n))}info(){return this.server?.gateway.info()}async start(){return this.server||(this.server=await b.GatewayServer.Factory(this.config)),this}async stop(){return await this.server?.close(),delete this.server,this}};function O(e){if(e){let t=e.publishers.map(i=>({identity:i.publisher,metrics:i.metrics})),r=e["non-matched"];return{publishers:t,non_matched:r}}}function g(e){let t=O(e?.filters),r=H(e?.conflation),i={...e,filters:t,conflation:r};return t||delete i.filters,r||delete i.conflation,i}function H(e){if(e)return{interval:e.interval}}function K(e){let t={publishers:[]};return e?.publishers?.forEach(r=>{if(typeof r=="string"){if(r==="rest"){if(t.publishers.push("rest"),e.rest){let i={...e.rest},n=i["user-agent"];delete i["user-agent"];let s={...i.headers,...n?{"user-agent":n}:{}};delete i.headers,t.rest={endpoint:i.endpoint,headers:s,...g(i)},t.rest.publishFn??="@interopio/gateway-server/metrics/publisher/rest"}}else if(r==="file"&&(t.publishers.push("file"),e.file)){let i={...e.file},n=i["skip-status"]===void 0?!0:!i["skip-status"];delete i["skip-status"],t.file={location:i.location,status:n,...g(i)},t.file.publishFn??="@interopio/gateway/metrics/publisher/file"}}else{let i={...r},n=i["split-size"];delete i["split-size"];let s=r.publisher?.file,o={split_size:n,publisher:{file:s,configuration:r.publisher?.configuration},context:r.context,...g(i)};o.split_size===void 0&&delete o.split_size,t.publishers.push(o)}}),e?.filters&&(t.filters=O(e?.filters)),t}function _(e){return e?.endsWith("/")?e.slice(0,-1):e}function U(e){if(e?.directory){let t=e.directory,r={endpoint:e?.endpoint};if(t.type==="rest"){let i;if(r.endpoint===void 0?r.endpoint=_(t.config?.directory_uri):i={uri:_(t.config?.directory_uri)},t.config?.announce_interval&&(i??={},i.interval=Number(t.config.announce_interval)),i!==void 0&&(r.directory=i,r.directory.metadata??=t.config?.metadata),t.config){let n={...t.config};delete n.directory_uri,delete n.announce_interval,Object.keys(n).length>0&&(r.opts=n)}return r}else if(t.type==="static")return r.directory={members:t.members??[]},r}}function Q(e){let t={auth:{user:null}};if(e?.configuration?.node_id&&(t.node=e.configuration.node_id),e?.configuration?.user&&(t.auth.user=e.configuration?.user),e?.type==="broker"&&(t.broker={endpoint:e.broker?.endpoint??"<unresolved>"}),e?.type==="p2p"){let r=U(e.p2p);r&&(t.cluster=r)}return t}function V(e){let t={available:[]};return e?.default&&(t.default=e.default),(e?.available).forEach(i=>{(i==="basic"||i==="oauth2"||e?.[i]?.authenticator!==void 0)&&(t.available.push(i),e?.[i]!==void 0&&(t[i]=e[i]))}),t}function I(e){let t={route:e.route,maxConnections:e.limits?.max_connections,origins:e.security?.origin_filters,authorize:e.authorize??{access:"permitted"},ping:e.ping,clients:e.clients??{inactive_seconds:0,buffer_size:100},contexts:{lifetime:"retained",visibility:[{context:/___channel___.+/,restrictions:"cluster"},{context:/T42\..+/,restrictions:"local"}]},methods:{visibility:[{method:/T42\..+/,restrictions:"local"}]},peers:{visibility:[{domain:"context",restrictions:"cluster"},{domain:"agm",restrictions:"local"}]},metrics:{publishers:[]}};return e.authentication!==void 0&&(e.authentication.token_ttl&&(t.token={ttl:e.authentication?.token_ttl}),(e.authentication.available||e.authentication.default)&&(t.authentication=V(e.authentication))),e.globals&&(t.globals=e.globals),e.contexts&&(t.contexts=e.contexts),e.methods&&(t.methods=e.methods),e.peers&&(t.peers=e.peers),e.cluster?.enabled&&(t.mesh=Q(e.cluster)),e.metrics?.publishers&&(t.metrics=K(e.metrics)),{port:e.port??3434,host:e.ip??e.host,cors:e.cors===null?void 0:e.cors??!1,memory:e.memory,app:async r=>{e.cluster?.embedded_broker?.enabled===!0&&r.socket({path:e.cluster.embedded_broker.route??"/mesh-broker",options:{authorize:e.cluster.embedded_broker.authorize??{access:"permitted"}},factory:async i=>{t.mesh?.broker?.endpoint==="<unresolved>"&&(t.mesh.broker.endpoint=i.endpoint);let n=(await Promise.resolve().then(()=>(L(),S))).default;return await n(i)}})},gateway:t}}var M=require("@interopio/gateway/logging/core");function X(e){return new u(I(e))}function Y(e){(0,M.configure)(w(e))}0&&(module.exports={configure_logging,create});
2
+ ${t.stack??t}`:"";this.#i=`${this.timestamp} ${this.level.toUpperCase()} [${this.namespace}] - ${this.message}${r}`}return this.#i}};function w(e){let t="info";e?.level&&(e.level==="fatal"?t="error":e.level!=="report"&&(t=e.level));let r={level:typeof t=="string"?{gateway:t}:t};e?.disabled_action_groups&&e.disabled_action_groups.forEach(n=>{r.level[`gateway.action.${n}`]="off"});let i=e?.appender;return i&&(r.appender=n=>{i(new f(n))}),r}var b=require("@interopio/gateway-server"),u=class{constructor(t){this.config=t}server;async connect(t){if(!this.server)throw new Error("not started");return await this.server.gateway.connect((i,n)=>t(i,n))}info(){return this.server?.gateway.info()}async start(){return this.server||(this.server=await b.GatewayServer.Factory(this.config)),this}async stop(){return await this.server?.close(),delete this.server,this}};function O(e){if(e){let t=e.publishers.map(i=>({identity:i.publisher,metrics:i.metrics})),r=e["non-matched"];return{publishers:t,non_matched:r}}}function g(e){let t=O(e?.filters),r=H(e?.conflation),i={...e,filters:t,conflation:r};return t||delete i.filters,r||delete i.conflation,i}function H(e){if(e)return{interval:e.interval}}function K(e){let t={publishers:[]};return e?.publishers?.forEach(r=>{if(typeof r=="string"){if(r==="rest"){if(t.publishers.push("rest"),e.rest){let i={...e.rest},n=i["user-agent"];delete i["user-agent"];let s={...i.headers,...n?{"user-agent":n}:{}};delete i.headers,t.rest={endpoint:i.endpoint,headers:s,...g(i)},t.rest.publishFn??="@interopio/gateway-server/metrics/publisher/rest"}}else if(r==="file"&&(t.publishers.push("file"),e.file)){let i={...e.file},n=i["skip-status"]===void 0?!0:!i["skip-status"];delete i["skip-status"],t.file={location:i.location,status:n,...g(i)},t.file.publishFn??="@interopio/gateway/metrics/publisher/file"}}else{let i={...r},n=i["split-size"];delete i["split-size"];let s=r.publisher?.file,o={split_size:n,publisher:{file:s,configuration:r.publisher?.configuration},context:r.context,...g(i)};o.split_size===void 0&&delete o.split_size,t.publishers.push(o)}}),e?.filters&&(t.filters=O(e?.filters)),t}function _(e){return e?.endsWith("/")?e.slice(0,-1):e}function U(e){if(e?.directory){let t=e.directory,r={endpoint:e?.endpoint};if(t.type==="rest"){let i;if(r.endpoint===void 0?r.endpoint=_(t.config?.directory_uri):i={uri:_(t.config?.directory_uri)},t.config?.announce_interval&&(i??={},i.interval=Number(t.config.announce_interval)),i!==void 0&&(r.directory=i,r.directory.metadata??=t.config?.metadata),t.config){let n={...t.config};delete n.directory_uri,delete n.announce_interval,Object.keys(n).length>0&&(r.opts=n)}return r}else if(t.type==="static")return r.directory={members:t.members??[]},r}}function Q(e){let t={auth:{user:null}};if(e?.configuration?.node_id&&(t.node=e.configuration.node_id),e?.configuration?.user&&(t.auth.user=e.configuration?.user),e?.type==="broker"&&(t.broker={endpoint:e.broker?.endpoint??"<unresolved>"}),e?.type==="p2p"){let r=U(e.p2p);r&&(t.cluster=r)}return t}function V(e){let t={available:[]};return e?.default&&(t.default=e.default),(e?.available).forEach(i=>{(i==="basic"||i==="oauth2"||e?.[i]?.authenticator!==void 0)&&(t.available.push(i),e?.[i]!==void 0&&(t[i]=e[i]))}),t}function I(e){let t={route:e.route,maxConnections:e.limits?.max_connections,origins:e.security?.origin_filters,authorize:e.authorize??{access:"permitted"},ping:e.ping,clients:e.clients??{inactive_seconds:0,buffer_size:100},contexts:{lifetime:"retained",visibility:[{context:/___channel___.+/,restrictions:"cluster"},{context:/T42\..+/,restrictions:"local"}]},methods:{visibility:[{method:/T42\..+/,restrictions:"local"}]},peers:{visibility:[{domain:"context",restrictions:"cluster"},{domain:"agm",restrictions:"local"}]},metrics:{publishers:[]}};if(e.authentication!==void 0){let r=e.authentication.token_ttl??e.authentication["token-ttl"];r!==void 0&&(t.token={ttl:r}),(e.authentication.available||e.authentication.default)&&(t.authentication=V(e.authentication))}return e.globals&&(t.globals=e.globals),e.contexts&&(t.contexts=e.contexts),e.methods&&(t.methods=e.methods),e.peers&&(t.peers=e.peers),e.cluster?.enabled&&(t.mesh=Q(e.cluster)),e.metrics?.publishers&&(t.metrics=K(e.metrics)),{port:e.port??3434,host:e.ip??e.host,cors:e.cors===null?void 0:e.cors??!1,memory:e.memory,app:async r=>{e.cluster?.embedded_broker?.enabled===!0&&r.socket({path:e.cluster.embedded_broker.route??"/mesh-broker",options:{authorize:e.cluster.embedded_broker.authorize??{access:"permitted"}},factory:async i=>{t.mesh?.broker?.endpoint==="<unresolved>"&&(t.mesh.broker.endpoint=i.endpoint);let n=(await Promise.resolve().then(()=>(L(),S))).default;return await n(i)}})},gateway:t}}var M=require("@interopio/gateway/logging/core");function X(e){return new u(I(e))}function Y(e){(0,M.configure)(w(e))}0&&(module.exports={configure_logging,create});
3
3
  //# sourceMappingURL=gateway-ent.cjs.map