From 577ef68dadff1751c0e4a35cbfd911725cc3c6a7 Mon Sep 17 00:00:00 2001 From: MrPiglr <31398225+MrPiglr@users.noreply.github.com> Date: Sun, 7 Dec 2025 00:17:04 +0000 Subject: [PATCH] Sync local changes --- .github/workflows/desktop-release.yml | 135 +++++ .replit | 6 + ...r-win-config-electron-bu_1765007431411.txt | 95 +++ ...r-win-config-electron-bu_1765007500661.txt | 95 +++ ...nfig-electron-builder-ym_1765007031609.txt | 75 +++ ...nfig-electron-builder-ym_1765007959498.txt | 75 +++ attached_assets/image_1765005879621.png | Bin 0 -> 51834 bytes client/App.tsx | 16 +- client/components/MaintenanceGuard.tsx | 33 ++ client/components/admin/MaintenanceToggle.tsx | 111 ++++ client/contexts/MaintenanceContext.tsx | 104 ++++ client/pages/Admin.tsx | 3 + client/pages/Maintenance.tsx | 159 +++++ discord-bot/bot.js | 2 +- package-lock.json | 554 ++++++++++++++++++ package.json | 2 + replit.md | 2 + server/index.ts | 123 ++++ 18 files changed, 1584 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/desktop-release.yml create mode 100644 attached_assets/Pasted-17s-12s-Run-npx-electron-builder-win-config-electron-bu_1765007431411.txt create mode 100644 attached_assets/Pasted-17s-12s-Run-npx-electron-builder-win-config-electron-bu_1765007500661.txt create mode 100644 attached_assets/Pasted-Run-npx-electron-builder-win-config-electron-builder-ym_1765007031609.txt create mode 100644 attached_assets/Pasted-Run-npx-electron-builder-win-config-electron-builder-ym_1765007959498.txt create mode 100644 attached_assets/image_1765005879621.png create mode 100644 client/components/MaintenanceGuard.tsx create mode 100644 client/components/admin/MaintenanceToggle.tsx create mode 100644 client/contexts/MaintenanceContext.tsx create mode 100644 client/pages/Maintenance.tsx diff --git a/.github/workflows/desktop-release.yml b/.github/workflows/desktop-release.yml new file mode 100644 index 00000000..d5fbc199 --- /dev/null +++ b/.github/workflows/desktop-release.yml @@ -0,0 +1,135 @@ +name: Build Desktop App + +on: + push: + tags: + - 'v*' + workflow_dispatch: + inputs: + version: + description: 'Version to build (e.g., 0.1.0)' + required: false + default: '' + +permissions: + contents: write + +jobs: + build-windows: + runs-on: windows-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build desktop renderer + run: npm run build:desktop + + - name: Build Windows installer + run: npx electron-builder --win --config electron-builder.yml + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload Windows artifact + uses: actions/upload-artifact@v4 + with: + name: windows-build + path: dist/*.exe + retention-days: 5 + + build-macos: + runs-on: macos-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build desktop renderer + run: npm run build:desktop + + - name: Build macOS installer + run: npx electron-builder --mac --config electron-builder.yml + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload macOS artifact + uses: actions/upload-artifact@v4 + with: + name: macos-build + path: dist/*.dmg + retention-days: 5 + + build-linux: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build desktop renderer + run: npm run build:desktop + + - name: Build Linux installers + run: npx electron-builder --linux --config electron-builder.yml + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload Linux artifacts + uses: actions/upload-artifact@v4 + with: + name: linux-build + path: | + dist/*.AppImage + dist/*.deb + retention-days: 5 + + release: + needs: [build-windows, build-macos, build-linux] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Display downloaded files + run: ls -R artifacts + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + draft: false + prerelease: ${{ contains(github.ref_name, 'beta') || contains(github.ref_name, 'alpha') }} + generate_release_notes: true + files: | + artifacts/windows-build/*.exe + artifacts/macos-build/*.dmg + artifacts/linux-build/*.AppImage + artifacts/linux-build/*.deb + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.replit b/.replit index db76c62c..9a438068 100644 --- a/.replit +++ b/.replit @@ -5,6 +5,7 @@ integrations = ["javascript_gemini_ai_integrations:1.0.0"] [nix] channel = "stable-25_05" +packages = ["imagemagick"] [workflows] runButton = "Project" @@ -53,6 +54,10 @@ externalPort = 80 localPort = 8044 externalPort = 3003 +[[ports]] +localPort = 8080 +externalPort = 8080 + [[ports]] localPort = 38557 externalPort = 3000 @@ -70,3 +75,4 @@ build = ["npm", "run", "build"] [userenv.shared] DISCORD_MAIN_CHAT_CHANNELS = "1425114041021497454" +MAINTENANCE_MODE = "true" diff --git a/attached_assets/Pasted-17s-12s-Run-npx-electron-builder-win-config-electron-bu_1765007431411.txt b/attached_assets/Pasted-17s-12s-Run-npx-electron-builder-win-config-electron-bu_1765007431411.txt new file mode 100644 index 00000000..d118e6d1 --- /dev/null +++ b/attached_assets/Pasted-17s-12s-Run-npx-electron-builder-win-config-electron-bu_1765007431411.txt @@ -0,0 +1,95 @@ +17s +12s +Run npx electron-builder --win --config electron-builder.yml + + • electron-builder version=25.1.8 os=10.0.26100 + • artifacts will be published reason=tag is defined tag=v0.1.1 + • loaded configuration file=D:\a\aethex-forge\aethex-forge\electron-builder.yml + • skipped dependencies rebuild reason=npmRebuild is set to false + • packaging platform=win32 arch=x64 electron=32.3.3 appOutDir=dist\win-unpacked + • downloading url=https://github.com/electron/electron/releases/download/v32.3.3/electron-v32.3.3-win32-x64.zip size=113 MB parts=8 + • downloaded url=https://github.com/electron/electron/releases/download/v32.3.3/electron-v32.3.3-win32-x64.zip duration=449ms + • updating asar integrity executable resource executablePath=dist\win-unpacked\AeThex Desktop Terminal.exe + ⨯ icon directory D:\a\aethex-forge\aethex-forge\build\icons doesn't contain icons +github.com/develar/app-builder/pkg/icons.CollectIcons + /Users/runner/work/app-builder/app-builder/pkg/icons/collect-icons.go:73 +github.com/develar/app-builder/pkg/icons.doConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:199 +github.com/develar/app-builder/pkg/icons.ConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:56 +github.com/develar/app-builder/pkg/icons.ConfigureCommand.func1 + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:33 +github.com/alecthomas/kingpin.(*actionMixin).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/actions.go:28 +github.com/alecthomas/kingpin.(*Application).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:557 +github.com/alecthomas/kingpin.(*Application).execute + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:390 +github.com/alecthomas/kingpin.(*Application).Parse + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:222 +main.main + /Users/runner/work/app-builder/app-builder/main.go:90 +runtime.main + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/proc.go:267 +runtime.goexit + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/asm_amd64.s:1650 +github.com/develar/app-builder/pkg/icons.doConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:201 +github.com/develar/app-builder/pkg/icons.ConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:56 +github.com/develar/app-builder/pkg/icons.ConfigureCommand.func1 + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:33 +github.com/alecthomas/kingpin.(*actionMixin).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/actions.go:28 +github.com/alecthomas/kingpin.(*Application).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:557 +github.com/alecthomas/kingpin.(*Application).execute + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:390 +github.com/alecthomas/kingpin.(*Application).Parse + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:222 +main.main + /Users/runner/work/app-builder/app-builder/main.go:90 +runtime.main + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/proc.go:267 +runtime.goexit + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/asm_amd64.s:1650 + ⨯ D:\a\aethex-forge\aethex-forge\node_modules\app-builder-bin\win\x64\app-builder.exe process failed ERR_ELECTRON_BUILDER_CANNOT_EXECUTE +Exit code: +1 failedTask=build stackTrace=Error: D:\a\aethex-forge\aethex-forge\node_modules\app-builder-bin\win\x64\app-builder.exe process failed ERR_ELECTRON_BUILDER_CANNOT_EXECUTE +Exit code: +1 + at ChildProcess. (D:\a\aethex-forge\aethex-forge\node_modules\builder-util\src\util.ts:255:14) + at Object.onceWrapper (node:events:639:26) + at ChildProcess.emit (node:events:524:28) + at ChildProcess.cp.emit (D:\a\aethex-forge\aethex-forge\node_modules\cross-spawn\lib\enoent.js:34:29) + at maybeClose (node:internal/child_process:1104:16) + at Process.ChildProcess._handle.onexit (node:internal/child_process:304:5) +From previous event: + at processImmediate (node:internal/timers:483:21) +From previous event: + at WinPackager.signApp (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\winPackager.ts:270:27) + at WinPackager.doSignAfterPack (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\platformPackager.ts:346:32) + at WinPackager.doPack (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\platformPackager.ts:331:7) + at WinPackager.pack (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\platformPackager.ts:138:5) + at Packager.doBuild (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\packager.ts:459:9) + at executeFinally (D:\a\aethex-forge\aethex-forge\node_modules\builder-util\src\promise.ts:12:14) + at Packager.build (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\packager.ts:393:31) + at executeFinally (D:\a\aethex-forge\aethex-forge\node_modules\builder-util\src\promise.ts:12:14) +Error: Process completed with exit code 1. +0s +0s +2s +Post job cleanup. +"C:\Program Files\Git\bin\git.exe" version +git version 2.52.0.windows.1 +Temporarily overriding HOME='D:\a\_temp\4963c2ff-b212-40d1-906e-719e33666ab2' before making global git config changes +Adding repository directory to the temporary git global config as a safe directory +"C:\Program Files\Git\bin\git.exe" config --global --add safe.directory D:\a\aethex-forge\aethex-forge +"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp core\.sshCommand +"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :\"" +"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader +http.https://github.com/.extraheader +"C:\Program Files\Git\bin\git.exe" config --local --unset-all http.https://github.com/.extraheader +"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :\"" +"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp ^includeIf\.gitdir: +"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "git config --local --show-origin --name-only --get-regexp remote.origin.url" \ No newline at end of file diff --git a/attached_assets/Pasted-17s-12s-Run-npx-electron-builder-win-config-electron-bu_1765007500661.txt b/attached_assets/Pasted-17s-12s-Run-npx-electron-builder-win-config-electron-bu_1765007500661.txt new file mode 100644 index 00000000..d118e6d1 --- /dev/null +++ b/attached_assets/Pasted-17s-12s-Run-npx-electron-builder-win-config-electron-bu_1765007500661.txt @@ -0,0 +1,95 @@ +17s +12s +Run npx electron-builder --win --config electron-builder.yml + + • electron-builder version=25.1.8 os=10.0.26100 + • artifacts will be published reason=tag is defined tag=v0.1.1 + • loaded configuration file=D:\a\aethex-forge\aethex-forge\electron-builder.yml + • skipped dependencies rebuild reason=npmRebuild is set to false + • packaging platform=win32 arch=x64 electron=32.3.3 appOutDir=dist\win-unpacked + • downloading url=https://github.com/electron/electron/releases/download/v32.3.3/electron-v32.3.3-win32-x64.zip size=113 MB parts=8 + • downloaded url=https://github.com/electron/electron/releases/download/v32.3.3/electron-v32.3.3-win32-x64.zip duration=449ms + • updating asar integrity executable resource executablePath=dist\win-unpacked\AeThex Desktop Terminal.exe + ⨯ icon directory D:\a\aethex-forge\aethex-forge\build\icons doesn't contain icons +github.com/develar/app-builder/pkg/icons.CollectIcons + /Users/runner/work/app-builder/app-builder/pkg/icons/collect-icons.go:73 +github.com/develar/app-builder/pkg/icons.doConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:199 +github.com/develar/app-builder/pkg/icons.ConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:56 +github.com/develar/app-builder/pkg/icons.ConfigureCommand.func1 + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:33 +github.com/alecthomas/kingpin.(*actionMixin).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/actions.go:28 +github.com/alecthomas/kingpin.(*Application).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:557 +github.com/alecthomas/kingpin.(*Application).execute + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:390 +github.com/alecthomas/kingpin.(*Application).Parse + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:222 +main.main + /Users/runner/work/app-builder/app-builder/main.go:90 +runtime.main + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/proc.go:267 +runtime.goexit + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/asm_amd64.s:1650 +github.com/develar/app-builder/pkg/icons.doConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:201 +github.com/develar/app-builder/pkg/icons.ConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:56 +github.com/develar/app-builder/pkg/icons.ConfigureCommand.func1 + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:33 +github.com/alecthomas/kingpin.(*actionMixin).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/actions.go:28 +github.com/alecthomas/kingpin.(*Application).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:557 +github.com/alecthomas/kingpin.(*Application).execute + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:390 +github.com/alecthomas/kingpin.(*Application).Parse + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:222 +main.main + /Users/runner/work/app-builder/app-builder/main.go:90 +runtime.main + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/proc.go:267 +runtime.goexit + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/asm_amd64.s:1650 + ⨯ D:\a\aethex-forge\aethex-forge\node_modules\app-builder-bin\win\x64\app-builder.exe process failed ERR_ELECTRON_BUILDER_CANNOT_EXECUTE +Exit code: +1 failedTask=build stackTrace=Error: D:\a\aethex-forge\aethex-forge\node_modules\app-builder-bin\win\x64\app-builder.exe process failed ERR_ELECTRON_BUILDER_CANNOT_EXECUTE +Exit code: +1 + at ChildProcess. (D:\a\aethex-forge\aethex-forge\node_modules\builder-util\src\util.ts:255:14) + at Object.onceWrapper (node:events:639:26) + at ChildProcess.emit (node:events:524:28) + at ChildProcess.cp.emit (D:\a\aethex-forge\aethex-forge\node_modules\cross-spawn\lib\enoent.js:34:29) + at maybeClose (node:internal/child_process:1104:16) + at Process.ChildProcess._handle.onexit (node:internal/child_process:304:5) +From previous event: + at processImmediate (node:internal/timers:483:21) +From previous event: + at WinPackager.signApp (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\winPackager.ts:270:27) + at WinPackager.doSignAfterPack (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\platformPackager.ts:346:32) + at WinPackager.doPack (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\platformPackager.ts:331:7) + at WinPackager.pack (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\platformPackager.ts:138:5) + at Packager.doBuild (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\packager.ts:459:9) + at executeFinally (D:\a\aethex-forge\aethex-forge\node_modules\builder-util\src\promise.ts:12:14) + at Packager.build (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\packager.ts:393:31) + at executeFinally (D:\a\aethex-forge\aethex-forge\node_modules\builder-util\src\promise.ts:12:14) +Error: Process completed with exit code 1. +0s +0s +2s +Post job cleanup. +"C:\Program Files\Git\bin\git.exe" version +git version 2.52.0.windows.1 +Temporarily overriding HOME='D:\a\_temp\4963c2ff-b212-40d1-906e-719e33666ab2' before making global git config changes +Adding repository directory to the temporary git global config as a safe directory +"C:\Program Files\Git\bin\git.exe" config --global --add safe.directory D:\a\aethex-forge\aethex-forge +"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp core\.sshCommand +"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :\"" +"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader +http.https://github.com/.extraheader +"C:\Program Files\Git\bin\git.exe" config --local --unset-all http.https://github.com/.extraheader +"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "sh -c \"git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :\"" +"C:\Program Files\Git\bin\git.exe" config --local --name-only --get-regexp ^includeIf\.gitdir: +"C:\Program Files\Git\bin\git.exe" submodule foreach --recursive "git config --local --show-origin --name-only --get-regexp remote.origin.url" \ No newline at end of file diff --git a/attached_assets/Pasted-Run-npx-electron-builder-win-config-electron-builder-ym_1765007031609.txt b/attached_assets/Pasted-Run-npx-electron-builder-win-config-electron-builder-ym_1765007031609.txt new file mode 100644 index 00000000..6e1eb3da --- /dev/null +++ b/attached_assets/Pasted-Run-npx-electron-builder-win-config-electron-builder-ym_1765007031609.txt @@ -0,0 +1,75 @@ +Run npx electron-builder --win --config electron-builder.yml + • electron-builder version=25.1.8 os=10.0.26100 + • artifacts will be published reason=tag is defined tag=v0.1.0 + • loaded configuration file=D:\a\aethex-forge\aethex-forge\electron-builder.yml + • skipped dependencies rebuild reason=npmRebuild is set to false + • packaging platform=win32 arch=x64 electron=32.3.3 appOutDir=dist\win-unpacked + • downloading url=https://github.com/electron/electron/releases/download/v32.3.3/electron-v32.3.3-win32-x64.zip size=113 MB parts=8 + • downloaded url=https://github.com/electron/electron/releases/download/v32.3.3/electron-v32.3.3-win32-x64.zip duration=592ms + • updating asar integrity executable resource executablePath=dist\win-unpacked\AeThex Desktop Terminal.exe + ⨯ icon directory D:\a\aethex-forge\aethex-forge\build\icons doesn't contain icons +github.com/develar/app-builder/pkg/icons.CollectIcons + /Users/runner/work/app-builder/app-builder/pkg/icons/collect-icons.go:73 +github.com/develar/app-builder/pkg/icons.doConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:199 +github.com/develar/app-builder/pkg/icons.ConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:56 +github.com/develar/app-builder/pkg/icons.ConfigureCommand.func1 + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:33 +github.com/alecthomas/kingpin.(*actionMixin).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/actions.go:28 +github.com/alecthomas/kingpin.(*Application).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:557 +github.com/alecthomas/kingpin.(*Application).execute + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:390 +github.com/alecthomas/kingpin.(*Application).Parse + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:222 +main.main + /Users/runner/work/app-builder/app-builder/main.go:90 +runtime.main + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/proc.go:267 +runtime.goexit + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/asm_amd64.s:1650 +github.com/develar/app-builder/pkg/icons.doConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:201 +github.com/develar/app-builder/pkg/icons.ConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:56 +github.com/develar/app-builder/pkg/icons.ConfigureCommand.func1 + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:33 +github.com/alecthomas/kingpin.(*actionMixin).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/actions.go:28 +github.com/alecthomas/kingpin.(*Application).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:557 +github.com/alecthomas/kingpin.(*Application).execute + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:390 +github.com/alecthomas/kingpin.(*Application).Parse + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:222 +main.main + /Users/runner/work/app-builder/app-builder/main.go:90 +runtime.main + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/proc.go:267 +runtime.goexit + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/asm_amd64.s:1650 + ⨯ D:\a\aethex-forge\aethex-forge\node_modules\app-builder-bin\win\x64\app-builder.exe process failed ERR_ELECTRON_BUILDER_CANNOT_EXECUTE +Exit code: +1 failedTask=build stackTrace=Error: D:\a\aethex-forge\aethex-forge\node_modules\app-builder-bin\win\x64\app-builder.exe process failed ERR_ELECTRON_BUILDER_CANNOT_EXECUTE +Exit code: +1 + at ChildProcess. (D:\a\aethex-forge\aethex-forge\node_modules\builder-util\src\util.ts:255:14) + at Object.onceWrapper (node:events:639:26) + at ChildProcess.emit (node:events:524:28) + at ChildProcess.cp.emit (D:\a\aethex-forge\aethex-forge\node_modules\cross-spawn\lib\enoent.js:34:29) + at maybeClose (node:internal/child_process:1104:16) + at Process.ChildProcess._handle.onexit (node:internal/child_process:304:5) +From previous event: + at processImmediate (node:internal/timers:483:21) +From previous event: + at WinPackager.signApp (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\winPackager.ts:270:27) + at WinPackager.doSignAfterPack (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\platformPackager.ts:346:32) + at WinPackager.doPack (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\platformPackager.ts:331:7) + at WinPackager.pack (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\platformPackager.ts:138:5) + at Packager.doBuild (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\packager.ts:459:9) + at executeFinally (D:\a\aethex-forge\aethex-forge\node_modules\builder-util\src\promise.ts:12:14) + at Packager.build (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\packager.ts:393:31) + at executeFinally (D:\a\aethex-forge\aethex-forge\node_modules\builder-util\src\promise.ts:12:14) +Error: Process completed with exit code 1. diff --git a/attached_assets/Pasted-Run-npx-electron-builder-win-config-electron-builder-ym_1765007959498.txt b/attached_assets/Pasted-Run-npx-electron-builder-win-config-electron-builder-ym_1765007959498.txt new file mode 100644 index 00000000..015ec83b --- /dev/null +++ b/attached_assets/Pasted-Run-npx-electron-builder-win-config-electron-builder-ym_1765007959498.txt @@ -0,0 +1,75 @@ +Run npx electron-builder --win --config electron-builder.yml + • electron-builder version=25.1.8 os=10.0.26100 + • artifacts will be published reason=tag is defined tag=v0.1.2 + • loaded configuration file=D:\a\aethex-forge\aethex-forge\electron-builder.yml + • skipped dependencies rebuild reason=npmRebuild is set to false + • packaging platform=win32 arch=x64 electron=32.3.3 appOutDir=dist\win-unpacked + • downloading url=https://github.com/electron/electron/releases/download/v32.3.3/electron-v32.3.3-win32-x64.zip size=113 MB parts=8 + • downloaded url=https://github.com/electron/electron/releases/download/v32.3.3/electron-v32.3.3-win32-x64.zip duration=732ms + • updating asar integrity executable resource executablePath=dist\win-unpacked\AeThex Desktop Terminal.exe + ⨯ icon directory D:\a\aethex-forge\aethex-forge\build\icons doesn't contain icons +github.com/develar/app-builder/pkg/icons.CollectIcons + /Users/runner/work/app-builder/app-builder/pkg/icons/collect-icons.go:73 +github.com/develar/app-builder/pkg/icons.doConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:199 +github.com/develar/app-builder/pkg/icons.ConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:56 +github.com/develar/app-builder/pkg/icons.ConfigureCommand.func1 + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:33 +github.com/alecthomas/kingpin.(*actionMixin).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/actions.go:28 +github.com/alecthomas/kingpin.(*Application).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:557 +github.com/alecthomas/kingpin.(*Application).execute + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:390 +github.com/alecthomas/kingpin.(*Application).Parse + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:222 +main.main + /Users/runner/work/app-builder/app-builder/main.go:90 +runtime.main + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/proc.go:267 +runtime.goexit + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/asm_amd64.s:1650 +github.com/develar/app-builder/pkg/icons.doConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:201 +github.com/develar/app-builder/pkg/icons.ConvertIcon + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:56 +github.com/develar/app-builder/pkg/icons.ConfigureCommand.func1 + /Users/runner/work/app-builder/app-builder/pkg/icons/icon-converter.go:33 +github.com/alecthomas/kingpin.(*actionMixin).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/actions.go:28 +github.com/alecthomas/kingpin.(*Application).applyActions + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:557 +github.com/alecthomas/kingpin.(*Application).execute + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:390 +github.com/alecthomas/kingpin.(*Application).Parse + /Users/runner/go/pkg/mod/github.com/alecthomas/kingpin@v2.2.6+incompatible/app.go:222 +main.main + /Users/runner/work/app-builder/app-builder/main.go:90 +runtime.main + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/proc.go:267 +runtime.goexit + /Users/runner/hostedtoolcache/go/1.21.13/arm64/src/runtime/asm_amd64.s:1650 + ⨯ D:\a\aethex-forge\aethex-forge\node_modules\app-builder-bin\win\x64\app-builder.exe process failed ERR_ELECTRON_BUILDER_CANNOT_EXECUTE +Exit code: +1 failedTask=build stackTrace=Error: D:\a\aethex-forge\aethex-forge\node_modules\app-builder-bin\win\x64\app-builder.exe process failed ERR_ELECTRON_BUILDER_CANNOT_EXECUTE +Exit code: +1 + at ChildProcess. (D:\a\aethex-forge\aethex-forge\node_modules\builder-util\src\util.ts:255:14) + at Object.onceWrapper (node:events:639:26) + at ChildProcess.emit (node:events:524:28) + at ChildProcess.cp.emit (D:\a\aethex-forge\aethex-forge\node_modules\cross-spawn\lib\enoent.js:34:29) + at maybeClose (node:internal/child_process:1104:16) + at Process.ChildProcess._handle.onexit (node:internal/child_process:304:5) +From previous event: + at processImmediate (node:internal/timers:483:21) +From previous event: + at WinPackager.signApp (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\winPackager.ts:270:27) + at WinPackager.doSignAfterPack (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\platformPackager.ts:346:32) + at WinPackager.doPack (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\platformPackager.ts:331:7) + at WinPackager.pack (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\platformPackager.ts:138:5) + at Packager.doBuild (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\packager.ts:459:9) + at executeFinally (D:\a\aethex-forge\aethex-forge\node_modules\builder-util\src\promise.ts:12:14) + at Packager.build (D:\a\aethex-forge\aethex-forge\node_modules\app-builder-lib\src\packager.ts:393:31) + at executeFinally (D:\a\aethex-forge\aethex-forge\node_modules\builder-util\src\promise.ts:12:14) +Error: Process completed with exit code 1. diff --git a/attached_assets/image_1765005879621.png b/attached_assets/image_1765005879621.png new file mode 100644 index 0000000000000000000000000000000000000000..f844f9672685b31c8f2040263baa837f6df4883e GIT binary patch literal 51834 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 Q=w5|)WE7 ( - - - + + + + + {/* Subdomain Passport (aethex.me and aethex.space) handles its own redirect if not a subdomain */} } /> } /> @@ -795,8 +799,10 @@ const App = () => ( } /> {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */} } /> - - + + + + diff --git a/client/components/MaintenanceGuard.tsx b/client/components/MaintenanceGuard.tsx new file mode 100644 index 00000000..72af235f --- /dev/null +++ b/client/components/MaintenanceGuard.tsx @@ -0,0 +1,33 @@ +import React from "react"; +import { useLocation } from "react-router-dom"; +import { useMaintenance } from "@/contexts/MaintenanceContext"; +import MaintenancePage from "@/pages/Maintenance"; + +const ALLOWED_PATHS = ["/login", "/staff/login", "/reset-password", "/health"]; + +interface MaintenanceGuardProps { + children: React.ReactNode; +} + +export default function MaintenanceGuard({ children }: MaintenanceGuardProps) { + const { isMaintenanceMode, canBypass, loading } = useMaintenance(); + const location = useLocation(); + + if (loading) { + return ( +
+
+
+ ); + } + + const isAllowedPath = ALLOWED_PATHS.some(path => + location.pathname === path || location.pathname.startsWith(path) + ); + + if (isMaintenanceMode && !canBypass && !isAllowedPath) { + return ; + } + + return <>{children}; +} diff --git a/client/components/admin/MaintenanceToggle.tsx b/client/components/admin/MaintenanceToggle.tsx new file mode 100644 index 00000000..ba5b0bee --- /dev/null +++ b/client/components/admin/MaintenanceToggle.tsx @@ -0,0 +1,111 @@ +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Switch } from "@/components/ui/switch"; +import { Badge } from "@/components/ui/badge"; +import { useMaintenance } from "@/contexts/MaintenanceContext"; +import { Construction, AlertTriangle, Loader2 } from "lucide-react"; +import { useState } from "react"; +import { aethexToast } from "@/lib/aethex-toast"; + +export default function MaintenanceToggle() { + const { isMaintenanceMode, canBypass, toggleMaintenanceMode, loading } = useMaintenance(); + const [toggling, setToggling] = useState(false); + + const handleToggle = async () => { + if (!canBypass) { + aethexToast.error("Only admins can toggle maintenance mode"); + return; + } + + setToggling(true); + try { + await toggleMaintenanceMode(); + aethexToast.success( + isMaintenanceMode + ? "Maintenance mode disabled - site is now live" + : "Maintenance mode enabled - visitors will see maintenance page" + ); + } catch (error: any) { + aethexToast.error(error?.message || "Failed to toggle maintenance mode"); + } finally { + setToggling(false); + } + }; + + if (loading) { + return ( + + + + + + ); + } + + return ( + + +
+
+
+ {isMaintenanceMode ? ( + + ) : ( + + )} +
+
+ Maintenance Mode + + {isMaintenanceMode + ? "Site is currently in maintenance mode" + : "Site is live and accessible"} + +
+
+ + {isMaintenanceMode ? "Active" : "Off"} + +
+
+ +
+
+ {isMaintenanceMode && ( + + )} +
+

+ {isMaintenanceMode + ? "Visitors see maintenance page" + : "All visitors can access the site"} +

+

+ {isMaintenanceMode + ? "Only admins can view the site. Toggle off to go live." + : "Toggle on to show maintenance page to visitors."} +

+
+
+
+ {toggling && } + +
+
+
+
+ ); +} diff --git a/client/contexts/MaintenanceContext.tsx b/client/contexts/MaintenanceContext.tsx new file mode 100644 index 00000000..ae868b2e --- /dev/null +++ b/client/contexts/MaintenanceContext.tsx @@ -0,0 +1,104 @@ +import React, { createContext, useContext, useState, useEffect, useCallback } from "react"; +import { useAuth } from "./AuthContext"; +import { supabase } from "@/lib/supabase"; + +interface MaintenanceContextType { + isMaintenanceMode: boolean; + canBypass: boolean; + loading: boolean; + toggleMaintenanceMode: () => Promise; + refreshStatus: () => Promise; +} + +const MaintenanceContext = createContext(undefined); + +const ADMIN_ROLES = ["admin", "super_admin", "staff", "owner"]; + +export function MaintenanceProvider({ children }: { children: React.ReactNode }) { + const { user, roles, session, loading: authLoading } = useAuth(); + const [isMaintenanceMode, setIsMaintenanceMode] = useState(false); + const [loading, setLoading] = useState(true); + + const isAdmin = roles.some(role => ADMIN_ROLES.includes(role.toLowerCase())); + const canBypass = isAdmin && !!user; + + const fetchMaintenanceStatus = useCallback(async () => { + try { + const response = await fetch("/api/admin/platform/maintenance"); + if (response.ok) { + const data = await response.json(); + setIsMaintenanceMode(data.maintenance_mode ?? false); + } + } catch (error) { + console.error("Failed to fetch maintenance status:", error); + } finally { + setLoading(false); + } + }, []); + + const toggleMaintenanceMode = useCallback(async () => { + if (!canBypass) { + throw new Error("Only admins can toggle maintenance mode"); + } + + const { data: sessionData } = await supabase.auth.getSession(); + const token = sessionData?.session?.access_token; + + if (!token) { + throw new Error("No auth session"); + } + + try { + const response = await fetch("/api/admin/platform/maintenance", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${token}`, + }, + body: JSON.stringify({ maintenance_mode: !isMaintenanceMode }), + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.error || "Failed to toggle maintenance mode"); + } + + const data = await response.json(); + setIsMaintenanceMode(data.maintenance_mode); + } catch (error) { + console.error("Failed to toggle maintenance mode:", error); + throw error; + } + }, [canBypass, isMaintenanceMode]); + + const refreshStatus = useCallback(async () => { + setLoading(true); + await fetchMaintenanceStatus(); + }, [fetchMaintenanceStatus]); + + useEffect(() => { + fetchMaintenanceStatus(); + }, [fetchMaintenanceStatus]); + + return ( + + {children} + + ); +} + +export function useMaintenance() { + const context = useContext(MaintenanceContext); + if (!context) { + throw new Error("useMaintenance must be used within MaintenanceProvider"); + } + return context; +} diff --git a/client/pages/Admin.tsx b/client/pages/Admin.tsx index 6b9d9870..6b37c89d 100644 --- a/client/pages/Admin.tsx +++ b/client/pages/Admin.tsx @@ -40,6 +40,7 @@ import AdminStaffChat from "@/components/admin/AdminStaffChat"; import AdminStaffAdmin from "@/components/admin/AdminStaffAdmin"; import AdminStaffDocs from "@/components/admin/AdminStaffDocs"; import AdminStaffAchievements from "@/components/admin/AdminStaffAchievements"; +import MaintenanceToggle from "@/components/admin/MaintenanceToggle"; import AdminSidebar from "@/components/admin/AdminSidebar"; import AdminEthosVerification from "@/pages/admin/AdminEthosVerification"; import AdminGameForgeStudio from "@/components/admin/AdminGameForgeStudio"; @@ -393,6 +394,8 @@ export default function Admin() { + +
diff --git a/client/pages/Maintenance.tsx b/client/pages/Maintenance.tsx new file mode 100644 index 00000000..db4a24a0 --- /dev/null +++ b/client/pages/Maintenance.tsx @@ -0,0 +1,159 @@ +import { useState, useEffect } from "react"; +import { Shield, Mail, Wrench, Clock, Zap } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { Card, CardContent } from "@/components/ui/card"; +import AeThexOSLogo from "@/components/AeThexOSLogo"; + +export default function MaintenancePage() { + const [currentMessage, setCurrentMessage] = useState(0); + const [dots, setDots] = useState(""); + + const messages = [ + "Upgrading quantum processors...", + "Optimizing neural networks...", + "Synchronizing data streams...", + "Calibrating system modules...", + "Enhancing user experience...", + ]; + + useEffect(() => { + const messageInterval = setInterval(() => { + setCurrentMessage((prev) => (prev + 1) % messages.length); + }, 2500); + + const dotsInterval = setInterval(() => { + setDots((prev) => (prev.length >= 3 ? "" : prev + ".")); + }, 400); + + return () => { + clearInterval(messageInterval); + clearInterval(dotsInterval); + }; + }, [messages.length]); + + return ( +
+
+ {[...Array(20)].map((_, i) => ( +
+ {["01", "10", "//", "{ }", "< >", "=>"][Math.floor(Math.random() * 6)]} +
+ ))} +
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+

+ System Maintenance +

+

+ We're upgrading AeThex to deliver a better experience. +

+
+ +
+ + + Maintenance Mode + + + + Back Soon + +
+
+ + + +
+
+ {[...Array(5)].map((_, i) => ( +
+ ))} +
+ + {messages[currentMessage]}{dots} + +
+ +
+ +
+
+
STATUS
+
+ + ACTIVE +
+
+
+
SYSTEM
+
AeThex v2.0
+
+
+
ETA
+
~30 min
+
+
+ + + + + +
+ + Questions? + + + support@aethex.dev + +
+
+
+ + +
+
+
+ ); +} diff --git a/discord-bot/bot.js b/discord-bot/bot.js index b7b28503..401b1321 100644 --- a/discord-bot/bot.js +++ b/discord-bot/bot.js @@ -311,7 +311,7 @@ async function registerDiscordCommands() { } // Start HTTP health check server -const healthPort = process.env.HEALTH_PORT || 8044; +const healthPort = process.env.HEALTH_PORT || 8080; const ADMIN_TOKEN = process.env.DISCORD_ADMIN_TOKEN || "aethex-bot-admin"; // Helper to check admin authentication diff --git a/package-lock.json b/package-lock.json index 95c5b96e..00c536af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,8 @@ "ethers": "^6.13.0", "express": "^4.18.2", "nodemailer": "^7.0.10", + "png-to-ico": "^3.0.1", + "sharp": "^0.34.5", "stripe": "^15.12.0", "zod": "^3.23.8" }, @@ -1737,6 +1739,23 @@ "node": ">= 10.0.0" } }, + "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, "node_modules/@emotion/cache": { "version": "10.0.29", "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", @@ -2364,6 +2383,471 @@ "react-hook-form": "^7.0.0" } }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@isaacs/balanced-match": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", @@ -13370,6 +13854,32 @@ "node": ">=10.4.0" } }, + "node_modules/png-to-ico": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/png-to-ico/-/png-to-ico-3.0.1.tgz", + "integrity": "sha512-S8BOAoaGd9gT5uaemQ62arIY3Jzco7Uc7LwUTqRyqJDTsKqOAiyfyN4dSdT0D+Zf8XvgztgpRbM5wnQd7EgYwg==", + "license": "MIT", + "dependencies": { + "@types/node": "^22.10.3", + "minimist": "^1.2.8", + "pngjs": "^7.0.0" + }, + "bin": { + "png-to-ico": "bin/cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", + "license": "MIT", + "engines": { + "node": ">=14.19.0" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -14698,6 +15208,50 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", diff --git a/package.json b/package.json index 0ef40b05..20f71d99 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,8 @@ "ethers": "^6.13.0", "express": "^4.18.2", "nodemailer": "^7.0.10", + "png-to-ico": "^3.0.1", + "sharp": "^0.34.5", "stripe": "^15.12.0", "zod": "^3.23.8" }, diff --git a/replit.md b/replit.md index 2a37930d..491a98ae 100644 --- a/replit.md +++ b/replit.md @@ -38,6 +38,8 @@ The monolith (`aethex.dev`) implements split routing to enforce legal separation This ensures the Foundation's user-facing URLs display `aethex.foundation` in the browser, demonstrating operational independence per the Axiom Model. ## Recent Changes (December 2025) +- **Maintenance Mode**: Site-wide maintenance mode with admin bypass. Admins can toggle via Admin Dashboard overview tab. Uses MAINTENANCE_MODE env var for initial state. Allowed paths during maintenance: /login, /staff/login, /reset-password, /health +- **Health Endpoint**: Added /health endpoint at aethex.dev/health that aggregates platform and Discord bot status - **Axiom Model Routing**: Foundation and GameForge routes redirect to `aethex.foundation` domain for legal entity separation - **AI Intelligent Agent Integration**: Added global AI chat with 10 specialized personas (Network Agent, Forge Master, Ethics Sentinel, SBS Architect, Curriculum Weaver, QuantumLeap, Vapor, Apex, Ethos Producer, AeThex Archivist) - **Tiered Access Control**: AI personas gated by user tier (Free/Architect/Council) based on roles diff --git a/server/index.ts b/server/index.ts index e746ff25..dc60f8fb 100644 --- a/server/index.ts +++ b/server/index.ts @@ -457,6 +457,129 @@ export function createServer() { } }); + // Health check endpoint - proxies to Discord bot health + app.get("/health", async (_req, res) => { + try { + const botHealthPort = process.env.HEALTH_PORT || 8080; + const response = await fetch(`http://localhost:${botHealthPort}/health`); + const data = await response.json(); + res.json({ + status: "online", + platform: "aethex.dev", + bot: data, + timestamp: new Date().toISOString(), + }); + } catch (error: any) { + res.json({ + status: "online", + platform: "aethex.dev", + bot: { status: "offline", error: error?.message || "Bot unreachable" }, + timestamp: new Date().toISOString(), + }); + } + }); + + // Maintenance Mode API endpoints + const ADMIN_ROLES = ["admin", "super_admin", "staff", "owner"]; + + // In-memory maintenance state (fallback when DB table doesn't exist) + let maintenanceModeCache: boolean | null = null; + + // Get maintenance status (public) + app.get("/api/admin/platform/maintenance", async (_req, res) => { + try { + // Try database first + const { data, error } = await adminSupabase + .from("platform_settings") + .select("value") + .eq("key", "maintenance_mode") + .single(); + + if (error) { + // If table doesn't exist, use env var or in-memory cache + if (error.code === "42P01" || error.message?.includes("does not exist")) { + const envMaintenance = process.env.MAINTENANCE_MODE === "true"; + res.json({ maintenance_mode: maintenanceModeCache ?? envMaintenance }); + return; + } + // Row not found is OK, means maintenance is off + if (error.code !== "PGRST116") { + throw error; + } + } + + const isActive = data?.value === "true" || data?.value === true; + maintenanceModeCache = isActive; + res.json({ maintenance_mode: isActive }); + } catch (e: any) { + console.error("[Maintenance] Error fetching status:", e?.message); + // Fall back to env var or cache + const envMaintenance = process.env.MAINTENANCE_MODE === "true"; + res.json({ maintenance_mode: maintenanceModeCache ?? envMaintenance }); + } + }); + + // Toggle maintenance mode (admin only) + app.post("/api/admin/platform/maintenance", async (req, res) => { + try { + const authHeader = req.headers.authorization; + if (!authHeader?.startsWith("Bearer ")) { + return res.status(401).json({ error: "Unauthorized" }); + } + + const token = authHeader.substring(7); + const { data: { user }, error: authError } = await adminSupabase.auth.getUser(token); + + if (authError || !user) { + return res.status(401).json({ error: "Invalid token" }); + } + + // Check if user has admin role + const { data: roles } = await adminSupabase + .from("user_roles") + .select("role") + .eq("user_id", user.id); + + const userRoles = roles?.map((r: any) => r.role?.toLowerCase()) || []; + const isAdmin = userRoles.some((role: string) => ADMIN_ROLES.includes(role)); + + if (!isAdmin) { + return res.status(403).json({ error: "Admin access required" }); + } + + const rawValue = req.body?.maintenance_mode; + const newMaintenanceMode = rawValue === true || rawValue === "true"; + + // Try to upsert in database + const { error } = await adminSupabase + .from("platform_settings") + .upsert({ + key: "maintenance_mode", + value: String(newMaintenanceMode), + updated_at: new Date().toISOString(), + updated_by: user.id, + }, { onConflict: "key" }); + + if (error) { + // If table doesn't exist, just use in-memory cache + if (error.code === "42P01" || error.message?.includes("does not exist")) { + maintenanceModeCache = newMaintenanceMode; + console.log(`[Maintenance] Mode set to ${newMaintenanceMode} (in-memory) by ${user.email}`); + return res.json({ maintenance_mode: newMaintenanceMode }); + } + throw error; + } + + maintenanceModeCache = newMaintenanceMode; + console.log(`[Maintenance] Mode set to ${newMaintenanceMode} by ${user.email}`); + + res.json({ maintenance_mode: newMaintenanceMode }); + } catch (e: any) { + console.error("[Maintenance] Error toggling:", e?.message); + res.status(500).json({ error: e?.message || "Failed to toggle maintenance mode" }); + } + }); + // Example API routes app.get("/api/ping", (_req, res) => { const ping = process.env.PING_MESSAGE ?? "ping";