v0.6.0: 收单入口
- 类型契约/Express 装配/MongoShrimp 全部合并进 src/main/index.ts - 删 src/main/expmon.ts、src/main/types.ts - package.json exports 收成只剩 "."(和 ./package.json) - IShrimpType.ts 头加 @contractVersion 1.0.0(供 shrimp-admin 副本对照) 未上生产,直接断掉 shrimp-server/expmon、shrimp-server/types 两个子入口。
This commit is contained in:
+1
-9
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "shrimp-server",
|
"name": "shrimp-server",
|
||||||
"version": "0.5.0",
|
"version": "0.6.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Shrimp 框架后端 — 声明式字段驱动的 Node.js 管理后台框架(Express + Mongoose + JWT)",
|
"description": "Shrimp 框架后端 — 声明式字段驱动的 Node.js 管理后台框架(Express + Mongoose + JWT)",
|
||||||
"main": "src/main/index.ts",
|
"main": "src/main/index.ts",
|
||||||
@@ -10,14 +10,6 @@
|
|||||||
"types": "./src/main/index.ts",
|
"types": "./src/main/index.ts",
|
||||||
"default": "./src/main/index.ts"
|
"default": "./src/main/index.ts"
|
||||||
},
|
},
|
||||||
"./expmon": {
|
|
||||||
"types": "./src/main/expmon.ts",
|
|
||||||
"default": "./src/main/expmon.ts"
|
|
||||||
},
|
|
||||||
"./types": {
|
|
||||||
"types": "./src/main/types.ts",
|
|
||||||
"default": "./src/main/types.ts"
|
|
||||||
},
|
|
||||||
"./package.json": "./package.json"
|
"./package.json": "./package.json"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
|||||||
+8
-2
@@ -1,6 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Shrimp 前后端共用类型定义
|
* Shrimp 类型契约 — 前后端 wire protocol 定义
|
||||||
* 定义错误码、协议、通用数据格式
|
*
|
||||||
|
* @contractVersion 1.0.0
|
||||||
|
*
|
||||||
|
* 改动此文件需要:
|
||||||
|
* 1. 升 @contractVersion(语义化版本)
|
||||||
|
* 2. 同步到 shrimp-admin/src/IShrimpType.ts,更新其 @syncedFrom
|
||||||
|
* 3. 通知消费侧对齐
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** 业务错误码 */
|
/** 业务错误码 */
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
/**
|
|
||||||
* Shrimp expmon 入口 — Express + Mongoose 整合方案
|
|
||||||
*
|
|
||||||
* 在 core 之上把 forMongo(MongoShrimp + 数据源)和 forExpress(buildShrimpRouter
|
|
||||||
* + JWT)拼起来,导出开箱即用的 ShrimpServer 装配体。
|
|
||||||
*
|
|
||||||
* 这一入口需要消费方安装 peer:express / mongoose / jsonwebtoken / bcrypt。
|
|
||||||
* 不需要时改从 'shrimp-server' 导入,不会触发任何 peer。
|
|
||||||
*
|
|
||||||
* 想换掉其中一块的高级用法:
|
|
||||||
* - 自己造 ITokenAuth(看 createJwtTokenAuth 实现)
|
|
||||||
* - 自己造 dataSource(实现 ShrimpCrud 接口)
|
|
||||||
* - 直接 buildShrimpRouter(deps) 拼自己的 Express app,绕开本类
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Router } from "express"
|
|
||||||
import { MongoShrimp, UserSchema, RoleSchema, OperationLogSchema } from "../forMongo/MongoShrimp"
|
|
||||||
import { buildShrimpRouter } from "../forExpress/buildShrimpRouter"
|
|
||||||
import { createJwtTokenAuth } from "../forExpress/jwtAuth"
|
|
||||||
import type { ITokenAuth, IUserAccessor } from "../forExpress/types"
|
|
||||||
import type { RootShrimpPower } from "../Shrimp/ShrimpPower"
|
|
||||||
import type { IUser, IRole, WithId } from "../IShrimpType"
|
|
||||||
|
|
||||||
// 再导出所有 core 的符号,'shrimp-server/expmon' 单一入口就够用
|
|
||||||
export * from "./index"
|
|
||||||
|
|
||||||
// ===== forMongo / forExpress 公开符号 =====
|
|
||||||
export { MongoShrimp, UserSchema, RoleSchema, OperationLogSchema } from "../forMongo/MongoShrimp"
|
|
||||||
export { MongoShrimpCrud } from "../forMongo/MongoShrimpCrud"
|
|
||||||
export { buildShrimpRouter } from "../forExpress/buildShrimpRouter"
|
|
||||||
export { createJwtTokenAuth } from "../forExpress/jwtAuth"
|
|
||||||
export type { IJwtTokenAuthOptions } from "../forExpress/jwtAuth"
|
|
||||||
export type { ITokenAuth, IUserAccessor, IShrimpRouterDeps } from "../forExpress/types"
|
|
||||||
|
|
||||||
// ============== ShrimpServer ==============
|
|
||||||
|
|
||||||
export class ShrimpServer extends MongoShrimp implements IUserAccessor {
|
|
||||||
router: Router
|
|
||||||
jwtSecret: string
|
|
||||||
config: Record<string, any>
|
|
||||||
globalOptions: Record<string, any> = {}
|
|
||||||
forcedOptionAccess = new Map<string, RootShrimpPower>()
|
|
||||||
|
|
||||||
constructor(jwtSecret: string, config: Record<string, any> = {}, mongodbUri: string = "mongodb://localhost:27017/shrimp") {
|
|
||||||
super(mongodbUri)
|
|
||||||
this.jwtSecret = jwtSecret
|
|
||||||
this.config = config
|
|
||||||
|
|
||||||
this.router = buildShrimpRouter({
|
|
||||||
shrimp: this,
|
|
||||||
userModule: this.userModule,
|
|
||||||
roleModule: this.roleModule,
|
|
||||||
operationLogModule: this.operationLogModule,
|
|
||||||
tokenAuth: this.createTokenAuth(),
|
|
||||||
config: this.config,
|
|
||||||
globalOptions: this.globalOptions,
|
|
||||||
forcedOptionAccess: this.forcedOptionAccess,
|
|
||||||
userAccessor: this,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
registerOptions(key: string, options: any, access?: RootShrimpPower) {
|
|
||||||
this.globalOptions[key] = options
|
|
||||||
if (access) {
|
|
||||||
this.forcedOptionAccess.set(key, access)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 创建 Token 鉴权,默认 JWT。子类可覆盖换成 session 之类。 */
|
|
||||||
protected createTokenAuth(): ITokenAuth {
|
|
||||||
return createJwtTokenAuth(this.jwtSecret)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============== 可覆盖的用户/角色字段访问钩子(实现 IUserAccessor) ==============
|
|
||||||
|
|
||||||
getJwtPayload(user: WithId<IUser>): Record<string, any> {
|
|
||||||
return { _id: user._id, roleId: user.roleId }
|
|
||||||
}
|
|
||||||
|
|
||||||
isUserActive(user: WithId<IUser>): boolean {
|
|
||||||
return user.active === true
|
|
||||||
}
|
|
||||||
|
|
||||||
getUserRoleIds(user: WithId<IUser>): string[] {
|
|
||||||
return Array.isArray(user.roleId) ? user.roleId.map(String) : user.roleId ? [String(user.roleId)] : []
|
|
||||||
}
|
|
||||||
|
|
||||||
isRoleSuperAdmin(role: WithId<IRole> | null): boolean {
|
|
||||||
return !!role?.isSuperAdmin
|
|
||||||
}
|
|
||||||
|
|
||||||
getRolePowers(role: WithId<IRole> | null): string[] {
|
|
||||||
return role?.powers || []
|
|
||||||
}
|
|
||||||
|
|
||||||
getUserDisplayName(user: WithId<IUser>): string {
|
|
||||||
return user.nickname || ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+95
-12
@@ -1,19 +1,28 @@
|
|||||||
/**
|
/**
|
||||||
* Shrimp 核心入口 — 0 重依赖
|
* Shrimp 单一入口 — 完整后端栈
|
||||||
*
|
*
|
||||||
* 只暴露 Shrimp 框架本体 + 内存数据源 + 类型定义,不引入
|
* 包含框架核心 + 类型契约 + Express + Mongoose + JWT 装配体。
|
||||||
* express / mongoose / jsonwebtoken。bcrypt 是 lazy import,
|
|
||||||
* 不走 Password 字段就不会触发。
|
|
||||||
*
|
*
|
||||||
* 适用场景:
|
* 安装 peer:express / mongoose / jsonwebtoken / bcrypt。
|
||||||
* - 只想用 Shrimp 的 RPC dispatch + 模块/字段声明 + 内存 CRUD
|
|
||||||
* - 自己接 HTTP / 自己写存储层
|
|
||||||
* - 跑测试 / 跑无 DB 的 demo
|
|
||||||
*
|
*
|
||||||
* 需要完整后台(Express + Mongoose + JWT)请从 'shrimp-server/expmon' 导入。
|
* 前端只想要类型契约,**不要**从这里 import — 见 shrimp-admin 的
|
||||||
|
* IShrimpType.ts(契约副本),避免把 mongoose/express 牵进前端 bundle。
|
||||||
|
*
|
||||||
|
* 想换掉其中一块的高级用法:
|
||||||
|
* - 自己造 ITokenAuth(看 createJwtTokenAuth 实现)
|
||||||
|
* - 自己造 dataSource(实现 ShrimpCrud 接口)
|
||||||
|
* - 直接 buildShrimpRouter(deps) 拼自己的 Express app,绕开 ShrimpServer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ===== 类型 / 接口 / 枚举 =====
|
import { Router } from "express"
|
||||||
|
import { MongoShrimp } from "../forMongo/MongoShrimp"
|
||||||
|
import { buildShrimpRouter } from "../forExpress/buildShrimpRouter"
|
||||||
|
import { createJwtTokenAuth } from "../forExpress/jwtAuth"
|
||||||
|
import type { ITokenAuth, IUserAccessor } from "../forExpress/types"
|
||||||
|
import type { RootShrimpPower } from "../Shrimp/ShrimpPower"
|
||||||
|
import type { IUser, IRole, WithId } from "../IShrimpType"
|
||||||
|
|
||||||
|
// ===== 类型契约 / 枚举 =====
|
||||||
export {
|
export {
|
||||||
ShrimpCode,
|
ShrimpCode,
|
||||||
ShrimpError,
|
ShrimpError,
|
||||||
@@ -64,9 +73,83 @@ export type { ShrimpCrud } from "../Shrimp/ShrimpCrud"
|
|||||||
export { UserModule, RoleModule } from "../Shrimp/UserRoleModule"
|
export { UserModule, RoleModule } from "../Shrimp/UserRoleModule"
|
||||||
export { OperationLogModule } from "../Shrimp/OperationLogModule"
|
export { OperationLogModule } from "../Shrimp/OperationLogModule"
|
||||||
|
|
||||||
// ===== 密码哈希(可注入,默认 bcrypt lazy import) =====
|
// ===== 密码哈希 =====
|
||||||
export { bcryptHasher, plainHasher } from "../PasswordHasher"
|
export { bcryptHasher, plainHasher } from "../PasswordHasher"
|
||||||
export type { IPasswordHasher } from "../PasswordHasher"
|
export type { IPasswordHasher } from "../PasswordHasher"
|
||||||
|
|
||||||
// ===== 数据源(纯内存,无外部依赖) =====
|
// ===== 数据源 =====
|
||||||
export { MemoryShrimpCrud } from "../MemoryShrimpCrud"
|
export { MemoryShrimpCrud } from "../MemoryShrimpCrud"
|
||||||
|
export { MongoShrimp, UserSchema, RoleSchema, OperationLogSchema } from "../forMongo/MongoShrimp"
|
||||||
|
export { MongoShrimpCrud } from "../forMongo/MongoShrimpCrud"
|
||||||
|
|
||||||
|
// ===== Express 装配 =====
|
||||||
|
export { buildShrimpRouter } from "../forExpress/buildShrimpRouter"
|
||||||
|
export { createJwtTokenAuth } from "../forExpress/jwtAuth"
|
||||||
|
export type { IJwtTokenAuthOptions } from "../forExpress/jwtAuth"
|
||||||
|
export type { ITokenAuth, IUserAccessor, IShrimpRouterDeps } from "../forExpress/types"
|
||||||
|
|
||||||
|
// ============== ShrimpServer ==============
|
||||||
|
|
||||||
|
export class ShrimpServer extends MongoShrimp implements IUserAccessor {
|
||||||
|
router: Router
|
||||||
|
jwtSecret: string
|
||||||
|
config: Record<string, any>
|
||||||
|
globalOptions: Record<string, any> = {}
|
||||||
|
forcedOptionAccess = new Map<string, RootShrimpPower>()
|
||||||
|
|
||||||
|
constructor(jwtSecret: string, config: Record<string, any> = {}, mongodbUri: string = "mongodb://localhost:27017/shrimp") {
|
||||||
|
super(mongodbUri)
|
||||||
|
this.jwtSecret = jwtSecret
|
||||||
|
this.config = config
|
||||||
|
|
||||||
|
this.router = buildShrimpRouter({
|
||||||
|
shrimp: this,
|
||||||
|
userModule: this.userModule,
|
||||||
|
roleModule: this.roleModule,
|
||||||
|
operationLogModule: this.operationLogModule,
|
||||||
|
tokenAuth: this.createTokenAuth(),
|
||||||
|
config: this.config,
|
||||||
|
globalOptions: this.globalOptions,
|
||||||
|
forcedOptionAccess: this.forcedOptionAccess,
|
||||||
|
userAccessor: this,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOptions(key: string, options: any, access?: RootShrimpPower) {
|
||||||
|
this.globalOptions[key] = options
|
||||||
|
if (access) {
|
||||||
|
this.forcedOptionAccess.set(key, access)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 创建 Token 鉴权,默认 JWT。子类可覆盖换成 session 之类。 */
|
||||||
|
protected createTokenAuth(): ITokenAuth {
|
||||||
|
return createJwtTokenAuth(this.jwtSecret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============== 可覆盖的用户/角色字段访问钩子(实现 IUserAccessor) ==============
|
||||||
|
|
||||||
|
getJwtPayload(user: WithId<IUser>): Record<string, any> {
|
||||||
|
return { _id: user._id, roleId: user.roleId }
|
||||||
|
}
|
||||||
|
|
||||||
|
isUserActive(user: WithId<IUser>): boolean {
|
||||||
|
return user.active === true
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserRoleIds(user: WithId<IUser>): string[] {
|
||||||
|
return Array.isArray(user.roleId) ? user.roleId.map(String) : user.roleId ? [String(user.roleId)] : []
|
||||||
|
}
|
||||||
|
|
||||||
|
isRoleSuperAdmin(role: WithId<IRole> | null): boolean {
|
||||||
|
return !!role?.isSuperAdmin
|
||||||
|
}
|
||||||
|
|
||||||
|
getRolePowers(role: WithId<IRole> | null): string[] {
|
||||||
|
return role?.powers || []
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserDisplayName(user: WithId<IUser>): string {
|
||||||
|
return user.nickname || ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
/**
|
|
||||||
* Shrimp 纯类型入口
|
|
||||||
*
|
|
||||||
* 只导出 IShrimpType.ts 的全部协议(类型 + ShrimpCode enum + ShrimpError class),
|
|
||||||
* 前端 shrimp-admin / 任何只需要协议定义的消费方从这里 import,
|
|
||||||
* 不会触发任何运行时依赖。
|
|
||||||
*/
|
|
||||||
|
|
||||||
export * from "../IShrimpType"
|
|
||||||
Reference in New Issue
Block a user