libmodulor 0.4.0 → 0.6.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.
- package/.github/dependabot.yml +19 -0
- package/CHANGELOG.md +35 -1
- package/README.md +10 -4
- package/dist/esm/app/workers/AppSrcFilePathBuilder.d.ts +16 -0
- package/dist/esm/app/workers/AppSrcFilePathBuilder.js +6 -4
- package/dist/esm/apps/Helper/index.js +1 -0
- package/dist/esm/apps/Helper/src/i18n.js +4 -0
- package/dist/esm/apps/Helper/src/lib/project.d.ts +2 -0
- package/dist/esm/apps/Helper/src/lib/project.js +120 -0
- package/dist/esm/apps/Helper/src/manifest.d.ts +5 -0
- package/dist/esm/apps/Helper/src/manifest.js +5 -0
- package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.d.ts +15 -0
- package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.js +118 -0
- package/dist/esm/apps/Helper/src/ucds/GenerateAppsTestsUCD.js +3 -2
- package/dist/esm/bundlers/vite/StripUCDLifecycleServerPlugin.js +3 -0
- package/dist/esm/convention.d.ts +1 -0
- package/dist/esm/convention.js +17 -4
- package/dist/esm/dt/Validation.d.ts +8 -0
- package/dist/esm/dt/Validation.js +8 -0
- package/dist/esm/dt/base/TBase.d.ts +2 -1
- package/dist/esm/dt/base/TBoolean.js +2 -0
- package/dist/esm/dt/base/TInt.js +3 -0
- package/dist/esm/dt/base/TNumber.js +2 -0
- package/dist/esm/dt/base/TObject.d.ts +15 -0
- package/dist/esm/dt/base/TObject.js +14 -0
- package/dist/esm/dt/base/TString.js +1 -1
- package/dist/esm/dt/final/TAmount.js +1 -0
- package/dist/esm/dt/final/TCountryISO3166Alpha2.js +1 -0
- package/dist/esm/dt/final/TCurrencyISO4217.js +1 -0
- package/dist/esm/dt/final/TDateTimeFormat.js +1 -0
- package/dist/esm/dt/final/TEmail.js +2 -0
- package/dist/esm/dt/final/TEmoji.js +4 -0
- package/dist/esm/dt/final/TFile.js +3 -0
- package/dist/esm/dt/final/THostAddress.js +2 -0
- package/dist/esm/dt/final/TIPv6.js +1 -0
- package/dist/esm/dt/final/TJWT.js +8 -0
- package/dist/esm/dt/final/TPercentage.js +5 -0
- package/dist/esm/dt/final/TSQLQuery.js +1 -0
- package/dist/esm/dt/final/TSSHPrivateKey.js +3 -1
- package/dist/esm/dt/final/TSemVerVersion.js +1 -0
- package/dist/esm/dt/final/TShellCommand.js +1 -0
- package/dist/esm/dt/final/TURL.js +2 -0
- package/dist/esm/dt/final/TUUID.js +1 -0
- package/dist/esm/dt/final/TYesNo.js +1 -1
- package/dist/esm/dt/index.d.ts +1 -1
- package/dist/esm/i18n/WordingManager.d.ts +16 -0
- package/dist/esm/i18n/types.d.ts +5 -0
- package/dist/esm/icon/Icon.d.ts +7 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.node.d.ts +1 -0
- package/dist/esm/index.node.js +1 -0
- package/dist/esm/index.react.d.ts +1 -1
- package/dist/esm/product/manifest.d.ts +15 -0
- package/dist/esm/products/Helper/container.js +4 -0
- package/dist/esm/products/Helper/index.js +5 -0
- package/dist/esm/products/Helper/manifest.d.ts +6 -1
- package/dist/esm/std/BufferManager.d.ts +18 -0
- package/dist/esm/std/ClockManager.d.ts +5 -0
- package/dist/esm/std/EnvironmentManager.d.ts +10 -0
- package/dist/esm/std/HTTPAPICaller.d.ts +6 -0
- package/dist/esm/std/I18nManager.d.ts +26 -0
- package/dist/esm/std/JWTManager.d.ts +26 -0
- package/dist/esm/std/JobManager.d.ts +6 -0
- package/dist/esm/std/LLMManager.d.ts +25 -0
- package/dist/esm/std/LLMManager.js +1 -0
- package/dist/esm/std/PromptManager.d.ts +8 -0
- package/dist/esm/std/SettingsManager.d.ts +19 -0
- package/dist/esm/std/SettingsManager.js +9 -0
- package/dist/esm/std/ShellCommandExecutor.d.ts +19 -0
- package/dist/esm/std/ShellCommandExecutor.js +1 -0
- package/dist/esm/std/impl/ConsoleLogger.js +7 -1
- package/dist/esm/std/impl/FakeEmailManager.js +1 -0
- package/dist/esm/std/impl/FakeJobManager.js +1 -0
- package/dist/esm/std/impl/FetchHTTPAPICallExecutor.d.ts +9 -0
- package/dist/esm/std/impl/FetchHTTPAPICallExecutor.js +11 -0
- package/dist/esm/std/impl/MistralAILLMManager.d.ts +17 -0
- package/dist/esm/std/impl/MistralAILLMManager.js +56 -0
- package/dist/esm/std/impl/NodeCryptoManager.js +6 -1
- package/dist/esm/std/impl/NodeDeterministicCryptoManager.d.ts +14 -0
- package/dist/esm/std/impl/NodeDeterministicCryptoManager.js +17 -3
- package/dist/esm/std/impl/NodeFSManager.js +10 -0
- package/dist/esm/std/impl/NodeHTTPAPICallExecutorAgentBuilder.js +2 -0
- package/dist/esm/std/impl/NodePromptManager.js +3 -0
- package/dist/esm/std/impl/NodeSpawnShellCommandExecutor.d.ts +4 -0
- package/dist/esm/std/impl/NodeSpawnShellCommandExecutor.js +41 -0
- package/dist/esm/std/impl/OllamaLLMManager.d.ts +20 -0
- package/dist/esm/std/impl/OllamaLLMManager.js +56 -0
- package/dist/esm/std/impl/OpenAILLMManager.d.ts +17 -0
- package/dist/esm/std/impl/OpenAILLMManager.js +51 -0
- package/dist/esm/std/impl/SimpleHTTPAPICaller.js +14 -0
- package/dist/esm/std/impl/SimpleMapI18nManager.js +4 -2
- package/dist/esm/std/impl/StdDateClockManager.js +3 -0
- package/dist/esm/std/impl/UCDataStoreExternalResourceManager.js +3 -0
- package/dist/esm/std/impl/WebCryptoManager.js +9 -0
- package/dist/esm/std/index.d.ts +2 -0
- package/dist/esm/std/index.js +2 -0
- package/dist/esm/target/lib/cli/renderer.js +3 -0
- package/dist/esm/target/lib/client/consts.d.ts +3 -0
- package/dist/esm/target/lib/client/consts.js +3 -0
- package/dist/esm/target/lib/mcp-server/MCPServerBooter.js +1 -0
- package/dist/esm/target/lib/react/UCContainer.js +1 -0
- package/dist/esm/target/lib/react/UCPanel.js +4 -0
- package/dist/esm/target/lib/react/form.d.ts +26 -2
- package/dist/esm/target/lib/react/form.js +18 -1
- package/dist/esm/target/lib/react/useUC.d.ts +8 -0
- package/dist/esm/target/lib/react/useUC.js +22 -0
- package/dist/esm/target/lib/react/useUCOR.d.ts +15 -0
- package/dist/esm/target/lib/react/useUCOR.js +45 -0
- package/dist/esm/target/lib/rn/input.d.ts +7 -0
- package/dist/esm/target/lib/rn/input.js +2 -0
- package/dist/esm/target/lib/server/AuthenticationChecker.js +2 -1
- package/dist/esm/target/lib/server/BasicAuthenticationChecker.js +1 -0
- package/dist/esm/target/lib/server/CSPDirectivesBuilder.js +13 -0
- package/dist/esm/target/lib/server/CustomerFacingErrorBuilder.js +3 -0
- package/dist/esm/target/lib/server/PrivateApiKeyAuthenticationChecker.js +1 -0
- package/dist/esm/target/lib/server/PublicApiKeyChecker.js +1 -1
- package/dist/esm/target/lib/server/RequestChecker.js +5 -4
- package/dist/esm/target/lib/server/RequestHandler.d.ts +5 -0
- package/dist/esm/target/lib/server/RequestLogger.js +5 -0
- package/dist/esm/target/lib/server/ServerManager.d.ts +19 -0
- package/dist/esm/target/lib/server/consts.d.ts +3 -0
- package/dist/esm/target/lib/server/consts.js +3 -0
- package/dist/esm/target/lib/web/input.d.ts +21 -0
- package/dist/esm/target/lib/web/input.js +4 -0
- package/dist/esm/target/node-core-cli/NodeCoreCLIManager.js +2 -2
- package/dist/esm/target/node-express-server/NodeExpressServerManager.js +5 -0
- package/dist/esm/target/node-express-server/lib/AuthCookieCreator.js +1 -1
- package/dist/esm/target/node-express-server/middlewares/AuthenticationCheckerMiddlewareBuilder.js +1 -0
- package/dist/esm/target/node-express-server/middlewares/PublicApiKeyCheckerMiddlewareBuilder.js +1 -0
- package/dist/esm/target/node-express-server/middlewares/RequestCheckerMiddlewareBuilder.js +1 -0
- package/dist/esm/target/node-express-server/middlewares/RequestHandlerMiddlewareBuilder.js +8 -0
- package/dist/esm/target/node-express-server/middlewares/RequestLoggerMiddlewareBuilder.js +1 -0
- package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.d.ts +10 -0
- package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.js +14 -0
- package/dist/esm/target/react-native-pure/UCForm.js +2 -2
- package/dist/esm/target/react-native-pure/UCFormField.d.ts +2 -9
- package/dist/esm/target/react-native-pure/UCFormField.js +9 -20
- package/dist/esm/target/react-native-pure/UCFormFieldControl.d.ts +3 -10
- package/dist/esm/target/react-native-pure/UCFormFieldControl.js +9 -8
- package/dist/esm/target/react-native-pure/UCFormFieldDesc.d.ts +2 -5
- package/dist/esm/target/react-native-pure/UCFormFieldDesc.js +2 -2
- package/dist/esm/target/react-native-pure/UCFormFieldErr.d.ts +2 -6
- package/dist/esm/target/react-native-pure/UCFormFieldLabel.d.ts +2 -5
- package/dist/esm/target/react-native-pure/UCFormFieldLabel.js +2 -2
- package/dist/esm/target/react-native-pure/UCFormSubmitControl.d.ts +2 -7
- package/dist/esm/target/react-native-pure/UCFormSubmitControl.js +1 -1
- package/dist/esm/target/react-web-pure/UCForm.js +1 -1
- package/dist/esm/target/react-web-pure/UCFormField.d.ts +2 -9
- package/dist/esm/target/react-web-pure/UCFormField.js +9 -20
- package/dist/esm/target/react-web-pure/UCFormFieldControl.d.ts +3 -10
- package/dist/esm/target/react-web-pure/UCFormFieldControl.js +20 -5
- package/dist/esm/target/react-web-pure/UCFormFieldDesc.d.ts +2 -5
- package/dist/esm/target/react-web-pure/UCFormFieldDesc.js +2 -2
- package/dist/esm/target/react-web-pure/UCFormFieldErr.d.ts +2 -6
- package/dist/esm/target/react-web-pure/UCFormFieldLabel.d.ts +2 -5
- package/dist/esm/target/react-web-pure/UCFormFieldLabel.js +3 -3
- package/dist/esm/target/react-web-pure/UCFormSubmitControl.d.ts +2 -4
- package/dist/esm/target/react-web-pure/UCFormSubmitControl.js +1 -1
- package/dist/esm/testing/AppTester.d.ts +4 -0
- package/dist/esm/testing/AppTester.js +16 -0
- package/dist/esm/testing/AppTesterConfigurator.d.ts +68 -0
- package/dist/esm/testing/UCDataStoreTester.d.ts +9 -0
- package/dist/esm/testing/UCDataStoreTester.js +13 -0
- package/dist/esm/testing/impl/SimpleAppDocsEmitter.js +22 -2
- package/dist/esm/testing/impl/SimpleAppTesterConfigurator.js +1 -0
- package/dist/esm/testing/impl/SimpleHTMLAppTestReportEmitter.js +9 -3
- package/dist/esm/testing/impl/TypeScriptLibUCDefASTParser.js +12 -4
- package/dist/esm/testing/impl/VitestAppTestSuiteEmitter.js +6 -0
- package/dist/esm/testing/opts.d.ts +38 -0
- package/dist/esm/testing/opts.js +1 -1
- package/dist/esm/testing/uc-input.js +2 -0
- package/dist/esm/testing/workers/AppTesterCtxInitializer.js +7 -0
- package/dist/esm/testing/workers/UCExecutor.js +1 -0
- package/dist/esm/testing/workers/checkers/AppIndexChecker.js +1 -0
- package/dist/esm/testing/workers/checkers/UCDefSourcesChecker.js +4 -0
- package/dist/esm/uc/UC.js +19 -1
- package/dist/esm/uc/UCInputField.d.ts +28 -0
- package/dist/esm/uc/UCInputField.js +42 -0
- package/dist/esm/uc/data.d.ts +3 -0
- package/dist/esm/uc/def.d.ts +7 -0
- package/dist/esm/uc/exec.d.ts +39 -0
- package/dist/esm/uc/exec.js +29 -0
- package/dist/esm/uc/ext.d.ts +30 -1
- package/dist/esm/uc/helpers/UCOutputBuilder.js +5 -0
- package/dist/esm/uc/helpers/UCOutputReader.js +3 -1
- package/dist/esm/uc/impl/HTTPUCTransporter.js +4 -0
- package/dist/esm/uc/impl/InMemoryUCDataStore.js +7 -0
- package/dist/esm/uc/impl/KnexUCDataStore.d.ts +4 -0
- package/dist/esm/uc/impl/KnexUCDataStore.js +14 -0
- package/dist/esm/uc/impl/SimpleUCManager.js +6 -0
- package/dist/esm/uc/input-field.d.ts +60 -0
- package/dist/esm/uc/input-field.js +33 -0
- package/dist/esm/uc/input.d.ts +24 -0
- package/dist/esm/uc/lifecycle/client/IdleClientMain.js +1 -0
- package/dist/esm/uc/lifecycle/server/IdleServerMain.js +2 -0
- package/dist/esm/uc/manager.d.ts +11 -0
- package/dist/esm/uc/metadata.d.ts +10 -0
- package/dist/esm/uc/opi-layout.d.ts +3 -0
- package/dist/esm/uc/opi.d.ts +8 -0
- package/dist/esm/uc/output-field.d.ts +9 -0
- package/dist/esm/uc/output-part.d.ts +22 -0
- package/dist/esm/uc/output.d.ts +3 -0
- package/dist/esm/uc/policies/RoleRegularUCPolicy.js +1 -0
- package/dist/esm/uc/policies/funcs.js +1 -0
- package/dist/esm/uc/policy.d.ts +22 -0
- package/dist/esm/uc/sec.d.ts +9 -0
- package/dist/esm/uc/server.d.ts +10 -0
- package/dist/esm/uc/settings.d.ts +25 -0
- package/dist/esm/uc/side-effect.d.ts +16 -0
- package/dist/esm/uc/side-effect.js +16 -0
- package/dist/esm/uc/utils/rInput.d.ts +12 -0
- package/dist/esm/uc/utils/rInput.js +2 -0
- package/dist/esm/uc/utils/rVal.d.ts +25 -0
- package/dist/esm/uc/utils/rVal.js +27 -0
- package/dist/esm/uc/utils/recIs.d.ts +9 -0
- package/dist/esm/uc/utils/recIs.js +12 -1
- package/dist/esm/uc/utils/stripUCDLifecycleServer.d.ts +13 -0
- package/dist/esm/uc/utils/stripUCDLifecycleServer.js +17 -0
- package/dist/esm/uc/utils/ucifcoIsForArray.d.ts +6 -0
- package/dist/esm/uc/utils/ucifcoIsForArray.js +6 -0
- package/dist/esm/uc/workers/SimpleAggregateFinder.d.ts +12 -0
- package/dist/esm/uc/workers/SimpleAggregateFinder.js +12 -0
- package/dist/esm/uc/workers/UCBuilder.d.ts +7 -0
- package/dist/esm/uc/workers/UCBuilder.js +7 -0
- package/dist/esm/uc/workers/UCExecChecker.js +2 -0
- package/dist/esm/uc/workers/UCInputFilesProcessor.js +10 -4
- package/dist/esm/uc/workers/UCOutputFilesProcessor.js +6 -2
- package/dist/esm/utils/async/sleep.d.ts +10 -0
- package/dist/esm/utils/async/sleep.js +10 -0
- package/dist/esm/utils/http/appendData.js +5 -1
- package/dist/esm/utils/ioc/ContainerPrinter.js +2 -0
- package/dist/esm/utils/ioc/bindCommon.js +4 -0
- package/dist/esm/utils/ioc/bindNodeCLI.js +2 -0
- package/dist/esm/utils/ioc/bindNodeCore.js +1 -0
- package/dist/esm/utils/ioc/bindProduct.js +2 -0
- package/dist/esm/utils/ioc/bindRN.js +1 -0
- package/dist/esm/utils/ioc/bindServer.js +1 -0
- package/dist/esm/utils/ioc/bindWeb.js +2 -0
- package/dist/esm/utils/ioc/container.js +6 -0
- package/dist/esm/utils/numbers/units.js +3 -0
- package/dist/esm/utils/types/funcs.d.ts +35 -0
- package/dist/esm/utils/types/funcs.js +35 -0
- package/dist/esm/utils/types/utility-types.d.ts +17 -0
- package/dist/esm/utils/types/utility-types.js +1 -0
- package/package.json +13 -14
|
@@ -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: {
|
|
@@ -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,
|
|
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);
|
package/dist/esm/uc/data.d.ts
CHANGED
package/dist/esm/uc/def.d.ts
CHANGED
|
@@ -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;
|
package/dist/esm/uc/exec.d.ts
CHANGED
|
@@ -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;
|
package/dist/esm/uc/exec.js
CHANGED
|
@@ -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
|
}
|
package/dist/esm/uc/ext.d.ts
CHANGED
|
@@ -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
|
-
|
|
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) =>
|
|
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
|
}
|
|
@@ -19,6 +19,7 @@ function predicate(key, filter) {
|
|
|
19
19
|
return (r) => r[key] === filter;
|
|
20
20
|
}
|
|
21
21
|
let InMemoryUCDataStore = class InMemoryUCDataStore {
|
|
22
|
+
// biome-ignore lint/suspicious/noExplicitAny: can be anything
|
|
22
23
|
entries;
|
|
23
24
|
tx;
|
|
24
25
|
constructor() {
|
|
@@ -46,10 +47,13 @@ let InMemoryUCDataStore = class InMemoryUCDataStore {
|
|
|
46
47
|
};
|
|
47
48
|
}
|
|
48
49
|
async install() {
|
|
50
|
+
// Nothing to do
|
|
49
51
|
}
|
|
50
52
|
async read(opts) {
|
|
51
53
|
let items = this
|
|
52
54
|
.entries;
|
|
55
|
+
// Filter
|
|
56
|
+
// Of course it handles only simple cases (eq X, is null, in) with the AND operator
|
|
53
57
|
if (opts?.filters) {
|
|
54
58
|
const { aggregateId, appName, name, organizationId, userId } = opts.filters;
|
|
55
59
|
if (aggregateId !== undefined) {
|
|
@@ -68,6 +72,8 @@ let InMemoryUCDataStore = class InMemoryUCDataStore {
|
|
|
68
72
|
items = items.filter(predicate('userId', userId));
|
|
69
73
|
}
|
|
70
74
|
}
|
|
75
|
+
// Sort
|
|
76
|
+
// => No need, we are processing them by order of insertion in the Map
|
|
71
77
|
return {
|
|
72
78
|
records: items,
|
|
73
79
|
};
|
|
@@ -79,6 +85,7 @@ let InMemoryUCDataStore = class InMemoryUCDataStore {
|
|
|
79
85
|
return [];
|
|
80
86
|
}
|
|
81
87
|
async testKey() {
|
|
88
|
+
// Nothing to do
|
|
82
89
|
}
|
|
83
90
|
async write(record) {
|
|
84
91
|
this.writeBulk([record]);
|
|
@@ -5,6 +5,10 @@ import type { UCDataStore, UCDataStoreReadOpts, UCDataStoreReadProjectionOpts, U
|
|
|
5
5
|
import type { UCData } from '../data.js';
|
|
6
6
|
import type { UCInput } from '../input.js';
|
|
7
7
|
import type { UCSettings } from '../settings.js';
|
|
8
|
+
/**
|
|
9
|
+
* @see https://knexjs.org/guide/#configuration-options
|
|
10
|
+
* @see https://knexjs.org/guide/#pool
|
|
11
|
+
*/
|
|
8
12
|
export interface KnexUCDataStoreSettings extends Settings {
|
|
9
13
|
knex_uc_data_store_conn_string: `postgresql://${string}`;
|
|
10
14
|
knex_uc_data_store_file_path: FilePath | ':memory:';
|
|
@@ -58,6 +58,7 @@ let KnexUCDataStore = class KnexUCDataStore {
|
|
|
58
58
|
}
|
|
59
59
|
async read(opts) {
|
|
60
60
|
const query = this.client(this.s().uc_data_store_ucs_dataset_name);
|
|
61
|
+
// Filter
|
|
61
62
|
if (opts?.filters) {
|
|
62
63
|
const { aggregateId, appName, idWithinInput, name, organizationId, userId, } = opts.filters;
|
|
63
64
|
this.filter(query, aggregateId, 'aggregateId');
|
|
@@ -67,10 +68,17 @@ let KnexUCDataStore = class KnexUCDataStore {
|
|
|
67
68
|
this.filter(query, userId, 'userId');
|
|
68
69
|
if (idWithinInput !== undefined) {
|
|
69
70
|
for (const [k, v] of Object.entries(idWithinInput)) {
|
|
71
|
+
// Not comfortable with the key here but it seems to escape correctly :
|
|
72
|
+
// select * from "d2efe54a-ce85-437c-958e-440f54c0743d"
|
|
73
|
+
// where jsonb_path_query_first("input", ?) #>> '{}' = ?
|
|
74
|
+
// and "name" = ?
|
|
75
|
+
// and "organization_id" = ?
|
|
76
|
+
// order by "created_at" asc
|
|
70
77
|
query.whereJsonPath('input', `$.${k}`, '=', v);
|
|
71
78
|
}
|
|
72
79
|
}
|
|
73
80
|
}
|
|
81
|
+
// Sort
|
|
74
82
|
query.orderBy('created_at', 'asc');
|
|
75
83
|
const records = (await query).map((r) => this.mapRowToRecord(r));
|
|
76
84
|
return {
|
|
@@ -79,11 +87,13 @@ let KnexUCDataStore = class KnexUCDataStore {
|
|
|
79
87
|
}
|
|
80
88
|
async readProjection(name, opts) {
|
|
81
89
|
const query = this.client(name);
|
|
90
|
+
// Sort
|
|
82
91
|
if (opts?.orderBy) {
|
|
83
92
|
for (const [k, v] of Object.entries(opts.orderBy)) {
|
|
84
93
|
query.orderBy(k, v);
|
|
85
94
|
}
|
|
86
95
|
}
|
|
96
|
+
// Paginate
|
|
87
97
|
if (opts?.limit) {
|
|
88
98
|
query.limit(opts.limit);
|
|
89
99
|
}
|
|
@@ -201,9 +211,13 @@ let KnexUCDataStore = class KnexUCDataStore {
|
|
|
201
211
|
};
|
|
202
212
|
}
|
|
203
213
|
parseJSONColIfNecessary(value) {
|
|
214
|
+
// In some DBs, the json type is returned as string (e.g. sqlite3)
|
|
204
215
|
return typeof value === 'string' ? JSON.parse(value) : value;
|
|
205
216
|
}
|
|
217
|
+
//#region migrations
|
|
206
218
|
async migration001CreateMainTable() {
|
|
219
|
+
// Using hasTable and then createTable because createTableIfNotExists has been deprecated
|
|
220
|
+
// See https://github.com/knex/knex/issues/1303#issuecomment-594489136
|
|
207
221
|
const exists = await this.client.schema.hasTable(this.s().uc_data_store_ucs_dataset_name);
|
|
208
222
|
if (exists) {
|
|
209
223
|
return;
|
|
@@ -29,6 +29,7 @@ let SimpleUCManager = class SimpleUCManager {
|
|
|
29
29
|
ucInputValidator;
|
|
30
30
|
ucInitProvider;
|
|
31
31
|
ucMainProvider;
|
|
32
|
+
// WARNING : This property makes this class "thread unsafe". Be careful how you inject it into your components.
|
|
32
33
|
tx;
|
|
33
34
|
constructor(ucClientConfirmManager, clockManager, cryptoManager, logger, ucDataStore, ucExecChecker, ucInputFilesProcessor, ucInputValidator, ucInitProvider, ucMainProvider) {
|
|
34
35
|
this.ucClientConfirmManager = ucClientConfirmManager;
|
|
@@ -64,6 +65,7 @@ let SimpleUCManager = class SimpleUCManager {
|
|
|
64
65
|
if (!client) {
|
|
65
66
|
throw new Error(`The use case ${metadata.name} has no client lifecycle`);
|
|
66
67
|
}
|
|
68
|
+
// Always check the right to execute, even if done when displaying the control
|
|
67
69
|
const { allowed } = await this.ucExecChecker.exec({
|
|
68
70
|
lifecycle: 'client',
|
|
69
71
|
uc,
|
|
@@ -72,6 +74,9 @@ let SimpleUCManager = class SimpleUCManager {
|
|
|
72
74
|
throw new ForbiddenError();
|
|
73
75
|
}
|
|
74
76
|
this.ucInputValidator.exec({ uc });
|
|
77
|
+
// Process the file client side only if it is not sent to the server
|
|
78
|
+
// Be careful with some edge cases where the file needs to be uploaded somewhere else.
|
|
79
|
+
// Note that we cannot check server !== true because in some cases, the server is not stripped (e.g. tests, node cli client, etc.).
|
|
75
80
|
if (server === undefined) {
|
|
76
81
|
await this.ucInputFilesProcessor.exec({ uc });
|
|
77
82
|
}
|
|
@@ -85,6 +90,7 @@ let SimpleUCManager = class SimpleUCManager {
|
|
|
85
90
|
if (typeof server !== 'object') {
|
|
86
91
|
throw new Error(`The use case ${metadata.name} has no server lifecycle`);
|
|
87
92
|
}
|
|
93
|
+
// Always check the right to execute, even if done when displaying the control
|
|
88
94
|
const { allowed } = await this.ucExecChecker.exec({
|
|
89
95
|
lifecycle: 'server',
|
|
90
96
|
uc,
|