@coherentglobal/spark-execute-sdk 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/.babelrc +12 -0
  2. package/.eslintrc.json +21 -0
  3. package/.github/workflows/build-publish.yml +46 -0
  4. package/.prettierrc +0 -0
  5. package/README.md +92 -0
  6. package/dist/browser.js +6925 -0
  7. package/examples/UsingBearerTokenFNAsync/bearerTokenExample.js +22 -0
  8. package/examples/UsingBearerTokenFNAsync/config.js +88 -0
  9. package/examples/UsingBearerTokenFNAsync/index.html +205 -0
  10. package/examples/UsingBearerTokenFNAsync/modelCInput.json +15 -0
  11. package/examples/UsingBearerTokenFNAsync/models/Model_C.zip +0 -0
  12. package/examples/UsingBearerTokenString/bearerTokenExample.js +22 -0
  13. package/examples/UsingBearerTokenString/config.js +182 -0
  14. package/examples/UsingBearerTokenString/index.html +191 -0
  15. package/examples/UsingBearerTokenString/modelCInput.json +15 -0
  16. package/examples/UsingBearerTokenString/models/Model_C.zip +0 -0
  17. package/examples/UsingSyntheticKeyFNAsync/bearerTokenExample.js +22 -0
  18. package/examples/UsingSyntheticKeyFNAsync/config.js +195 -0
  19. package/examples/UsingSyntheticKeyFNAsync/index.html +205 -0
  20. package/examples/UsingSyntheticKeyFNAsync/modelCInput.json +15 -0
  21. package/examples/UsingSyntheticKeyFNAsync/models/Model_C.zip +0 -0
  22. package/examples/UsingSyntheticKeyString/bearerTokenExample.js +22 -0
  23. package/examples/UsingSyntheticKeyString/config.js +181 -0
  24. package/examples/UsingSyntheticKeyString/index.html +192 -0
  25. package/examples/UsingSyntheticKeyString/modelCInput.json +15 -0
  26. package/examples/UsingSyntheticKeyString/models/Model_C.zip +0 -0
  27. package/examples/asyncFunctionModel/config.js +96 -0
  28. package/examples/asyncFunctionModel/modelCInput.json +15 -0
  29. package/examples/asyncFunctionModel/models/Model_C.zip +0 -0
  30. package/examples/asyncFunctionModel/node.js +125 -0
  31. package/examples/asyncFunctionModel/tool.js +17 -0
  32. package/examples/base64Model/config.js +96 -0
  33. package/examples/base64Model/modelCInput.json +15 -0
  34. package/examples/base64Model/models/Model_C.zip +0 -0
  35. package/examples/base64Model/node.js +125 -0
  36. package/examples/base64Model/tool.js +17 -0
  37. package/examples/base64modelBrowser/config.js +96 -0
  38. package/examples/base64modelBrowser/index.html +194 -0
  39. package/examples/base64modelBrowser/modelCInput.json +15 -0
  40. package/examples/base64modelBrowser/models/Model_C.zip +0 -0
  41. package/examples/base64modelBrowser/models/base64model.txt +1 -0
  42. package/examples/base64modelBrowser/node.js +126 -0
  43. package/examples/base64modelBrowser/tool.js +17 -0
  44. package/examples/binary/config.js +96 -0
  45. package/examples/binary/modelCInput.json +15 -0
  46. package/examples/binary/models/Model_C.zip +0 -0
  47. package/examples/binary/models/binary.txt +1 -0
  48. package/examples/binary/node.js +131 -0
  49. package/examples/binary/tool.js +18 -0
  50. package/examples/functionModel/config.js +96 -0
  51. package/examples/functionModel/modelCInput.json +15 -0
  52. package/examples/functionModel/models/Model_C.zip +0 -0
  53. package/examples/functionModel/node.js +138 -0
  54. package/examples/functionModel/tool.js +17 -0
  55. package/examples/nodejs/node.js +250 -0
  56. package/examples/nodejs/test_models/Archive.zip +0 -0
  57. package/examples/nodejs/test_models/BlackScholes.zip +0 -0
  58. package/examples/nodejs/test_models/Model_A.zip +0 -0
  59. package/examples/nodejs/test_models/Par7.zip +0 -0
  60. package/package.json +79 -0
  61. package/src/browser.js +198 -0
  62. package/src/error.js +87 -0
  63. package/src/helpers/utils.js +79 -0
  64. package/src/logger.js +3 -0
  65. package/src/models.js +26 -0
  66. package/src/node.js +254 -0
  67. package/src/resolver/externalResolver.js +118 -0
  68. package/src/services/entityStore.js +260 -0
  69. package/src/services/resolver.js +134 -0
  70. package/src/services/spark.js +80 -0
  71. package/src/tenant_resolver/externalResolver_coherent.js +118 -0
  72. package/src/tenant_resolver/externalResolver_test.js +118 -0
  73. package/src/validate.js +38 -0
  74. package/test/config.test.js +124 -0
  75. package/test/mock-data/dummy-config.json +102 -0
  76. package/test/mock-data/valid.json +21 -0
  77. package/test/spark-sdk.test.js +28 -0
  78. package/tsconfig.json +105 -0
  79. package/types/browser.d.ts +72 -0
  80. package/types/browser.d.ts.map +1 -0
  81. package/types/error.d.ts +42 -0
  82. package/types/error.d.ts.map +1 -0
  83. package/types/helpers/utils.d.ts +11 -0
  84. package/types/helpers/utils.d.ts.map +1 -0
  85. package/types/logger.d.ts +3 -0
  86. package/types/logger.d.ts.map +1 -0
  87. package/types/models.d.ts +8 -0
  88. package/types/models.d.ts.map +1 -0
  89. package/types/node.d.ts +78 -0
  90. package/types/node.d.ts.map +1 -0
  91. package/types/resolver/externalResolver.d.ts +2 -0
  92. package/types/resolver/externalResolver.d.ts.map +1 -0
  93. package/types/services/entityStore.d.ts +51 -0
  94. package/types/services/entityStore.d.ts.map +1 -0
  95. package/types/services/resolver.d.ts +20 -0
  96. package/types/services/resolver.d.ts.map +1 -0
  97. package/types/services/spark.d.ts +6 -0
  98. package/types/services/spark.d.ts.map +1 -0
  99. package/types/tenant_resolver/externalResolver_coherent.d.ts +2 -0
  100. package/types/tenant_resolver/externalResolver_coherent.d.ts.map +1 -0
  101. package/types/tenant_resolver/externalResolver_test.d.ts +2 -0
  102. package/types/tenant_resolver/externalResolver_test.d.ts.map +1 -0
  103. package/types/validate.d.ts +4 -0
  104. package/types/validate.d.ts.map +1 -0
