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",
|
"name": "tkmind-admin",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@node-rs/argon2": "^2.0.2",
|
||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"mysql2": "^3.22.5",
|
"mysql2": "^3.22.5",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
@@ -304,6 +305,37 @@
|
|||||||
"node": ">=6.9.0"
|
"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": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.25.12",
|
"version": "0.25.12",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
||||||
@@ -796,6 +828,267 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@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": {
|
"node_modules/@rolldown/pluginutils": {
|
||||||
"version": "1.0.0-beta.27",
|
"version": "1.0.0-beta.27",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
|
||||||
@@ -1153,6 +1446,16 @@
|
|||||||
"win32"
|
"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": {
|
"node_modules/@types/babel__core": {
|
||||||
"version": "7.20.5",
|
"version": "7.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||||
@@ -2691,6 +2994,13 @@
|
|||||||
"node": ">=0.6"
|
"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": {
|
"node_modules/type-is": {
|
||||||
"version": "1.6.18",
|
"version": "1.6.18",
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||||
|
|||||||
+3
-1
@@ -8,9 +8,11 @@
|
|||||||
"dev:web": "vite",
|
"dev:web": "vite",
|
||||||
"dev:server": "node server/index.mjs",
|
"dev:server": "node server/index.mjs",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview"
|
"preview": "node scripts/preview.mjs",
|
||||||
|
"dev:preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@node-rs/argon2": "^2.0.2",
|
||||||
"express": "^4.21.2",
|
"express": "^4.21.2",
|
||||||
"mysql2": "^3.22.5",
|
"mysql2": "^3.22.5",
|
||||||
"react": "^19.0.0",
|
"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}"
|
ROOT="${ADM_ROOT:-/Users/john/Project/memind_adm}"
|
||||||
PORT="${ADM_PORT:-5174}"
|
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"
|
LOG="${ROOT}/adm-preview.log"
|
||||||
|
API_LOG="${ROOT}/adm-api.log"
|
||||||
PID_FILE="${ROOT}/.adm-preview.pid"
|
PID_FILE="${ROOT}/.adm-preview.pid"
|
||||||
|
API_PID_FILE="${ROOT}/.adm-api.pid"
|
||||||
|
|
||||||
export PATH="${NODE_PATH}:${PATH}"
|
export PATH="${NODE_PATH}:${PATH}"
|
||||||
command -v node >/dev/null 2>&1 || { echo "❌ 未找到 node" >&2; exit 1; }
|
command -v node >/dev/null 2>&1 || { echo "❌ 未找到 node" >&2; exit 1; }
|
||||||
@@ -23,19 +26,36 @@ if [[ ! -d node_modules ]]; then
|
|||||||
npm install
|
npm install
|
||||||
fi
|
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:${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
|
sleep 1
|
||||||
lsof -ti "TCP:${PORT}" -sTCP:LISTEN 2>/dev/null | xargs kill -9 2>/dev/null || true
|
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}..."
|
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}"
|
echo $! >"${PID_FILE}"
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
if curl -sf "http://127.0.0.1:${PORT}/" >/dev/null; then
|
if curl -sf "http://127.0.0.1:${PORT}/" >/dev/null; then
|
||||||
echo "✅ memind_adm 已就绪: http://127.0.0.1:${PORT}/"
|
echo "✅ memind_adm 已就绪: http://127.0.0.1:${PORT}/"
|
||||||
curl -sf "http://127.0.0.1:${PORT}/" >/dev/null && echo " 首页 OK"
|
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
|
else
|
||||||
echo "❌ 启动失败,最近日志:" >&2
|
echo "❌ 启动失败,最近日志:" >&2
|
||||||
tail -n 40 "${LOG}" >&2 || true
|
tail -n 40 "${LOG}" >&2 || true
|
||||||
|
|||||||
+9
-17
@@ -1,5 +1,5 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { paginateArray, listUsagePaged, listLedgerPaged } from './pagination.mjs';
|
import { listUsagePaged, listLedgerPaged } from './pagination.mjs';
|
||||||
|
|
||||||
export function createAdminApp(services) {
|
export function createAdminApp(services) {
|
||||||
const { userAuth, llmProviderService, pool, ready } = services;
|
const { userAuth, llmProviderService, pool, ready } = services;
|
||||||
@@ -100,22 +100,14 @@ export function createAdminApp(services) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
adminApi.get('/users', requireAdmin, async (req, res) => {
|
adminApi.get('/users', requireAdmin, async (req, res) => {
|
||||||
let users = await userAuth.listUsers();
|
const result = await userAuth.listUsers({
|
||||||
const search = typeof req.query.search === 'string' ? req.query.search.trim().toLowerCase() : '';
|
page: Number(req.query.page) || 1,
|
||||||
const role = typeof req.query.role === 'string' ? req.query.role.trim() : '';
|
pageSize: Number(req.query.pageSize) || 20,
|
||||||
const status = typeof req.query.status === 'string' ? req.query.status.trim() : '';
|
search: typeof req.query.search === 'string' ? req.query.search.trim() : '',
|
||||||
if (search) {
|
role: typeof req.query.role === 'string' ? req.query.role.trim() : '',
|
||||||
users = users.filter(
|
status: typeof req.query.status === 'string' ? req.query.status.trim() : '',
|
||||||
(user) =>
|
});
|
||||||
user.username?.toLowerCase().includes(search) ||
|
res.json(result);
|
||||||
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 });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
adminApi.get('/summary', requireAdmin, async (_req, res) => {
|
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';
|
import { loadProjectEnv } from './load-env.mjs';
|
||||||
|
|
||||||
|
ensureArgon2Sync();
|
||||||
import { bootstrapAdminServices } from './bootstrap.mjs';
|
import { bootstrapAdminServices } from './bootstrap.mjs';
|
||||||
import { importMemind } from './lib-path.mjs';
|
import { importMemind } from './lib-path.mjs';
|
||||||
import { createAdminApp } from './app.mjs';
|
import { createAdminApp } from './app.mjs';
|
||||||
|
|||||||
Reference in New Issue
Block a user