feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,37 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
add_compile_options(-std=c++20)
file(GLOB_RECURSE hermes_executor_SRC CONFIGURE_DEPENDS *.cpp)
add_library(
hermes_executor_common
STATIC
${hermes_executor_SRC}
)
target_include_directories(hermes_executor_common PUBLIC .)
target_link_libraries(hermes_executor_common
jsireact
hermes-engine::libhermes
jsi
hermes_inspector_modern
)
if(${CMAKE_BUILD_TYPE} MATCHES Debug)
target_compile_options(
hermes_executor_common
PRIVATE
-DHERMES_ENABLE_DEBUGGER=1
)
else()
target_compile_options(
hermes_executor_common
PRIVATE
-DNDEBUG
)
endif()

View File

@@ -0,0 +1,292 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "HermesExecutorFactory.h"
#include <thread>
#include <cxxreact/MessageQueueThread.h>
#include <cxxreact/SystraceSection.h>
#include <hermes/hermes.h>
#include <jsi/decorator.h>
#include <jsinspector-modern/InspectorFlags.h>
#include <hermes/inspector-modern/chrome/HermesRuntimeAgentDelegate.h>
#include <hermes/inspector-modern/chrome/Registration.h>
#include <hermes/inspector/RuntimeAdapter.h>
using namespace facebook::hermes;
using namespace facebook::jsi;
namespace facebook::react {
namespace {
#ifdef HERMES_ENABLE_DEBUGGER
class HermesExecutorRuntimeAdapter
: public facebook::hermes::inspector_modern::RuntimeAdapter {
public:
HermesExecutorRuntimeAdapter(
std::shared_ptr<HermesRuntime> runtime,
std::shared_ptr<MessageQueueThread> thread)
: runtime_(runtime), thread_(std::move(thread)) {}
virtual ~HermesExecutorRuntimeAdapter() = default;
HermesRuntime& getRuntime() override {
return *runtime_;
}
void tickleJs() override {
thread_->runOnQueue(
[weakRuntime = std::weak_ptr<HermesRuntime>(runtime_)]() {
auto runtime = weakRuntime.lock();
if (!runtime) {
return;
}
jsi::Function func =
runtime->global().getPropertyAsFunction(*runtime, "__tickleJs");
func.call(*runtime);
});
}
private:
std::shared_ptr<HermesRuntime> runtime_;
std::shared_ptr<MessageQueueThread> thread_;
};
#endif // HERMES_ENABLE_DEBUGGER
struct ReentrancyCheck {
// This is effectively a very subtle and complex assert, so only
// include it in builds which would include asserts.
#ifndef NDEBUG
ReentrancyCheck() : tid(std::thread::id()), depth(0) {}
void before() {
std::thread::id this_id = std::this_thread::get_id();
std::thread::id expected = std::thread::id();
// A note on memory ordering: the main purpose of these checks is
// to observe a before/before race, without an intervening after.
// This will be detected by the compare_exchange_strong atomicity
// properties, regardless of memory order.
//
// For everything else, it is easiest to think of 'depth' as a
// proxy for any access made inside the VM. If access to depth
// are reordered incorrectly, the same could be true of any other
// operation made by the VM. In fact, using acquire/release
// memory ordering could create barriers which mask a programmer
// error. So, we use relaxed memory order, to avoid masking
// actual ordering errors. Although, in practice, ordering errors
// of this sort would be surprising, because the decorator would
// need to call after() without before().
if (tid.compare_exchange_strong(
expected, this_id, std::memory_order_relaxed)) {
// Returns true if tid and expected were the same. If they
// were, then the stored tid referred to no thread, and we
// atomically saved this thread's tid. Now increment depth.
assert(depth == 0 && "No thread id, but depth != 0");
++depth;
} else if (expected == this_id) {
// If the stored tid referred to a thread, expected was set to
// that value. If that value is this thread's tid, that's ok,
// just increment depth again.
assert(depth != 0 && "Thread id was set, but depth == 0");
++depth;
} else {
// The stored tid was some other thread. This indicates a bad
// programmer error, where VM methods were called on two
// different threads unsafely. Fail fast (and hard) so the
// crash can be analyzed.
__builtin_trap();
}
}
void after() {
assert(
tid.load(std::memory_order_relaxed) == std::this_thread::get_id() &&
"No thread id in after()");
if (--depth == 0) {
// If we decremented depth to zero, store no-thread into tid.
std::thread::id expected = std::this_thread::get_id();
bool didWrite = tid.compare_exchange_strong(
expected, std::thread::id(), std::memory_order_relaxed);
assert(didWrite && "Decremented to zero, but no tid write");
}
}
std::atomic<std::thread::id> tid;
// This is not atomic, as it is only written or read from the owning
// thread.
unsigned int depth;
#endif
};
// This adds ReentrancyCheck and debugger enable/teardown to the given
// Runtime.
class DecoratedRuntime : public jsi::WithRuntimeDecorator<ReentrancyCheck> {
public:
// The first argument may be another decorater which itself
// decorates the real HermesRuntime, depending on the build config.
// The second argument is the real HermesRuntime as well to
// manage the debugger registration.
DecoratedRuntime(
std::unique_ptr<Runtime> runtime,
HermesRuntime& hermesRuntime,
std::shared_ptr<MessageQueueThread> jsQueue,
bool enableDebugger,
const std::string& debuggerName)
: jsi::WithRuntimeDecorator<ReentrancyCheck>(*runtime, reentrancyCheck_),
runtime_(std::move(runtime)) {
#ifdef HERMES_ENABLE_DEBUGGER
enableDebugger_ = enableDebugger;
if (enableDebugger_) {
std::shared_ptr<HermesRuntime> rt(runtime_, &hermesRuntime);
auto adapter =
std::make_unique<HermesExecutorRuntimeAdapter>(rt, jsQueue);
debugToken_ = facebook::hermes::inspector_modern::chrome::enableDebugging(
std::move(adapter), debuggerName);
}
#endif // HERMES_ENABLE_DEBUGGER
}
~DecoratedRuntime() {
#ifdef HERMES_ENABLE_DEBUGGER
if (enableDebugger_) {
facebook::hermes::inspector_modern::chrome::disableDebugging(debugToken_);
}
#endif // HERMES_ENABLE_DEBUGGER
}
private:
// runtime_ is a potentially decorated Runtime.
// hermesRuntime is a reference to a HermesRuntime managed by runtime_.
//
// HermesExecutorRuntimeAdapter requirements are kept, because the
// dtor will disable debugging on the HermesRuntime before the
// member managing it is destroyed.
std::shared_ptr<Runtime> runtime_;
ReentrancyCheck reentrancyCheck_;
#ifdef HERMES_ENABLE_DEBUGGER
bool enableDebugger_;
facebook::hermes::inspector_modern::chrome::DebugSessionToken debugToken_;
#endif // HERMES_ENABLE_DEBUGGER
};
} // namespace
void HermesExecutorFactory::setEnableDebugger(bool enableDebugger) {
enableDebugger_ = enableDebugger;
}
void HermesExecutorFactory::setDebuggerName(const std::string& debuggerName) {
debuggerName_ = debuggerName;
}
std::unique_ptr<JSExecutor> HermesExecutorFactory::createJSExecutor(
std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> jsQueue) {
std::unique_ptr<HermesRuntime> hermesRuntime;
{
SystraceSection s("makeHermesRuntime");
hermesRuntime = hermes::makeHermesRuntime(runtimeConfig_);
}
HermesRuntime& hermesRuntimeRef = *hermesRuntime;
auto& inspectorFlags = jsinspector_modern::InspectorFlags::getInstance();
bool enableDebugger =
!inspectorFlags.getEnableModernCDPRegistry() && enableDebugger_;
auto decoratedRuntime = std::make_shared<DecoratedRuntime>(
std::move(hermesRuntime),
hermesRuntimeRef,
jsQueue,
enableDebugger,
debuggerName_);
// So what do we have now?
// DecoratedRuntime -> HermesRuntime
//
// DecoratedRuntime is held by JSIExecutor. When it gets used, it
// will check that it's on the right thread, do any necessary trace
// logging, then call the real HermesRuntime. When it is destroyed,
// it will shut down the debugger before the HermesRuntime is. In
// the normal case where debugging is not compiled in,
// all that's left is the thread checking.
// Add js engine information to Error.prototype so in error reporting we
// can send this information.
auto errorPrototype =
decoratedRuntime->global()
.getPropertyAsObject(*decoratedRuntime, "Error")
.getPropertyAsObject(*decoratedRuntime, "prototype");
errorPrototype.setProperty(*decoratedRuntime, "jsEngine", "hermes");
return std::make_unique<HermesExecutor>(
decoratedRuntime,
delegate,
jsQueue,
timeoutInvoker_,
runtimeInstaller_,
hermesRuntimeRef);
}
::hermes::vm::RuntimeConfig HermesExecutorFactory::defaultRuntimeConfig() {
return ::hermes::vm::RuntimeConfig::Builder()
.withEnableSampleProfiling(true)
.build();
}
HermesExecutor::HermesExecutor(
std::shared_ptr<jsi::Runtime> runtime,
std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> jsQueue,
const JSIScopedTimeoutInvoker& timeoutInvoker,
RuntimeInstaller runtimeInstaller,
HermesRuntime& hermesRuntime)
: JSIExecutor(runtime, delegate, timeoutInvoker, runtimeInstaller),
jsQueue_(jsQueue),
runtime_(runtime),
hermesRuntime_(hermesRuntime) {}
std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate>
HermesExecutor::createAgentDelegate(
jsinspector_modern::FrontendChannel frontendChannel,
jsinspector_modern::SessionState& sessionState,
std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate::ExportedState>
previouslyExportedState,
const jsinspector_modern::ExecutionContextDescription&
executionContextDescription) {
std::shared_ptr<HermesRuntime> hermesRuntimeShared(runtime_, &hermesRuntime_);
return std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate>(
new jsinspector_modern::HermesRuntimeAgentDelegate(
frontendChannel,
sessionState,
std::move(previouslyExportedState),
executionContextDescription,
hermesRuntimeShared,
[jsQueueWeak = std::weak_ptr(jsQueue_),
runtimeWeak = std::weak_ptr(runtime_)](auto fn) {
auto jsQueue = jsQueueWeak.lock();
if (!jsQueue) {
return;
}
jsQueue->runOnQueue([runtimeWeak, fn]() {
auto runtime = runtimeWeak.lock();
if (!runtime) {
return;
}
fn(*runtime);
});
}));
}
} // namespace facebook::react

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <hermes/hermes.h>
#include <jsireact/JSIExecutor.h>
#include <utility>
namespace facebook::react {
class HermesExecutorFactory : public JSExecutorFactory {
public:
explicit HermesExecutorFactory(
JSIExecutor::RuntimeInstaller runtimeInstaller,
const JSIScopedTimeoutInvoker& timeoutInvoker =
JSIExecutor::defaultTimeoutInvoker,
::hermes::vm::RuntimeConfig runtimeConfig = defaultRuntimeConfig())
: runtimeInstaller_(runtimeInstaller),
timeoutInvoker_(timeoutInvoker),
runtimeConfig_(std::move(runtimeConfig)) {
assert(timeoutInvoker_ && "Should not have empty timeoutInvoker");
}
void setEnableDebugger(bool enableDebugger);
void setDebuggerName(const std::string& debuggerName);
std::unique_ptr<JSExecutor> createJSExecutor(
std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> jsQueue) override;
private:
static ::hermes::vm::RuntimeConfig defaultRuntimeConfig();
JSIExecutor::RuntimeInstaller runtimeInstaller_;
JSIScopedTimeoutInvoker timeoutInvoker_;
::hermes::vm::RuntimeConfig runtimeConfig_;
bool enableDebugger_ = true;
std::string debuggerName_ = "Hermes React Native";
};
class HermesExecutor : public JSIExecutor {
public:
HermesExecutor(
std::shared_ptr<jsi::Runtime> runtime,
std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> jsQueue,
const JSIScopedTimeoutInvoker& timeoutInvoker,
RuntimeInstaller runtimeInstaller,
hermes::HermesRuntime& hermesRuntime);
virtual std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate>
createAgentDelegate(
jsinspector_modern::FrontendChannel frontendChannel,
jsinspector_modern::SessionState& sessionState,
std::unique_ptr<jsinspector_modern::RuntimeAgentDelegate::ExportedState>
previouslyExportedState,
const jsinspector_modern::ExecutionContextDescription&
executionContextDescription) override;
private:
JSIScopedTimeoutInvoker timeoutInvoker_;
std::shared_ptr<MessageQueueThread> jsQueue_;
std::shared_ptr<jsi::Runtime> runtime_;
hermes::HermesRuntime& hermesRuntime_;
};
} // namespace facebook::react

View File

@@ -0,0 +1,41 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require "json"
package = JSON.parse(File.read(File.join(__dir__, "../../..", "package.json")))
version = package['version']
source = { :git => 'https://github.com/facebook/react-native.git' }
if version == '1000.0.0'
# This is an unpublished version, use the latest commit hash of the react-native repo, which were presumably in.
source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1")
else
source[:tag] = "v#{version}"
end
Pod::Spec.new do |s|
s.name = "React-jsitracing"
s.version = version
s.summary = "Internal library for JSI debugging."
s.homepage = "https://reactnative.dev/"
s.license = package["license"]
s.author = "Meta Platforms, Inc. and its affiliates"
s.platforms = min_supported_versions
s.source = source
s.source_files = "JSITracing.{cpp,h}"
s.header_dir = "."
s.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"${PODS_TARGET_SRCROOT}/../..\"",
"USE_HEADERMAP" => "YES",
"CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
"GCC_WARN_PEDANTIC" => "YES" }
if ENV['USE_FRAMEWORKS']
s.header_mappings_dir = './'
s.module_name = 'React_jsitracing'
end
s.dependency "React-jsi"
end