From 7eee87ec90ad8c90273eaabd0af20a6b1d660c8d Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Wed, 7 Jan 2026 14:25:01 +0000 Subject: [PATCH] refactor: remove LuaScript entity and related operations - Deleted all LuaScript CRUD operations from Client and entities. - Removed LuaScript validation functions and related files. - Updated InMemoryStore to remove LuaScript storage. - Cleaned up tests by removing LuaScript related test cases. - Adjusted documentation and quick start guide to reflect the removal of LuaScript functionality. --- .../include/dbal/adapters/adapter.hpp | 6 - dbal/production/include/dbal/core/client.hpp | 9 -- dbal/production/include/dbal/core/types.hpp | 32 ---- dbal/production/src/client.cpp | 26 --- dbal/production/src/entities/entities.hpp | 5 +- dbal/production/src/entities/index.hpp | 13 +- .../lua_script/crud/create_lua_script.hpp | 65 -------- .../lua_script/crud/delete_lua_script.hpp | 39 ----- .../lua_script/crud/get_lua_script.hpp | 36 ----- .../lua_script/crud/list_lua_scripts.hpp | 67 -------- .../lua_script/crud/search_lua_scripts.hpp | 71 --------- .../lua_script/crud/update_lua_script.hpp | 113 ------------- .../src/entities/lua_script/index.hpp | 15 -- dbal/production/src/store/in_memory_store.hpp | 6 - .../entity/lua_script_validation.hpp | 61 ------- .../src/validation/lua_script_validation.hpp | 4 - dbal/production/src/validation/validation.hpp | 5 +- dbal/production/tests/unit/client_test.cpp | 149 +----------------- .../common/contracts/conformance_cases.yaml | 61 +------ dbal/shared/docs/QUICK_START.md | 25 +-- frontends/nextjs/src/app/layout.tsx | 4 +- .../nextjs/src/app/ui/[[...slug]]/page.tsx | 29 ++-- .../ui-page-renderer/UIPageRenderer.tsx | 25 ++- .../lib/lua/ui/generate-component-tree.tsx | 100 ------------ .../src/lib/lua/ui/types/lua-ui-package.ts | 15 -- .../src/lib/ui-pages/load-page-from-db.ts | 7 - .../ui-pages/load-page-from-lua-packages.ts | 10 -- 27 files changed, 42 insertions(+), 956 deletions(-) delete mode 100644 dbal/production/src/entities/lua_script/crud/create_lua_script.hpp delete mode 100644 dbal/production/src/entities/lua_script/crud/delete_lua_script.hpp delete mode 100644 dbal/production/src/entities/lua_script/crud/get_lua_script.hpp delete mode 100644 dbal/production/src/entities/lua_script/crud/list_lua_scripts.hpp delete mode 100644 dbal/production/src/entities/lua_script/crud/search_lua_scripts.hpp delete mode 100644 dbal/production/src/entities/lua_script/crud/update_lua_script.hpp delete mode 100644 dbal/production/src/entities/lua_script/index.hpp delete mode 100644 dbal/production/src/validation/entity/lua_script_validation.hpp delete mode 100644 dbal/production/src/validation/lua_script_validation.hpp delete mode 100644 frontends/nextjs/src/lib/lua/ui/generate-component-tree.tsx delete mode 100644 frontends/nextjs/src/lib/lua/ui/types/lua-ui-package.ts delete mode 100644 frontends/nextjs/src/lib/ui-pages/load-page-from-lua-packages.ts diff --git a/dbal/production/include/dbal/adapters/adapter.hpp b/dbal/production/include/dbal/adapters/adapter.hpp index 9bd0de64b..1767693d7 100644 --- a/dbal/production/include/dbal/adapters/adapter.hpp +++ b/dbal/production/include/dbal/adapters/adapter.hpp @@ -37,12 +37,6 @@ public: virtual Result deleteSession(const std::string& id) = 0; virtual Result> listSessions(const ListOptions& options) = 0; - virtual Result createLuaScript(const CreateLuaScriptInput& input) = 0; - virtual Result getLuaScript(const std::string& id) = 0; - virtual Result updateLuaScript(const std::string& id, const UpdateLuaScriptInput& input) = 0; - virtual Result deleteLuaScript(const std::string& id) = 0; - virtual Result> listLuaScripts(const ListOptions& options) = 0; - virtual Result createPackage(const CreatePackageInput& input) = 0; virtual Result getPackage(const std::string& id) = 0; virtual Result updatePackage(const std::string& id, const UpdatePackageInput& input) = 0; diff --git a/dbal/production/include/dbal/core/client.hpp b/dbal/production/include/dbal/core/client.hpp index da2f933cf..ae79c6504 100644 --- a/dbal/production/include/dbal/core/client.hpp +++ b/dbal/production/include/dbal/core/client.hpp @@ -85,15 +85,6 @@ public: Result deleteSession(const std::string& id); Result> listSessions(const ListOptions& options); - Result createLuaScript(const CreateLuaScriptInput& input); - Result getLuaScript(const std::string& id); - Result updateLuaScript(const std::string& id, const UpdateLuaScriptInput& input); - Result deleteLuaScript(const std::string& id); - Result> listLuaScripts(const ListOptions& options); - Result> searchLuaScripts(const std::string& query, - const std::optional& createdBy = std::nullopt, - int limit = 20); - Result createPackage(const CreatePackageInput& input); Result getPackage(const std::string& id); Result updatePackage(const std::string& id, const UpdatePackageInput& input); diff --git a/dbal/production/include/dbal/core/types.hpp b/dbal/production/include/dbal/core/types.hpp index 7e0cf2e3e..064ade42f 100644 --- a/dbal/production/include/dbal/core/types.hpp +++ b/dbal/production/include/dbal/core/types.hpp @@ -158,38 +158,6 @@ struct UpdateSessionInput { std::optional userAgent; }; -struct CreateLuaScriptInput { - std::optional tenantId; - std::string name; - std::optional description; - std::string code; - std::string parameters; - std::optional returnType; - bool isSandboxed = true; - std::string allowedGlobals; - int timeoutMs = 5000; - int version = 1; - std::optional createdAt; - std::optional updatedAt; - std::optional createdBy; -}; - -struct UpdateLuaScriptInput { - std::optional tenantId; - std::optional name; - std::optional description; - std::optional code; - std::optional parameters; - std::optional returnType; - std::optional isSandboxed; - std::optional allowedGlobals; - std::optional timeoutMs; - std::optional version; - std::optional createdAt; - std::optional updatedAt; - std::optional createdBy; -}; - struct CreatePackageInput { std::string packageId; std::optional tenantId; diff --git a/dbal/production/src/client.cpp b/dbal/production/src/client.cpp index fba2626fd..98b50767a 100644 --- a/dbal/production/src/client.cpp +++ b/dbal/production/src/client.cpp @@ -199,32 +199,6 @@ Result> Client::listSessions(const ListOptions& options) { return entities::session::list(getStore(), options); } -Result Client::createLuaScript(const CreateLuaScriptInput& input) { - return entities::lua_script::create(getStore(), input); -} - -Result Client::getLuaScript(const std::string& id) { - return entities::lua_script::get(getStore(), id); -} - -Result Client::updateLuaScript(const std::string& id, const UpdateLuaScriptInput& input) { - return entities::lua_script::update(getStore(), id, input); -} - -Result Client::deleteLuaScript(const std::string& id) { - return entities::lua_script::remove(getStore(), id); -} - -Result> Client::listLuaScripts(const ListOptions& options) { - return entities::lua_script::list(getStore(), options); -} - -Result> Client::searchLuaScripts(const std::string& query, - const std::optional& createdBy, - int limit) { - return entities::lua_script::search(getStore(), query, createdBy, limit); -} - Result Client::createPackage(const CreatePackageInput& input) { return entities::package::create(getStore(), input); } diff --git a/dbal/production/src/entities/entities.hpp b/dbal/production/src/entities/entities.hpp index 1d356e4c6..1eda29051 100644 --- a/dbal/production/src/entities/entities.hpp +++ b/dbal/production/src/entities/entities.hpp @@ -10,8 +10,7 @@ #include "user_operations.hpp" #include "page_operations.hpp" #include "workflow_operations.hpp" -#include "session_operations.hpp" -#include "lua_script_operations.hpp" -#include "package_operations.hpp" +#include "session_operations.hpp" +#include "package_operations.hpp" #endif diff --git a/dbal/production/src/entities/index.hpp b/dbal/production/src/entities/index.hpp index f3dedda11..ba5f8e940 100644 --- a/dbal/production/src/entities/index.hpp +++ b/dbal/production/src/entities/index.hpp @@ -8,13 +8,12 @@ #ifndef DBAL_ENTITIES_INDEX_HPP #define DBAL_ENTITIES_INDEX_HPP -#include "user/index.hpp" -#include "page/index.hpp" -#include "component/index.hpp" -#include "workflow/index.hpp" -#include "session/index.hpp" -#include "lua_script/index.hpp" -#include "package/index.hpp" +#include "user/index.hpp" +#include "page/index.hpp" +#include "component/index.hpp" +#include "workflow/index.hpp" +#include "session/index.hpp" +#include "package/index.hpp" #include "credential/index.hpp" #endif diff --git a/dbal/production/src/entities/lua_script/crud/create_lua_script.hpp b/dbal/production/src/entities/lua_script/crud/create_lua_script.hpp deleted file mode 100644 index cb5c4f0f7..000000000 --- a/dbal/production/src/entities/lua_script/crud/create_lua_script.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file create_lua_script.hpp - * @brief Create Lua script operation - */ -#ifndef DBAL_CREATE_LUA_SCRIPT_HPP -#define DBAL_CREATE_LUA_SCRIPT_HPP - -#include "dbal/types.hpp" -#include "dbal/errors.hpp" -#include "../../../store/in_memory_store.hpp" -#include "../../../validation/entity/lua_script_validation.hpp" - -namespace dbal { -namespace entities { -namespace lua_script { - -/** - * Create a new Lua script in the store - */ -inline Result create(InMemoryStore& store, const CreateLuaScriptInput& input) { - if (!validation::isValidLuaScriptName(input.name)) { - return Error::validationError("Lua script name must be 1-255 characters"); - } - if (!validation::isValidLuaScriptCode(input.code)) { - return Error::validationError("Lua script code must be a non-empty string"); - } - if (!validation::isValidLuaTimeout(input.timeoutMs)) { - return Error::validationError("Timeout must be between 100 and 30000 ms"); - } - std::string globals_error; - if (!validation::validateLuaAllowedGlobals(input.allowedGlobals, globals_error)) { - return Error::validationError(globals_error); - } - - if (store.lua_script_names.find(input.name) != store.lua_script_names.end()) { - return Error::conflict("Lua script name already exists: " + input.name); - } - - LuaScript script; - script.id = store.generateId("lua", ++store.lua_script_counter); - script.tenantId = input.tenantId; - script.name = input.name; - script.description = input.description; - script.code = input.code; - script.parameters = input.parameters; - script.returnType = input.returnType; - script.isSandboxed = input.isSandboxed; - script.allowedGlobals = input.allowedGlobals; - script.timeoutMs = input.timeoutMs; - script.version = input.version; - script.createdAt = input.createdAt.value_or(std::chrono::system_clock::now()); - script.updatedAt = input.updatedAt.value_or(script.createdAt); - script.createdBy = input.createdBy; - - store.lua_scripts[script.id] = script; - store.lua_script_names[script.name] = script.id; - - return Result(script); -} - -} // namespace lua_script -} // namespace entities -} // namespace dbal - -#endif diff --git a/dbal/production/src/entities/lua_script/crud/delete_lua_script.hpp b/dbal/production/src/entities/lua_script/crud/delete_lua_script.hpp deleted file mode 100644 index b2dd84e37..000000000 --- a/dbal/production/src/entities/lua_script/crud/delete_lua_script.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file delete_lua_script.hpp - * @brief Delete Lua script operation - */ -#ifndef DBAL_DELETE_LUA_SCRIPT_HPP -#define DBAL_DELETE_LUA_SCRIPT_HPP - -#include "dbal/types.hpp" -#include "dbal/errors.hpp" -#include "../../../store/in_memory_store.hpp" - -namespace dbal { -namespace entities { -namespace lua_script { - -/** - * Delete a Lua script by ID - */ -inline Result remove(InMemoryStore& store, const std::string& id) { - if (id.empty()) { - return Error::validationError("Lua script ID cannot be empty"); - } - - auto it = store.lua_scripts.find(id); - if (it == store.lua_scripts.end()) { - return Error::notFound("Lua script not found: " + id); - } - - store.lua_script_names.erase(it->second.name); - store.lua_scripts.erase(it); - - return Result(true); -} - -} // namespace lua_script -} // namespace entities -} // namespace dbal - -#endif diff --git a/dbal/production/src/entities/lua_script/crud/get_lua_script.hpp b/dbal/production/src/entities/lua_script/crud/get_lua_script.hpp deleted file mode 100644 index bdec37fad..000000000 --- a/dbal/production/src/entities/lua_script/crud/get_lua_script.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @file get_lua_script.hpp - * @brief Get Lua script by ID operation - */ -#ifndef DBAL_GET_LUA_SCRIPT_HPP -#define DBAL_GET_LUA_SCRIPT_HPP - -#include "dbal/types.hpp" -#include "dbal/errors.hpp" -#include "../../../store/in_memory_store.hpp" - -namespace dbal { -namespace entities { -namespace lua_script { - -/** - * Get a Lua script by ID - */ -inline Result get(InMemoryStore& store, const std::string& id) { - if (id.empty()) { - return Error::validationError("Lua script ID cannot be empty"); - } - - auto it = store.lua_scripts.find(id); - if (it == store.lua_scripts.end()) { - return Error::notFound("Lua script not found: " + id); - } - - return Result(it->second); -} - -} // namespace lua_script -} // namespace entities -} // namespace dbal - -#endif diff --git a/dbal/production/src/entities/lua_script/crud/list_lua_scripts.hpp b/dbal/production/src/entities/lua_script/crud/list_lua_scripts.hpp deleted file mode 100644 index 09c61cf85..000000000 --- a/dbal/production/src/entities/lua_script/crud/list_lua_scripts.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file list_lua_scripts.hpp - * @brief List Lua scripts with filtering and pagination - */ -#ifndef DBAL_LIST_LUA_SCRIPTS_HPP -#define DBAL_LIST_LUA_SCRIPTS_HPP - -#include "dbal/types.hpp" -#include "dbal/errors.hpp" -#include "../../../store/in_memory_store.hpp" -#include - -namespace dbal { -namespace entities { -namespace lua_script { - -/** - * List Lua scripts with filtering and pagination - */ -inline Result> list(InMemoryStore& store, const ListOptions& options) { - std::vector scripts; - - for (const auto& [id, script] : store.lua_scripts) { - bool matches = true; - - if (options.filter.find("createdBy") != options.filter.end()) { - if (!script.createdBy.has_value() || script.createdBy.value() != options.filter.at("createdBy")) { - matches = false; - } - } - - if (options.filter.find("isSandboxed") != options.filter.end()) { - bool filter_sandboxed = options.filter.at("isSandboxed") == "true"; - if (script.isSandboxed != filter_sandboxed) matches = false; - } - - if (matches) { - scripts.push_back(script); - } - } - - if (options.sort.find("name") != options.sort.end()) { - std::sort(scripts.begin(), scripts.end(), [](const LuaScript& a, const LuaScript& b) { - return a.name < b.name; - }); - } else if (options.sort.find("createdAt") != options.sort.end()) { - std::sort(scripts.begin(), scripts.end(), [](const LuaScript& a, const LuaScript& b) { - return a.createdAt.value_or(std::chrono::system_clock::time_point()) < - b.createdAt.value_or(std::chrono::system_clock::time_point()); - }); - } - - int start = (options.page - 1) * options.limit; - int end = std::min(start + options.limit, static_cast(scripts.size())); - - if (start < static_cast(scripts.size())) { - return Result>(std::vector(scripts.begin() + start, scripts.begin() + end)); - } - - return Result>(std::vector()); -} - -} // namespace lua_script -} // namespace entities -} // namespace dbal - -#endif diff --git a/dbal/production/src/entities/lua_script/crud/search_lua_scripts.hpp b/dbal/production/src/entities/lua_script/crud/search_lua_scripts.hpp deleted file mode 100644 index 234531ed0..000000000 --- a/dbal/production/src/entities/lua_script/crud/search_lua_scripts.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef DBAL_SEARCH_LUA_SCRIPTS_HPP -#define DBAL_SEARCH_LUA_SCRIPTS_HPP - -#include "dbal/errors.hpp" -#include "../../../store/in_memory_store.hpp" -#include -#include -#include -#include -#include -#include - -namespace dbal { -namespace entities { -namespace lua_script { - -namespace { - -inline std::string toLower(const std::string& value) { - std::string lowered; - lowered.reserve(value.size()); - std::transform(value.begin(), value.end(), std::back_inserter(lowered), [](unsigned char c) { - return static_cast(std::tolower(c)); - }); - return lowered; -} - -inline bool containsInsensitive(const std::string& text, const std::string& query) { - if (query.empty()) { - return false; - } - return toLower(text).find(toLower(query)) != std::string::npos; -} - -} // namespace - -inline Result> search(InMemoryStore& store, - const std::string& query, - const std::optional& createdBy = std::nullopt, - int limit = 20) { - if (query.empty()) { - return Error::validationError("search query is required"); - } - - std::vector matches; - for (const auto& [id, script] : store.lua_scripts) { - (void)id; - if (createdBy.has_value() && (!script.createdBy.has_value() || script.createdBy.value() != createdBy.value())) { - continue; - } - if (containsInsensitive(script.name, query) || containsInsensitive(script.code, query)) { - matches.push_back(script); - } - } - - std::sort(matches.begin(), matches.end(), [](const LuaScript& a, const LuaScript& b) { - return a.name < b.name; - }); - - if (limit > 0 && static_cast(matches.size()) > limit) { - matches.resize(limit); - } - - return Result>(matches); -} - -} // namespace lua_script -} // namespace entities -} // namespace dbal - -#endif diff --git a/dbal/production/src/entities/lua_script/crud/update_lua_script.hpp b/dbal/production/src/entities/lua_script/crud/update_lua_script.hpp deleted file mode 100644 index 76d70327a..000000000 --- a/dbal/production/src/entities/lua_script/crud/update_lua_script.hpp +++ /dev/null @@ -1,113 +0,0 @@ -/** - * @file update_lua_script.hpp - * @brief Update Lua script operation - */ -#ifndef DBAL_UPDATE_LUA_SCRIPT_HPP -#define DBAL_UPDATE_LUA_SCRIPT_HPP - -#include "dbal/types.hpp" -#include "dbal/errors.hpp" -#include "../../../store/in_memory_store.hpp" -#include "../../../validation/entity/lua_script_validation.hpp" - -namespace dbal { -namespace entities { -namespace lua_script { - -/** - * Update an existing Lua script - */ -inline Result update(InMemoryStore& store, const std::string& id, const UpdateLuaScriptInput& input) { - if (id.empty()) { - return Error::validationError("Lua script ID cannot be empty"); - } - - auto it = store.lua_scripts.find(id); - if (it == store.lua_scripts.end()) { - return Error::notFound("Lua script not found: " + id); - } - - LuaScript& script = it->second; - std::string old_name = script.name; - - if (input.name.has_value()) { - if (!validation::isValidLuaScriptName(input.name.value())) { - return Error::validationError("Lua script name must be 1-255 characters"); - } - auto name_it = store.lua_script_names.find(input.name.value()); - if (name_it != store.lua_script_names.end() && name_it->second != id) { - return Error::conflict("Lua script name already exists: " + input.name.value()); - } - store.lua_script_names.erase(old_name); - store.lua_script_names[input.name.value()] = id; - script.name = input.name.value(); - } - - if (input.description.has_value()) { - script.description = input.description.value(); - } - - if (input.code.has_value()) { - if (!validation::isValidLuaScriptCode(input.code.value())) { - return Error::validationError("Lua script code must be a non-empty string"); - } - script.code = input.code.value(); - } - - if (input.parameters.has_value()) { - script.parameters = input.parameters.value(); - } - - if (input.returnType.has_value()) { - script.returnType = input.returnType.value(); - } - - if (input.isSandboxed.has_value()) { - script.isSandboxed = input.isSandboxed.value(); - } - - if (input.allowedGlobals.has_value()) { - std::string globals_error; - if (!validation::validateLuaAllowedGlobals(input.allowedGlobals.value(), globals_error)) { - return Error::validationError(globals_error); - } - script.allowedGlobals = input.allowedGlobals.value(); - } - - if (input.timeoutMs.has_value()) { - if (!validation::isValidLuaTimeout(input.timeoutMs.value())) { - return Error::validationError("Timeout must be between 100 and 30000 ms"); - } - script.timeoutMs = input.timeoutMs.value(); - } - - if (input.version.has_value()) { - script.version = input.version.value(); - } - - if (input.createdAt.has_value()) { - script.createdAt = input.createdAt.value(); - } - - if (input.updatedAt.has_value()) { - script.updatedAt = input.updatedAt.value(); - } else { - script.updatedAt = std::chrono::system_clock::now(); - } - - if (input.createdBy.has_value()) { - script.createdBy = input.createdBy.value(); - } - - if (input.tenantId.has_value()) { - script.tenantId = input.tenantId.value(); - } - - return Result(script); -} - -} // namespace lua_script -} // namespace entities -} // namespace dbal - -#endif diff --git a/dbal/production/src/entities/lua_script/index.hpp b/dbal/production/src/entities/lua_script/index.hpp deleted file mode 100644 index 2355fd2d7..000000000 --- a/dbal/production/src/entities/lua_script/index.hpp +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @file index.hpp - * @brief Barrel include for Lua script operations - */ -#ifndef DBAL_LUA_SCRIPT_INDEX_HPP -#define DBAL_LUA_SCRIPT_INDEX_HPP - -#include "crud/create_lua_script.hpp" -#include "crud/get_lua_script.hpp" -#include "crud/update_lua_script.hpp" -#include "crud/delete_lua_script.hpp" -#include "crud/list_lua_scripts.hpp" -#include "crud/search_lua_scripts.hpp" - -#endif diff --git a/dbal/production/src/store/in_memory_store.hpp b/dbal/production/src/store/in_memory_store.hpp index aa5090769..06d3849b0 100644 --- a/dbal/production/src/store/in_memory_store.hpp +++ b/dbal/production/src/store/in_memory_store.hpp @@ -24,7 +24,6 @@ struct InMemoryStore { std::map pages; std::map workflows; std::map sessions; - std::map lua_scripts; std::map packages; std::map credentials; @@ -32,7 +31,6 @@ struct InMemoryStore { std::map page_paths; // path -> id std::map workflow_names; // name -> id std::map session_tokens; // token -> id - std::map lua_script_names; // name -> id std::map package_keys; // packageId -> id // Entity counters for ID generation @@ -40,7 +38,6 @@ struct InMemoryStore { int page_counter = 0; int workflow_counter = 0; int session_counter = 0; - int lua_script_counter = 0; int package_counter = 0; int credential_counter = 0; @@ -69,8 +66,6 @@ struct InMemoryStore { workflow_names.clear(); sessions.clear(); session_tokens.clear(); - lua_scripts.clear(); - lua_script_names.clear(); packages.clear(); package_keys.clear(); credentials.clear(); @@ -82,7 +77,6 @@ struct InMemoryStore { page_counter = 0; workflow_counter = 0; session_counter = 0; - lua_script_counter = 0; package_counter = 0; credential_counter = 0; component_counter = 0; diff --git a/dbal/production/src/validation/entity/lua_script_validation.hpp b/dbal/production/src/validation/entity/lua_script_validation.hpp deleted file mode 100644 index 488ff562f..000000000 --- a/dbal/production/src/validation/entity/lua_script_validation.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/** - * @file lua_script_validation.hpp - * @brief Validation functions for LuaScript entity - */ -#ifndef DBAL_LUA_SCRIPT_VALIDATION_HPP -#define DBAL_LUA_SCRIPT_VALIDATION_HPP - -#include -#include - -namespace dbal { -namespace validation { - -/** - * Validate Lua script name (1-255 characters) - */ -inline bool isValidLuaScriptName(const std::string& name) { - return !name.empty() && name.length() <= 255; -} - -/** - * Validate Lua script code (non-empty) - */ -inline bool isValidLuaScriptCode(const std::string& code) { - return !code.empty(); -} - -/** - * Validate Lua script timeout (100-30000 ms) - */ -inline bool isValidLuaTimeout(int timeoutMs) { - return timeoutMs >= 100 && timeoutMs <= 30000; -} - -/** - * Check if a global name is allowed in the Lua sandbox - */ -inline bool isAllowedLuaGlobal(const std::string& name) { - static const std::unordered_set allowed = { - "assert", "error", "ipairs", "next", "pairs", "pcall", "select", - "tonumber", "tostring", "type", "unpack", "xpcall", - "string", "table", "math", "bit32", "print", "log" - }; - return allowed.find(name) != allowed.end(); -} - -/** - * Validate allowed globals list for Lua scripts - */ -inline bool validateLuaAllowedGlobals(const std::string& globals, std::string& error) { - if (globals.empty()) { - error = "allowedGlobals must be a JSON string"; - return false; - } - return true; -} - -} // namespace validation -} // namespace dbal - -#endif diff --git a/dbal/production/src/validation/lua_script_validation.hpp b/dbal/production/src/validation/lua_script_validation.hpp deleted file mode 100644 index c18c96900..000000000 --- a/dbal/production/src/validation/lua_script_validation.hpp +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -#include "entity/lua_script_validation.hpp" - diff --git a/dbal/production/src/validation/validation.hpp b/dbal/production/src/validation/validation.hpp index c699e054a..cebbe507d 100644 --- a/dbal/production/src/validation/validation.hpp +++ b/dbal/production/src/validation/validation.hpp @@ -10,9 +10,8 @@ #include "user_validation.hpp" #include "page_validation.hpp" #include "entity/component_validation.hpp" -#include "workflow_validation.hpp" -#include "lua_script_validation.hpp" -#include "package_validation.hpp" +#include "workflow_validation.hpp" +#include "package_validation.hpp" #include "entity/credential_validation.hpp" #endif diff --git a/dbal/production/tests/unit/client_test.cpp b/dbal/production/tests/unit/client_test.cpp index ca24b0988..d3c261ff2 100644 --- a/dbal/production/tests/unit/client_test.cpp +++ b/dbal/production/tests/unit/client_test.cpp @@ -1155,148 +1155,6 @@ void test_session_validation() { std::cout << " ✓ Duplicate token rejected" << std::endl; } -void test_lua_script_crud() { - std::cout << "Testing Lua script CRUD operations..." << std::endl; - - dbal::ClientConfig config; - config.adapter = "sqlite"; - config.database_url = ":memory:"; - dbal::Client client(config); - - dbal::CreateUserInput userInput; - userInput.username = "lua_owner"; - userInput.email = "lua_owner@example.com"; - auto userResult = client.createUser(userInput); - assert(userResult.isOk()); - - dbal::CreateLuaScriptInput input; - input.name = "health_check"; - input.description = "Health check"; - input.code = "return true"; - input.parameters = "[]"; - input.isSandboxed = true; - input.allowedGlobals = "[]"; - input.timeoutMs = 1000; - input.createdBy = userResult.value().id; - - auto createResult = client.createLuaScript(input); - assert(createResult.isOk()); - std::string scriptId = createResult.value().id; - std::cout << " ✓ Lua script created with ID: " << scriptId << std::endl; - - auto getResult = client.getLuaScript(scriptId); - assert(getResult.isOk()); - assert(getResult.value().name == "health_check"); - std::cout << " ✓ Retrieved Lua script by ID" << std::endl; - - dbal::UpdateLuaScriptInput updateInput; - updateInput.timeoutMs = 2000; - updateInput.isSandboxed = false; - auto updateResult = client.updateLuaScript(scriptId, updateInput); - assert(updateResult.isOk()); - assert(updateResult.value().timeoutMs == 2000); - std::cout << " ✓ Lua script updated" << std::endl; - - dbal::ListOptions listOptions; - listOptions.filter["isSandboxed"] = "false"; - auto listResult = client.listLuaScripts(listOptions); - assert(listResult.isOk()); - assert(listResult.value().size() >= 1); - std::cout << " ✓ Listed Lua scripts (filtered by isSandboxed=false)" << std::endl; - - auto deleteResult = client.deleteLuaScript(scriptId); - assert(deleteResult.isOk()); - - auto notFoundResult = client.getLuaScript(scriptId); - assert(notFoundResult.isError()); - std::cout << " ✓ Lua script deleted" << std::endl; -} - -void test_lua_script_validation() { - std::cout << "Testing Lua script validation..." << std::endl; - - dbal::ClientConfig config; - config.adapter = "sqlite"; - config.database_url = ":memory:"; - dbal::Client client(config); - - dbal::CreateUserInput userInput; - userInput.username = "lua_validator"; - userInput.email = "lua_validator@example.com"; - auto userResult = client.createUser(userInput); - assert(userResult.isOk()); - - dbal::CreateLuaScriptInput input1; - input1.name = "invalid-timeout"; - input1.code = "return true"; - input1.parameters = "[]"; - input1.isSandboxed = true; - input1.allowedGlobals = "[]"; - input1.timeoutMs = 50; - input1.createdBy = userResult.value().id; - auto result1 = client.createLuaScript(input1); - assert(result1.isError()); - assert(result1.error().code() == dbal::ErrorCode::ValidationError); - std::cout << " ✓ Invalid timeout rejected" << std::endl; - - dbal::CreateLuaScriptInput input2; - input2.name = "duplicate-script"; - input2.code = "return true"; - input2.parameters = "[]"; - input2.isSandboxed = true; - input2.allowedGlobals = "[]"; - input2.timeoutMs = 1000; - input2.createdBy = userResult.value().id; - auto result2 = client.createLuaScript(input2); - assert(result2.isOk()); - - dbal::CreateLuaScriptInput input3 = input2; - auto result3 = client.createLuaScript(input3); - assert(result3.isError()); - assert(result3.error().code() == dbal::ErrorCode::Conflict); - std::cout << " ✓ Duplicate script name rejected" << std::endl; -} - -void test_lua_script_search() { - std::cout << "Testing Lua script search..." << std::endl; - - dbal::ClientConfig config; - config.adapter = "sqlite"; - config.database_url = ":memory:"; - dbal::Client client(config); - - dbal::CreateUserInput userInput; - userInput.username = "lua_search_owner"; - userInput.email = "lua_search_owner@example.com"; - auto userResult = client.createUser(userInput); - assert(userResult.isOk()); - - dbal::CreateLuaScriptInput scriptInput; - scriptInput.name = "search_script"; - scriptInput.code = "return 'search'"; - scriptInput.parameters = "[]"; - scriptInput.allowedGlobals = "[]"; - scriptInput.createdBy = userResult.value().id; - auto createResult = client.createLuaScript(scriptInput); - assert(createResult.isOk()); - - dbal::CreateLuaScriptInput otherInput = scriptInput; - otherInput.name = "other_script"; - otherInput.code = "return 'other'"; - auto otherResult = client.createLuaScript(otherInput); - assert(otherResult.isOk()); - - auto searchResult = client.searchLuaScripts("search", userResult.value().id, 10); - assert(searchResult.isOk()); - assert(searchResult.value().size() == 1); - std::cout << " ✓ Script name search works" << std::endl; - - auto codeSearch = client.searchLuaScripts("return 'other'", std::nullopt, 10); - assert(codeSearch.isOk()); - assert(codeSearch.value().size() >= 1); - std::cout << " ✓ Script code search works" << std::endl; -} - void test_package_crud() { std::cout << "Testing package CRUD operations..." << std::endl; @@ -1316,7 +1174,7 @@ void test_package_crud() { input.version = "1.2.3"; input.installedAt = std::chrono::system_clock::now(); input.enabled = false; - input.config = "{\"entry\":\"index.lua\"}"; + input.config = "{\"entry\":\"index.js\"}"; auto createResult = client.createPackage(input); assert(createResult.isOk()); @@ -1498,9 +1356,6 @@ int main() { test_workflow_validation(); test_session_crud(); test_session_validation(); - test_lua_script_crud(); - test_lua_script_validation(); - test_lua_script_search(); test_package_crud(); test_package_validation(); test_package_batch_operations(); @@ -1508,7 +1363,7 @@ int main() { std::cout << std::endl; std::cout << "==================================================" << std::endl; - std::cout << "✅ All 33 test suites passed!" << std::endl; + std::cout << "✅ All test suites passed!" << std::endl; std::cout << "==================================================" << std::endl; return 0; } catch (const std::exception& e) { diff --git a/dbal/shared/common/contracts/conformance_cases.yaml b/dbal/shared/common/contracts/conformance_cases.yaml index 91ef23113..7e5bb3f0d 100644 --- a/dbal/shared/common/contracts/conformance_cases.yaml +++ b/dbal/shared/common/contracts/conformance_cases.yaml @@ -195,63 +195,6 @@ status: success output: true -- name: "LuaScript CRUD operations" - description: "Test basic create, read, update, delete operations for LuaScript entity" - operations: - - action: create - entity: User - input: - username: "lua_owner" - email: "lua_owner@example.com" - role: "admin" - expected: - status: success - - - action: create - entity: LuaScript - input: - name: "health_check" - description: "Simple health check" - code: "return true" - isSandboxed: true - allowedGlobals: ["math"] - timeoutMs: 1000 - createdBy: "$steps[0].id" - expected: - status: success - output: - name: "health_check" - isSandboxed: true - - - action: read - entity: LuaScript - input: - id: "$steps[1].id" - expected: - status: success - output: - name: "health_check" - - - action: update - entity: LuaScript - input: - id: "$steps[1].id" - isSandboxed: false - timeoutMs: 2000 - expected: - status: success - output: - isSandboxed: false - timeoutMs: 2000 - - - action: delete - entity: LuaScript - input: - id: "$steps[1].id" - expected: - status: success - output: true - - name: "Package CRUD operations" description: "Test basic create, read, update, delete operations for Package entity" operations: @@ -271,8 +214,8 @@ version: "1.2.3" description: "Forum package" author: "MetaBuilder" - manifest: - entry: "index.lua" + manifest: + entry: "index.js" isInstalled: false expected: status: success diff --git a/dbal/shared/docs/QUICK_START.md b/dbal/shared/docs/QUICK_START.md index b952ac42e..efbef1868 100644 --- a/dbal/shared/docs/QUICK_START.md +++ b/dbal/shared/docs/QUICK_START.md @@ -125,14 +125,13 @@ Check browser console for `[DBAL Audit]` logs. Full TypeScript support: ```typescript -import type { User, PageConfig, ComponentNode, Workflow, LuaScript, InstalledPackage, Session } from '../../dbal/development/src' +import type { User, PageConfig, ComponentNode, Workflow, InstalledPackage, Session } from '../../dbal/development/src' // Type-safe entities const user: User = await client.users.create({ ... }) const page: PageConfig = await client.pageConfigs.create({ ... }) const component: ComponentNode = await client.componentNodes.create({ ... }) const workflow: Workflow = await client.workflows.create({ ... }) -const script: LuaScript = await client.luaScripts.create({ ... }) const pkg: InstalledPackage = await client.installedPackages.create({ ... }) const session: Session = await client.sessions.create({ ... }) @@ -182,28 +181,6 @@ client.workflows.delete(id) client.workflows.list(options) ``` -### Lua Scripts -```typescript -client.luaScripts.create(data) -client.luaScripts.read(id) -client.luaScripts.update(id, data) -client.luaScripts.delete(id) -client.luaScripts.list(options) -``` - -```typescript -const script = await client.luaScripts.create({ - name: 'health_check', - description: 'Simple health check', - code: 'return true', - parameters: JSON.stringify([]), - isSandboxed: true, - allowedGlobals: JSON.stringify(['math']), - timeoutMs: 1000, - createdBy: '11111111-1111-1111-1111-111111111111', -}) -``` - ### Packages ```typescript client.installedPackages.create(data) diff --git a/frontends/nextjs/src/app/layout.tsx b/frontends/nextjs/src/app/layout.tsx index 259a5b855..1c27e0719 100644 --- a/frontends/nextjs/src/app/layout.tsx +++ b/frontends/nextjs/src/app/layout.tsx @@ -28,8 +28,8 @@ export const metadata: Metadata = { template: '%s | MetaBuilder', }, description: - 'A data-driven, multi-tenant application platform where 95% of functionality is defined through JSON and Lua.', - keywords: ['metabuilder', 'low-code', 'no-code', 'lua', 'platform', 'multi-tenant'], + 'A data-driven, multi-tenant platform where every experience is powered by JSON packages.', + keywords: ['metabuilder', 'low-code', 'no-code', 'platform', 'multi-tenant'], authors: [{ name: 'MetaBuilder Team' }], creator: 'MetaBuilder', icons: { diff --git a/frontends/nextjs/src/app/ui/[[...slug]]/page.tsx b/frontends/nextjs/src/app/ui/[[...slug]]/page.tsx index b338a4b61..07c7a48db 100644 --- a/frontends/nextjs/src/app/ui/[[...slug]]/page.tsx +++ b/frontends/nextjs/src/app/ui/[[...slug]]/page.tsx @@ -1,9 +1,9 @@ import type { Metadata } from 'next' import { notFound } from 'next/navigation' +import type { JSONComponent } from '@/lib/packages/json/types' import { UIPageRenderer } from '@/components/ui-page-renderer/UIPageRenderer' import { loadPageFromDb } from '@/lib/ui-pages/load-page-from-db' -import { loadPageFromLuaPackages } from '@/lib/ui-pages/load-page-from-lua-packages' interface PageProps { params: Promise<{ @@ -17,33 +17,32 @@ interface PageProps { * * Flow: * 1. JSON seed data → Database (via import-ui-pages.ts) - * 2. Database → Load page record - * 3. Lua actions → Execute if present - * 4. UIPageRenderer → Generate React components - * 5. User sees rendered page + * 2. Database → Load component tree + * 3. UIPageRenderer → Generate React components + * 4. User sees rendered page */ export default async function DynamicUIPage({ params }: PageProps) { const resolvedParams = await params const slug = resolvedParams.slug ?? [] const path = '/' + slug.join('/') - // Prefer Lua package-based UI pages, fallback to database-backed pages - const rawPageData = (await loadPageFromLuaPackages(path)) ?? (await loadPageFromDb(path)) + const rawPageData = await loadPageFromDb(path) if (rawPageData === null) { notFound() } - // Transform PageConfig to UIPageData - const pageData = { - layout: rawPageData, - actions: {}, + const componentTree = rawPageData.componentTree + if (componentTree === null || componentTree === undefined) { + notFound() } - // Check authentication if required - // TODO: Add auth check based on pageData.requireAuth and pageData.requiredRole + const layout = componentTree as JSONComponent + if (typeof layout !== 'object' || Array.isArray(layout)) { + notFound() + } - return + return } /** @@ -54,7 +53,7 @@ export async function generateMetadata({ params }: PageProps): Promise const slug = resolvedParams.slug ?? [] const path = '/' + slug.join('/') - const pageData = (await loadPageFromLuaPackages(path)) ?? (await loadPageFromDb(path)) + const pageData = await loadPageFromDb(path) if (pageData === null) { return { diff --git a/frontends/nextjs/src/components/ui-page-renderer/UIPageRenderer.tsx b/frontends/nextjs/src/components/ui-page-renderer/UIPageRenderer.tsx index 989062ea7..01244245a 100644 --- a/frontends/nextjs/src/components/ui-page-renderer/UIPageRenderer.tsx +++ b/frontends/nextjs/src/components/ui-page-renderer/UIPageRenderer.tsx @@ -2,28 +2,25 @@ import React from 'react' -import { generateComponentTree } from '@/lib/lua/ui/generate-component-tree' -import type { LuaUIComponent } from '@/lib/lua/ui/types/lua-ui-package' -import type { LuaActionHandler, UIPageData } from '@/lib/ui-pages/load-page-from-db' +import { renderJSONComponent } from '@/lib/packages/json/render-json-component' +import type { JSONComponent } from '@/lib/packages/json/types' + +type PageActionHandler = (action: string, data: Record) => void | Promise interface UIPageRendererProps { - pageData: UIPageData + layout: JSONComponent + actions?: Record } /** * Generic TSX renderer for database-loaded UI pages - * Flow: Database → Lua → This Component → React Elements → User + * Flow: Database → JSON component → React Elements → User */ -export function UIPageRenderer({ pageData }: UIPageRendererProps) { - // Convert JSON layout to LuaUIComponent structure - const layout = pageData.layout as LuaUIComponent +export function UIPageRenderer({ layout, actions = {} }: UIPageRendererProps) { + const elements = React.useMemo(() => renderJSONComponent(layout), [layout]) - // Create React elements from component tree - const elements = generateComponentTree(layout) - - // Provide action handlers via context return ( - + {elements} ) @@ -33,7 +30,7 @@ export function UIPageRenderer({ pageData }: UIPageRendererProps) { * Context for action handlers * Components can access these via useUIPageActions hook */ -const UIPageActionsContext = React.createContext>({}) +const UIPageActionsContext = React.createContext>({}) /** * Hook to access page action handlers diff --git a/frontends/nextjs/src/lib/lua/ui/generate-component-tree.tsx b/frontends/nextjs/src/lib/lua/ui/generate-component-tree.tsx deleted file mode 100644 index 19154cd78..000000000 --- a/frontends/nextjs/src/lib/lua/ui/generate-component-tree.tsx +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Generate React component tree from Lua UI component definitions - * - * Transforms LuaUIComponent structures into React elements using - * the JSON component renderer infrastructure. - */ - -import React, { type ReactNode } from 'react' -import type { LuaUIComponent } from './types/lua-ui-package' - -export interface ComponentTree { - type: string - props?: Record - children?: ComponentTree[] -} - -/** - * Map of basic HTML elements that can be rendered directly - */ -const HTML_ELEMENTS = new Set([ - 'div', 'span', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', - 'section', 'article', 'header', 'footer', 'main', 'aside', 'nav', - 'ul', 'ol', 'li', 'dl', 'dt', 'dd', - 'table', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', - 'form', 'input', 'button', 'select', 'option', 'textarea', 'label', - 'a', 'img', 'video', 'audio', 'canvas', 'svg', - 'strong', 'em', 'code', 'pre', 'blockquote', -]) - -/** - * Render a single LuaUIComponent to a React element - */ -function renderComponent(component: LuaUIComponent, key?: string | number): ReactNode { - const { type, props = {}, children } = component - - // Render children recursively - const renderedChildren = children?.map((child, index) => - renderComponent(child, index) - ) - - // Handle text content - if (type === 'text' && typeof props.content === 'string') { - return props.content - } - - // Handle HTML elements - if (HTML_ELEMENTS.has(type)) { - return React.createElement( - type, - { ...props, key }, - renderedChildren - ) - } - - // Handle custom components - wrap in div with data attribute for future component registry - return React.createElement( - 'div', - { - 'data-component': type, - className: `component-${type}`, - ...props, - key, - }, - renderedChildren ?? ( - - [{type}] - - ) - ) -} - -/** - * Generate a complete React component tree from a Lua UI component definition. - * - * @param luaComponent - The root LuaUIComponent to render - * @returns React node tree, or null if input is invalid - */ -export function generateComponentTree(luaComponent: unknown): ReactNode { - // Validate input - if (luaComponent === null || luaComponent === undefined) { - return null - } - - if (typeof luaComponent !== 'object') { - return null - } - - const component = luaComponent as LuaUIComponent - - // Must have a type to render - if (typeof component.type !== 'string' || component.type.length === 0) { - return ( -
- Invalid component: missing type -
- ) - } - - return renderComponent(component) -} diff --git a/frontends/nextjs/src/lib/lua/ui/types/lua-ui-package.ts b/frontends/nextjs/src/lib/lua/ui/types/lua-ui-package.ts deleted file mode 100644 index 10cfacdbc..000000000 --- a/frontends/nextjs/src/lib/lua/ui/types/lua-ui-package.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Lua UI types (stub) - */ - -export interface LuaUIComponent { - type: string - props?: Record - children?: LuaUIComponent[] -} - -export interface LuaUIPackage { - id: string - name: string - components: unknown[] -} diff --git a/frontends/nextjs/src/lib/ui-pages/load-page-from-db.ts b/frontends/nextjs/src/lib/ui-pages/load-page-from-db.ts index a01facee6..bd15cf41f 100644 --- a/frontends/nextjs/src/lib/ui-pages/load-page-from-db.ts +++ b/frontends/nextjs/src/lib/ui-pages/load-page-from-db.ts @@ -5,13 +5,6 @@ import type { PageConfig } from '../types/level-types' import { prisma } from '@/lib/config/prisma' -export type LuaActionHandler = (action: string, data: Record) => void | Promise - -export interface UIPageData { - layout: unknown - actions?: Record -} - export async function loadPageFromDb(path: string, tenantId?: string): Promise { // Prisma client typing is generated; suppress lint in environments without generated types. diff --git a/frontends/nextjs/src/lib/ui-pages/load-page-from-lua-packages.ts b/frontends/nextjs/src/lib/ui-pages/load-page-from-lua-packages.ts deleted file mode 100644 index 67abc73cc..000000000 --- a/frontends/nextjs/src/lib/ui-pages/load-page-from-lua-packages.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Load UI page from Lua packages (stub) - */ - -import type { PageConfig } from '../types/level-types' - -export function loadPageFromLuaPackages(_b_path: string): Promise { - // TODO: Implement page loading from Lua packages - return Promise.resolve(null) -}