@goplus123/core-api 1.1.2 → 1.1.3
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 +235 -8
- package/dist/index.cjs +195 -110
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +86 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,6 +11,17 @@
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [快速开始](#快速开始)
|
|
17
|
+
- [调用链路概览](#调用链路概览)
|
|
18
|
+
- [Transport 选择规则](#transport-选择规则)
|
|
19
|
+
- [WS 推送与事件](#ws-推送与事件)
|
|
20
|
+
- [错误处理](#错误处理)
|
|
21
|
+
- [API 参考(对外导出)](#api-参考对外导出)
|
|
22
|
+
- [spec 驱动的 Service 列表](#spec-驱动的-service-列表)
|
|
23
|
+
- [开发指南:如何补充 spec 路由](#开发指南如何补充-spec-路由)
|
|
24
|
+
|
|
14
25
|
## 设计方案与思路
|
|
15
26
|
|
|
16
27
|
### 这是什么
|
|
@@ -40,7 +51,7 @@
|
|
|
40
51
|
### 关键设计原则(对后续重构/AI 重设计很重要)
|
|
41
52
|
|
|
42
53
|
- 单一装配点:只允许通过 `initSDK()` 构建/覆盖全局状态,避免“到处 new client”导致的状态分裂
|
|
43
|
-
-
|
|
54
|
+
- 显式路由表:`requestApi` 优先按 spec 路由;迁移期允许显式 `transport: 'ws'` 走 raw WS 兜底
|
|
44
55
|
- transport 无关的调用链:上层只关心 EndpointSpec 与请求参数;transport 细节由 UnifiedApiClient 分发
|
|
45
56
|
- 横切能力可插拔:拦截器链(interceptors)是统一入口,避免散落在各 transport 内部
|
|
46
57
|
- 向后兼容优先:spec 未命中时允许落到 legacy serviceInstances 或 raw WS 兜底(便于迁移期稳定)
|
|
@@ -109,6 +120,36 @@ spec 的职责是提供“可路由的接口清单”,而不是提供具体实
|
|
|
109
120
|
|
|
110
121
|
拦截器的设计意图是把“与业务接口无关的能力”统一实现一次,三种 transport 复用同一条链路。
|
|
111
122
|
|
|
123
|
+
### 内置拦截器如何启用
|
|
124
|
+
|
|
125
|
+
SDK 默认只开放“配置式启用”内置拦截器(业务侧目前不需要也不支持直接注入自定义 `ApiInterceptor`)。
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { initSDK } from '@goplus123/core-api'
|
|
129
|
+
|
|
130
|
+
initSDK({
|
|
131
|
+
http: { baseUrl: 'https://api.example.com' },
|
|
132
|
+
grpc: { baseUrl: 'https://grpc.example.com' },
|
|
133
|
+
ws: { url: 'wss://ws.example.com' },
|
|
134
|
+
headerConfig: {
|
|
135
|
+
version: '1',
|
|
136
|
+
platformId: 'web',
|
|
137
|
+
isReload: false,
|
|
138
|
+
deviceType: 'web',
|
|
139
|
+
childPlatformId: 'web',
|
|
140
|
+
},
|
|
141
|
+
auth: {
|
|
142
|
+
getToken: () => localStorage.getItem('token'),
|
|
143
|
+
},
|
|
144
|
+
logger: console,
|
|
145
|
+
})
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
启用效果:
|
|
149
|
+
|
|
150
|
+
- HTTP/gRPC:通过拦截器把 token 注入到请求头
|
|
151
|
+
- WS:token 由 `WsClient` 在连接 URL/query 或消息体中携带(受浏览器限制无法设置自定义 header)
|
|
152
|
+
|
|
112
153
|
### token/header 注入策略
|
|
113
154
|
|
|
114
155
|
`initSDK({ auth })` 提供的 `getToken/getHeaders` 会被注入到:
|
|
@@ -132,6 +173,32 @@ spec 的职责是提供“可路由的接口清单”,而不是提供具体实
|
|
|
132
173
|
- 让上层(UI/日志/监控)用一致结构处理错误,不必分辨来自 HTTP/WS/gRPC
|
|
133
174
|
- 把错误分为三类:`biz / transport / unknown`,用于更合理的告警与重试策略
|
|
134
175
|
|
|
176
|
+
### 业务侧案例:统一判断 token 失效(401/403)
|
|
177
|
+
|
|
178
|
+
业务侧推荐用 `apiError.use(...)` 或 `initSDK({ onApiError })` 统一处理鉴权失效,而不是在每个接口单独 try/catch。
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { apiError } from '@goplus123/core-api'
|
|
182
|
+
|
|
183
|
+
apiError.use((error, _ctx, next) => {
|
|
184
|
+
const isHttpAuthFailed =
|
|
185
|
+
error.transport === 'http' && (error.status === 401 || error.status === 403)
|
|
186
|
+
|
|
187
|
+
const isGrpcAuthFailed =
|
|
188
|
+
error.transport === 'grpc' &&
|
|
189
|
+
(error.code === 7 || error.code === 16)
|
|
190
|
+
|
|
191
|
+
const isWsAuthFailed =
|
|
192
|
+
error.transport === 'ws' && (error.status === 401 || error.status === 403 || error.code === 403)
|
|
193
|
+
|
|
194
|
+
if (isHttpAuthFailed || isGrpcAuthFailed || isWsAuthFailed) {
|
|
195
|
+
// 例如:清 token、跳转登录、或触发 refresh token 流程
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return next()
|
|
199
|
+
})
|
|
200
|
+
```
|
|
201
|
+
|
|
135
202
|
---
|
|
136
203
|
|
|
137
204
|
## 依赖与技术方案清单
|
|
@@ -255,6 +322,7 @@ const sdk = initSDK({
|
|
|
255
322
|
- `sdk.api`:底层 `RequestApi`(包含 `http/ws/grpc` 三个 client)
|
|
256
323
|
- `sdk.client`:统一路由分发的 `UnifiedApiClient`
|
|
257
324
|
- `sdk.rpc`:对外暴露的 `WsRpcClient`(便于调试 / 订阅)
|
|
325
|
+
- `sdk.wsNotify`:底层 `WsNotifyCenter`(直接订阅 WS 推送事件)
|
|
258
326
|
- `sdk.cms / sdk.admin / sdk.platform`:类型安全的 service client(由 spec 生成)
|
|
259
327
|
- `sdk.apiError / sdk.notify`:全局错误与通知中心(同名导出也可直接使用)
|
|
260
328
|
|
|
@@ -709,6 +777,41 @@ await requestApi({
|
|
|
709
777
|
|
|
710
778
|
## WS 推送与事件
|
|
711
779
|
|
|
780
|
+
`notify(type)` 返回一个通知通道(channel),用于承接两类事件:
|
|
781
|
+
|
|
782
|
+
- 服务端 WS 推送:初始化了 `ws` 时,会自动挂载到 `ws.notify`,把推送分发到同名 channel
|
|
783
|
+
- 本地事件分发:可用 `emit` 主动触发(不发给服务端),用于调试/桥接
|
|
784
|
+
|
|
785
|
+
channel 支持的方法:
|
|
786
|
+
|
|
787
|
+
- `use(middleware)`:注册中间件(可在内部决定是否继续传递)
|
|
788
|
+
- `subscribe(listener)`:注册订阅者(等价于一个简单的中间件包装)
|
|
789
|
+
- `emit(payload)`:主动触发一次本地分发
|
|
790
|
+
- `destroy()`:销毁该 type 的 channel 与所有监听
|
|
791
|
+
|
|
792
|
+
### 直接订阅 wsNotify
|
|
793
|
+
|
|
794
|
+
如果你想绕开 `notify(type)` 的 channel/middleware 机制,直接订阅 WS 推送事件,可以使用 `sdk.wsNotify`:
|
|
795
|
+
|
|
796
|
+
```ts
|
|
797
|
+
const sdk = initSDK({
|
|
798
|
+
ws: { url: 'wss://example.com/websocket' },
|
|
799
|
+
headerConfig: {
|
|
800
|
+
version: '1.0.0',
|
|
801
|
+
platformId: '0',
|
|
802
|
+
isReload: false,
|
|
803
|
+
deviceType: 1,
|
|
804
|
+
childPlatformId: '0',
|
|
805
|
+
},
|
|
806
|
+
} as any)
|
|
807
|
+
|
|
808
|
+
const off = sdk.wsNotify?.on<{ gameId: string }>('notifyGameInfo', (payload) => {
|
|
809
|
+
console.log('game info:', payload)
|
|
810
|
+
})
|
|
811
|
+
|
|
812
|
+
// off?.()
|
|
813
|
+
```
|
|
814
|
+
|
|
712
815
|
### 订阅 WS 推送
|
|
713
816
|
|
|
714
817
|
`notify(type)` 会创建一个 channel,并在初始化了 `ws` 时自动挂载到 `ws.notify`。
|
|
@@ -721,6 +824,36 @@ const off = notify<{ gameId: string }>('notifyGameInfo').subscribe((payload) =>
|
|
|
721
824
|
// off()
|
|
722
825
|
```
|
|
723
826
|
|
|
827
|
+
### notify 中间件(use)
|
|
828
|
+
|
|
829
|
+
`use` 适合做过滤、埋点、转换、桥接等逻辑;签名为 `(payload, ctx, next) => any`,调用 `next()` 才会继续向后传递。
|
|
830
|
+
|
|
831
|
+
```ts
|
|
832
|
+
import { notify } from '@goplus123/core-api'
|
|
833
|
+
|
|
834
|
+
notify<{ level: 'info' | 'error'; message: string }>('app:log').use((payload, _ctx, next) => {
|
|
835
|
+
if (payload.level !== 'error') return
|
|
836
|
+
console.log('[app:log][error]', payload.message)
|
|
837
|
+
return next()
|
|
838
|
+
})
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
### 主动触发 notify(emit)
|
|
842
|
+
|
|
843
|
+
`notify(type).emit(payload)` 可以主动触发一次本地事件分发(不会发给服务端),常用于调试/本地桥接复用同一套订阅机制。
|
|
844
|
+
|
|
845
|
+
```ts
|
|
846
|
+
import { notify } from '@goplus123/core-api'
|
|
847
|
+
|
|
848
|
+
const off = notify<{ type: number }>('wsStatus').subscribe((payload) => {
|
|
849
|
+
console.log('wsStatus payload:', payload.type)
|
|
850
|
+
})
|
|
851
|
+
|
|
852
|
+
notify('wsStatus').emit({ type: 2 })
|
|
853
|
+
|
|
854
|
+
off()
|
|
855
|
+
```
|
|
856
|
+
|
|
724
857
|
### 监听 WS 连接状态
|
|
725
858
|
|
|
726
859
|
SDK 内置了 `ws:status` 通道(初始化时自动绑定到 WS 事件):
|
|
@@ -779,6 +912,9 @@ apiError.use((error, ctx, next) => {
|
|
|
779
912
|
### requestApi(args) / callApi(args)
|
|
780
913
|
|
|
781
914
|
- 作用:统一调用入口(spec 驱动路由;若 spec 未命中,会尝试 legacy serviceInstances,再兜底走 raw WS)
|
|
915
|
+
- 别名:
|
|
916
|
+
- `callApi`:`requestApi` 的同名别名
|
|
917
|
+
- `requestApiSpec`:`requestApi` 的同名别名(历史兼容)
|
|
782
918
|
- 入参:
|
|
783
919
|
- `service: string`
|
|
784
920
|
- `functionName: string`
|
|
@@ -788,16 +924,33 @@ apiError.use((error, ctx, next) => {
|
|
|
788
924
|
- `callOptions?: CallOptions`
|
|
789
925
|
- `meta?: Record<string, any>`
|
|
790
926
|
|
|
927
|
+
### getWsSnapshot()
|
|
928
|
+
|
|
929
|
+
- 作用:同步获取 WS 连接状态快照(不依赖订阅)
|
|
930
|
+
- 返回:`{ readyState?: number; isConnected: boolean; status?: WsStatusPayload }`
|
|
931
|
+
|
|
791
932
|
### notify(type)
|
|
792
933
|
|
|
793
|
-
-
|
|
794
|
-
-
|
|
934
|
+
- 作用:获取通知通道(channel)
|
|
935
|
+
- 方法:
|
|
936
|
+
- `use(middleware)`:注册中间件;返回 `off()` 用于注销当前中间件
|
|
937
|
+
- `subscribe(listener)`:注册订阅者;返回 `off()` 用于注销当前订阅
|
|
938
|
+
- `emit(payload)`:主动触发一次本地分发(不发给服务端)
|
|
939
|
+
- `destroy()`:销毁该 type 的 channel 与所有监听
|
|
940
|
+
- 注意:未初始化时调用 `emit` 为 no-op(会 warn);`use/subscribe` 可提前注册,初始化后会自动挂载到 WS 推送
|
|
795
941
|
|
|
796
942
|
### apiError
|
|
797
943
|
|
|
798
944
|
- `apiError.use(middleware)`:注册错误中间件
|
|
799
945
|
- `apiError.emit(error, source?)`:手动注入一个归一化后的 `ApiError`
|
|
800
946
|
|
|
947
|
+
### 类型导出(常用)
|
|
948
|
+
|
|
949
|
+
- `WsStatusState` / `WsStatusPayload`:WS 状态类型(配合 `ws:status` 与 `getWsSnapshot`)
|
|
950
|
+
- `ApiErrorMiddleware`:`apiError.use(...)` 的中间件签名
|
|
951
|
+
- `NotifyMiddleware`:`notify(type).use(...)` 的中间件签名
|
|
952
|
+
- `KeyValueStorage`:unikey 存储抽象
|
|
953
|
+
|
|
801
954
|
### fetchGuid()
|
|
802
955
|
|
|
803
956
|
- 作用:生成/读取一个稳定的设备唯一标识(unikey),用于跨请求/跨连接的设备识别
|
|
@@ -866,17 +1019,34 @@ setUniqueKeyStorage(appStorage)
|
|
|
866
1019
|
|
|
867
1020
|
spec 定义入口:[`spec/index.ts`](./src/spec/index.ts)
|
|
868
1021
|
|
|
1022
|
+
说明:
|
|
1023
|
+
|
|
1024
|
+
- spec 影响的是 `requestApi` 的路由表(能让 `requestApi({ service, functionName })` 正确选 transport)
|
|
1025
|
+
- 当前 `initSDK()` 默认只创建了 `sdk.cms / sdk.admin / sdk.platform` 三个“类型安全的 service client”
|
|
1026
|
+
- 其它 spec service 仍然可以通过 `requestApi` 调用(必要时再扩展 sdk 返回值即可)
|
|
1027
|
+
|
|
869
1028
|
按 service 拆分的落点文件:
|
|
870
1029
|
|
|
871
|
-
- cms:[`spec/cms.ts`](./src/spec/cms.ts)
|
|
872
1030
|
- admin:[`spec/admin.ts`](./src/spec/admin.ts)
|
|
1031
|
+
- auth:[`spec/auth.ts`](./src/spec/auth.ts)
|
|
1032
|
+
- cms:[`spec/cms.ts`](./src/spec/cms.ts)
|
|
1033
|
+
- packet:[`spec/packet.ts`](./src/spec/packet.ts)
|
|
1034
|
+
- payment:[`spec/payment.ts`](./src/spec/payment.ts)
|
|
1035
|
+
- player:[`spec/player.ts`](./src/spec/player.ts)
|
|
873
1036
|
- platform:[`spec/platform.ts`](./src/spec/platform.ts)
|
|
1037
|
+
- promotion:[`spec/promotion.ts`](./src/spec/promotion.ts)
|
|
1038
|
+
- provider:[`spec/provider.ts`](./src/spec/provider.ts)
|
|
1039
|
+
- recommend:[`spec/recommend.ts`](./src/spec/recommend.ts)
|
|
1040
|
+
- riskcontrol:[`spec/riskcontrol.ts`](./src/spec/riskcontrol.ts)
|
|
1041
|
+
- userEngagement:[`spec/userEngagement.ts`](./src/spec/userEngagement.ts)
|
|
874
1042
|
|
|
875
|
-
### cms(gRPC
|
|
1043
|
+
### cms(gRPC 为主,部分接口可多协议;支持 sdk.cms)
|
|
876
1044
|
|
|
877
1045
|
- `getPageResource`
|
|
878
1046
|
- `getPageGameList`(multi:grpc + ws)
|
|
1047
|
+
- `getPageGameListV2`(multi:grpc + ws)
|
|
879
1048
|
- `getJackpotResources`
|
|
1049
|
+
- `getJackpotConfig`
|
|
880
1050
|
- `readPopup`
|
|
881
1051
|
- `readEventPopup`
|
|
882
1052
|
- `getAmbassadorConfig`
|
|
@@ -887,7 +1057,7 @@ spec 定义入口:[`spec/index.ts`](./src/spec/index.ts)
|
|
|
887
1057
|
- `getSportTodayMatch`
|
|
888
1058
|
- `getGameSuggestions`
|
|
889
1059
|
|
|
890
|
-
### admin(gRPC)
|
|
1060
|
+
### admin(gRPC;支持 sdk.admin)
|
|
891
1061
|
|
|
892
1062
|
- `signIn`
|
|
893
1063
|
- `getAdminProfileByJwt`
|
|
@@ -902,10 +1072,65 @@ spec 定义入口:[`spec/index.ts`](./src/spec/index.ts)
|
|
|
902
1072
|
- `updateMarketingDepartmentConfig`
|
|
903
1073
|
- `deleteMarketingDepartmentConfig`
|
|
904
1074
|
|
|
905
|
-
### platform(WS)
|
|
1075
|
+
### platform(WS;支持 sdk.platform)
|
|
906
1076
|
|
|
907
1077
|
- `getConfig`
|
|
908
1078
|
|
|
1079
|
+
### riskcontrol(gRPC)
|
|
1080
|
+
|
|
1081
|
+
- `getPlayerDepositLimitStateOverview`
|
|
1082
|
+
- `updatePlayerDepositLimitSwitch`
|
|
1083
|
+
- `updatePlayerPeriodDepositLimit`
|
|
1084
|
+
|
|
1085
|
+
### userEngagement(gRPC)
|
|
1086
|
+
|
|
1087
|
+
- `updatePWASubscriptionStatus`
|
|
1088
|
+
|
|
1089
|
+
### provider(gRPC)
|
|
1090
|
+
|
|
1091
|
+
- `getRecentPlayedGames`
|
|
1092
|
+
- `getLoginURL`
|
|
1093
|
+
|
|
1094
|
+
### recommend(gRPC)
|
|
1095
|
+
|
|
1096
|
+
- `saveSearchHistory`
|
|
1097
|
+
- `getSearchHistories`
|
|
1098
|
+
- `deleteSearchHistory`
|
|
1099
|
+
- `searchGames`
|
|
1100
|
+
|
|
1101
|
+
### packet(gRPC)
|
|
1102
|
+
|
|
1103
|
+
- `assignPacket`
|
|
1104
|
+
- `getServerTime`
|
|
1105
|
+
- `getPacketsInfo`
|
|
1106
|
+
- `grabFreeSpin`
|
|
1107
|
+
- `getEventGrabProgress`
|
|
1108
|
+
- `verifyPlayerPacket`
|
|
1109
|
+
- `verifyPlayerFreeSpin`
|
|
1110
|
+
- `playerClaimAllRewardsLite`
|
|
1111
|
+
|
|
1112
|
+
### payment(gRPC)
|
|
1113
|
+
|
|
1114
|
+
- `getCredit`
|
|
1115
|
+
- `getBankTypes`
|
|
1116
|
+
- `getBindBankCards`
|
|
1117
|
+
- `getAvailableDepositMethods`
|
|
1118
|
+
- `updatePaymentInfo`
|
|
1119
|
+
- `verifyUnionBank`
|
|
1120
|
+
- `getUnionBankTopUp`
|
|
1121
|
+
- `getPlayerDisbursements`
|
|
1122
|
+
- `claimPlayerDisbursement`
|
|
1123
|
+
- `getMud`
|
|
1124
|
+
- `getPlayerMudTransactions`
|
|
1125
|
+
- `getMudTransactionHistory`
|
|
1126
|
+
- `getCreditChangeNotifyMsg`
|
|
1127
|
+
- `removeCreditChangeNotifyMsg`
|
|
1128
|
+
- `getPlatformPlayerFreeSpinListing`
|
|
1129
|
+
|
|
1130
|
+
### auth / player / promotion
|
|
1131
|
+
|
|
1132
|
+
- 这三个 service 的 spec 方法较多,建议直接查看对应 spec 文件的 `export const <service>Endpoints` 键名。
|
|
1133
|
+
|
|
909
1134
|
---
|
|
910
1135
|
|
|
911
1136
|
## 为接口新增/扩展 transport(spec 写法)
|
|
@@ -918,7 +1143,9 @@ spec 的职责是给 `requestApi` 提供“路由表”:
|
|
|
918
1143
|
|
|
919
1144
|
- runtime 上它会被加载进 `apiMap`,并在 `initSDK()` 时构建 registry(见 [`rebuildEndpointRegistry`](./src/routing/router.ts#L84-L132))
|
|
920
1145
|
- 调用方可以通过 `sdk.<service>.<method>()` 或 `requestApi({ service, functionName })` 走到对应 transport
|
|
921
|
-
- 当调用方显式指定 `transport`
|
|
1146
|
+
- 当调用方显式指定 `transport` 时:
|
|
1147
|
+
- `grpc/http`:若 spec 命中但没有对应变体,会在路由选择阶段同步抛错
|
|
1148
|
+
- `ws`:若 spec 命中但没有对应变体,会兜底走 raw WS(需要已初始化 ws)
|
|
922
1149
|
|
|
923
1150
|
### 1) 选择落点文件
|
|
924
1151
|
|