Browse Source

fixed

theme
npmrun 2 years ago
parent
commit
6f195d395e
  1. 1
      packages/hapi-router/.gitignore
  2. 4
      packages/hapi-router/README.MD
  3. 477
      packages/hapi-router/dist/hapi-router.cjs.js
  4. 1
      packages/hapi-router/dist/hapi-router.cjs.js.map
  5. 25
      packages/hapi-router/dist/index.d.ts
  6. 4
      packages/hapi-router/global.d.ts
  7. 1961
      packages/hapi-router/package-lock.json
  8. 42
      packages/hapi-router/package.json
  9. 1179
      packages/hapi-router/pnpm-lock.yaml
  10. 113
      packages/hapi-router/rollup.config.js
  11. 24
      packages/hapi-router/scripts/build.js
  12. 7
      packages/hapi-router/scripts/dev.js
  13. 0
      packages/hapi-router/scripts/publish.js
  14. 190
      packages/hapi-router/src/index.ts
  15. 40
      packages/hapi-router/src/util/decorators.ts
  16. 81
      packages/hapi-router/src/util/index.ts
  17. 37
      packages/hapi-router/tsconfig.json
  18. 2
      pnpm-workspace.yaml
  19. 13
      route.txt
  20. BIN
      source/db/data.db
  21. 29
      source/plugins/router-plugin/index.ts
  22. 6
      source/plugins/router-plugin/util/decorators.ts
  23. 113
      source/route/views/index.ts
  24. 31
      source/route/views/index/index.ts
  25. 46
      source/route/views/login.ts
  26. 53
      source/route/views/register.ts
  27. 24
      source/route/views/user.ts
  28. 1
      template/htmx/path/about.pug
  29. 1
      template/htmx/path/index.pug
  30. 4
      template/ui/header.pug

1
packages/hapi-router/.gitignore

@ -1 +0,0 @@
node_modules

4
packages/hapi-router/README.MD

@ -1,4 +0,0 @@
# @noderun/hapi-router
> 发布:npm publish --access public
> 删除:npm unpublish --force

477
packages/hapi-router/dist/hapi-router.cjs.js

