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.
- package/CHANGELOG.md +29 -1
- package/README.md +7 -182
- 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/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/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.react-native-pure.d.ts +10 -0
- package/dist/esm/index.react-native-pure.js +10 -0
- package/dist/esm/product/manifest.d.ts +15 -0
- package/dist/esm/products/Helper/index.js +3 -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/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/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 +1 -0
- package/dist/esm/std/index.js +1 -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/entrypoint.d.ts +2 -0
- 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 +15 -0
- package/dist/esm/target/lib/rn/input.js +28 -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/UCAutoExecLoader.d.ts +2 -0
- package/dist/esm/target/react-native-pure/UCAutoExecLoader.js +5 -0
- package/dist/esm/target/react-native-pure/UCEntrypointTouchable.d.ts +4 -0
- package/dist/esm/target/react-native-pure/UCEntrypointTouchable.js +6 -0
- package/dist/esm/target/react-native-pure/UCExecTouchable.d.ts +4 -0
- package/dist/esm/target/react-native-pure/UCExecTouchable.js +9 -0
- package/dist/esm/target/react-native-pure/UCForm.d.ts +4 -0
- package/dist/esm/target/react-native-pure/UCForm.js +13 -0
- package/dist/esm/target/react-native-pure/UCFormField.d.ts +11 -0
- package/dist/esm/target/react-native-pure/UCFormField.js +32 -0
- package/dist/esm/target/react-native-pure/UCFormFieldControl.d.ts +11 -0
- package/dist/esm/target/react-native-pure/UCFormFieldControl.js +37 -0
- package/dist/esm/target/react-native-pure/UCFormFieldDesc.d.ts +7 -0
- package/dist/esm/target/react-native-pure/UCFormFieldDesc.js +11 -0
- package/dist/esm/target/react-native-pure/UCFormFieldErr.d.ts +7 -0
- package/dist/esm/target/react-native-pure/UCFormFieldErr.js +5 -0
- package/dist/esm/target/react-native-pure/UCFormFieldLabel.d.ts +7 -0
- package/dist/esm/target/react-native-pure/UCFormFieldLabel.js +8 -0
- package/dist/esm/target/react-native-pure/UCFormSubmitControl.d.ts +9 -0
- package/dist/esm/target/react-native-pure/UCFormSubmitControl.js +8 -0
- package/dist/esm/target/react-web-pure/UCEntrypointTouchable.d.ts +1 -1
- package/dist/esm/target/react-web-pure/UCExecTouchable.d.ts +1 -1
- package/dist/esm/target/react-web-pure/UCExecTouchable.js +1 -1
- package/dist/esm/target/react-web-pure/UCFormFieldControl.d.ts +1 -1
- package/dist/esm/target/react-web-pure/UCFormFieldControl.js +3 -3
- 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 +16 -9
- package/docs/assets/trading-buy-asset-sequence-diagram.png +0 -0
- package/docs/assets/trading-target-mcp-server.png +0 -0
- package/docs/assets/trading-target-web-human.png +0 -0
- package/docs/assets/trading-target-web.png +0 -0
- package/docs/getting-started/001_Create_the_project.md +0 -168
- package/docs/getting-started/002_Create_the_App.md +0 -49
- package/docs/getting-started/003_Create_the_UseCase.md +0 -205
- package/docs/getting-started/004_Test_the_App.md +0 -114
- package/docs/getting-started/005_Create_the_Product.md +0 -46
- package/docs/getting-started/006_Create_the_server_Target.md +0 -130
- package/docs/getting-started/007_Create_the_web_Target.md +0 -262
- package/docs/getting-started/008_Switch_to_a_persistent_data_storage.md +0 -55
- package/docs/getting-started/009_Define_wording_for_humans.md +0 -42
- package/docs/getting-started/010_Create_the_cli_Target.md +0 -102
- package/docs/getting-started/011_Create_the_mcp_server_Target.md +0 -157
- package/docs/getting-started/012_Summary.md +0 -29
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
2
|
import { UC, } from '../../../uc/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* This hook provides utilities to init a use case and perform actions on it in a React way
|
|
5
|
+
* @param appManifest
|
|
6
|
+
* @param def
|
|
7
|
+
* @param auth
|
|
8
|
+
* @param opts
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
3
11
|
export function useUC(appManifest, def, auth, opts) {
|
|
4
12
|
const [uc, setUC] = useState(() => {
|
|
5
13
|
const { name: appName, ucReg } = appManifest;
|
|
@@ -13,8 +21,22 @@ export function useUC(appManifest, def, auth, opts) {
|
|
|
13
21
|
}
|
|
14
22
|
return v;
|
|
15
23
|
});
|
|
24
|
+
/**
|
|
25
|
+
* Get a new `UC` based on the initial one
|
|
26
|
+
* @param i
|
|
27
|
+
* @returns
|
|
28
|
+
*/
|
|
16
29
|
const clone = (i) => new UC(uc.appManifest, uc.def, uc.auth).fill(i);
|
|
30
|
+
/**
|
|
31
|
+
* Get a new `UC` based on the "common" settings of the initial one (i.e. `auth`)
|
|
32
|
+
* @param ucd
|
|
33
|
+
* @returns
|
|
34
|
+
*/
|
|
17
35
|
const divert = (siblingUCD) => new UC(uc.appManifest, siblingUCD, uc.auth);
|
|
36
|
+
/**
|
|
37
|
+
* Update the existing `uc` in an immutable way to trigger components re-rendering
|
|
38
|
+
* @param i
|
|
39
|
+
*/
|
|
18
40
|
const refill = (i) => {
|
|
19
41
|
setUC(new UC(uc.appManifest, uc.def, uc.auth).fill(i));
|
|
20
42
|
};
|
|
@@ -2,6 +2,21 @@ import type { UCInput, UCOPIBase, UCOutputReader, UCOutputReaderPart } from '../
|
|
|
2
2
|
type AppendFunc<OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = (ucor: UCOutputReader<any, OPI0, OPI1>) => void;
|
|
3
3
|
type RemoveFunc<OPI extends UCOPIBase> = (item: OPI) => void;
|
|
4
4
|
type UpdateFunc<OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = (ucor: UCOutputReader<any, OPI0, OPI1>) => void;
|
|
5
|
+
/**
|
|
6
|
+
* This hook provides utilities to act on a {@link UCOutputReader} in a React way
|
|
7
|
+
*
|
|
8
|
+
* A usual scenario of this is a "CRUD-like" UI displaying multiple use cases :
|
|
9
|
+
*
|
|
10
|
+
* - A `List` use case to display a collection of items
|
|
11
|
+
* - A `Create` use case to add an item
|
|
12
|
+
* - A `Delete` use case to remove an item
|
|
13
|
+
* - An `Update` use case to update an item
|
|
14
|
+
*
|
|
15
|
+
* Whenever one of this use case is performed, you can use the `ucor` to act on the main UCOR in an immutable way.
|
|
16
|
+
*
|
|
17
|
+
* @param ucor
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
5
20
|
export declare function useUCOR<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(ucor: UCOutputReader<I, OPI0, OPI1>): [
|
|
6
21
|
UCOutputReaderPart<NonNullable<OPI0>> | undefined,
|
|
7
22
|
UCOutputReaderPart<NonNullable<OPI1>> | undefined,
|
|
@@ -39,10 +39,35 @@ function update(a, b) {
|
|
|
39
39
|
items: newItems,
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* This hook provides utilities to act on a {@link UCOutputReader} in a React way
|
|
44
|
+
*
|
|
45
|
+
* A usual scenario of this is a "CRUD-like" UI displaying multiple use cases :
|
|
46
|
+
*
|
|
47
|
+
* - A `List` use case to display a collection of items
|
|
48
|
+
* - A `Create` use case to add an item
|
|
49
|
+
* - A `Delete` use case to remove an item
|
|
50
|
+
* - An `Update` use case to update an item
|
|
51
|
+
*
|
|
52
|
+
* Whenever one of this use case is performed, you can use the `ucor` to act on the main UCOR in an immutable way.
|
|
53
|
+
*
|
|
54
|
+
* @param ucor
|
|
55
|
+
* @returns
|
|
56
|
+
*/
|
|
42
57
|
export function useUCOR(ucor) {
|
|
43
58
|
const [part0, setPart0] = useState(ucor.part0());
|
|
44
59
|
const [part1, setPart1] = useState(ucor.part1());
|
|
60
|
+
/**
|
|
61
|
+
* Append items to part0
|
|
62
|
+
* @param ucor2
|
|
63
|
+
* @returns
|
|
64
|
+
*/
|
|
45
65
|
const append0 = (ucor2) => setPart0((prev) => append(prev, ucor2.part0()));
|
|
66
|
+
/**
|
|
67
|
+
* Append items to part1 (if applicable)
|
|
68
|
+
* @param ucor2
|
|
69
|
+
* @returns
|
|
70
|
+
*/
|
|
46
71
|
const append1 = (ucor2) => setPart1((prev) => {
|
|
47
72
|
const b = ucor2.part1();
|
|
48
73
|
if (!prev || !b) {
|
|
@@ -50,14 +75,34 @@ export function useUCOR(ucor) {
|
|
|
50
75
|
}
|
|
51
76
|
return append(prev, b);
|
|
52
77
|
});
|
|
78
|
+
/**
|
|
79
|
+
* Remove the item from part0
|
|
80
|
+
* @param item
|
|
81
|
+
* @returns
|
|
82
|
+
*/
|
|
53
83
|
const remove0 = (item) => setPart0((prev) => remove(prev, item));
|
|
84
|
+
/**
|
|
85
|
+
* Remove the item from part1 (if applicable)
|
|
86
|
+
* @param item
|
|
87
|
+
* @returns
|
|
88
|
+
*/
|
|
54
89
|
const remove1 = (item) => setPart1((prev) => {
|
|
55
90
|
if (!prev) {
|
|
56
91
|
return;
|
|
57
92
|
}
|
|
58
93
|
return remove(prev, item);
|
|
59
94
|
});
|
|
95
|
+
/**
|
|
96
|
+
* Update items in part0
|
|
97
|
+
* @param ucor2
|
|
98
|
+
* @returns
|
|
99
|
+
*/
|
|
60
100
|
const update0 = (ucor2) => setPart0((prev) => update(prev, ucor2.part0()));
|
|
101
|
+
/**
|
|
102
|
+
* Update items in part1 (if applicable)
|
|
103
|
+
* @param ucor2
|
|
104
|
+
* @returns
|
|
105
|
+
*/
|
|
61
106
|
const update1 = (ucor2) => setPart1((prev) => {
|
|
62
107
|
const b = ucor2.part1();
|
|
63
108
|
if (!prev || !b) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { TextInputProps } from 'react-native';
|
|
2
|
+
import { type DataType, type ErrorMessage } from '../../../dt/index.js';
|
|
3
|
+
import { type UCExecState, type UCInputField } from '../../../uc/index.js';
|
|
4
|
+
export interface RNInputDef {
|
|
5
|
+
internal?: undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Fields that are part of {@link TextInputProps}
|
|
8
|
+
*
|
|
9
|
+
* These are safe to destructure directly in a `<TextInput />` component.
|
|
10
|
+
*
|
|
11
|
+
* @example `<TextInput {...attrs.spec} />`
|
|
12
|
+
*/
|
|
13
|
+
spec?: TextInputProps;
|
|
14
|
+
}
|
|
15
|
+
export declare function rnInputDef<T extends DataType>(field: UCInputField<T>, execState: UCExecState, _errMsg: ErrorMessage | null): RNInputDef;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { TString, } from '../../../dt/index.js';
|
|
2
|
+
import { ucIsDisabled, ucifHint, ucifId, } from '../../../uc/index.js';
|
|
3
|
+
export function rnInputDef(field, execState, _errMsg) {
|
|
4
|
+
const def = {
|
|
5
|
+
internal: undefined,
|
|
6
|
+
spec: {},
|
|
7
|
+
};
|
|
8
|
+
if (!def.spec) {
|
|
9
|
+
// Just a guard to safely type the rest of the function without using !
|
|
10
|
+
return def;
|
|
11
|
+
}
|
|
12
|
+
const { key, def: fDef } = field;
|
|
13
|
+
const { type: fType } = fDef;
|
|
14
|
+
def.spec.editable = !ucIsDisabled(execState);
|
|
15
|
+
def.spec.id = ucifId(key);
|
|
16
|
+
// Testing the types by usage probability to make the if/else evaluation stop ideally earlier
|
|
17
|
+
if (fType instanceof TString) {
|
|
18
|
+
const constraints = fType.getConstraints();
|
|
19
|
+
if (constraints) {
|
|
20
|
+
def.spec.maxLength = constraints.maxLength;
|
|
21
|
+
}
|
|
22
|
+
def.spec.multiline = fType.isPotentiallyLong();
|
|
23
|
+
}
|
|
24
|
+
def.spec.placeholder = ucifHint(fDef);
|
|
25
|
+
def.spec.inputMode = fType.rnInputMode();
|
|
26
|
+
def.spec.secureTextEntry = fType.isSensitive();
|
|
27
|
+
return def;
|
|
28
|
+
}
|
|
@@ -35,7 +35,7 @@ let AuthenticationChecker = class AuthenticationChecker {
|
|
|
35
35
|
authorizationHeader,
|
|
36
36
|
});
|
|
37
37
|
const output = {
|
|
38
|
-
allowed: false,
|
|
38
|
+
allowed: false, // By default it's not allowed
|
|
39
39
|
auth: null,
|
|
40
40
|
};
|
|
41
41
|
const { lifecycle: { server }, sec, } = uc.def;
|
|
@@ -52,6 +52,7 @@ let AuthenticationChecker = class AuthenticationChecker {
|
|
|
52
52
|
output.allowed = allowed;
|
|
53
53
|
}
|
|
54
54
|
else {
|
|
55
|
+
// Follows the OpenAPI spec : https://swagger.io/docs/specification/authentication
|
|
55
56
|
switch (authType) {
|
|
56
57
|
case 'apiKey':
|
|
57
58
|
if (authorizationHeader &&
|
|
@@ -36,10 +36,23 @@ let CSPDirectivesBuilder = class CSPDirectivesBuilder {
|
|
|
36
36
|
this.logger.info('Default CSP directives', defaultDirectives);
|
|
37
37
|
const directives = { ...defaultDirectives };
|
|
38
38
|
if (!this.environmentManager.isProd()) {
|
|
39
|
+
// In dev mode, we allow ourselves to remove this directive.
|
|
40
|
+
// It is necessary when testing from an external device and accessing the server via 192.168.x.x for example
|
|
41
|
+
// Otherwise the requests are upgraded and it doesn't work since there is no HTTPS in localhost
|
|
42
|
+
// Source : https://stackoverflow.com/questions/66599655/how-to-enable-and-disable-upgradeinsecurerequests-csp-directive-using-helmet-4-4
|
|
39
43
|
this.logger.warn('Disabling upgrade-insecure-requests');
|
|
40
44
|
directives['upgrade-insecure-requests'] = null;
|
|
45
|
+
// In dev mode, NextJS uses eval
|
|
46
|
+
// Enabling it prevents the following error from occurring in the console
|
|
47
|
+
// Uncaught EvalError: call to eval() blocked by CSP NextJS
|
|
48
|
+
// Source : https://github.com/vercel/next.js/discussions/17396
|
|
41
49
|
this.logger.warn('Enabling unsafe-eval');
|
|
42
50
|
directives[CSPDirectivesBuilder_1.SCRIPT_SRC]?.push("'unsafe-eval'");
|
|
51
|
+
// In dev mode, React Dev Tools use inline injection
|
|
52
|
+
// Enabling it prevents the following error from occurring in the console
|
|
53
|
+
// Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”).
|
|
54
|
+
// Download the React DevTools for a better development experience: https://reactjs.org/link/react-devtools
|
|
55
|
+
// Uncaught TypeError: hook.sub is not a function
|
|
43
56
|
this.logger.warn('Enabling unsafe-inline');
|
|
44
57
|
directives[CSPDirectivesBuilder_1.SCRIPT_SRC]?.push("'unsafe-inline'");
|
|
45
58
|
}
|
|
@@ -21,11 +21,14 @@ let CustomerFacingErrorBuilder = class CustomerFacingErrorBuilder {
|
|
|
21
21
|
}
|
|
22
22
|
exec({ error }) {
|
|
23
23
|
if (error instanceof CustomError) {
|
|
24
|
+
// It's already ready to be sent as is
|
|
24
25
|
return {
|
|
25
26
|
error,
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
this.logger.error(error);
|
|
30
|
+
// Create a specific generic error to avoid leaking potentially sensitive error
|
|
31
|
+
// We all know the infamous "Cannot connect to MySQL database"...
|
|
29
32
|
return {
|
|
30
33
|
error: new InternalServerError(this.environmentManager.isProd()
|
|
31
34
|
? undefined
|
|
@@ -27,7 +27,7 @@ let PublicApiKeyChecker = class PublicApiKeyChecker {
|
|
|
27
27
|
}
|
|
28
28
|
async exec({ checkType = DEFAULT_UC_SEC_PAKCT, value, }) {
|
|
29
29
|
this.logger.trace('Checking apiKey', { checkType, value });
|
|
30
|
-
let allowed = false;
|
|
30
|
+
let allowed = false; // By default it's not allowed
|
|
31
31
|
switch (checkType) {
|
|
32
32
|
case 'off':
|
|
33
33
|
allowed = true;
|
|
@@ -27,10 +27,10 @@ let RequestChecker = class RequestChecker {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
exec({ secure, url, xForwardedProtoHeader }) {
|
|
30
|
-
const isSecure = secure;
|
|
31
|
-
const isSecureForwarded = xForwardedProtoHeader === 'https';
|
|
32
|
-
const isNotProd = !this.environmentManager.isProd();
|
|
33
|
-
const isSSLCertificateCheck = !!url.match(/^\/\.well-known\/acme-challenge\/(.*)/);
|
|
30
|
+
const isSecure = secure; // https://localhost:8443
|
|
31
|
+
const isSecureForwarded = xForwardedProtoHeader === 'https'; // https://domain.com => http://localhost:8080
|
|
32
|
+
const isNotProd = !this.environmentManager.isProd(); // http://localhost:8443
|
|
33
|
+
const isSSLCertificateCheck = !!url.match(/^\/\.well-known\/acme-challenge\/(.*)/); // http://localhost:8443/.well-known/acme-challenge/ywml7k8e8qxdjwFf1pN4hIKWJ1Jrc0CvAP3t9PSmnzw
|
|
34
34
|
this.logger.trace('Request checker', {
|
|
35
35
|
isNotProd,
|
|
36
36
|
isSSLCertificateCheck,
|
|
@@ -39,6 +39,7 @@ let RequestChecker = class RequestChecker {
|
|
|
39
39
|
});
|
|
40
40
|
const allowed = isSecure || isSecureForwarded || isNotProd || isSSLCertificateCheck;
|
|
41
41
|
if (!allowed) {
|
|
42
|
+
// Not sure it's the right HTTP status to send in these cases but not a big deal for now
|
|
42
43
|
throw new ForbiddenError();
|
|
43
44
|
}
|
|
44
45
|
}
|
|
@@ -5,5 +5,10 @@ export interface RequestHandlerInputRaw<I extends UCInput | undefined = undefine
|
|
|
5
5
|
appManifest: AppManifest;
|
|
6
6
|
envelope: HTTPDataEnvelope;
|
|
7
7
|
ucd: UCDef<I, OPI0, OPI1>;
|
|
8
|
+
/**
|
|
9
|
+
* It is not injected in the handler constructor because it must be the same as the one used in ServerManager.
|
|
10
|
+
*
|
|
11
|
+
* And in some cases, this latter is specific to a context : for instance in automated tests.
|
|
12
|
+
*/
|
|
8
13
|
ucManager: UCManager;
|
|
9
14
|
}
|
|
@@ -20,6 +20,11 @@ let RequestLogger = class RequestLogger {
|
|
|
20
20
|
}
|
|
21
21
|
exec({ body, method, url }) {
|
|
22
22
|
const prefix = [method, url].join(' ');
|
|
23
|
+
// By security, we don't log the body in production, in case it contains sensitive info (e.g. password when authenticating).
|
|
24
|
+
// That being said, in some cases, it can be handy to investigate issues.
|
|
25
|
+
// Let's think about it and how we can do it properly.
|
|
26
|
+
// One way is to this.logger.trace the body, considering it will never be the default in production since it produces too many logs.
|
|
27
|
+
// TODO : Consider logging request body even in production
|
|
23
28
|
if (this.environmentManager.isProd()) {
|
|
24
29
|
this.logger.debug(prefix);
|
|
25
30
|
return;
|
|
@@ -31,9 +31,28 @@ export interface ServerManagerSettings extends ServerManagerAuthSettings, Settin
|
|
|
31
31
|
}
|
|
32
32
|
export interface ServerManager extends Initializable {
|
|
33
33
|
overrideUCManager(ucManager: UCManager): void;
|
|
34
|
+
/**
|
|
35
|
+
* Mount the use case as an endpoint
|
|
36
|
+
* @param appManifest
|
|
37
|
+
* @param ucd
|
|
38
|
+
* @param contract
|
|
39
|
+
*/
|
|
34
40
|
mount<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(appManifest: AppManifest, ucd: UCDef<I, OPI0, OPI1>, contract: UCHTTPContract): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Mount the static directory at `/`
|
|
43
|
+
* @param dirPath
|
|
44
|
+
*/
|
|
35
45
|
mountStaticDir(dirPath: DirPath): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Start listening on the specific host and port
|
|
48
|
+
*/
|
|
36
49
|
start(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Stop listening
|
|
52
|
+
*/
|
|
37
53
|
stop(): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Warm up with things that must be done after the routes have been defined (e.g. error middleware, etc.)
|
|
56
|
+
*/
|
|
38
57
|
warmUp(): Promise<void>;
|
|
39
58
|
}
|
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
import { type DataType, type ErrorMessage, type HTMLInputType } from '../../../dt/index.js';
|
|
2
2
|
import { type UCExecState, type UCInputField } from '../../../uc/index.js';
|
|
3
3
|
export interface HTMLInputDef {
|
|
4
|
+
/**
|
|
5
|
+
* Internal types that are not part of the W3C spec
|
|
6
|
+
*
|
|
7
|
+
* @see node_modules/@types/react/index.d.ts#InputHTMLAttributes
|
|
8
|
+
*/
|
|
4
9
|
internal?: {
|
|
10
|
+
/**
|
|
11
|
+
* When a fiels is `multiline`, you should probably render a `<textarea />` in place of an `<input />`.
|
|
12
|
+
*/
|
|
5
13
|
multiline?: boolean | undefined;
|
|
6
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Fields that are part of the W3C spec
|
|
17
|
+
*
|
|
18
|
+
* These are safe to destructure directly in an `<input />` component.
|
|
19
|
+
*
|
|
20
|
+
* Note that they come with their camel case form, à la React.
|
|
21
|
+
* The reason is that it's easier to transform this to the original spec (`maxLength` => `maxlength`) vs doing the opposite (`maxlength` > `maxLength`).
|
|
22
|
+
* In the first case, we can simply call `.toLowerCase()` on the keys, while in the second, we'd need a dedicated function that "camel-cases" a string.
|
|
23
|
+
*
|
|
24
|
+
* @example `<input {...attrs.spec} />`
|
|
25
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attributes
|
|
26
|
+
* @see node_modules/@types/react/index.d.ts `InputHTMLAttributes`
|
|
27
|
+
*/
|
|
7
28
|
spec?: {
|
|
8
29
|
'aria-errormessage'?: string | undefined;
|
|
9
30
|
'aria-invalid'?: boolean | undefined;
|
|
@@ -6,6 +6,7 @@ export function htmlInputDef(field, execState, errMsg) {
|
|
|
6
6
|
spec: {},
|
|
7
7
|
};
|
|
8
8
|
if (!def.internal || !def.spec) {
|
|
9
|
+
// Just a guard to safely type the rest of the function without using !
|
|
9
10
|
return def;
|
|
10
11
|
}
|
|
11
12
|
const { key, def: fDef } = field;
|
|
@@ -13,11 +14,14 @@ export function htmlInputDef(field, execState, errMsg) {
|
|
|
13
14
|
def.spec.disabled = ucIsDisabled(execState);
|
|
14
15
|
def.spec.id = ucifId(key);
|
|
15
16
|
def.spec.name = key;
|
|
17
|
+
// Testing the types by usage probability to make the if/else evaluation stop ideally earlier
|
|
16
18
|
if (fType instanceof TString) {
|
|
17
19
|
const constraints = fType.getConstraints();
|
|
18
20
|
if (constraints) {
|
|
19
21
|
def.spec.maxLength = constraints.maxLength;
|
|
20
22
|
def.spec.minLength = constraints.minLength;
|
|
23
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/pattern
|
|
24
|
+
// > No forward slashes should be specified around the pattern text
|
|
21
25
|
def.spec.pattern = constraints.format?.regexp?.source;
|
|
22
26
|
}
|
|
23
27
|
def.internal.multiline = fType.isPotentiallyLong();
|
|
@@ -57,7 +57,7 @@ let NodeCoreCLIManager = class NodeCoreCLIManager {
|
|
|
57
57
|
}
|
|
58
58
|
parseArgsConfig(uc) {
|
|
59
59
|
const config = {
|
|
60
|
-
allowPositionals: true,
|
|
60
|
+
allowPositionals: true, // For the command name
|
|
61
61
|
strict: true,
|
|
62
62
|
};
|
|
63
63
|
if (uc.inputFields.length === 0) {
|
|
@@ -68,7 +68,7 @@ let NodeCoreCLIManager = class NodeCoreCLIManager {
|
|
|
68
68
|
const { def } = f;
|
|
69
69
|
let defaultValue = def.type.getDefaultValue();
|
|
70
70
|
if (typeof defaultValue === 'number') {
|
|
71
|
-
defaultValue = defaultValue.toString();
|
|
71
|
+
defaultValue = defaultValue.toString(); // parseArgs does not accept numbers as default value
|
|
72
72
|
}
|
|
73
73
|
const [isRepeatable, _max] = ucifRepeatability(def);
|
|
74
74
|
const type = def.type instanceof TBoolean ? 'boolean' : 'string';
|
|
@@ -77,6 +77,8 @@ let NodeExpressServerManager = class NodeExpressServerManager {
|
|
|
77
77
|
async init() {
|
|
78
78
|
this.runtime = express();
|
|
79
79
|
this.runtime.use(this.helmetMB.exec({}));
|
|
80
|
+
// TODO : Add FileStorageManager (Local, S3, FSBucket)
|
|
81
|
+
// Right now, the files are only stored locally. We need more flexibility. Maybe we can also install https://imgproxy.net.
|
|
80
82
|
this.runtime.use(fileUpload({
|
|
81
83
|
createParentPath: true,
|
|
82
84
|
debug: this.s().logger_level === 'trace',
|
|
@@ -125,6 +127,8 @@ let NodeExpressServerManager = class NodeExpressServerManager {
|
|
|
125
127
|
if (!this.server?.listening) {
|
|
126
128
|
return;
|
|
127
129
|
}
|
|
130
|
+
// As stated in the docs of `close`, only awaiting `.close` is not enough to make sure all the connections are closed.
|
|
131
|
+
// Hence the wrapping in a promise, where the callback is called when the 'close' event is emitted.
|
|
128
132
|
return new Promise((resolve, reject) => {
|
|
129
133
|
if (!this.server) {
|
|
130
134
|
return resolve();
|
|
@@ -138,6 +142,7 @@ let NodeExpressServerManager = class NodeExpressServerManager {
|
|
|
138
142
|
});
|
|
139
143
|
}
|
|
140
144
|
async warmUp() {
|
|
145
|
+
// Always at the "almost" last position to handle all the errors (from other middlewares and request handlers)
|
|
141
146
|
this.runtime.use(this.errorMB.exec({}));
|
|
142
147
|
}
|
|
143
148
|
async createServer() {
|
|
@@ -35,7 +35,7 @@ let AuthCookieCreator = class AuthCookieCreator {
|
|
|
35
35
|
httpOnly: this.s().server_cookies_http_only,
|
|
36
36
|
sameSite: this.s().server_cookies_same_site,
|
|
37
37
|
secure: this.s().server_cookies_secure,
|
|
38
|
-
signed: false,
|
|
38
|
+
signed: false, // Not signing to keep it simple and btw, the JWT is already signed
|
|
39
39
|
},
|
|
40
40
|
val: jwt,
|
|
41
41
|
};
|
|
@@ -49,6 +49,8 @@ let RequestHandlerMiddlewareBuilder = class RequestHandlerMiddlewareBuilder {
|
|
|
49
49
|
if (ucor.canItem00()) {
|
|
50
50
|
item = ucor.item00().item;
|
|
51
51
|
}
|
|
52
|
+
// Be careful with this, as some are incompatible.
|
|
53
|
+
// For instance, if there is a REDIRECT and then a CLEAR_AUTH, the latter won't be executed as we return after the redirect.
|
|
52
54
|
for (const se of sideEffects) {
|
|
53
55
|
const { type } = se;
|
|
54
56
|
switch (type) {
|
|
@@ -74,6 +76,7 @@ let RequestHandlerMiddlewareBuilder = class RequestHandlerMiddlewareBuilder {
|
|
|
74
76
|
res.send(output && transform ? transform(output) : output);
|
|
75
77
|
}
|
|
76
78
|
catch (err) {
|
|
79
|
+
// Always catch otherwise it breaks the middleware chain and hangs forever
|
|
77
80
|
nextFn(err);
|
|
78
81
|
}
|
|
79
82
|
};
|
|
@@ -82,6 +85,7 @@ let RequestHandlerMiddlewareBuilder = class RequestHandlerMiddlewareBuilder {
|
|
|
82
85
|
switch (envelope) {
|
|
83
86
|
case 'form-data': {
|
|
84
87
|
const input = req.body;
|
|
88
|
+
// files is present when using express-fileupload
|
|
85
89
|
if ('files' in req && req.files) {
|
|
86
90
|
for (const [field, value] of Object.entries(req.files)) {
|
|
87
91
|
input[field] = Array.isArray(value)
|
|
@@ -89,6 +93,8 @@ let RequestHandlerMiddlewareBuilder = class RequestHandlerMiddlewareBuilder {
|
|
|
89
93
|
: this.toFile(value);
|
|
90
94
|
}
|
|
91
95
|
}
|
|
96
|
+
// TODO : Change this ugly code
|
|
97
|
+
// When a field has multiple values, they key is `field[]` and not `field`
|
|
92
98
|
const sanitized = {};
|
|
93
99
|
for (const [k, v] of Object.entries(input)) {
|
|
94
100
|
const sanitizedKey = k.split('[')[0];
|
|
@@ -96,6 +102,8 @@ let RequestHandlerMiddlewareBuilder = class RequestHandlerMiddlewareBuilder {
|
|
|
96
102
|
continue;
|
|
97
103
|
}
|
|
98
104
|
sanitized[sanitizedKey] = v;
|
|
105
|
+
// For some reason, when there is only one value, it is received as scalar and not as an array
|
|
106
|
+
// Even if there is only one, we want an array
|
|
99
107
|
if (k.includes('[') && !Array.isArray(v)) {
|
|
100
108
|
sanitized[sanitizedKey] = [v];
|
|
101
109
|
}
|
|
@@ -7,6 +7,16 @@ import type { Configurable, LoggerSettings, SettingsManager } from '../../std/in
|
|
|
7
7
|
import { UCBuilder, type UCDef, type UCHTTPContract, type UCInput, type UCManager, type UCOPIBase } from '../../uc/index.js';
|
|
8
8
|
import type { ServerManager } from '../lib/server/ServerManager.js';
|
|
9
9
|
type S = Pick<LoggerSettings, 'logger_level'>;
|
|
10
|
+
/**
|
|
11
|
+
* A simple MCP Server implementation
|
|
12
|
+
*
|
|
13
|
+
* Although it implements {@link ServerManager}, this implementation is not necessarily a "server".
|
|
14
|
+
* Indeed, it uses a local `Transport` so it must be considered the same as a {@link NodeCoreCLIManager}.
|
|
15
|
+
* Therefore, it calls `execClient` and not `execServer`.
|
|
16
|
+
* This way, Claude AI, or any other client is just a wrapper on top of it.
|
|
17
|
+
*
|
|
18
|
+
* @alpha This implementation still has lots of TODOs and has not been tested in real conditions. It needs to be stabilized before usage.
|
|
19
|
+
*/
|
|
10
20
|
export declare class NodeLocalStdioMCPServerManager implements Configurable<S>, ServerManager {
|
|
11
21
|
private productManifest;
|
|
12
22
|
private settingsManager;
|
|
@@ -17,6 +17,16 @@ import { inject, injectable } from 'inversify';
|
|
|
17
17
|
import { WordingManager } from '../../i18n/index.js';
|
|
18
18
|
import { UCBuilder, ucMountingPoint, ucifIsMandatory, } from '../../uc/index.js';
|
|
19
19
|
import { propertyType, resError, resObj } from './funcs.js';
|
|
20
|
+
/**
|
|
21
|
+
* A simple MCP Server implementation
|
|
22
|
+
*
|
|
23
|
+
* Although it implements {@link ServerManager}, this implementation is not necessarily a "server".
|
|
24
|
+
* Indeed, it uses a local `Transport` so it must be considered the same as a {@link NodeCoreCLIManager}.
|
|
25
|
+
* Therefore, it calls `execClient` and not `execServer`.
|
|
26
|
+
* This way, Claude AI, or any other client is just a wrapper on top of it.
|
|
27
|
+
*
|
|
28
|
+
* @alpha This implementation still has lots of TODOs and has not been tested in real conditions. It needs to be stabilized before usage.
|
|
29
|
+
*/
|
|
20
30
|
let NodeLocalStdioMCPServerManager = class NodeLocalStdioMCPServerManager {
|
|
21
31
|
productManifest;
|
|
22
32
|
settingsManager;
|
|
@@ -55,6 +65,9 @@ let NodeLocalStdioMCPServerManager = class NodeLocalStdioMCPServerManager {
|
|
|
55
65
|
});
|
|
56
66
|
if (this.s().logger_level !== 'error') {
|
|
57
67
|
const message = 'Set the logging_level to "error" as MCP does not want the server to log to stdout (see https://modelcontextprotocol.io/docs/tools/debugging#implementing-logging)';
|
|
68
|
+
// Depending on the `Logger` implementation, this.logger.error() might not write to stderr (e.g. can write to a file).
|
|
69
|
+
// That's why we explicitly write to stdout by calling console.error().
|
|
70
|
+
// biome-ignore lint/suspicious/noConsole: we want it
|
|
58
71
|
console.error(new Error(message));
|
|
59
72
|
}
|
|
60
73
|
}
|
|
@@ -112,6 +125,7 @@ let NodeLocalStdioMCPServerManager = class NodeLocalStdioMCPServerManager {
|
|
|
112
125
|
}
|
|
113
126
|
async execRequest(request) {
|
|
114
127
|
const { name, arguments: args } = request.params;
|
|
128
|
+
// TODO : Check authentication in some way (see if MCP handles it)
|
|
115
129
|
const auth = null;
|
|
116
130
|
try {
|
|
117
131
|
const route = this.tools.get(name);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ReactElement } from 'react';
|
|
2
|
+
import type { UCInput, UCOPIBase } from '../../uc/index.js';
|
|
3
|
+
import type { UCEntrypointTouchableProps } from '../lib/react/touchable.js';
|
|
4
|
+
export declare function UCEntrypointTouchable<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ onPress, wording, }: UCEntrypointTouchableProps<I, OPI0, OPI1>): ReactElement;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ReactElement } from 'react';
|
|
2
|
+
import type { UCInput, UCOPIBase } from '../../uc/index.js';
|
|
3
|
+
import type { UCExecTouchableProps } from '../lib/react/touchable.js';
|
|
4
|
+
export declare function UCExecTouchable<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ disabled, execState, onSubmit, uc, }: UCExecTouchableProps<I, OPI0, OPI1>): ReactElement;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React, {} from 'react';
|
|
2
|
+
import { Pressable, Text } from 'react-native';
|
|
3
|
+
import { useDIContext } from '../lib/react/DIContextProvider.js';
|
|
4
|
+
export function UCExecTouchable({ disabled, execState, onSubmit, uc, }) {
|
|
5
|
+
const { wordingManager } = useDIContext();
|
|
6
|
+
const label = wordingManager.ucISubmit(uc.def, execState);
|
|
7
|
+
return (React.createElement(Pressable, { disabled: disabled, onPress: onSubmit },
|
|
8
|
+
React.createElement(Text, null, label)));
|
|
9
|
+
}
|