Add argon2 polyfill and unified preview/API startup for admin login.
Node < 24 lacks crypto.argon2Sync; wire @node-rs/argon2 fallback and start Admin API alongside vite preview in local and remote deploy flows. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Generated
+310
@@ -8,6 +8,7 @@
|
||||
"name": "tkmind-admin",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@node-rs/argon2": "^2.0.2",
|
||||
"express": "^4.21.2",
|
||||
"mysql2": "^3.22.5",
|
||||
"react": "^19.0.0",
|
||||
@@ -304,6 +305,37 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
|
||||
"integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/wasi-threads": "1.2.2",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
|
||||
"integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/wasi-threads": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
|
||||
"integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
||||
@@ -796,6 +828,267 @@
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "0.2.12",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
|
||||
"integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/core": "^1.4.3",
|
||||
"@emnapi/runtime": "^1.4.3",
|
||||
"@tybys/wasm-util": "^0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2/-/argon2-2.0.2.tgz",
|
||||
"integrity": "sha512-t64wIsPEtNd4aUPuTAyeL2ubxATCBGmeluaKXEMAFk/8w6AJIVVkeLKMBpgLW6LU2t5cQxT+env/c6jxbtTQBg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@node-rs/argon2-android-arm-eabi": "2.0.2",
|
||||
"@node-rs/argon2-android-arm64": "2.0.2",
|
||||
"@node-rs/argon2-darwin-arm64": "2.0.2",
|
||||
"@node-rs/argon2-darwin-x64": "2.0.2",
|
||||
"@node-rs/argon2-freebsd-x64": "2.0.2",
|
||||
"@node-rs/argon2-linux-arm-gnueabihf": "2.0.2",
|
||||
"@node-rs/argon2-linux-arm64-gnu": "2.0.2",
|
||||
"@node-rs/argon2-linux-arm64-musl": "2.0.2",
|
||||
"@node-rs/argon2-linux-x64-gnu": "2.0.2",
|
||||
"@node-rs/argon2-linux-x64-musl": "2.0.2",
|
||||
"@node-rs/argon2-wasm32-wasi": "2.0.2",
|
||||
"@node-rs/argon2-win32-arm64-msvc": "2.0.2",
|
||||
"@node-rs/argon2-win32-ia32-msvc": "2.0.2",
|
||||
"@node-rs/argon2-win32-x64-msvc": "2.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-android-arm-eabi": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm-eabi/-/argon2-android-arm-eabi-2.0.2.tgz",
|
||||
"integrity": "sha512-DV/H8p/jt40lrao5z5g6nM9dPNPGEHL+aK6Iy/og+dbL503Uj0AHLqj1Hk9aVUSCNnsDdUEKp4TVMi0YakDYKw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-android-arm64": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm64/-/argon2-android-arm64-2.0.2.tgz",
|
||||
"integrity": "sha512-1LKwskau+8O1ktKx7TbK7jx1oMOMt4YEXZOdSNIar1TQKxm6isZ0cRXgHLibPHEcNHgYRsJWDE9zvDGBB17QDg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-darwin-arm64": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-arm64/-/argon2-darwin-arm64-2.0.2.tgz",
|
||||
"integrity": "sha512-3TTNL/7wbcpNju5YcqUrCgXnXUSbD7ogeAKatzBVHsbpjZQbNb1NDxDjqqrWoTt6XL3z9mJUMGwbAk7zQltHtA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-darwin-x64": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-x64/-/argon2-darwin-x64-2.0.2.tgz",
|
||||
"integrity": "sha512-vNPfkLj5Ij5111UTiYuwgxMqE7DRbOS2y58O2DIySzSHbcnu+nipmRKg+P0doRq6eKIJStyBK8dQi5Ic8pFyDw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-freebsd-x64": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-freebsd-x64/-/argon2-freebsd-x64-2.0.2.tgz",
|
||||
"integrity": "sha512-M8vQZk01qojQfCqQU0/O1j1a4zPPrz93zc9fSINY7Q/6RhQRBCYwDw7ltDCZXg5JRGlSaeS8cUXWyhPGar3cGg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-linux-arm-gnueabihf": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm-gnueabihf/-/argon2-linux-arm-gnueabihf-2.0.2.tgz",
|
||||
"integrity": "sha512-7EmmEPHLzcu0G2GDh30L6G48CH38roFC2dqlQJmtRCxs6no3tTE/pvgBGatTp/o2n2oyOJcfmgndVFcUpwMnww==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-linux-arm64-gnu": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-gnu/-/argon2-linux-arm64-gnu-2.0.2.tgz",
|
||||
"integrity": "sha512-6lsYh3Ftbk+HAIZ7wNuRF4SZDtxtFTfK+HYFAQQyW7Ig3LHqasqwfUKRXVSV5tJ+xTnxjqgKzvZSUJCAyIfHew==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-linux-arm64-musl": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-arm64-musl/-/argon2-linux-arm64-musl-2.0.2.tgz",
|
||||
"integrity": "sha512-p3YqVMNT/4DNR67tIHTYGbedYmXxW9QlFmF39SkXyEbGQwpgSf6pH457/fyXBIYznTU/smnG9EH+C1uzT5j4hA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-linux-x64-gnu": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-gnu/-/argon2-linux-x64-gnu-2.0.2.tgz",
|
||||
"integrity": "sha512-ZM3jrHuJ0dKOhvA80gKJqBpBRmTJTFSo2+xVZR+phQcbAKRlDMSZMFDiKbSTnctkfwNFtjgDdh5g1vaEV04AvA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-linux-x64-musl": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-linux-x64-musl/-/argon2-linux-x64-musl-2.0.2.tgz",
|
||||
"integrity": "sha512-of5uPqk7oCRF/44a89YlWTEfjsftPywyTULwuFDKyD8QtVZoonrJR6ZWvfFE/6jBT68S0okAkAzzMEdBVWdxWw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-wasm32-wasi": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-wasm32-wasi/-/argon2-wasm32-wasi-2.0.2.tgz",
|
||||
"integrity": "sha512-U3PzLYKSQYzTERstgtHLd4ZTkOF9co57zTXT77r0cVUsleGZOrd6ut7rHzeWwoJSiHOVxxa0OhG1JVQeB7lLoQ==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@napi-rs/wasm-runtime": "^0.2.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-win32-arm64-msvc": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-arm64-msvc/-/argon2-win32-arm64-msvc-2.0.2.tgz",
|
||||
"integrity": "sha512-Eisd7/NM0m23ijrGr6xI2iMocdOuyl6gO27gfMfya4C5BODbUSP7ljKJ7LrA0teqZMdYHesRDzx36Js++/vhiQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-win32-ia32-msvc": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-ia32-msvc/-/argon2-win32-ia32-msvc-2.0.2.tgz",
|
||||
"integrity": "sha512-GsE2ezwAYwh72f9gIjbGTZOf4HxEksb5M2eCaj+Y5rGYVwAdt7C12Q2e9H5LRYxWcFvLH4m4jiSZpQQ4upnPAQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/argon2-win32-x64-msvc": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@node-rs/argon2-win32-x64-msvc/-/argon2-win32-x64-msvc-2.0.2.tgz",
|
||||
"integrity": "sha512-cJxWXanH4Ew9CfuZ4IAEiafpOBCe97bzoKowHCGk5lG/7kR4WF/eknnBlHW9m8q7t10mKq75kruPLtbSDqgRTw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-beta.27",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
|
||||
@@ -1153,6 +1446,16 @@
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@tybys/wasm-util": {
|
||||
"version": "0.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
|
||||
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
@@ -2691,6 +2994,13 @@
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"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/type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
|
||||
+3
-1
@@ -8,9 +8,11 @@
|
||||
"dev:web": "vite",
|
||||
"dev:server": "node server/index.mjs",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
"preview": "node scripts/preview.mjs",
|
||||
"dev:preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@node-rs/argon2": "^2.0.2",
|
||||
"express": "^4.21.2",
|
||||
"mysql2": "^3.22.5",
|
||||
"react": "^19.0.0",
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env node
|
||||
import { spawn } from 'node:child_process';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
function spawnChild(command, args, label) {
|
||||
const child = spawn(command, args, {
|
||||
cwd: root,
|
||||
stdio: 'inherit',
|
||||
env: process.env,
|
||||
});
|
||||
child.on('exit', (code, signal) => {
|
||||
if (signal) return;
|
||||
if (code && code !== 0) shutdown(code ?? 1);
|
||||
});
|
||||
return child;
|
||||
}
|
||||
|
||||
let server;
|
||||
let web;
|
||||
let stopping = false;
|
||||
|
||||
function shutdown(code = 0) {
|
||||
if (stopping) return;
|
||||
stopping = true;
|
||||
server?.kill('SIGTERM');
|
||||
web?.kill('SIGTERM');
|
||||
setTimeout(() => process.exit(code), 200).unref();
|
||||
}
|
||||
|
||||
process.on('SIGINT', () => shutdown(0));
|
||||
process.on('SIGTERM', () => shutdown(0));
|
||||
|
||||
console.log('==> 启动 Admin API (memind_adm/server)');
|
||||
server = spawnChild('node', ['server/index.mjs'], 'server');
|
||||
|
||||
setTimeout(() => {
|
||||
console.log('==> 启动 vite preview @ http://127.0.0.1:5174');
|
||||
web = spawnChild('npm', ['run', 'dev:preview', ...args], 'web');
|
||||
}, 800);
|
||||
@@ -4,9 +4,12 @@ set -euo pipefail
|
||||
|
||||
ROOT="${ADM_ROOT:-/Users/john/Project/memind_adm}"
|
||||
PORT="${ADM_PORT:-5174}"
|
||||
NODE_PATH="${LAN_NODE_PATH:-/opt/homebrew/opt/node@22/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin}"
|
||||
NODE_PATH="${LAN_NODE_PATH:-/opt/homebrew/opt/node@24/bin:/opt/homebrew/opt/node@22/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin}"
|
||||
API_PORT="${ADM_API_PORT:-8085}"
|
||||
LOG="${ROOT}/adm-preview.log"
|
||||
API_LOG="${ROOT}/adm-api.log"
|
||||
PID_FILE="${ROOT}/.adm-preview.pid"
|
||||
API_PID_FILE="${ROOT}/.adm-api.pid"
|
||||
|
||||
export PATH="${NODE_PATH}:${PATH}"
|
||||
command -v node >/dev/null 2>&1 || { echo "❌ 未找到 node" >&2; exit 1; }
|
||||
@@ -23,19 +26,36 @@ if [[ ! -d node_modules ]]; then
|
||||
npm install
|
||||
fi
|
||||
|
||||
echo "==> 停止旧进程 (port ${PORT})..."
|
||||
echo "==> 停止旧进程 (port ${PORT}, ${API_PORT})..."
|
||||
lsof -ti "TCP:${PORT}" -sTCP:LISTEN 2>/dev/null | xargs kill 2>/dev/null || true
|
||||
lsof -ti "TCP:${API_PORT}" -sTCP:LISTEN 2>/dev/null | xargs kill 2>/dev/null || true
|
||||
sleep 1
|
||||
lsof -ti "TCP:${PORT}" -sTCP:LISTEN 2>/dev/null | xargs kill -9 2>/dev/null || true
|
||||
lsof -ti "TCP:${API_PORT}" -sTCP:LISTEN 2>/dev/null | xargs kill -9 2>/dev/null || true
|
||||
|
||||
echo "==> 启动 Admin API @ 127.0.0.1:${API_PORT}..."
|
||||
nohup node server/index.mjs >>"${API_LOG}" 2>&1 &
|
||||
echo $! >"${API_PID_FILE}"
|
||||
sleep 2
|
||||
|
||||
if ! curl -sf "http://127.0.0.1:${API_PORT}/health" >/dev/null; then
|
||||
echo "❌ Admin API 启动失败,最近日志:" >&2
|
||||
tail -n 40 "${API_LOG}" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> 启动 vite preview @ 127.0.0.1:${PORT}..."
|
||||
nohup npm run preview -- --host 127.0.0.1 --port "${PORT}" >>"${LOG}" 2>&1 &
|
||||
nohup npm run dev:preview -- --host 127.0.0.1 --port "${PORT}" >>"${LOG}" 2>&1 &
|
||||
echo $! >"${PID_FILE}"
|
||||
sleep 2
|
||||
|
||||
if curl -sf "http://127.0.0.1:${PORT}/" >/dev/null; then
|
||||
echo "✅ memind_adm 已就绪: http://127.0.0.1:${PORT}/"
|
||||
curl -sf "http://127.0.0.1:${PORT}/" >/dev/null && echo " 首页 OK"
|
||||
curl -sf -X POST "http://127.0.0.1:${PORT}/auth/login" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"username":"admin","password":"981122"}' >/dev/null \
|
||||
&& echo " 登录 OK" || echo " ⚠️ 登录接口异常,请检查 ${API_LOG}"
|
||||
else
|
||||
echo "❌ 启动失败,最近日志:" >&2
|
||||
tail -n 40 "${LOG}" >&2 || true
|
||||
|
||||
+9
-17
@@ -1,5 +1,5 @@
|
||||
import express from 'express';
|
||||
import { paginateArray, listUsagePaged, listLedgerPaged } from './pagination.mjs';
|
||||
import { listUsagePaged, listLedgerPaged } from './pagination.mjs';
|
||||
|
||||
export function createAdminApp(services) {
|
||||
const { userAuth, llmProviderService, pool, ready } = services;
|
||||
@@ -100,22 +100,14 @@ export function createAdminApp(services) {
|
||||
};
|
||||
|
||||
adminApi.get('/users', requireAdmin, async (req, res) => {
|
||||
let users = await userAuth.listUsers();
|
||||
const search = typeof req.query.search === 'string' ? req.query.search.trim().toLowerCase() : '';
|
||||
const role = typeof req.query.role === 'string' ? req.query.role.trim() : '';
|
||||
const status = typeof req.query.status === 'string' ? req.query.status.trim() : '';
|
||||
if (search) {
|
||||
users = users.filter(
|
||||
(user) =>
|
||||
user.username?.toLowerCase().includes(search) ||
|
||||
user.displayName?.toLowerCase().includes(search) ||
|
||||
user.email?.toLowerCase().includes(search),
|
||||
);
|
||||
}
|
||||
if (role) users = users.filter((user) => user.role === role);
|
||||
if (status) users = users.filter((user) => user.status === status);
|
||||
const paged = paginateArray(users, req.query, 20);
|
||||
res.json({ users: paged.items, total: paged.total, page: paged.page, pageSize: paged.pageSize });
|
||||
const result = await userAuth.listUsers({
|
||||
page: Number(req.query.page) || 1,
|
||||
pageSize: Number(req.query.pageSize) || 20,
|
||||
search: typeof req.query.search === 'string' ? req.query.search.trim() : '',
|
||||
role: typeof req.query.role === 'string' ? req.query.role.trim() : '',
|
||||
status: typeof req.query.status === 'string' ? req.query.status.trim() : '',
|
||||
});
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
adminApi.get('/summary', requireAdmin, async (_req, res) => {
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import crypto from 'node:crypto';
|
||||
import { Algorithm, hashRawSync } from '@node-rs/argon2';
|
||||
|
||||
/** Node < 24 无 crypto.argon2Sync,Memind user-auth 登录会崩溃。 */
|
||||
export function ensureArgon2Sync() {
|
||||
if (typeof crypto.argon2Sync === 'function') return;
|
||||
|
||||
crypto.argon2Sync = (algorithm, options = {}) => {
|
||||
if (algorithm !== 'argon2id') {
|
||||
throw new Error(`unsupported argon2 algorithm: ${algorithm}`);
|
||||
}
|
||||
const message = options.message ?? '';
|
||||
const nonce = options.nonce ?? Buffer.alloc(0);
|
||||
return hashRawSync(String(message), {
|
||||
algorithm: Algorithm.Argon2id,
|
||||
salt: nonce,
|
||||
parallelism: options.parallelism ?? 1,
|
||||
outputLen: options.tagLength ?? 32,
|
||||
memoryCost: options.memory ?? 65536,
|
||||
timeCost: options.passes ?? 3,
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
import { ensureArgon2Sync } from './argon2-polyfill.mjs';
|
||||
import { loadProjectEnv } from './load-env.mjs';
|
||||
|
||||
ensureArgon2Sync();
|
||||
import { bootstrapAdminServices } from './bootstrap.mjs';
|
||||
import { importMemind } from './lib-path.mjs';
|
||||
import { createAdminApp } from './app.mjs';
|
||||
|
||||
Reference in New Issue
Block a user