@ -1,477 +0,0 @@
#!/usr/bin/env node
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var Joi = require('joi');
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () {
return e[k];
}
});
}
});
}
n['default'] = e;
return Object.freeze(n);
}
var Joi__namespace = /*#__PURE__*/_interopNamespace(Joi);
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
function __values(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}
function __read(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
}
function __spread() {
for (var ar = [], i = 0; i < arguments.length; i++)
ar = ar.concat(__read(arguments[i]));
return ar;
}
var path$1 = require("path");
var fs$1 = require("fs");
function removeIndex(ss) {
var remove = function (str) {
if (str.endsWith("/index")) {
return str.slice(0, -6);
}
if (str.endsWith("index")) {
return str.slice(0, -5);
}
return str ? str : "/";
};
var r = true;
var rr = ss;
while (r) {
if (rr.endsWith("/index")) {
rr = remove(rr);
}
else {
r = false;
}
}
return rr ? rr : "/";
}
function isIndexEnd(str) {
return str.length == 1 && str.endsWith("/");
}
function walkDir(filePath, exclude) {
if (exclude === void 0) { exclude = ["node_modules", "^_", ".git", ".idea", ".gitignore", "client", "\.txt$", "\.test\.js$", "\.test\.ts$"]; }
var files = [];
function Data(opts) {
this.relativeDir = opts.relativeDir;
this.relativeFile = opts.relativeFile;
this.filename = opts.filename;
this.file = opts.file;
this.absoluteFile = opts.absoluteFile;
this.relativeFileNoExt = opts.relativeFileNoExt;
this.absoluteDir = opts.absoluteDir;
}
function readDir(filePath, dirname) {
if (dirname === void 0) { dirname = "."; }
var res = fs$1.readdirSync(filePath);
res.forEach(function (filename) {
var filepath = path$1.resolve(filePath, filename);
var stat = fs$1.statSync(filepath);
var name = filepath.split(path$1.sep).slice(-1)[0];
if (typeof exclude === "string" && new RegExp(exclude).test(name)) {
return;
}
if (Array.isArray(exclude)) {
for (var i = 0; i < exclude.length; i++) {
var excludeItem = exclude[i];
if (new RegExp(excludeItem).test(name)) {
return;
}
}
}
if (!stat.isFile()) {
readDir(filepath, dirname + path$1.sep + name);
}
else {
var data = new Data({
relativeDir: dirname,
relativeFile: dirname + path$1.sep + path$1.parse(filepath).base,
relativeFileNoExt: dirname + path$1.sep + path$1.parse(filepath).name,
file: path$1.parse(filepath).base,
filename: path$1.parse(filepath).name,
absoluteFile: filepath,
absoluteDir: path$1.parse(filepath).dir,
});
files.push(data);
}
});
}
readDir(filePath);
return files;
}
function method(opts) {
return function (target, propertyKey, descriptor) {
target[propertyKey].$method = opts;
};
}
function route(route) {
return function (target, propertyKey, descriptor) {
target[propertyKey].$route = route;
};
}
function config(options) {
return function (target, propertyKey, descriptor) {
target[propertyKey].$options = options;
};
}
function auth(isAuth) {
if (isAuth === void 0) { isAuth = true; }
return function (target, propertyKey, descriptor) {
target[propertyKey].$auth = isAuth;
};
}
function validate(validate) {
return function (target, propertyKey, descriptor) {
target[propertyKey].$validate = validate;
};
}
function swagger(desc, notes, tags) {
return function (target, propertyKey, descriptor) {
target[propertyKey].$swagger = [desc, notes, tags];
};
}
var path = require("path");
var fs = require("fs");
var routePlugin = (function () {
function routePlugin() {
this.name = "routePlugin";
this.version = "0.0.1";
}
routePlugin.prototype.register = function (server, opts) {
var sourceDir = opts.sourceDir;
var type = opts.type || "jwt";
var auth = opts.auth || [];
var array = [];
for (var i = 0; i < sourceDir.length; i++) {
var dir = sourceDir[i];
console.log(dir);
array.push(dir.dir + "对应路径:");
array = array.concat(this.registerRoute(server, dir.dir, dir.prefix || "", auth, type));
}
fs.writeFileSync(path.resolve(process.cwd(), "route.txt"), array.join("\n"), {
encoding: "utf-8",
});
};
routePlugin.prototype.registerRoute = function (server, sourceDir, prefix, auth, type) {
var files = walkDir(sourceDir);
var routes = [];
files.forEach(function (file) {
var e_1, _a;
var filename = file.relativeFileNoExt;
var array = filename.split(path.sep).slice(1);
var fileNoExt = removeIndex("/" + array.join("/"));
var moduleName = path.resolve(sourceDir, filename);
var obj = require(moduleName);
if (obj.default) {
var func = new (obj.default || obj)();
var prototype = Object.getPrototypeOf(func);
var keys = Reflect.ownKeys(prototype);
var _loop_1 = function (key) {
if (key !== "constructor") {
var ff_1 = func[key];
var handler = undefined;
var method = ff_1.$method || "GET";
var route_1 = "";
if (ff_1.$route) {
if (isIndexEnd(fileNoExt)) {
route_1 = ff_1.$route;
}
else {
route_1 = fileNoExt + ff_1.$route;
}
}
else {
if (isIndexEnd(fileNoExt)) {
route_1 = fileNoExt + key.toString();
}
else {
route_1 = fileNoExt + "/" + key.toString();
}
}
route_1 = removeIndex(route_1);
route_1 = prefix ? route_1[0] + prefix + "/" + route_1.slice(1) : route_1;
var options = ff_1.$options ? ff_1.$options : {};
if (!options.auth) {
if (ff_1.$auth == undefined) {
if (auth &&
auth.length &&
auth.filter(function (v) { return route_1.startsWith(v); }).length) {
options.auth = type;
}
else {
options.auth = false;
}
}
else if (ff_1.$auth) {
options.auth =
typeof ff_1.$auth === "boolean"
? type
: {
strategy: type,
mode: ff_1.$auth,
};
}
else {
options.auth = false;
}
}
if (!options.validate) {
var validateObj = ff_1.$validate || {};
if (options.auth && type === "jwt") {
if (validateObj.headers) {
validateObj.headers = validateObj.headers.keys({
Authorization: Joi__namespace.string(),
});
}
else {
validateObj.headers = Joi__namespace.object({
headers: Joi__namespace.object({
Authorization: Joi__namespace.string(),
}).unknown(),
});
}
}
if (validateObj && !!Object.keys(validateObj).length) {
var failReason_1 = validateObj.failReason;
delete validateObj.failReason;
if (validateObj.failAction === "log") {
if (!options.log)
options.log = {};
options.log.collect = true;
var errto_1 = validateObj.$errto;
handler = function () {
var argus = [];
for (var _i = 0; _i < arguments.length; _i++) {
argus[_i] = arguments[_i];
}
return __awaiter(this, void 0, void 0, function () {
var request, h;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
request = argus[0];
h = argus[1];
if (request.logs && !!request.logs.length && errto_1) {
request.yar.flash('error', failReason_1);
return [2, h.redirect(errto_1)];
}
return [4, ff_1.call.apply(ff_1, __spread([this], argus))];
case 1: return [2, _a.sent()];
}
});
});
};
}
if (validateObj.failAction === "function") {
var errto_2 = validateObj.$errto;
validateObj.failAction = function (request, h, err) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
if (err.details) {
request.$joi_error = err.details.map(function (v) { return v.message; });
}
return [2, h.continue];
});
});
};
handler = function () {
var argus = [];
for (var _i = 0; _i < arguments.length; _i++) {
argus[_i] = arguments[_i];
}
return __awaiter(this, void 0, void 0, function () {
var request, h;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
request = argus[0];
h = argus[1];
if (request.$joi_error) {
loggerSite.debug('传输参数错误: ', request.$joi_error);
request.yar.flash('error', failReason_1);
delete request.$joi_error;
return [2, h.redirect(errto_2)];
}
return [4, ff_1.call.apply(ff_1, __spread([this], argus))];
case 1: return [2, _a.sent()];
}
});
});
};
}
options.validate = validateObj;
}
}
if (ff_1.$swagger) {
options.description = ff_1.$swagger[0];
options.notes = ff_1.$swagger[1];
options.tags = ff_1.$swagger[2];
}
var str = route_1;
if ((typeof options.auth === "string" && options.auth) ||
(typeof options.auth === "object" &&
options.auth.mode === "required")) {
str =
" 需要权限 : " + " " + full(method) + " " + str;
}
else if (typeof options.auth === "object" &&
options.auth.mode === "optional") {
str =
" 不需权限(提供即需验证): " + " " + full(method) + " " + str;
}
else if (typeof options.auth === "object" &&
options.auth.mode === "try") {
str =
" 不需权限(提供无需验证): " + " " + full(method) + " " + str;
}
else {
str =
" 不需权限 : " + " " + full(method) + " " + str;
}
routes.push(str);
if (options.validate && options.validate.$errto) {
delete options.validate.$errto;
}
if (!handler) {
handler = ff_1;
}
server.route({
method: method,
path: route_1,
handler: handler,
options: options,
});
}
};
try {
for (var keys_1 = __values(keys), keys_1_1 = keys_1.next(); !keys_1_1.done; keys_1_1 = keys_1.next()) {
var key = keys_1_1.value;
_loop_1(key);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (keys_1_1 && !keys_1_1.done && (_a = keys_1.return)) _a.call(keys_1);
}
finally { if (e_1) throw e_1.error; }
}
}
});
return routes;
};
return routePlugin;
}());
function full(str, length) {
if (length === void 0) { length = 10; }
var len = str.length;
var need = length - len;
if (need <= 0)
return str;
return str + __spread(Array(need)).map(function (v, i) { return " "; }).join("");
}
var plugin = new routePlugin();
exports.auth = auth;
exports.config = config;
exports.method = method;
exports.plugin = plugin;
exports.route = route;
exports.swagger = swagger;
exports.validate = validate;
//# sourceMappingURL=hapi-router.cjs.js.map

