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:
2026-05-23 22:27:36 +08:00
parent 652b31052e
commit c99ea0e18c
5 changed files with 104 additions and 131 deletions
+1 -9
View File
@@ -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
View File
@@ -1,6 +1,12 @@
/** /**
* Shrimp 前后端共用类型定义 * Shrimp 类型契约 — 前后端 wire protocol 定义
* 定义错误码、协议、通用数据格式 *
* @contractVersion 1.0.0
*
* 改动此文件需要:
* 1. 升 @contractVersion(语义化版本)
* 2. 同步到 shrimp-admin/src/IShrimpType.ts,更新其 @syncedFrom
* 3. 通知消费侧对齐
*/ */
/** 业务错误码 */ /** 业务错误码 */
-99
View File
@@ -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
View File
@@ -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 || ""
}
}
-9
View File
@@ -1,9 +0,0 @@
/**
* Shrimp 纯类型入口
*
* 只导出 IShrimpType.ts 的全部协议(类型 + ShrimpCode enum + ShrimpError class),
* 前端 shrimp-admin / 任何只需要协议定义的消费方从这里 import,
* 不会触发任何运行时依赖。
*/
export * from "../IShrimpType"