libmodulor 0.3.0 → 0.5.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 (247) hide show
  1. package/CHANGELOG.md +29 -1
  2. package/README.md +7 -182
  3. package/dist/esm/app/workers/AppSrcFilePathBuilder.d.ts +16 -0
  4. package/dist/esm/app/workers/AppSrcFilePathBuilder.js +6 -4
  5. package/dist/esm/apps/Helper/index.js +1 -0
  6. package/dist/esm/apps/Helper/src/ucds/GenerateAppsTestsUCD.js +3 -2
  7. package/dist/esm/bundlers/vite/StripUCDLifecycleServerPlugin.js +3 -0
  8. package/dist/esm/convention.d.ts +1 -0
  9. package/dist/esm/convention.js +17 -4
  10. package/dist/esm/dt/Validation.d.ts +8 -0
  11. package/dist/esm/dt/Validation.js +8 -0
  12. package/dist/esm/dt/base/TBase.d.ts +2 -1
  13. package/dist/esm/dt/base/TBoolean.js +2 -0
  14. package/dist/esm/dt/base/TInt.js +3 -0
  15. package/dist/esm/dt/base/TNumber.js +2 -0
  16. package/dist/esm/dt/base/TObject.d.ts +15 -0
  17. package/dist/esm/dt/base/TObject.js +14 -0
  18. package/dist/esm/dt/base/TString.js +1 -1
  19. package/dist/esm/dt/final/TAmount.js +1 -0
  20. package/dist/esm/dt/final/TCountryISO3166Alpha2.js +1 -0
  21. package/dist/esm/dt/final/TCurrencyISO4217.js +1 -0
  22. package/dist/esm/dt/final/TDateTimeFormat.js +1 -0
  23. package/dist/esm/dt/final/TEmail.js +2 -0
  24. package/dist/esm/dt/final/TEmoji.js +4 -0
  25. package/dist/esm/dt/final/TFile.js +3 -0
  26. package/dist/esm/dt/final/THostAddress.js +2 -0
  27. package/dist/esm/dt/final/TIPv6.js +1 -0
  28. package/dist/esm/dt/final/TJWT.js +8 -0
  29. package/dist/esm/dt/final/TPercentage.js +5 -0
  30. package/dist/esm/dt/final/TSQLQuery.js +1 -0
  31. package/dist/esm/dt/final/TSSHPrivateKey.js +3 -1
  32. package/dist/esm/dt/final/TSemVerVersion.js +1 -0
  33. package/dist/esm/dt/final/TShellCommand.js +1 -0
  34. package/dist/esm/dt/final/TURL.js +2 -0
  35. package/dist/esm/dt/final/TUUID.js +1 -0
  36. package/dist/esm/dt/final/TYesNo.js +1 -1
  37. package/dist/esm/i18n/WordingManager.d.ts +16 -0
  38. package/dist/esm/i18n/types.d.ts +5 -0
  39. package/dist/esm/icon/Icon.d.ts +7 -0
  40. package/dist/esm/index.d.ts +3 -0
  41. package/dist/esm/index.js +4 -0
  42. package/dist/esm/index.react-native-pure.d.ts +10 -0
  43. package/dist/esm/index.react-native-pure.js +10 -0
  44. package/dist/esm/product/manifest.d.ts +15 -0
  45. package/dist/esm/products/Helper/index.js +3 -0
  46. package/dist/esm/products/Helper/manifest.d.ts +6 -1
  47. package/dist/esm/std/BufferManager.d.ts +18 -0
  48. package/dist/esm/std/ClockManager.d.ts +5 -0
  49. package/dist/esm/std/EnvironmentManager.d.ts +10 -0
  50. package/dist/esm/std/HTTPAPICaller.d.ts +6 -0
  51. package/dist/esm/std/I18nManager.d.ts +26 -0
  52. package/dist/esm/std/JWTManager.d.ts +26 -0
  53. package/dist/esm/std/JobManager.d.ts +6 -0
  54. package/dist/esm/std/LLMManager.d.ts +25 -0
  55. package/dist/esm/std/LLMManager.js +1 -0
  56. package/dist/esm/std/PromptManager.d.ts +8 -0
  57. package/dist/esm/std/SettingsManager.d.ts +19 -0
  58. package/dist/esm/std/SettingsManager.js +9 -0
  59. package/dist/esm/std/impl/ConsoleLogger.js +7 -1
  60. package/dist/esm/std/impl/FakeEmailManager.js +1 -0
  61. package/dist/esm/std/impl/FakeJobManager.js +1 -0
  62. package/dist/esm/std/impl/FetchHTTPAPICallExecutor.d.ts +9 -0
  63. package/dist/esm/std/impl/FetchHTTPAPICallExecutor.js +11 -0
  64. package/dist/esm/std/impl/MistralAILLMManager.d.ts +17 -0
  65. package/dist/esm/std/impl/MistralAILLMManager.js +56 -0
  66. package/dist/esm/std/impl/NodeCryptoManager.js +6 -1
  67. package/dist/esm/std/impl/NodeDeterministicCryptoManager.d.ts +14 -0
  68. package/dist/esm/std/impl/NodeDeterministicCryptoManager.js +17 -3
  69. package/dist/esm/std/impl/NodeFSManager.js +10 -0
  70. package/dist/esm/std/impl/NodeHTTPAPICallExecutorAgentBuilder.js +2 -0
  71. package/dist/esm/std/impl/NodePromptManager.js +3 -0
  72. package/dist/esm/std/impl/OllamaLLMManager.d.ts +20 -0
  73. package/dist/esm/std/impl/OllamaLLMManager.js +56 -0
  74. package/dist/esm/std/impl/OpenAILLMManager.d.ts +17 -0
  75. package/dist/esm/std/impl/OpenAILLMManager.js +51 -0
  76. package/dist/esm/std/impl/SimpleHTTPAPICaller.js +14 -0
  77. package/dist/esm/std/impl/SimpleMapI18nManager.js +4 -2
  78. package/dist/esm/std/impl/StdDateClockManager.js +3 -0
  79. package/dist/esm/std/impl/UCDataStoreExternalResourceManager.js +3 -0
  80. package/dist/esm/std/impl/WebCryptoManager.js +9 -0
  81. package/dist/esm/std/index.d.ts +1 -0
  82. package/dist/esm/std/index.js +1 -0
  83. package/dist/esm/target/lib/cli/renderer.js +3 -0
  84. package/dist/esm/target/lib/client/consts.d.ts +3 -0
  85. package/dist/esm/target/lib/client/consts.js +3 -0
  86. package/dist/esm/target/lib/mcp-server/MCPServerBooter.js +1 -0
  87. package/dist/esm/target/lib/react/UCContainer.js +1 -0
  88. package/dist/esm/target/lib/react/UCPanel.js +4 -0
  89. package/dist/esm/target/lib/react/entrypoint.d.ts +2 -0
  90. package/dist/esm/target/lib/react/useUC.d.ts +8 -0
  91. package/dist/esm/target/lib/react/useUC.js +22 -0
  92. package/dist/esm/target/lib/react/useUCOR.d.ts +15 -0
  93. package/dist/esm/target/lib/react/useUCOR.js +45 -0
  94. package/dist/esm/target/lib/rn/input.d.ts +15 -0
  95. package/dist/esm/target/lib/rn/input.js +28 -0
  96. package/dist/esm/target/lib/server/AuthenticationChecker.js +2 -1
  97. package/dist/esm/target/lib/server/BasicAuthenticationChecker.js +1 -0
  98. package/dist/esm/target/lib/server/CSPDirectivesBuilder.js +13 -0
  99. package/dist/esm/target/lib/server/CustomerFacingErrorBuilder.js +3 -0
  100. package/dist/esm/target/lib/server/PrivateApiKeyAuthenticationChecker.js +1 -0
  101. package/dist/esm/target/lib/server/PublicApiKeyChecker.js +1 -1
  102. package/dist/esm/target/lib/server/RequestChecker.js +5 -4
  103. package/dist/esm/target/lib/server/RequestHandler.d.ts +5 -0
  104. package/dist/esm/target/lib/server/RequestLogger.js +5 -0
  105. package/dist/esm/target/lib/server/ServerManager.d.ts +19 -0
  106. package/dist/esm/target/lib/server/consts.d.ts +3 -0
  107. package/dist/esm/target/lib/server/consts.js +3 -0
  108. package/dist/esm/target/lib/web/input.d.ts +21 -0
  109. package/dist/esm/target/lib/web/input.js +4 -0
  110. package/dist/esm/target/node-core-cli/NodeCoreCLIManager.js +2 -2
  111. package/dist/esm/target/node-express-server/NodeExpressServerManager.js +5 -0
  112. package/dist/esm/target/node-express-server/lib/AuthCookieCreator.js +1 -1
  113. package/dist/esm/target/node-express-server/middlewares/AuthenticationCheckerMiddlewareBuilder.js +1 -0
  114. package/dist/esm/target/node-express-server/middlewares/PublicApiKeyCheckerMiddlewareBuilder.js +1 -0
  115. package/dist/esm/target/node-express-server/middlewares/RequestCheckerMiddlewareBuilder.js +1 -0
  116. package/dist/esm/target/node-express-server/middlewares/RequestHandlerMiddlewareBuilder.js +8 -0
  117. package/dist/esm/target/node-express-server/middlewares/RequestLoggerMiddlewareBuilder.js +1 -0
  118. package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.d.ts +10 -0
  119. package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.js +14 -0
  120. package/dist/esm/target/react-native-pure/UCAutoExecLoader.d.ts +2 -0
  121. package/dist/esm/target/react-native-pure/UCAutoExecLoader.js +5 -0
  122. package/dist/esm/target/react-native-pure/UCEntrypointTouchable.d.ts +4 -0
  123. package/dist/esm/target/react-native-pure/UCEntrypointTouchable.js +6 -0
  124. package/dist/esm/target/react-native-pure/UCExecTouchable.d.ts +4 -0
  125. package/dist/esm/target/react-native-pure/UCExecTouchable.js +9 -0
  126. package/dist/esm/target/react-native-pure/UCForm.d.ts +4 -0
  127. package/dist/esm/target/react-native-pure/UCForm.js +13 -0
  128. package/dist/esm/target/react-native-pure/UCFormField.d.ts +11 -0
  129. package/dist/esm/target/react-native-pure/UCFormField.js +32 -0
  130. package/dist/esm/target/react-native-pure/UCFormFieldControl.d.ts +11 -0
  131. package/dist/esm/target/react-native-pure/UCFormFieldControl.js +37 -0
  132. package/dist/esm/target/react-native-pure/UCFormFieldDesc.d.ts +7 -0
  133. package/dist/esm/target/react-native-pure/UCFormFieldDesc.js +11 -0
  134. package/dist/esm/target/react-native-pure/UCFormFieldErr.d.ts +7 -0
  135. package/dist/esm/target/react-native-pure/UCFormFieldErr.js +5 -0
  136. package/dist/esm/target/react-native-pure/UCFormFieldLabel.d.ts +7 -0
  137. package/dist/esm/target/react-native-pure/UCFormFieldLabel.js +8 -0
  138. package/dist/esm/target/react-native-pure/UCFormSubmitControl.d.ts +9 -0
  139. package/dist/esm/target/react-native-pure/UCFormSubmitControl.js +8 -0
  140. package/dist/esm/target/react-web-pure/UCEntrypointTouchable.d.ts +1 -1
  141. package/dist/esm/target/react-web-pure/UCExecTouchable.d.ts +1 -1
  142. package/dist/esm/target/react-web-pure/UCExecTouchable.js +1 -1
  143. package/dist/esm/target/react-web-pure/UCFormFieldControl.d.ts +1 -1
  144. package/dist/esm/target/react-web-pure/UCFormFieldControl.js +3 -3
  145. package/dist/esm/testing/AppTester.d.ts +4 -0
  146. package/dist/esm/testing/AppTester.js +16 -0
  147. package/dist/esm/testing/AppTesterConfigurator.d.ts +68 -0
  148. package/dist/esm/testing/UCDataStoreTester.d.ts +9 -0
  149. package/dist/esm/testing/UCDataStoreTester.js +13 -0
  150. package/dist/esm/testing/impl/SimpleAppDocsEmitter.js +22 -2
  151. package/dist/esm/testing/impl/SimpleAppTesterConfigurator.js +1 -0
  152. package/dist/esm/testing/impl/SimpleHTMLAppTestReportEmitter.js +9 -3
  153. package/dist/esm/testing/impl/TypeScriptLibUCDefASTParser.js +12 -4
  154. package/dist/esm/testing/impl/VitestAppTestSuiteEmitter.js +6 -0
  155. package/dist/esm/testing/opts.d.ts +38 -0
  156. package/dist/esm/testing/opts.js +1 -1
  157. package/dist/esm/testing/uc-input.js +2 -0
  158. package/dist/esm/testing/workers/AppTesterCtxInitializer.js +7 -0
  159. package/dist/esm/testing/workers/UCExecutor.js +1 -0
  160. package/dist/esm/testing/workers/checkers/AppIndexChecker.js +1 -0
  161. package/dist/esm/testing/workers/checkers/UCDefSourcesChecker.js +4 -0
  162. package/dist/esm/uc/UC.js +19 -1
  163. package/dist/esm/uc/UCInputField.d.ts +28 -0
  164. package/dist/esm/uc/UCInputField.js +42 -0
  165. package/dist/esm/uc/data.d.ts +3 -0
  166. package/dist/esm/uc/def.d.ts +7 -0
  167. package/dist/esm/uc/exec.d.ts +39 -0
  168. package/dist/esm/uc/exec.js +29 -0
  169. package/dist/esm/uc/ext.d.ts +30 -1
  170. package/dist/esm/uc/helpers/UCOutputBuilder.js +5 -0
  171. package/dist/esm/uc/helpers/UCOutputReader.js +3 -1
  172. package/dist/esm/uc/impl/HTTPUCTransporter.js +4 -0
  173. package/dist/esm/uc/impl/InMemoryUCDataStore.js +7 -0
  174. package/dist/esm/uc/impl/KnexUCDataStore.d.ts +4 -0
  175. package/dist/esm/uc/impl/KnexUCDataStore.js +14 -0
  176. package/dist/esm/uc/impl/SimpleUCManager.js +6 -0
  177. package/dist/esm/uc/input-field.d.ts +60 -0
  178. package/dist/esm/uc/input-field.js +33 -0
  179. package/dist/esm/uc/input.d.ts +24 -0
  180. package/dist/esm/uc/lifecycle/client/IdleClientMain.js +1 -0
  181. package/dist/esm/uc/lifecycle/server/IdleServerMain.js +2 -0
  182. package/dist/esm/uc/manager.d.ts +11 -0
  183. package/dist/esm/uc/metadata.d.ts +10 -0
  184. package/dist/esm/uc/opi-layout.d.ts +3 -0
  185. package/dist/esm/uc/opi.d.ts +8 -0
  186. package/dist/esm/uc/output-field.d.ts +9 -0
  187. package/dist/esm/uc/output-part.d.ts +22 -0
  188. package/dist/esm/uc/output.d.ts +3 -0
  189. package/dist/esm/uc/policies/RoleRegularUCPolicy.js +1 -0
  190. package/dist/esm/uc/policies/funcs.js +1 -0
  191. package/dist/esm/uc/policy.d.ts +22 -0
  192. package/dist/esm/uc/sec.d.ts +9 -0
  193. package/dist/esm/uc/server.d.ts +10 -0
  194. package/dist/esm/uc/settings.d.ts +25 -0
  195. package/dist/esm/uc/side-effect.d.ts +16 -0
  196. package/dist/esm/uc/side-effect.js +16 -0
  197. package/dist/esm/uc/utils/rInput.d.ts +12 -0
  198. package/dist/esm/uc/utils/rInput.js +2 -0
  199. package/dist/esm/uc/utils/rVal.d.ts +25 -0
  200. package/dist/esm/uc/utils/rVal.js +27 -0
  201. package/dist/esm/uc/utils/recIs.d.ts +9 -0
  202. package/dist/esm/uc/utils/recIs.js +12 -1
  203. package/dist/esm/uc/utils/stripUCDLifecycleServer.d.ts +13 -0
  204. package/dist/esm/uc/utils/stripUCDLifecycleServer.js +17 -0
  205. package/dist/esm/uc/utils/ucifcoIsForArray.d.ts +6 -0
  206. package/dist/esm/uc/utils/ucifcoIsForArray.js +6 -0
  207. package/dist/esm/uc/workers/SimpleAggregateFinder.d.ts +12 -0
  208. package/dist/esm/uc/workers/SimpleAggregateFinder.js +12 -0
  209. package/dist/esm/uc/workers/UCBuilder.d.ts +7 -0
  210. package/dist/esm/uc/workers/UCBuilder.js +7 -0
  211. package/dist/esm/uc/workers/UCExecChecker.js +2 -0
  212. package/dist/esm/uc/workers/UCInputFilesProcessor.js +10 -4
  213. package/dist/esm/uc/workers/UCOutputFilesProcessor.js +6 -2
  214. package/dist/esm/utils/async/sleep.d.ts +10 -0
  215. package/dist/esm/utils/async/sleep.js +10 -0
  216. package/dist/esm/utils/http/appendData.js +5 -1
  217. package/dist/esm/utils/ioc/ContainerPrinter.js +2 -0
  218. package/dist/esm/utils/ioc/bindCommon.js +4 -0
  219. package/dist/esm/utils/ioc/bindNodeCLI.js +2 -0
  220. package/dist/esm/utils/ioc/bindNodeCore.js +1 -0
  221. package/dist/esm/utils/ioc/bindProduct.js +2 -0
  222. package/dist/esm/utils/ioc/bindRN.js +1 -0
  223. package/dist/esm/utils/ioc/bindServer.js +1 -0
  224. package/dist/esm/utils/ioc/bindWeb.js +2 -0
  225. package/dist/esm/utils/ioc/container.js +6 -0
  226. package/dist/esm/utils/numbers/units.js +3 -0
  227. package/dist/esm/utils/types/funcs.d.ts +35 -0
  228. package/dist/esm/utils/types/funcs.js +35 -0
  229. package/dist/esm/utils/types/utility-types.d.ts +17 -0
  230. package/dist/esm/utils/types/utility-types.js +1 -0
  231. package/package.json +16 -9
  232. package/docs/assets/trading-buy-asset-sequence-diagram.png +0 -0
  233. package/docs/assets/trading-target-mcp-server.png +0 -0
  234. package/docs/assets/trading-target-web-human.png +0 -0
  235. package/docs/assets/trading-target-web.png +0 -0
  236. package/docs/getting-started/001_Create_the_project.md +0 -168
  237. package/docs/getting-started/002_Create_the_App.md +0 -49
  238. package/docs/getting-started/003_Create_the_UseCase.md +0 -205
  239. package/docs/getting-started/004_Test_the_App.md +0 -114
  240. package/docs/getting-started/005_Create_the_Product.md +0 -46
  241. package/docs/getting-started/006_Create_the_server_Target.md +0 -130
  242. package/docs/getting-started/007_Create_the_web_Target.md +0 -262
  243. package/docs/getting-started/008_Switch_to_a_persistent_data_storage.md +0 -55
  244. package/docs/getting-started/009_Define_wording_for_humans.md +0 -42
  245. package/docs/getting-started/010_Create_the_cli_Target.md +0 -102
  246. package/docs/getting-started/011_Create_the_mcp_server_Target.md +0 -157
  247. package/docs/getting-started/012_Summary.md +0 -29
