Current version : 0.23.0
Made in 🇫🇷 ◌ GitHubNPM

Playground

An example showcasing a fully featured product with multiple apps exposed on multiple targets.

Get

git clone git@github.com:c100k/libmodulor.git
pnpm install

Build

./scripts/examples/build.sh

Targets

server-node-express

This target uses the built-in node-express-server target, is transpiled with tsc and executed with Node.js. It uses SQLite as UCDataStore.

Start the server.

(cd dist-examples/products/Playground/server-node-express && node --env-file .env index.js)

Test in your Terminal Emulator with curl.

# BuyAsset
curl -X POST -H "Content-Type: application/json" http://localhost:7443/api/v1/Trading_BuyAsset
# ❌ {"message":"Invalid credentials"}
curl -X POST -H "Content-Type: application/json" -H "X-API-Key: PublicApiKeyToBeChangedWhenDeploying" http://localhost:7443/api/v1/Trading_BuyAsset
# ❌ {"message":"ISIN must be filled"}
curl -X POST -H "Content-Type: application/json" -H "X-API-Key: PublicApiKeyToBeChangedWhenDeploying" -d '{"isin":"US02079K3059","limit":123.5,"qty":150}' http://localhost:7443/api/v1/Trading_BuyAsset
# ✅ {"parts":{"_0":{"items":[{"isin":"US02079K3059","id":"882f384b-fa46-424b-8b82-e0781ab1fbec","limit":123.5,"qty":150,"status":"pending"}],"total":1}}}

# CancelOrder
curl -X DELETE -H "Content-Type: application/json" -H "X-API-Key: PublicApiKeyToBeChangedWhenDeploying" -d '{"id":"882f384b-fa46-424b-8b82-e0781ab1fbec"}' http://localhost:7443/api/v1/Trading_CancelOrder
# ✅ {"parts":{"_0":{"items":[{"id":"a2285506-1afd-4649-98a6-e4443d1c6ce7","isin":"US02079K3059","limit":123.5,"qty":150,"status":"cancelled"}],"total":1}}}
curl -X DELETE -H "Content-Type: application/json" -H "X-API-Key: PublicApiKeyToBeChangedWhenDeploying" -d '{"id":"882f384b-fa46-424b-8b82-e0781ab1fbec"}' http://localhost:7443/api/v1/Trading_CancelOrder
# ❌ {"message":"Cannot cancel an order that is not pending"}

# ListOrders
curl -H "Content-Type: application/json" -H "X-API-Key: PublicApiKeyToBeChangedWhenDeploying" http://localhost:7443/api/v1/Trading_ListOrders
# ✅ {"parts":{"_0":{"items":[{"id":"a2285506-1afd-4649-98a6-e4443d1c6ce7","isin":"US02079K3059","limit":123.5,"qty":150,"status":"cancelled"}],"total":1}}}

Keep your server running to test the "client" targets defined below.

spa

This target uses the built-in react-web-pure target and is bundled with vite.

It is statically served by the server defined above for convenience, but it could also be served by anything else (e.g. an S3 bucket, a simple nginx server and so on).

Test in your browser at http://localhost:7443.

Web UI

cli-node-core

This target uses the built-in node-core-cli target, is transpiled with tsc and executed with Node.js.

Test in your Terminal Emulator.

# BuyAsset
(cd dist-examples/products/Playground/cli-node-core && node index.js Trading_BuyAsset)
# ❌ ISIN must be filled
(cd dist-examples/products/Playground/cli-node-core && node index.js Trading_BuyAsset --isin US02079K3059 --limit 123.5 --qty 150)
# ✅ {"parts":{"_0":{"items":[{"isin":"US02079K3059","id":"c1ef95f1-f6e1-4616-a7a5-5584758b3a65","limit":123.5,"qty":150,"status":"pending"}],"total":1}}}

# CancelOrder
(cd dist-examples/products/Playground/cli-node-core && node index.js Trading_CancelOrder --id c1ef95f1-f6e1-4616-a7a5-5584758b3a65)
# Are you sure ? [Y,y = Yes / N,n = Cancel] : y
# ✅ {"parts":{"_0":{"items":[{"id":"c1ef95f1-f6e1-4616-a7a5-5584758b3a65","isin":"US02079K3059","limit":123.5,"qty":150,"status":"cancelled"}],"total":1}}}
(cd dist-examples/products/Playground/cli-node-core && node index.js Trading_CancelOrder --id c1ef95f1-f6e1-4616-a7a5-5584758b3a65)
# Are you sure ? [Y,y = Yes / N,n = Cancel] : y
# ❌ Cannot cancel an order that is not pending

# ListOrders
(cd dist-examples/products/Playground/cli-node-core && node index.js Trading_ListOrders)
# ✅ {"parts":{"_0":{"items":[{"id":"a2285506-1afd-4649-98a6-e4443d1c6ce7","isin":"US02079K3059","limit":123.5,"qty":150,"status":"cancelled"},{"id":"882f384b-fa46-424b-8b82-e0781ab1fbec","isin":"US02079K3059","limit":123.5,"qty":150,"status":"pending"},{"id":"c1ef95f1-f6e1-4616-a7a5-5584758b3a65","isin":"US02079K3059","limit":123.5,"qty":150,"status":"cancelled"},{"id":"78509b91-0f33-43a2-b6e3-2ced5a1fa171","isin":"US02079K3059","limit":123.5,"qty":150,"status":"pending"}],"total":4}}}

