libmodulor 0.23.0 → 0.24.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 (70) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +154 -2
  3. package/dist/esm/apps/Helper/src/lib/project.js +3 -3
  4. package/dist/esm/apps/Helper/src/ucds/TestAppUCD.d.ts +2 -1
  5. package/dist/esm/apps/Helper/src/ucds/TestAppUCD.js +8 -0
  6. package/dist/esm/convention.d.ts +3 -0
  7. package/dist/esm/convention.js +3 -0
  8. package/dist/esm/dt/DataTypes.d.ts +1 -2
  9. package/dist/esm/dt/base/TObject.js +1 -1
  10. package/dist/esm/i18n/index.d.ts +1 -1
  11. package/dist/esm/i18n/locales/de.d.ts +2 -0
  12. package/dist/esm/i18n/locales/de.js +54 -0
  13. package/dist/esm/i18n/locales/es.d.ts +2 -0
  14. package/dist/esm/i18n/locales/es.js +54 -0
  15. package/dist/esm/i18n/types.d.ts +3 -2
  16. package/dist/esm/index.babel.d.ts +1 -0
  17. package/dist/esm/index.babel.js +1 -0
  18. package/dist/esm/index.node-stricli-cli.d.ts +2 -0
  19. package/dist/esm/index.node-stricli-cli.js +2 -0
  20. package/dist/esm/index.vite.d.ts +1 -1
  21. package/dist/esm/index.vite.js +1 -1
  22. package/dist/esm/index.webpack.d.ts +1 -0
  23. package/dist/esm/index.webpack.js +1 -0
  24. package/dist/esm/std/I18nManager.d.ts +12 -0
  25. package/dist/esm/std/impl/NodeFSManager.js +1 -1
  26. package/dist/esm/std/impl/SimpleMapI18nManager.d.ts +6 -1
  27. package/dist/esm/std/impl/SimpleMapI18nManager.js +41 -12
  28. package/dist/esm/target/lib/server/AuthenticationChecker.js +1 -1
  29. package/dist/esm/target/lib/server/PublicApiKeyChecker.js +1 -1
  30. package/dist/esm/target/lib/server/ServerRequestHandler.js +2 -2
  31. package/dist/esm/target/lib/server-express/funcs.js +2 -2
  32. package/dist/esm/target/lib/server-hono/funcs.js +2 -2
  33. package/dist/esm/target/lib/server-node/funcs.js +1 -1
  34. package/dist/esm/target/node-stricli-cli/NodeStricliCLIManager.d.ts +12 -0
  35. package/dist/esm/target/node-stricli-cli/NodeStricliCLIManager.js +118 -0
  36. package/dist/esm/testing/AppTester.js +4 -5
  37. package/dist/esm/testing/UCDefASTParser.d.ts +24 -6
  38. package/dist/esm/testing/impl/SimpleAppDocsEmitter.js +4 -5
  39. package/dist/esm/testing/impl/TypeScriptLibUCDefASTParser.js +38 -11
  40. package/dist/esm/testing/impl/VitestAppTestSuiteRunner.d.ts +1 -1
  41. package/dist/esm/testing/impl/VitestAppTestSuiteRunner.js +17 -2
  42. package/dist/esm/testing/opts.js +1 -1
  43. package/dist/esm/testing/workers/AppTestSuiteRunner.d.ts +2 -0
  44. package/dist/esm/testing/workers/UCExecutor.js +1 -1
  45. package/dist/esm/testing/workers/checkers/AppI18nChecker.d.ts +8 -2
  46. package/dist/esm/testing/workers/checkers/AppI18nChecker.js +44 -2
  47. package/dist/esm/testing/workers/checkers/UCDefSourcesChecker.js +12 -12
  48. package/dist/esm/uc/impl/HTTPUCTransporter.js +2 -2
  49. package/dist/esm/uc/impl/KnexUCDataStore.js +2 -2
  50. package/dist/esm/uc/index.d.ts +0 -1
  51. package/dist/esm/uc/index.js +0 -1
  52. package/dist/esm/uc/workers/UCExecChecker.js +1 -1
  53. package/dist/esm/utils/bundling/babel/plugin.d.ts +2 -0
  54. package/dist/esm/utils/bundling/babel/plugin.js +38 -0
  55. package/dist/esm/utils/bundling/funcs.d.ts +6 -0
  56. package/dist/esm/utils/bundling/funcs.js +20 -0
  57. package/dist/esm/utils/bundling/typescript.d.ts +3 -0
  58. package/dist/esm/utils/bundling/typescript.js +61 -0
  59. package/dist/esm/utils/bundling/vite/plugin.d.ts +6 -0
  60. package/dist/esm/utils/bundling/vite/plugin.js +17 -0
  61. package/dist/esm/utils/bundling/webpack/loader.d.ts +2 -0
  62. package/dist/esm/utils/bundling/webpack/loader.js +12 -0
  63. package/dist/esm/utils/http/HTTPRequestBuilder.js +1 -1
  64. package/dist/esm/utils/ioc/bindCommon.js +1 -1
  65. package/dist/esm/utils/terminal/fmt.js +1 -1
  66. package/package.json +30 -8
  67. package/pnpm-workspace.yaml +1 -4
  68. package/tsconfig.build.examples.json +8 -0
  69. package/tsconfig.json +1 -0
  70. package/vitest.config.ts +16 -0
