@longzai-intelligence-tenant/elysia-in-memory-plugin 0.0.1

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.
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{failure as e,success as t}from"@longzai-intelligence/shared-kernel";import{membershipApi as n,quotaApi as r,subscriptionApi as i,tenantApi as a}from"@longzai-intelligence-tenant/sdk";var o=class{store=new Map;slugIndex=new Map;async findById(e){return t(this.store.get(e)??null)}async findBySlug(e){let n=this.slugIndex.get(e);return t(n?this.store.get(n)??null:null)}async findByOwnerId(e){return t(Array.from(this.store.values()).filter(t=>t.ownerId===e))}async findAll(e){let n=Array.from(this.store.values());if(e?.status&&(n=n.filter(t=>t.status===e.status)),e?.search){let t=e.search.toLowerCase();n=n.filter(e=>e.name.toLowerCase().includes(t)||e.slug.toLowerCase().includes(t))}let r=n.length,i=e?.page??1,a=e?.pageSize??20,o=Math.max(1,Math.ceil(r/a)),s=(i-1)*a;return t({items:n.slice(s,s+a).map(e=>({id:e.id,name:e.name,slug:e.slug,status:e.status,plan:e.plan,ownerId:e.ownerId,createdAt:e.createdAt})),total:r,page:i,pageSize:a,totalPages:o})}async create(n){let r=crypto.randomUUID(),i=new Date().toISOString();if(this.slugIndex.has(n.slug))return e({name:`TenantSlugDuplicateError`,message:`租户标识 ${n.slug} 已存在`,slug:n.slug});let a={id:r,name:n.name,slug:n.slug,status:`active`,plan:n.plan??null,ownerId:n.ownerId,maxMembers:n.maxMembers??10,settings:n.settings??{},createdAt:i,updatedAt:i};return this.store.set(r,a),this.slugIndex.set(n.slug,r),t(a)}async update(n,r){let i=this.store.get(n);if(!i)return e({name:`TenantNotFoundError`,message:`租户 ${n} 未找到`,tenantId:n});let a=new Date().toISOString(),o={...i,name:r.name??i.name,plan:r.plan??i.plan,maxMembers:r.maxMembers??i.maxMembers,settings:r.settings??i.settings,updatedAt:a};return this.store.set(n,o),t(o)}async delete(e){let n=this.store.get(e);return n&&this.slugIndex.delete(n.slug),this.store.delete(e),t(void 0)}},s=class{currentTenant=null;getCurrentTenant(){return this.currentTenant}setTenant(e){this.currentTenant=e}async validateTenant(e){return this.currentTenant?this.currentTenant.id===e?{valid:!0,tenant:this.currentTenant}:{valid:!1,error:`租户 ID ${e} 与当前租户不匹配`}:{valid:!1,error:`未设置当前租户`}}clearTenant(){this.currentTenant=null}},c=class{tenantStore=new Map;slugIndex=new Map;registerTenant(e){this.tenantStore.set(e.id,e),e.slug&&this.slugIndex.set(e.slug,e)}async resolveFromHeader(e){let t=e[`x-tenant-id`];if(t)return this.tenantStore.get(t)??null;let n=e[`x-tenant-slug`];return n?this.slugIndex.get(n)??null:null}async resolveFromSubdomain(e){let t=e.split(`.`);if(t.length>=2){let e=t[0];return this.slugIndex.get(e)??null}return null}async resolveFromToken(e){if(e.startsWith(`tenant-`)){let t=e.slice(7);return this.tenantStore.get(t)??null}return null}},l=class{store=new Map;async findById(e){return t(this.store.get(e)??null)}async findByTenantId(e){return t(Array.from(this.store.values()).filter(t=>t.tenantId===e))}async findByUserId(e){return t(Array.from(this.store.values()).filter(t=>t.userId===e))}async findByTenantAndUser(e,n){return t(Array.from(this.store.values()).find(t=>t.tenantId===e&&t.userId===n)??null)}async add(e){let n=crypto.randomUUID(),r=new Date().toISOString(),i={id:n,tenantId:e.tenantId,userId:e.userId,role:e.role,status:`active`,joinedAt:r};return this.store.set(n,i),t(i)}async changeRole(n,r){let i=this.store.get(n);if(!i)return e({name:`MemberNotFoundError`,message:`成员 ${n} 未找到`,memberId:n});let a={...i,role:r.role};return this.store.set(n,a),t(a)}async delete(e){return this.store.delete(e),t(void 0)}},u=class{store=new Map;codeIndex=new Map;async findById(e){return t(this.store.get(e)??null)}async findByTenantId(e){return t(Array.from(this.store.values()).filter(t=>t.tenantId===e))}async findByCode(e){let n=this.codeIndex.get(e);return t(n?this.store.get(n)??null:null)}async create(e){let n=crypto.randomUUID(),r=new Date().toISOString(),i=new Date(Date.now()+7*864e5).toISOString(),a={id:n,tenantId:e.tenantId,inviterId:e.inviterId,email:e.email,role:e.role,code:crypto.randomUUID().slice(0,8).toUpperCase(),status:`pending`,createdAt:r,expiresAt:i};return this.store.set(n,a),this.codeIndex.set(a.code,n),t(a)}async accept(n){let r=this.codeIndex.get(n.code);if(!r)return e({name:`InvitationNotFoundError`,message:`邀请码 ${n.code} 未找到`,code:n.code});let i=this.store.get(r);if(!i)return e({name:`InvitationNotFoundError`,message:`邀请 ${r} 未找到`,invitationId:r});let a={...i,status:`accepted`,acceptedAt:new Date().toISOString(),acceptedBy:n.userId};return this.store.set(r,a),t(a)}async delete(e){let n=this.store.get(e);return n&&this.codeIndex.delete(n.code),this.store.delete(e),t(void 0)}},d=class{store=new Map;tenantIndex=new Map;async findById(e){return t(this.store.get(e)??null)}async findByTenantId(e){let n=this.tenantIndex.get(e);return t(n?this.store.get(n)??null:null)}async subscribe(e){let n=crypto.randomUUID(),r=new Date().toISOString(),i=e.trialDays?new Date(Date.now()+e.trialDays*864e5).toISOString():null,a={id:n,tenantId:e.tenantId,planId:e.planId,status:e.trialDays?`trial`:`active`,startDate:r,endDate:null,trialEndAt:i};return this.store.set(n,a),this.tenantIndex.set(e.tenantId,n),t(a)}async delete(e){let n=this.store.get(e);return n&&this.tenantIndex.delete(n.tenantId),this.store.delete(e),t(void 0)}},f=class{store=new Map;async findById(e){return t(this.store.get(e)??null)}async findAll(){return t(Array.from(this.store.values()))}async create(e){let n=crypto.randomUUID(),r=new Date().toISOString(),i={id:n,name:e.name,description:e.description??null,features:e.features??[],limits:e.limits??{},price:e.price,billingCycle:e.billingCycle,status:`active`,createdAt:r};return this.store.set(n,i),t(i)}async delete(e){return this.store.delete(e),t(void 0)}},p=class{store=new Map;async findById(e){return t(this.store.get(e)??null)}async findByTenantId(e){return t(Array.from(this.store.values()).filter(t=>t.tenantId===e))}async findByTenantAndType(e,n){return t(Array.from(this.store.values()).find(t=>t.tenantId===e&&t.resourceType===n)??null)}async check(e,n){let r=Array.from(this.store.values()).find(t=>t.tenantId===e&&t.resourceType===n);return t(r?{allowed:r.used<r.limit,resourceType:r.resourceType,current:r.used,limit:r.limit}:{allowed:!1,resourceType:n,current:0,limit:0})}async adjust(n){let r=this.store.get(n.id);if(!r)return e({name:`QuotaNotFoundError`,message:`配额 ${n.id} 未找到`,quotaId:n.id});let i={...r,limit:n.limit??r.limit,used:n.used??r.used};return this.store.set(n.id,i),t(i)}async delete(e){return this.store.delete(e),t(void 0)}};function m(){return{tenantPort:new o,tenantContextPort:new s,tenantResolverPort:new c,memberPort:new l,invitationPort:new u,planPort:new f,subscriptionPort:new d,quotaPort:new p}}function h(e,t,n){for(let[r,i]of Object.entries(t.routes)){let a=`/${t.prefix}${i.path}`,o=n[r];o&&(i.method===`GET`?e.get(a,async e=>o(e.params,e.query)):i.method===`POST`?e.post(a,async e=>o(e.body,e.params)):i.method===`PATCH`?e.patch(a,async e=>o(e.body,e.params)):i.method===`DELETE`?e.delete(a,async e=>o(e.params)):i.method===`PUT`&&e.put(a,async e=>o(e.body,e.params)))}return e}function g(){let e=m();return t=>(t.derive(async({request:t})=>{let n=null,r={};if(t.headers.forEach((e,t)=>{r[t]=e}),n=await e.tenantResolverPort.resolveFromHeader(r),!n){let r=t.headers.get(`host`);r&&(n=await e.tenantResolverPort.resolveFromSubdomain(r))}if(!n){let r=t.headers.get(`authorization`);if(r){let t=r.startsWith(`Bearer `)?r.slice(7):r;n=await e.tenantResolverPort.resolveFromToken(t)}}return n&&e.tenantContextPort.setTenant(n),{tenant:n}}).as(`scoped`),t=h(t,a,{getTenant:t=>e.tenantPort.findById(t.id),listTenants:(t,n)=>e.tenantPort.findAll(n),createTenant:t=>e.tenantPort.create(t),updateTenant:(t,n)=>e.tenantPort.update(n.id,t),deleteTenant:t=>e.tenantPort.delete(t.id),getTenantBySlug:t=>e.tenantPort.findBySlug(t.slug),validateTenant:t=>e.tenantContextPort.validateTenant(t.id),resolveFromHeader:t=>{let n=t;return e.tenantResolverPort.resolveFromHeader(n)},resolveFromSubdomain:t=>{let n=t;return e.tenantResolverPort.resolveFromSubdomain(n.host)},resolveFromToken:t=>{let n=t;return e.tenantResolverPort.resolveFromToken(n.token)}}),t=h(t,n,{getMember:t=>e.memberPort.findById(t.id),listMembersByTenant:(t,n)=>e.memberPort.findByTenantId(t.tenantId),listMembersByUser:t=>e.memberPort.findByUserId(t.userId),getMemberByTenantAndUser:t=>e.memberPort.findByTenantAndUser(t.tenantId,t.userId),addMember:(t,n)=>e.memberPort.add({...t,tenantId:n.tenantId}),deleteMember:t=>e.memberPort.delete(t.id),getInvitation:t=>e.invitationPort.findById(t.id),listInvitationsByTenant:t=>e.invitationPort.findByTenantId(t.tenantId),getInvitationByCode:t=>e.invitationPort.findByCode(t.code),createInvitation:(t,n)=>e.invitationPort.create({...t,tenantId:n.tenantId}),deleteInvitation:t=>e.invitationPort.delete(t.id)}),t=h(t,i,{getPlan:t=>e.planPort.findById(t.id),listPlans:()=>e.planPort.findAll(),createPlan:t=>e.planPort.create(t),deletePlan:t=>e.planPort.delete(t.id),getSubscription:t=>e.subscriptionPort.findById(t.id),getSubscriptionByTenant:t=>e.subscriptionPort.findByTenantId(t.tenantId),subscribe:(t,n)=>e.subscriptionPort.subscribe({...t,tenantId:n.tenantId}),cancelSubscription:t=>e.subscriptionPort.delete(t.id)}),t=h(t,r,{getQuota:t=>e.quotaPort.findById(t.id),listQuotasByTenant:t=>e.quotaPort.findByTenantId(t.tenantId),getQuotaByTenantAndType:t=>e.quotaPort.findByTenantAndType(t.tenantId,t.resourceType),checkQuota:(t,n)=>e.quotaPort.check(n.tenantId,t.resourceType),adjustQuota:t=>e.quotaPort.adjust(t),deleteQuota:t=>e.quotaPort.delete(t.id)}),t)}export{u as InMemoryInvitationAdapter,l as InMemoryMemberAdapter,f as InMemoryPlanAdapter,p as InMemoryQuotaAdapter,d as InMemorySubscriptionAdapter,o as InMemoryTenantAdapter,s as InMemoryTenantContextAdapter,c as InMemoryTenantResolverAdapter,m as createMemoryPreset,g as createTenantPreset};
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@longzai-intelligence-tenant/elysia-in-memory-plugin",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "license": "UNLICENSED",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsgo --build tsconfig/build.json && resolve-aliases -p tsconfig/build.json",
20
+ "build:prod": "NODE_ENV=production tsdown",
21
+ "prepublishOnly": "bun run build:prod",
22
+ "typecheck": "bun run typecheck:app && bun run typecheck:node && bun run typecheck:test",
23
+ "typecheck:app": "tsgo --noEmit -p tsconfig/app.json",
24
+ "typecheck:node": "tsgo --noEmit -p tsconfig/node.json",
25
+ "typecheck:test": "tsgo --noEmit -p tsconfig/test.json",
26
+ "lint": "oxlint src && oxfmt --check src",
27
+ "lint:fix": "oxlint --fix src && oxfmt src",
28
+ "test": "bun test",
29
+ "test:watch": "bun test --watch",
30
+ "test:coverage": "bun test --coverage",
31
+ "clean": "rm -rf dist out .cache"
32
+ },
33
+ "dependencies": {
34
+ "@longzai-intelligence-tenant/sdk": "0.0.1",
35
+ "@longzai-intelligence-tenant/core": "0.0.1",
36
+ "@longzai-intelligence/shared-kernel": "^0.1.4",
37
+ "@longzai-intelligence/error": "^0.0.5"
38
+ },
39
+ "peerDependencies": {
40
+ "elysia": "^1.3"
41
+ },
42
+ "devDependencies": {
43
+ "elysia": "^1.3",
44
+ "@longzai-intelligence-tenant/tenant-contract": "0.0.1",
45
+ "@longzai-intelligence-tenant/membership-contract": "0.0.1",
46
+ "@longzai-intelligence-tenant/subscription-contract": "0.0.1",
47
+ "@longzai-intelligence-tenant/quota-contract": "0.0.1"
48
+ }
49
+ }