diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index 5abb9f3..81e51cc 100644 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -1,14 +1,5 @@ // DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN -// Copy web assets to the native project -task copyWebApp(type: Copy) { - from '../../dist' - into 'src/main/assets/public' -} - -// Before building the app, run the copyWebApp task -preBuild.dependsOn copyWebApp - android { compileOptions { sourceCompatibility JavaVersion.VERSION_21 @@ -36,6 +27,7 @@ dependencies { implementation project(':capacitor-splash-screen') implementation project(':capacitor-status-bar') implementation project(':capacitor-toast') + implementation project(':capacitor-native-biometric') } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 1758740..92cd079 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -37,6 +37,22 @@ - + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..4574163 --- /dev/null +++ b/android/app/src/main/res/values/colors.xml @@ -0,0 +1,26 @@ + + + + #DC2626 + #0a0a0a + #D4AF37 + + + #0a0a0a + + + #0a0a0a + + + #0a0a0a + + + #DC2626 + #D4AF37 + #1a0505 + + + #3B82F6 + #C0C0C0 + #0f172a + diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index be874e5..911dbd8 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -2,21 +2,27 @@ - - \ No newline at end of file diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle index 36ac670..3879f65 100644 --- a/android/capacitor.settings.gradle +++ b/android/capacitor.settings.gradle @@ -55,3 +55,6 @@ project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacit include ':capacitor-toast' project(':capacitor-toast').projectDir = new File('../node_modules/@capacitor/toast/android') + +include ':capacitor-native-biometric' +project(':capacitor-native-biometric').projectDir = new File('../node_modules/capacitor-native-biometric/android') diff --git a/capacitor.config.ts b/capacitor.config.ts index 678f468..061fe4a 100644 --- a/capacitor.config.ts +++ b/capacitor.config.ts @@ -20,22 +20,23 @@ const config: CapacitorConfig = { }, plugins: { SplashScreen: { - launchShowDuration: 0, + launchShowDuration: 2000, launchAutoHide: true, - backgroundColor: '#000000', + launchFadeOutDuration: 500, + backgroundColor: '#0a0a0a', androidSplashResourceName: 'splash', androidScaleType: 'CENTER_CROP', - showSpinner: false, - androidSpinnerStyle: 'large', + showSpinner: true, + androidSpinnerStyle: 'small', iosSpinnerStyle: 'small', - spinnerColor: '#999999', + spinnerColor: '#DC2626', splashFullScreen: true, splashImmersive: true }, StatusBar: { style: 'DARK', - backgroundColor: '#000000', - overlaysWebView: true + backgroundColor: '#0a0a0a', + overlaysWebView: false }, App: { backButtonEnabled: true @@ -45,8 +46,18 @@ const config: CapacitorConfig = { }, LocalNotifications: { smallIcon: 'ic_stat_icon_config_sample', - iconColor: '#488AFF', + iconColor: '#DC2626', sound: 'beep.wav' + }, + Keyboard: { + resize: 'body', + resizeOnFullScreen: true, + style: 'dark' + }, + Haptics: { + selectionStart: true, + selectionChanged: true, + selectionEnd: true } }, android: { diff --git a/client/src/App.tsx b/client/src/App.tsx index 43a747e..3692d95 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -5,6 +5,7 @@ import { Toaster } from "@/components/ui/toaster"; import { AuthProvider } from "@/lib/auth"; import { TutorialProvider } from "@/components/Tutorial"; import { ProtectedRoute } from "@/components/ProtectedRoute"; +import { HapticProvider } from "@/components/mobile/HapticFeedback"; import NotFound from "@/pages/not-found"; import Home from "@/pages/home"; import Passport from "@/pages/passport"; @@ -114,12 +115,14 @@ function App() { return ( - - - - - - + + + + + + + + ); diff --git a/client/src/components/mobile/HapticButton.tsx b/client/src/components/mobile/HapticButton.tsx new file mode 100644 index 0000000..18426e2 --- /dev/null +++ b/client/src/components/mobile/HapticButton.tsx @@ -0,0 +1,37 @@ +import * as React from "react"; +import { Button, ButtonProps } from "@/components/ui/button"; +import { useHaptics } from "@/hooks/use-haptics"; + +export interface HapticButtonProps extends ButtonProps { + hapticStyle?: 'light' | 'medium' | 'heavy'; + hapticOnPress?: boolean; +} + +/** + * Button wrapper that adds haptic feedback on mobile devices. + * Falls back gracefully to normal button on web. + */ +export const HapticButton = React.forwardRef( + ({ hapticStyle = 'light', hapticOnPress = true, onClick, ...props }, ref) => { + const haptics = useHaptics(); + + const handleClick = (e: React.MouseEvent) => { + if (hapticOnPress) { + haptics.impact(hapticStyle); + } + onClick?.(e); + }; + + return ( + - - -