1
packages/hapi-router/dist/hapi-router.cjs.js.map

File diff suppressed because one or more lines are too long

25
packages/hapi-router/dist/index.d.ts

@ -1,25 +0,0 @@
// Generated by dts-bundle v0.7.3
declare module '@noderun/hapi-router' {
class routePlugin {
name: string;
version: string;
register(server: any, opts: any): void;
registerRoute(server: any, sourceDir: any, prefix: any, auth: any, type: any): any[];
}
const plugin: routePlugin;
export { plugin };
export * from "@noderun/hapi-router/util/decorators";
}
declare module '@noderun/hapi-router/util/decorators' {
type TMethod = "GET" | "POST" | "PUT" | "DELETE";
export function method(opts?: TMethod | Array<TMethod>): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export function route(route?: string): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export function config(options: Object): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export function auth(isAuth?: boolean | "try" | "required" | "optional"): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export function validate(validate: Object): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export function swagger(desc: any, notes: any, tags: any): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
export {};
}

4
packages/hapi-router/global.d.ts

@ -1,4 +0,0 @@
// 全局替换
declare var __DEV__: boolean;

1961
packages/hapi-router/package-lock.json

File diff suppressed because it is too large

42
packages/hapi-router/package.json

@ -1,42 +0,0 @@
{
"name": "@noderun/hapi-router",
"version": "0.0.1",
"description": "",
"main": "dist/hapi-router.cjs.js",
"typings": "dist/index.d.ts",
"buildOptions": {
"filename": "hapi-router",
"var": "hapiRouter",
"formats": [
"cjs"
]
},
"scripts": {
"build": "node scripts/build.js",
"dev": "node scripts/dev.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@rollup/plugin-alias": "^3.1.1",
"@rollup/plugin-commonjs": "^15.0.0",
"@rollup/plugin-replace": "^2.3.3",
"@types/node": "^15.12.2",
"chalk": "^4.1.0",
"dts-bundle": "^0.7.3",
"execa": "^4.0.3",
"fs-extra": "^9.0.1",
"ftp-deploy": "^2.3.6",
"lodash": "^4.17.20",
"rollup": "^2.26.3",
"rollup-plugin-sourcemaps": "^0.6.2",
"rollup-plugin-typescript2": "^0.27.2",
"tslib": "^2.0.1",
"typescript": "^3.9.7"
},
"dependencies": {
"joi": "^17.4.0",
"json-merge-patch": "^1.0.1"
}
}

1179
packages/hapi-router/pnpm-lock.yaml

File diff suppressed because it is too large

113
packages/hapi-router/rollup.config.js

