corebasic 1.0.265 → 1.0.267

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.
@@ -48,6 +48,21 @@ const getFeatureMethod = (api) => api.split(' ')[0].toLowerCase();
48
48
  const getFeatureUrl = (api) => { const url = api.split(' ')[1]; if (!url)
49
49
  throw new Error(`Invalid Feature url in api: ${api}`); return url; };
50
50
  const getFeature = (name) => features[name];
51
+ function getLeaf(feature, req) {
52
+ if (feature)
53
+ return feature.split(/\.(query|command)\./)[0];
54
+ if (req) {
55
+ for (let key in features) {
56
+ const feature = features[key];
57
+ if (feature.featureless && feature.api === req.method.toUpperCase() + ' ' + req.path)
58
+ return key.split(/\.(query|command)\./)[0];
59
+ }
60
+ return "NOLEAF"; // This code will never be reached as apiHandler()'s prior code ensures req is valid and there exists a feature. Included to silence ./tsc
61
+ }
62
+ else {
63
+ return "NOLEAF"; // This code will never be reached as apiHandler()'s prior code ensures req is valid and there exists a feature. Included to silence ./tsc
64
+ }
65
+ }
51
66
  const DEPLOY_TOKEN_SECRET = process.env.DEPLOY_TOKEN_SECRET || "MY_SECRET_DEPLOY_TOKEN";
52
67
  const SERVICE_ACCESS_TOKEN = jwt.sign({ app: process.env.APP_DEPLOYMENT_NAME }, DEPLOY_TOKEN_SECRET, { expiresIn: '365d' });
