@longzai-intelligence-auth/elysia 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/index.d.ts +648 -25
  2. package/dist/index.js +1 -15
  3. package/package.json +12 -30
  4. package/dist/core/auth-strategy.d.ts +0 -14
  5. package/dist/core/auth-strategy.js +0 -98
  6. package/dist/core/error-mapper.d.ts +0 -2
  7. package/dist/core/error-mapper.js +0 -27
  8. package/dist/plugin.d.ts +0 -6
  9. package/dist/plugin.js +0 -39
  10. package/dist/plugins/audit.plugin.d.ts +0 -38
  11. package/dist/plugins/audit.plugin.js +0 -13
  12. package/dist/plugins/error-handler.plugin.d.ts +0 -46
  13. package/dist/plugins/error-handler.plugin.js +0 -45
  14. package/dist/plugins/jwt-verify.plugin.d.ts +0 -9
  15. package/dist/plugins/jwt-verify.plugin.js +0 -31
  16. package/dist/plugins/logger.plugin.d.ts +0 -33
  17. package/dist/plugins/logger.plugin.js +0 -16
  18. package/dist/plugins/rate-limit.plugin.d.ts +0 -40
  19. package/dist/plugins/rate-limit.plugin.js +0 -39
  20. package/dist/plugins/rbac.plugin.d.ts +0 -36
  21. package/dist/plugins/rbac.plugin.js +0 -42
  22. package/dist/plugins/tenant.plugin.d.ts +0 -38
  23. package/dist/plugins/tenant.plugin.js +0 -19
  24. package/dist/presets/basic-preset.d.ts +0 -11
  25. package/dist/presets/basic-preset.js +0 -11
  26. package/dist/presets/standard-preset.d.ts +0 -13
  27. package/dist/presets/standard-preset.js +0 -26
  28. package/dist/routes/auth.routes.d.ts +0 -17
  29. package/dist/routes/auth.routes.js +0 -145
  30. package/dist/types/auth-plugin-config.d.ts +0 -40
  31. package/dist/types/auth-plugin-config.js +0 -1
  32. package/dist/utils/extract-client-ip.d.ts +0 -1
  33. package/dist/utils/extract-client-ip.js +0 -5
  34. package/dist/utils/extract-user-agent.d.ts +0 -1
  35. package/dist/utils/extract-user-agent.js +0 -3
