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
@@ -19,6 +19,7 @@ let VitestAppTestSuiteEmitter = class VitestAppTestSuiteEmitter {
19
19
  }
20
20
  async exec({ appPath, depsMapping, idx, monkeyTestingTimeoutInMs, serverPortRangeStart, }) {
21
21
  const testPath = this.fsManager.path(appPath, APP_TEST_DIR_NAME);
22
+ // Since we're using 'recursive: true', there will be no error if the directory already exists
22
23
  await this.fsManager.mkdir(testPath, { recursive: true });
23
24
  const outPath = this.fsManager.path(testPath, APP_TEST_MAIN_FILE_NAME);
24
25
  let tpl = template(serverPortRangeStart, idx, monkeyTestingTimeoutInMs);
@@ -37,6 +38,11 @@ VitestAppTestSuiteEmitter = __decorate([
37
38
  __metadata("design:paramtypes", [Object])
38
39
  ], VitestAppTestSuiteEmitter);
39
40
  export { VitestAppTestSuiteEmitter };
41
+ // For now, we can have it here. When it becomes harder to maintain, we can introduce some kind of template engine.
42
+ // Be aware that this will introduce complexities on building the lib.
43
+ // We'll need to include these templates in the build and make them accessible via package.json "exports" or any other mechanism.
44
+ // Hence the choice to keep it simple for now.
45
+ // Defined it as function in case we need to pass args.
40
46
  const template = (serverPortRangeStart, idx, monkeyTestingTimeoutInMs) => `/*
41
47
  All this code has been auto generated.
42
48
  DO NOT EDIT.
@@ -5,25 +5,63 @@ import type { AppTesterCtx } from './ctx.js';
5
5
  type AppTesterOptsAliasPrefix = string;
6
6
  type AppTesterOptsImportsList = string[];
7
7
  export interface AppTesterTypeScriptOpts {
8
+ /**
9
+ * Although the TS lib relies on an enum (`ModuleKind`), we use plain text so it's compatible with a regular tsconfig.json
10
+ * @see https://www.typescriptlang.org/tsconfig/#module
11
+ * @defaultValue "NodeNext"
12
+ */
8
13
  module?: string;
14
+ /**
15
+ * Although the TS lib relies on an enum (`ModuleResolutionKind`), we use plain text so it's compatible with a regular tsconfig.json
16
+ * @see https://www.typescriptlang.org/tsconfig/#moduleResolution
17
+ * @defaultValue "NodeNext"
18
+ */
9
19
  moduleResolution?: string;
20
+ /**
21
+ * @see https://www.typescriptlang.org/tsconfig/#noCheck
22
+ * @defaultValue true
23
+ */
10
24
  noCheck?: boolean;
25
+ /**
26
+ * @see https://www.typescriptlang.org/tsconfig/#skipLibCheck
27
+ * @defaultValue true
28
+ */
11
29
  skipLibCheck?: boolean;
30
+ /**
31
+ * Although the TS lib relies on an enum (`ScriptTarget`), we use plain text so it's compatible with a regular tsconfig.json
32
+ * @see https://www.typescriptlang.org/tsconfig/#target
33
+ * @defaultValue "ESNext"
34
+ */
12
35
  target?: string;
13
36
  }
14
37
  export type AppTesterOpts = Partial<Pick<LoggerSettings, 'logger_level'>> & {
15
38
  source?: {
16
39
  imports?: {
17
40
  external?: {
41
+ /**
42
+ * @defaultValue '@'
43
+ */
18
44
  aliasPrefix?: AppTesterOptsAliasPrefix;
45
+ /**
46
+ * @defaultValue ['fik-sdk', 'inversify']
47
+ */
19
48
  allowed?: AppTesterOptsImportsList;
20
49
  };
21
50
  internal?: {
51
+ /**
52
+ * @defaultValue '../../'
53
+ */
22
54
  maxDepth?: FilePath;
55
+ /**
56
+ * @defaultValue '.'
57
+ */
23
58
  startChar?: string;
24
59
  };
25
60
  };
26
61
  ts?: {
62
+ /**
63
+ * @defaultValue tsconfig.json
64
+ */
27
65
  configFileName?: FileName;
28
66
  } & AppTesterTypeScriptOpts;
29
67
  };
@@ -1,5 +1,5 @@
1
1
  export const DEFAULT_APP_TESTER_OPTS = {
2
- logger_level: 'error',
2
+ logger_level: 'error', // Having 'debug' makes the test output bloated so it's opt-in
3
3
  source: {
4
4
  imports: {
5
5
  external: {
@@ -33,11 +33,13 @@ export function onlySetProgrammaticallyWithExamples(uc) {
33
33
  fillWithExample(f);
34
34
  }
35
35
  }
36
+ // biome-ignore lint/suspicious/noExplicitAny: can be anything
36
37
  function fillWithExample(f) {
37
38
  const { type } = f.def;
38
39
  let val = type.getExamples()?.[0] ?? type.example();
39
40
  if (type instanceof TFile) {
40
41
  const file = val;
42
+ // TODO : Consider building a real file with real data (e.g. image, pdf, txt, etc.)
41
43
  val = new File(['01010101010101010101010101010101'], file.path, {
42
44
  type: file.type,
43
45
  });
@@ -28,6 +28,10 @@ let AppTesterCtxInitializer = class AppTesterCtxInitializer {
28
28
  const filePaths = await this.fsManager.ls(ucdsPath);
29
29
  const ucdFilePaths = filePaths.filter(({ path, type }) => path.endsWith(UC_DEF_FILE_NAME_SUFFIX) &&
30
30
  type === FSManagerItemInfoType.FILE);
31
+ // Initially, this was using Promise.all.
32
+ // But in some cases, it hangs. I didn't investigate more, but I suspect some lock on the CPU or FileSystem.
33
+ // There were exactly 6 use cases.
34
+ // Since 'for await of' fixes it, let's just use and investigate when we have more time.
31
35
  const ucdRefs = [];
32
36
  for await (const { path } of ucdFilePaths) {
33
37
  ucdRefs.push({
@@ -36,6 +40,9 @@ let AppTesterCtxInitializer = class AppTesterCtxInitializer {
36
40
  name: path.replace(UC_DEF_FILE_NAME_SUFFIX, ''),
37
41
  });
38
42
  }
43
+ // Sorting is necessary because the file system sorting is not necessarily the same as A-Z sorting.
44
+ // Indeed, CreatePostUCD will arrive after CreatePostCommentUCD in the file system.
45
+ // But in alphabetical order, CreatePost should arrive before CreatePostComment.
39
46
  ucdRefs.sort((a, b) => a.name.localeCompare(b.name));
40
47
  return {
41
48
  ctx: {
@@ -43,6 +43,7 @@ let UCExecutor = class UCExecutor {
43
43
  o: null,
44
44
  },
45
45
  };
46
+ // In a typical scenario, client calls the server so only the client actually needs to be called here
46
47
  await this.execClient(appManifest, ucd, out);
47
48
  return {
48
49
  out,
@@ -21,6 +21,7 @@ let AppIndexChecker = class AppIndexChecker {
21
21
  this.output = { errors: [] };
22
22
  }
23
23
  async exec({ appPath }) {
24
+ // TODO : Consider changing this to await import like the other checkers
24
25
  const contents = await this.fsManager.cat(this.fsManager.path(appPath, APP_INDEX_FILE_NAME));
25
26
  this.makeSureExposesNecessary(contents);
26
27
  return this.output;
@@ -21,6 +21,7 @@ const ERR_UCD_IMPORTS_INTERNAL_MAX_DEPTH = (maxDepth) => `Internal imports must
21
21
  const ERR_UCD_INPUT_FIELD_PATTERN = () => `The input field def must match ${UC_INPUT_FIELD_PATTERN}`;
22
22
  const ERR_UCD_INPUT_TYPE_NAME = (ucName) => `The input type must be named ${ucName}${UC_INPUT_SUFFIX}`;
23
23
  const ERR_UCD_OPI_TYPE_NAME = (ucName, idx) => `The OPI must be named ${ucName}${UC_OPI_SUFFIX}${idx}`;
24
+ // TODO : Improve the check* methods that look a little bit hacky
24
25
  let UCDefSourcesChecker = class UCDefSourcesChecker {
25
26
  fsManager;
26
27
  logger;
@@ -37,6 +38,7 @@ let UCDefSourcesChecker = class UCDefSourcesChecker {
37
38
  }
38
39
  async exec({ ctx }) {
39
40
  const { appPath, opts } = ctx;
41
+ // TODO : Consider removing this and using profiling when needed
40
42
  const startTime = new Date().getTime();
41
43
  this.logger.debug('UCDefSourceChecker starting', {
42
44
  appPath,
@@ -96,6 +98,7 @@ let UCDefSourcesChecker = class UCDefSourcesChecker {
96
98
  continue;
97
99
  }
98
100
  const [_name, type] = parts;
101
+ // trim because we process `name: Type` if the code is linted correctly
99
102
  f.err =
100
103
  type?.trim().match(new RegExp(UC_INPUT_FIELD_PATTERN)) !== null
101
104
  ? null
@@ -155,6 +158,7 @@ let UCDefSourcesChecker = class UCDefSourcesChecker {
155
158
  const fieldsKey = `${key}Fields`;
156
159
  item[fieldsKey] = fields;
157
160
  for (const f of item[fieldsKey]) {
161
+ // There are no specific validation rules for OPIx for now
158
162
  f.err = null;
159
163
  }
160
164
  }
package/dist/esm/uc/UC.js CHANGED
@@ -8,6 +8,7 @@ export class UC {
8
8
  appManifest;
9
9
  def;
10
10
  auth;
11
+ // biome-ignore lint/suspicious/noExplicitAny: can be anything
11
12
  inputFields;
12
13
  constructor(appManifest, def, auth) {
13
14
  this.appManifest = appManifest;
@@ -15,11 +16,15 @@ export class UC {
15
16
  this.auth = auth;
16
17
  const iFields = def.io.i?.fields;
17
18
  this.inputFields = iFields
18
- ? Object.entries(iFields).map(([key, def]) => new UCInputField(key, def))
19
+ ? Object.entries(iFields).map(([key, def]) => new UCInputField(key,
20
+ // biome-ignore lint/suspicious/noExplicitAny: can be anything
21
+ def))
19
22
  : [];
20
23
  }
21
24
  clear() {
22
25
  for (const f of this.inputFields) {
26
+ // We clear only the fields that have been filled manually
27
+ // For example, fields marked as `UCInputFieldFillingMode.AUTO_PRE` are not cleared so they can be reused in the use case
23
28
  if (!ucifMustBeFilledManually(f.def)) {
24
29
  continue;
25
30
  }
@@ -27,6 +32,8 @@ export class UC {
27
32
  }
28
33
  }
29
34
  clearSensitiveInputFields() {
35
+ // TODO : Check how we can automate this before and .persist operation
36
+ // Be careful with the fields that are saved but hashed before (e.g. password).
30
37
  for (const f of this.inputFieldsSensitive()) {
31
38
  f.clear();
32
39
  }
@@ -53,6 +60,7 @@ export class UC {
53
60
  }
54
61
  return field;
55
62
  }
63
+ // biome-ignore lint/suspicious/noExplicitAny: can be anything
56
64
  inputFieldsForForm() {
57
65
  const ordered = this.inputFieldsOrdered().filter((f) => ucifMustBeFilledManually(f.def));
58
66
  const dependencies = this.def.io.i?.dependencies;
@@ -69,6 +77,7 @@ export class UC {
69
77
  return blankDepsValues.length === 0;
70
78
  });
71
79
  }
80
+ // biome-ignore lint/suspicious/noExplicitAny: can be anything
72
81
  inputFieldsOrdered() {
73
82
  const order = this.def.io.i?.order;
74
83
  if (!order) {
@@ -86,9 +95,11 @@ export class UC {
86
95
  return 0;
87
96
  });
88
97
  }
98
+ // biome-ignore lint/suspicious/noExplicitAny: can be anything
89
99
  inputFieldsInsensitive() {
90
100
  return this.inputFields.filter((f) => !ucifIsSensitive(f.def));
91
101
  }
102
+ // biome-ignore lint/suspicious/noExplicitAny: can be anything
92
103
  inputFieldsSensitive() {
93
104
  return this.inputFields.filter((f) => ucifIsSensitive(f.def));
94
105
  }
@@ -97,6 +108,7 @@ export class UC {
97
108
  if (fields.length === 0) {
98
109
  return false;
99
110
  }
111
+ // TODO : Avoid this workaround when we figure out how to let the user change these values in terms of UI
100
112
  const isListInput = Object.keys(ListInputDef.fields)
101
113
  .sort((a, b) => a.localeCompare(b))
102
114
  .join('') ===
@@ -126,13 +138,18 @@ export class UC {
126
138
  rValArr(key) {
127
139
  return this.inputField(key).rValArr();
128
140
  }
141
+ // biome-ignore lint/suspicious/noExplicitAny: can be anything
129
142
  validate() {
143
+ // This implementation returns an error as soon as one is met.
144
+ // This can be discussed later as we can also return an array of errors all at once.
145
+ // Unary fields
130
146
  for (const f of this.inputFields) {
131
147
  const validation = f.validate();
132
148
  if (!validation.isOK()) {
133
149
  return [f, validation];
134
150
  }
135
151
  }
152
+ // Fields combinations
136
153
  const combinedValidation = this.def.io.i?.validation;
137
154
  if (!combinedValidation) {
138
155
  return null;
@@ -148,6 +165,7 @@ export class UC {
148
165
  const validation = new Validation();
149
166
  validation.add({
150
167
  constraint: 'fieldsOr',
168
+ // TODO : Display the translated labels and not the keys
151
169
  expected: or.join(', '),
152
170
  });
153
171
  return [null, validation];
@@ -5,14 +5,42 @@ import { rVal0, rValArr, type reqVal0 } from './utils/rVal.js';
5
5
  export declare class UCInputField<T extends DataType> {
6
6
  key: UCFieldKey;
7
7
  def: UCInputFieldDef<T>;
8
+ /**
9
+ * In some cases, the wording needs to be adapted in function of the context and not be statically fetched from {@link I18nManager}.
10
+ *
11
+ * For instance, when the user does X, then the description becomes Y.
12
+ */
8
13
  private dynamicWording;
9
14
  private value;
10
15
  constructor(key: UCFieldKey, def: UCInputFieldDef<T>);
11
16
  clear(): void;
12
17
  getDynamicWording(): Partial<UCWording> | undefined;
13
18
  getValue(): UCInputFieldValue<T>;
19
+ /**
20
+ * Read the value as a primitive
21
+ *
22
+ * Unlike the standalone {@link rVal0}, it returns the default value if present.
23
+ *
24
+ * @returns
25
+ */
14
26
  rVal0(): ReturnType<typeof rVal0<T>>;
27
+ /**
28
+ * Require the value as a primitive
29
+ *
30
+ * Unlink the standalone {@link reqVal0}, it returns the default value if present.
31
+ *
32
+ * Otherwise, it throws an error.
33
+ *
34
+ * @returns
35
+ */
15
36
  reqVal0(): ReturnType<typeof reqVal0<T>>;
37
+ /**
38
+ * Require the value as an array
39
+ *
40
+ * Unlink the standalone {@link rValArr}, it returns the default value in an array if present.
41
+ *
42
+ * @returns
43
+ */
16
44
  rValArr(): ReturnType<typeof rValArr<T>>;
17
45
  setValue(op: UCInputFieldChangeOperator, value: UCInputFieldValue<T>): void;
18
46
  updateDef(def: UCInputFieldDef<T>): void;
@@ -6,6 +6,11 @@ import { ucifcoIsForArray } from './utils/ucifcoIsForArray.js';
6
6
  export class UCInputField {
7
7
  key;
8
8
  def;
9
+ /**
10
+ * In some cases, the wording needs to be adapted in function of the context and not be statically fetched from {@link I18nManager}.
11
+ *
12
+ * For instance, when the user does X, then the description becomes Y.
13
+ */
9
14
  dynamicWording;
10
15
  value;
11
16
  constructor(key, def) {
@@ -29,6 +34,13 @@ export class UCInputField {
29
34
  getValue() {
30
35
  return this.value;
31
36
  }
37
+ /**
38
+ * Read the value as a primitive
39
+ *
40
+ * Unlike the standalone {@link rVal0}, it returns the default value if present.
41
+ *
42
+ * @returns
43
+ */
32
44
  rVal0() {
33
45
  const val = rVal0(this.value);
34
46
  if (!isBlank(val)) {
@@ -40,9 +52,19 @@ export class UCInputField {
40
52
  }
41
53
  return null;
42
54
  }
55
+ /**
56
+ * Require the value as a primitive
57
+ *
58
+ * Unlink the standalone {@link reqVal0}, it returns the default value if present.
59
+ *
60
+ * Otherwise, it throws an error.
61
+ *
62
+ * @returns
63
+ */
43
64
  reqVal0() {
44
65
  if (!isBlank(this.value)) {
45
66
  if (Array.isArray(this.value)) {
67
+ // Throwing an Error and not a IllegalArgumentError because this is usually the developer's fault.
46
68
  throw new Error('The value is an array. Use rValArr instead.');
47
69
  }
48
70
  return this.value;
@@ -51,19 +73,31 @@ export class UCInputField {
51
73
  if (defaultValue !== undefined) {
52
74
  return defaultValue;
53
75
  }
76
+ // Throwing an Error and not an IllegalArgumentError because this is usually the developer's fault.
54
77
  throw new Error(`${this.key.toString()} is not set and has no default value. Do not require it.`);
55
78
  }
79
+ /**
80
+ * Require the value as an array
81
+ *
82
+ * Unlink the standalone {@link rValArr}, it returns the default value in an array if present.
83
+ *
84
+ * @returns
85
+ */
56
86
  rValArr() {
57
87
  if (!isBlank(this.value)) {
58
88
  if (!Array.isArray(this.value)) {
89
+ // Throwing an Error and not a IllegalArgumentError because this is usually the developer's fault.
59
90
  throw new Error('The value is a primitive. Use reqVal0 instead.');
60
91
  }
61
92
  return this.value;
62
93
  }
63
94
  const defaultValue = this.def.type.getDefaultValue();
64
95
  if (defaultValue !== undefined) {
96
+ // We might need to allow multiple default values to handle all the cases.
65
97
  return [defaultValue];
66
98
  }
99
+ // Unlike in reqVal0, we return a default empty array anyways to make it usable.
100
+ // Otherwise, we could not get the value of an optional repeatable field (see remark above on the defaultValue).
67
101
  return [];
68
102
  }
69
103
  setValue(op, value) {
@@ -78,6 +112,7 @@ export class UCInputField {
78
112
  return;
79
113
  }
80
114
  if (!ucifcoIsForArray(op)) {
115
+ // Using a switch, even for just one case, to have it trigger an error if we miss to handle an enum value
81
116
  switch (op) {
82
117
  case UCInputFieldChangeOperator.SET:
83
118
  this.value = val;
@@ -89,6 +124,7 @@ export class UCInputField {
89
124
  }
90
125
  const current = Array.isArray(this.value) ? this.value : [];
91
126
  switch (op) {
127
+ // We are not really forced to use immutability here, but it's better for consistency
92
128
  case UCInputFieldChangeOperator.ADD:
93
129
  this.value = current.concat([val]);
94
130
  break;
@@ -110,6 +146,10 @@ export class UCInputField {
110
146
  }
111
147
  validateMandatoriness() {
112
148
  const validation = new Validation();
149
+ // We use `noContext: true` here to validate even the fields that should be set AUTO_PRE
150
+ // Even though it's an indicator that the developer made a mistake,
151
+ // we shouldn't send the error "X is not set and has no default value. Do not require it."
152
+ // to the user
113
153
  const needsValidation = ucifMustBeFilledManually(this.def, { noContext: true }) &&
114
154
  ucifIsMandatory(this.def) &&
115
155
  isBlank(this.value);
@@ -123,6 +163,8 @@ export class UCInputField {
123
163
  return validation;
124
164
  }
125
165
  validate() {
166
+ // Unlike UC.validate, this method returns all the errors at once.
167
+ // This can be discussed later to see if we want to harmonize.
126
168
  const validation = this.validateMandatoriness();
127
169
  if (this.value !== undefined && this.value !== null) {
128
170
  const [isRepeatable] = ucifRepeatability(this.def);
@@ -1,2 +1,5 @@
1
+ /**
2
+ * Base interface all the use case data interfaces must extend
3
+ */
1
4
  export interface UCData {
2
5
  }
@@ -21,6 +21,13 @@ export interface UCDef<I extends UCInput | undefined = undefined, OPI0 extends U
21
21
  };
22
22
  lifecycle: {
23
23
  client?: UCClientDef<I, OPI0, OPI1>;
24
+ /**
25
+ * When bundling for clients, your bundler needs to strip the server definition to avoid bundling server side code for the client.
26
+ *
27
+ * For example with Webpack, you need to implement a custom loader.
28
+ *
29
+ * @see strip-ucd-lifecycle-server
30
+ */
24
31
  server?: UCServerDef<I, OPI0, OPI1> | true;
25
32
  };
26
33
  metadata: UCMetadata;
@@ -1,7 +1,46 @@
1
+ /**
2
+ * Mode of execution of a use case
3
+ *
4
+ * Unlike all the other enums, the values are lowercased for compatibility reasons.
5
+ * Indeed, this value is persisted in the database so we need to support all existing deployments.
6
+ */
1
7
  export declare enum UCExecMode {
8
+ /**
9
+ * The use case has been executed programmatically
10
+ */
2
11
  AUTO = "auto",
12
+ /**
13
+ * The use case has been executed explicitly by a user
14
+ */
3
15
  USER = "user"
4
16
  }
17
+ /**
18
+ * State of execution of a use case
19
+ *
20
+ * - `changing` : An action triggered a change, fields should be disabled
21
+ * - `idle` : It can be touched and filled by the user
22
+ * - `initializing` : It's initializing in some way, fields should be disabled
23
+ * - `submitting` : It's submitting, fields should be disabled and some indicator should show the processing
24
+ *
25
+ * It applies to a form, but it can be applied and generalized to any other interaction mechanism (i.e. cli, voice...).
26
+ */
5
27
  export type UCExecState = 'changing' | 'idle' | 'initializing' | 'submitting';
28
+ /**
29
+ * Check whether the execution corresponds to a "disabled" state
30
+ *
31
+ * Typically, this is used in a form to derive the `disabled` attribute.
32
+ *
33
+ * @param execState
34
+ * @returns
35
+ */
6
36
  export declare function ucIsDisabled(execState: UCExecState): boolean;
37
+ /**
38
+ * Check whether the execution corresponds to a "loading" state
39
+ *
40
+ * Typically, this is used to show a `loading` indicator. Thus, it's `true` when `execState === 'submitting'`.
41
+ * Note that it's not for `changing` or `initializing` because these are not triggered by the user per sé.
42
+ *
43
+ * @param execState
44
+ * @returns
45
+ */
7
46
  export declare function ucIsLoading(execState: UCExecState): boolean;
@@ -1,11 +1,40 @@
1
+ /**
2
+ * Mode of execution of a use case
3
+ *
4
+ * Unlike all the other enums, the values are lowercased for compatibility reasons.
5
+ * Indeed, this value is persisted in the database so we need to support all existing deployments.
6
+ */
1
7
  export var UCExecMode;
2
8
  (function (UCExecMode) {
9
+ /**
10
+ * The use case has been executed programmatically
11
+ */
3
12
  UCExecMode["AUTO"] = "auto";
13
+ /**
14
+ * The use case has been executed explicitly by a user
15
+ */
4
16
  UCExecMode["USER"] = "user";
5
17
  })(UCExecMode || (UCExecMode = {}));
18
+ /**
19
+ * Check whether the execution corresponds to a "disabled" state
20
+ *
21
+ * Typically, this is used in a form to derive the `disabled` attribute.
22
+ *
23
+ * @param execState
24
+ * @returns
25
+ */
6
26
  export function ucIsDisabled(execState) {
7
27
  return execState !== 'idle';
8
28
  }
29
+ /**
30
+ * Check whether the execution corresponds to a "loading" state
31
+ *
32
+ * Typically, this is used to show a `loading` indicator. Thus, it's `true` when `execState === 'submitting'`.
33
+ * Note that it's not for `changing` or `initializing` because these are not triggered by the user per sé.
34
+ *
35
+ * @param execState
36
+ * @returns
37
+ */
9
38
  export function ucIsLoading(execState) {
10
39
  return execState === 'submitting';
11
40
  }
@@ -5,12 +5,41 @@ import type { UCMountingPoint } from './utils/ucMountingPoint.js';
5
5
  export type UCHTTPMountingPoint = `/${URLPath}`;
6
6
  export interface UCExt<OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> {
7
7
  cmd?: {
8
+ /**
9
+ * The command on which the use case is mounted at
10
+ *
11
+ * By default, it's mounted at `${fqucn}`.
12
+ */
8
13
  mountAt?: UCMountingPoint;
9
14
  };
10
15
  http?: {
16
+ /**
17
+ * The verb on which the use case is mounted at
18
+ *
19
+ * By default, it's computed from the {@link UCMetadata.action} with some specific heuristics.
20
+ *
21
+ * For instance, you can set `POST` even for a `List` use case, which usually defaults to `GET`.
22
+ * This can be useful in case you want the input to "travel" through the body of the request, and not the query params.
23
+ */
11
24
  method?: HTTPMethod;
25
+ /**
26
+ * The path on which the use case should mounted at
27
+ *
28
+ * By default, it's mounted at `/api/v1/${fqucn}`.
29
+ */
12
30
  mountAt?: UCHTTPMountingPoint;
31
+ /**
32
+ * The path on which the use case should also mounted at
33
+ *
34
+ * This is typically used when the mounting point is changed and you want to maintain a "legacy" endpoint for clients having
35
+ * a different release cycle than the server (e.g. a mobile app), who are still calling the old endpoint.
36
+ */
13
37
  mountAlsoAt?: UCHTTPMountingPoint[];
14
- transform?: <T extends object>(output: UCOutput<OPI0, OPI1>) => T;
38
+ /**
39
+ * Transform the output received to fit with some specific cases where the endpoint is expected to respect a certain contract
40
+ * @param output
41
+ * @returns
42
+ */
43
+ transform?: (output: UCOutput<OPI0, OPI1>) => object;
15
44
  };
16
45
  }
@@ -19,13 +19,17 @@ export class UCOutputBuilder {
19
19
  }
20
20
  addAll1(items) {
21
21
  this.init1IfNecessary();
22
+ // biome-ignore lint/style/noNonNullAssertion: set in the call above
22
23
  this.output.parts._1.items.push(...items);
24
+ // biome-ignore lint/style/noNonNullAssertion: set in the call above
23
25
  this.output.parts._1.total += items.length;
24
26
  return this;
25
27
  }
26
28
  add1(item) {
27
29
  this.init1IfNecessary();
30
+ // biome-ignore lint/style/noNonNullAssertion: set in the call above
28
31
  this.output.parts._1.items.push(item);
32
+ // biome-ignore lint/style/noNonNullAssertion: set in the call above
29
33
  this.output.parts._1.total += 1;
30
34
  return this;
31
35
  }
@@ -34,6 +38,7 @@ export class UCOutputBuilder {
34
38
  }
35
39
  count1() {
36
40
  this.init1IfNecessary();
41
+ // biome-ignore lint/style/noNonNullAssertion: set in the call above
37
42
  return this.output.parts._1.total;
38
43
  }
39
44
  has(predicate) {
@@ -75,7 +75,9 @@ export class UCOutputReader {
75
75
  total = part.total;
76
76
  }
77
77
  return {
78
- fields: allFieldsKeys.map((fieldKey) => new UCOutputField(fieldKey, allFields[fieldKey])),
78
+ fields: allFieldsKeys.map((fieldKey) =>
79
+ // biome-ignore lint/suspicious/noExplicitAny: can be anything
80
+ new UCOutputField(fieldKey, allFields[fieldKey])),
79
81
  idx,
80
82
  items,
81
83
  key,
@@ -40,6 +40,7 @@ let HTTPUCTransporter = class HTTPUCTransporter {
40
40
  const publicApiKeyCheckType = sec?.publicApiKeyCheckType ?? DEFAULT_UC_SEC_PAKCT;
41
41
  switch (publicApiKeyCheckType) {
42
42
  case 'off':
43
+ // Nothing to do
43
44
  break;
44
45
  case 'on': {
45
46
  const publicApiKey = await this.serverClientManager.publicApiKey();
@@ -102,6 +103,9 @@ let HTTPUCTransporter = class HTTPUCTransporter {
102
103
  },
103
104
  urlBuilder: async () => `${baseURL}${path}`,
104
105
  });
106
+ // In case of 204, we get an empty object.
107
+ // Even though it makes deserializing easier, this is not considered a valid output.
108
+ // So we handle the case here.
105
109
  if (!res || Object.keys(res).length === 0) {
106
110
  return;
107
111
  }