@@ -59,7 +59,7 @@ let UCExecChecker = class UCExecChecker {
59
59
  output.allowed = typeof server === 'object';
60
60
  break;
61
61
  default:
62
- ((_) => { })(lifecycle);
62
+ lifecycle;
63
63
  }
64
64
  return output;
65
65
  }
@@ -0,0 +1,2 @@
1
+ import { type PluginObj } from '@babel/core';
2
+ export declare const Plugin: PluginObj;
@@ -0,0 +1,38 @@
1
+ import { types as t } from '@babel/core';
2
+ import { UC_LIFECYCLE_PROP_NAME, UC_LIFECYCLE_SERVER_PROP_NAME, } from '../../../convention.js';
3
+ import { isFileEligible } from '../funcs.js';
4
+ // Using `PluginObj` instead of `satisfies PluginObj`.
5
+ // Otherwise TypeScript is not happy and triggers a TS2209.
6
+ export const Plugin = {
7
+ name: 'libmodulor-plugin',
8
+ visitor: {
9
+ ObjectExpression(path, state) {
10
+ if (!isFileEligible(state.filename, ['js', 'ts'])) {
11
+ return;
12
+ }
13
+ const lifecycle = findLifecycleProp(path);
14
+ if (!lifecycle) {
15
+ return;
16
+ }
17
+ const lifecycleObj = lifecycle.value;
18
+ const server = findServerProp(lifecycleObj);
19
+ if (!server) {
20
+ return;
21
+ }
22
+ server.value = t.booleanLiteral(true);
23
+ },
24
+ },
25
+ };
26
+ function findLifecycleProp(path) {
27
+ return path.node.properties.find((p) => t.isObjectProperty(p) &&
28
+ t.isIdentifier(p.key, {
29
+ name: UC_LIFECYCLE_PROP_NAME,
30
+ }) &&
31
+ t.isObjectExpression(p.value));
32
+ }
33
+ function findServerProp(lifecycleObj) {
34
+ return lifecycleObj.properties.find((p) => t.isObjectProperty(p) &&
35
+ t.isIdentifier(p.key, {
36
+ name: UC_LIFECYCLE_SERVER_PROP_NAME,
37
+ }));
38
+ }
@@ -0,0 +1,6 @@
1
+ import type { FileName } from '../../dt/index.js';
2
+ export type InputCode = string;
3
+ export type OutputCode = string;
4
+ export type StrippableFileExtension = 'js' | 'ts';
5
+ export declare function isFileEligible(fileName: FileName | undefined, exts: StrippableFileExtension[]): boolean;
6
+ export declare function assertTransformedCorrectly(transformed: OutputCode, fileName: FileName | undefined): void;
@@ -0,0 +1,20 @@
1
+ import { UC_DEF_SUFFIX } from '../../convention.js';
2
+ export function isFileEligible(fileName, exts) {
3
+ if (!fileName) {
4
+ return false;
5
+ }
6
+ for (const ext of exts) {
7
+ if (fileName.endsWith(`${UC_DEF_SUFFIX}.${ext}`)) {
8
+ return true;
9
+ }
10
+ }
11
+ return false;
12
+ }
13
+ export function assertTransformedCorrectly(transformed, fileName) {
14
+ const match = transformed.match(/server: (.*)ServerMain/g);
15
+ if (match !== null) {
16
+ // biome-ignore lint/suspicious/noConsole: we want it
17
+ console.warn(transformed);
18
+ throw new Error(`[WARNING] The following file might not have been transformed correctly : ${fileName} (see transformed above)`);
19
+ }
20
+ }
@@ -0,0 +1,3 @@
1
+ import type { FileName } from '../../dt/index.js';
2
+ import type { InputCode, OutputCode } from './funcs.js';
3
+ export declare function transform(code: InputCode, fileName: FileName): OutputCode;
@@ -0,0 +1,61 @@
1
+ import ts from 'typescript';
2
+ import { UC_DEF_SUFFIX, UC_LIFECYCLE_PROP_NAME, UC_LIFECYCLE_SERVER_PROP_NAME, } from '../../convention.js';
3
+ export function transform(code, fileName) {
4
+ const sourceFile = ts.createSourceFile(fileName, code, ts.ScriptTarget.ESNext);
5
+ const result = ts.transform(sourceFile, [transformer()]);
6
+ const transformed = result.transformed[0];
7
+ if (!transformed) {
8
+ throw new Error(`Could not transform file : ${fileName}`);
9
+ }
10
+ const printer = ts.createPrinter();
11
+ return printer.printFile(transformed);
12
+ }
13
+ function transformer() {
14
+ return (context) => {
15
+ return (sourceFile) => {
16
+ const { factory } = context;
17
+ function visit(node) {
18
+ if (!isUCDDeclaration(sourceFile, node)) {
19
+ return ts.visitEachChild(node, visit, context);
20
+ }
21
+ const rootObj = node.initializer;
22
+ const lifecycle = findLifecycleProp(sourceFile, rootObj);
23
+ if (!lifecycle) {
24
+ return ts.visitEachChild(node, visit, context);
25
+ }
26
+ const lifecycleObj = lifecycle.initializer;
27
+ const server = findServerProp(sourceFile, lifecycleObj);
28
+ if (!server) {
29
+ return ts.visitEachChild(node, visit, context);
30
+ }
31
+ // Nodes are immutable so we need to re-create the whole tree
32
+ const newServer = factory.updatePropertyAssignment(server, server.name, factory.createTrue());
33
+ const newLifecycleObj = factory.updateObjectLiteralExpression(lifecycleObj, lifecycleObj.properties.map((p) => p === server ? newServer : p));
34
+ const newLifecycle = factory.updatePropertyAssignment(lifecycle, lifecycle.name, newLifecycleObj);
35
+ const newRootObj = factory.updateObjectLiteralExpression(rootObj, rootObj.properties.map((p) => p === lifecycle ? newLifecycle : p));
36
+ return factory.updateVariableDeclaration(node, node.name, node.exclamationToken, node.type, newRootObj);
37
+ }
38
+ return ts.visitNode(sourceFile, visit);
39
+ };
40
+ };
41
+ }
42
+ function isUCDDeclaration(sourceFile, node) {
43
+ if (!ts.isVariableDeclaration(node)) {
44
+ return false;
45
+ }
46
+ const name = node.name.getText(sourceFile);
47
+ return (name.endsWith(UC_DEF_SUFFIX) &&
48
+ !!node.initializer &&
49
+ ts.isObjectLiteralExpression(node.initializer));
50
+ }
51
+ function findLifecycleProp(sourceFile, rootObj) {
52
+ return rootObj.properties.find((p) => ts.isPropertyAssignment(p) &&
53
+ ts.isIdentifier(p.name) &&
54
+ p.name.getText(sourceFile) === UC_LIFECYCLE_PROP_NAME &&
55
+ ts.isObjectLiteralExpression(p.initializer));
56
+ }
57
+ function findServerProp(sourceFile, lifecycleObj) {
58
+ return lifecycleObj.properties.find((p) => ts.isPropertyAssignment(p) &&
59
+ ts.isIdentifier(p.name) &&
60
+ p.name.getText(sourceFile) === UC_LIFECYCLE_SERVER_PROP_NAME);
61
+ }
@@ -0,0 +1,6 @@
1
+ export declare const Plugin: {
2
+ name: string;
3
+ transform: (this: import("rollup").TransformPluginContext, code: string, id: string) => {
4
+ code: string;
5
+ };
6
+ };
@@ -0,0 +1,17 @@
1
+ import { assertTransformedCorrectly, isFileEligible } from '../funcs.js';
2
+ import { transform } from '../typescript.js';
3
+ export const Plugin = {
4
+ name: 'libmodulor-plugin',
5
+ transform: (code, id) => {
6
+ if (!isFileEligible(id, ['ts'])) {
7
+ return {
8
+ code,
9
+ };
10
+ }
11
+ const transformed = transform(code, id);
12
+ assertTransformedCorrectly(transformed, id);
13
+ return {
14
+ code: transformed,
15
+ };
16
+ },
17
+ };
@@ -0,0 +1,2 @@
1
+ import { type InputCode, type OutputCode } from '../funcs.js';
2
+ export default function loader(source: InputCode): OutputCode;
@@ -0,0 +1,12 @@
1
+ import { assertTransformedCorrectly, isFileEligible, } from '../funcs.js';
2
+ import { transform } from '../typescript.js';
3
+ export default function loader(source) {
4
+ // @ts-expect-error -- magically made available by Webpack at execution
5
+ const fileName = this.resourcePath;
6
+ if (!isFileEligible(fileName, ['ts'])) {
7
+ return source;
8
+ }
9
+ const transformed = transform(source, fileName);
10
+ assertTransformedCorrectly(transformed, fileName);
11
+ return transformed;
12
+ }
@@ -41,7 +41,7 @@ let HTTPRequestBuilder = class HTTPRequestBuilder {
41
41
  break;
42
42
  }