@ -1,113 +0,0 @@
import commonjs from "@rollup/plugin-commonjs";
import typescript from "rollup-plugin-typescript2";
import alias from "@rollup/plugin-alias";
import replace from "@rollup/plugin-replace";
import sourcemaps from "rollup-plugin-sourcemaps";
const pkg = require("./package.json");
const path = require("path");
let isProd = process.env.NODE_ENV === "production";
const input = "src/index.ts";
const openSourceMap = true;
const buildOptions = pkg.buildOptions;
buildOptions.formats = process.env.TARGET
? [process.env.TARGET]
: buildOptions.formats;
export default createConfig();
function createConfig() {
return {
input,
external: ['joi'],
output: createOutput(buildOptions),
plugins: createPlugin(),
};
}
function createPlugin() {
let plugin = [];
const aliasPlugin = alias({
resolve: [".ts"],
"@": path.resolve(__dirname, "src"),
});
const tsPlugin = typescript({
check: isProd,
tsconfig: path.resolve(__dirname, "tsconfig.json"),
cacheRoot: path.resolve(__dirname, "node_modules/.rts2_cache"),
tsconfigOverride: {
compilerOptions: {
declaration: isProd,
},
},
});
const replacePlugin = replace({
__DEV__: isProd,
preventAssignment: true
});
plugin = [sourcemaps(), commonjs(), tsPlugin, aliasPlugin, replacePlugin];
return plugin;
}
function createOutput(options) {
const output = [];
const filterType = {
//可用script标签导入,会输出一个全局变量
iife: {
sourcemap: openSourceMap,
file: `dist/${options.filename}.iife.js`,
format: "iife",
name: options.var,
},
// amd规范,可用require.js加载
amd: {
sourcemap: openSourceMap,
file: `dist/${options.filename}.amd.js`,
format: "amd",
},
// 兼容 IIFE, AMD, CJS 三种模块规范
umd: {
sourcemap: openSourceMap,
file: `dist/${options.filename}.umd.js`,
format: "umd",
name: options.var,
},
// CommonJS规范
cjs: {
sourcemap: openSourceMap,
file: `dist/${options.filename}.cjs.js`,
format: "cjs",
exports: "auto",
banner: "#!/usr/bin/env node", // 提供命令行的可执行权限
},
// ES2015 Module 规范, 可用 `Webpack`, `Rollup` 加载
esm: {
sourcemap: openSourceMap,
file: `dist/${options.filename}.esm.js`,
format: "es",
},
"esm-browser": {
sourcemap: openSourceMap,
file: `dist/${options.filename}.esm-browser.js`,
format: "es",
},
};
if (options.formats) {
options.formats.forEach((format) => {
if (filterType[format]) {
output.push(filterType[format]);
} else {
console.error("无效类型:" + format);
}
});
} else {
for (const key in filterType) {
if (filterType.hasOwnProperty(key)) {
const element = filterType[key];
output.push(element);
}
}
}
return output;
}

24
packages/hapi-router/scripts/build.js

@ -1,24 +0,0 @@
const execa = require("execa");
const fs = require("fs-extra");
const chalk = require('chalk');
const dts = require("dts-bundle");
const pkg = require("../package.json");
(async function () {
console.log(chalk.red("正在清理dist文件夹"));
await fs.remove(`dist`);
console.log(chalk.red("清理完成,开始构建"));
await execa("rollup", ["-c", "--environment", `NODE_ENV:production`], {
stdio: "inherit",
});
console.log(chalk.red("构建完成,开始生成d.ts"));
const dtsOptions = {
name: pkg.name,
main: `dist/src/index.d.ts`,
out: `../index.d.ts`,
};
dts.bundle(dtsOptions);
console.log(chalk.red("生成完毕,开始清理残余"));
await fs.remove(`dist/src`);
console.log('所有文件清理完成');
})();

7
packages/hapi-router/scripts/dev.js

@ -1,7 +0,0 @@
const execa = require("execa");
const chalk = require('chalk');
console.log(chalk.red("开始监听,格式:umd"));
execa("rollup", ["-wc", "--environment", `NODE_ENV:development,TARGET:cjs`], {
stdio: "inherit",
});

0
packages/hapi-router/scripts/publish.js

190
packages/hapi-router/src/index.ts

