Sync local changes

This commit is contained in:
MrPiglr 2025-12-07 00:17:04 +00:00
parent 74bfcc218b
commit 577ef68dad
18 changed files with 1584 additions and 6 deletions

135
.github/workflows/desktop-release.yml vendored Normal file
View file

@ -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 }}

View file

@ -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"

View file

@ -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.<anonymous> (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"

View file

@ -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.<anonymous> (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"

View file

@ -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.<anonymous> (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.

View file

@ -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.<anonymous> (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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View file

@ -10,6 +10,8 @@ import { AuthProvider } from "./contexts/AuthContext";
import { Web3Provider } from "./contexts/Web3Context";
import { DocsThemeProvider } from "./contexts/DocsThemeContext";
import { ArmThemeProvider } from "./contexts/ArmThemeContext";
import { MaintenanceProvider } from "./contexts/MaintenanceContext";
import MaintenanceGuard from "./components/MaintenanceGuard";
import PageTransition from "./components/PageTransition";
import SkipAgentController from "./components/SkipAgentController";
import Index from "./pages/Index";
@ -182,9 +184,11 @@ const App = () => (
<BrowserRouter>
<SubdomainPassportProvider>
<ArmThemeProvider>
<SkipAgentController />
<PageTransition>
<Routes>
<MaintenanceProvider>
<MaintenanceGuard>
<SkipAgentController />
<PageTransition>
<Routes>
{/* Subdomain Passport (aethex.me and aethex.space) handles its own redirect if not a subdomain */}
<Route path="/" element={<SubdomainPassport />} />
<Route path="/onboarding" element={<Onboarding />} />
@ -795,8 +799,10 @@ const App = () => (
<Route path="/404" element={<FourOhFourPage />} />
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
<Route path="*" element={<FourOhFourPage />} />
</Routes>
</PageTransition>
</Routes>
</PageTransition>
</MaintenanceGuard>
</MaintenanceProvider>
</ArmThemeProvider>
</SubdomainPassportProvider>
</BrowserRouter>

View file

@ -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 (
<div className="min-h-screen bg-gray-900 flex items-center justify-center">
<div className="w-8 h-8 border-2 border-purple-500 border-t-transparent rounded-full animate-spin" />
</div>
);
}
const isAllowedPath = ALLOWED_PATHS.some(path =>
location.pathname === path || location.pathname.startsWith(path)
);
if (isMaintenanceMode && !canBypass && !isAllowedPath) {
return <MaintenancePage />;
}
return <>{children}</>;
}

View file

@ -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 (
<Card className="bg-card/60 border-border/40 backdrop-blur">
<CardContent className="flex items-center justify-center py-8">
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
</CardContent>
</Card>
);
}
return (
<Card className={`bg-card/60 border-border/40 backdrop-blur ${isMaintenanceMode ? 'border-yellow-500/30' : ''}`}>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className={`flex h-10 w-10 items-center justify-center rounded-full border ${
isMaintenanceMode
? 'border-yellow-500/30 bg-yellow-500/10'
: 'border-emerald-500/30 bg-emerald-500/10'
}`}>
{isMaintenanceMode ? (
<Construction className="h-5 w-5 text-yellow-400" />
) : (
<Construction className="h-5 w-5 text-emerald-400" />
)}
</div>
<div>
<CardTitle className="text-lg">Maintenance Mode</CardTitle>
<CardDescription>
{isMaintenanceMode
? "Site is currently in maintenance mode"
: "Site is live and accessible"}
</CardDescription>
</div>
</div>
<Badge
variant="outline"
className={isMaintenanceMode
? "border-yellow-500/30 bg-yellow-500/10 text-yellow-200"
: "border-emerald-500/30 bg-emerald-500/10 text-emerald-200"
}
>
{isMaintenanceMode ? "Active" : "Off"}
</Badge>
</div>
</CardHeader>
<CardContent>
<div className="flex items-center justify-between rounded-lg border border-border/30 bg-background/40 p-4">
<div className="flex items-center gap-3">
{isMaintenanceMode && (
<AlertTriangle className="h-5 w-5 text-yellow-400" />
)}
<div>
<p className="font-medium text-sm">
{isMaintenanceMode
? "Visitors see maintenance page"
: "All visitors can access the site"}
</p>
<p className="text-xs text-muted-foreground mt-1">
{isMaintenanceMode
? "Only admins can view the site. Toggle off to go live."
: "Toggle on to show maintenance page to visitors."}
</p>
</div>
</div>
<div className="flex items-center gap-2">
{toggling && <Loader2 className="h-4 w-4 animate-spin" />}
<Switch
checked={isMaintenanceMode}
onCheckedChange={handleToggle}
disabled={toggling || !canBypass}
/>
</div>
</div>
</CardContent>
</Card>
);
}

View file

@ -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<void>;
refreshStatus: () => Promise<void>;
}
const MaintenanceContext = createContext<MaintenanceContextType | undefined>(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 (
<MaintenanceContext.Provider
value={{
isMaintenanceMode,
canBypass,
loading: loading || authLoading,
toggleMaintenanceMode,
refreshStatus,
}}
>
{children}
</MaintenanceContext.Provider>
);
}
export function useMaintenance() {
const context = useContext(MaintenanceContext);
if (!context) {
throw new Error("useMaintenance must be used within MaintenanceProvider");
}
return context;
}

View file

@ -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() {
</TabsList>
<TabsContent value="overview" className="space-y-6">
<MaintenanceToggle />
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<Card className="bg-card/60 border-border/40 backdrop-blur">
<CardHeader className="pb-3">

View file

@ -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 (
<div className="min-h-screen bg-background overflow-hidden relative">
<div className="absolute inset-0 pointer-events-none overflow-hidden opacity-5">
{[...Array(20)].map((_, i) => (
<div
key={i}
className="absolute text-blue-400 animate-float font-mono"
style={{
left: `${Math.random() * 100}%`,
top: `${Math.random() * 100}%`,
animationDelay: `${Math.random() * 3}s`,
animationDuration: `${4 + Math.random() * 3}s`,
fontSize: `${10 + Math.random() * 6}px`,
}}
>
{["01", "10", "//", "{ }", "< >", "=>"][Math.floor(Math.random() * 6)]}
</div>
))}
</div>
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-blue-500/5 rounded-full blur-3xl" />
<div className="absolute bottom-1/4 right-1/4 w-80 h-80 bg-cyan-500/5 rounded-full blur-3xl" />
<div className="relative z-10 flex items-center justify-center min-h-screen p-4">
<div className="max-w-xl w-full text-center space-y-8">
<div className="space-y-6">
<div className="relative inline-block">
<div className="absolute -inset-4 bg-gradient-to-r from-blue-500 to-cyan-500 opacity-20 blur-xl rounded-full animate-pulse" />
<div className="relative w-24 h-24 mx-auto bg-gradient-to-br from-blue-500/20 to-cyan-500/20 border border-blue-500/40 rounded-xl flex items-center justify-center shadow-lg shadow-blue-500/10">
<AeThexOSLogo size="lg" variant="default" animate />
</div>
</div>
<div className="space-y-3">
<h1 className="text-4xl md:text-5xl font-bold bg-gradient-to-r from-blue-400 via-cyan-400 to-blue-400 bg-clip-text text-transparent">
System Maintenance
</h1>
<p className="text-lg text-muted-foreground max-w-md mx-auto">
We're upgrading AeThex to deliver a better experience.
</p>
</div>
<div className="flex justify-center gap-3 flex-wrap">
<Badge variant="outline" className="border-blue-500/50 text-blue-400 animate-pulse">
<Wrench className="h-3 w-3 mr-1" />
Maintenance Mode
</Badge>
<Badge variant="outline" className="border-cyan-500/50 text-cyan-400">
<Clock className="h-3 w-3 mr-1" />
Back Soon
</Badge>
</div>
</div>
<Card className="bg-card/50 border-border/50 backdrop-blur-sm">
<CardContent className="p-6 space-y-4">
<div className="flex items-center justify-center gap-3">
<div className="flex gap-1">
{[...Array(5)].map((_, i) => (
<div
key={i}
className="w-1.5 bg-gradient-to-t from-blue-500 to-cyan-400 rounded-full animate-pulse"
style={{
height: `${12 + i * 4}px`,
animationDelay: `${i * 0.15}s`,
}}
/>
))}
</div>
<span className="text-sm text-muted-foreground font-mono">
{messages[currentMessage]}{dots}
</span>
</div>
<div className="h-px bg-border" />
<div className="grid grid-cols-3 gap-4 text-center text-xs">
<div className="space-y-1">
<div className="text-muted-foreground">STATUS</div>
<div className="text-blue-400 font-semibold flex items-center justify-center gap-1">
<Zap className="h-3 w-3" />
ACTIVE
</div>
</div>
<div className="space-y-1">
<div className="text-muted-foreground">SYSTEM</div>
<div className="text-foreground font-semibold">AeThex v2.0</div>
</div>
<div className="space-y-1">
<div className="text-muted-foreground">ETA</div>
<div className="text-cyan-400 font-semibold">~30 min</div>
</div>
</div>
</CardContent>
</Card>
<Card className="bg-background/30 border-border/30">
<CardContent className="p-4">
<div className="flex items-center justify-center gap-2 text-sm">
<Shield className="w-4 h-4 text-blue-400" />
<span className="text-muted-foreground">Questions?</span>
<Mail className="w-4 h-4 text-muted-foreground" />
<a
href="mailto:support@aethex.dev"
className="text-blue-400 hover:text-blue-300 transition-colors"
>
support@aethex.dev
</a>
</div>
</CardContent>
</Card>
<Button
variant="ghost"
size="sm"
asChild
className="text-muted-foreground hover:text-foreground hover:bg-blue-500/10"
>
<a href="/login">Staff Login</a>
</Button>
</div>
</div>
</div>
);
}

View file

@ -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

554
package-lock.json generated
View file

@ -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",

View file

@ -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"
},

View file

@ -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

View file

@ -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";