samanbayaka 0.0.26 → 0.0.28
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 +5 -3
- package/commit-hash.mjs +1 -1
- package/config/nats.yml +0 -1
- package/config/sysconfigs.yml +24 -0
- package/helper/file/esm-loading.mjs +21 -151
- package/helper/mol-built-in/AjvValidator.mjs +1 -14
- package/helper/utility/config-handler.mjs +42 -12
- package/helper/utility/error-handler.mjs +2 -2
- package/helper/utility/global-configs-validator.mjs +3 -2
- package/helper/utility/openapi-to-mol-params.mjs +71 -0
- package/index.mjs +25 -4
- package/package.json +2 -1
- package/public/config-manager.html +0 -2
- package/public/scalar/index.html +27 -0
- package/services/about/index.mjs +2 -1
- package/services/gateway/index.mjs +34 -22
- package/services/system/config-manager.mjs +460 -0
- package/services/system/generate-openapi-docs.mjs +55 -0
- package/services/system/index.mjs +66 -229
- package/services/system/{scalar.mjs → scalar-ui.mjs} +3 -3
- package/services/system/system-manager.mjs +152 -0
- package/services/system/config/server.mjs +0 -36
- package/services/system/sw-stats-mw.mjs +0 -12
package/README.md
CHANGED
|
@@ -436,6 +436,8 @@ SBK_CONFIG_CRED='<your_etcs_user> <your_etcd_pass> <your_etcd_port>' node index.
|
|
|
436
436
|
```
|
|
437
437
|
or
|
|
438
438
|
```bash
|
|
439
|
+
rm -rf node_modules/samanbayaka/ &&cp -r ../../samanbayaka/. node_modules/samanbayaka/ && SBK_CONFIG_CRED='sbk sbk@123 12379' node index.mjs
|
|
440
|
+
|
|
439
441
|
pm2 stop "$(basename "$PWD")" && rm -rf node_modules/samanbayaka/ &&cp -r ../../samanbayaka/. node_modules/samanbayaka/ && SBK_CONFIG_CRED='sbk sbk@123 12379' pm2 start index.mjs --name "$(basename "$PWD")" --stop-exit-codes 1 --output /var/log/samanbayaka/sbk-out-${HOSTNAME}-$$.log --error /var/log/samanbayaka/sbk-err-${HOSTNAME}-$$.log
|
|
440
442
|
```
|
|
441
443
|
* production
|
|
@@ -618,6 +620,8 @@ services:
|
|
|
618
620
|
etcdctl --endpoints=http://etcd:2379 --user=root:${ETCD_ROOT_PW} user grant-role msg msg
|
|
619
621
|
|
|
620
622
|
# ---------------------------------------------------------
|
|
623
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/sys/yaml/SYS_CONFIGS "$(cat /etcd-data/sysconfig.yml)" || true
|
|
624
|
+
|
|
621
625
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/REVISION "" || true
|
|
622
626
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/APP_ENV development || true
|
|
623
627
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/global/envs/LOG_LEVEL warn || true
|
|
@@ -652,14 +656,12 @@ services:
|
|
|
652
656
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/demo true || true
|
|
653
657
|
|
|
654
658
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system true || true
|
|
655
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/PORT 8765 || true
|
|
656
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/BROADCAST_INTERVAL 600000 || true
|
|
657
659
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/LOG_LEVEL error || true
|
|
658
660
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/MAX_L1_TTL 0 || true
|
|
659
661
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/system/envs/MAX_L2_TTL 0 || true
|
|
660
662
|
|
|
661
663
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/gateway true || true
|
|
662
|
-
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/gateway/envs/PORT
|
|
664
|
+
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/gateway/envs/PORT 8765 || true
|
|
663
665
|
|
|
664
666
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/test true || true
|
|
665
667
|
etcdctl --endpoints=http://etcd:2379 --user=configadmin:${ETCD_CONFIG_ADMIN_PW} put /config/sbk/members/sms add || true
|
package/commit-hash.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const COMMIT_HASH = '
|
|
1
|
+
export const COMMIT_HASH = 'f4221ba';
|
package/config/nats.yml
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Expose the system API on the specified port
|
|
2
|
+
port: <your_sys_port>
|
|
3
|
+
|
|
4
|
+
# Project description
|
|
5
|
+
projDescription: "{#var#} is a microservices-based project built with moleculer and moleculer-web, designed for scalable, high-performance service communication and API management."
|
|
6
|
+
|
|
7
|
+
# Configuration brodcast interval in miliseconds
|
|
8
|
+
broadcastInterval: 600000 # 10 minitues
|
|
9
|
+
|
|
10
|
+
# The broadcast interval increases by the specified factor after each broadcast,
|
|
11
|
+
# i.e., interval = factor × interval.
|
|
12
|
+
factor: 1.1
|
|
13
|
+
|
|
14
|
+
# Configuration broadcast maximum duration in miliseconds
|
|
15
|
+
maxBroadcastDuration: 86400000 # 24 hours
|
|
16
|
+
|
|
17
|
+
# Expose the API to the domain
|
|
18
|
+
domain: sbk.wbsedcl.in
|
|
19
|
+
|
|
20
|
+
# Directory Path for API Assets
|
|
21
|
+
assetPath: public
|
|
22
|
+
|
|
23
|
+
# URL of Redpanda web client
|
|
24
|
+
redpandaWebUiPath: http://redpanda.web.ui:9080
|
|
@@ -7,24 +7,11 @@ import os from "os"
|
|
|
7
7
|
import { createRequire } from 'module'
|
|
8
8
|
|
|
9
9
|
import chokidar from "chokidar"
|
|
10
|
-
import * as configHld from '#hUti/config-handler.mjs'
|
|
11
10
|
|
|
12
11
|
const __filename = fileURLToPath(import.meta.url)
|
|
13
12
|
const __dirname = path.dirname(__filename)
|
|
14
13
|
const require = createRequire(import.meta.url)
|
|
15
14
|
|
|
16
|
-
/**
|
|
17
|
-
* Edge configs
|
|
18
|
-
*/
|
|
19
|
-
const EC_ASSET_PATH = (await configHld.getConfigs(`/config/sbk/edge/asset/path`)) || "public"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Configuration path
|
|
24
|
-
* @type {string}
|
|
25
|
-
*/
|
|
26
|
-
const CONFIG_PATH = process.env.SBK_CONFIG_PATH // Environment variable of configuration path
|
|
27
|
-
|
|
28
15
|
|
|
29
16
|
/**
|
|
30
17
|
* Project absolute path
|
|
@@ -50,12 +37,12 @@ const SERVICES_DIR = /node_modules/.test(__dirname)
|
|
|
50
37
|
/**
|
|
51
38
|
* Assets path
|
|
52
39
|
*/
|
|
53
|
-
export const
|
|
54
|
-
|
|
40
|
+
export const absoluteAssetPath = (dirName) => {
|
|
41
|
+
return path
|
|
55
42
|
.join(
|
|
56
43
|
ABSOLUTE_PATH,
|
|
57
|
-
|
|
58
|
-
)
|
|
44
|
+
dirName,
|
|
45
|
+
)
|
|
59
46
|
}
|
|
60
47
|
|
|
61
48
|
|
|
@@ -103,7 +90,7 @@ const pkgMain = readPkg(ABSOLUTE_PATH)
|
|
|
103
90
|
* Create and object of name and version
|
|
104
91
|
* @type {Object}
|
|
105
92
|
*/
|
|
106
|
-
export const
|
|
93
|
+
export const pkgInfo = {
|
|
107
94
|
name: pkgMain.name.split('-')[0]
|
|
108
95
|
.split(" ")
|
|
109
96
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
@@ -113,139 +100,22 @@ export const pkgDtls = {
|
|
|
113
100
|
}
|
|
114
101
|
|
|
115
102
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
// * @param {RegExp} regx to filter only *.mjs files from service path
|
|
133
|
-
// * @return {void}
|
|
134
|
-
// */
|
|
135
|
-
// export const loadServices = async (broker) => {
|
|
136
|
-
// /**
|
|
137
|
-
// * Derive the service directory from the server configuration.
|
|
138
|
-
// * @type {string}
|
|
139
|
-
// */
|
|
140
|
-
// const SERVICES_DIR = path
|
|
141
|
-
// .join(
|
|
142
|
-
// ABSOLUTE_PATH,
|
|
143
|
-
// CONFIG.servicesDir,
|
|
144
|
-
// serviceName
|
|
145
|
-
// )
|
|
146
|
-
|
|
147
|
-
// const filePath = path.join(SERVICES_DIR, CONFIG.serviceMain)
|
|
148
|
-
|
|
149
|
-
// /**
|
|
150
|
-
// * Dynamic import with cache busting
|
|
151
|
-
// * @type {object}
|
|
152
|
-
// */
|
|
153
|
-
// const module = await import(`${pathToFileURL(filePath)}?t=${Date.now()}`)
|
|
154
|
-
// const schema = module.default || module
|
|
155
|
-
|
|
156
|
-
// if (!schema || typeof schema !== "object" || !schema.name || schema.name != serviceName) {
|
|
157
|
-
// const regex = new RegExp(`(\\/${CONFIG.servicesDir}\\/.*)$`)
|
|
158
|
-
// const rfPath = pathToFileURL(filePath).href.match(regex)[1]
|
|
159
|
-
// await broker.stop()
|
|
160
|
-
// broker.logger.fatal('SBKERR ❖', `Service start failed: invalid service name or schema in ${rfPath}`)
|
|
161
|
-
// process.exit(0)
|
|
162
|
-
// }
|
|
163
|
-
|
|
164
|
-
// broker.createService(schema)
|
|
165
|
-
// broker.logger.info('SBKMSG ❖', `Hot-realod: ${isHotReloadEnabled ? "ON" : "OFF"}`)
|
|
166
|
-
|
|
167
|
-
// const watcher = chokidar.watch(SERVICES_DIR, {
|
|
168
|
-
// ignoreInitial: true,
|
|
169
|
-
// awaitWriteFinish: {
|
|
170
|
-
// stabilityThreshold: 200, // wait 200ms after last change
|
|
171
|
-
// pollInterval: 50
|
|
172
|
-
// },
|
|
173
|
-
// ignored: [
|
|
174
|
-
// /(^|[\/\\])\../,
|
|
175
|
-
// /~$/,
|
|
176
|
-
// /\.swp$/,
|
|
177
|
-
// /\.tmp$/
|
|
178
|
-
// ]
|
|
179
|
-
// })
|
|
180
|
-
|
|
181
|
-
// const handleWatchFile = async(wfPath, isUnlink) => {
|
|
182
|
-
// const regex = new RegExp(`(\\/${CONFIG.servicesDir}\\/.*)$`)
|
|
183
|
-
// const rfPath = pathToFileURL(wfPath).href.match(regex)[1]
|
|
184
|
-
// /**
|
|
185
|
-
// * Hot Reloading of moleculer services from service path
|
|
186
|
-
// */
|
|
187
|
-
// if(isHotReloadEnabled){
|
|
188
|
-
// if(path.basename(filePath) === path.basename(wfPath)){
|
|
189
|
-
// const oldServiceFullName = (broker.services.find(s => s.name === serviceName))?.fullName
|
|
190
|
-
// const oldService = broker.getLocalService(oldServiceFullName)
|
|
191
|
-
|
|
192
|
-
// if (!isUnlink) {
|
|
193
|
-
// try {
|
|
194
|
-
// /**
|
|
195
|
-
// * Dynamic import with cache busting
|
|
196
|
-
// */
|
|
197
|
-
// const serviceModule = await import(`${pathToFileURL(filePath)}?t=${Date.now()}`)
|
|
198
|
-
// const schema = serviceModule.default || serviceModule
|
|
199
|
-
|
|
200
|
-
// if (!schema || typeof schema !== "object" || !schema.name || schema.name != serviceName) {
|
|
201
|
-
// broker.logger.error('SBKERR ❖', `Hot-reloading terminated due to an invalid service name or schema for ${filePath}`)
|
|
202
|
-
// return
|
|
203
|
-
// }
|
|
204
|
-
|
|
205
|
-
// /**
|
|
206
|
-
// * Remove the already loaded service if it exists.
|
|
207
|
-
// */
|
|
208
|
-
// if (oldService) {
|
|
209
|
-
// await broker.destroyService(oldService)
|
|
210
|
-
// }
|
|
211
|
-
|
|
212
|
-
// /**
|
|
213
|
-
// * Create new service
|
|
214
|
-
// */
|
|
215
|
-
// broker.createService(schema)
|
|
216
|
-
// const newServiceFullName = schema.version === undefined
|
|
217
|
-
// ? schema.name
|
|
218
|
-
// : `${schema.version}.${schema.name}`
|
|
219
|
-
// broker.logger.info('SBKMSG ❖', `Service '${newServiceFullName}' reloaded.`)
|
|
220
|
-
// } catch (err) {
|
|
221
|
-
// broker.logger.error('SBKERR ❖', `Hot-reloading of service '${newServiceFullName}' failed..`, err)
|
|
222
|
-
// }
|
|
223
|
-
// } else if (event === "unlink") {
|
|
224
|
-
// /**
|
|
225
|
-
// * Remove the already loaded service if it exists.
|
|
226
|
-
// */
|
|
227
|
-
// if (oldService) {
|
|
228
|
-
// await broker.destroyService(oldService)
|
|
229
|
-
// broker.logger.info('SBKMSG ❖', `Service '${newServiceFullName}' removed.`)
|
|
230
|
-
// }
|
|
231
|
-
// }
|
|
232
|
-
// }
|
|
233
|
-
// else {
|
|
234
|
-
// broker.logger.warn('SBKWRN ❖',`Changes detected in the file "${rfPath}". Restart required to apply updates.`)
|
|
235
|
-
// }
|
|
236
|
-
|
|
237
|
-
// }
|
|
238
|
-
// else {
|
|
239
|
-
// broker.logger.warn('SBKWRN ❖',`Changes detected in the file "${rfPath}". Restart required to apply updates.`)
|
|
240
|
-
// }
|
|
241
|
-
// }
|
|
242
|
-
|
|
243
|
-
// watcher.on("add", (fp) => handleWatchFile(fp, false))
|
|
244
|
-
// watcher.on("change", (fp) => handleWatchFile(fp, false))
|
|
245
|
-
// watcher.on("unlink", (fp) => handleWatchFile(fp, true))
|
|
246
|
-
// }
|
|
247
|
-
|
|
248
|
-
|
|
103
|
+
/**
|
|
104
|
+
* File chage watcher in the service directory
|
|
105
|
+
*/
|
|
106
|
+
export const dirWatcher = chokidar.watch(SERVICES_DIR, {
|
|
107
|
+
ignoreInitial: true,
|
|
108
|
+
awaitWriteFinish: {
|
|
109
|
+
stabilityThreshold: 2000, // wait 2000ms after last change
|
|
110
|
+
pollInterval: 50
|
|
111
|
+
},
|
|
112
|
+
ignored: [
|
|
113
|
+
/(^|[\/\\])\../,
|
|
114
|
+
/~$/,
|
|
115
|
+
/\.swp$/,
|
|
116
|
+
/\.tmp$/
|
|
117
|
+
]
|
|
118
|
+
})
|
|
249
119
|
|
|
250
120
|
|
|
251
121
|
|
|
@@ -24,19 +24,18 @@ export const client = new Etcd3({
|
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* Getting configurations
|
|
28
|
-
* ftom the path defined in environment variable
|
|
27
|
+
* Getting configurations against a Etcd key
|
|
29
28
|
* @param {string}
|
|
30
|
-
* @return {object}
|
|
29
|
+
* @return {object | string}
|
|
31
30
|
*/
|
|
32
|
-
export const getConfigs = async (path) => {
|
|
31
|
+
export const getConfigs = async (path, isYaml = false) => {
|
|
33
32
|
try {
|
|
34
|
-
const yamlText = await client.get(path)
|
|
33
|
+
const yamlText = (await client.get(path))?.toString()
|
|
35
34
|
if ( path.split('/').includes('yaml') ) {
|
|
36
|
-
return Object.freeze( YAML.parse(yamlText
|
|
35
|
+
return isYaml ? yamlText : Object.freeze( YAML.parse( yamlText ) )
|
|
37
36
|
}
|
|
38
37
|
else {
|
|
39
|
-
return yamlText
|
|
38
|
+
return yamlText
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
} catch (err) {
|
|
@@ -44,7 +43,12 @@ export const getConfigs = async (path) => {
|
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Getting all keys having prefix path
|
|
48
|
+
* @param {string} path
|
|
49
|
+
* @param {Boolean} fullPath
|
|
50
|
+
* @return {array}
|
|
51
|
+
*/
|
|
48
52
|
export const getConfigKeys = async (path, fullPath = false) => {
|
|
49
53
|
try {
|
|
50
54
|
const entries = await client.getAll()
|
|
@@ -60,6 +64,35 @@ export const getConfigKeys = async (path, fullPath = false) => {
|
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Create Etcd key with value
|
|
69
|
+
* @param {string} path
|
|
70
|
+
* @param {string} data
|
|
71
|
+
*/
|
|
72
|
+
export const putConfig = async(path, data) => {
|
|
73
|
+
await client.put(path)
|
|
74
|
+
.value(data)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Delete Etcd key
|
|
79
|
+
* @param {string} path
|
|
80
|
+
* @return {string}
|
|
81
|
+
*/
|
|
82
|
+
export const delConfig = async(path) => {
|
|
83
|
+
const deletedData = await client
|
|
84
|
+
.delete()
|
|
85
|
+
.key(path)
|
|
86
|
+
.getPrevious()
|
|
87
|
+
|
|
88
|
+
return deletedData.map(item => ({
|
|
89
|
+
...item,
|
|
90
|
+
key: Buffer.from(item.key).toString("utf8"),
|
|
91
|
+
value: Buffer.from(item.value).toString("utf8"),
|
|
92
|
+
}))
|
|
93
|
+
|
|
94
|
+
}
|
|
95
|
+
|
|
63
96
|
|
|
64
97
|
export const getConfigAll = async (path, fullPath = false) => {
|
|
65
98
|
try {
|
|
@@ -115,8 +148,5 @@ export const watchConfigs = async (path, callback) => {
|
|
|
115
148
|
|
|
116
149
|
}
|
|
117
150
|
|
|
118
|
-
|
|
119
|
-
await client.put(path)
|
|
120
|
-
.value(data)
|
|
121
|
-
}
|
|
151
|
+
|
|
122
152
|
|
|
@@ -250,7 +250,7 @@ export const ErrorFormatterMW = {
|
|
|
250
250
|
return await next(ctx)
|
|
251
251
|
}
|
|
252
252
|
catch (err) {
|
|
253
|
-
if(!err?.data?.traceId){
|
|
253
|
+
if(!err?.data?.traceId) {
|
|
254
254
|
const requestID = ctx?.requestID
|
|
255
255
|
const status = err?.code || 500
|
|
256
256
|
const type = err?.type || 'INTERNAL_ERROR'
|
|
@@ -301,7 +301,7 @@ export const ErrorFormatterMW = {
|
|
|
301
301
|
* Ensures all errors include a standard set of fields such as status code,
|
|
302
302
|
* message, and optional metadata for client consumption.
|
|
303
303
|
*/
|
|
304
|
-
export const httpErrorFormatter = (req, res, err)=>{
|
|
304
|
+
export const httpErrorFormatter = (req, res, err)=> {
|
|
305
305
|
const code = err.code || 500
|
|
306
306
|
const errorBody = {
|
|
307
307
|
...(err?.data || { message: err.message }),
|
|
@@ -4,13 +4,13 @@ export const validateGlobalConfigs = async(prefix) => {
|
|
|
4
4
|
try{
|
|
5
5
|
const nodeVer = errHdl.checkMinNoveVer()
|
|
6
6
|
const configHdl = await import("./config-handler.mjs")
|
|
7
|
-
const { serviceDtls } = await import("#hFil/esm-loading.mjs")
|
|
7
|
+
const { serviceDtls, dirWatcher } = await import("#hFil/esm-loading.mjs")
|
|
8
8
|
const globalConfigs = await configHdl.getConfigAll(prefix)
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
const isServiceRemoved = (((await configHdl.getConfigs( `/config/sbk/members/${serviceDtls.name}` )) || "false") == "false")
|
|
12
12
|
if ( serviceDtls.name != "samanbayaka" && isServiceRemoved ) {
|
|
13
|
-
throw new Error (`The service "${serviceDtls.name}" is
|
|
13
|
+
throw new Error (`The service "${serviceDtls.name}" is disallowed by CONFIGADMIN.`)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
return Object.freeze({
|
|
@@ -22,6 +22,7 @@ export const validateGlobalConfigs = async(prefix) => {
|
|
|
22
22
|
telemetry: errHdl.validateTelemetry(globalConfigs?.TELEMETRY),
|
|
23
23
|
configRevision: errHdl.validateConfRevision(globalConfigs?.REVISION),
|
|
24
24
|
serviceDtls,
|
|
25
|
+
dirWatcher,
|
|
25
26
|
hostEntry: {
|
|
26
27
|
nats: await errHdl.validateHostEntry('nats'),
|
|
27
28
|
redis: await errHdl.validateHostEntry('redis'),
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate Moleculer params definitions from the OpenAPI schema to enable request parameter validation using AJV
|
|
3
|
+
* @param {object} schema
|
|
4
|
+
*/
|
|
5
|
+
export const openApiToMoleculerParams = (schema) => {
|
|
6
|
+
if( schema?.openapi?.parameters || schema?.openapi?.requestBody ){
|
|
7
|
+
schema.params = {
|
|
8
|
+
type: "object",
|
|
9
|
+
properties: {
|
|
10
|
+
params: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
},
|
|
14
|
+
required: [],
|
|
15
|
+
additionalProperties: false,
|
|
16
|
+
},
|
|
17
|
+
query: {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
|
|
21
|
+
},
|
|
22
|
+
required: [],
|
|
23
|
+
},
|
|
24
|
+
body: {}
|
|
25
|
+
},
|
|
26
|
+
required:[],
|
|
27
|
+
additionalProperties: false,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
if( schema?.openapi?.requestBody?.required ){
|
|
32
|
+
schema.params.required.push("body")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if( schema?.openapi?.requestBody && schema?.openapi?.requestBody?.content ){
|
|
36
|
+
schema.params.properties.body.anyOf = Object.entries(schema?.openapi?.requestBody?.content)
|
|
37
|
+
.map(el=>el[1].schema)
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if( schema?.openapi?.parameters ) {
|
|
42
|
+
schema.params.properties.params.properties = schema?.openapi?.parameters
|
|
43
|
+
.filter(el=> el.in == "path")
|
|
44
|
+
.reduce((obj, item) => {
|
|
45
|
+
obj[item.name] = item.schema
|
|
46
|
+
return obj
|
|
47
|
+
}, {})
|
|
48
|
+
schema.params.properties.params.required = Object.keys(schema.params.properties.params.properties)
|
|
49
|
+
|
|
50
|
+
if( schema.params.properties.params.required.length > 0 ){
|
|
51
|
+
schema.params.required.push("params")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
schema.params.properties.query.properties = schema?.openapi?.parameters
|
|
55
|
+
.filter(el=> el.in == "query").reduce((obj, item) => {
|
|
56
|
+
obj[item.name] = item.schema
|
|
57
|
+
return obj
|
|
58
|
+
}, {})
|
|
59
|
+
|
|
60
|
+
if( Object.keys(schema.params.properties.query.properties).length > 0 ){
|
|
61
|
+
schema.params.required.push("query")
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
schema.params.properties.query.required = schema?.openapi?.parameters
|
|
65
|
+
.filter(el=> el.in == "query")
|
|
66
|
+
.filter(el => el.required)
|
|
67
|
+
.map(el => el.name )
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
}
|
package/index.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import HybridCacher from "#hMol/HybridCacher.mjs"
|
|
|
10
10
|
|
|
11
11
|
import { gracefulShutdown, validateServiceName, ErrorFormatterMW } from '#hUti/error-handler.mjs'
|
|
12
12
|
import { createOpenTelemetryExporters, OpenTelemetryMW } from '#hUti/telemetry.mjs'
|
|
13
|
+
import { openApiToMoleculerParams } from '#hUti/openapi-to-mol-params.mjs'
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Global Configs
|
|
@@ -137,6 +138,18 @@ const createSbkServices = async(schemas, isREPL = false) => {
|
|
|
137
138
|
...configRevisionListner
|
|
138
139
|
}
|
|
139
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Override params according to the OpenAPI schema definition
|
|
143
|
+
*/
|
|
144
|
+
if( schema?.actions ) {
|
|
145
|
+
Object.keys(schema.actions).map((el) => {
|
|
146
|
+
if( schema.actions[el] ){
|
|
147
|
+
openApiToMoleculerParams(schema.actions[el])
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
140
153
|
if( index == 0 ) validateServiceName(schema, SBK_GLOBAL_CONFIGS.serviceDtls.name)
|
|
141
154
|
broker.createService(schema)
|
|
142
155
|
}
|
|
@@ -156,6 +169,17 @@ const createSbkServices = async(schemas, isREPL = false) => {
|
|
|
156
169
|
}
|
|
157
170
|
|
|
158
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Notify on changes to files in the service directory.
|
|
174
|
+
*/
|
|
175
|
+
SBK_GLOBAL_CONFIGS.dirWatcher.on("add", (fp) => {
|
|
176
|
+
broker.logger.warn({message: `The new file "${fp}" has been added to your service folder. Restart your service for the changes to take effect.`})
|
|
177
|
+
})
|
|
178
|
+
SBK_GLOBAL_CONFIGS.dirWatcher.on("change", (fp) => {
|
|
179
|
+
broker.logger.warn({message: `The file "${fp}" in your service folder has been modified. Restart your service for the changes to take effect.`})
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
|
|
159
183
|
/**
|
|
160
184
|
* Listen for force stop signals
|
|
161
185
|
*/
|
|
@@ -194,7 +218,6 @@ export default {
|
|
|
194
218
|
* Loading Demo
|
|
195
219
|
*/
|
|
196
220
|
createDemo: async() => {
|
|
197
|
-
const { default: about } = await import('#sAbt/index.mjs')
|
|
198
221
|
const { default: apiGateway } = await import('#sApi/index.mjs')
|
|
199
222
|
const demo = await import('#sDmo/index.mjs')
|
|
200
223
|
|
|
@@ -207,7 +230,6 @@ export default {
|
|
|
207
230
|
})
|
|
208
231
|
createSbkServices([
|
|
209
232
|
gtWy,
|
|
210
|
-
about,
|
|
211
233
|
demo.user,
|
|
212
234
|
demo.role,
|
|
213
235
|
demo.mail,
|
|
@@ -227,9 +249,8 @@ export default {
|
|
|
227
249
|
},
|
|
228
250
|
|
|
229
251
|
registerEdgeAPI: async () => {
|
|
230
|
-
const { default: about } = await import('#sAbt/index.mjs')
|
|
231
252
|
const { default: apiGateway } = await import('#sApi/index.mjs')
|
|
232
|
-
createSbkServices(
|
|
253
|
+
createSbkServices(apiGateway)
|
|
233
254
|
|
|
234
255
|
},
|
|
235
256
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "samanbayaka",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.28",
|
|
4
4
|
"description": "Moleculer Gateway service with kafka transporter",
|
|
5
5
|
"homepage": "https://gitlab.com/dalal.suvendu/samanbayaka#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"@opentelemetry/semantic-conventions": "^1.40.0",
|
|
41
41
|
"ajv": "^8.18.0",
|
|
42
42
|
"approve-builds": "^1.0.0",
|
|
43
|
+
"body-parser": "^2.3.0",
|
|
43
44
|
"chokidar": "^5.0.0",
|
|
44
45
|
"compression": "^1.8.1",
|
|
45
46
|
"cookie-parser": "^1.4.7",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>Scalar API Reference</title>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<meta
|
|
7
|
+
name="viewport"
|
|
8
|
+
content="width=device-width, initial-scale=1" />
|
|
9
|
+
</head>
|
|
10
|
+
|
|
11
|
+
<body>
|
|
12
|
+
<div id="app"></div>
|
|
13
|
+
|
|
14
|
+
<!-- Load the Script -->
|
|
15
|
+
<script src="./js/standalone.js"></script>
|
|
16
|
+
|
|
17
|
+
<!-- Initialize the Scalar API Reference -->
|
|
18
|
+
<script>
|
|
19
|
+
Scalar.createApiReference('#app', {
|
|
20
|
+
// The URL of the OpenAPI/Swagger document
|
|
21
|
+
url: '../sbk/system/docs/openapi/json',
|
|
22
|
+
// Avoid CORS issues
|
|
23
|
+
// proxyUrl: 'https://proxy.scalar.com',
|
|
24
|
+
})
|
|
25
|
+
</script>
|
|
26
|
+
</body>
|
|
27
|
+
</html>
|
package/services/about/index.mjs
CHANGED
|
@@ -21,7 +21,8 @@ export default {
|
|
|
21
21
|
},
|
|
22
22
|
|
|
23
23
|
handler: async(ctx) => {
|
|
24
|
-
return
|
|
24
|
+
return ctx.call("system.projDesc")
|
|
25
|
+
// return `${pkgDtls.name} is a microservices-based project built with moleculer and moleculer-web, designed for scalable, high-performance service communication and API management.`
|
|
25
26
|
},
|
|
26
27
|
},
|
|
27
28
|
version: {
|