@ -1,190 +0,0 @@
// @ts-nocheck
import { walkDir, removeIndex, isIndexEnd } from "./util"
import * as Joi from "joi"
const path = require("path")
const fs = require("fs")
class routePlugin {
public name: string = "routePlugin"
public version: string = "0.0.1"
public register(server: any, opts: any) {
const sourceDir = opts.sourceDir
const type = opts.type || "jwt"
const auth = opts.auth || []
let array = []
for (let i = 0; i < sourceDir.length; i++) {
const dir = sourceDir[i]
console.log(dir)
array.push(dir.dir + "对应路径:")
array = array.concat(this.registerRoute(server, dir.dir, dir.prefix || "", auth, type))
}
fs.writeFileSync(path.resolve(process.cwd(), "route.txt"), array.join("\n"), {
encoding: "utf-8",
})
}
registerRoute(server, sourceDir, prefix, auth, type) {
const files = walkDir(sourceDir)
const routes = []
files.forEach(file => {
let filename = file.relativeFileNoExt
let array = filename.split(path.sep).slice(1)
let fileNoExt = removeIndex("/" + array.join("/"))
const moduleName = path.resolve(sourceDir, filename)
const obj = require(moduleName)
if (obj.default) {
const func = new (obj.default || obj)()
const prototype = Object.getPrototypeOf(func)
const keys = Reflect.ownKeys(prototype)
for (const key of keys) {
if (key !== "constructor") {
let ff = func[key]
let handler: () => void = undefined
// 默认方法
const method = ff.$method || "GET"
// 路由收集规则
let route = ""
if (ff.$route) {
if (isIndexEnd(fileNoExt)) {
route = ff.$route
} else {
route = fileNoExt + ff.$route
}
} else {
if (isIndexEnd(fileNoExt)) {
route = fileNoExt + key.toString()
} else {
route = fileNoExt + "/" + key.toString()
}
}
route = removeIndex(route)
route = prefix ? route[0] + prefix + "/" + route.slice(1) : route
// 配置规则
const options = ff.$options ? ff.$options : {}
if (!options.auth) {
if (ff.$auth == undefined) {
if (auth && auth.length && auth.filter(v => route.startsWith(v)).length) {
options.auth = type
} else {
options.auth = false
}
} else if (ff.$auth) {
options.auth =
typeof ff.$auth === "boolean"
? type
: {
strategy: type,
mode: ff.$auth,
}
} else {
options.auth = false
}
}
if (!options.validate) {
let validateObj = ff.$validate || {}
if (options.auth && type === "jwt") {
if (validateObj.headers) {
validateObj.headers = validateObj.headers.keys({
Authorization: Joi.string(),
})
} else {
validateObj.headers = Joi.object({
headers: Joi.object({
Authorization: Joi.string(),
}).unknown(), // 注意加上这个
})
}
}
if (validateObj && !!Object.keys(validateObj).length) {
const failReason = validateObj.failReason
delete validateObj.failReason
if (validateObj.failAction === "log") {
if (!options.log) options.log = {}
options.log.collect = true
let errto = validateObj.$errto
handler = async function (...argus) {
const request = argus[0]
const h = argus[1]
if (request.logs && !!request.logs.length && errto) {
// request.yar.flash('error', request.logs.map((v: any)=>v.error.message));
request.yar.flash("error", failReason || request.logs.map((v: any)=>v.error.message))
return h.redirect(errto)
}
return await ff.call(this, ...argus)
}
}
if (validateObj.failAction === "function") {
let errto = validateObj.$errto
validateObj.failAction = async function (request, h, err) {
if (err.details) {
request.$joi_error = err.details.map(v => v.message)
}
return h.continue
}
handler = async function (...argus) {
const request = argus[0]
const h = argus[1]
if (request.$joi_error) {
loggerSite.debug("传输参数错误: ", request.$joi_error)
request.yar.flash("error", failReason || request.$joi_error)
delete request.$joi_error
return h.redirect(errto)
}
return await ff.call(this, ...argus)
}
}
options.validate = validateObj
}
}
// && route.startsWith("/api")
if (ff.$swagger) {
options.description = ff.$swagger[0]
options.notes = ff.$swagger[1]
options.tags = ff.$swagger[2]
}
let str = route
if (
(typeof options.auth === "string" && options.auth) ||
(typeof options.auth === "object" && options.auth.mode === "required")
) {
str = " 需要权限 : " + " " + full(method) + " " + str
} else if (typeof options.auth === "object" && options.auth.mode === "optional") {
str = " 不需权限(提供即需验证): " + " " + full(method) + " " + str
} else if (typeof options.auth === "object" && options.auth.mode === "try") {
str = " 不需权限(提供无需验证): " + " " + full(method) + " " + str
} else {
str = " 不需权限 : " + " " + full(method) + " " + str
}
routes.push(str)
if (options.validate && options.validate.$errto) {
delete options.validate.$errto
}
if (!handler) {
handler = ff
}
server.route({
method: method,
path: route,
handler: handler,
options: options,
})
}
}
}
})
return routes
}
}
function full(str: string, length = 10) {
let len = str.length
let need = length - len
if (need <= 0) return str
return str + [...Array(need)].map((v, i) => " ").join("")
}
const plugin = new routePlugin()
export { plugin }
export * from "./util/decorators"

40
packages/hapi-router/src/util/decorators.ts

@ -1,40 +0,0 @@
// @ts-nocheck
/**
*
* @param opts
*/
type TMethod = "GET" | "POST" | "PUT" | "DELETE"
export function method(opts?: TMethod | Array<TMethod>) {
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
target[propertyKey].$method = opts
}
}
export function route(route?: string) {
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
target[propertyKey].$route = route
}
}
export function config(options: Object) {
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
target[propertyKey].$options = options
}
}
export function auth(isAuth: boolean | "try" | "required" | "optional" = true) {
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
target[propertyKey].$auth = isAuth
}
}
export function validate(validate: Object) {
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
target[propertyKey].$validate = validate
}
}
export function swagger(desc, notes, tags) {
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
target[propertyKey].$swagger = [desc, notes, tags]
}
}

81
packages/hapi-router/src/util/index.ts

