@linkfox-web/api-user-center 0.0.0-stage → 0.2.0

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/README.md CHANGED
@@ -1,3 +1,21 @@
1
- # Temporary Holding Version
1
+ # @linkfox-web/api-user-center
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ LinkFox 用户中心接口。登录成功后自动写入 `@linkfox-web/http` 的会话并同步当前团队,其他 `@linkfox-web/api-*` 包随即可用;同时注册「刷新 token」「补团队」能力,供所有服务包在 401 时使用。
4
+
5
+ ```bash
6
+ pnpm add @linkfox-web/http @linkfox-web/api-user-center
7
+ ```
8
+
9
+ | 函数 | 说明 |
10
+ | --- | --- |
11
+ | `getImageVerifyCode()` | 图形验证码,返回 `{ uuid, imageBase64 }` |
12
+ | `getVerifyCode(params)` | 发送短信验证码 |
13
+ | `loginByPassword(params)` / `loginByCode(params)` | 账密 / 短信验证码登录 |
14
+ | `getWechatQrCode()` / `getWechatQrCodeStatus(sessionId)` / `loginByWechat(params)` | 微信扫码登录 |
15
+ | `getUserInfo()` | 用户信息与团队列表 |
16
+ | `switchTeam(teamId)` | 切换团队并写入会话 |
17
+ | `getPersonalKey(teamId?)` | 当前用户在某团队下的个人 API Key 列表;`teamId` 为用户中心团队 ID,不传取当前团队 |
18
+ | `syncApiKey(teamId?)` | 取个人 API Key(优先 `USER_PRIMARY`)注入 `@linkfox-web/ai-tools` 配置并返回;只在内存,刷新页面或 `switchTeam` 后需重新调用 |
19
+ | `logout()` | 清除本地会话,并清掉已注入的 API Key |
20
+
21
+ 登录函数的第二个参数可传 `{ sourceUrl }`,默认取 `location.href`。`source`、`systemId`、`clientChannel` 可通过 `configure({ services: { 'user-center': { … } } })` 覆盖。
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";var V=Object.create;var l=Object.defineProperty;var z=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var X=Object.getPrototypeOf,Y=Object.prototype.hasOwnProperty;var G=(e,t)=>{for(var n in t)l(e,n,{get:t[n],enumerable:!0})},U=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of j(t))!Y.call(e,i)&&i!==n&&l(e,i,{get:()=>t[i],enumerable:!(r=z(t,i))||r.enumerable});return e};var m=(e,t,n)=>(n=e!=null?V(X(e)):{},U(t||!e||!e.__esModule?l(n,"default",{value:e,enumerable:!0}):n,e)),J=e=>U(l({},"__esModule",{value:!0}),e);var re={};G(re,{getImageVerifyCode:()=>D,getPersonalKey:()=>I,getUserInfo:()=>d,getVerifyCode:()=>q,getWechatQrCode:()=>F,getWechatQrCodeStatus:()=>H,loginByCode:()=>B,loginByPassword:()=>Q,loginByWechat:()=>M,logout:()=>L,resolveCurrentTeam:()=>g,switchTeam:()=>b,syncApiKey:()=>E,syncCurrentTeam:()=>u});module.exports=J(re);var f=require("@linkfox-web/http");var h=require("@linkfox-web/http");var S={baseURL:"https://api.linkfox.com",aesKey:"AR7x7zfje4nkim4t",source:"ai-linkfox-web",systemId:"LinkFoxAgent",clientChannel:"LinkFoxAI"};var Z=new Set(["30003","30009","30011","30015","30017","30019"]),k="LINKFOX_CLIENT_ID";function p(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function y(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}function $(){try{let e=localStorage.getItem(k);return e||(e=y(),localStorage.setItem(k,e)),e}catch{return""}}function ee(e){try{return btoa(JSON.stringify({a_id:$(),d_id:e}))}catch{return""}}var o=(0,h.defineService)({name:"user-center",defaults:S,baseHeaders:e=>({source:e.config.source,uid:ee(e.session?.userId??"")}),authorize:e=>e.session?{authorization:e.session.accessToken}:{},isUnauthorized:(e,t)=>e.status===401||p(t)&&t.success!==!0&&Z.has(String(t.code??"")),refreshOnUnauthorized:!1,unwrap:(e,t)=>{if(p(t)&&(t.code==="OK"&&t.success!==!1||t.code===200&&t.success!==!1||t.success===!0)&&e.ok)return t.data;throw new h.LinkfoxHttpError({service:"user-center",status:e.status,code:p(t)?t.code:void 0,message:p(t)&&(t.message||t.msg)||e.statusText||`HTTP ${e.status}`,body:t})}});var a=require("@linkfox-web/http");var s=require("@linkfox-web/http");async function I(e){return(await o.request({method:"POST",path:"/linkFoxApp/api/userCenter/api-credential/getPersonalKey",body:{teamId:e||await te()}}))?.credentials??[]}async function te(){let e=(0,s.getCurrentTeam)()?.teamId;if(e)return e;let{teamList:t}=await d(),n=(g(t)??t.find(r=>r.isSelect===1)??t[0])?.teamId;if(!n)throw new s.LinkfoxHttpError({service:"user-center",status:200,code:"TEAM_REQUIRED",message:"当前账号没有可用团队"});return n}async function E(e){let t=await I(e),n=t.find(r=>r.credentialType==="USER_PRIMARY"&&r.credential)??t.find(r=>r.credential);if(!n)throw new s.LinkfoxHttpError({service:"user-center",status:200,code:"API_KEY_NOT_FOUND",message:"当前账号没有可用的 API Key"});return T(n.credential),n.credential}function T(e){(0,s.configure)({services:{"ai-tools":{apiKey:e}}})}function d(){return R(!1)}function R(e){return o.request({method:"POST",path:"/linkFoxApp/api/userCenter/userInfo",body:{},skipRecovery:e})}function g(e){if(!e?.length)return;let t=e.find(r=>r.isSelect===1);if(t?.agentMemberId)return t;let n=e.find(r=>r.teamType===1);return n?.agentMemberId?n:e.find(r=>r.agentMemberId)}function v(e){return e.aiTeamId?{id:e.aiTeamId,teamId:e.teamId,name:e.teamName,type:e.teamType,logo:e.logo??"",ownerId:e.ownerId}:null}async function u(e){let t=await R(e?.skipRecovery??!1),n=g(t.teamList),r=n?v(n):null;return r?((0,a.setTeam)(r),!0):!1}async function b(e){await o.request({method:"POST",path:"/linkFoxApp/api/userCenter/team/switchTeam",body:{targetTeamId:e}});let t=await d(),n=t.teamList.find(i=>i.teamId===e),r=n?v(n):null;return r?(0,a.setTeam)(r):(0,a.clearTeam)(),t}function L(){(0,a.clearSession)(),T(void 0)}async function ne(e){let t=await o.request({method:"POST",path:"/cp/v1/user/refresh",auth:"none",skipRecovery:!0,headers:{authorization:e.refreshToken??""}});if(!t?.accessToken)throw new Error("REFRESH_TOKEN_EXPIRED");(0,f.updateSession)({accessToken:t.accessToken,refreshToken:t.refreshToken,expireAt:t.expireAt})}function A(){(0,f.registerCapability)("refresh",ne),(0,f.registerCapability)("resolveTeam",()=>u({skipRecovery:!0}))}var C=require("@linkfox-web/http");var O=m(require("crypto-js/aes"),1),_=m(require("crypto-js/enc-utf8"),1),N=m(require("crypto-js/mode-ecb"),1),K=m(require("crypto-js/pad-zeropadding"),1);function W(e,t){return O.default.encrypt(e,_.default.parse(t),{mode:N.default,padding:K.default}).toString()}function w(e){return e?.sourceUrl??(typeof location<"u"?location.href:"")}async function P(e){if(!e?.accessToken)throw new C.LinkfoxHttpError({service:"user-center",status:200,code:"INVALID_LOGIN_RESPONSE",message:"登录响应缺少 accessToken",body:e});(0,C.setSession)(e);try{await u()}catch{}return e}function x(e,t){return o.request({method:"POST",path:e,body:t,auth:"none"})}async function D(){let e=y(),t=await o.request({path:"/user/v1/sendMessageCode.jpg",query:{uuid:e},auth:"none",responseType:"blob"}),n=await new Promise((r,i)=>{let c=new FileReader;c.onloadend=()=>r(String(c.result??"")),c.onerror=()=>i(c.error),c.readAsDataURL(t)});return{uuid:e,imageBase64:n}}async function Q(e,t){let n=o.config(),r=await x("/user/v2/web/login",{type:"smsPwd",method:"login",sourceUrl:w(t),data:{authPhone:e.authPhone,auth:W(e.password,n.aesKey),uuid:e.uuid,imageCode:e.imageCode,systemId:n.systemId}});return P(r)}async function q(e){await x("/user/v3/web/login",{type:"sms",method:"getVerifyCode",data:{authPhone:e.authPhone,areaCode:e.areaCode??"+86",...e.uuid?{uuid:e.uuid}:{},...e.imageCode?{imageCode:e.imageCode}:{},clientChannel:o.config().clientChannel}})}async function B(e,t){let n=await x("/user/v3/web/login",{type:"sms",method:"login",sourceUrl:w(t),data:{authPhone:e.authPhone,areaCode:e.areaCode??"+86",authCode:e.authCode,sourceChannel:e.sourceChannel??""}});return P(n)}function F(){return o.request({method:"POST",path:"/user/v1/web/login/wechat/qr_url",body:{type:"1"},auth:"none"})}function H(e){return o.request({path:"/user/v1/web/login/wechat",query:{sessionId:e},auth:"none"})}async function M(e,t){let n=await x("/user/v2/web/login",{type:"wechatQR",method:"login",sourceUrl:w(t),data:{sessionId:e.sessionId,...e.authPhone?{authPhone:e.authPhone}:{},...e.authCode?{authCode:e.authCode}:{},sourceChannel:e.sourceChannel??""}});return P(n)}A();
@@ -0,0 +1,149 @@
1
+ import { Session } from '@linkfox-web/http';
2
+
3
+ /** 登录接口返回:token 字段之外的用户信息原样写进会话 */
4
+ interface LoginResult extends Session {
5
+ userName?: string;
6
+ email?: string;
7
+ phoneNum?: string;
8
+ avatarUrl?: string;
9
+ loginType?: string;
10
+ newUser?: boolean;
11
+ aiNewUser?: boolean;
12
+ sourceChannel?: string;
13
+ }
14
+ interface LoginOptions {
15
+ /** 登录来源页,默认 location.href */
16
+ sourceUrl?: string;
17
+ }
18
+ interface ImageVerifyCode {
19
+ uuid: string;
20
+ /** data URL,可直接放进 img src */
21
+ imageBase64: string;
22
+ }
23
+ /** 获取图形验证码 */
24
+ declare function getImageVerifyCode(): Promise<ImageVerifyCode>;
25
+ /** 账密登录 */
26
+ declare function loginByPassword(params: {
27
+ authPhone: string;
28
+ password: string;
29
+ imageCode: string;
30
+ uuid: string;
31
+ }, options?: LoginOptions): Promise<LoginResult>;
32
+ /** 发送短信验证码 */
33
+ declare function getVerifyCode(params: {
34
+ authPhone: string;
35
+ areaCode?: string;
36
+ uuid?: string;
37
+ imageCode?: string;
38
+ }): Promise<void>;
39
+ /** 短信验证码登录 */
40
+ declare function loginByCode(params: {
41
+ authPhone: string;
42
+ authCode: string;
43
+ areaCode?: string;
44
+ sourceChannel?: string;
45
+ }, options?: LoginOptions): Promise<LoginResult>;
46
+ interface WechatQrCode {
47
+ qrUrl: string;
48
+ sessionId: string;
49
+ }
50
+ /** 获取微信登录二维码 */
51
+ declare function getWechatQrCode(): Promise<WechatQrCode>;
52
+ interface WechatQrCodeStatus {
53
+ /** 2=已扫码 */
54
+ status: number;
55
+ /** true 表示需要绑定手机号 */
56
+ first: boolean;
57
+ }
58
+ /** 轮询微信二维码扫码状态 */
59
+ declare function getWechatQrCodeStatus(sessionId: string): Promise<WechatQrCodeStatus>;
60
+ /** 微信扫码登录;需要绑定手机号时附带 authPhone / authCode */
61
+ declare function loginByWechat(params: {
62
+ sessionId: string;
63
+ authPhone?: string;
64
+ authCode?: string;
65
+ sourceChannel?: string;
66
+ }, options?: LoginOptions): Promise<LoginResult>;
67
+
68
+ interface UserInfoTeam {
69
+ teamId: string;
70
+ teamName: string;
71
+ aiTeamId: string | null;
72
+ agentTeamId: string | null;
73
+ agentMemberId: string | null;
74
+ /** 1=所有者 2=成员 3=管理员 4=开放平台用户 */
75
+ role: string;
76
+ logo: string | null;
77
+ /** 1=当前选中 */
78
+ isSelect: number;
79
+ /** 1=个人 2=团队 */
80
+ teamType: number;
81
+ ownerId: string;
82
+ mergeSourceInfo: string | null;
83
+ }
84
+ interface UserInfo {
85
+ id: string;
86
+ nickName: string;
87
+ phoneNum: string;
88
+ avatar: string | null;
89
+ verifyStatus: boolean;
90
+ bindWechat: boolean;
91
+ status: number;
92
+ /** 注销冷静期到期时间戳(毫秒) */
93
+ freezeExpireTime?: number;
94
+ teamList: UserInfoTeam[];
95
+ }
96
+ declare function getUserInfo(): Promise<UserInfo>;
97
+ /** 选出当前团队:优先 isSelect=1,没有 agentMemberId 时回退个人账号,再回退任意可用团队 */
98
+ declare function resolveCurrentTeam(teamList: UserInfoTeam[] | undefined): UserInfoTeam | undefined;
99
+ /**
100
+ * 拉用户信息并把当前团队写进会话;写到返回 true。
101
+ * `skipRecovery` 为 true 时 token 失效直接抛错,由调用方决定是否刷新(401 恢复流程里用)。
102
+ */
103
+ declare function syncCurrentTeam(options?: {
104
+ skipRecovery?: boolean;
105
+ }): Promise<boolean>;
106
+ /** 切换团队,成功后把新团队写进会话 */
107
+ declare function switchTeam(teamId: string): Promise<UserInfo>;
108
+ /** 登出:只清本地会话,不调后端(与主站一致);同时清掉内存里的 API Key,避免下一个登录的用户沿用 */
109
+ declare function logout(): void;
110
+
111
+ interface ApiCredential {
112
+ credentialId: string;
113
+ /** API Key 本身,即工具网关的 Authorization 值 */
114
+ credential: string;
115
+ /** 脱敏前缀,如 `eyJhbGciOi***` */
116
+ keyPrefix: string;
117
+ /** 如 USER_PRIMARY */
118
+ credentialType: string;
119
+ /** 如 AGENT_LEGACY */
120
+ keyFormat: string;
121
+ version: number;
122
+ rotated: boolean;
123
+ ipWhitelist: string[];
124
+ }
125
+ /**
126
+ * 查询当前登录用户在指定团队下的个人 API Key 列表。
127
+ * teamId 是用户中心的 teamId(不是 aiTeamId);不传时取会话里的当前团队,会话里没有再查用户信息选当前团队。
128
+ */
129
+ declare function getPersonalKey(teamId?: string): Promise<ApiCredential[]>;
130
+ /**
131
+ * 获取个人 API Key(优先 USER_PRIMARY,teamId 规则同 getPersonalKey)并注入 @linkfox-web/ai-tools 的配置,返回该 Key。
132
+ * 只存在内存里,刷新页面后需重新调用;没有可用 Key 时抛 API_KEY_NOT_FOUND,且不改动已有配置。
133
+ */
134
+ declare function syncApiKey(teamId?: string): Promise<string>;
135
+
136
+ interface UserCenterConfig {
137
+ baseURL: string;
138
+ aesKey: string;
139
+ source: string;
140
+ systemId: string;
141
+ clientChannel: string;
142
+ }
143
+ declare module '@linkfox-web/http' {
144
+ interface ServiceConfigMap {
145
+ 'user-center': UserCenterConfig;
146
+ }
147
+ }
148
+
149
+ export { type ApiCredential, type ImageVerifyCode, type LoginOptions, type LoginResult, type UserCenterConfig, type UserInfo, type UserInfoTeam, type WechatQrCode, type WechatQrCodeStatus, getImageVerifyCode, getPersonalKey, getUserInfo, getVerifyCode, getWechatQrCode, getWechatQrCodeStatus, loginByCode, loginByPassword, loginByWechat, logout, resolveCurrentTeam, switchTeam, syncApiKey, syncCurrentTeam };
@@ -0,0 +1,149 @@
1
+ import { Session } from '@linkfox-web/http';
2
+
3
+ /** 登录接口返回:token 字段之外的用户信息原样写进会话 */
4
+ interface LoginResult extends Session {
5
+ userName?: string;
6
+ email?: string;
7
+ phoneNum?: string;
8
+ avatarUrl?: string;
9
+ loginType?: string;
10
+ newUser?: boolean;
11
+ aiNewUser?: boolean;
12
+ sourceChannel?: string;
13
+ }
14
+ interface LoginOptions {
15
+ /** 登录来源页,默认 location.href */
16
+ sourceUrl?: string;
17
+ }
18
+ interface ImageVerifyCode {
19
+ uuid: string;
20
+ /** data URL,可直接放进 img src */
21
+ imageBase64: string;
22
+ }
23
+ /** 获取图形验证码 */
24
+ declare function getImageVerifyCode(): Promise<ImageVerifyCode>;
25
+ /** 账密登录 */
26
+ declare function loginByPassword(params: {
27
+ authPhone: string;
28
+ password: string;
29
+ imageCode: string;
30
+ uuid: string;
31
+ }, options?: LoginOptions): Promise<LoginResult>;
32
+ /** 发送短信验证码 */
33
+ declare function getVerifyCode(params: {
34
+ authPhone: string;
35
+ areaCode?: string;
36
+ uuid?: string;
37
+ imageCode?: string;
38
+ }): Promise<void>;
39
+ /** 短信验证码登录 */
40
+ declare function loginByCode(params: {
41
+ authPhone: string;
42
+ authCode: string;
43
+ areaCode?: string;
44
+ sourceChannel?: string;
45
+ }, options?: LoginOptions): Promise<LoginResult>;
46
+ interface WechatQrCode {
47
+ qrUrl: string;
48
+ sessionId: string;
49
+ }
50
+ /** 获取微信登录二维码 */
51
+ declare function getWechatQrCode(): Promise<WechatQrCode>;
52
+ interface WechatQrCodeStatus {
53
+ /** 2=已扫码 */
54
+ status: number;
55
+ /** true 表示需要绑定手机号 */
56
+ first: boolean;
57
+ }
58
+ /** 轮询微信二维码扫码状态 */
59
+ declare function getWechatQrCodeStatus(sessionId: string): Promise<WechatQrCodeStatus>;
60
+ /** 微信扫码登录;需要绑定手机号时附带 authPhone / authCode */
61
+ declare function loginByWechat(params: {
62
+ sessionId: string;
63
+ authPhone?: string;
64
+ authCode?: string;
65
+ sourceChannel?: string;
66
+ }, options?: LoginOptions): Promise<LoginResult>;
67
+
68
+ interface UserInfoTeam {
69
+ teamId: string;
70
+ teamName: string;
71
+ aiTeamId: string | null;
72
+ agentTeamId: string | null;
73
+ agentMemberId: string | null;
74
+ /** 1=所有者 2=成员 3=管理员 4=开放平台用户 */
75
+ role: string;
76
+ logo: string | null;
77
+ /** 1=当前选中 */
78
+ isSelect: number;
79
+ /** 1=个人 2=团队 */
80
+ teamType: number;
81
+ ownerId: string;
82
+ mergeSourceInfo: string | null;
83
+ }
84
+ interface UserInfo {
85
+ id: string;
86
+ nickName: string;
87
+ phoneNum: string;
88
+ avatar: string | null;
89
+ verifyStatus: boolean;
90
+ bindWechat: boolean;
91
+ status: number;
92
+ /** 注销冷静期到期时间戳(毫秒) */
93
+ freezeExpireTime?: number;
94
+ teamList: UserInfoTeam[];
95
+ }
96
+ declare function getUserInfo(): Promise<UserInfo>;
97
+ /** 选出当前团队:优先 isSelect=1,没有 agentMemberId 时回退个人账号,再回退任意可用团队 */
98
+ declare function resolveCurrentTeam(teamList: UserInfoTeam[] | undefined): UserInfoTeam | undefined;
99
+ /**
100
+ * 拉用户信息并把当前团队写进会话;写到返回 true。
101
+ * `skipRecovery` 为 true 时 token 失效直接抛错,由调用方决定是否刷新(401 恢复流程里用)。
102
+ */
103
+ declare function syncCurrentTeam(options?: {
104
+ skipRecovery?: boolean;
105
+ }): Promise<boolean>;
106
+ /** 切换团队,成功后把新团队写进会话 */
107
+ declare function switchTeam(teamId: string): Promise<UserInfo>;
108
+ /** 登出:只清本地会话,不调后端(与主站一致);同时清掉内存里的 API Key,避免下一个登录的用户沿用 */
109
+ declare function logout(): void;
110
+
111
+ interface ApiCredential {
112
+ credentialId: string;
113
+ /** API Key 本身,即工具网关的 Authorization 值 */
114
+ credential: string;
115
+ /** 脱敏前缀,如 `eyJhbGciOi***` */
116
+ keyPrefix: string;
117
+ /** 如 USER_PRIMARY */
118
+ credentialType: string;
119
+ /** 如 AGENT_LEGACY */
120
+ keyFormat: string;
121
+ version: number;
122
+ rotated: boolean;
123
+ ipWhitelist: string[];
124
+ }
125
+ /**
126
+ * 查询当前登录用户在指定团队下的个人 API Key 列表。
127
+ * teamId 是用户中心的 teamId(不是 aiTeamId);不传时取会话里的当前团队,会话里没有再查用户信息选当前团队。
128
+ */
129
+ declare function getPersonalKey(teamId?: string): Promise<ApiCredential[]>;
130
+ /**
131
+ * 获取个人 API Key(优先 USER_PRIMARY,teamId 规则同 getPersonalKey)并注入 @linkfox-web/ai-tools 的配置,返回该 Key。
132
+ * 只存在内存里,刷新页面后需重新调用;没有可用 Key 时抛 API_KEY_NOT_FOUND,且不改动已有配置。
133
+ */
134
+ declare function syncApiKey(teamId?: string): Promise<string>;
135
+
136
+ interface UserCenterConfig {
137
+ baseURL: string;
138
+ aesKey: string;
139
+ source: string;
140
+ systemId: string;
141
+ clientChannel: string;
142
+ }
143
+ declare module '@linkfox-web/http' {
144
+ interface ServiceConfigMap {
145
+ 'user-center': UserCenterConfig;
146
+ }
147
+ }
148
+
149
+ export { type ApiCredential, type ImageVerifyCode, type LoginOptions, type LoginResult, type UserCenterConfig, type UserInfo, type UserInfoTeam, type WechatQrCode, type WechatQrCodeStatus, getImageVerifyCode, getPersonalKey, getUserInfo, getVerifyCode, getWechatQrCode, getWechatQrCodeStatus, loginByCode, loginByPassword, loginByWechat, logout, resolveCurrentTeam, switchTeam, syncApiKey, syncCurrentTeam };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{registerCapability as P,updateSession as Q}from"@linkfox-web/http";import{defineService as k,LinkfoxHttpError as E}from"@linkfox-web/http";var h={baseURL:"https://api.linkfox.com",aesKey:"AR7x7zfje4nkim4t",source:"ai-linkfox-web",systemId:"LinkFoxAgent",clientChannel:"LinkFoxAI"};var R=new Set(["30003","30009","30011","30015","30017","30019"]),C="LINKFOX_CLIENT_ID";function a(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function f(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e==="x"?t:t&3|8).toString(16)})}function v(){try{let e=localStorage.getItem(C);return e||(e=f(),localStorage.setItem(C,e)),e}catch{return""}}function b(e){try{return btoa(JSON.stringify({a_id:v(),d_id:e}))}catch{return""}}var o=k({name:"user-center",defaults:h,baseHeaders:e=>({source:e.config.source,uid:b(e.session?.userId??"")}),authorize:e=>e.session?{authorization:e.session.accessToken}:{},isUnauthorized:(e,t)=>e.status===401||a(t)&&t.success!==!0&&R.has(String(t.code??"")),refreshOnUnauthorized:!1,unwrap:(e,t)=>{if(a(t)&&(t.code==="OK"&&t.success!==!1||t.code===200&&t.success!==!1||t.success===!0)&&e.ok)return t.data;throw new E({service:"user-center",status:e.status,code:a(t)?t.code:void 0,message:a(t)&&(t.message||t.msg)||e.statusText||`HTTP ${e.status}`,body:t})}});import{clearSession as N,clearTeam as K,setTeam as I}from"@linkfox-web/http";import{configure as L,getCurrentTeam as A,LinkfoxHttpError as x}from"@linkfox-web/http";async function y(e){return(await o.request({method:"POST",path:"/linkFoxApp/api/userCenter/api-credential/getPersonalKey",body:{teamId:e||await O()}}))?.credentials??[]}async function O(){let e=A()?.teamId;if(e)return e;let{teamList:t}=await u(),n=(c(t)??t.find(r=>r.isSelect===1)??t[0])?.teamId;if(!n)throw new x({service:"user-center",status:200,code:"TEAM_REQUIRED",message:"当前账号没有可用团队"});return n}async function _(e){let t=await y(e),n=t.find(r=>r.credentialType==="USER_PRIMARY"&&r.credential)??t.find(r=>r.credential);if(!n)throw new x({service:"user-center",status:200,code:"API_KEY_NOT_FOUND",message:"当前账号没有可用的 API Key"});return l(n.credential),n.credential}function l(e){L({services:{"ai-tools":{apiKey:e}}})}function u(){return T(!1)}function T(e){return o.request({method:"POST",path:"/linkFoxApp/api/userCenter/userInfo",body:{},skipRecovery:e})}function c(e){if(!e?.length)return;let t=e.find(r=>r.isSelect===1);if(t?.agentMemberId)return t;let n=e.find(r=>r.teamType===1);return n?.agentMemberId?n:e.find(r=>r.agentMemberId)}function w(e){return e.aiTeamId?{id:e.aiTeamId,teamId:e.teamId,name:e.teamName,type:e.teamType,logo:e.logo??"",ownerId:e.ownerId}:null}async function s(e){let t=await T(e?.skipRecovery??!1),n=c(t.teamList),r=n?w(n):null;return r?(I(r),!0):!1}async function W(e){await o.request({method:"POST",path:"/linkFoxApp/api/userCenter/team/switchTeam",body:{targetTeamId:e}});let t=await u(),n=t.teamList.find(g=>g.teamId===e),r=n?w(n):null;return r?I(r):K(),t}function D(){N(),l(void 0)}async function q(e){let t=await o.request({method:"POST",path:"/cp/v1/user/refresh",auth:"none",skipRecovery:!0,headers:{authorization:e.refreshToken??""}});if(!t?.accessToken)throw new Error("REFRESH_TOKEN_EXPIRED");Q({accessToken:t.accessToken,refreshToken:t.refreshToken,expireAt:t.expireAt})}function U(){P("refresh",q),P("resolveTeam",()=>s({skipRecovery:!0}))}import{LinkfoxHttpError as V,setSession as z}from"@linkfox-web/http";import B from"crypto-js/aes";import F from"crypto-js/enc-utf8";import H from"crypto-js/mode-ecb";import M from"crypto-js/pad-zeropadding";function S(e,t){return B.encrypt(e,F.parse(t),{mode:H,padding:M}).toString()}function m(e){return e?.sourceUrl??(typeof location<"u"?location.href:"")}async function p(e){if(!e?.accessToken)throw new V({service:"user-center",status:200,code:"INVALID_LOGIN_RESPONSE",message:"登录响应缺少 accessToken",body:e});z(e);try{await s()}catch{}return e}function d(e,t){return o.request({method:"POST",path:e,body:t,auth:"none"})}async function j(){let e=f(),t=await o.request({path:"/user/v1/sendMessageCode.jpg",query:{uuid:e},auth:"none",responseType:"blob"}),n=await new Promise((r,g)=>{let i=new FileReader;i.onloadend=()=>r(String(i.result??"")),i.onerror=()=>g(i.error),i.readAsDataURL(t)});return{uuid:e,imageBase64:n}}async function X(e,t){let n=o.config(),r=await d("/user/v2/web/login",{type:"smsPwd",method:"login",sourceUrl:m(t),data:{authPhone:e.authPhone,auth:S(e.password,n.aesKey),uuid:e.uuid,imageCode:e.imageCode,systemId:n.systemId}});return p(r)}async function Y(e){await d("/user/v3/web/login",{type:"sms",method:"getVerifyCode",data:{authPhone:e.authPhone,areaCode:e.areaCode??"+86",...e.uuid?{uuid:e.uuid}:{},...e.imageCode?{imageCode:e.imageCode}:{},clientChannel:o.config().clientChannel}})}async function G(e,t){let n=await d("/user/v3/web/login",{type:"sms",method:"login",sourceUrl:m(t),data:{authPhone:e.authPhone,areaCode:e.areaCode??"+86",authCode:e.authCode,sourceChannel:e.sourceChannel??""}});return p(n)}function J(){return o.request({method:"POST",path:"/user/v1/web/login/wechat/qr_url",body:{type:"1"},auth:"none"})}function Z(e){return o.request({path:"/user/v1/web/login/wechat",query:{sessionId:e},auth:"none"})}async function $(e,t){let n=await d("/user/v2/web/login",{type:"wechatQR",method:"login",sourceUrl:m(t),data:{sessionId:e.sessionId,...e.authPhone?{authPhone:e.authPhone}:{},...e.authCode?{authCode:e.authCode}:{},sourceChannel:e.sourceChannel??""}});return p(n)}U();export{j as getImageVerifyCode,y as getPersonalKey,u as getUserInfo,Y as getVerifyCode,J as getWechatQrCode,Z as getWechatQrCodeStatus,G as loginByCode,X as loginByPassword,$ as loginByWechat,D as logout,c as resolveCurrentTeam,W as switchTeam,_ as syncApiKey,s as syncCurrentTeam};
package/package.json CHANGED
@@ -1,6 +1,51 @@
1
1
  {
2
2
  "name": "@linkfox-web/api-user-center",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.0",
4
+ "description": "LinkFox 用户中心接口:登录、刷新、用户信息、切换团队",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://git.ziniao.com/a58-linkfoxagent/linkfox-agent/linkfox-frontend-sdk.git",
8
+ "directory": "packages/api-user-center"
9
+ },
10
+ "type": "module",
11
+ "main": "./dist/index.cjs",
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "import": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ },
20
+ "require": {
21
+ "types": "./dist/index.d.cts",
22
+ "default": "./dist/index.cjs"
23
+ }
24
+ }
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "sideEffects": [
30
+ "./dist/index.js",
31
+ "./dist/index.cjs"
32
+ ],
33
+ "peerDependencies": {
34
+ "@linkfox-web/http": "^0.2.0"
35
+ },
36
+ "dependencies": {
37
+ "crypto-js": "4.2.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/crypto-js": "4.2.2",
41
+ "@linkfox-web/http": "0.2.0"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "license": "MIT",
47
+ "scripts": {
48
+ "build": "tsup",
49
+ "typecheck": "tsc -p tsconfig.json"
50
+ }
6
51
  }