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,13 @@
Zero-Clause BSD
=============
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,27 @@
## `jsc-safe-url`
JavaScriptCore santizes source URLs in error stacks by stripping query strings and fragments. Ref: [`Webkit/Webkit#49109d`](https://github.com/WebKit/WebKit/commit/49109db4ab87a715f7a8987c7ee380e63060298b).
This package contains utility functions required to implement the proposed [React Native Community RFC0646](https://github.com/react-native-community/discussions-and-proposals/pull/646). It exports three functons:
## `function isJscSafeUrl(url: string): boolean`
Returns `false` if the URL has a query component that could be stripped by JSC.
## `function toJscSafeUrl(urlToConvert: string): string`
Accepts an absolute or relative URL, and encodes any data in the input query string (if present) into the [path component](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) of the URL, by using the delimiter `//&` (which cannot appear in a normalized file path) to separate the original path from the orignal query string.
```
toJscSafeUrl('https://example.com/path?foo=bar#fragment')
// 'https://example.com/path//&foo=bar#fragment'
```
## `function toNormalUrl(urlToNormalize: string): string`
Accepts an absolute or relative URL, and replaces the first unescaped `//&` in the [path component](https://www.rfc-editor.org/rfc/rfc3986#section-3.3) with `?`. (Effectively the reverse of `toJscSafeUrl`.)
```
toNormalUrl('https://example.com/path//&foo=bar#fragment')
// 'https://example.com/path?foo=bar#fragment'
```

View File

@@ -0,0 +1,3 @@
export function isJscSafeUrl(url: string): boolean;
export function toNormalUrl(urlToNormalize: string): string;
export function toJscSafeUrl(urlToConvert: string): string;

View File

@@ -0,0 +1,96 @@
/**
* These functions are for handling of query-string free URLs, necessitated
* by query string stripping of URLs in JavaScriptCore stack traces
* introduced in iOS 16.4.
*
* See https://github.com/facebook/react-native/issues/36794 for context.
*
* @flow strict
*/
// We use regex-based URL parsing as defined in RFC3986 because it's easier to
// determine whether the input is a complete URI, a path-absolute or a
// path-rootless (as defined in the spec), and be as faithful to the input as
// possible. This will match any string, and does not imply validity.
//
// https://www.rfc-editor.org/rfc/rfc3986#appendix-B
const URI_REGEX = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
function _rfc3986Parse(url /*:string */) {
const match = url.match(URI_REGEX);
if (match == null) {
throw new Error("Unexpected error - failed to regex-match URL");
}
return {
schemeAndAuthority: (match[1] || "") + (match[3] || ""),
path: match[5] || "",
hasQueryPart: match[6] != null,
queryWithoutQuestionMark: match[7] || "",
fragmentWithHash: match[8] || "",
};
}
function isJscSafeUrl(url /*:string */) /*:boolean*/ {
const parsedUrl = _rfc3986Parse(url);
return !parsedUrl.hasQueryPart;
}
/**
* @param {string} urlToNormalize
* @returns string
*/
function toNormalUrl(urlToNormalize /*:string */) /*:string */ {
const parsedUrl = _rfc3986Parse(urlToNormalize);
if (parsedUrl.path.indexOf("//&") === -1) {
return urlToNormalize;
}
return (
parsedUrl.schemeAndAuthority +
parsedUrl.path.replace("//&", "?") +
// We don't expect JSC urls to also have query strings, but interpret
// liberally and append them.
(parsedUrl.queryWithoutQuestionMark.length > 0
? "&" + parsedUrl.queryWithoutQuestionMark
: "") +
// Likewise, JSC URLs will usually have their fragments stripped, but
// preserve if we find one.
parsedUrl.fragmentWithHash
);
}
/**
* @param {string} urlToConvert
* @returns string
*/
function toJscSafeUrl(urlToConvert /*:string */) /*:string */ {
if (!_rfc3986Parse(urlToConvert).hasQueryPart) {
return urlToConvert;
}
const parsedUrl = _rfc3986Parse(toNormalUrl(urlToConvert));
if (
parsedUrl.queryWithoutQuestionMark.length > 0 &&
(parsedUrl.path === "" || parsedUrl.path === "/")
) {
throw new Error(
`The given URL "${urlToConvert}" has an empty path and cannot be converted to a JSC-safe format.`
);
}
return (
parsedUrl.schemeAndAuthority +
parsedUrl.path +
(parsedUrl.queryWithoutQuestionMark.length > 0
? "//&" +
// Query strings may contain '?' (e.g. in key or value names) - these
// must be percent-encoded to form a valid path, and not be stripped.
parsedUrl.queryWithoutQuestionMark.replace(/\?/g, "%3F")
: "") +
// We expect JSC to strip this - we don't handle fragments for now.
parsedUrl.fragmentWithHash
);
}
module.exports = {
isJscSafeUrl,
toNormalUrl,
toJscSafeUrl,
};

View File

@@ -0,0 +1,32 @@
{
"name": "jsc-safe-url",
"version": "0.2.4",
"description": "Utility functions for converting to and from URLs that encode query string data into URL paths",
"main": "index.js",
"scripts": {
"test": "node --test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/robhogan/jsc-safe-url.git"
},
"keywords": [
"javascriptcore",
"metro",
"react-native"
],
"files": [
"index.js",
"index.d.ts"
],
"author": "Rob Hogan <npm@rhogan.net>",
"license": "0BSD",
"bugs": {
"url": "https://github.com/robhogan/jsc-safe-url/issues"
},
"homepage": "https://github.com/robhogan/jsc-safe-url#readme",
"devDependencies": {
"flow-bin": "^0.206.0",
"prettier": "^2.8.8"
}
}