cli-node-stricli

This target uses the built-in node-stricli-cli target which is based on stricli, is transpiled with tsc and executed with Node.js.

It works the exact same way as the other cli target defined above.

mcp-server

This target target uses the built-in node-mcp-server target, is transpiled with tsc and exposes an index.js file to be used by the MCP client.

Test in Claude Desktop.

Open the config file to register the MCP server.

nano ~/Library/Application\ Support/Claude/claude_desktop_config.json

Paste the following config and adapt the absolute path.

{
    "mcpServers": {
        "libmodulor-playground": {
            "command": "node",
            "args": [
                "/ABSOLUTE_PATH_TO_THE_CWD/dist-examples/products/Playground/mcp-server/index.js"
            ]
        }
    }
}

Launch Claude Desktop.

At the bottom right of the prompt, you should see a little hammer 🔨 indicating 1 MCP Tool available.

Click on it. You should see the use cases registered.

Write a prompt to buy an asset.

Dear Claude. Please buy 150 shares of Google.

Claude Desktop

rn

This target uses the built-in react-native-pure target, is bundled with expo and runs on android and ios.

Make sure your environment is setup to be able to use the Android Emulator and iOS Simulator (macOS only).

android

To call the server running on your machine, the Android emulator uses the special IP address 10.0.2.2. Therefore, you need to restart you server to listen on 0.0.0.0.

(cd dist-examples/products/Playground/server-node-express && app_server_binding_host=0.0.0.0 node --env-file .env index.js)

Start the application on the android emulator.

pnpm expo start --android dist-examples/products/Playground/rn

ios

Start the application on the ios simulator.

pnpm expo start --ios dist-examples/products/Playground/rn

Android & iOS

server-node-hono

This target uses the built-in node-hono-server target. It is very similar to node-express-server, except that it uses hono instead of express. It also uses SQLite as UCDataStore.

If the node-express-server is still running, stop it and start this one.

(cd dist-examples/products/Playground/server-node-hono && node --env-file .env index.js)

You can test it the exact same way as above (with curl or the different clients).

server-nextjs

This target uses the built-in server-nextjs target and the same components as the spa target defined above. Except that they are served by Next.js. It also uses SQLite as UCDataStore.

(cd dist-examples/products/Playground/server-nextjs && pnpm next dev)

You can test it the exact same way as above (with curl or the different clients). The only difference is that the server listens on port 3000 instead of 7443. Thus, you need to adapt it in the clients' container.ts. That's a good exercise to get used to the settings mechanism.

server-cloudflare-worker

This target uses the built-in edge-worker-hono-server target in its sync flavor and is managed with wrangler. It uses Cloudflare D1 as UCDataStore.

You need a Cloudflare account to test this target, even locally, as you need to create a D1 database. Please note that this might occur charges on your account.

Initialize the D1 database.

pnpm wrangler d1 create libmodulor-examples-playground-uc-data-store
pnpm wrangler d1 list

Adapt the {your_database_id} in dist-examples/products/Playground/server-cloudflare-worker/wrangler.jsonc.

Apply the migrations to create the schema (local and remote).

pnpm wrangler d1 execute libmodulor-examples-playground-uc-data-store --cwd ./dist-examples/products/Playground/server-cloudflare-worker --local --file=./migrations/001_init.sql
pnpm wrangler d1 execute libmodulor-examples-playground-uc-data-store --cwd ./dist-examples/Playground/server-cloudflare-worker --remote --file=./migrations/001_init.sql

Start the server locally.

pnpm run:server-cloudflare-worker

You can test it the exact same way as above (with curl or the different clients). The only difference is that the server listens on port 8787 (or a random one assigned by wrangler) instead of 7443. Thus, you need to adapt it in the clients' container.ts. That's a good exercise to get used to the settings mechanism.

You can even deploy it on your account.

pnpm deploy:server-cloudflare-worker

Once done, perform the exact same tests as above, simply by replacing the local address and port by the remote one.

You can inspect the requests in the Cloudflare Workers & Pages dashboard as shown below.

Cloudflare Worker Dashboard

Explore the data

SQLite

The server-node-express, server-node-hono and server-nextjs targets rebind the UCDataStore from InMemoryUCDataStore (default) to KnexUCDataStore configured with SQLite.

Explore the data with your favorite DB tool like DBeaver or TablePlus.

open uc-data-store.sqlite

SQLite UCDataStore

Cloudflare D1

The server-cloudflare-worker target rebinds UCDataStore from InMemoryUCDataStore (default) to CloudflareD1UCDataStore.

Explore the data with your favorite DB tool like DBeaver or TablePlus.

open dist-examples/products/Playground/server-cloudflare-worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/{hash}.sqlite

For remote data, open the Cloudflare D1 dashboard as shown below.

Cloudflare D1 UCDataStore