package/dist/index.js CHANGED
@@ -1,15 +1 @@
1
- // @bun
2
- export {
3
- mapDomainErrorToStatus,
4
- extractUserAgent,
5
- extractClientIp,
6
- createTenantPlugin,
7
- createStandardPreset,
8
- createRbacPlugin,
9
- createRateLimitPlugin,
10
- createLoggerPlugin,
11
- createJwtVerifyPlugin,
12
- createErrorHandlerPlugin,
13
- createBasicPreset,
14
- createAuditPlugin
15
- };
1
+ import{AuthenticationError as e,DomainError as t,DuplicateEntityError as n,isBusinessRuleError as r,isConcurrencyError as i,isEntityNotFoundError as a,isPermissionDeniedError as o,isValidationError as s}from"@longzai-intelligence/error";import{AccountDisabledError as c,InvalidCredentialsError as l,MfaRequiredError as u,RateLimitExceededError as d,TokenExpiredError as f,TokenInvalidError as p,TokenMissingError as m,UserAlreadyExistsError as h,accessTokenPayloadSchema as g,createDefaultJwtConfig as _}from"@longzai-intelligence-auth/core";import{Elysia as v}from"elysia";import{JwtTokenVerifier as y}from"@longzai-intelligence-auth/jwt";function b(t){return s(t)?400:t instanceof f||t instanceof p||t instanceof m||t instanceof u||t instanceof l||t instanceof c||t instanceof e?401:o(t)?403:a(t)?404:t instanceof n||t instanceof h?409:t instanceof d?429:i(t)?409:r(t)||t.code===`PASSWORD_POLICY_VIOLATION`?422:500}function x(e,t){return{userId:e.sub,tenantId:e.tenantId??t,roles:e.roles??[],permissions:e.permissions??[],authMethod:`jwt`}}function S(e){return{userId:``,tenantId:e,roles:[],permissions:[],authMethod:`jwt`}}function C(e,t){return t.some(t=>t.endsWith(`/*`)?e.startsWith(t.slice(0,-2)):e===t)}function w(e){return{algorithm:`HS256`,secret:e.secret,accessExpiresIn:e.accessExpiresIn,refreshExpiresIn:e.refreshExpiresIn}}function T(e,t){return e||new y(w(t??_()))}function E(e){let{verifier:t,jwt:n,defaultTenantId:r=`default`,publicPaths:i=[],extendSchema:a}=e,o=T(t,n);return new v({name:`@longzai-intelligence-auth/jwt-verify`}).derive(async({request:e})=>{if(C(new URL(e.url).pathname,i)){let e=a?a.parse({}):{};return{auth:{...S(r),...e}}}let t=e.headers.get(`Authorization`),n=t?.startsWith(`Bearer `)?t.slice(7):null;if(!n)throw new m;let s=await o.verifyAccessToken(n);if(!s.success||!s.payload)throw new p(s.error);g.parse(s.payload);let c=x(s.payload,r),l=a?a.parse(s.payload):{};return{auth:{...c,...l}}}).as(`scoped`)}function D(e){return{algorithm:`HS256`,secret:e.secret,accessExpiresIn:e.accessExpiresIn,refreshExpiresIn:e.refreshExpiresIn}}function O(e,t){return e||new y(D(t??_()))}function k(e){let{verifier:t,jwt:n,defaultTenantId:r=`default`,extendSchema:i}=e,a=O(t,n);return new v({name:`@longzai-intelligence-auth/optional-jwt`}).derive(async({request:e})=>{let t=e.headers.get(`Authorization`),n=t?.startsWith(`Bearer `)?t.slice(7):null;if(!n)return{auth:null};try{let e=await a.verifyAccessToken(n);if(!e.success||!e.payload)return{auth:null};g.parse(e.payload);let t=e.payload,o={userId:t.sub,tenantId:t.tenantId??r,roles:t.roles??[],permissions:t.permissions??[],authMethod:`jwt`},s=i?i.parse(t):{};return{auth:{...o,...s}}}catch{return{auth:null}}}).as(`scoped`)}function A(e,t,n){return e.some(e=>e.resource===`*`&&e.action===`*`||e.resource===t&&e.action===`*`||e.resource===`*`&&e.action===n||e.resource===t&&e.action===n)}function j(e,t,n){let r=`${t}:${n}`;return e.includes(r)||e.includes(`${t}:*`)||e.includes(`*:${n}`)||e.includes(`*:*`)}function M(e={}){let{userRole:t}=e;return new v({name:`@longzai-intelligence-auth/rbac`}).derive({as:`scoped`},async e=>{let n=e.auth;if(!n)throw new m;let r=n.userId,i=n.tenantId;return{requirePermission:async(e,a)=>{if(t){if(A(await t.findPermissionsByUserId(r,i),e,a))return;let{PermissionDeniedError:n}=await import(`@longzai-intelligence/error`);throw new n(e,a)}if(j(n.permissions??[],e,a))return;let{PermissionDeniedError:o}=await import(`@longzai-intelligence/error`);throw new o(e,a)}}}).as(`global`)}function N(e){let{header:t=`x-api-key`,validator:n}=e;return new v({name:`@longzai-intelligence-auth/api-key`}).derive(async({request:e})=>{let r=e.headers.get(t)??e.headers.get(t.toLowerCase());if(!r)throw new m(`缺少 API Key`);let i=await n(r);if(!i)throw new p(`无效的 API Key`);return{auth:{userId:i.principalId,tenantId:i.tenantId??`default`,roles:i.roles,permissions:i.permissions,authMethod:`api-key`}}}).as(`scoped`)}function P(e){return async t=>{let n=e[t];return n?{principalId:n.principalId,tenantId:n.tenantId,roles:n.roles,permissions:n.permissions}:null}}function F(e){return{authMethod:`jwt`,userId:e.userId,tenantId:e.tenantId,roles:e.roles,permissions:e.permissions}}function I(e,t){return{authMethod:`api-key`,userId:e.principalId,tenantId:e.tenantId??t,roles:e.roles,permissions:e.permissions}}function L(e){return{algorithm:`HS256`,secret:e.secret,accessExpiresIn:e.accessExpiresIn,refreshExpiresIn:e.refreshExpiresIn}}function R(e,t){return e||new y(L(t??_()))}function z(e,t){return t.some(t=>t.endsWith(`/*`)?e.startsWith(t.slice(0,-2)):e===t)}function B(e){let{verifier:t,jwt:n,defaultTenantId:r=`default`,apiKeyValidator:i,apiKeyHeader:a=`x-api-key`,publicPaths:o=[]}=e,s=R(t,n);return new v({name:`@longzai-intelligence-auth/composite-auth`}).derive(async({request:e})=>{if(z(new URL(e.url).pathname,o))return{auth:null};let t=e.headers.get(`Authorization`),n=t?.startsWith(`Bearer `)?t.slice(7):null;if(n)try{let e=await s.verifyAccessToken(n);if(e.success&&e.payload)return g.parse(e.payload),{auth:F({userId:e.payload.sub,tenantId:e.payload.tenantId??r,roles:e.payload.roles??[],permissions:e.payload.permissions??[]})}}catch{}if(i){let t=e.headers.get(a)??e.headers.get(a.toLowerCase());if(t){let e=await i(t);if(e)return{auth:I(e,r)}}}return{auth:null}}).as(`scoped`)}function V(e){let{verifier:t,jwt:n,defaultTenantId:r=`default`,apiKeyValidator:i,apiKeyHeader:a=`x-api-key`,publicPaths:o=[]}=e,s=R(t,n);return new v({name:`@longzai-intelligence-auth/required-composite-auth`}).derive(async({request:e})=>{if(z(new URL(e.url).pathname,o))return{auth:{authMethod:`jwt`,userId:``,tenantId:r,roles:[],permissions:[]}};let t=e.headers.get(`Authorization`),n=t?.startsWith(`Bearer `)?t.slice(7):null;if(n)try{let e=await s.verifyAccessToken(n);if(e.success&&e.payload)return g.parse(e.payload),{auth:F({userId:e.payload.sub,tenantId:e.payload.tenantId??r,roles:e.payload.roles??[],permissions:e.payload.permissions??[]})}}catch{}if(i){let t=e.headers.get(a)??e.headers.get(a.toLowerCase());if(t){let e=await i(t);if(e)return{auth:I(e,r)}}}throw Error(`认证失败:需要提供有效的 JWT Token 或 API Key`)}).as(`scoped`)}function H(e={}){let{defaultTenantId:t=`default`,validateFn:n}=e;return new v({name:`@longzai-intelligence-auth/tenant`}).derive(({request:e})=>({tenantId:e.headers.get(`x-tenant-id`)??t})).as(`scoped`).onBeforeHandle(async({tenantId:e})=>{if(n&&e!==t&&!(await n(e)).valid){let{PermissionDeniedError:e}=await import(`@longzai-intelligence/error`);throw new e(`tenant`,`access`)}}).as(`global`)}function U(e){return e.headers.get(`x-forwarded-for`)?.split(`,`)[0]?.trim()??e.headers.get(`x-real-ip`)??`unknown`}function W(e){let{limiter:t,logger:n}=e,r=e.keyGenerator??U;return new v({name:`@longzai-intelligence-auth/rate-limit`}).derive(({request:e})=>({clientIp:r(e)})).derive(async({clientIp:e,request:r})=>{let i=new URL(r.url).pathname,a=`${e}:${i}`,o=await t.checkLimit(a);if(!o.allowed)throw n?.warn(`限流触发`,{clientIp:e,path:i}),new d;return{rateLimitRemaining:o.remaining}}).as(`global`)}function G(e={}){let{logger:n}=e;return new v({name:`@longzai-intelligence-auth/error-handler`}).onError(({code:e,error:r,set:i})=>{if(r instanceof t)return i.status=b(r),{code:r.code,message:r.message,...r.context&&Object.keys(r.context).length>0?{details:r.context}:{}};switch(e){case`VALIDATION`:return i.status=400,{code:`VALIDATION_ERROR`,message:`请求参数验证失败`,details:r.all.map(e=>({path:e.path,message:e.summary}))};case`NOT_FOUND`:return i.status=404,{code:`NOT_FOUND`,message:`未找到请求的资源`};case`PARSE`:return i.status=400,{code:`PARSE_ERROR`,message:`请求数据解析失败`};default:return n?.error(`未预期的错误`,{error:r instanceof Error?r.message:String(r),stack:r instanceof Error?r.stack:void 0}),i.status=500,{code:`INTERNAL_ERROR`,message:`服务器内部错误`}}}).as(`global`)}function K(e){let{logger:t}=e;return new v({name:`@longzai-intelligence-auth/logger`}).onRequest(({request:e})=>{t.info(`${e.method} ${e.url}`)}).onAfterResponse(({request:e,set:n})=>{t.info(`${e.method} ${e.url} ${n.status}`)}).onError(({request:e,error:n})=>{t.error(`${e.method} ${e.url} 请求错误`,{error:n instanceof Error?n.message:String(n)})}).as(`global`)}function q(e){return new v({name:`@longzai-intelligence-auth/basic-preset`}).use(E({verifier:e.tokenVerifier,defaultTenantId:e.defaultTenantId,publicPaths:e.publicPaths,extendSchema:e.extendSchema})).use(G({logger:e.logger}))}function J(e){let t=e.apiKeyValidator?V({verifier:e.tokenVerifier,defaultTenantId:e.defaultTenantId,publicPaths:e.publicPaths,apiKeyValidator:e.apiKeyValidator}):E({verifier:e.tokenVerifier,defaultTenantId:e.defaultTenantId,publicPaths:e.publicPaths,extendSchema:e.extendSchema}),n=new v({name:`@longzai-intelligence-auth/standard-preset`}).use(t).use(M({userRole:e.userRole})).use(H({defaultTenantId:e.defaultTenantId,validateFn:e.validateFn}));return e.rateLimiter&&n.use(W({limiter:e.rateLimiter,logger:e.logger})),n.use(G({logger:e.logger}))}function Y(e){return e.headers.get(`x-forwarded-for`)?.split(`,`)[0]?.trim()??e.headers.get(`x-real-ip`)??void 0}function X(e){return e.headers.get(`user-agent`)??void 0}export{N as createApiKeyPlugin,q as createBasicPreset,B as createCompositeAuthPlugin,G as createErrorHandlerPlugin,P as createInMemoryApiKeyValidator,E as createJwtVerifyPlugin,K as createLoggerPlugin,k as createOptionalJwtPlugin,W as createRateLimitPlugin,M as createRbacPlugin,V as createRequiredCompositeAuthPlugin,J as createStandardPreset,H as createTenantPlugin,Y as extractClientIp,X as extractUserAgent,b as mapDomainErrorToStatus};
package/package.json CHANGED
@@ -1,22 +1,15 @@
1
1
  {
2
2
  "name": "@longzai-intelligence-auth/elysia",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
- "main": "./dist/index.cjs",
8
- "module": "./dist/index.js",
7
+ "main": "./dist/index.js",
9
8
  "types": "./dist/index.d.ts",
10
9
  "exports": {
11
10
  ".": {
12
- "import": {
13
- "types": "./dist/index.d.ts",
14
- "default": "./dist/index.js"
15
- },
16
- "require": {
17
- "types": "./dist/index.d.cts",
18
- "default": "./dist/index.cjs"
19
- }
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
20
13
  }
21
14
  },
22
15
  "files": [
@@ -26,10 +19,9 @@
26
19
  "access": "public"
27
20
  },
28
21
  "scripts": {
29
- "build": "bun build src/index.ts --outdir dist --target bun",
30
- "build:declaration": "tsgo --declaration --emitDeclarationOnly --outDir dist -p tsconfig/app.json",
22
+ "build": "tsgo --build tsconfig/build.json && resolve-aliases -p tsconfig/build.json",
31
23
  "build:prod": "NODE_ENV=production tsdown",
32
- "prepublishOnly": "echo skip",
24
+ "prepublishOnly": "bun run build:prod",
33
25
  "typecheck": "bun run typecheck:app && bun run typecheck:node && bun run typecheck:test",
34
26
  "typecheck:app": "tsgo --noEmit -p tsconfig/app.json",
35
27
  "typecheck:node": "tsgo --noEmit -p tsconfig/node.json",
@@ -44,26 +36,16 @@
44
36
  "clean": "rm -rf dist out .cache"
45
37
  },
46
38
  "dependencies": {
47
- "@longzai-intelligence-auth/core": "0.0.1",
48
- "@longzai-intelligence-auth/jwt": "0.0.1",
49
- "@longzai-intelligence-auth/rate-limit": "0.0.1",
50
- "@longzai-intelligence-auth/rbac": "0.0.1",
51
- "@longzai-intelligence-auth/session": "0.0.1",
52
- "@longzai-intelligence-auth/hashing": "0.0.1",
39
+ "@longzai-intelligence-auth/core": "0.0.5",
40
+ "@longzai-intelligence-auth/jwt": "0.0.5",
53
41
  "@longzai-intelligence/error": "^0.0.5",
54
- "@elysiajs/bearer": "^1.3"
42
+ "@elysiajs/bearer": "^1.3",
43
+ "zod": "^3.24"
55
44
  },
56
45
  "peerDependencies": {
57
- "elysia": "^1.3",
58
- "@longzai-intelligence-audit/elysia": "^0.1.0"
59
- },
60
- "peerDependenciesMeta": {
61
- "@longzai-intelligence-audit/elysia": {
62
- "optional": true
63
- }
46
+ "elysia": "^1.3"
64
47
  },
65
48
  "devDependencies": {
66
- "elysia": "^1.3",
67
- "tsdown": "^0.22.1"
49
+ "elysia": "^1.3"
68
50
  }
69
51
  }