43
43
  default:
44
- ((_) => { })(envelope);
44
+ envelope;
45
45
  return output;
46
46
  }
47
47
  return output;
@@ -49,7 +49,7 @@ export function bindCommon(container, settingsFunc) {
49
49
  .bind('I18nManager')
50
50
  .to(SimpleMapI18nManager)
51
51
  .inSingletonScope();
52
- container.bind('I18n').toConstantValue({});
52
+ container.bind('I18n').toConstantValue({ en: {} });
53
53
  container.bind('Logger').to(ConsoleLogger);
54
54
  container.bind('Settings').toConstantValue(settings);
55
55
  container
@@ -5,7 +5,7 @@ export function fmtCommand(cmd, details, padEnd) {
5
5
  return ` ${cmd.padEnd(padEnd)}${details ?? ''}`;
6
6
  }
7
7
  export function fmtPadEndFor(s) {
8
- const longest = s.sort((a, b) => a.length - b.length).reverse()[0];
8
+ const longest = [...s].sort((a, b) => a.length - b.length).reverse()[0];
9
9
  return (longest?.length ?? 1) + 10;
10
10
  }
11
11
  export function fmtSection(s) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "libmodulor",
3
3
  "description": "A TypeScript library to create platform-agnostic applications",
4
- "version": "0.23.0",
4
+ "version": "0.24.0",
5
5
  "license": "LGPL-3.0",
6
6
  "author": "Chafik H'nini <chafik.hnini@gmail.com>",
7
7
  "homepage": "https://libmodulor.c100k.eu",
@@ -23,12 +23,21 @@
23
23
  ".": {
24
24
  "import": "./dist/esm/index.js"
25
25
  },
26
+ "./babel": {
27
+ "import": "./dist/esm/index.babel.js"
28
+ },
26
29
  "./cloudflare-worker-hono": {
27
30
  "import": "./dist/esm/index.cloudflare-worker-hono.js"
28
31
  },
32
+ "./locales/de": {
33
+ "import": "./dist/esm/i18n/locales/de.js"
34
+ },
29
35
  "./locales/en": {
30
36
  "import": "./dist/esm/i18n/locales/en.js"
31
37
  },
38
+ "./locales/es": {
39
+ "import": "./dist/esm/i18n/locales/es.js"
40
+ },
32
41
  "./locales/fr": {
33
42
  "import": "./dist/esm/i18n/locales/fr.js"
34
43
  },
@@ -44,6 +53,9 @@
44
53
  "./node-mcp": {
45
54
  "import": "./dist/esm/index.node-mcp.js"
46
55
  },
56
+ "./node-stricli-cli": {
57
+ "import": "./dist/esm/index.node-stricli-cli.js"
58
+ },
47
59
  "./node-test": {
48
60
  "import": "./dist/esm/index.node-test.js"
49
61
  },
@@ -73,6 +85,9 @@
73
85
  },