package/src/node.js ADDED
@@ -0,0 +1,254 @@
1
+ const utils = require("./helpers/utils.js");
2
+ const WasmRunnerErrors = require("./error.js");
3
+ const { WasmRunner } = require("@coherentglobal/wasm-runner");
4
+ const logger = require("./logger");
5
+ const validate = require("./validate.js");
6
+ const processModels = require("./models.js");
7
+ const got = require("got");
8
+
9
+ // const resolverDir = path.join(__dirname, "/tenant_resolver");
10
+ let registry = [];
11
+ let INVOCATION_CACHE = [];
12
+ class Spark {
13
+ /**
14
+ * @param {object} config
15
+ */
16
+ constructor(config) {
17
+ /**
18
+ * @private
19
+ */
20
+ this.config = this.validateConfig(config);
21
+ const {
22
+ sparkEndpoint: { syntheticKey, bearerToken, authType, tenant, url },
23
+ nodeGenModels,
24
+ } = this.config;
25
+
26
+ /**
27
+ * @private
28
+ */
29
+ this.tenant = tenant;
30
+ /**
31
+ * @private
32
+ */
33
+ this.authType = authType;
34
+ /**
35
+ * @private
36
+ */
37
+ this.token = syntheticKey || bearerToken;
38
+ /**
39
+ * @private
40
+ */
41
+ this.url = url;
42
+ /**
43
+ * @private
44
+ */
45
+ this.isCompatible = utils.isWasmSupported();
46
+ /**
47
+ * @private
48
+ */
49
+ this.model = this._models(nodeGenModels);
50
+
51
+ /**
52
+ * @private
53
+ */
54
+ this.fallbackEnabled = false;
55
+
56
+ // (async () => {
57
+ // if (!(await utils.isPathExist(resolverDir))) {
58
+ // await fs.promises.mkdir(resolverDir, { mode: 0o750 });
59
+ // }
60
+ // })();
61
+ }
62
+
63
+ /**
64
+ *
65
+ * @param {object} nodegen
66
+ * @returns {object}
67
+ */
68
+ _models(nodegen) {
69
+ const models = nodegen.map(processModels);
70
+ return models;
71
+ }
72
+
73
+ /**
74
+ *
75
+ * @param {object} config
76
+ * @returns {object}
77
+ */
78
+ validateConfig(config) {
79
+ const { value, error } = validate(config);
80
+ if (!error) {
81
+ return value;
82
+ } else {
83
+ const message = JSON.stringify(error.details);
84
+ logger.error({
85
+ EventType: "ValidationError",
86
+ TextMessage: message,
87
+ });
88
+ throw new Error(`ValidationError: ${message}`);
89
+ }
90
+ }
91
+
92
+ /**
93
+ *
94
+ * @param {string} id
95
+ * @returns {boolean}
96
+ */
97
+ _getModel(id) {
98
+ const model = this.model.find((m) => m.versionId === id);
99
+ if (!model) throw new WasmRunnerErrors.MissingModelError(id);
100
+
101
+ return model;
102
+ }
103
+
104
+ /**
105
+ *
106
+ * @param {string} versionId
107
+ */
108
+ async load(versionId) {
109
+ const { versionId: versionUuid, binary: modelPath } =
110
+ this._getModel(versionId);
111
+
112
+ logger.info({
113
+ EventType: "ModelInfo",
114
+ TextMessage: `Append model tenant: ${this.tenant} uuid: ${versionUuid}`,
115
+ });
116
+
117
+ // if (!registry[this.tenant]) {
118
+ if (!utils.isEmpty(registry)) {
119
+ // const resolverPath = path.join(
120
+ // resolverDir,
121
+ // `externalResolver_${this.tenant}.js`
122
+ // );
123
+
124
+ // const template = await fs.promises.readFile(
125
+ // require.resolve("./resolver/externalResolver"),
126
+ // {
127
+ // encoding: "utf8",
128
+ // flag: "r",
129
+ // }
130
+ // );
131
+
132
+ // await fs.promises.writeFile(
133
+ // resolverPath,
134
+ // template.replace("%%tenant_to_replace%%", this.tenant)
135
+ // );
136
+
137
+ registry = new WasmRunner();
138
+ }
139
+
140
+ console.log("APPENDING");
141
+ await registry.append({
142
+ id: versionUuid,
143
+ url: modelPath,
144
+ // size,
145
+ });
146
+
147
+ INVOCATION_CACHE = [
148
+ ...INVOCATION_CACHE,
149
+ { id: versionUuid },
150
+ // { id: versionUuid, tenant: this.tenant },
151
+ ];
152
+ }
153
+
154
+ /**
155
+ * Check for exiting Model
156
+ *
157
+ * @param {string} model
158
+ * @returns {boolean}
159
+ */
160
+ isExist = (model) => {
161
+ return registry.isExist(model);
162
+ };
163
+
164
+ /**
165
+ * Execute model
166
+ *
167
+ * @param {object} input
168
+ * @param {string} version_id
169
+ * @returns {object}
170
+ */
171
+ async execute(input, version_id) {
172
+ if (!input.request_meta.version_id && !input.request_meta.version_uuid) {
173
+ input.request_meta.version_id = version_id;
174
+ }
175
+ const versionID =
176
+ input.request_meta.version_id || input.request_meta.version_uuid;
177
+
178
+ const model = this._getModel(versionID);
179
+
180
+ await this.load(model.versionId);
181
+
182
+ logger.info({
183
+ EventType: "ExecuteModel",
184
+ TextMessage: `Execute uuid: ${model.versionId}`,
185
+ });
186
+
187
+ if (this.isExist(model.versionId)) {
188
+ let modelUrl = "";
189
+
190
+ if (
191
+ !this.isCompatible &&
192
+ !utils.isEmpty(this.url) &&
193
+ this.fallbackEnabled
194
+ ) {
195
+ let token = "";
196
+ if (this.token.constructor.name === "AsyncFunction") {
197
+ token = await this.token();
198
+ } else {
199
+ token = this.token;
200
+ }
201
+ console.log("TOKEN", token);
202
+
203
+ if (utils.isEmpty(this.token)) {
204
+ throw new WasmRunnerErrors.UnauthorizedError();
205
+ }
206
+
207
+ const options = {
208
+ headers: utils.getAuthHeaders(token, this.authType, this.tenant),
209
+ json: {
210
+ request_data: {},
211
+ request_meta: input.request_meta,
212
+ },
213
+ };
214
+
215
+ console.log("OPTIONS", options);
216
+ modelUrl = new URL(
217
+ `/${this.tenant}/api/v3/version/${input.request_meta.version_id}`,
218
+ this.url
219
+ );
220
+
221
+ try {
222
+ const response = await got.post(modelUrl, options).json();
223
+
224
+ return response;
225
+ } catch (err) {
226
+ throw new WasmRunnerErrors.UnauthorizedError();
227
+ }
228
+ } else if (this.isCompatible) {
229
+ const modelIndex = INVOCATION_CACHE.findIndex(
230
+ (item) => item.id === model.versionId
231
+ );
232
+
233
+ INVOCATION_CACHE[modelIndex].lastUsed = Date.now();
234
+
235
+ const result = await registry.execute(input, model.versionId, true);
236
+
237
+ return result;
238
+ } else {
239
+ throw new WasmRunnerErrors.NotSupportedError(
240
+ "WebAssembly is not supported"
241
+ );
242
+ }
243
+ } else {
244
+ throw new WasmRunnerErrors.BadRequestError("Missing request input.");
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Remove Model
250
+ */
251
+ // async remove(versionId) {}
252
+ }
253
+
254
+ module.exports = Spark;
@@ -0,0 +1,118 @@
1
+ const { StatusCodes } = require("http-status-codes");
2
+ const { logger } = require("@coherentglobal/node-sdk");
3
+ // const config = require("../config"); env vars
4
+ const {
5
+ handleDirectRequest,
6
+ modelServiceValidation,
7
+ getLatestVersionFromServiceMapTable,
8
+ } = require("../logic/runnerLogic");
9
+ const { getModelViaFolder } = require("../services/entityStore");
10
+ const tenant = "%%tenant_to_replace%%";
11
+
12
+ const CALL_TYPE = {
13
+ 0: "SparkService",
14
+ 1: "ExternalApi",
15
+ };
16
+
17
+ const ERROR_CODES = {
18
+ A1: {
19
+ code: "a1",
20
+ message: "ERROR:[Main item] missing in Xcall [NAME] table.",
21
+ },
22
+ };
23
+
24
+ const XcallResBuilder = {
25
+ Json: function (callType, name, status, errorCode, responseTime, data) {
26
+ return JSON.stringify({
27
+ metadata: {
28
+ calltype: callType,
29
+ name: name,
30
+ status: status,
31
+ error_code: errorCode,
32
+ response_time: responseTime,
33
+ },
34
+ data: data || {},
35
+ });
36
+ },
37
+ XML: function (callType, name, status, errorCode, responseTime, data) {
38
+ const trimmedData = data.replace(/\<\?xml.+\?\>/gm, "");
39
+
40
+ const response = `
41
+ <data calltype="${callType}" name="${name}" status="${status}" error_code="${errorCode}" response_time = "${responseTime}">
42
+ ${trimmedData}
43
+ </data>
44
+ `;
45
+
46
+ return response;
47
+ },
48
+ };
49
+
50
+ module.exports = {
51
+ sparkService: async (requestData, context) => {
52
+ const modelLocation = config().modelLocation;
53
+ const headers = context.headers;
54
+ const folderName = requestData.folder_name;
55
+ const serviceName = requestData.service_name;
56
+
57
+ logger.info({
58
+ eventType: "SparkService",
59
+ msg: `WASMSERVER:DISPATCH_TYPE.SPARK_SERVICE ${tenant}`,
60
+ });
61
+ logger.info({ eventType: "RequestData", msg: requestData });
62
+ const requestBodyFromEngine = JSON.parse(requestData.request_body);
63
+ const requestMetaFromEngine = requestBodyFromEngine.request_meta;
64
+ const findAvailableLatestModelFromLocal =
65
+ getLatestVersionFromServiceMapTable(
66
+ context.servicemap,
67
+ headers.tenant,
68
+ decodeURI(folderName),
69
+ decodeURI(serviceName)
70
+ );
71
+ requestMetaFromEngine.version_id = findAvailableLatestModelFromLocal;
72
+ const serviceMap = modelServiceValidation(
73
+ context.servicemap,
74
+ headers.tenant,
75
+ requestMetaFromEngine
76
+ );
77
+ // const modelVersion = modelLocation
78
+ // ? // ? await resolveOffline(requestMetaFromEngine, headers.tenant, headers, serviceMap)
79
+ // findAvailableLatestModelFromLocal
80
+ // : await getModelViaFolder(folderName, serviceName, headers);
81
+
82
+ const modelVersion = await getModelViaFolder(
83
+ folderName,
84
+ serviceName,
85
+ headers
86
+ );
87
+ const params = {
88
+ tenant: headers.tenant,
89
+ };
90
+ const body = {
91
+ ...requestBodyFromEngine,
92
+ request_meta: {
93
+ ...requestBodyFromEngine.request_meta,
94
+ version_id: modelVersion,
95
+ call_purpose: "Spark - API Tester",
96
+ source_system: "SPARK",
97
+ correlation_id: "",
98
+ requested_output: null,
99
+ service_category: "",
100
+ },
101
+ };
102
+ const payload = {
103
+ body,
104
+ headers,
105
+ params,
106
+ };
107
+ const results = await handleDirectRequest(payload);
108
+ const response = XcallResBuilder.Json(
109
+ CALL_TYPE[0],
110
+ serviceName,
111
+ StatusCodes.ACCEPTED,
112
+ "",
113
+ 0,
114
+ results
115
+ );
116
+ return response;
117
+ },
118
+ };
@@ -0,0 +1,260 @@
1
+ const tmp = require("tmp");
2
+ const cuid = require("cuid");
3
+ const fs = require("fs");
4
+ const got = require("got");
5
+ const path = require("path");
6
+ const { logger } = require("@coherentglobal/node-sdk");
7
+ const { EntityStoreError } = require("../error");
8
+ const config = require("../config");
9
+
10
+ const request = got.extend({
11
+ throwHttpErrors: false, // allows us to throw our own error based off got response
12
+ handlers: [
13
+ (options, next) =>
14
+ (async () => {
15
+ const response = await next(options);
16
+ // return an http error of error response but with local stacktrace and not from got api response
17
+ if (response && response.statusCode >= 400 && response.body) {
18
+ let extendError;
19
+ try {
20
+ // eslint-disable-next-line prefer-destructuring
21
+ extendError = JSON.parse(response.body).errors[0];
22
+ } catch (err) {
23
+ // eslint-disable-next-line prefer-destructuring
24
+ extendError = response.body.errors[0];
25
+ }
26
+
27
+ if (response.statusCode === 404) {
28
+ extendError = "MODEL_NOT_FOUND";
29
+ }
30
+
31
+ logger.info({
32
+ EventType: "EntityStoreError",
33
+ TextMessage: `EntityStoreError: ${JSON.stringify(response.body)}`,
34
+ });
35
+ throw new EntityStoreError(extendError, response.statusCode);
36
+ }
37
+ return response;
38
+ })(),
39
+ ],
40
+ });
41
+
42
+ /**
43
+ * Fetch Temporary file.
44
+ *
45
+ * @param {String} url
46
+ * Temporary blob download url.
47
+ *
48
+ * @param {String} token
49
+ * Keycloak Token.
50
+ *
51
+ * @returns {Buffer}
52
+ */
53
+ const getFromTempUrl = async (url, headers) => {
54
+ let options = {};
55
+
56
+ if (headers) {
57
+ options = {
58
+ headers,
59
+ };
60
+ }
61
+ const output = await request.get(url, options);
62
+ return output.rawBody;
63
+ };
64
+
65
+ /**
66
+ * Fetch documnet using Document Version Id.
67
+ *
68
+ * @param {String} versionUuid
69
+ * Document Version Id.
70
+ *
71
+ * @param {String} token
72
+ * Keycloak token.
73
+ *
74
+ * @returns
75
+ */
76
+ const getDocumentByVersionId = async (versionUuid, token) => {
77
+ const { entityStoreUrl } = config();
78
+ const url = new URL(
79
+ `/docstore/api/v1/documents/versions/${versionUuid}`,
80
+ entityStoreUrl
81
+ ).toString();
82
+ logger.info({
83
+ EventType: "GetVersionID",
84
+ TextMessage: `getDocumentByVersionId , ${url}`,
85
+ });
86
+ const options = {
87
+ headers: {
88
+ Authorization: token,
89
+ },
90
+ responseType: "json",
91
+ };
92
+
93
+ const output = await request.get(url, options);
94
+
95
+ return output.body;
96
+ };
97
+
98
+ const getParameterSetById = async (versionUuid, token, tenant = "coherent") => {
99
+ if (!parameterSetCache[`${tenant}::${versionUuid}`]) {
100
+ const { sparkUrl } = config();
101
+ const url = new URL(
102
+ `/${tenant}/api/v3/parameter/versions/${versionUuid}`,
103
+ sparkUrl
104
+ ).toString();
105
+ logger.info({
106
+ EventType: "ParameterSet",
107
+ TextMessage: `getParameterSetById , ${url}`,
108
+ });
109
+ const options = {
110
+ headers: {
111
+ Authorization: token,
112
+ },
113
+ responseType: "json",
114
+ };
115
+ const output = await request.get(url, options);
116
+ parameterSetCache[`${tenant}::${versionUuid}`] = output.body.response_data;
117
+ }
118
+
119
+ return parameterSetCache[`${tenant}::${versionUuid}`];
120
+ };
121
+
122
+ const TMP_DIR = tmp.dirSync().name;
123
+
124
+ /**
125
+ * Save Temporary file.
126
+ *
127
+ * @param {String} versionUuid
128
+ * Document version ID.
129
+ *
130
+ * @param {Buffer} content
131
+ * Temporary file content.
132
+ *
133
+ * @param {String} token
134
+ * Keycloak token.
135
+ *
136
+ * @returns
137
+ */
138
+ const downloadModelFile = async (url, versionUuid, headers) => {
139
+ const getWasmDocument = await getFromTempUrl(url, headers);
140
+
141
+ logger.info({
142
+ EventType: "DownloadModelFile",
143
+ TextMessage: `downloadModelFile url:${url}, versionUuid:${versionUuid}`,
144
+ });
145
+ const tmpWasm = tmp.fileSync({
146
+ dir: TMP_DIR,
147
+ name: `${versionUuid}-${Date.now()}.zip`,
148
+ });
149
+
150
+ const wasmDestination = fs.createWriteStream(tmpWasm.name.toString());
151
+ wasmDestination.write(getWasmDocument);
152
+ logger.info({
153
+ EventType: "DownloadComplete",
154
+ TextMessage: `downloadModelFile complete url:${url}, versionUuid:${versionUuid}`,
155
+ });
156
+ return tmpWasm.name;
157
+ };
158
+
159
+ const downloadJSON = async (url, versionUuid, headers) => {
160
+ try {
161
+ const getDocument = await getFromTempUrl(url, headers);
162
+
163
+ const filePath = path.join(TMP_DIR, `${versionUuid}.json`);
164
+ if (!fs.existsSync(filePath)) {
165
+ logger.info({
166
+ EventType: "DownloadJson",
167
+ TextMessage: `downloadJSON url:${url}, versionUuid:${versionUuid}`,
168
+ });
169
+ const tmpWasm = tmp.fileSync({
170
+ dir: TMP_DIR,
171
+ name: `${versionUuid}.json`,
172
+ });
173
+ const wasmDestination = fs.createWriteStream(tmpWasm.name.toString());
174
+ wasmDestination.write(getDocument);
175
+ logger.info({
176
+ EventType: "JsonDownloaded",
177
+ TextMessage: `downloadJSON complete url:${url}, versionUuid:${versionUuid}`,
178
+ });
179
+ }
180
+
181
+ const jsonString = await fs.promises.readFile(filePath, "utf8");
182
+
183
+ return JSON.parse(jsonString);
184
+ } catch (err) {
185
+ throw new Error("File is not a JSON document");
186
+ }
187
+ };
188
+
189
+ /* istanbul ignore next */
190
+ const downloadModel = async (versionUuid, token) => {
191
+ const { entityStoreUrl } = config();
192
+ const { url: documentURL } = await getDocumentByVersionId(versionUuid, token);
193
+ const downloadUrl = new URL(documentURL, entityStoreUrl).toString();
194
+ const modelFile = await downloadModelFile(downloadUrl, versionUuid);
195
+ logger.info({
196
+ EventType: "ModelDownloaded",
197
+ TextMessage: `downloadModel complete versionUuid:${versionUuid}`,
198
+ });
199
+ return modelFile;
200
+ };
201
+
202
+ /* istanbul ignore next */
203
+ const parameterSetCache = {};
204
+
205
+ /* istanbul ignore next */
206
+ const getParameterSet = async (versionUuid, tenant, token) => {
207
+ const { entityStoreUrl } = config();
208
+ const url = `https://excel.dev.coherent.global/coherent/api/v3/parameter/versions/${versionUuid}`;
209
+ if (!parameterSetCache[`${tenant}::${versionUuid}`]) {
210
+ const { url: documentURL } = await getDocumentByVersionId(
211
+ versionUuid,
212
+ token
213
+ );
214
+ const downloadUrl = new URL(documentURL, entityStoreUrl).toString();
215
+ const parameterSet = await downloadJSON(downloadUrl, versionUuid);
216
+ parameterSetCache[`${tenant}::${versionUuid}`] = parameterSet;
217
+ return parameterSet;
218
+ }
219
+
220
+ return parameterSetCache[`${tenant}::${versionUuid}`];
221
+ };
222
+
223
+ /**
224
+ *
225
+ * @param {*} folder
226
+ * @param {*} model
227
+ *
228
+ * https://excel.dev.coherent.global/api/filemanager/GetFolderDocs?folderPath=/products/FJ%20Test/productfactory/engines/DownstreamService_example
229
+ */
230
+ const getModelViaFolder = async (folder, model, headers) => {
231
+ const { sparkUrl } = config();
232
+ let options = {}
233
+ const folderPath = `/products/${folder}/productfactory/engines/${model}`
234
+ const folderUrl = `/api/filemanager/GetFolderDocs?folderPath=${folderPath}`
235
+ const folderSparkUrl = new URL(folderUrl, sparkUrl).toString();
236
+ if (headers) {
237
+ options = {
238
+ headers,
239
+ };
240
+ }
241
+ const output = await request.get(folderSparkUrl, options);
242
+ const body = output.body ? JSON.parse(output.body) : {}
243
+ let response = ""
244
+ if(body) {
245
+ const documents = body.data.documents
246
+ const findModelFromDocuments = documents.find( name => name.name === `${model}.c1engine`)
247
+ if(findModelFromDocuments) response = findModelFromDocuments.latestVersionId
248
+ }
249
+ return response
250
+ }
251
+
252
+ module.exports = {
253
+ getDocumentByVersionId,
254
+ getFromTempUrl,
255
+ downloadModelFile,
256
+ downloadModel,
257
+ getParameterSet,
258
+ getParameterSetById,
259
+ getModelViaFolder
260
+ };