@@ -0,0 +1,56 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ var MistralAILLMManager_1;
14
+ import { inject, injectable } from 'inversify';
15
+ let MistralAILLMManager = class MistralAILLMManager {
16
+ static { MistralAILLMManager_1 = this; }
17
+ httpAPICaller;
18
+ settingsManager;
19
+ static BASE_URL = 'https://api.mistral.ai/v1';
20
+ constructor(httpAPICaller, settingsManager) {
21
+ this.httpAPICaller = httpAPICaller;
22
+ this.settingsManager = settingsManager;
23
+ }
24
+ s() {
25
+ return {
26
+ mai_api_key: this.settingsManager.get()('mai_api_key'),
27
+ };
28
+ }
29
+ async send(req) {
30
+ return await this.httpAPICaller.exec({
31
+ authorizationHeader: {
32
+ value: this.s().mai_api_key,
33
+ prefix: 'Bearer',
34
+ },
35
+ errBuilder: async (error) => {
36
+ if ('message' in error) {
37
+ return error.message;
38
+ }
39
+ return error.detail.map((d) => d.msg).join('\n');
40
+ },
41
+ method: 'POST',
42
+ req: {
43
+ envelope: 'json',
44
+ builder: async () => req,
45
+ },
46
+ urlBuilder: async () => `${MistralAILLMManager_1.BASE_URL}/chat/completions`,
47
+ });
48
+ }
49
+ };
50
+ MistralAILLMManager = MistralAILLMManager_1 = __decorate([
51
+ injectable(),
52
+ __param(0, inject('HTTPAPICaller')),
53
+ __param(1, inject('SettingsManager')),
54
+ __metadata("design:paramtypes", [Object, Object])
55
+ ], MistralAILLMManager);
56
+ export { MistralAILLMManager };
@@ -7,10 +7,13 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import crypto from 'node:crypto';
8
8
  import { promisify } from 'node:util';