Code Gallery

+ {/* Header - hidden when embedded in OS iframe */} + {!embedded && ( +
+
+ + + + +

Code Gallery

+
+
- - + )}
diff --git a/client/src/pages/hub/file-manager.tsx b/client/src/pages/hub/file-manager.tsx index cf428f2..0326405 100644 --- a/client/src/pages/hub/file-manager.tsx +++ b/client/src/pages/hub/file-manager.tsx @@ -3,6 +3,7 @@ import { Link } from "wouter"; import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; import { ArrowLeft, FileText, Folder, Plus, Trash2, Download, Copy, Loader2 } from "lucide-react"; +import { isEmbedded } from "@/lib/embed-utils"; import { supabase } from "@/lib/supabase"; import { useAuth } from "@/lib/auth"; import { nanoid } from "nanoid"; @@ -70,23 +71,27 @@ export default function FileManager() { } }; + const embedded = isEmbedded(); + return (
- {/* Header */} -
-
- - - -

File Manager

+ {/* Header - hidden when embedded in OS iframe */} + {!embedded && ( +
+
+ + + +

File Manager

+
+
- -
+ )}
{/* File List */} diff --git a/client/src/pages/hub/game-marketplace.tsx b/client/src/pages/hub/game-marketplace.tsx index e7f5283..021c878 100644 --- a/client/src/pages/hub/game-marketplace.tsx +++ b/client/src/pages/hub/game-marketplace.tsx @@ -8,6 +8,7 @@ import { ArrowLeft, ShoppingCart, Star, Plus, Loader2, Gamepad2, Zap, Trophy, Users, DollarSign, TrendingUp, Filter, Search } from "lucide-react"; +import { isEmbedded } from "@/lib/embed-utils"; import { supabase } from "@/lib/supabase"; import { useAuth } from "@/lib/auth"; @@ -196,55 +197,59 @@ export default function GameMarketplace() { item.name.toLowerCase().includes(searchQuery.toLowerCase()) ); + const embedded = isEmbedded(); + return (
- {/* Header */} -
-
-
-
- - - -
- -

Game Marketplace

+ {/* Header - hidden when embedded in OS iframe */} + {!embedded && ( +
+
+
+
+ + + +
+ +

Game Marketplace

+
+
+ + {/* Wallet Balance */} +
+ + {wallet.balance} {wallet.currency}
- {/* Wallet Balance */} -
- - {wallet.balance} {wallet.currency} + {/* Search & Filter */} +
+
+ + setSearchQuery(e.target.value)} + className="pl-10 bg-slate-800 border-slate-700 text-white" + /> +
+
- - {/* Search & Filter */} -
-
- - setSearchQuery(e.target.value)} - className="pl-10 bg-slate-800 border-slate-700 text-white" - /> -
- -
-
+ )} {/* Main Content */}
diff --git a/client/src/pages/hub/game-streaming.tsx b/client/src/pages/hub/game-streaming.tsx index 3889853..75380f9 100644 --- a/client/src/pages/hub/game-streaming.tsx +++ b/client/src/pages/hub/game-streaming.tsx @@ -7,6 +7,7 @@ import { ArrowLeft, Radio, Eye, Heart, MessageCircle, Share2, Twitch, Youtube, Play, Clock, Users, TrendingUp, Filter, Search } from "lucide-react"; +import { isEmbedded } from "@/lib/embed-utils"; interface Stream { id: string; @@ -180,43 +181,47 @@ export default function GameStreaming() { const liveStreams = filteredStreams.filter(s => s.isLive); const recordedStreams = filteredStreams.filter(s => !s.isLive); + const embedded = isEmbedded(); + return (
- {/* Header */} -
-
-
- - - -

Game Streaming Hub

-
- - {/* Search & Filter */} -
-
- - setSearchQuery(e.target.value)} - className="w-full pl-10 pr-4 py-2 bg-slate-800 border border-slate-700 rounded-lg text-white text-sm placeholder-slate-400" - /> + {/* Header - hidden when embedded in OS iframe */} + {!embedded && ( +
+
+
+ + + +

Game Streaming Hub

+
+ + {/* Search & Filter */} +
+
+ + setSearchQuery(e.target.value)} + className="w-full pl-10 pr-4 py-2 bg-slate-800 border border-slate-700 rounded-lg text-white text-sm placeholder-slate-400" + /> +
+
-
-
+ )} {/* Stats */}
diff --git a/client/src/pages/hub/game-workshop.tsx b/client/src/pages/hub/game-workshop.tsx index 88018db..4673ad0 100644 --- a/client/src/pages/hub/game-workshop.tsx +++ b/client/src/pages/hub/game-workshop.tsx @@ -7,6 +7,7 @@ import { Trash2, Award, User, Calendar, Search, Filter, Plus, Loader2, Package, AlertCircle, CheckCircle } from "lucide-react"; +import { isEmbedded } from "@/lib/embed-utils"; interface Mod { id: string; @@ -199,69 +200,72 @@ export default function ModWorkshop() { const games = ["all", "Minecraft", "Roblox", "Steam Games", "All Games"]; + const embedded = isEmbedded(); + return (
- {/* Header */} -
-
-
-
- - - -
- -

Mod Workshop

+ {/* Header - hidden when embedded in OS iframe */} + {!embedded && ( +
+
+
+
+ + + +
+ +

Mod Workshop

+
-
- -
- - {/* Search & Filters */} -
-
-
- - setSearchQuery(e.target.value)} - className="w-full pl-10 pr-4 py-2 bg-slate-800 border border-slate-700 rounded-lg text-white text-sm placeholder-slate-400" - /> -
- + + Upload Mod + Upload +
- {/* Category & Game Filters */} -
+ {/* Search & Filters */} +
- {(["all", "gameplay", "cosmetic", "utility", "enhancement"] as const).map(cat => ( -
+ + {/* Category & Game Filters */} +
+
+ {(["all", "gameplay", "cosmetic", "utility", "enhancement"] as const).map(cat => ( + - -

Marketplace

-
-
-
-

Balance

-

{balance} LP

+ {/* Header - hidden when embedded in OS iframe */} + {!embedded && ( +
+
+
+ + + +

Marketplace

+
+
+
+

Balance

+

{balance} LP

+
+
-
-
+ )}
{/* Category Tabs */} diff --git a/client/src/pages/hub/messaging.tsx b/client/src/pages/hub/messaging.tsx index 09a7025..f80d377 100644 --- a/client/src/pages/hub/messaging.tsx +++ b/client/src/pages/hub/messaging.tsx @@ -5,6 +5,7 @@ import { Input } from "@/components/ui/input"; import { Card } from "@/components/ui/card"; import { ArrowLeft, Send, Search, Loader2 } from "lucide-react"; import { MobileHeader } from "@/components/mobile/MobileHeader"; +import { isEmbedded } from "@/lib/embed-utils"; import { supabase } from "@/lib/supabase"; import { useAuth } from "@/lib/auth"; import { nanoid } from "nanoid"; @@ -96,22 +97,29 @@ export default function Messaging() { c.username.toLowerCase().includes(searchQuery.toLowerCase()) ); + const embedded = isEmbedded(); + return (
- {/* Mobile Header */} -
- -
- - {/* Desktop Header */} -
- - - -

Messages

-
+ {/* Headers - hidden when embedded in OS iframe */} + {!embedded && ( + <> + {/* Mobile Header */} +
+ +
+ + {/* Desktop Header */} +
+ + + +

Messages

+
+ + )}
{/* Chat List */} diff --git a/client/src/pages/hub/projects.tsx b/client/src/pages/hub/projects.tsx index 1e511fa..5c6c28f 100644 --- a/client/src/pages/hub/projects.tsx +++ b/client/src/pages/hub/projects.tsx @@ -6,6 +6,7 @@ import { Card } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ArrowLeft, Plus, Trash2, ExternalLink, Github, Globe, Loader2 } from "lucide-react"; import { MobileHeader } from "@/components/mobile/MobileHeader"; +import { isEmbedded } from "@/lib/embed-utils"; import { supabase } from "@/lib/supabase"; import { useAuth } from "@/lib/auth"; import { nanoid } from "nanoid"; @@ -102,31 +103,38 @@ export default function Projects() { } }; + const embedded = isEmbedded(); + return (
- {/* Mobile Header */} -
- -
- - {/* Desktop Header */} -
-
- - - -

Projects & Portfolio

-
- -
+ {/* Headers - hidden when embedded in OS iframe */} + {!embedded && ( + <> + {/* Mobile Header */} +
+ +
+ + {/* Desktop Header */} +
+
+ + + +

Projects & Portfolio

+
+ +
+ + )}
{/* Add Project Form */} diff --git a/client/src/pages/hub/settings.tsx b/client/src/pages/hub/settings.tsx index e0f0569..da2f841 100644 --- a/client/src/pages/hub/settings.tsx +++ b/client/src/pages/hub/settings.tsx @@ -3,6 +3,7 @@ import { Link } from "wouter"; import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; import { ArrowLeft, Settings, Bell, Lock, Palette, HardDrive, User, Loader2 } from "lucide-react"; +import { isEmbedded } from "@/lib/embed-utils"; import { supabase } from "@/lib/supabase"; import { useAuth } from "@/lib/auth"; import { nanoid } from "nanoid"; @@ -88,18 +89,22 @@ export default function SettingsWorkspace() { saveSettings(newSettings); }; + const embedded = isEmbedded(); + return (
- {/* Header */} -
- - - - -

Workspace Settings

-
+ {/* Header - hidden when embedded in OS iframe */} + {!embedded && ( +
+ + + + +

Workspace Settings

+
+ )}
{/* Appearance Settings */} diff --git a/client/src/pages/os.tsx b/client/src/pages/os.tsx index 2472d2a..090b274 100644 --- a/client/src/pages/os.tsx +++ b/client/src/pages/os.tsx @@ -11,6 +11,8 @@ import { useMobileNative } from "@/hooks/use-mobile-native"; import { useNativeFeatures } from "@/hooks/use-native-features"; import { useBiometricAuth } from "@/hooks/use-biometric-auth"; import { StatusBar, Style } from '@capacitor/status-bar'; +import { App as CapacitorApp } from '@capacitor/app'; +import { isMobile } from '@/lib/platform'; import { MobileQuickActions } from "@/components/MobileQuickActions"; import { Minesweeper } from "@/components/games/Minesweeper"; import { CookieClicker } from "@/components/games/CookieClicker"; @@ -1215,131 +1217,162 @@ export default function AeThexOS() { }; }, [layout.isMobile]); + // Handle Android hardware back button + useEffect(() => { + if (!layout.isMobile || !isMobile()) return; + + const backHandler = CapacitorApp.addListener('backButton', () => { + // Get current active windows (non-minimized) + const activeWindows = windows.filter(w => !w.minimized); + + if (activeWindows.length > 0) { + // Close the topmost window + const topWindow = activeWindows[activeWindows.length - 1]; + closeWindow(topWindow.id); + impact('light'); + } else { + // No windows open - minimize app (don't exit) + CapacitorApp.minimizeApp(); + } + }); + + return () => { + backHandler.remove(); + }; + }, [layout.isMobile, windows, closeWindow, impact]); + // Native Android App Layout if (layout.isMobile) { const activeWindows = windows.filter(w => !w.minimized); const currentWindow = activeWindows[activeWindows.length - 1]; + + // Dynamic theme colors based on clearance mode + const isFoundation = clearanceMode === 'foundation'; + const mobileTheme = { + primary: isFoundation ? 'rgb(220, 38, 38)' : 'rgb(59, 130, 246)', // red-600 or blue-500 + secondary: isFoundation ? 'rgb(212, 175, 55)' : 'rgb(148, 163, 184)', // gold or slate-400 + primaryClass: isFoundation ? 'text-red-500' : 'text-blue-500', + secondaryClass: isFoundation ? 'text-amber-400' : 'text-slate-300', + borderClass: isFoundation ? 'border-red-900/50' : 'border-blue-900/50', + bgAccent: isFoundation ? 'bg-red-900/20' : 'bg-blue-900/20', + iconClass: isFoundation ? 'text-red-400' : 'text-blue-400', + gradientBg: isFoundation + ? 'linear-gradient(135deg, #0a0a0a 0%, #1a0505 50%, #0a0a0a 100%)' + : 'linear-gradient(135deg, #0a0a0a 0%, #050a14 50%, #0a0a0a 100%)', + }; return ( -
- - - {/* Ingress Status Bar - Minimal */} -
-
+
+ {/* AeThex Mobile Status Bar */} +
- - -
- {[...Array(4)].map((_, i) => ( -
- ))} -
+ AeThex + + {isFoundation ? 'FOUNDATION' : 'CORP'} + +
-
+
+ {batteryInfo?.level || 100}% - - {time.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} + + {time.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
{/* Main Content */} -
- +
+ {currentWindow ? ( - // Fullscreen App View with 3D Card Flip - {/* Ingress Style - Minimal App Bar */} -
-
-
-
-
- -
-

- {currentWindow.title} -

-
- + {/* App Header */} +
+ +
+

{currentWindow.title}

+
{/* App Content */} -
+
{renderAppContent(currentWindow.component)}
) : ( - // ULTRA FUTURISTIC LAUNCHER + // Home Launcher - {/* Ingress Style Search Bar */} -
-
-
-
- + {/* Header with Theme Toggle */} +
+
+

+ {isFoundation ? 'The Foundation' : 'The Corporation'} +

+

Welcome back, Architect

+
+ +
+ + {/* Search Bar */} +
+
+
+ impact('light')} /> -
- {/* App Grid - Hexagonal */} -
+ {/* App Grid */} +
-
-
-

- Quick Access -

-
+
+
+

Quick Access

+
-
+
{apps.slice(0, 8).map((app) => ( @@ -1364,14 +1393,12 @@ export default function AeThexOS() {
- {/* All Apps - Minimal List */} + {/* All Apps List */}
-
-
-

- All Systems -

-
+
+
+

All Apps

+
{apps.slice(8).map((app) => ( @@ -1381,13 +1408,13 @@ export default function AeThexOS() { impact('medium'); openApp(app); }} - className="relative w-full flex items-center gap-3 p-3 border border-emerald-500/30 active:bg-emerald-500/10 active:border-cyan-500" + className={`w-full flex items-center gap-4 p-3 rounded-xl bg-zinc-900/40 border border-zinc-800/40 active:${mobileTheme.bgAccent} active:${mobileTheme.borderClass}`} > -
-
{app.icon}
+
+
{app.icon}
- {app.title} - + {app.title} + ))}
@@ -1398,30 +1425,27 @@ export default function AeThexOS() {
- {/* INGRESS STYLE NAVIGATION BAR - Lightweight */} + {/* Bottom Navigation */}
-
-
+
- {/* Floating Action Button with Orbital Menu */} + {/* Floating Quick Actions */}
); diff --git a/package-lock.json b/package-lock.json index dfbedfe..a35de68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,6 +65,7 @@ "@tanstack/react-query": "^5.60.5", "@types/bcrypt": "^6.0.0", "bcrypt": "^6.0.0", + "capacitor-native-biometric": "^4.2.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", @@ -186,6 +187,7 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -566,6 +568,7 @@ "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-8.0.2.tgz", "integrity": "sha512-EXZfxkL6GFJS2cb7TIBR7RiHA5iz6ufDcl1VmUpI2pga3lJ5Ck2+iqbx7N+osL3XYem9ad4XCidJEMm64DX6UQ==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -4832,6 +4835,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -4875,6 +4879,7 @@ "integrity": "sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "@types/node": "*", "pg-protocol": "*", @@ -4907,6 +4912,7 @@ "integrity": "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -4917,6 +4923,7 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -5088,6 +5095,7 @@ "integrity": "sha512-CGJ25bc8fRi8Lod/3GHSvXRKi7nBo3kxh0ApW4yCjmrWmRmlT53B5E08XRSZRliygG0aVNxLrBEqPYdz/KcCtQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/utils": "4.0.18", "fflate": "^0.8.2", @@ -5419,6 +5427,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -5449,20 +5458,6 @@ "dev": true, "license": "MIT" }, - "node_modules/bufferutil": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz", - "integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -5522,6 +5517,24 @@ ], "license": "CC-BY-4.0" }, + "node_modules/capacitor-native-biometric": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/capacitor-native-biometric/-/capacitor-native-biometric-4.2.2.tgz", + "integrity": "sha512-stg0h48UxgkNuNcCAgCXLp2DUspRQs79bCBPntpCBhsDxk2bhDRUu+J/QpFtDQHG4M4DioSUcYaAsVw2N6N7wA==", + "license": "MIT", + "dependencies": { + "@capacitor/core": "^3.4.3" + } + }, + "node_modules/capacitor-native-biometric/node_modules/@capacitor/core": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-3.9.0.tgz", + "integrity": "sha512-j1lL0+/7stY8YhIq1Lm6xixvUqIn89vtyH5ZpJNNmcZ0kwz6K9eLkcG6fvq1UWMDgSVZg9JrRGSFhb4LLoYOsw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/chai": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", @@ -6047,6 +6060,7 @@ "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.39.3.tgz", "integrity": "sha512-EZ8ZpYvDIvKU9C56JYLOmUskazhad+uXZCTCRN4OnRMsL+xAJ05dv1eCpAG5xzhsm1hqiuC5kAZUCS924u2DTw==", "license": "Apache-2.0", + "peer": true, "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", @@ -6212,7 +6226,8 @@ "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/embla-carousel-react": { "version": "8.6.0", @@ -6402,6 +6417,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -7608,6 +7624,7 @@ "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", "license": "MIT", + "peer": true, "dependencies": { "dompurify": "3.2.7", "marked": "14.0.0" @@ -7940,6 +7957,7 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.18.0.tgz", "integrity": "sha512-xqrUDL1b9MbkydY/s+VZ6v+xiMUmOUk7SS9d/1kpyQxoJ6U9AO1oIJyUWVZojbfe5Cc/oluutcgFG4L9RDP1iQ==", "license": "MIT", + "peer": true, "dependencies": { "pg-connection-string": "^2.11.0", "pg-pool": "^3.11.0", @@ -8037,6 +8055,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -8108,6 +8127,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -8274,6 +8294,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -8314,6 +8335,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -8326,6 +8348,7 @@ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.71.1.tgz", "integrity": "sha512-9SUJKCGKo8HUSsCO+y0CtqkqI5nNuaDqTxyqPsZPqIwudpj4rCrAz/jZV+jn57bx5gtZKOh3neQu94DXMc+w5w==", "license": "MIT", + "peer": true, "engines": { "node": ">=18.0.0" }, @@ -9100,7 +9123,8 @@ "version": "4.1.18", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tailwindcss-animate": { "version": "1.0.7", @@ -9826,6 +9850,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9968,6 +9993,7 @@ "integrity": "sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA==", "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "node-gyp-build": "^4.3.0" }, @@ -10055,6 +10081,7 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -10614,6 +10641,7 @@ "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/expect": "4.0.18", "@vitest/mocker": "4.0.18", @@ -10888,6 +10916,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index d76fd2c..69dabfc 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,11 @@ "start": "NODE_ENV=production node dist/index.js", "check": "tsc", "db:push": "drizzle-kit push", - "tauri": "cd shell/aethex-shell && npm run tauri", - "tauri:dev": "cd shell/aethex-shell && npm run tauri dev", - "tauri:build": "cd shell/aethex-shell && npm run tauri build", - "audit:org-scope": "tsx script/org-scope-audit.ts", - "test:org-scope": "tsx --test server/org-scoping.test.ts" + "tauri": "cd shell/aethex-shell && npm run tauri", + "tauri:dev": "cd shell/aethex-shell && npm run tauri dev", + "tauri:build": "cd shell/aethex-shell && npm run tauri build", + "audit:org-scope": "tsx script/org-scope-audit.ts", + "test:org-scope": "tsx --test server/org-scoping.test.ts" }, "dependencies": { "@capacitor-community/privacy-screen": "^6.0.0", @@ -83,6 +83,7 @@ "@tanstack/react-query": "^5.60.5", "@types/bcrypt": "^6.0.0", "bcrypt": "^6.0.0", + "capacitor-native-biometric": "^4.2.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1",