@smythos/sre 1.5.1 → 1.5.4

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 (193) hide show
  1. package/LICENSE +18 -0
  2. package/dist/index.js +22329 -4
  3. package/dist/index.js.map +1 -1
  4. package/dist/types/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.d.ts +2 -2
  5. package/dist/types/subsystems/IO/VectorDB.service/embed/BaseEmbedding.d.ts +11 -7
  6. package/dist/types/types/VectorDB.types.d.ts +13 -11
  7. package/package.json +102 -127
  8. package/src/Components/APICall/APICall.class.ts +155 -0
  9. package/src/Components/APICall/AccessTokenManager.ts +130 -0
  10. package/src/Components/APICall/ArrayBufferResponse.helper.ts +58 -0
  11. package/src/Components/APICall/OAuth.helper.ts +294 -0
  12. package/src/Components/APICall/mimeTypeCategories.ts +46 -0
  13. package/src/Components/APICall/parseData.ts +167 -0
  14. package/src/Components/APICall/parseHeaders.ts +41 -0
  15. package/src/Components/APICall/parseProxy.ts +68 -0
  16. package/src/Components/APICall/parseUrl.ts +91 -0
  17. package/src/Components/APIEndpoint.class.ts +234 -0
  18. package/src/Components/APIOutput.class.ts +58 -0
  19. package/src/Components/AgentPlugin.class.ts +102 -0
  20. package/src/Components/Async.class.ts +155 -0
  21. package/src/Components/Await.class.ts +90 -0
  22. package/src/Components/Classifier.class.ts +158 -0
  23. package/src/Components/Component.class.ts +94 -0
  24. package/src/Components/ComponentHost.class.ts +38 -0
  25. package/src/Components/DataSourceCleaner.class.ts +92 -0
  26. package/src/Components/DataSourceIndexer.class.ts +181 -0
  27. package/src/Components/DataSourceLookup.class.ts +141 -0
  28. package/src/Components/FEncDec.class.ts +29 -0
  29. package/src/Components/FHash.class.ts +33 -0
  30. package/src/Components/FSign.class.ts +80 -0
  31. package/src/Components/FSleep.class.ts +25 -0
  32. package/src/Components/FTimestamp.class.ts +25 -0
  33. package/src/Components/FileStore.class.ts +75 -0
  34. package/src/Components/ForEach.class.ts +97 -0
  35. package/src/Components/GPTPlugin.class.ts +70 -0
  36. package/src/Components/GenAILLM.class.ts +395 -0
  37. package/src/Components/HuggingFace.class.ts +314 -0
  38. package/src/Components/Image/imageSettings.config.ts +70 -0
  39. package/src/Components/ImageGenerator.class.ts +407 -0
  40. package/src/Components/JSONFilter.class.ts +54 -0
  41. package/src/Components/LLMAssistant.class.ts +213 -0
  42. package/src/Components/LogicAND.class.ts +28 -0
  43. package/src/Components/LogicAtLeast.class.ts +85 -0
  44. package/src/Components/LogicAtMost.class.ts +86 -0
  45. package/src/Components/LogicOR.class.ts +29 -0
  46. package/src/Components/LogicXOR.class.ts +34 -0
  47. package/src/Components/MCPClient.class.ts +112 -0
  48. package/src/Components/PromptGenerator.class.ts +122 -0
  49. package/src/Components/ScrapflyWebScrape.class.ts +159 -0
  50. package/src/Components/TavilyWebSearch.class.ts +98 -0
  51. package/src/Components/index.ts +77 -0
  52. package/src/Core/AgentProcess.helper.ts +240 -0
  53. package/src/Core/Connector.class.ts +123 -0
  54. package/src/Core/ConnectorsService.ts +192 -0
  55. package/src/Core/DummyConnector.ts +49 -0
  56. package/src/Core/HookService.ts +105 -0
  57. package/src/Core/SmythRuntime.class.ts +292 -0
  58. package/src/Core/SystemEvents.ts +15 -0
  59. package/src/Core/boot.ts +55 -0
  60. package/src/config.ts +15 -0
  61. package/src/constants.ts +125 -0
  62. package/src/data/hugging-face.params.json +580 -0
  63. package/src/helpers/BinaryInput.helper.ts +324 -0
  64. package/src/helpers/Conversation.helper.ts +1094 -0
  65. package/src/helpers/JsonContent.helper.ts +97 -0
  66. package/src/helpers/LocalCache.helper.ts +97 -0
  67. package/src/helpers/Log.helper.ts +234 -0
  68. package/src/helpers/OpenApiParser.helper.ts +150 -0
  69. package/src/helpers/S3Cache.helper.ts +129 -0
  70. package/src/helpers/SmythURI.helper.ts +5 -0
  71. package/src/helpers/TemplateString.helper.ts +243 -0
  72. package/src/helpers/TypeChecker.helper.ts +329 -0
  73. package/src/index.ts +179 -0
  74. package/src/index.ts.bak +179 -0
  75. package/src/subsystems/AgentManager/Agent.class.ts +1108 -0
  76. package/src/subsystems/AgentManager/Agent.helper.ts +3 -0
  77. package/src/subsystems/AgentManager/AgentData.service/AgentDataConnector.ts +230 -0
  78. package/src/subsystems/AgentManager/AgentData.service/connectors/CLIAgentDataConnector.class.ts +66 -0
  79. package/src/subsystems/AgentManager/AgentData.service/connectors/LocalAgentDataConnector.class.ts +142 -0
  80. package/src/subsystems/AgentManager/AgentData.service/connectors/NullAgentData.class.ts +39 -0
  81. package/src/subsystems/AgentManager/AgentData.service/index.ts +18 -0
  82. package/src/subsystems/AgentManager/AgentLogger.class.ts +297 -0
  83. package/src/subsystems/AgentManager/AgentRequest.class.ts +51 -0
  84. package/src/subsystems/AgentManager/AgentRuntime.class.ts +559 -0
  85. package/src/subsystems/AgentManager/AgentSSE.class.ts +101 -0
  86. package/src/subsystems/AgentManager/AgentSettings.class.ts +52 -0
  87. package/src/subsystems/AgentManager/Component.service/ComponentConnector.ts +32 -0
  88. package/src/subsystems/AgentManager/Component.service/connectors/LocalComponentConnector.class.ts +59 -0
  89. package/src/subsystems/AgentManager/Component.service/index.ts +11 -0
  90. package/src/subsystems/AgentManager/EmbodimentSettings.class.ts +47 -0
  91. package/src/subsystems/AgentManager/ForkedAgent.class.ts +153 -0
  92. package/src/subsystems/AgentManager/OSResourceMonitor.ts +77 -0
  93. package/src/subsystems/ComputeManager/Code.service/CodeConnector.ts +99 -0
  94. package/src/subsystems/ComputeManager/Code.service/connectors/AWSLambdaCode.class.ts +63 -0
  95. package/src/subsystems/ComputeManager/Code.service/index.ts +11 -0
  96. package/src/subsystems/IO/CLI.service/CLIConnector.ts +47 -0
  97. package/src/subsystems/IO/CLI.service/index.ts +9 -0
  98. package/src/subsystems/IO/Log.service/LogConnector.ts +32 -0
  99. package/src/subsystems/IO/Log.service/connectors/ConsoleLog.class.ts +28 -0
  100. package/src/subsystems/IO/Log.service/index.ts +13 -0
  101. package/src/subsystems/IO/NKV.service/NKVConnector.ts +41 -0
  102. package/src/subsystems/IO/NKV.service/connectors/NKVRAM.class.ts +204 -0
  103. package/src/subsystems/IO/NKV.service/connectors/NKVRedis.class.ts +182 -0
  104. package/src/subsystems/IO/NKV.service/index.ts +12 -0
  105. package/src/subsystems/IO/Router.service/RouterConnector.ts +21 -0
  106. package/src/subsystems/IO/Router.service/connectors/ExpressRouter.class.ts +48 -0
  107. package/src/subsystems/IO/Router.service/connectors/NullRouter.class.ts +40 -0
  108. package/src/subsystems/IO/Router.service/index.ts +11 -0
  109. package/src/subsystems/IO/Storage.service/SmythFS.class.ts +472 -0
  110. package/src/subsystems/IO/Storage.service/StorageConnector.ts +66 -0
  111. package/src/subsystems/IO/Storage.service/connectors/LocalStorage.class.ts +305 -0
  112. package/src/subsystems/IO/Storage.service/connectors/S3Storage.class.ts +418 -0
  113. package/src/subsystems/IO/Storage.service/index.ts +13 -0
  114. package/src/subsystems/IO/VectorDB.service/VectorDBConnector.ts +108 -0
  115. package/src/subsystems/IO/VectorDB.service/connectors/MilvusVectorDB.class.ts +454 -0
  116. package/src/subsystems/IO/VectorDB.service/connectors/PineconeVectorDB.class.ts +384 -0
  117. package/src/subsystems/IO/VectorDB.service/connectors/RAMVecrtorDB.class.ts +421 -0
  118. package/src/subsystems/IO/VectorDB.service/embed/BaseEmbedding.ts +107 -0
  119. package/src/subsystems/IO/VectorDB.service/embed/OpenAIEmbedding.ts +109 -0
  120. package/src/subsystems/IO/VectorDB.service/embed/index.ts +21 -0
  121. package/src/subsystems/IO/VectorDB.service/index.ts +14 -0
  122. package/src/subsystems/LLMManager/LLM.helper.ts +221 -0
  123. package/src/subsystems/LLMManager/LLM.inference.ts +335 -0
  124. package/src/subsystems/LLMManager/LLM.service/LLMConnector.ts +375 -0
  125. package/src/subsystems/LLMManager/LLM.service/LLMCredentials.helper.ts +145 -0
  126. package/src/subsystems/LLMManager/LLM.service/connectors/Anthropic.class.ts +632 -0
  127. package/src/subsystems/LLMManager/LLM.service/connectors/Bedrock.class.ts +405 -0
  128. package/src/subsystems/LLMManager/LLM.service/connectors/Echo.class.ts +81 -0
  129. package/src/subsystems/LLMManager/LLM.service/connectors/GoogleAI.class.ts +689 -0
  130. package/src/subsystems/LLMManager/LLM.service/connectors/Groq.class.ts +257 -0
  131. package/src/subsystems/LLMManager/LLM.service/connectors/OpenAI.class.ts +848 -0
  132. package/src/subsystems/LLMManager/LLM.service/connectors/Perplexity.class.ts +255 -0
  133. package/src/subsystems/LLMManager/LLM.service/connectors/VertexAI.class.ts +193 -0
  134. package/src/subsystems/LLMManager/LLM.service/index.ts +43 -0
  135. package/src/subsystems/LLMManager/ModelsProvider.service/ModelsProviderConnector.ts +281 -0
  136. package/src/subsystems/LLMManager/ModelsProvider.service/connectors/SmythModelsProvider.class.ts +229 -0
  137. package/src/subsystems/LLMManager/ModelsProvider.service/index.ts +11 -0
  138. package/src/subsystems/LLMManager/custom-models.ts +854 -0
  139. package/src/subsystems/LLMManager/models.ts +2539 -0
  140. package/src/subsystems/LLMManager/paramMappings.ts +69 -0
  141. package/src/subsystems/MemoryManager/Cache.service/CacheConnector.ts +86 -0
  142. package/src/subsystems/MemoryManager/Cache.service/connectors/LocalStorageCache.class.ts +297 -0
  143. package/src/subsystems/MemoryManager/Cache.service/connectors/RAMCache.class.ts +201 -0
  144. package/src/subsystems/MemoryManager/Cache.service/connectors/RedisCache.class.ts +252 -0
  145. package/src/subsystems/MemoryManager/Cache.service/connectors/S3Cache.class.ts +373 -0
  146. package/src/subsystems/MemoryManager/Cache.service/index.ts +15 -0
  147. package/src/subsystems/MemoryManager/LLMCache.ts +72 -0
  148. package/src/subsystems/MemoryManager/LLMContext.ts +125 -0
  149. package/src/subsystems/MemoryManager/RuntimeContext.ts +249 -0
  150. package/src/subsystems/Security/AccessControl/ACL.class.ts +208 -0
  151. package/src/subsystems/Security/AccessControl/AccessCandidate.class.ts +76 -0
  152. package/src/subsystems/Security/AccessControl/AccessRequest.class.ts +52 -0
  153. package/src/subsystems/Security/Account.service/AccountConnector.ts +41 -0
  154. package/src/subsystems/Security/Account.service/connectors/AWSAccount.class.ts +76 -0
  155. package/src/subsystems/Security/Account.service/connectors/DummyAccount.class.ts +130 -0
  156. package/src/subsystems/Security/Account.service/connectors/JSONFileAccount.class.ts +159 -0
  157. package/src/subsystems/Security/Account.service/index.ts +14 -0
  158. package/src/subsystems/Security/Credentials.helper.ts +62 -0
  159. package/src/subsystems/Security/ManagedVault.service/ManagedVaultConnector.ts +34 -0
  160. package/src/subsystems/Security/ManagedVault.service/connectors/NullManagedVault.class.ts +57 -0
  161. package/src/subsystems/Security/ManagedVault.service/connectors/SecretManagerManagedVault.ts +154 -0
  162. package/src/subsystems/Security/ManagedVault.service/index.ts +12 -0
  163. package/src/subsystems/Security/SecureConnector.class.ts +110 -0
  164. package/src/subsystems/Security/Vault.service/Vault.helper.ts +30 -0
  165. package/src/subsystems/Security/Vault.service/VaultConnector.ts +26 -0
  166. package/src/subsystems/Security/Vault.service/connectors/HashicorpVault.class.ts +46 -0
  167. package/src/subsystems/Security/Vault.service/connectors/JSONFileVault.class.ts +166 -0
  168. package/src/subsystems/Security/Vault.service/connectors/NullVault.class.ts +54 -0
  169. package/src/subsystems/Security/Vault.service/connectors/SecretsManager.class.ts +140 -0
  170. package/src/subsystems/Security/Vault.service/index.ts +12 -0
  171. package/src/types/ACL.types.ts +104 -0
  172. package/src/types/AWS.types.ts +9 -0
  173. package/src/types/Agent.types.ts +61 -0
  174. package/src/types/AgentLogger.types.ts +17 -0
  175. package/src/types/Cache.types.ts +1 -0
  176. package/src/types/Common.types.ts +3 -0
  177. package/src/types/LLM.types.ts +419 -0
  178. package/src/types/Redis.types.ts +8 -0
  179. package/src/types/SRE.types.ts +64 -0
  180. package/src/types/Security.types.ts +18 -0
  181. package/src/types/Storage.types.ts +5 -0
  182. package/src/types/VectorDB.types.ts +86 -0
  183. package/src/utils/base64.utils.ts +275 -0
  184. package/src/utils/cli.utils.ts +68 -0
  185. package/src/utils/data.utils.ts +263 -0
  186. package/src/utils/date-time.utils.ts +22 -0
  187. package/src/utils/general.utils.ts +238 -0
  188. package/src/utils/index.ts +12 -0
  189. package/src/utils/numbers.utils.ts +13 -0
  190. package/src/utils/oauth.utils.ts +35 -0
  191. package/src/utils/string.utils.ts +414 -0
  192. package/src/utils/url.utils.ts +19 -0
  193. package/src/utils/validation.utils.ts +74 -0