@@ -1,14 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import type { JwtSignerConfig } from "@longzai-intelligence-auth/jwt";
3
- import type { JwtStrategyConfig, StandaloneStrategyConfig, EnvBasicStrategyConfig, StrategyContext, AuthPluginConfig } from "../types/auth-plugin-config";
4
- type AnyElysia = Elysia<any, any, any, any, any, any, any>;
5
- export type AuthStrategy = {
6
- context: StrategyContext;
7
- createJwtVerifyPlugin(): AnyElysia;
8
- supportsAuthRoutes: boolean;
9
- };
10
- export declare function createAuthStrategy(config: AuthPluginConfig): Promise<AuthStrategy>;
11
- export declare function extractJwtConfig(config: JwtStrategyConfig | StandaloneStrategyConfig | EnvBasicStrategyConfig): JwtSignerConfig;
12
- export declare function extractDefaultTenantId(config: JwtStrategyConfig | StandaloneStrategyConfig | EnvBasicStrategyConfig): string;
13
- export declare function extractRegisterRoutes(config: AuthPluginConfig): boolean;
14
- export {};
@@ -1,98 +0,0 @@
1
- import { createJwtVerifyPlugin } from "../plugins/jwt-verify.plugin";
2
- function createJwtStrategy(config) {
3
- const defaultTenantId = config.defaultTenantId ?? "default";
4
- return {
5
- context: {
6
- strategy: "jwt",
7
- defaultTenantId,
8
- registerRoutes: config.registerRoutes ?? false,
9
- },
10
- createJwtVerifyPlugin: () => createJwtVerifyPlugin({ jwt: config.jwt, defaultTenantId }),
11
- supportsAuthRoutes: true,
12
- };
13
- }
14
- function createStandaloneStrategy(config) {
15
- console.warn("[@longzai-intelligence-auth/elysia] standalone 策略仅用于开发和测试环境,生产环境请使用 jwt 策略");
16
- const defaultTenantId = config.defaultTenantId ?? "default";
17
- return {
18
- context: {
19
- strategy: "standalone",
20
- defaultTenantId,
21
- registerRoutes: config.registerRoutes ?? true,
22
- adapter: config.adapter,
23
- passwordHasher: config.passwordHasher,
24
- },
25
- createJwtVerifyPlugin: () => createJwtVerifyPlugin({ jwt: config.jwt, defaultTenantId }),
26
- supportsAuthRoutes: true,
27
- };
28
- }
29
- async function createEnvBasicStrategy(config) {
30
- const adminUsername = config.adminUsername ?? process.env.AUTH_ADMIN_USERNAME ?? "admin";
31
- const adminPassword = config.adminPassword ?? process.env.AUTH_ADMIN_PASSWORD;
32
- if (!adminPassword) {
33
- throw new Error("[@longzai-intelligence-auth/elysia] env-basic 策略需要设置 AUTH_ADMIN_PASSWORD 环境变量或 adminPassword 配置项");
34
- }
35
- console.warn("[@longzai-intelligence-auth/elysia] env-basic 策略仅用于开发和测试环境,生产环境请使用 jwt 或 standalone 策略");
36
- let createInMemoryAuthBackend;
37
- let createEnvBasicPasswordHasher;
38
- try {
39
- const adapter = await import("@longzai-intelligence-auth/identity-adapter");
40
- createInMemoryAuthBackend = adapter.createInMemoryAuthBackend;
41
- createEnvBasicPasswordHasher = adapter.createEnvBasicPasswordHasher;
42
- }
43
- catch {
44
- throw new Error("[@longzai-intelligence-auth/elysia] env-basic 策略需要安装 @longzai-intelligence-auth/identity-adapter 包");
45
- }
46
- const defaultTenantId = config.defaultTenantId ?? "default";
47
- const backend = createInMemoryAuthBackend({
48
- adminUsername,
49
- adminPassword,
50
- jwtConfig: config.jwt,
51
- });
52
- const passwordHasher = createEnvBasicPasswordHasher();
53
- return {
54
- context: {
55
- strategy: "env-basic",
56
- defaultTenantId,
57
- registerRoutes: config.registerRoutes ?? true,
58
- adapter: backend,
59
- passwordHasher,
60
- },
61
- createJwtVerifyPlugin: () => createJwtVerifyPlugin({ jwt: config.jwt, defaultTenantId }),
62
- supportsAuthRoutes: true,
63
- };
64
- }
65
- export async function createAuthStrategy(config) {
66
- switch (config.strategy) {
67
- case "jwt":
68
- return createJwtStrategy(config);
69
- case "standalone":
70
- return createStandaloneStrategy(config);
71
- case "env-basic":
72
- return createEnvBasicStrategy(config);
73
- default: {
74
- const _exhaustive = config;
75
- throw new Error(`未知的认证策略: ${JSON.stringify(_exhaustive)}`);
76
- }
77
- }
78
- }
79
- export function extractJwtConfig(config) {
80
- return config.jwt;
81
- }
82
- export function extractDefaultTenantId(config) {
83
- return config.defaultTenantId ?? "default";
84
- }
85
- export function extractRegisterRoutes(config) {
86
- switch (config.strategy) {
87
- case "jwt":
88
- return config.registerRoutes ?? false;
89
- case "standalone":
90
- return config.registerRoutes ?? true;
91
- case "env-basic":
92
- return config.registerRoutes ?? true;
93
- default: {
94
- const _exhaustive = config;
95
- return false;
96
- }
97
- }
98
- }
@@ -1,2 +0,0 @@
1
- import type { DomainError } from "@longzai-intelligence/error";
2
- export declare function mapDomainErrorToStatus(error: DomainError): number;
@@ -1,27 +0,0 @@
1
- import { AuthenticationError, DuplicateEntityError, isValidationError, isEntityNotFoundError, isPermissionDeniedError, isBusinessRuleError, isConcurrencyError, } from "@longzai-intelligence/error";
2
- import { TokenExpiredError, TokenInvalidError, TokenMissingError, MfaRequiredError, InvalidCredentialsError, AccountDisabledError, RateLimitExceededError, } from "@longzai-intelligence-auth/core";
3
- export function mapDomainErrorToStatus(error) {
4
- if (isValidationError(error))
5
- return 400;
6
- if (error instanceof TokenExpiredError ||
7
- error instanceof TokenInvalidError ||
8
- error instanceof TokenMissingError ||
9
- error instanceof MfaRequiredError ||
10
- error instanceof InvalidCredentialsError ||
11
- error instanceof AccountDisabledError ||
12
- error instanceof AuthenticationError)
13
- return 401;
14
- if (isPermissionDeniedError(error))
15
- return 403;
16
- if (isEntityNotFoundError(error))
17
- return 404;
18
- if (error instanceof DuplicateEntityError)
19
- return 409;
20
- if (error instanceof RateLimitExceededError)
21
- return 429;
22
- if (isConcurrencyError(error))
23
- return 409;
24
- if (isBusinessRuleError(error))
25
- return 422;
26
- return 500;
27
- }
package/dist/plugin.d.ts DELETED
@@ -1,6 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import type { AuthPluginOptions } from "./types/auth-plugin-config";
3
- type AnyElysia = Elysia<any, any, any, any, any, any, any>;
4
- export declare function createAuthPlugin(options: AuthPluginOptions): Promise<AnyElysia>;
5
- export type { AuthPluginConfig, AuthPluginOptions, StrategyContext, StrategyName } from "./types/auth-plugin-config";
6
- export type { AuthStrategy } from "./core/auth-strategy";
package/dist/plugin.js DELETED
@@ -1,39 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import { createAuthStrategy, extractJwtConfig, extractDefaultTenantId, extractRegisterRoutes } from "./core/auth-strategy";
3
- import { createAuthRoutes, createMeRoute } from "./routes/auth.routes";
4
- import { createErrorHandlerPlugin } from "./plugins/error-handler.plugin";
5
- export async function createAuthPlugin(options) {
6
- const { logger, ...config } = options;
7
- const strategy = await createAuthStrategy(config);
8
- const jwtConfig = extractJwtConfig(config);
9
- const defaultTenantId = extractDefaultTenantId(config);
10
- const registerRoutes = extractRegisterRoutes(config);
11
- let plugin = new Elysia({ name: "@longzai-intelligence-auth/plugin" })
12
- .use(strategy.createJwtVerifyPlugin())
13
- .use(createErrorHandlerPlugin({ logger }));
14
- if (registerRoutes && config.strategy === "standalone") {
15
- const standaloneConfig = config;
16
- plugin = plugin.use(createAuthRoutes({
17
- jwt: jwtConfig,
18
- adapter: standaloneConfig.adapter,
19
- passwordHasher: standaloneConfig.passwordHasher,
20
- defaultTenantId,
21
- }));
22
- }
23
- if (registerRoutes && config.strategy === "env-basic") {
24
- const envBasicConfig = config;
25
- plugin = plugin.use(createAuthRoutes({
26
- jwt: jwtConfig,
27
- adapter: strategy.context.adapter,
28
- passwordHasher: strategy.context.passwordHasher,
29
- defaultTenantId,
30
- }));
31
- }
32
- if (registerRoutes && config.strategy === "jwt") {
33
- plugin = plugin.use(createMeRoute({
34
- jwt: jwtConfig,
35
- defaultTenantId,
36
- }));
37
- }
38
- return plugin;
39
- }
@@ -1,38 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import type { AuthBackendPort } from "@longzai-intelligence-auth/core";
3
- import type { AuditLogEntry } from "@longzai-intelligence-auth/core";
4
- export type AuditPluginOptions = {
5
- adapter: AuthBackendPort;
6
- };
7
- export declare function createAuditPlugin(options: AuditPluginOptions): Elysia<"", {
8
- decorator: {};
9
- store: {};
10
- derive: {};
11
- resolve: {};
12
- }, {
13
- typebox: {};
14
- error: {};
15
- }, {
16
- schema: {};
17
- standaloneSchema: {};
18
- macro: {};
19
- macroFn: {};
20
- parser: {};
21
- response: {};
22
- }, {}, {
23
- derive: {
24
- readonly recordAudit: (entry: Omit<AuditLogEntry, never>) => void;
25
- };
26
- resolve: {};
27
- schema: {};
28
- standaloneSchema: {};
29
- response: import("elysia").ExtractErrorFromHandle<{
30
- readonly recordAudit: (entry: Omit<AuditLogEntry, never>) => void;
31
- }>;
32
- }, {
33
- derive: {};
34
- resolve: {};
35
- schema: {};
36
- standaloneSchema: {};
37
- response: {};
38
- }>;
@@ -1,13 +0,0 @@
1
- import { Elysia } from "elysia";
2
- export function createAuditPlugin(options) {
3
- const { adapter } = options;
4
- return new Elysia({ name: "@longzai-intelligence-auth/audit" })
5
- .derive(() => ({
6
- recordAudit: (entry) => {
7
- adapter.audit.write(entry).catch((error) => {
8
- console.error("审计日志写入失败:", error);
9
- });
10
- },
11
- }))
12
- .as("scoped");
13
- }
@@ -1,46 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import type { LoggerService } from "@longzai-intelligence-auth/core";
3
- export type ErrorHandlerPluginOptions = {
4
- logger?: LoggerService;
5
- };
6
- export declare function createErrorHandlerPlugin(options?: ErrorHandlerPluginOptions): Elysia<"", {
7
- decorator: {};
8
- store: {};
9
- derive: {};
10
- resolve: {};
11
- }, {
12
- typebox: {};
13
- error: {};
14
- }, {
15
- schema: {};
16
- standaloneSchema: {};
17
- macro: {};
18
- macroFn: {};
19
- parser: {};
20
- response: {};
21
- }, {}, {
22
- derive: {};
23
- resolve: {};
24
- schema: {};
25
- standaloneSchema: {};
26
- response: {};
27
- }, {
28
- derive: {};
29
- resolve: {};
30
- schema: {};
31
- standaloneSchema: {};
32
- response: {
33
- 200: {
34
- code: string;
35
- message: string;
36
- details?: Record<string, unknown> | undefined;
37
- } | {
38
- code: string;
39
- message: string;
40
- details: {
41
- path: string;
42
- message: string | undefined;
43
- }[];
44
- };
45
- };
46
- }>;
@@ -1,45 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import { DomainError } from "@longzai-intelligence/error";
3
- import { mapDomainErrorToStatus } from "../core/error-mapper";
4
- export function createErrorHandlerPlugin(options = {}) {
5
- const { logger } = options;
6
- return new Elysia({ name: "@longzai-intelligence-auth/error-handler" })
7
- .onError(({ code, error, set }) => {
8
- if (error instanceof DomainError) {
9
- const status = mapDomainErrorToStatus(error);
10
- set.status = status;
11
- return {
12
- code: error.code,
13
- message: error.message,
14
- ...(error.context && Object.keys(error.context).length > 0
15
- ? { details: error.context }
16
- : {}),
17
- };
18
- }
19
- switch (code) {
20
- case "VALIDATION":
21
- set.status = 400;
22
- return {
23
- code: "VALIDATION_ERROR",
24
- message: "请求参数验证失败",
25
- details: error.all.map((e) => ({
26
- path: e.path,
27
- message: e.summary,
28
- })),
29
- };
30
- case "NOT_FOUND":
31
- set.status = 404;
32
- return { code: "NOT_FOUND", message: "未找到请求的资源" };
33
- case "PARSE":
34
- set.status = 400;
35
- return { code: "PARSE_ERROR", message: "请求数据解析失败" };
36
- default:
37
- logger?.error("未预期的错误", {
38
- error: error instanceof Error ? error.message : String(error),
39
- stack: error instanceof Error ? error.stack : undefined,
40
- });
41
- set.status = 500;
42
- return { code: "INTERNAL_ERROR", message: "服务器内部错误" };
43
- }
44
- });
45
- }
@@ -1,9 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import type { JwtSignerConfig } from "@longzai-intelligence-auth/jwt";
3
- export type JwtVerifyPluginOptions = {
4
- jwt: JwtSignerConfig;
5
- defaultTenantId?: string;
6
- };
7
- type AnyElysia = Elysia<any, any, any, any, any, any, any>;
8
- export declare function createJwtVerifyPlugin(options: JwtVerifyPluginOptions): AnyElysia;
9
- export {};
@@ -1,31 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import { createJwtVerifier } from "@longzai-intelligence-auth/jwt";
3
- import { TokenMissingError, TokenInvalidError } from "@longzai-intelligence-auth/core";
4
- export function createJwtVerifyPlugin(options) {
5
- const { jwt: jwtConfig, defaultTenantId = "default" } = options;
6
- let verifierPromise = null;
7
- const getVerifier = () => {
8
- if (!verifierPromise) {
9
- verifierPromise = createJwtVerifier(jwtConfig);
10
- }
11
- return verifierPromise;
12
- };
13
- return new Elysia({ name: "@longzai-intelligence-auth/jwt-verify" })
14
- .derive(async ({ request }) => {
15
- const authHeader = request.headers.get("Authorization");
16
- const bearer = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
17
- if (!bearer) {
18
- throw new TokenMissingError();
19
- }
20
- const verifier = await getVerifier();
21
- const result = await verifier.verifyAccessToken(bearer);
22
- if (!result.success || !result.payload) {
23
- throw new TokenInvalidError(result.error);
24
- }
25
- const payload = result.payload;
26
- const userId = payload.sub;
27
- const tenantId = payload.tenantId ?? defaultTenantId;
28
- return { userId, tenantId };
29
- })
30
- .as("scoped");
31
- }
@@ -1,33 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import type { LoggerService } from "@longzai-intelligence-auth/core";
3
- export type LoggerPluginOptions = {
4
- logger: LoggerService;
5
- };
6
- export declare function createLoggerPlugin(options: LoggerPluginOptions): Elysia<"", {
7
- decorator: {};
8
- store: {};
9
- derive: {};
10
- resolve: {};
11
- }, {
12
- typebox: {};
13
- error: {};
14
- }, {
15
- schema: {};
16
- standaloneSchema: {};
17
- macro: {};
18
- macroFn: {};
19
- parser: {};
20
- response: {};
21
- }, {}, {
22
- derive: {};
23
- resolve: {};
24
- schema: {};
25
- standaloneSchema: {};
26
- response: {};
27
- }, {
28
- derive: {};
29
- resolve: {};
30
- schema: {};
31
- standaloneSchema: {};
32
- response: {};
33
- }>;
@@ -1,16 +0,0 @@
1
- import { Elysia } from "elysia";
2
- export function createLoggerPlugin(options) {
3
- const { logger } = options;
4
- return new Elysia({ name: "@longzai-intelligence-auth/logger" })
5
- .onRequest(({ request }) => {
6
- logger.info(`${request.method} ${request.url}`);
7
- })
8
- .onAfterResponse(({ request, set }) => {
9
- logger.info(`${request.method} ${request.url} ${set.status}`);
10
- })
11
- .onError(({ request, error }) => {
12
- logger.error(`${request.method} ${request.url} 请求错误`, {
13
- error: error instanceof Error ? error.message : String(error),
14
- });
15
- });
16
- }
@@ -1,40 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import type { RateLimitConfig, LoggerService } from "@longzai-intelligence-auth/core";
3
- export type RateLimitPluginOptions = RateLimitConfig & {
4
- logger?: LoggerService;
5
- keyGenerator?: (request: Request) => string;
6
- };
7
- export declare function createRateLimitPlugin(options?: RateLimitPluginOptions): Elysia<"", {
8
- decorator: {};
9
- store: {};
10
- derive: {};
11
- resolve: {};
12
- }, {
13
- typebox: {};
14
- error: {};
15
- }, {
16
- schema: {};
17
- standaloneSchema: {};
18
- macro: {};
19
- macroFn: {};
20
- parser: {};
21
- response: {};
22
- }, {}, {
23
- derive: {};
24
- resolve: {};
25
- schema: {};
26
- standaloneSchema: {};
27
- response: {};
28
- }, {
29
- derive: {
30
- readonly clientIp: string;
31
- } & {
32
- readonly rateLimitRemaining: number;
33
- };
34
- resolve: {};
35
- schema: {};
36
- standaloneSchema: {};
37
- response: import("elysia").ExtractErrorFromHandle<{
38
- readonly rateLimitRemaining: number;
39
- }>;
40
- }>;
@@ -1,39 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import { createMemoryRateLimiter } from "@longzai-intelligence-auth/rate-limit";
3
- import { RateLimitExceededError } from "@longzai-intelligence-auth/core";
4
- function defaultKeyGenerator(request) {
5
- return request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()
6
- ?? request.headers.get("x-real-ip")
7
- ?? "unknown";
8
- }
9
- export function createRateLimitPlugin(options = { windowSeconds: 60, maxRequests: 100 }) {
10
- const { logger } = options;
11
- const keyGen = options.keyGenerator ?? defaultKeyGenerator;
12
- const limiter = createMemoryRateLimiter({
13
- windowSeconds: options.windowSeconds,
14
- maxRequests: options.maxRequests,
15
- });
16
- const timer = setInterval(() => {
17
- limiter.cleanup();
18
- }, 60_000);
19
- if (typeof process !== "undefined" && typeof process.on === "function") {
20
- process.on("exit", () => clearInterval(timer));
21
- }
22
- return new Elysia({ name: "@longzai-intelligence-auth/rate-limit" })
23
- .derive(({ request }) => {
24
- const clientIp = keyGen(request);
25
- return { clientIp };
26
- })
27
- .derive(async ({ clientIp, request }) => {
28
- const url = new URL(request.url);
29
- const path = url.pathname;
30
- const key = `${clientIp}:${path}`;
31
- const allowed = await limiter.check(key);
32
- if (!allowed) {
33
- logger?.warn("限流触发", { clientIp, path });
34
- throw new RateLimitExceededError();
35
- }
36
- const remaining = options.maxRequests - limiter.getCount(key);
37
- return { rateLimitRemaining: remaining };
38
- });
39
- }
@@ -1,36 +0,0 @@
1
- import { Elysia } from "elysia";
2
- import type { JwtSignerConfig } from "@longzai-intelligence-auth/jwt";
3
- export type RbacPluginOptions = {
4
- jwt: JwtSignerConfig;
5
- defaultTenantId?: string;
6
- };
7
- export declare function createRbacPlugin(options: RbacPluginOptions): Elysia<"", {
8
- decorator: {};
9
- store: {};
10
- derive: {};
11
- resolve: {};
12
- }, {
13
- typebox: {};
14
- error: {};
15
- }, {
16
- schema: {};
17
- standaloneSchema: {};
18
- macro: Partial<{}>;
19
- macroFn: ({ onBeforeHandle }: any) => {
20
- permission(permission: string): void;
21
- };
22
- parser: {};
23
- response: {};
24
- }, {}, {
25
- derive: {};
26
- resolve: {};
27
- schema: {};
28
- standaloneSchema: {};
29
- response: {};
30
- }, {
31
- derive: {};
32
- resolve: {};
33
- schema: {};
34
- standaloneSchema: {};
35
- response: {};
36
- }>;