@ -1,81 +0,0 @@
// @ts-nocheck
const path = require("path")
const fs = require("fs")
export function removeIndex(ss: any) {
const remove = (str: any) => {
if (str.endsWith("/index")) {
return str.slice(0, -6)
}
if (str.endsWith("index")) {
return str.slice(0, -5)
}
return str ? str : "/"
}
let r = true
let rr = ss
while (r) {
if (rr.endsWith("/index")) {
rr = remove(rr)
} else {
r = false
}
}
return rr ? rr : "/"
}
export function isIndexEnd(str: any) {
return str.length == 1 && str.endsWith("/")
}
export function walkDir(
filePath: any,
exclude = ["node_modules", "^_", ".git", ".idea", ".gitignore", "client", ".txt$", ".test.js$", ".test.ts$"],
) {
let files: any[] = []
function Data(opts: any) {
this.relativeDir = opts.relativeDir
this.relativeFile = opts.relativeFile
this.filename = opts.filename
this.file = opts.file
this.absoluteFile = opts.absoluteFile
this.relativeFileNoExt = opts.relativeFileNoExt
this.absoluteDir = opts.absoluteDir
}
function readDir(filePath, dirname = ".") {
let res = fs.readdirSync(filePath)
res.forEach(filename => {
const filepath = path.resolve(filePath, filename)
const stat = fs.statSync(filepath)
const name = filepath.split(path.sep).slice(-1)[0]
if (typeof exclude === "string" && new RegExp(exclude).test(name)) {
return
}
if (Array.isArray(exclude)) {
for (let i = 0; i < exclude.length; i++) {
const excludeItem = exclude[i]
if (new RegExp(excludeItem).test(name)) {
return
}
}
}
if (!stat.isFile()) {
readDir(filepath, dirname + path.sep + name)
} else {
const data = new Data({
relativeDir: dirname,
relativeFile: dirname + path.sep + path.parse(filepath).base,
relativeFileNoExt: dirname + path.sep + path.parse(filepath).name,
file: path.parse(filepath).base,
filename: path.parse(filepath).name,
absoluteFile: filepath,
absoluteDir: path.parse(filepath).dir,
})
files.push(data)
}
})
}
readDir(filePath)
return files
}

37
packages/hapi-router/tsconfig.json

