corebasic 1.0.211 → 1.0.213

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.
Files changed (167) hide show
  1. package/dist/index.js +10 -0
  2. package/dist/libs/ObjectId.js +114 -0
  3. package/dist/libs/auth.js +103 -0
  4. package/dist/libs/compression.js +11 -0
  5. package/dist/libs/cpp.js +154 -0
  6. package/dist/libs/dip/suffix/date.js +89 -0
  7. package/dist/libs/dip/suffix/index.js +227 -0
  8. package/dist/libs/dip/suffix/policy.js +113 -0
  9. package/dist/libs/dip/suffix/query.js +279 -0
  10. package/dist/libs/dip/suffix/suffix.js +99 -0
  11. package/dist/libs/dip/suffix/tests/date.test.js +187 -0
  12. package/dist/libs/dip/suffix/tests/index.test.js +441 -0
  13. package/dist/libs/dip/suffix/tests/policy.applySuffixPolicy.test.js +489 -0
  14. package/dist/libs/dip/suffix/tests/policy.test.js +329 -0
  15. package/dist/libs/dip/suffix/tests/suffix.test.js +316 -0
  16. package/dist/libs/dip.js +102 -0
  17. package/dist/libs/dipper.js +73 -0
  18. package/dist/libs/elabase.js +656 -0
  19. package/dist/libs/features.js +366 -0
  20. package/dist/libs/kafka.js +121 -0
  21. package/dist/libs/messaging.js +130 -0
  22. package/dist/libs/mobilecodes.js +562 -0
  23. package/dist/libs/session.js +96 -0
  24. package/dist/libs/utils.js +297 -0
  25. package/index.ts +23 -0
  26. package/libs/{auth.js → auth.ts} +3 -3
  27. package/libs/{compression.js → compression.ts} +1 -1
  28. package/libs/dip/suffix/date.ts +121 -0
  29. package/libs/dip/suffix/{index.js → index.ts} +7 -18
  30. package/libs/dip/suffix/{policy.js → policy.ts} +2 -2
  31. package/libs/dip/suffix/{suffix.js → suffix.ts} +2 -2
  32. package/libs/dip/suffix/tests/{date.test.js → date.test.ts} +1 -1
  33. package/libs/dip/suffix/tests/{index.test.js → index.test.ts} +1 -1
  34. package/libs/dip/suffix/tests/{policy.applySuffixPolicy.test.js → policy.applySuffixPolicy.test.ts} +1 -1
  35. package/libs/dip/suffix/tests/{policy.test.js → policy.test.ts} +1 -1
  36. package/libs/dip/suffix/tests/{suffix.test.js → suffix.test.ts} +1 -1
  37. package/libs/{dip.js → dip.ts} +1 -1
  38. package/libs/{elabase.js → elabase.ts} +4 -4
  39. package/libs/{features.js → features.ts} +5 -5
  40. package/libs/{messaging.js → messaging.ts} +1 -1
  41. package/libs/{session.js → session.ts} +2 -2
  42. package/libs/{utils.js → utils.ts} +80 -9
  43. package/package.json +3 -2
  44. package/tsc/@typescript/typescript-linux-x64/LICENSE +55 -0
  45. package/tsc/@typescript/typescript-linux-x64/NOTICE.txt +436 -0
  46. package/tsc/@typescript/typescript-linux-x64/README.md +3 -0
  47. package/tsc/@typescript/typescript-linux-x64/lib/lib.d.ts +20 -0
  48. package/tsc/@typescript/typescript-linux-x64/lib/lib.decorators.d.ts +382 -0
  49. package/tsc/@typescript/typescript-linux-x64/lib/lib.decorators.legacy.d.ts +20 -0
  50. package/tsc/@typescript/typescript-linux-x64/lib/lib.dom.asynciterable.d.ts +18 -0
  51. package/tsc/@typescript/typescript-linux-x64/lib/lib.dom.d.ts +45125 -0
  52. package/tsc/@typescript/typescript-linux-x64/lib/lib.dom.iterable.d.ts +18 -0
  53. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.collection.d.ts +159 -0
  54. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.core.d.ts +595 -0
  55. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.d.ts +26 -0
  56. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.generator.d.ts +75 -0
  57. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.iterable.d.ts +603 -0
  58. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.promise.d.ts +79 -0
  59. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.proxy.d.ts +126 -0
  60. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.reflect.d.ts +142 -0
  61. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.symbol.d.ts +44 -0
  62. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.symbol.wellknown.d.ts +324 -0
  63. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2016.array.include.d.ts +114 -0
  64. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2016.d.ts +19 -0
  65. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2016.full.d.ts +21 -0
  66. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2016.intl.d.ts +29 -0
  67. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.arraybuffer.d.ts +19 -0
  68. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.d.ts +24 -0
  69. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.date.d.ts +29 -0
  70. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.full.d.ts +21 -0
  71. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.intl.d.ts +42 -0
  72. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.object.d.ts +47 -0
  73. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.sharedmemory.d.ts +133 -0
  74. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.string.d.ts +47 -0
  75. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.typedarrays.d.ts +51 -0
  76. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.asyncgenerator.d.ts +75 -0
  77. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.asynciterable.d.ts +51 -0
  78. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.d.ts +22 -0
  79. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.full.d.ts +22 -0
  80. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.intl.d.ts +81 -0
  81. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.promise.d.ts +28 -0
  82. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.regexp.d.ts +35 -0
  83. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.array.d.ts +77 -0
  84. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.d.ts +22 -0
  85. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.full.d.ts +22 -0
  86. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.intl.d.ts +21 -0
  87. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.object.d.ts +31 -0
  88. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.string.d.ts +35 -0
  89. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.symbol.d.ts +22 -0
  90. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.bigint.d.ts +763 -0
  91. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.d.ts +25 -0
  92. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.date.d.ts +40 -0
  93. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.full.d.ts +22 -0
  94. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.intl.d.ts +472 -0
  95. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.number.d.ts +26 -0
  96. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.promise.d.ts +45 -0
  97. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.sharedmemory.d.ts +97 -0
  98. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.string.d.ts +42 -0
  99. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.symbol.wellknown.d.ts +39 -0
  100. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2021.d.ts +21 -0
  101. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2021.full.d.ts +22 -0
  102. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2021.intl.d.ts +164 -0
  103. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2021.promise.d.ts +46 -0
  104. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2021.string.d.ts +31 -0
  105. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2021.weakref.d.ts +76 -0
  106. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.array.d.ts +119 -0
  107. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.d.ts +23 -0
  108. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.error.d.ts +73 -0
  109. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.full.d.ts +22 -0
  110. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.intl.d.ts +143 -0
  111. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.object.d.ts +24 -0
  112. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.regexp.d.ts +37 -0
  113. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.string.d.ts +23 -0
  114. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2023.array.d.ts +922 -0
  115. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2023.collection.d.ts +19 -0
  116. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2023.d.ts +20 -0
  117. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2023.full.d.ts +22 -0
  118. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2023.intl.d.ts +62 -0
  119. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.arraybuffer.d.ts +63 -0
  120. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.collection.d.ts +27 -0
  121. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.d.ts +24 -0
  122. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.full.d.ts +22 -0
  123. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.object.d.ts +27 -0
  124. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.promise.d.ts +33 -0
  125. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.regexp.d.ts +23 -0
  126. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.sharedmemory.d.ts +66 -0
  127. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.string.d.ts +27 -0
  128. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.collection.d.ts +94 -0
  129. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.d.ts +23 -0
  130. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.float16.d.ts +443 -0
  131. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.full.d.ts +22 -0
  132. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.intl.d.ts +200 -0
  133. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.iterator.d.ts +146 -0
  134. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.promise.d.ts +32 -0
  135. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.regexp.d.ts +30 -0
  136. package/tsc/@typescript/typescript-linux-x64/lib/lib.es5.d.ts +4599 -0
  137. package/tsc/@typescript/typescript-linux-x64/lib/lib.es6.d.ts +21 -0
  138. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.array.d.ts +33 -0
  139. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.collection.d.ts +47 -0
  140. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.d.ts +27 -0
  141. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.date.d.ts +21 -0
  142. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.decorators.d.ts +26 -0
  143. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.disposable.d.ts +191 -0
  144. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.error.d.ts +22 -0
  145. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.full.d.ts +22 -0
  146. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.intl.d.ts +107 -0
  147. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.sharedmemory.d.ts +23 -0
  148. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.temporal.d.ts +485 -0
  149. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.typedarrays.d.ts +90 -0
  150. package/tsc/@typescript/typescript-linux-x64/lib/lib.scripthost.d.ts +320 -0
  151. package/tsc/@typescript/typescript-linux-x64/lib/lib.webworker.asynciterable.d.ts +18 -0
  152. package/tsc/@typescript/typescript-linux-x64/lib/lib.webworker.d.ts +15606 -0
  153. package/tsc/@typescript/typescript-linux-x64/lib/lib.webworker.importscripts.d.ts +21 -0
  154. package/tsc/@typescript/typescript-linux-x64/lib/lib.webworker.iterable.d.ts +18 -0
  155. package/tsc/@typescript/typescript-linux-x64/lib/tsc +0 -0
  156. package/tsc/@typescript/typescript-linux-x64/lib/tsc.sig +11 -0
  157. package/tsc/@typescript/typescript-linux-x64/package.json +45 -0
  158. package/tsc/notes +14 -0
  159. package/tsconfig.json +48 -0
  160. package/index.js +0 -23
  161. package/libs/dip/suffix/date.js +0 -103
  162. /package/libs/{ObjectId.js → ObjectId.ts} +0 -0
  163. /package/libs/{cpp.js → cpp.ts} +0 -0
  164. /package/libs/dip/suffix/{query.js → query.ts} +0 -0
  165. /package/libs/{dipper.js → dipper.ts} +0 -0
  166. /package/libs/{kafka.js → kafka.ts} +0 -0
  167. /package/libs/{mobilecodes.js → mobilecodes.ts} +0 -0