@@ -0,0 +1,275 @@
1
+ import { fileTypeFromBuffer } from 'file-type';
2
+ import { isValidString } from './string.utils';
3
+ import { MAX_FILE_SIZE } from '@sre/constants';
4
+
5
+ /**
6
+ * This function converts a text string to a base64 URL.
7
+ * @param text
8
+ * @returns
9
+ */
10
+ export function textToBase64Url(text) {
11
+ // Create a Buffer from the string
12
+ const buffer = Buffer.from(text, 'utf-8');
13
+
14
+ // Convert the Buffer to a base64 string
15
+ const base64String = buffer.toString('base64');
16
+
17
+ // Construct the data URL
18
+ const base64Url = `data:text/plain;base64,${base64String}`;
19
+
20
+ return base64Url;
21
+ }
22
+
23
+ export const isBase64FileUrl = (url: string): boolean => {
24
+ if (typeof url !== 'string') return false;
25
+
26
+ const regex = /^data:([\w+\-\.]+\/[\w+\-\.]+);base64,(.*)$/;
27
+ const match = url.match(regex);
28
+ if (!match) return false;
29
+ const [, , base64Data] = match;
30
+
31
+ return isBase64(base64Data);
32
+ };
33
+
34
+ export const getMimetypeFromBase64Data = async (data: string) => {
35
+ try {
36
+ data = _cleanUpBase64Data(data);
37
+
38
+ // Convert the base64 string back to a Buffer
39
+ const imageBuffer = Buffer.from(data, 'base64');
40
+
41
+ const type = await fileTypeFromBuffer(imageBuffer);
42
+ return type?.mime || '';
43
+ } catch (error) {
44
+ console.error('Error getting mimetype from base64 data: ', error);
45
+ return '';
46
+ }
47
+ };
48
+
49
+ export async function getBase64FileInfo(data: string): Promise<{ data: string; mimetype: string; size: number } | null> {
50
+ if (isBase64FileUrl(data)) {
51
+ const regex = /^data:([^;]+);base64,(.*)$/;
52
+ const match = data.match(regex);
53
+ if (!match) return { data: '', mimetype: '', size: 0 };
54
+ const [, mimetype, base64Data] = match;
55
+
56
+ const cleanData = _cleanUpBase64Data(base64Data);
57
+ const buffer = Buffer.from(cleanData, 'base64');
58
+
59
+ return { data: cleanData, mimetype, size: buffer.byteLength };
60
+ } else if (isBase64(data)) {
61
+ const cleanData = _cleanUpBase64Data(data);
62
+ const buffer = Buffer.from(cleanData, 'base64');
63
+
64
+ return {
65
+ data: cleanData,
66
+ mimetype: await getMimetypeFromBase64Data(cleanData),
67
+ size: buffer.byteLength,
68
+ };
69
+ }
70
+
71
+ return null;
72
+ }
73
+
74
+ //=== Legacy code below ===
75
+ //@Forhad the functions below need to be reviewed and refactored
76
+
77
+ /**
78
+ * Remove all whitespace characters and literal \n and \s sequences
79
+ *
80
+ * @note It's common practice to split base64 data into multiple lines for better readability and to avoid issues with systems that can't handle very long lines. So we need to clean up newline characters from the base64 data before processing it.
81
+ * @param {string} str - The input string.
82
+ * @returns {string} The input string with all newline characters and escaped newline strings removed.
83
+ */
84
+ function cleanBase64(str: string): string {
85
+ return str.replace(/\s|\\n|\\s/g, '');
86
+ }
87
+
88
+ /**
89
+ * Checks if the input is a data URL.
90
+ *
91
+ * @param {string} input - The input string.
92
+ * @returns {boolean} True if the input is a data URL, false otherwise.
93
+ */
94
+ export function isBase64DataUrl(input: string): boolean {
95
+ // Data URL pattern: data:[<mediatype>][;base64],<data>
96
+ const pattern = /^data:([\w+\-\.]+\/[\w+\-\.]+);base64,(.*)$/;
97
+
98
+ return pattern.test(input);
99
+ }
100
+
101
+ /**
102
+ * Checks if the given string is a valid Base64-encoded string.
103
+ *
104
+ * @param {string} str - The string to check.
105
+ * @returns {boolean} True if the string is a valid Base64-encoded string, false otherwise.
106
+ */
107
+ export function isBase64(str: string): boolean {
108
+ if (!isValidString(str)) return false;
109
+
110
+ const cleanedBase64Data = cleanBase64(str);
111
+
112
+ // Sometimes words like 'male' and hashes like md5, sha1, sha256, sha512 are detected as base64
113
+ if (cleanedBase64Data.length < 128) return false;
114
+
115
+ try {
116
+ const buffer = Buffer.from(cleanedBase64Data, 'base64');
117
+
118
+ // ignoring trailing padding ensures that the comparison is based on the actual content, not the padding
119
+ return buffer.toString('base64').replace(/=+$/, '') === cleanedBase64Data.replace(/=+$/, '');
120
+ } catch {
121
+ return false;
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Parses a Base64-encoded data URL and extracts the MIME type and cleaned data.
127
+ *
128
+ * @param {string} input - The Base64-encoded data URL.
129
+ * @returns {{ mimetype: string; data: string }} An object containing the MIME type and the cleaned Base64 data.
130
+ * @throws {Error} If the input is invalid.
131
+ */
132
+ function parseBase64DataUrl(input: string): { mimetype: string; data: string } {
133
+ const pattern = /^data:([\w+\-\.]+\/[\w+\-\.]+);base64,(.*)$/;
134
+ const matches = input.match(pattern);
135
+
136
+ if (!matches) {
137
+ throw new Error('Invalid data URL!');
138
+ }
139
+
140
+ const [, mimetype, data] = matches;
141
+
142
+ if (!isBase64(data)) {
143
+ throw new Error('Invalid base64 data!');
144
+ }
145
+
146
+ return { mimetype, data: cleanBase64(data) };
147
+ }
148
+
149
+ /**
150
+ * Parses a Base64-encoded string and extracts the MIME type and cleaned data.
151
+ *
152
+ * @param {string} input - The Base64-encoded string.
153
+ * @returns {Promise<{ mimetype: string; data: string }>} An object containing the MIME type and the cleaned Base64 data.
154
+ */
155
+ export async function parseBase64(input: string): Promise<{ mimetype: string; data: string }> {
156
+ const cleanedData = cleanBase64(input);
157
+ const mimetype = await identifyMimetypeFromBase64(cleanedData);
158
+
159
+ return { mimetype, data: cleanedData };
160
+ }
161
+
162
+ /**
163
+ * Identifies the MIME type from a Base64-encoded string.
164
+ *
165
+ * This function cleans the input Base64 string, converts it to a buffer, and then identifies the MIME type
166
+ * using the `fileTypeFromBuffer` function.
167
+ *
168
+ * @param {string} data - The Base64-encoded string from which to identify the MIME type.
169
+ * @returns {Promise<string>} A promise that resolves to the MIME type of the data, or an empty string if the MIME type cannot be determined.
170
+ *
171
+ * @throws {Error} If an error occurs during the process, it logs the error and returns an empty string.
172
+ */
173
+ export async function identifyMimetypeFromBase64(data: string): Promise<string> {
174
+ try {
175
+ const cleanedData = cleanBase64(data);
176
+
177
+ // Convert the base64 string back to a Buffer
178
+ const buffer = Buffer.from(cleanedData, 'base64');
179
+
180
+ const type = await fileTypeFromBuffer(buffer);
181
+
182
+ return type?.mime || '';
183
+ } catch (error) {
184
+ throw new Error(`Error identifying MIME type from base64 data: ${error?.message}`);
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Identifies the MIME type from a Base64-encoded string.
190
+ *
191
+ * This function cleans the input Base64 string, converts it to a buffer, and then identifies the MIME type
192
+ * using the `fileTypeFromBuffer` function.
193
+ *
194
+ * @param {string} data - The Base64-encoded string from which to identify the MIME type.
195
+ * @returns {Promise<string>} A promise that resolves to the MIME type of the data, or an empty string if the MIME type cannot be determined.
196
+ *
197
+ * @throws {Error} If an error occurs during the process, it logs the error and returns an empty string.
198
+ */
199
+ export async function identifyMimeTypeFromBase64DataUrl(input: string): Promise<string> {
200
+ try {
201
+ const { data } = await parseBase64DataUrl(input);
202
+
203
+ const buffer = Buffer.from(data, 'base64');
204
+
205
+ const type = await fileTypeFromBuffer(buffer);
206
+
207
+ return type?.mime || '';
208
+ } catch (error) {
209
+ throw new Error(`Error identifying MIME type from base64 data: ${error?.message}`);
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Calculates the size of a Base64-encoded string in bytes.
215
+ *
216
+ * This function validates the input string to ensure it is a valid Base64-encoded string,
217
+ * converts it to a buffer, and then returns the byte length of the buffer.
218
+ *
219
+ * @param {string} str - The Base64-encoded string whose size is to be calculated.
220
+ * @returns {number} The size of the Base64-encoded string in bytes.
221
+ *
222
+ * @throws {Error} If the input string is not a valid Base64-encoded string or if an error occurs during conversion.
223
+ */
224
+ export function getSizeOfBase64(str: string): number {
225
+ if (!isValidString(str)) {
226
+ throw new Error('Invalid Base64 data!');
227
+ }
228
+
229
+ try {
230
+ const buffer = Buffer.from(str, 'base64');
231
+ return buffer.byteLength;
232
+ } catch (error) {
233
+ throw new Error(`Invalid Base64 data! ${error.message}`);
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Generates a Base64 Data URL from a Base64-encoded string.
239
+ *
240
+ * This function validates the input Base64 string, removes any newline characters,
241
+ * and constructs a Data URL with the specified MIME type.
242
+ *
243
+ * @param {string} data - The Base64-encoded string to be converted into a Data URL.
244
+ * @param {string} [mimetype='application/octet-stream'] - The MIME type of the data. Defaults to 'application/octet-stream'.
245
+ * @returns {string} The generated Base64 Data URL.
246
+ *
247
+ * @throws {Error} If the input string is not a valid Base64-encoded string.
248
+ */
249
+ export function makeBase64Url(data: string, mimetype: string = 'application/octet-stream'): string {
250
+ if (!isValidString(data)) {
251
+ throw new Error('Invalid Base64 data!');
252
+ }
253
+
254
+ // Remove any newline characters from the Base64 string
255
+ const cleanedData = data.replace(/\n/g, '');
256
+
257
+ // Construct and return the Data URL
258
+ return `data:${mimetype};base64,${cleanedData}`;
259
+ }
260
+
261
+ /**
262
+ ** It's common practice to split base64 data into multiple lines for better readability and to avoid issues with systems that can't handle very long lines.
263
+ ** So we need to clean up newline characters from the base64 data before processing it.
264
+ * @param {string} str - The input string.
265
+ * @returns {string} The input string with all newline characters and escaped newline strings removed.
266
+ */
267
+ const _cleanUpBase64Data = (str: string): string => {
268
+ // Check if the input is a string and is not excessively large
269
+ if (typeof str !== 'string' || str.length > MAX_FILE_SIZE) {
270
+ throw new Error('Invalid input');
271
+ }
272
+
273
+ // Remove all whitespace characters and literal \n and \s sequences
274
+ return str.replace(/\s|\\n|\\s/g, '');
275
+ };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * This function parses the command line arguments and returns an object with the parsed values.
3
+ * The expected format is --file ./path/to/file.txt or --settings key1=value1 key2=value2
4
+ * Examples:
5
+ * --file ./path/to/file.txt : calling parseCLIArgs('file', process.argv) will return {file: './path/to/file.txt'}
6
+ * --settings key1=value1 key2=value2 : calling parseCLIArgs('settings', process.argv) will return {settings: {key1: 'value1', key2: 'value2'}}
7
+ * it can also parse multiple arguments at once, for example:
8
+ * parseCLIArgs(['file', 'settings'], process.argv) will return {file: './path/to/file.txt', settings: {key1: 'value1', key2: 'value2'}}
9
+ *
10
+ * @param argList the argument to parse
11
+ * @param argv the command line arguments, usually process.argv
12
+ * @returns parsed arguments object
13
+ */
14
+
15
+ export function parseCLIArgs(argList: string | Array<string>, argv?: Array<string>): Record<string, any> {
16
+ if (!argv) argv = process.argv;
17
+ const args = argv;
18
+ const result = {};
19
+ const mainArgs = Array.isArray(argList) ? argList : [argList];
20
+ mainArgs.forEach((mainArg) => {
21
+ const mainArgIndex = args.indexOf(`--${mainArg}`);
22
+ if (mainArgIndex !== -1) {
23
+ const values: any = [];
24
+ for (let i = mainArgIndex + 1; i < args.length; i++) {
25
+ if (args[i].startsWith('--')) break;
26
+ values.push(args[i]);
27
+ }
28
+
29
+ if (values.length === 1 && values[0].includes('=')) {
30
+ const keyValuePairs = {};
31
+ const [key, ...valParts] = values[0].split('=');
32
+ const val = valParts.join('=').replace(/^"|"$/g, '');
33
+ keyValuePairs[key] = val;
34
+ result[mainArg] = keyValuePairs;
35
+ } else if (values.length === 1) {
36
+ result[mainArg] = values[0];
37
+ } else if (values.length > 1) {
38
+ const keyValuePairs = {};
39
+ values.forEach((value) => {
40
+ const [key, ...valParts] = value.split('=');
41
+ const val = valParts.join('=').replace(/^"|"$/g, '');
42
+ keyValuePairs[key] = val;
43
+ });
44
+ result[mainArg] = keyValuePairs;
45
+ }
46
+ }
47
+ });
48
+
49
+ return result;
50
+ }
51
+
52
+ /**
53
+ * List all cli main arguments
54
+ * example : node index.js --file ./path/to/file.txt --settings key1=value1 key2=value2
55
+ * calling getMainArgs(process.argv) will return ['file', 'settings']
56
+ */
57
+ export function getMainArgs(argv?: Array<string>): Array<string> {
58
+ if (!argv) argv = process.argv;
59
+ const args = argv;
60
+ const result = [];
61
+ for (let i = 2; i < args.length; i++) {
62
+ if (args[i].startsWith('--')) {
63
+ result.push(args[i].replace(/^--/, ''));
64
+ }
65
+ }
66
+
67
+ return result;
68
+ }
@@ -0,0 +1,263 @@
1
+ import { Readable } from 'stream';
2
+ import axios from 'axios';
3
+
4
+ import { identifyMimeTypeFromBase64DataUrl, isBase64FileUrl, isBase64, identifyMimetypeFromBase64, isBase64DataUrl } from './base64.utils';
5
+ import { isBinaryFileSync } from 'isbinaryfile';
6
+ import { fileTypeFromBuffer } from 'file-type';
7
+ import { BinaryInput } from '@sre/helpers/BinaryInput.helper';
8
+ import { identifyMimetypeFromString } from './string.utils';
9
+
10
+ // Helper function to convert stream to buffer
11
+ export async function streamToBuffer(stream: Readable): Promise<Buffer> {
12
+ const chunks: Buffer[] = [];
13
+ for await (const chunk of stream) {
14
+ chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
15
+ }
16
+ return Buffer.concat(chunks);
17
+ }
18
+
19
+ /////////////////////////////////////////////////////////////////////////////////////////////
20
+ // == Helpers from Legacy Smyth implementation ==============================================
21
+ // FIXME : below functions should probably be converted to a validator
22
+
23
+ //export declare function isBinaryFile(file: string | Buffer, size?: number): Promise<boolean>;
24
+ //export declare function isBinaryFileSync(file: string | Buffer, size?: number): boolean;
25
+ const binaryMimeTypes = ['image/', 'audio/', 'video/', 'application/pdf', 'application/zip', 'application/octet-stream'];
26
+
27
+ export function dataToBuffer(data: any): Buffer | null {
28
+ let bufferData;
29
+ switch (true) {
30
+ case data instanceof ArrayBuffer:
31
+ bufferData = Buffer.from(new Uint8Array(data));
32
+ break;
33
+ case ArrayBuffer.isView(data) && !(data instanceof DataView):
34
+ bufferData = Buffer.from(new Uint8Array(data.buffer));
35
+ break;
36
+ case data instanceof DataView:
37
+ bufferData = Buffer.from(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
38
+ break;
39
+ case Buffer.isBuffer(data):
40
+ bufferData = data;
41
+ break;
42
+ case typeof data === 'string':
43
+ bufferData = Buffer.from(data, 'utf-8');
44
+ break;
45
+ default:
46
+ return null;
47
+ }
48
+
49
+ return bufferData;
50
+ }
51
+
52
+ export const getSizeFromBinary = (data: any) => {
53
+ const buffer = dataToBuffer(data);
54
+ if (!buffer) return 0;
55
+ return buffer.byteLength;
56
+ };
57
+
58
+ /**
59
+ * Calculates the size in bytes of a base64-encoded string after decoding
60
+ *
61
+ * @param base64String - The base64 string to calculate the size for. Can be a raw base64 string or a data URL.
62
+ * @returns The size in bytes of the decoded data
63
+ */
64
+ function getBase64FileSize(base64String: string): number {
65
+ // Remove data URL prefix if present
66
+ const base64Data = base64String.includes(';base64,') ? base64String.split(';base64,')[1] : base64String;
67
+
68
+ // Formula: (n * 3) / 4 - padding
69
+ const padding = base64Data.endsWith('==') ? 2 : base64Data.endsWith('=') ? 1 : 0;
70
+ return Math.floor((base64Data.length * 3) / 4) - padding;
71
+ }
72
+
73
+ export const isPlainObject = (data: any): boolean => {
74
+ return (
75
+ typeof data === 'object' &&
76
+ data !== null &&
77
+ !Array.isArray(data) &&
78
+ Object.prototype.toString.call(data) === '[object Object]' &&
79
+ data.constructor === Object
80
+ );
81
+ };
82
+
83
+ // isBuffer checks if the provided data is a Buffer object in Node.js.
84
+ export const isBuffer = (data: any): boolean => {
85
+ try {
86
+ return Buffer.isBuffer(data);
87
+ } catch {
88
+ // Buffer.isBuffer throws error when non-array Object is passed
89
+ return false;
90
+ }
91
+ };
92
+
93
+ // isBinaryMimeType checks if the provided mimetype indicates binary data.
94
+ export const isBinaryMimeType = (mimetype): boolean => {
95
+ if (mimetype) {
96
+ return binaryMimeTypes.some((type) => mimetype.startsWith(type));
97
+ }
98
+ return false;
99
+ };
100
+
101
+ // isBinaryData checks if the provided data is binary.
102
+ // If the data is a Buffer, ArrayBuffer, TypedArray, or DataView, it checks if it contains binary data.
103
+ export const isBinaryData = (data): boolean => {
104
+ // To prevent returning true when we have emojis in the string like "Hello 😀"
105
+ if (typeof data === 'string') return false;
106
+
107
+ try {
108
+ const buffer = dataToBuffer(data);
109
+ if (!buffer) return false;
110
+ return isBinaryFileSync(buffer, buffer.byteLength);
111
+ } catch (error) {
112
+ return false;
113
+ }
114
+ };
115
+
116
+ // TODO: Need to check if this is intentional, I think we're checking for http/https urls only
117
+ export function isUrl(str: string): boolean {
118
+ if (typeof str !== 'string') return false;
119
+ // This regex checks for protocol, hostname, domain, port (optional), path (optional), and query string (optional)
120
+ //const regex = /^(https?:\/\/)([^\s.]+\.[^\s]{2,})(:[0-9]{1,5})?(\/[^\s]*)?(\?[^\s]*)?$/i;
121
+ const regex = /^([a-zA-Z0-9]+:\/\/)([^\s.]+\.[^\s]{2,})(:[0-9]{1,5})?(\/[^\s]*)?(\?[^\s]*)?$/i;
122
+
123
+ return regex.test(str);
124
+ }
125
+
126
+ export function isSmythFsUrl(str: string): boolean {
127
+ if (typeof str !== 'string') return false;
128
+ const regex = /^smythfs:\/\/([^\s.]+\.[^\s]{2,})(:[0-9]{1,5})?(\/[^\s]*)?(\?[^\s]*)?$/i;
129
+ return regex.test(str);
130
+ }
131
+
132
+ export const isSmythFileObject = (data: any): boolean => {
133
+ return !!(typeof data === 'object' && data !== null && data?.url && isUrl(data?.url) && 'size' in data && 'mimetype' in data);
134
+ };
135
+
136
+ export const isBufferObject = (data: Record<string, any>): boolean => {
137
+ if (!data) return false;
138
+
139
+ return typeof data === 'object' && data !== null && data?.buffer && isBuffer(data.buffer) && 'size' in data && 'mimetype' in data;
140
+ };
141
+
142
+ export const isBase64Object = (data: Record<string, any>): boolean => {
143
+ if (!data) return false;
144
+
145
+ return typeof data === 'object' && data !== null && data?.base64 && isBase64(data.base64) && 'size' in data && 'mimetype' in data;
146
+ };
147
+
148
+ export async function getMimeType(data: any): Promise<string> {
149
+ const mimeTypeGetters = {
150
+ blob: () => data.type,
151
+ buffer: async () => {
152
+ try {
153
+ // TODO: debug why this is not returning a file type for images when used through BinaryInput.helper.ts
154
+ const fileType = await fileTypeFromBuffer(data);
155
+ return fileType?.mime ?? '';
156
+ } catch {
157
+ console.warn('Failed to get mime type from buffer');
158
+ return '';
159
+ }
160
+ },
161
+ url: async () => {
162
+ try {
163
+ const response = await axios.get(data); // head() method does not work for all URLs
164
+ const contentType = response.headers['content-type'];
165
+ return contentType;
166
+ } catch {
167
+ console.warn('Failed to get mime type from URL');
168
+ return '';
169
+ }
170
+ },
171
+ smythFile: () => data.mimetype,
172
+ base64DataUrl: () => identifyMimeTypeFromBase64DataUrl(data),
173
+ base64: () => identifyMimetypeFromBase64(data),
174
+ string: () => identifyMimetypeFromString(data),
175
+ };
176
+
177
+ const typeChecks = {
178
+ blob: data instanceof Blob,
179
+ buffer: isBuffer(data),
180
+ url: isUrl(data),
181
+ smythFile: isSmythFileObject(data),
182
+ base64DataUrl: isBase64FileUrl(data),
183
+ base64: isBase64(data),
184
+ string: typeof data === 'string',
185
+ };
186
+
187
+ const [matchedType = ''] = Object.entries(typeChecks).find(([, value]) => value) || [];
188
+ if (!matchedType) return '';
189
+
190
+ return await mimeTypeGetters?.[matchedType]?.();
191
+ }
192
+
193
+ // Mask data like Buffer, FormData, etc. in debug output
194
+ // TODO [Forhad]: Need to get the size of FormData
195
+ export async function formatDataForDebug(data: any) {
196
+ let dataForDebug;
197
+
198
+ if (!data) {
199
+ return data;
200
+ }
201
+
202
+ try {
203
+ if (data.constructor?.name === 'BinaryInput') {
204
+ const jsonData = await data.getJsonData();
205
+ dataForDebug = `[BinaryInput size=${jsonData?.size}]`;
206
+ } else if (isBuffer(data)) {
207
+ dataForDebug = `[Buffer size=${data.byteLength}]`;
208
+ } else if (data.constructor?.name === 'FormData') {
209
+ dataForDebug = `[FormData]`;
210
+ } else if (isBase64(data) || isBase64DataUrl(data)) {
211
+ dataForDebug = `[Base64 size=${getBase64FileSize(data)}]`;
212
+ } else {
213
+ dataForDebug = data;
214
+ }
215
+ } catch (error) {
216
+ // Fallback to a safe representation if any error occurs
217
+ dataForDebug = '[Binary]';
218
+ }
219
+
220
+ return dataForDebug;
221
+ }
222
+
223
+ // TODO: Maybe we need move this function to any helper file, as it depends on BinaryInput class
224
+ export async function normalizeImageInput(inputImage: string | BinaryInput): Promise<string> {
225
+ if (!inputImage) {
226
+ return '';
227
+ }
228
+
229
+ // Handle string inputs
230
+ if (typeof inputImage === 'string') {
231
+ if (isBase64(inputImage)) {
232
+ // Convert raw base64 to data URL with proper MIME type
233
+ const mimeType = (await getMimeType(inputImage)) || 'image/png';
234
+ return `data:${mimeType};base64,${inputImage}`;
235
+ }
236
+
237
+ if (isBase64DataUrl(inputImage)) {
238
+ return inputImage; // Already in correct format
239
+ }
240
+
241
+ if (isUrl(inputImage)) {
242
+ return inputImage; // Valid URL, return as-is
243
+ }
244
+
245
+ throw new Error('Invalid string input: must be base64, data URL, or HTTP(S) URL');
246
+ }
247
+
248
+ // Handle BinaryInput
249
+ // * There is a bug (server crash) when we check like this: inputImage instanceof BinaryInput
250
+ // TODO [Forhad]: Need find out the root cause and fix it
251
+ if (inputImage.constructor?.name === 'BinaryInput') {
252
+ try {
253
+ const buffer = await inputImage.getBuffer();
254
+ const mimeType = (await getMimeType(buffer)) || 'image/png';
255
+ const base64Data = buffer.toString('base64');
256
+ return `data:${mimeType};base64,${base64Data}`;
257
+ } catch (error) {
258
+ throw new Error(`Failed to process BinaryInput: ${error.message}`);
259
+ }
260
+ }
261
+
262
+ throw new Error('Unsupported input type');
263
+ }
@@ -0,0 +1,22 @@
1
+ export function getCurrentFormattedDate() {
2
+ const date = new Date();
3
+ const year = date.getFullYear();
4
+ const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-based
5
+ const day = String(date.getDate()).padStart(2, '0');
6
+ const hours = String(date.getHours()).padStart(2, '0');
7
+ const minutes = String(date.getMinutes()).padStart(2, '0');
8
+ const seconds = String(date.getSeconds()).padStart(2, '0');
9
+ return `${year}-${month}-${day}-${hours}-${minutes}-${seconds}`;
10
+ }
11
+
12
+ export function getDayFormattedDate() {
13
+ const date = new Date();
14
+ const year = date.getFullYear();
15
+ const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-based
16
+ const day = String(date.getDate()).padStart(2, '0');
17
+ return `${year}-${month}-${day}`;
18
+ }
19
+
20
+ export function delay(ms) {
21
+ return new Promise((r) => setTimeout(r, ms));
22
+ }