@ -1,37 +0,0 @@
{
"compilerOptions": {
"allowUnreachableCode": true,
"strictNullChecks": true,
// ,
"strict": true,
"allowJs": true,
// js
"target": "ES5",
//
"module": "ES2015",
// any
"noImplicitAny": true,
// "__extends"
// "import {__extends} from 'tslib'
"importHelpers": true,
//
"removeComments": true,
// const enum
"preserveConstEnums": false,
//
"lib": ["dom", "esnext"],
"sourceMap": true,
// /forof
"downlevelIteration": true,
// node,import xx from 'xx'
"moduleResolution": "node",
"esModuleInterop": true, // esModuleInterop使import d from 'cjs'commonjs
"baseUrl": ".",
"rootDir": ".", // root
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["./src/**/*", "./global.d.ts"],
"exclude": ["node_modules"]
}

2
pnpm-workspace.yaml

@ -1,2 +0,0 @@
packages:
- 'packages/*'

13
route.txt

@ -1,17 +1,16 @@
/home/topuser/Code/@project/hapi-demo/dist/route/htmx对应路径:
D:\1XYX\pro\hapi-demo\source\route\htmx对应路径:
不需权限 : GET /htmx/path/{path*}
/home/topuser/Code/@project/hapi-demo/dist/route/views对应路径:
D:\1XYX\pro\hapi-demo\source\route\views对应路径:
不需权限(提供无需验证): GET /404
不需权限 : GET /css
不需权限(提供无需验证): GET /
不需权限(提供无需验证): GET /about
需要权限 : GET /docs/{path*}
不需权限 : GET /{path*}
不需权限(提供无需验证): GET /login
不需权限 : POST /login
需要权限 : GET /logout
需要权限 : POST /del
不需权限 : GET /nav
不需权限(提供无需验证): GET /register
不需权限 : POST /register
不需权限 : GET /nav
需要权限 : GET /user
需要权限 : GET /user
需要权限 : GET /user/logout
需要权限 : POST /user/del

BIN
source/db/data.db

Binary file not shown.

29
source/plugins/router-plugin/index.ts

@ -44,21 +44,26 @@ class routePlugin {
const method = ff.$method || "GET"
// 路由收集规则
let route = ""
if (ff.$route) {
if (isIndexEnd(fileNoExt)) {
route = ff.$route
} else {
route = fileNoExt + ff.$route
}
} else {
if (isIndexEnd(fileNoExt)) {
route = fileNoExt + key.toString()
if(ff.$route_path){
route = ff.$route_path
route = prefix ? route[0] + prefix + "/" + route.slice(1) : route
}else{
if (ff.$route) {
if (isIndexEnd(fileNoExt)) {
route = ff.$route
} else {
route = fileNoExt + ff.$route
}
} else {
route = fileNoExt + "/" + key.toString()
if (isIndexEnd(fileNoExt)) {
route = fileNoExt + key.toString()
} else {
route = fileNoExt + "/" + key.toString()
}
}
route = removeIndex(route)
route = prefix ? route[0] + prefix + "/" + route.slice(1) : route
}
route = removeIndex(route)
route = prefix ? route[0] + prefix + "/" + route.slice(1) : route
// 配置规则
const options = ff.$options ? ff.$options : {}
if (!options.auth) {

6
source/plugins/router-plugin/util/decorators.ts

@ -14,7 +14,11 @@ export function route(route?: string) {
target[propertyKey].$route = route
}
}
export function route_path(route_path?: string) {
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
target[propertyKey].$route_path = route_path
}
}
export function config(options: Object) {
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
target[propertyKey].$options = options

113
source/route/views/index.ts

@ -1,113 +0,0 @@
import { Req, Res, ReturnValue } from "#/global"
import { LoginUserSchema, RegisterUserSchema, UserSchema } from "@/schema"
import { gFail, gSuccess } from "@/util"
import { auth, config, method, route, validate } from "@noderun/hapi-router"
import * as bcrypt from "bcrypt"
/**
*
*/
export default class {
@route("/login")
@auth("try")
@method("GET")
async login_GET(request: Req, h: Res): ReturnValue {
if (request.auth.isAuthenticated) {
request.yar.flash("warning", "您已经登陆")
return h.redirect("/")
} else {
logger.debug("未登录")
}
return h.view("views/login.pug")
}
@validate({
payload: LoginUserSchema,
$errto: "/login",
// failAction: 'log'
failAction: "function",
// failReason: "用户名或密码错误,请重试",
})
@method("POST")
@route("/login")
async login_POST(request: Req, h: Res): ReturnValue {
const { username, password, referrer } = request.payload as any
const User = request.getModel("User")
const account = <any>await User.findOne({ where: { username: username } })
if (!account || !(await bcrypt.compare(password, account.password))) {
request.yar.flash("error", "Invalid username or password")
return h.redirect("/login")
}
request.cookieAuth.set({ id: account.id, nickname: account.nickname })
request.yar.flash("success", "用户已登录")
return h.redirect(referrer ? referrer : "/")
}
@method("GET")
@auth()
async logout(request: Req, h: Res): ReturnValue {
request.yar.flash("success", "用户已退出")
request.cookieAuth.clear()
return h.redirect("/")
}
@method("POST")
@auth()
async del(request: Req, h: Res): ReturnValue {
const { id } = request.auth.credentials
try {
const User = request.getModel("User")
await User.destroy({ where: { id: id }})
request.yar.flash("success", "用户已删除")
request.cookieAuth.clear()
} catch (error) {
loggerSite.error(`用户删除错误`, error.message)
request.yar.flash("error", "用户删除错误")
}
return h.redirect("/")
}
@route("/register")
@auth("try")
@method("GET")
async registerView(request: Req, h: Res): ReturnValue {
if (request.auth.isAuthenticated) {
request.yar.flash("warning", "您已经登陆")
return h.redirect("/")
} else {
logger.debug("未登录")
}
return h.view("views/register.pug")
}
@validate({
payload: RegisterUserSchema,
$errto: "/register",
failAction: "function",
failReason: "注册账户不符合规范",
})
@method("POST")
async register(request: Req, h: Res): ReturnValue {
console.log(request);
let { username, password } = request.payload as any
const User = request.getModel("User")
logger.trace("当前注册用户:" + username)
try {
const result = await User.findOne({ where: { username: username } })
if (result != null) {
request.yar.flash("error", "已存在该用户")
return h.redirect("/register")
}
let salt = bcrypt.genSaltSync(10)
let pwdLock = bcrypt.hashSync(password, salt)
await User.create({ username, password: pwdLock, nickname: username })
request.yar.flash("success", "用户注册成功")
return h.redirect("/login")
} catch (e) {
loggerSite.error(`注册用户失败`, e.message)
request.yar.flash("error", "注册用户失败")
return h.redirect("/register")
}
}
}

31
source/route/views/index/index.ts

@ -6,10 +6,6 @@ import { baseDir, gFail } from "@/util"
import MarkdownIt from "markdown-it"
export default class Index {
async css(request: Req, h: Res): ReturnValue {
return h.view("views/css.pug")
}
@auth("try")
async index(request: Req, h: Res): ReturnValue {
if (request.auth.isAuthenticated) {
@ -22,26 +18,23 @@ export default class Index {
@route("/about")
@auth("try")
async about(request: Req, h) {
// console.log(request.auth);
// console.log(1);
// try {
// const User = request.getModel("User");
// console.log(await User.findOne({ where: { username: "xieyaxin" } }));
// } catch (error) {
// console.log(error);
// }
// console.log(2);
const { id } = request.auth.credentials
async about(request: Req, h: Res) {
const isRenderHtmx = Reflect.has(request.query, "htmx")
console.log(Reflect.has(request.query, "htmx"))
if (!request.auth.isAuthenticated) {
if (isRenderHtmx) {
// https://github.com/hapijs/hapi/issues/4443
// https://github.com/hapijs/hapi/issues/4212
return h.response().header("HX-Redirect", `/login?next=${encodeURIComponent(request.path)}`)
}
return h.redirect(`/login?next=${encodeURIComponent(request.path)}`).takeover()
}
const { id } = request.auth.credentials
const User = request.getModel("User")
let res = await User.findOne({ where: { id: id } })
if (res == null) {
return gFail(null, "不存在该用户")
request.yar.flash("warning", "不存在此用户")
return h.redirect(`/`).takeover()
}
const userinfo = res.toJSON()
delete userinfo.password

46
source/route/views/login.ts

@ -0,0 +1,46 @@
import { Req, Res, ReturnValue } from "#/global"
import { LoginUserSchema, RegisterUserSchema, UserSchema } from "@/schema"
import { gFail, gSuccess } from "@/util"
import { auth, config, method, route, route_path, validate } from "@noderun/hapi-router"
import * as bcrypt from "bcrypt"
/**
*
*/
export default class {
@route_path("/login")
@auth("try")
@method("GET")
async login_GET(request: Req, h: Res): ReturnValue {
if (request.auth.isAuthenticated) {
request.yar.flash("warning", "您已经登陆")
return h.redirect("/")
} else {
logger.debug("未登录")
}
return h.view("views/login.pug")
}
@validate({
payload: LoginUserSchema,
$errto: "/login",
// failAction: 'log'
failAction: "function",
// failReason: "用户名或密码错误,请重试",
})
@method("POST")
@route_path("/login")
async login_POST(request: Req, h: Res): ReturnValue {
const { username, password, referrer } = request.payload as any
const User = request.getModel("User")
const account = <any>await User.findOne({ where: { username: username } })
if (!account || !(await bcrypt.compare(password, account.password))) {
request.yar.flash("error", "Invalid username or password")
return h.redirect("/login")
}
request.cookieAuth.set({ id: account.id, nickname: account.nickname })
request.yar.flash("success", "用户已登录")
return h.redirect(referrer ? referrer : "/")
}
}

53
source/route/views/register.ts

@ -0,0 +1,53 @@
import { Req, Res, ReturnValue } from "#/global"
import { LoginUserSchema, RegisterUserSchema, UserSchema } from "@/schema"
import { gFail, gSuccess } from "@/util"
import { auth, config, method, route, route_path, validate } from "@noderun/hapi-router"
import * as bcrypt from "bcrypt"
/**
*
*/
export default class {
@route_path("/register")
@auth("try")
@method("GET")
async register_GET(request: Req, h: Res): ReturnValue {
if (request.auth.isAuthenticated) {
request.yar.flash("warning", "您已经登陆")
return h.redirect("/")
} else {
logger.debug("未登录")
}
return h.view("views/register.pug")
}
@validate({
payload: RegisterUserSchema,
$errto: "/register",
failAction: "function",
failReason: "注册账户不符合规范",
})
@method("POST")
@route_path("/register")
async register_POST(request: Req, h: Res): ReturnValue {
console.log(request)
let { username, password } = request.payload as any
const User = request.getModel("User")
logger.trace("当前注册用户:" + username)
try {
const result = await User.findOne({ where: { username: username } })
if (result != null) {
request.yar.flash("error", "已存在该用户")
return h.redirect("/register")
}
let salt = bcrypt.genSaltSync(10)
let pwdLock = bcrypt.hashSync(password, salt)
await User.create({ username, password: pwdLock, nickname: username })
request.yar.flash("success", "用户注册成功")
return h.redirect("/login")
} catch (e) {
loggerSite.error(`注册用户失败`, e.message)
request.yar.flash("error", "注册用户失败")
return h.redirect("/register")
}
}
}

24
source/route/views/user.ts

@ -20,4 +20,28 @@ export default class {
delete userinfo.password
return h.view("views/user.pug", { userinfo })
}
@method("GET")
@auth()
async logout(request: Req, h: Res): ReturnValue {
request.yar.flash("success", "用户已退出")
request.cookieAuth.clear()
return h.redirect("/")
}
@method("POST")
@auth()
async del(request: Req, h: Res): ReturnValue {
const { id } = request.auth.credentials
try {
const User = request.getModel("User")
await User.destroy({ where: { id: id } })
request.yar.flash("success", "用户已删除")
request.cookieAuth.clear()
} catch (error) {
loggerSite.error(`用户删除错误`, error.message)
request.yar.flash("error", "用户删除错误")
}
return h.redirect("/")
}
}

1
template/htmx/path/about.pug

@ -1,3 +1,4 @@
include @/helper/flush.pug
include @/helper/helper.pug
block var

1
template/htmx/path/index.pug

@ -1,3 +1,4 @@
include @/helper/flush.pug
block var
-title="首页" // 网页标题
title 首页

4
template/ui/header.pug

@ -39,9 +39,9 @@ nav.is-fixed-top.navbar(role='navigation', aria-label='main navigation', style="
a.navbar-item
| 用户资料
hr.navbar-divider
a.navbar-item(href="/logout")
a.navbar-item(href="/user/logout")
| 退出
form(action="/del" method="post")
form(action="/user/del" method="post")
+security
a.navbar-item
button(type="submit") 删除

Loading…
Cancel
Save