74
86
  "./web": {
75
87
  "import": "./dist/esm/index.web.js"
88
+ },
89
+ "./webpack": {
90
+ "import": "./dist/esm/index.webpack.js"
76
91
  }
77
92
  },
78
93
  "bin": "./dist/esm/products/Helper/index.js",
@@ -81,11 +96,18 @@
81
96
  "lint:ci": "biome check"
82
97
  },
83
98
  "devDependencies": {
84
- "@biomejs/biome": "^2.3.4"
99
+ "@biomejs/biome": "^2.3.8",
100
+ "@react-native-community/slider": "^4.5.7",
101
+ "@types/react": "^19.2.7",
102
+ "@types/react-dom": "^19.2.3",
103
+ "babel-plugin-parameter-decorator": "^1.0.16",
104
+ "babel-plugin-transform-typescript-metadata": "^0.3.2",
105
+ "expo": "^54.0.25",
106
+ "wrangler": "^4.51.0"
85
107
  },
86
108
  "peerDependencies": {
87
109
  "@hono/node-server": "^1.19.6",
88
- "@modelcontextprotocol/sdk": "^1.21.0",
110
+ "@modelcontextprotocol/sdk": "^1.23.0",
89
111
  "@stricli/core": "^1.2.4",
90
112
  "buffer": "^6.0.3",
91
113
  "cookie-parser": "^1.4.7",
@@ -93,14 +115,14 @@
93
115
  "express-fileupload": "^1.5.2",
94
116
  "fast-check": "^4.3.0",
95
117
  "helmet": "^8.1.0",
96
- "hono": "^4.10.4",
118
+ "hono": "^4.10.7",
97
119
  "inversify": "^7.10.4",
98
- "jose": "^6.1.0",
120
+ "jose": "^6.1.2",
99
121
  "knex": "^3.1.0",
100
- "next": "^15.5.6",
122
+ "next": "^15.5.7",
101
123
  "pg": "^8.16.3",
102
- "react": "^19.2.0",
103
- "react-dom": "^19.2.0",
124
+ "react": "^19.2.1",
125
+ "react-dom": "^19.2.1",
104
126
  "react-native": "^0.81.5",
105
127
  "reflect-metadata": "^0.2.2",
106
128
  "sqlite3": "^5.1.7",
@@ -1,11 +1,8 @@
1
1
  minimumReleaseAge: 2880
2
- packages:
3
- - examples/basic
4
- - examples/standalone
5
- - examples/supertrader
6
2
  onlyBuiltDependencies:
7
3
  - '@biomejs/biome'
8
4
  - '@tailwindcss/oxide'
9
5
  - esbuild
10
6
  - sharp
11
7
  - sqlite3
8
+ - workerd
@@ -0,0 +1,8 @@
1
+ {
2
+ "compilerOptions": {
3
+ "noEmit": false,
4
+ "outDir": "dist-examples"
5
+ },
6
+ "extends": "./tsconfig.json",
7
+ "include": ["examples"]
8
+ }
package/tsconfig.json CHANGED
@@ -28,6 +28,7 @@
28
28
  },
29
29
  "exclude": [
30
30
  "dist",
31
+ "dist-examples",
31
32
  "examples/**/dist",
32
33
  "examples/**/node_modules",
33
34
  "node_modules"
@@ -0,0 +1,16 @@
1
+ import { loadEnv } from 'vite';
2
+ import { defineConfig } from 'vitest/config';
3
+
4
+ export default defineConfig(({ mode }) => ({
5
+ test: {
6
+ coverage: {
7
+ exclude: ['src/apps/**/test', 'src/**/*.test.ts'],
8
+ include: ['src'],
9
+ reporter: ['html', 'lcov', 'text'],
10
+ reportOnFailure: false,
11
+ },
12
+ env: loadEnv(mode, process.cwd(), ''),
13
+ exclude: ['**/node_modules/**', '**/dist/**', '**/dist-examples/**'],
14
+ reporters: ['verbose'],
15
+ },
16
+ }));