samanbayaka 0.0.20 → 0.0.22

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/README.md CHANGED
@@ -14,8 +14,16 @@ This project is a modular, production-ready microservices framework built with M
14
14
  - [Installation](#installation)
15
15
  - [Prerequisites](#prerequisites)
16
16
  - [Documentations](#documentations)
17
+ - [Errors](#errors)
18
+ - [getConfig](#getConfig)
19
+ - [loadDemo](#loadDemo)
20
+ - [loadGatewayService](#loadGatewayService)
21
+ - [loadFeatureService](#loadFeatureService)
22
+ - [auxBrokerService](#auxBrokerService)
17
23
  - [Usage](#usage)
18
24
  - [Demo](#Demo)
25
+ - [Dockers](#dockers)
26
+ - [Etcd](#etcd)
19
27
 
20
28
  ## Features
21
29
 
@@ -43,14 +51,14 @@ import sbk from "samanbayaka"
43
51
  ```
44
52
  ## Prerequisites
45
53
  It is assumed that NATS, Redpanda, Redis, and Etcd are installed and properly configured. All services should be discoverable through the /etc/hosts file.
46
- #### Minimum required Node.js version: >= 22.x.x
54
+ ### Minimum required Node.js version: >= 22.x.x
47
55
  ```bash
48
56
  node -v
49
57
  nvm use 22
50
58
  ```
51
59
  Additionally, OpenObserve is used to view logs and telemetry.
52
60
 
53
- #### Environment variables
61
+ ### Environment variables
54
62
  To configure all required environment variables, create a Bash file:
55
63
  ```bash
56
64
  source /etc/profile.d/sbk.sh
@@ -84,14 +92,14 @@ Optionally, you may verify the set environment variables.
84
92
  ```bash
85
93
  echo $SBK_PORT
86
94
  ```
87
- #### Configuration files
95
+ ### Configuration files
88
96
  Create a directory to store the configuration files, then copy all configuration files from the current project path into this directory and update them as needed. Before copying, ensure that your current working directory is the project directory.
89
97
  ```bash
90
98
  pwd
91
99
  sudo mkdir -p /usr/local/etc/<your_folder>
92
100
  sudo cp config/*.*  /usr/local/etc/<your_folder>
93
101
  ```
94
- #### Log files
102
+ ### Log files
95
103
  For production, it is recommended to create a new directory named "samanbayaka" under /var/log to store logs.
96
104
  ```bash
97
105
  sudo mkdir -p /var/log/samanbayaka
@@ -102,7 +110,7 @@ Empty your log files if they become very large, as follows:
102
110
  ```bash
103
111
  truncate -s 0 /var/log/samanbayaka/sbk-*.log
104
112
  ```
105
- #### Setup logrotate (optional)
113
+ ### Setup logrotate (optional)
106
114
  Create config file:
107
115
  ```bash
108
116
  sudo nano /etc/logrotate.d/sbk
@@ -123,25 +131,25 @@ Paste this:
123
131
 
124
132
  ## Documentations
125
133
 
126
- ### sbk.Errors
134
+ ### Errors
127
135
 
128
136
  `sbk.Errors` exposes the Moleculer `Errors` object.
129
137
 
130
- ### sbk.getConfig
138
+ ### getConfig
131
139
 
132
140
  `sbk.getConfig` is a function that returns a configuration object from a specified file name.
133
141
 
134
142
  The file is loaded from the configuration directory defined by the environment variable.
135
143
 
136
- ### sbk.loadDemo
144
+ ### loadDemo
137
145
 
138
146
  `sbk.loadDemo` is an asynchronous function that creates a demo service to help understand the project.
139
147
 
140
- ### sbk.loadGatewayService
148
+ ### loadGatewayService
141
149
 
142
150
  `sbk.loadGatewayService` is an asynchronous function that creates a gateway service to expose REST APIs.
143
151
 
144
- ### sbk.loadFeatureService
152
+ ### loadFeatureService
145
153
 
146
154
  `sbk.loadFeatureService` is an asynchronous function that creates a feature service.
147
155
 
@@ -173,7 +181,7 @@ Example:
173
181
  ```
174
182
 
175
183
 
176
- ### sbk.auxBrokerService
184
+ ### auxBrokerService
177
185
 
178
186
  `sbk.auxBrokerService` is a function used to initialize and manage message brokers such as Kafka, MQTT, and RabbitMQ.
179
187
 
@@ -253,7 +261,7 @@ Example:
253
261
  ```
254
262
 
255
263
  ## Usage
256
- #### Create gateway service
264
+ ### Create gateway service
257
265
  The Gateway is a critical service that exposes all endpoints as REST APIs. At least one Gateway service must be running to make the REST APIs accessible.
258
266
  ```bash
259
267
  mkdir gateway
@@ -269,7 +277,7 @@ import sbk from "samanbayaka"
269
277
  await sbk.loadGatewayService()
270
278
  ```
271
279
  ---
272
- #### Create feature services
280
+ ### Create feature services
273
281
  ```bash
274
282
  mkdir <your_service_name>
275
283
  cd <your_service_name>
@@ -328,7 +336,7 @@ await sbk.loadFeatureService({
328
336
 
329
337
  ```
330
338
  ---
331
- #### Create auxaliary broker services
339
+ ### Create auxaliary broker services
332
340
  ##### for producer
333
341
  ```bash
334
342
  mkdir <your_service_name>-<type>-<topic>
@@ -369,7 +377,7 @@ If you do not expose the service as a REST API and run it as a private/internal
369
377
  rest: false
370
378
  ```
371
379
 
372
- ##### for consumer
380
+ #### for consumer
373
381
  ```bash
374
382
  mkdir <your_service_name>-<type>-<topic>-<group>
375
383
  cd <your_service_name>-<type>-<topic>-<group>
@@ -407,7 +415,7 @@ The `interMessageDelayMs` option introduces a delay between two consecutive mess
407
415
 
408
416
  ---
409
417
 
410
- #### Run the services
418
+ ### Run the services
411
419
 
412
420
  * development/testing
413
421
  ```bash
@@ -443,6 +451,134 @@ Run the service, demo
443
451
  node demo.mjs
444
452
  ```
445
453
 
454
+ ## Dockers
455
+
456
+ ### Etcd
457
+ To manage configurations centrally, use the docker-compose.yml file to run Etcd.
458
+ ```bash
459
+ mkdir -p etcd
460
+ cd etcd
461
+ touch docker-compose.yml
462
+ export ETCD_ROOT_PW=<your_root_pass>
463
+ export ETCD_CONFIG_ADMIN_PW=<your_config_admin_pass>
464
+ ```
465
+
466
+ Open `docker-compose.yml` and paste the following:
467
+ ```yml
468
+ services:
469
+ etcd:
470
+ image: quay.io/coreos/etcd:v3.5.5
471
+ container_name: sbk-etcd
472
+
473
+ ports:
474
+ - "<your_api_port>:2379"
475
+ - "<your_cluster_port>:2380"
476
+
477
+ volumes:
478
+ - /usr/local/etc/samanbayaka:/etcd-data
479
+
480
+ command:
481
+ - /usr/local/bin/etcd
482
+ - --name=etcd
483
+ - --data-dir=/etcd-data
484
+ - --listen-client-urls=http://0.0.0.0:2379
485
+ - --advertise-client-urls=http://etcd:2379
486
+ - --listen-peer-urls=http://0.0.0.0:2380
487
+ - --initial-advertise-peer-urls=http://etcd:2380
488
+ - --initial-cluster=etcd=http://etcd:2380
489
+ - --initial-cluster-state=new
490
+
491
+ restart: unless-stopped
492
+
493
+ etcd-init:
494
+ image: quay.io/coreos/etcd:v3.5.5
495
+ depends_on:
496
+ - etcd
497
+
498
+ volumes:
499
+ - /usr/local/etc/samanbayaka:/etcd-data
500
+
501
+ environment:
502
+ - ETCDCTL_API=3
503
+
504
+ entrypoint:
505
+ - /bin/sh
506
+ - -c
507
+
508
+ command:
509
+ - |
510
+ set -e
511
+
512
+ echo "waiting for etcd..."
513
+
514
+ for i in $(seq 1 30); do
515
+ etcdctl --endpoints=http://etcd:2379 endpoint health && break
516
+ echo "retry $$i..."
517
+ sleep 2
518
+ done
519
+
520
+ echo "etcd initialized"
521
+
522
+ echo "Creating the root role"
523
+ etcdctl --endpoints=http://etcd:2379 role add root || true
524
+
525
+ echo "Creating the root user"
526
+ etcdctl --endpoints=http://etcd:2379 user add root:${ETCD_ROOT_PW} || true
527
+
528
+ echo "Granting the root role to the root user"
529
+ etcdctl --endpoints=http://etcd:2379 user grant-role root root
530
+
531
+ echo "Enable authentication"
532
+ etcdctl --endpoints=http://etcd:2379 auth enable || true
533
+
534
+ # -------------------------------------------------------
535
+
536
+ echo "Creating admin role"
537
+ etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role add admin
538
+
539
+ echo "Granting broad permissions"
540
+ etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true admin readwrite /
541
+
542
+ echo "Creating configadmin user"
543
+ etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user add configadmin:${ETCD_CONFIG_ADMIN_PW}
544
+
545
+ echo "Assign role"
546
+ etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role configadmin admin
547
+
548
+ # ---------------------------------------------------------
549
+
550
+ echo "Creating Roles and Granting"
551
+ etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role add gateway
552
+ etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true gateway read /config/yaml/nats
553
+ etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true gateway read /config/yaml/auth
554
+ etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true gateway read /config/yaml/catch
555
+ etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} role grant-permission --prefix=true gateway read /config/yaml/telemetry
556
+
557
+ # ---------------------------------------------------------
558
+
559
+ echo "Creating User and Assign Role"
560
+ etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user add <your_user>:<your_pass>
561
+ etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role apigtwy gateway
562
+
563
+ # ---------------------------------------------------------
564
+
565
+ etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/yaml/nats "$(cat /etcd-data/nats.yml)" || true
566
+
567
+ #etcdctl --endpoints=http://etcd:2379 --user=<your_user>:<your_pass> get /config/yaml/nats
568
+
569
+
570
+ echo "etcd initialization completed"
571
+ ```
572
+ Optionally verify:
573
+ ```bash
574
+ docker ps | grep 'sbk-etcd'
575
+ ```
576
+ Optionally check health:
577
+ ```bash
578
+ docker exec -it sbk-etcd etcdctl --endpoints=http://etcd:2379 endpoint health
579
+ ```
580
+ ---
581
+
446
582
  <p align="center" style="margin-top: 100px;">
447
583
  <img src="https://moleculer.services/images/banner.png" alt="Moleculer Logo" width="600">
448
584
  </p>
package/commit-hash.mjs CHANGED
@@ -1 +1 @@
1
- export const COMMIT_HASH = '8d687db';
1
+ export const COMMIT_HASH = '02c6744';
@@ -0,0 +1,21 @@
1
+ import { Etcd3 } from "etcd3"
2
+ import YAML from 'yaml'
3
+
4
+ const [user, pass] = (process.env.SBK_CONFIG_URPW || "ur:pa").split(":")
5
+
6
+ const client = new Etcd3({
7
+ hosts: "http://etcd:12379",
8
+ auth: {
9
+ username: user,
10
+ password: pass
11
+ }
12
+ })
13
+
14
+ try {
15
+ const yamlText = await client.get("/config/yaml/telemetry")
16
+ const obj = YAML.parse(yamlText);
17
+
18
+ console.log(obj);
19
+ } catch (err) {
20
+ console.error("Configuration reading error: ", err.message)
21
+ }
@@ -7,13 +7,24 @@ import os from "os"
7
7
  import { createRequire } from 'module'
8
8
 
9
9
  import chokidar from "chokidar"
10
-
10
+ import { Etcd3 } from "etcd3"
11
+ import YAML from 'yaml'
11
12
 
12
13
  const __filename = fileURLToPath(import.meta.url)
13
14
  const __dirname = path.dirname(__filename)
14
15
  const require = createRequire(import.meta.url)
15
16
 
16
17
 
18
+ const [user, pass] = (process.env.SBK_CONFIG_URPW || "ur:pa").split(":")
19
+
20
+ const client = new Etcd3({
21
+ hosts: "http://etcd:12379",
22
+ auth: {
23
+ username: user,
24
+ password: pass
25
+ }
26
+ })
27
+
17
28
  /**
18
29
  * Configuration path
19
30
  * @type {string}
@@ -47,42 +58,51 @@ const SERVICES_DIR = __dirname.split('node_modules')[0]
47
58
  * @return {object}
48
59
  */
49
60
  export const getConfig = async (fileName) => {
50
- const configFile = path.
51
- join(
52
- CONFIG_PATH,
53
- `${fileName}.mjs`
54
- )
55
-
56
- // /**
57
- // * Validate Configuration
58
- // */
59
- // if(process.env.NODE_ENV){
60
- // console.error("NODE_ENV must be 'production', 'testing', or 'development'")
61
- // process.exit(0)
62
- // }
61
+ // const configFile = path
62
+ // .join(
63
+ // CONFIG_PATH,
64
+ // `${fileName}.mjs`
65
+ // )
66
+
67
+ // // /**
68
+ // // * Validate Configuration
69
+ // // */
70
+ // // if(process.env.NODE_ENV){
71
+ // // console.error("NODE_ENV must be 'production', 'testing', or 'development'")
72
+ // // process.exit(0)
73
+ // // }
63
74
 
64
75
 
65
- return (await import(pathToFileURL(configFile).href)).default
76
+ // return (await import(pathToFileURL(configFile).href)).default
77
+
78
+ // try {
79
+ const yamlText = await client.get(`/config/yaml/${fileName}`)
80
+ return Object.freeze(
81
+ YAML.parse(yamlText)
82
+ )
83
+ // } catch (err) {
84
+ // throw new Error(`Configuration reading error: ${err.message}`)
85
+ // }
66
86
  }
67
87
 
68
88
 
69
- /**
70
- * Getting server configuration.
71
- * @type {string}
72
- */
73
- const CONFIG = await getConfig('server')
89
+ // /**
90
+ // * Getting server configuration.
91
+ // * @type {string}
92
+ // */
93
+ // const CONFIG = await getConfig('server')
74
94
 
75
95
 
76
- /**
77
- * Assets path
78
- */
79
- export const assetPath = {
80
- rootFolder: path
81
- .join(
82
- ABSOLUTE_PATH,
83
- CONFIG.assetPath,
84
- ),
85
- }
96
+ // /**
97
+ // * Assets path
98
+ // */
99
+ // export const assetPath = {
100
+ // rootFolder: path
101
+ // .join(
102
+ // ABSOLUTE_PATH,
103
+ // CONFIG.assetPath,
104
+ // ),
105
+ // }
86
106
 
87
107
 
88
108
  /**
@@ -139,18 +159,18 @@ export const pkgDtls = {
139
159
  }
140
160
 
141
161
 
142
- /**
143
- * OpenAPI configuration
144
- */
145
- export const openApiConfig = {
146
- info: {
147
- title: pkgDtls.name,
148
- version: pkgDtls.version,
149
- summary: CONFIG.openApiInfo[0].summary,
150
- description: CONFIG.openApiInfo[0].description,
151
- },
152
- servers: CONFIG.openApiInfo[0].url,
153
- }
162
+ // /**
163
+ // * OpenAPI configuration
164
+ // */
165
+ // export const openApiConfig = {
166
+ // info: {
167
+ // title: pkgDtls.name,
168
+ // version: pkgDtls.version,
169
+ // summary: CONFIG.openApiInfo[0].summary,
170
+ // description: CONFIG.openApiInfo[0].description,
171
+ // },
172
+ // servers: CONFIG.openApiInfo[0].url,
173
+ // }
154
174
 
155
175
  // /**
156
176
  // * Load modules from path as moleculer-repl is only supports cjs files
@@ -2,9 +2,25 @@ import ApiGateway from "moleculer-web"
2
2
  import jwt from "jsonwebtoken"
3
3
  import jwksClient from "jwks-rsa"
4
4
 
5
+ // const OPENID_CONFIG = {
6
+ // url: "https://accounts.google.com/.well-known/openid-configuration",
7
+ // url: "",
8
+ // clientId: "184045176764-ugg28aegdro383pintufun14uubtt374.apps.googleusercontent.com",
9
+ // jwksClient: {
10
+ // cache: true,
11
+ // cacheMaxEntries: 5,
12
+ // cacheMaxAge: 10 * 60 * 1000,
13
+ // rateLimit: true,
14
+ // jwksRequestsPerMinute: 10,
15
+ // },
16
+ // jwtVerifyAlgo: ["RS256"],
17
+ // client: {},
18
+ // issuer: "",
19
+ // }
20
+
5
21
  const OPENID_CONFIG = {
6
- url: "https://accounts.google.com/.well-known/openid-configuration",
7
- clientId: "184045176764-ugg28aegdro383pintufun14uubtt374.apps.googleusercontent.com",
22
+ url: "https://auth.wbsedcl.in/realms/redpanda/.well-known/openid-configuration",
23
+ clientId: "bff-client",
8
24
  jwksClient: {
9
25
  cache: true,
10
26
  cacheMaxEntries: 5,
@@ -159,7 +175,18 @@ export const authorize = async (ctx, route, req) => {
159
175
  })
160
176
 
161
177
  ctx.broker.logger.debug({message: "Decoded Token Object", token: decoded})
162
- ctx.meta.user = { name: decoded?.name, email: decoded?.email }
178
+ ctx.meta.user = {
179
+ sessionId: decoded?.sid,
180
+ id: decoded?.sub,
181
+ userId: (decoded?.sub).split(":").at(-1),
182
+ username: decoded?.preferred_username,
183
+ firstName: decoded?.given_name,
184
+ lastName: decoded?.family_name,
185
+ fullName: [...new Set(decoded?.name.split(/\s+/))].join(" "),
186
+ emailIds: decoded?.email,
187
+ mobileNos: decoded?.mobile_no,
188
+ userRoles: decoded?.user_role,
189
+ }
163
190
  return decoded
164
191
 
165
192
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "samanbayaka",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "description": "Moleculer Gateway service with kafka transporter",
5
5
  "homepage": "https://gitlab.com/dalal.suvendu/samanbayaka#readme",
6
6
  "bugs": {
@@ -41,6 +41,7 @@
41
41
  "chokidar": "^5.0.0",
42
42
  "compression": "^1.8.1",
43
43
  "cookie-parser": "^1.4.7",
44
+ "etcd3": "^1.1.2",
44
45
  "helmet": "^8.1.0",
45
46
  "ioredis": "^5.10.1",
46
47
  "jsonwebtoken": "^9.0.3",
@@ -55,7 +56,8 @@
55
56
  "nats": "^2.29.3",
56
57
  "pino": "^10.3.1",
57
58
  "pnpm": "^10.32.1",
58
- "sinon": "^21.1.2"
59
+ "sinon": "^21.1.2",
60
+ "yaml": "^2.9.0"
59
61
  },
60
62
  "devDependencies": {
61
63
  "chai": "^6.2.2",
@@ -41,7 +41,8 @@ export default {
41
41
  },
42
42
 
43
43
  handler: async(ctx) => {
44
- return ctx.meta.user
44
+ const { sessionId, id, ...profile } = ctx.meta.user
45
+ return profile
45
46
  }
46
47
  }
47
48
  },
@@ -73,7 +73,7 @@ export default {
73
73
  */
74
74
  {
75
75
  path: "/api",
76
- authorization: true,
76
+ authorization: false,
77
77
  whitelist: [
78
78
  /**
79
79
  * Access any actions except 'gateway' and 'system' service