@@ -0,0 +1,366 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import * as Dip from './dip.js';
10
+ import * as Kafka from './kafka.js';
11
+ import * as Utils from './utils.js';
12
+ import * as Session from './session.js';
13
+ import * as Messaging from './messaging.js';
14
+ import axios from 'axios';
15
+ import jwt from 'jsonwebtoken';
16
+ let features = {};
17
+ let apis = {};
18
+ const getFeatureMethod = api => api.split(' ')[0].toLowerCase();
19
+ const getFeatureUrl = api => api.split(' ')[1];
20
+ const getFeature = name => features[name];
21
+ const DEPLOY_TOKEN_SECRET = process.env.DEPLOY_TOKEN_SECRET || "MY_SECRET_DEPLOY_TOKEN";
22
+ const SERVICE_ACCESS_TOKEN = jwt.sign({ app: process.env.APP_DEPLOYMENT_NAME }, DEPLOY_TOKEN_SECRET, { expiresIn: '365d' });
23
+ const NDCURVE_DEVELOPER_LICENSE_ACCESS_TOKEN = await (async (_) => { if (process.env.NDCURVE_DEVELOPER_SERVICE)
24
+ try {
25
+ return (await Utils.fileToJson('file://', '/.ndcurve/developer.license.json')).accessToken?.trim();
26
+ }
27
+ catch { } })();
28
+ async function loadLocalFeatures() {
29
+ let data = {};
30
+ if (process.env.LOAD_LOCAL_FEATURES) {
31
+ try {
32
+ let url = process.env.LOAD_LOCAL_FEATURES_URL ? `${process.env.LOAD_LOCAL_FEATURES_URL}/features` : 'https://slyp.app/slyp-dev/api/v1/features';
33
+ let result = (await axios.get(url, { data: {}, headers: { jwt: SERVICE_ACCESS_TOKEN, service: true, NDCURVE_DEVELOPER_LICENSE_ACCESS_TOKEN }, timeout: 3000 })).data;
34
+ await Utils.stringToFile('/slyp.local.features.json', JSON.stringify(result.data, null, '\t'));
35
+ }
36
+ catch {
37
+ console.log('Error Fetching Remote Features');
38
+ }
39
+ try {
40
+ data = JSON.parse(await Utils.fileToString('/slyp.local.features.json'));
41
+ }
42
+ catch {
43
+ console.log('Error Loading Remote Features');
44
+ }
45
+ }
46
+ return data;
47
+ }
48
+ let SLYP_FEATURES_LIST = await loadLocalFeatures();
49
+ let appId = Utils.uid();
50
+ let SERVICE_ADDRESS = process.env.APP_ENDPOINT || 'http://127.0.0.1:3000';
51
+ export const get = feature => {
52
+ const throwError = () => { throw new Error(`Feature ${feature} not found in internal or external list during Features.subscribe call`); };
53
+ let { api, service = SERVICE_ADDRESS, topic } = getFeature(feature) ?? SLYP_FEATURES_LIST[feature] ?? throwError();
54
+ return { api, service, topic };
55
+ };
56
+ export const send = async (meta, feature, data, params) => {
57
+ const throwError = () => { throw new Error(`Feature ${feature} not found in internal or external list during inter feature call`); };
58
+ let { api, service = SERVICE_ADDRESS } = getFeature(feature) ?? SLYP_FEATURES_LIST[feature] ?? throwError();
59
+ let method = getFeatureMethod(api);
60
+ let url = getFeatureUrl(api);
61
+ if (params || url.includes(':')) {
62
+ for (let key in params)
63
+ url = url.replace(`:${key}`, params[key]);
64
+ if (url.includes(':'))
65
+ throw new Error(`Error: Internal feature call send on feature: ${feature} when api/params/substitution`);
66
+ }
67
+ let payload = { ...meta, data, feature, txn: Utils.uid() };
68
+ service = service.replace('http://slyp.app', 'https://slyp.app');
69
+ // return (await axios[method](`${service}${url}`, { data: payload, headers: {jwt: headers.jwt}, timeout: 1000 })).data
70
+ // Used to work. But request to 127.0.0.1 fails to send the specified headers along with the request.
71
+ // return (await axios[method](`${service}${url}`, payload, {headers: {jwt: SERVICE_ACCESS_TOKEN, service: true}, timeout: 1000 })).data // Worked Earlier, but issue spotted
72
+ if (getFeature(feature)) { // Local call
73
+ let response;
74
+ let req = { meta, body: payload, params, method };
75
+ req = JSON.parse(JSON.stringify(req));
76
+ let res = { json: payload => response = payload, end: _ => true };
77
+ await apiHandler(req, res);
78
+ return response;
79
+ }
80
+ // Workaround: https://stackoverflow.com/questions/72343387/axios-not-sending-headers-request-failing-getting-401-error
81
+ return (await axios({
82
+ method,
83
+ url: `${service}${url}`,
84
+ headers: { jwt: SERVICE_ACCESS_TOKEN, service: true, NDCURVE_DEVELOPER_LICENSE_ACCESS_TOKEN },
85
+ data: payload,
86
+ timeout: 30000 // 30 secs
87
+ })).data;
88
+ };
89
+ let appids = {};
90
+ async function announce() {
91
+ let exp_features = {};
92
+ for (let [key, { api, subscribe }] of Object.entries(features))
93
+ exp_features[key] = { api, service: SERVICE_ADDRESS, subscribe };
94
+ await Messaging.subscribe(`${process.env.REDIS_CHANNEL_PREFIX}_SLYP_FEATURES_LIST`, async (message, channel) => {
95
+ let msg = JSON.parse(message);
96
+ if (msg.uid !== appId && !appids[msg.uid]) {
97
+ appids[msg.uid] = true;
98
+ SLYP_FEATURES_LIST = { ...SLYP_FEATURES_LIST, ...msg };
99
+ delete SLYP_FEATURES_LIST.uid;
100
+ await Messaging.produce(`${process.env.REDIS_CHANNEL_PREFIX}_SLYP_FEATURES_LIST`, JSON.stringify({ ...exp_features, uid: appId }));
101
+ await subscribe();
102
+ }
103
+ });
104
+ await Messaging.produce(`${process.env.REDIS_CHANNEL_PREFIX}_SLYP_FEATURES_LIST`, JSON.stringify({ ...exp_features, uid: appId }));
105
+ }
106
+ function getFeaturelessFeature(req) {
107
+ if (Session.ALLOWED_URLS.includes(req.path)) {
108
+ for (let key in features) {
109
+ if (features[key].featureless && features[key].api === req.method.toUpperCase() + ' ' + req.path) {
110
+ return getFeature(key);
111
+ }
112
+ }
113
+ }
114
+ }
115
+ const apiHandler = async (req, res) => {
116
+ let method = req.method.toLowerCase();
117
+ let featureless;
118
+ try {
119
+ let feature = getFeature(req.body?.feature);
120
+ featureless = feature ? undefined : (feature = getFeaturelessFeature(req));
121
+ if (!req.body?.feature && !featureless) {
122
+ console.warn(`Feature: feature not sent by client`);
123
+ throw { status: 404, message: "Resource not found. Feature not sent by client." };
124
+ }
125
+ if (!feature && !featureless) {
126
+ console.warn(`Feature: ${req.body.feature} not available`);
127
+ throw { status: 404, message: `Resource not found. Feature ${req.body.feature} not available.` };
128
+ }
129
+ let topic = feature.topic;
130
+ let params = getFeatureUrl(feature.api).split("/").filter(item => item.startsWith(":")).map(item => item.replace(":", ""));
131
+ for (let param of params)
132
+ if (!req.params[param])
133
+ throw { status: 404, message: "Resource not found. One or more url parameter not specified." };
134
+ let meta = { ...req.body, data: undefined };
135
+ req.meta = meta;
136
+ if (process.env.USE_DEFAULT_COMPANY) {
137
+ req.meta.company = 'DEFAULT_COMPANY';
138
+ req.meta.outlet = 'DEFAULT_OUTLET';
139
+ }
140
+ if (method === "get") {
141
+ try {
142
+ req.body = { ...req.body, topic };
143
+ await feature.handler(req, res);
144
+ }
145
+ catch (err) {
146
+ if (process.env.DEBUG_MODE)
147
+ console.log('Error: Feature: ', req.body?.feature ?? (featureless ? `Featureless Api:${featureless.api}` : undefined), err);
148
+ throw { status: 500, message: "Failed to GET feature", ...err };
149
+ }
150
+ }
151
+ else if (method !== "get" && feature.bypass) {
152
+ try {
153
+ await feature.handler(topic, prepareMessage(req), req, res);
154
+ }
155
+ catch (err) {
156
+ if (process.env.DEBUG_MODE)
157
+ console.log('Error: Feature: ', req.body?.feature ?? (featureless ? `Featureless Api:${featureless.api}` : undefined), err);
158
+ throw { status: 500, message: "Failed to POST feature", ...err };
159
+ }
160
+ }
161
+ else
162
+ await commandAction(req, res, topic);
163
+ }
164
+ catch (err) {
165
+ if (process.env.DEBUG_MODE)
166
+ console.log('Error: Feature: ', req.body?.feature ?? (featureless ? `Featureless Api:${featureless.api}` : undefined), err);
167
+ try { // Sometimes error occurs when disconnecting stream from front end
168
+ res.status(err.status ?? 500).json(err);
169
+ }
170
+ catch (_) { }
171
+ }
172
+ };
173
+ let ExpressApp;
174
+ let PROJECT_ROOT_URL;
175
+ export async function registerFeatures(newFeatures) {
176
+ // Registering handlers
177
+ await registerHandler(newFeatures);
178
+ features = { ...newFeatures, ...features };
179
+ // Registering apis
180
+ registerApi();
181
+ }
182
+ async function registerHandler(features) {
183
+ for (let name in features) {
184
+ let feature = features[name];
185
+ apis[feature.api] = apis[feature.api] ?? {};
186
+ apis[feature.api][name] = feature;
187
+ const featureName = name;
188
+ name = name.split('.');
189
+ let handler = name.pop();
190
+ name = `src/${name.join('/')}`;
191
+ if (name === 'src/transactions/query')
192
+ continue;
193
+ if (featureName.startsWith("flows.") && !featureName.startsWith("flows.query.") && !featureName.startsWith("flows.command.") && !featureName.startsWith("flows.designs."))
194
+ feature.handler = (await import(__rewriteRelativeImportExtension(`${new URL(`src/flows/query.js`, PROJECT_ROOT_URL).toString().replace('file://', '')}`))).FEATURE_HANDLERS[handler];
195
+ else
196
+ feature.handler = (await import(__rewriteRelativeImportExtension(`${new URL(`${name}.js`, PROJECT_ROOT_URL).toString().replace('file://', '')}`)))[handler];
197
+ }
198
+ }
199
+ function registerApi() {
200
+ for (let api in apis) {
201
+ let method = getFeatureMethod(api);
202
+ let url = api.split(' ')[1];
203
+ if (api === 'GET /transactions/:id')
204
+ continue;
205
+ ExpressApp[method](url, apiHandler);
206
+ }
207
+ }
208
+ export const start = async (app, url, file) => {
209
+ const globalMeta = Dip.globalMeta();
210
+ Dip.excludeCollectionConfig("users.txns");
211
+ Dip.excludeCollectionConfig("Features.txns");
212
+ ExpressApp = app;
213
+ PROJECT_ROOT_URL = url;
214
+ features = await Utils.fileToJson(url, file);
215
+ await announce();
216
+ app.get('/features', async (req, res) => {
217
+ let exp_features = {};
218
+ for (let [key, { api }] of Object.entries(features))
219
+ exp_features[key] = { api, service: `${SERVICE_ADDRESS}` };
220
+ if (process.env.LOAD_LOCAL_FEATURES) {
221
+ for (let key in SLYP_FEATURES_LIST)
222
+ SLYP_FEATURES_LIST[key].headers = { JWT: SERVICE_ACCESS_TOKEN, service: true, NDCURVE_DEVELOPER_LICENSE_ACCESS_TOKEN };
223
+ }
224
+ res.json({ data: { ...SLYP_FEATURES_LIST, ...exp_features } });
225
+ });
226
+ // Registering features
227
+ await registerFeatures(features);
228
+ // Get unique kafka topics list from features
229
+ let kafkaTopics = [];
230
+ for (let name in features) {
231
+ let feature = features[name];
232
+ if (feature.api.split(' ')[0].toLowerCase() === "get")
233
+ continue;
234
+ kafkaTopics = [...new Set(kafkaTopics.concat([feature.topic]))];
235
+ }
236
+ // Subscribe to each topic
237
+ for (let topic of kafkaTopics) {
238
+ Kafka.receive(`Features.${topic}`, async (topic, message) => {
239
+ if (Utils.isEmpty(message.meta?.company))
240
+ message.meta = { ...message.meta, company: "GLOBAL", outlet: "GLOBAL" };
241
+ if (!message?.feature)
242
+ return;
243
+ const timer = ms => new Promise(res => setTimeout(res, ms)); // A promise that resolves after "ms" Milliseconds
244
+ topic = topic.replace(/^.*Features./, '');
245
+ while (true) {
246
+ try {
247
+ // const iso_date = new Date(message.date).toISOString()
248
+ // // TODO: use $useChunks: [] once support is added in dip insert
249
+ // await Dip.insert(globalMeta, `users.txns`, { _id: `${message.user}_${iso_date}_${message.txn}`, user: message.user, feature: message.feature, date: message.date, created: message.date, updated: message.date, status: "Queued" }, {idempotent: true}) // Can always update the status later
250
+ // TODO: Avoid duplicate processing
251
+ await features[message.feature].handler(topic, message);
252
+ await Dip.insert(globalMeta, "Features.txns", { _id: message.txn, status: "Processed" }, { idempotent: true });
253
+ break;
254
+ }
255
+ catch (err) {
256
+ if (process.env.DEBUG_MODE)
257
+ console.log('Error: Feature: ', message.feature, err);
258
+ console.warn(`Feature: ${message.feature}, error in executing handler during Kafka.receive(topic: ${topic})`);
259
+ }
260
+ await timer(10000);
261
+ }
262
+ });
263
+ }
264
+ await subscribe();
265
+ // Transaction status api
266
+ app.get('/transactions/:id', async (req, res) => {
267
+ try {
268
+ let items = await Dip.query(globalMeta, "Features.txns", { _id: req.params.id });
269
+ if (items.length)
270
+ res.json({ data: { ...items[0], txn: items._id } });
271
+ else
272
+ throw false;
273
+ }
274
+ catch {
275
+ res.status(500).json({ message: "Failed to retreive data" });
276
+ }
277
+ });
278
+ // app.get('/users/:id/transactions', async (req, res) => {
279
+ // try {
280
+ // const idPrefix = `${req.params.id}_`
281
+ // // TODO: use $useChunks: [] once support is added in dip insert
282
+ // // TODO: remove $orderby: { date: -1 } and remove $orderby: { _id: -1 }
283
+ // // res.json({ data: await Dip.query(globalMeta, `users.txns`, {}, { $rangeFrom: idPrefix, $rangeTo: idPrefix, $rangeDirection: -1, $rangeInclusive: true, $orderby: { date: -1 } }) })
284
+ // res.json({ data: await Dip.query(globalMeta, `users.txns`, {}, { $rangeFrom: idPrefix, $rangeTo: idPrefix, $rangeDirection: -1, $rangeInclusive: true, $orderby: { _id: -1 } }) })
285
+ // } catch {
286
+ // res.status(500).json({ message: "Failed to retreive data" })
287
+ // }
288
+ // })
289
+ try {
290
+ await Messaging.start(app);
291
+ }
292
+ catch {
293
+ console.log('Messaging failed to start. Maybe missing redis');
294
+ }
295
+ };
296
+ function prepareMessage(req) {
297
+ let txn = req.body.txn ?? Utils.uid();
298
+ let _id = req.body.data?._id ?? txn;
299
+ let { data, feature, app, user, outlet, company, client, version } = req.body;
300
+ let meta = req.meta;
301
+ let params = req.params;
302
+ return { data, params, meta, feature, app, user, outlet, company, client, version, txn, id: _id, date: new Date().getTime() };
303
+ }
304
+ const commandAction = async (req, res, topic) => {
305
+ let message = prepareMessage(req);
306
+ try {
307
+ await Kafka.send(`Features.${topic}`, message, message.user, { compression: Kafka.CompressionTypes.GZIP });
308
+ }
309
+ catch {
310
+ throw { status: 500, message: "Failed to queue the transaction" };
311
+ }
312
+ res.json({ data: { txn: message.txn, success: true, status: "Queued", featureQueued: true } });
313
+ };
314
+ let subscriptions = {
315
+ // "coins.query.hello": "invoices.command.add", // Consumer : Feature of Topic
316
+ };
317
+ let subscribed_consumers = {};
318
+ async function subscribe() {
319
+ let Features = { get, send };
320
+ for (let [key, { subscribe }] of Object.entries(features))
321
+ if (!Utils.isEmpty(subscribe) && subscriptions[key] !== subscribe && subscribed_consumers[key]) {
322
+ try {
323
+ await subscribed_consumers[key].disconnect();
324
+ }
325
+ catch (_) { }
326
+ delete subscribed_consumers[key];
327
+ }
328
+ for (let key in SLYP_FEATURES_LIST)
329
+ if (!Utils.isEmpty(SLYP_FEATURES_LIST[key].subscribe) && subscriptions[key] !== SLYP_FEATURES_LIST[key].subscribe && subscribed_consumers[key]) {
330
+ try {
331
+ await subscribed_consumers[key].disconnect();
332
+ }
333
+ catch (_) { }
334
+ delete subscribed_consumers[key];
335
+ }
336
+ let exp_features = {};
337
+ for (let key in SLYP_FEATURES_LIST)
338
+ if (!Utils.isEmpty(SLYP_FEATURES_LIST[key].subscribe)) {
339
+ subscriptions[key] = SLYP_FEATURES_LIST[key].subscribe;
340
+ }
341
+ for (let [key, { subscribe }] of Object.entries(features))
342
+ if (!Utils.isEmpty(subscribe)) {
343
+ subscriptions[key] = subscribe;
344
+ }
345
+ for (let consumer in subscriptions) {
346
+ let publisher = subscriptions[consumer];
347
+ let { topic } = getFeature(publisher);
348
+ if (subscribed_consumers[consumer] || !getFeature(publisher))
349
+ continue;
350
+ let kafka_consumer = Kafka.receive(`Features.${topic}`, consumer, async (topic, message) => {
351
+ topic = topic.replace(/^.*Features./, '');
352
+ const timer = ms => new Promise(res => setTimeout(res, ms)); // A promise that resolves after "ms" Milliseconds
353
+ while (true) {
354
+ try {
355
+ await Features.send(message.meta, consumer, message.data, message.params);
356
+ break;
357
+ }
358
+ catch {
359
+ console.warn(`Feature: ${consumer}, error in executing handler during Features.subscribe(topic: ${topic})`);
360
+ }
361
+ await timer(10000);
362
+ }
363
+ });
364
+ subscribed_consumers[consumer] = kafka_consumer;
365
+ }
366
+ }
@@ -0,0 +1,121 @@
1
+ import { Kafka, logLevel as KafkaLogLevel, CompressionTypes as KafkaCompressionTypes } from 'kafkajs';
2
+ export const logLevel = KafkaLogLevel;
3
+ export const CompressionTypes = KafkaCompressionTypes;
4
+ let kafka, producer, admin;
5
+ let appName;
6
+ let topicPrefix = '';
7
+ export const start = (arg) => {
8
+ arg = !arg && !process.env.APP_DEPLOYMENT_NAME ? { clientId: (global.app?.name ?? 'app') + '-dev', brokers: ['127.0.0.1:9092'], sasl: false, logLevel: logLevel.ERROR } : arg;
9
+ appName = arg?.clientId ?? (process.env.APP_DEPLOYMENT_NAME ?? (global.app?.name ?? 'app'));
10
+ topicPrefix = `${appName}.`;
11
+ kafka = new Kafka({
12
+ logLevel: arg?.logLevel ?? logLevel.INFO,
13
+ clientId: appName,
14
+ brokers: arg?.brokers ?? ['redpanda-0.redpanda.redpanda.svc.cluster.local:9093'], // ['107.155.108.78:9092'] ['127.0.0.1:29092']
15
+ sasl: arg?.sasl == false ? undefined : {
16
+ mechanism: 'SCRAM-SHA-512',
17
+ username: process.env.KAFKA_USERNAME,
18
+ password: process.env.KAFKA_PASSWORD
19
+ },
20
+ });
21
+ producer = kafka.producer({ allowAutoTopicCreation: true });
22
+ admin = kafka.admin();
23
+ };
24
+ export const createTopic = async (topic, partition, replicas) => {
25
+ topic = topicPrefix + topic;
26
+ return await admin.createTopics({ topics: [{ topic, numPartitions: partition ?? 1, replicationFactor: replicas ?? 1 }] });
27
+ };
28
+ // ===========
29
+ // Consumer
30
+ // ===========
31
+ let consumers = [];
32
+ const start_consumer = async function (topic, groupId, callback) {
33
+ callback = typeof groupId === "string" ? callback : groupId;
34
+ groupId = typeof groupId === "string" ? `${appName}.${groupId}` : `${appName}.${topic}`;
35
+ const consumer = kafka.consumer({ groupId: groupId });
36
+ consumers.push(consumer);
37
+ await consumer.connect();
38
+ await consumer.subscribe({ topic: topic, fromBeginning: true });
39
+ await consumer.run({
40
+ autoCommit: false,
41
+ eachMessage: async ({ topic, partition, message }) => {
42
+ // callback(topic, message.value.toString(), partition) // toString() returns array so won't parse if json.
43
+ let success;
44
+ try {
45
+ success = await callback(topic, JSON.parse(message.value), partition);
46
+ }
47
+ catch (ex) {
48
+ success = await callback(topic, message.value, partition);
49
+ }
50
+ await consumer.commitOffsets([{ topic, partition, offset: (Number(message.offset) + 1).toString() }]);
51
+ },
52
+ });
53
+ return consumer;
54
+ };
55
+ // ===========
56
+ // Producer
57
+ // ===========
58
+ let producerInvoked = false;
59
+ const start_producer = async function (topic, message, key, options) {
60
+ let isJson = Object.prototype.toString.call(message) === '[object Object]' || Object.prototype.toString.call(message) === '[object Array]';
61
+ if (!producerInvoked) {
62
+ await producer.connect();
63
+ producerInvoked = true;
64
+ }
65
+ let value = isJson ? JSON.stringify(message) : message;
66
+ await producer.send({
67
+ topic: topic,
68
+ ...(options ?? {}),
69
+ messages: [
70
+ key ? { key, value } : { value },
71
+ ],
72
+ });
73
+ // .then(console.log)
74
+ // .catch(e => console.error("[example/producer] " + e.message, e))
75
+ // await producer.disconnect()
76
+ };
77
+ // start_consumer('quickstart-events')
78
+ // start_producer('quickstart-events', 'Hello KafkaJS user! Little')
79
+ export const receive = async function (topic, groupId, callback) {
80
+ topic = topicPrefix + topic;
81
+ return (await start_consumer(topic, groupId, callback));
82
+ };
83
+ export const send = async function (topic, message, key, options) {
84
+ topic = topicPrefix + topic;
85
+ await start_producer(topic, message, key, options);
86
+ };
87
+ // Usage
88
+ // -------
89
+ // send('quickstart-events', { name: 'Muneer', age: 30 })
90
+ // receive('quickstart-events', function (topic, message) {
91
+ // console.log(message)
92
+ // })
93
+ // const errorTypes = ['unhandledRejection', 'uncaughtException']
94
+ // const signalTraps = ['SIGTERM', 'SIGINT', 'SIGUSR2']
95
+ //
96
+ // errorTypes.forEach(type => {
97
+ // process.on(type, async () => {
98
+ // try {
99
+ // console.log(`process.on ${type}`)
100
+ // if (producer)
101
+ // await producer.disconnect()
102
+ // for (let i = 0; i < consumers.length; i++)
103
+ // await consumers[i].disconnect()
104
+ // process.exit(0)
105
+ // } catch (_) {
106
+ // process.exit(1)
107
+ // }
108
+ // })
109
+ // })
110
+ // signalTraps.forEach(type => {
111
+ // process.once(type, async () => {
112
+ // try {
113
+ // if (producer)
114
+ // await producer.disconnect()
115
+ // for (let i = 0; i < consumers.length; i++)
116
+ // await consumers[i].disconnect()
117
+ // } finally {
118
+ // process.kill(process.pid, type)
119
+ // }
120
+ // })
121
+ // })
@@ -0,0 +1,130 @@
1
+ import axios from 'axios';
2
+ import { createClient } from 'redis';
3
+ import * as Utils from './utils.js';
4
+ const url = process.env.REDIS_URL || "redis://localhost:6380";
5
+ // url: 'redis://alice:foobared@localhost:6380'
6
+ let consumer, publisher;
7
+ let users_pool = {};
8
+ async function disconnect(user, uid) {
9
+ if (!users_pool[user])
10
+ return;
11
+ let [{ res }] = users_pool[user].reqres.filter(item => item.uid === uid).concat([{}]);
12
+ res.end();
13
+ if (users_pool[user].listeners[uid]) {
14
+ if (users_pool[user].listeners.count == 1)
15
+ await consumer.unsubscribe(user, users_pool[user].listeners[uid]);
16
+ users_pool[user].listeners.count--;
17
+ }
18
+ users_pool[user].reqres = users_pool[user].reqres.filter(item => item.uid !== uid);
19
+ delete users_pool[user].listeners[uid];
20
+ if (!users_pool[user].listeners.count)
21
+ delete users_pool[user];
22
+ // await consumer.unsubscribe(user);
23
+ }
24
+ async function connect({ user, req, res, uid }) {
25
+ res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' });
26
+ const listener = (message, channel) => {
27
+ if (users_pool[user]) {
28
+ try {
29
+ message = JSON.parse(message);
30
+ }
31
+ catch { }
32
+ for (let { req, res } of users_pool[user].reqres) {
33
+ res.write(JSON.stringify({ message, channel }) + "\n");
34
+ if (res.flush) // If compression enabled
35
+ res.flush();
36
+ }
37
+ }
38
+ };
39
+ users_pool[user] = users_pool[user] ?? { reqres: [], listeners: { count: 0 } };
40
+ users_pool[user].reqres.push({ req, res, uid });
41
+ users_pool[user].listeners[uid] = listener;
42
+ if (!users_pool[user].listeners.count)
43
+ await consumer.subscribe(user, listener);
44
+ users_pool[user].listeners.count++;
45
+ }
46
+ export async function start(app) {
47
+ consumer = createClient({ url });
48
+ await consumer.connect();
49
+ publisher = createClient({ url });
50
+ await publisher.connect();
51
+ consumer.on('error', err => console.log('Redis Client Error', err));
52
+ app.get('/messages/:user', async (req, res) => {
53
+ let uid = req.body.client;
54
+ await connect({ user: req.params.user, req, res, uid });
55
+ req.on("close", async () => await disconnect(req.params.user, uid)); // request closed unexpectedly
56
+ req.on("end", async () => await disconnect(req.params.user, uid)); // request ended normally
57
+ });
58
+ app.get('/messages/disconnects/:user', async (req, res) => {
59
+ let uid = req.body.client;
60
+ if (users_pool[req.params.user])
61
+ await disconnect(req.params.user, uid);
62
+ res.json({});
63
+ });
64
+ }
65
+ export async function publish(channel, message) {
66
+ if (publisher && !Utils.isEmpty(channel)) {
67
+ try {
68
+ await publisher.publish(channel, typeof message === "object" ? JSON.stringify(message) : message);
69
+ }
70
+ catch {
71
+ console.log('Error: Publishing on redis channel', channel);
72
+ }
73
+ }
74
+ }
75
+ // Generic Functions
76
+ // -----------------
77
+ export async function newConsumer() {
78
+ let consumer = createClient({ url });
79
+ await consumer.connect();
80
+ return consumer;
81
+ }
82
+ export async function newProducer() {
83
+ let publisher = createClient({ url });
84
+ await publisher.connect();
85
+ return publisher;
86
+ }
87
+ let defaultConsumer = await newConsumer();
88
+ let defaultProducer = await newProducer();
89
+ export async function subscribe(channel, listener) {
90
+ await defaultConsumer.subscribe(channel, listener);
91
+ }
92
+ export async function produce(channel, message) {
93
+ await defaultProducer.publish(channel, message);
94
+ }
95
+ let defaultSetGetConsumer = await newConsumer();
96
+ export async function set(key, value) {
97
+ await defaultSetGetConsumer.set(`${process.env.REDIS_CHANNEL_PREFIX}_${key}`, typeof value === 'object' ? JSON.stringify(value) : value);
98
+ }
99
+ export async function get(key) {
100
+ let value = await defaultSetGetConsumer.get(`${process.env.REDIS_CHANNEL_PREFIX}_${key}`);
101
+ try {
102
+ value = JSON.parse(value);
103
+ }
104
+ catch (err) { }
105
+ return value;
106
+ }
107
+ export async function del(key) {
108
+ await defaultSetGetConsumer.del(`${process.env.REDIS_CHANNEL_PREFIX}_${key}`);
109
+ }
110
+ export async function hset(key, subkey, value) {
111
+ await defaultSetGetConsumer.HSET(`${process.env.REDIS_CHANNEL_PREFIX}_${key}`, subkey, typeof value === 'object' ? JSON.stringify(value) : value);
112
+ }
113
+ export async function hget(key, subkey) {
114
+ let value = await defaultSetGetConsumer.HGET(`${process.env.REDIS_CHANNEL_PREFIX}_${key}`, subkey);
115
+ try {
116
+ value = JSON.parse(value);
117
+ }
118
+ catch (err) { }
119
+ return value;
120
+ }
121
+ export async function hdel(key, subkey) {
122
+ await defaultSetGetConsumer.HDEL(`${process.env.REDIS_CHANNEL_PREFIX}_${key}`, subkey);
123
+ }
124
+ // Hydrate
125
+ export async function hydrate(callback) {
126
+ setTimeout(async (_) => {
127
+ let { user, company, items } = await callback();
128
+ await publish(user, { event: "RPC_hydrate", data: { company, items }, txn: Utils.uid() });
129
+ }, 100);
130
+ }