53
68
  const NDCURVE_DEVELOPER_LICENSE_ACCESS_TOKEN = await (async () => { if (process.env.NDCURVE_DEVELOPER_SERVICE)
@@ -81,8 +96,8 @@ let SERVICE_ADDRESS = process.env.APP_ENDPOINT || 'http://127.0.0.1:3000';
81
96
  export const get = (feature) => {
82
97
  const throwError = () => { throw new Error(`Feature ${feature} not found in internal or external list during Features.subscribe call`); };
83
98
  const baseFeature = getFeature(feature);
84
- let { api, service = SERVICE_ADDRESS, topic } = baseFeature ? baseFeature : (SLYP_FEATURES_LIST[feature] ?? throwError());
85
- return { api, service, topic };
99
+ let { api, service = SERVICE_ADDRESS } = baseFeature ? baseFeature : (SLYP_FEATURES_LIST[feature] ?? throwError());
100
+ return { api, service };
86
101
  };
87
102
  export const send = async (meta, feature, data, params) => {
88
103
  const throwError = () => { throw new Error(`Feature ${feature} not found in internal or external list during inter feature call`); };
@@ -134,7 +149,7 @@ let appids = {};
134
149
  async function announce() {
135
150
  let exp_features = {};
136
151
  for (let [key, { api, subscribe }] of Object.entries(features))
137
- exp_features[key] = { api, service: SERVICE_ADDRESS, subscribe, topic: "" };
152
+ exp_features[key] = { api, service: SERVICE_ADDRESS, subscribe };
138
153
  await Messaging.subscribe(`${process.env.REDIS_CHANNEL_PREFIX}_SLYP_FEATURES_LIST`, async (message, _channel) => {
139
154
  let { uid, ...msg } = JSON.parse(message);
140
155
  if (uid !== appId && !appids[uid]) {
@@ -172,11 +187,12 @@ const apiHandler = async (req, res) => {
172
187
  throw { status: 404, message: `Resource not found. Feature ${req.body.feature} not available.` };
173
188
  }
174
189
  feature = feature; // typescript validation with !
190
+ const leaf = getLeaf(req.body.feature, req);
175
191
  let params = getFeatureUrl(feature.api).split("/").filter((item) => item.startsWith(":")).map((item) => item.replace(":", ""));
176
192
  for (let param of params)
177
193
  if (!req.params[param])
178
194
  throw { status: 404, message: "Resource not found. One or more url parameter not specified." };
179
- let meta = { ...req.body, data: undefined, topic: feature.topic, date: new Date().getTime() }; // TODO: Must also include invoiceTxn
195
+ let meta = { ...req.body, data: undefined, topic: leaf, date: new Date().getTime() }; // TODO: Must also include invoiceTxn
180
196
  if (process.env.USE_DEFAULT_COMPANY) {
181
197
  meta.company = 'DEFAULT_COMPANY';
182
198
  meta.outlet = 'DEFAULT_OUTLET';
@@ -318,7 +334,7 @@ export const start = async (app, url, file) => {
318
334
  app.get('/features', async (_req, res) => {
319
335
  let exp_features = {};
320
336
  for (let [key, { api }] of Object.entries(features))
321
- exp_features[key] = { api, service: `${SERVICE_ADDRESS}`, subscribe: '', topic: '' };
337
+ exp_features[key] = { api, service: `${SERVICE_ADDRESS}`, subscribe: '' };
322
338
  if (process.env.LOAD_LOCAL_FEATURES) {
323
339
  for (let key in SLYP_FEATURES_LIST)
324
340
  SLYP_FEATURES_LIST[key].headers = { JWT: SERVICE_ACCESS_TOKEN, service: true, NDCURVE_DEVELOPER_LICENSE_ACCESS_TOKEN }; // TODO: CRITICAL: Security issue
@@ -328,12 +344,13 @@ export const start = async (app, url, file) => {
328
344
  // Registering features
329
345
  await registerFeatures(features);
330
346
  // Get unique kafka topics list from features
331
- let kafkaTopics = [];
347
+ let kafkaTopics = new Set();
332
348
  for (const name in features) {
333
349
  let feature = features[name];
334
350
  if (feature.api.split(' ')[0]?.toLowerCase() === "get")
335
351
  continue;
336
- kafkaTopics = [...new Set(kafkaTopics.concat([feature.topic]))];
352
+ const leaf = getLeaf(name);
353
+ kafkaTopics.add(leaf);
337
354
  }
338
355
  // Subscribe to each topic
339
356
  for (let topic of kafkaTopics) {
@@ -442,7 +459,7 @@ async function subscribe() {
442
459
  const publisherFeature = getFeature(publisher);
443
460
  if (subscribed_consumers[consumer] || !publisherFeature)
444
461
  continue;
445
- let { topic } = publisherFeature;
462
+ let topic = getLeaf(publisher);
446
463
  let kafka_consumer_promise = Kafka.receive(`Features.${topic}`, consumer, async (topic, message) => {
447
464
  topic = topic.replace(/^.*Features./, '');
448
465
  const timer = (ms) => new Promise(res => setTimeout(res, ms)); // A promise that resolves after "ms" Milliseconds
package/libs/features.ts CHANGED
@@ -141,11 +141,10 @@ type RemoteFeatureEntry = {
141
141
  api: string
142
142
  service: string
143
143
  subscribe: string
144
- topic: string
145
144
  headers?: {JWT?: string, service?: boolean, NDCURVE_DEVELOPER_LICENSE_ACCESS_TOKEN?: string}
146
145
  }
147
146
 
148
- type FeatureEntry = { api: string, topic: string, bypass: boolean, featureless: boolean, subscribe: string, handler: Handler<unknown, unknown, keyof Schema>, opt?: string[], mut?: string[] }
147
+ type FeatureEntry = { api: string, bypass: boolean, featureless: boolean, subscribe: string, handler: Handler<unknown, unknown, keyof Schema>, opt?: string[], mut?: string[] }
149
148
 
150
149
 
151
150
  let features: Record<string, FeatureEntry> = {}
@@ -157,6 +156,23 @@ const getFeatureMethod = (api: string): HttpMethod => api.split(' ')[0]!.toLower
157
156
  const getFeatureUrl = (api: string): string => { const url = api.split(' ')[1]; if (!url) throw new Error(`Invalid Feature url in api: ${api}`); return url}
158
157
  const getFeature = (name: string): FeatureEntry | undefined => features[name]
159
158
 
159
+ function getLeaf(feature: string, req?: ExpressRequest): string {
160
+ if (feature)
161
+ return feature.split(/\.(query|command)\./)[0]!
162
+
163
+ if (req) {
164
+ for(let key in features) {
165
+ const feature = features[key]!
166
+ if (feature.featureless && feature.api === req.method.toUpperCase() + ' ' + req.path)
167
+ return key.split(/\.(query|command)\./)[0]!
168
+ }
169
+ return "NOLEAF" // This code will never be reached as apiHandler()'s prior code ensures req is valid and there exists a feature. Included to silence ./tsc
170
+ } else {
171
+ return "NOLEAF" // This code will never be reached as apiHandler()'s prior code ensures req is valid and there exists a feature. Included to silence ./tsc
172
+ }
173
+ }
174
+
175
+
160
176
  const DEPLOY_TOKEN_SECRET = process.env.DEPLOY_TOKEN_SECRET || "MY_SECRET_DEPLOY_TOKEN"
161
177
  const SERVICE_ACCESS_TOKEN = jwt.sign({app: process.env.APP_DEPLOYMENT_NAME}, DEPLOY_TOKEN_SECRET, { expiresIn: '365d' });
162
178
 
@@ -189,8 +205,8 @@ let SERVICE_ADDRESS = process.env.APP_ENDPOINT || 'http://127.0.0.1:3000'
189
205
  export const get = (feature: string) => {
190
206
  const throwError = () => {throw new Error(`Feature ${feature} not found in internal or external list during Features.subscribe call`)}
191
207
  const baseFeature: FeatureEntry | undefined = getFeature(feature)
192
- let {api, service = SERVICE_ADDRESS, topic} = baseFeature ? baseFeature as FeatureEntry & {service: string} : (SLYP_FEATURES_LIST[feature] ?? throwError())
193
- return {api, service, topic}
208
+ let {api, service = SERVICE_ADDRESS} = baseFeature ? baseFeature as FeatureEntry & {service: string} : (SLYP_FEATURES_LIST[feature] ?? throwError())
209
+ return {api, service}
194
210
  }
195
211
 
196
212
 
@@ -251,7 +267,7 @@ let appids: Record<string, boolean> = {}
251
267
  async function announce() {
252
268
  let exp_features: Record<string, RemoteFeatureEntry> = {}
253
269
  for (let [key, {api,subscribe}] of Object.entries(features))
254
- exp_features[key] = {api, service: SERVICE_ADDRESS, subscribe, topic: ""}
270
+ exp_features[key] = {api, service: SERVICE_ADDRESS, subscribe}
255
271
 
256
272
  await Messaging.subscribe(`${process.env.REDIS_CHANNEL_PREFIX}_SLYP_FEATURES_LIST`, async (message, _channel) => {
257
273
  let {uid, ...msg} = JSON.parse(message) as Record<string, RemoteFeatureEntry> & {uid: string}
@@ -297,12 +313,14 @@ const apiHandler = async (req: ExpressRequest, res: ExpressResponse) => {
297
313
 
298
314
  feature = feature! // typescript validation with !
299
315
 
316
+ const leaf = getLeaf(req.body.feature, req)
317
+
300
318
  let params = getFeatureUrl(feature.api).split("/").filter((item: string) => item.startsWith(":")).map((item: string) => item.replace(":", ""))
301
319
  for (let param of params)
302
320
  if (!req.params[param])
303
321
  throw { status: 404, message: "Resource not found. One or more url parameter not specified." }
304
322
 
305
- let meta = {...req.body, data: undefined, topic: feature.topic, date: new Date().getTime()} as FeatureMeta // TODO: Must also include invoiceTxn
323
+ let meta = {...req.body, data: undefined, topic: leaf, date: new Date().getTime()} as FeatureMeta // TODO: Must also include invoiceTxn
306
324
 
307
325
  if (process.env.USE_DEFAULT_COMPANY) {
308
326
  meta.company = 'DEFAULT_COMPANY'
@@ -457,7 +475,7 @@ export const start = async (app: ExpressApplication, url: URL, file: string) =>
457
475
  app.get('/features', async (_req: ExpressRequest, res: ExpressResponse) => {
458
476
  let exp_features: Record<string, RemoteFeatureEntry> = {}
459
477
  for (let [key, {api}] of Object.entries(features))
460
- exp_features[key] = {api, service: `${SERVICE_ADDRESS}`, subscribe: '', topic: ''}
478
+ exp_features[key] = {api, service: `${SERVICE_ADDRESS}`, subscribe: ''}
461
479
  if (process.env.LOAD_LOCAL_FEATURES) {
462
480
  for (let key in SLYP_FEATURES_LIST)
463
481
  SLYP_FEATURES_LIST[key]!.headers = {JWT: SERVICE_ACCESS_TOKEN, service: true, NDCURVE_DEVELOPER_LICENSE_ACCESS_TOKEN} // TODO: CRITICAL: Security issue
@@ -469,12 +487,13 @@ export const start = async (app: ExpressApplication, url: URL, file: string) =>
469
487
  await registerFeatures(features)
470
488
 
471
489
  // Get unique kafka topics list from features
472
- let kafkaTopics: string[] = []
490
+ let kafkaTopics = new Set<string>()
473
491
  for (const name in features) {
474
492
  let feature = features[name]!
475
493
  if (feature.api.split(' ')[0]?.toLowerCase() === "get" )
476
494
  continue
477
- kafkaTopics = [... new Set(kafkaTopics.concat([feature.topic]))]
495
+ const leaf = getLeaf(name)
496
+ kafkaTopics.add(leaf)
478
497
  }
479
498
 
480
499
  // Subscribe to each topic
@@ -587,7 +606,7 @@ async function subscribe() {
587
606
  if (subscribed_consumers[consumer] || !publisherFeature)
588
607
  continue
589
608
 
590
- let {topic} = publisherFeature
609
+ let topic = getLeaf(publisher)
591
610
 
592
611
  let kafka_consumer_promise = Kafka.receive<FeatureMessage>(`Features.${topic}`, consumer, async (topic: string, message: FeatureMessage) => {
593
612
  topic = topic.replace(/^.*Features./,'')
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "corebasic",
3
3
  "type": "module",
4
- "version": "1.0.265",
4
+ "version": "1.0.267",
5
5
  "description": "",
6
6
  "main": "dist/index.js",
7
7
  "types": "./index.ts",