9
9
  import { injectable } from 'inversify';
10
+ // https://nodejs.org/api/crypto.html#cryptopbkdf2password-salt-iterations-keylen-digest-callback
10
11
  const pbkdf2 = promisify(crypto.pbkdf2);
12
+ // https://nodejs.org/api/crypto.html#cryptoscryptpassword-salt-keylen-options-callback
11
13
  const scrypt = promisify(crypto.scrypt);
12
14
  let NodeCryptoManager = class NodeCryptoManager {
13
15
  async clear() {
16
+ // Nothing to do
14
17
  }
15
18
  hash(algorithm, base, binaryToTextEncoding) {
16
19
  return crypto
@@ -35,9 +38,11 @@ let NodeCryptoManager = class NodeCryptoManager {
35
38
  return Uint8Array.from(result);
36
39
  }
37
40
  async randomString(length) {
41
+ // Not perfect in terms of randomness (because of Math.random() but pretty fine for now)
38
42
  let res = '';
39
43
  while (res.length < length) {
40
44
  const next = Math.random().toString(36).slice(2, 3);
45
+ // For now, we want only chars at the beginning, so it can be used as an identifier (i.e. in a database)
41
46
  if (res.length === 0 &&
42
47
  Number.isInteger(Number.parseInt(next, 10))) {
43
48
  continue;
@@ -50,7 +55,7 @@ let NodeCryptoManager = class NodeCryptoManager {
50
55
  return crypto.randomUUID();
51
56
  }
52
57
  async scrypt(password, salt, keyLength) {
53
- const buffer = (await scrypt(password, salt, keyLength));
58
+ const buffer = (await scrypt(password, salt, keyLength)); // Forced to cast because it seems to be not typed correctly
54
59
  return buffer.toString('hex');
55
60
  }
56
61
  };
@@ -1,6 +1,20 @@
1
1
  import type { UIntQuantity, UUID } from '../../dt/index.js';
2
2
  import type { CryptoManagerRandomString } from '../CryptoManager.js';
3
3
  import { NodeCryptoManager } from './NodeCryptoManager.js';
4
+ /**
5
+ * A deterministic {@link CryptoManager} based on {@link NodeCryptoManager}
6
+ *
7
+ * The main purpose is to have an implementation that generates always the
8
+ * same data deterministically to make snapshot assertions in tests easier.
9
+ *
10
+ * WARNING : it keeps internal "seeds" to generate always the same data.
11
+ *
12
+ * In our case, it's an auto-incremented integer.
13
+ *
14
+ * So if the same implementation is used in multiple places
15
+ * (e.g. in concurrent tests within the same test suite),
16
+ * be ready for "race conditions" and inconsistencies.
17
+ */
4
18
  export declare class NodeDeterministicCryptoManager extends NodeCryptoManager {
5
19
  private randomStringIdx;
6
20
  private uuidIdx;
@@ -7,6 +7,20 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { createHash } from 'node:crypto';
8
8
  import { injectable } from 'inversify';
9
9
  import { NodeCryptoManager } from './NodeCryptoManager.js';
10
+ /**
11
+ * A deterministic {@link CryptoManager} based on {@link NodeCryptoManager}
12
+ *
13
+ * The main purpose is to have an implementation that generates always the
14
+ * same data deterministically to make snapshot assertions in tests easier.
15
+ *
16
+ * WARNING : it keeps internal "seeds" to generate always the same data.
17
+ *
18
+ * In our case, it's an auto-incremented integer.
19
+ *
20
+ * So if the same implementation is used in multiple places
21
+ * (e.g. in concurrent tests within the same test suite),
22
+ * be ready for "race conditions" and inconsistencies.
23
+ */
10
24
  let NodeDeterministicCryptoManager = class NodeDeterministicCryptoManager extends NodeCryptoManager {
11
25
  randomStringIdx = 0;
12
26
  uuidIdx = 0;
@@ -33,14 +47,14 @@ let NodeDeterministicCryptoManager = class NodeDeterministicCryptoManager extend
33
47
  const hashBytes = hash.digest().subarray(0, 16);
34
48
  const bytes = Array.from(hashBytes);
35
49
  if (bytes[6] !== undefined) {
36
- bytes[6] = (bytes[6] & 0x0f) | 0x40;
50
+ bytes[6] = (bytes[6] & 0x0f) | 0x40; // Set the version to 4 (UUID v4)
37
51
  }
38
52
  if (bytes[8] !== undefined) {
39
- bytes[8] = (bytes[8] & 0x3f) | 0x80;
53
+ bytes[8] = (bytes[8] & 0x3f) | 0x80; // Set the variant to the correct RFC 4122 variant
40
54
  }
41
55
  const raw = bytes
42
56
  .map((byte) => {
43
- return (byte + 0x1_00).toString(16).substring(1);
57
+ return (byte + 0x1_00).toString(16).substring(1); // Convert byte to hex
44
58
  })
45
59
  .join('');
46
60
  const uuid = [
@@ -13,6 +13,9 @@ let NodeFSManager = class NodeFSManager {
13
13
  return true;
14
14
  }
15
15
  async cat(path, opts) {
16
+ // Be careful : omitting to pass an encoding makes it return a Buffer and not a string
17
+ // This can be problematic in some callers, manipulating the file as a string (e.g. startsWith, includes, etc.)
18
+ // So make sure to fallback on a default encoding
16
19
  return readFile(path, opts?.encoding ?? 'utf8');
17
20
  }
18
21
  async chmod(path, mode) {
@@ -25,6 +28,8 @@ let NodeFSManager = class NodeFSManager {
25
28
  await appendFile(src, content);
26
29
  }
27
30
  async exists(path) {
31
+ // Before, we could use fs.exists(path) but it's been deprecated : @deprecated since v1.0.0 Use `fs.stat()` or `fs.access()` instead
32
+ // Both functions are very unpractical to use because we need to wrap everything in a try/catch. It's too verbose !
28
33
  try {
29
34
  await stat(path);
30
35
  return true;
@@ -45,6 +50,11 @@ let NodeFSManager = class NodeFSManager {
45
50
  const parsedPath = parse(path);
46
51
  const stats = await stat(path);
47
52
  const { birthtime, size } = stats;
53
+ // For now there is nothing in the standard library to detect it.
54
+ // There are 3rd party packages like mime, mime-type, etc. but we prefer
55
+ // limiting the external dependencies.
56
+ // One can also call `file -b --mime-type /some/path` via exec/spawn if their
57
+ // system has this utility.
48
58
  const mimeType = null;
49
59
  const type = this.determineType(stats);
50
60
  return {
@@ -21,6 +21,8 @@ let NodeHTTPAPICallExecutorAgentBuilder = class NodeHTTPAPICallExecutorAgentBuil
21
21
  exec({ url, }) {
22
22
  if (url.protocol.startsWith('https')) {
23
23
  return new https.Agent({
24
+ // We allow self-signed certificates in non-prod environments
25
+ // This is useful when testing the CLI calling a the server from a docker container for example
24
26
  rejectUnauthorized: this.environmentManager.isProd(),
25
27
  });
26
28
  }
@@ -9,10 +9,13 @@ import { createInterface } from 'node:readline/promises';
9
9
  import { injectable } from 'inversify';
10
10
  let NodePromptManager = class NodePromptManager {
11
11
  async prompt(invite, opts) {
12
+ // TODO : Add keypress handling to hide when sensitive data is typed
12
13
  const readLine = createInterface({
13
14
  input: stdin,
14
15
  output: stdout,
15
16
  });
17
+ // To avoid "Warning: Detected unsettled top-level await at file:///[...]/dist/esm/xxx.js"
18
+ // when pressing Ctrl+C while being prompted
16
19
  readLine.on('SIGINT', () => {
17
20
  readLine.close();
18
21
  process.exit(0);
@@ -0,0 +1,20 @@
1
+ import type { URL } from '../../dt/index.js';
2
+ import type { HTTPAPICaller } from '../HTTPAPICaller.js';
3
+ import type { LLMManager, LLMManagerSendReq, LLMManagerSendRes } from '../LLMManager.js';
4
+ import type { Configurable, Settings, SettingsManager } from '../SettingsManager.js';
5
+ /**
6
+ * Unlike the "commercial" APIs, Ollama does not secure the API with an API key
7
+ * @see https://github.com/ollama/ollama/issues/849
8
+ */
9
+ export interface OllamaLLMManagerSettings extends Settings {
10
+ oll_base_url: URL;
11
+ }
12
+ type S = OllamaLLMManagerSettings;
13
+ export declare class OllamaLLMManager implements Configurable<S>, LLMManager {
14
+ private httpAPICaller;
15
+ private settingsManager;
16
+ constructor(httpAPICaller: HTTPAPICaller, settingsManager: SettingsManager<S>);
17
+ s(): OllamaLLMManagerSettings;
18
+ send(req: LLMManagerSendReq): Promise<LLMManagerSendRes>;
19
+ }
20
+ export {};
@@ -0,0 +1,56 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { inject, injectable } from 'inversify';
14
+ import { IllegalArgumentError } from '../../error/index.js';
15
+ let OllamaLLMManager = class OllamaLLMManager {
16
+ httpAPICaller;
17
+ settingsManager;
18
+ constructor(httpAPICaller, settingsManager) {
19
+ this.httpAPICaller = httpAPICaller;
20
+ this.settingsManager = settingsManager;
21
+ }
22
+ s() {
23
+ return {
24
+ oll_base_url: this.settingsManager.get()('oll_base_url'),
25
+ };
26
+ }
27
+ async send(req) {
28
+ const firstMessage = req.messages[0];
29
+ if (!firstMessage) {
30
+ throw new IllegalArgumentError('Please provide at least one message');
31
+ }
32
+ return await this.httpAPICaller.exec({
33
+ errBuilder: async (error) => error.error,
34
+ method: 'POST',
35
+ outputBuilder: async (res) => ({
36
+ choices: [{ message: { content: res.response } }],
37
+ }),
38
+ req: {
39
+ envelope: 'json',
40
+ builder: async () => ({
41
+ model: req.model,
42
+ prompt: firstMessage.content,
43
+ stream: false,
44
+ }),
45
+ },
46
+ urlBuilder: async () => `${this.s().oll_base_url}/api/generate`,
47
+ });
48
+ }
49
+ };
50
+ OllamaLLMManager = __decorate([
51
+ injectable(),
52
+ __param(0, inject('HTTPAPICaller')),
53
+ __param(1, inject('SettingsManager')),
54
+ __metadata("design:paramtypes", [Object, Object])
55
+ ], OllamaLLMManager);
56
+ export { OllamaLLMManager };
@@ -0,0 +1,17 @@
1
+ import type { ApiKey } from '../../dt/index.js';
2
+ import type { HTTPAPICaller } from '../HTTPAPICaller.js';
3
+ import type { LLMManager, LLMManagerSendReq, LLMManagerSendRes } from '../LLMManager.js';
4
+ import type { Configurable, Settings, SettingsManager } from '../SettingsManager.js';
5
+ export interface OpenAILLMManagerSettings extends Settings {
6
+ oai_api_key: ApiKey;
7
+ }
8
+ type S = OpenAILLMManagerSettings;
9
+ export declare class OpenAILLMManager implements Configurable<S>, LLMManager {
10
+ private httpAPICaller;
11
+ private settingsManager;
12
+ private static BASE_URL;
13
+ constructor(httpAPICaller: HTTPAPICaller, settingsManager: SettingsManager<S>);
14
+ s(): OpenAILLMManagerSettings;
15
+ send(req: LLMManagerSendReq): Promise<LLMManagerSendRes>;
16
+ }
17
+ export {};
@@ -0,0 +1,51 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ var OpenAILLMManager_1;
14
+ import { inject, injectable } from 'inversify';
15
+ let OpenAILLMManager = class OpenAILLMManager {
16
+ static { OpenAILLMManager_1 = this; }
17
+ httpAPICaller;
18
+ settingsManager;
19
+ static BASE_URL = 'https://api.openai.com/v1';
20
+ constructor(httpAPICaller, settingsManager) {
21
+ this.httpAPICaller = httpAPICaller;
22
+ this.settingsManager = settingsManager;
23
+ }
24
+ s() {
25
+ return {
26
+ oai_api_key: this.settingsManager.get()('oai_api_key'),
27
+ };
28
+ }
29
+ async send(req) {
30
+ return await this.httpAPICaller.exec({
31
+ authorizationHeader: {
32
+ value: this.s().oai_api_key,
33
+ prefix: 'Bearer',
34
+ },
35
+ errBuilder: async (error) => error.error.message,
36
+ method: 'POST',
37
+ req: {
38
+ envelope: 'json',
39
+ builder: async () => req,
40
+ },
41
+ urlBuilder: async () => `${OpenAILLMManager_1.BASE_URL}/chat/completions`,
42
+ });
43
+ }
44
+ };
45
+ OpenAILLMManager = OpenAILLMManager_1 = __decorate([
46
+ injectable(),
47
+ __param(0, inject('HTTPAPICaller')),
48
+ __param(1, inject('SettingsManager')),
49
+ __metadata("design:paramtypes", [Object, Object])
50
+ ], OpenAILLMManager);
51
+ export { OpenAILLMManager };
@@ -64,6 +64,7 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
64
64
  if (status === 202 || status === 204) {
65
65
  return {};
66
66
  }
67
+ // Using .startsWith instead of === because the value can look like this 'application/json; charset=utf-8'
67
68
  const responseContentType = headers.get('Content-Type');
68
69
  const isJSON = responseContentType?.startsWith('application/json');
69
70
  const isFormURLEncoded = responseContentType?.startsWith('application/x-www-form-urlencoded');
@@ -87,6 +88,10 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
87
88
  async computeHeaders({ additionalHeadersBuilder, authorizationHeader, basicAuth, contentType = 'application/json', req, }) {
88
89
  const headers = {};
89
90
  if (req?.envelope !== 'form-data') {
91
+ // The boundary needs to be set when sending data this way, so the server can understand how to read it (Source : https://stackoverflow.com/a/20321259/1259118)
92
+ // In RN, the content-type we set is automatically overriden by the internal fetch client (i.e. 'content-type': 'multipart/form-data; boundary=7ZsqoHiTstShSc4-Yi4U7ier3GPc_4QL5iN2eT9rnSNd0g1UoFPgt3I6.fsWlV8YpJhFkG')
93
+ // In CLI, if it is set, it's not overriden. So it creates problems. With 'form-data', we send 'content-type': 'multipart/form-data'` but the server expects something like 'content-type': 'multipart/form-data;boundary=--------------------------743913816161509008636675'
94
+ // So we don't set it at all and we're good to go.
90
95
  headers['Content-Type'] = contentType;
91
96
  }
92
97
  if (authorizationHeader) {
@@ -110,6 +115,8 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
110
115
  return headers;
111
116
  }
112
117
  async processResBad({ errBuilder, opts, }, isJSON, isXML, response) {
118
+ // NOTE : This method must handle all possible cases and never throw
119
+ // Indeed, it's supposed to handle the errors so it shouldn't throw one
113
120
  let error;
114
121
  try {
115
122
  if (isJSON) {
@@ -134,6 +141,7 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
134
141
  return null;
135
142
  }
136
143
  if (typeof error === 'string') {
144
+ // For example, it can be from `asText`, containing funny formatting (developers and errors you know...)
137
145
  return error.trim();
138
146
  }
139
147
  if (!error) {
@@ -144,10 +152,14 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
144
152
  if (typeof message === 'string') {
145
153
  return message;
146
154
  }
155
+ // Case where `errBuilder` is of type (error: string) => string
156
+ // If an object is passed to it, it would return an object instead, interpreted incorrectly as [object Object] by error handlers
147
157
  return JSON.stringify(message);
148
158
  }
149
159
  catch (err) {
150
160
  this.logger.error(err);
161
+ // Case where `errBuilder` is of type (error: Object) => string
162
+ // If an object of another shape is passed to it, it would trigger some TypeError or cannot call .message of undefined
151
163
  return JSON.stringify(error);
152
164
  }
153
165
  }
@@ -163,7 +175,9 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
163
175
  });
164
176
  if (isFormURLEncoded) {
165
177
  payload = {};
178
+ // TODO : Find a better way to do this (without adding any external dependency because the code must be portable)
166
179
  new URL(`http://localhost?${asText}`).searchParams.forEach((v, k) => {
180
+ // @ts-ignore
167
181
  payload[k] = v;
168
182
  });
169
183
  }
@@ -17,7 +17,7 @@ let SimpleMapI18nManager = class SimpleMapI18nManager {
17
17
  static { SimpleMapI18nManager_1 = this; }
18
18
  i18n;
19
19
  logger;
20
- static PLACEHOLDERS_REGEX = /{{([A-Z-a-z0-9]+)}}/g;
20
+ static PLACEHOLDERS_REGEX = /{{([A-Z-a-z0-9]+)}}/g; // Note the 'g' so it can be used with `matchAll`
21
21
  entries;
22
22
  constructor(i18n, logger) {
23
23
  this.i18n = i18n;
@@ -48,12 +48,14 @@ let SimpleMapI18nManager = class SimpleMapI18nManager {
48
48
  if (opts?.fallback) {
49
49
  return opts.fallback;
50
50
  }
51
- return key;
51
+ return key; // Mimic the behavior of some common libraries like i18next
52
52
  }
53
53
  tOrNull(key, _opts) {
54
54
  return this.entries.get(key) || null;
55
55
  }
56
56
  replacePlaceholders(v, opts) {
57
+ // DO NOT USE THIS IN PRODUCTION
58
+ // The purpose of it is to have a simple and dependency-less implementation, to play with
57
59
  let res = v;
58
60
  const placeholders = res.matchAll(SimpleMapI18nManager_1.PLACEHOLDERS_REGEX);
59
61
  for (const [placeholder, key] of placeholders) {
@@ -10,6 +10,9 @@ let StdDateClockManager = class StdDateClockManager {
10
10
  return new Date();
11
11
  }
12
12
  nowToKey() {
13
+ // The rationale behind this being hardcoded is to avoid adding a library (luxon, date-fns) just for that.
14
+ // For instance, luxon adds a huge amount of code to a basic web target when bundled, for nothing.
15
+ // See https://github.com/moment/luxon/issues/854#issuecomment-1729384672
13
16
  return this.now()
14
17
  .toISOString()
15
18
  .replaceAll(/-|T|:/g, '')
@@ -11,6 +11,9 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
13
  import { inject, injectable } from 'inversify';
14
+ // TODO : Wait for the DB to be ready or add a retry mechanism
15
+ // Because when we start from a fresh install, this is executed before the docker container is ready
16
+ // A temporary workaround is to stop and restart everything. At the 2nd startup, the db is ready, and it works
14
17
  let UCDataStoreExternalResourceManager = class UCDataStoreExternalResourceManager {
15
18
  ucDataStore;
16
19
  constructor(ucDataStore) {
@@ -10,6 +10,7 @@ const DIGEST_MAPPING = new Map([
10
10
  ]);
11
11
  let WebCryptoManager = class WebCryptoManager {
12
12
  async clear() {
13
+ // Nothing to do
13
14
  }
14
15
  hash(_algorithm, _base) {
15
16
  throw new Error('Method not implemented.');
@@ -25,9 +26,13 @@ let WebCryptoManager = class WebCryptoManager {
25
26
  if (!hash) {
26
27
  throw new Error(`Digest ${digest} is not valid for WebCryptoManager`);
27
28
  }
29
+ // "Secure context: This feature is available only in secure contexts (HTTPS), in some or all supporting browsers."
30
+ // Warning: This API provides a number of low-level cryptographic primitives. It's very easy to misuse them, and the pitfalls involved can be very subtle.
31
+ // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto
28
32
  const textEncoder = new TextEncoder();
29
33
  const passwordKey = await crypto.subtle.importKey('raw', textEncoder.encode(password), 'PBKDF2', false, ['deriveBits']);
30
34
  const result = await crypto.subtle.deriveBits({
35
+ // https://developer.mozilla.org/en-US/docs/Web/API/Pbkdf2Params
31
36
  hash,
32
37
  iterations: iterationsCount,
33
38
  name: 'PBKDF2',
@@ -36,9 +41,11 @@ let WebCryptoManager = class WebCryptoManager {
36
41
  return new Uint8Array(result);
37
42
  }
38
43
  async randomString(length) {
44
+ // Not perfect in terms of randomness (because of Math.random() but pretty fine for now)
39
45
  let res = '';
40
46
  while (res.length < length) {
41
47
  const next = Math.random().toString(36).slice(2, 3);
48
+ // For now, we want only chars at the beginning, so it can be used as an identifier (i.e. in a database)
42
49
  if (res.length === 0 &&
43
50
  Number.isInteger(Number.parseInt(next, 10))) {
44
51
  continue;
@@ -48,6 +55,8 @@ let WebCryptoManager = class WebCryptoManager {
48
55
  return res;
49
56
  }
50
57
  randomUUID() {
58
+ // "Secure context: This feature is available only in secure contexts (HTTPS), in some or all supporting browsers."
59
+ // https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID
51
60
  return crypto.randomUUID();
52
61
  }
53
62
  async scrypt() {
@@ -13,6 +13,7 @@ export * from './HTTPAPICallExecutor.js';
13
13
  export * from './I18nManager.js';
14
14
  export * from './JobManager.js';
15
15
  export * from './JWTManager.js';
16
+ export * from './LLMManager.js';
16
17
  export * from './Logger.js';
17
18
  export * from './PromptManager.js';
18
19
  export * from './SettingsManager.js';
@@ -13,6 +13,7 @@ export * from './HTTPAPICallExecutor.js';
13
13
  export * from './I18nManager.js';
14
14
  export * from './JobManager.js';
15
15
  export * from './JWTManager.js';
16
+ export * from './LLMManager.js';
16
17
  export * from './Logger.js';
17
18
  export * from './PromptManager.js';
18
19
  export * from './SettingsManager.js';
@@ -1,5 +1,6 @@
1
1
  import { CustomError } from '../../../error/index.js';
2
2
  export function print(line) {
3
+ // biome-ignore lint/suspicious/noConsole: we want it
3
4
  console.info(line);
4
5
  }
5
6
  export function printError(err) {
@@ -7,11 +8,13 @@ export function printError(err) {
7
8
  if (err instanceof Error) {
8
9
  message = err.message;
9
10
  if (!(err instanceof CustomError)) {
11
+ // biome-ignore lint/suspicious/noConsole: we want it
10
12
  console.error(err);
11
13
  }
12
14
  }
13
15
  else if (typeof err === 'string') {
14
16
  message = err;
15
17
  }
18
+ // biome-ignore lint/suspicious/noConsole: we want it
16
19
  console.error(message);
17
20
  }
@@ -1,2 +1,5 @@
1
1
  import type { ServerClientManagerSettings } from './ServerClientManager.js';
2
+ /**
3
+ * @see TARGET_DEFAULT_SERVER_MANAGER_SETTINGS
4
+ */
2
5
  export declare const TARGET_DEFAULT_SERVER_CLIENT_MANAGER_SETTINGS: ServerClientManagerSettings;
@@ -1,3 +1,6 @@
1
+ /**
2
+ * @see TARGET_DEFAULT_SERVER_MANAGER_SETTINGS
3
+ */
1
4
  export const TARGET_DEFAULT_SERVER_CLIENT_MANAGER_SETTINGS = {
2
5
  server_public_api_key: 'PublicApiKeyToBeChangedWhenDeploying',
3
6
  server_public_api_key_header_name: 'X-API-Key',
@@ -32,6 +32,7 @@ let MCPServerBooter = class MCPServerBooter {
32
32
  srcImporter,
33
33
  });
34
34
  for await (const uc of ucs) {
35
+ // Declared only for compatibility with ServerManager's contract but not used
35
36
  const contract = ucHTTPContract(uc);
36
37
  await this.ucManager.initServer(uc);
37
38
  await this.serverManager.mount(uc.appManifest, uc.def, contract);
@@ -15,6 +15,7 @@ export function UCContainer({ children, uc, }) {
15
15
  })();
16
16
  }, [uc, ucExecChecker]);
17
17
  if (isAllowed === undefined) {
18
+ // TODO : Add some loader while we check if can do
18
19
  return React.createElement(React.Fragment, null);
19
20
  }
20
21
  if (isAllowed === false) {
@@ -33,6 +33,9 @@ export function UCPanel({ autoExec = false, clearAfterExec = true, onDone, onErr
33
33
  };
34
34
  const onSubmit = async () => {
35
35
  setExecState('submitting');
36
+ // Is some targets, the confirmClient blocks the main thread (e.g. window.confirm()).
37
+ // This leads to the state set above not being updated.
38
+ // This is a "hacky" workaroud to let React re-render the control with 'submitting' state before
36
39
  await sleep(100);
37
40
  await onStartSubmitting?.();
38
41
  const confirmed = await ucManager.confirmClient(uc);
@@ -62,6 +65,7 @@ export function UCPanel({ autoExec = false, clearAfterExec = true, onDone, onErr
62
65
  };
63
66
  const disabled = ucIsDisabled(execState);
64
67
  const loading = ucIsLoading(execState);
68
+ // TODO : Keep these as a state to avoid recomputation
65
69
  const ctx = {
66
70
  clearAfterExec,
67
71
  disabled,
@@ -1,6 +1,8 @@
1
1
  import type { URLPath } from '../../../dt/index.js';
2
2
  import type { UC, UCInput, UCOPIBase } from '../../../uc/index.js';
3
+ export type UCEntrypointOnPress = () => Promise<void>;
3
4
  export interface UCEntrypointCtx<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> {
5
+ onPress?: UCEntrypointOnPress;
4
6
  path?: URLPath | undefined;
5
7
  uc: UC<I, OPI0, OPI1>;
6
8
  }
@@ -2,6 +2,14 @@ import { type ArgsRecord, UC, type UCDef, type UCInput, type UCOPIBase } from '.
2
2
  type CloneFunc<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = (i: Partial<I>) => UC<I, OPI0, OPI1>;
3
3
  type DivertFunc<II extends UCInput | undefined = undefined, OOPI0 extends UCOPIBase | undefined = undefined, OOPI1 extends UCOPIBase | undefined = undefined> = (siblingUCD: UCDef) => UC<II, OOPI0, OOPI1>;
4
4
  type RefillFunc<I extends UCInput | undefined = undefined> = (i: Partial<I>) => void;
5
+ /**
6
+ * This hook provides utilities to init a use case and perform actions on it in a React way
7
+ * @param appManifest
8
+ * @param def
9
+ * @param auth
10
+ * @param opts
11
+ * @returns
12
+ */
5
13
  export declare function useUC<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(appManifest: ArgsRecord<I, OPI0, OPI1>['appManifest'], def: ArgsRecord<I, OPI0, OPI1>['def'], auth: ArgsRecord<I, OPI0, OPI1>['auth'], opts?: {
6
14
  fillWith: Partial<I>;
7
15
  }): [