@cx00123/lunetale-game-sdk 0.2.0 → 0.3.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 +17 -1
- package/package.json +1 -1
- package/src/index.d.ts +9 -0
- package/src/index.js +11 -2
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ try {
|
|
|
43
43
|
|
|
44
44
|
```html
|
|
45
45
|
<script type="module">
|
|
46
|
-
import { createGameClient } from 'https://cdn.jsdelivr.net/npm/@cx00123/lunetale-game-sdk@0.
|
|
46
|
+
import { createGameClient } from 'https://cdn.jsdelivr.net/npm/@cx00123/lunetale-game-sdk@0.3.0/src/index.js'
|
|
47
47
|
const game = createGameClient()
|
|
48
48
|
const vip = await game.getVIP()
|
|
49
49
|
document.querySelector('#vip').textContent = vip.isVip ? '会员' : '普通用户'
|
|
@@ -80,6 +80,20 @@ if (character) {
|
|
|
80
80
|
- 角色游戏存档按账号/身份/角色/游戏/存档代际独立保存,兼容程序更新继续使用同一存档;不自动导入旧版账号级存档,不向网页暴露这些隔离键。
|
|
81
81
|
- `chat()` 仍为通用模型调用:由游戏提供 messages,不读写角色长期记忆。选择角色不会偷偷改变 `chat()` 的语义。
|
|
82
82
|
|
|
83
|
+
### 获取当前玩家资料(0.3.0+)
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
const player = await game.getPlayerProfile()
|
|
87
|
+
// 当前 App 登录账号的展示资料,不是角色或聊天身份。
|
|
88
|
+
document.querySelector('#player-name').textContent = player.nickname
|
|
89
|
+
if (player.avatarUrl) document.querySelector('#player-avatar').src = player.avatarUrl
|
|
90
|
+
console.log(player.bio)
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
返回 `{nickname, avatarUrl, bio}`,均为字符串,未设置时为空。昵称来自账号展示名,不会用邮箱兜底。每次调用读取后端最新资料,无 AI 计费;普通游戏也可使用,无需选角色。仍须从 App 或可信登录入口获得有效游戏凭证,不支持匿名读取或传 userId 查询别人。SDK 仅返回三个展示字段,不包含内部账号 ID、UUID、邮箱、手机号、密码、登录 token、聊天身份或记忆。
|
|
94
|
+
|
|
95
|
+
需要同时部署新版后端和新版 Android / iOS App,旧 App 的原生桥不支持 `player` action;SDK 不会绕过旧端白名单,也不把 App JWT 交给网页。玩家资料属于个人信息,游戏应仅用于必要的界面展示,勿写入第三方分析日志。
|
|
96
|
+
|
|
83
97
|
## 2. 平台管理员准备
|
|
84
98
|
|
|
85
99
|
1. 发布支持本 SDK 的后端并完成游戏定向迁移(先核对目标库和备份;角色/剧本模块须已部署);安装新版 Android / iOS App。
|
|
@@ -135,6 +149,7 @@ CDN 的 HTML、图片等静态文件仍可公开访问;这些凭证保护的
|
|
|
135
149
|
| --- | --- |
|
|
136
150
|
| `createGameClient(options?)` | 创建一个顶层页面客户端;调用时同步取走并清除 fragment 授权码 |
|
|
137
151
|
| `ready()` | 完成授权;其它方法也会按需自动授权 |
|
|
152
|
+
| `getPlayerProfile()` | `{nickname,avatarUrl,bio}`,当前账号展示资料,非所选角色 |
|
|
138
153
|
| `getVIP()` | `{isVip,tier,expiresAt,balance,aiEnabled,cost,vipOnly}` |
|
|
139
154
|
| `isVIP()` | `boolean`;有效 VIP、SVIP 都是 true,查询失败会抛异常,不伪装为 false |
|
|
140
155
|
| `chat({requestId?,messages})` | 通用 AI,`{requestId,content,charged,balance}`;不写角色记忆 |
|
|
@@ -193,6 +208,7 @@ CDN 的 HTML、图片等静态文件仍可公开访问;这些凭证保护的
|
|
|
193
208
|
| POST | `/lunetale/game/runtime/exchange` | `Origin` + 一次性 code | `{code}` → `{accessToken,expiresAt,gameId}` |
|
|
194
209
|
| GET | `/lunetale/game/runtime/vip` | `Origin` + `Authorization: Bearer <游戏凭证>` | VIPStatus,可选 credential |
|
|
195
210
|
| POST | `/lunetale/game/runtime/chat` | 同上 | `{requestId,messages}` → ChatResult,可选 credential |
|
|
211
|
+
| GET | `/lunetale/game/runtime/player` | 同上 | `{player:{nickname,avatarUrl,bio}}`,可选 credential;无参数 |
|
|
196
212
|
| GET | `/lunetale/game/runtime/character` | 同上 | `{character: SelectedCharacter|null}`,可选 credential |
|
|
197
213
|
| POST | `/lunetale/game/runtime/character-chat` | 同上 | `{requestId,message,scene?}` → CharacterChatResult,可选 credential |
|
|
198
214
|
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -34,6 +34,13 @@ export interface ChatResult {
|
|
|
34
34
|
/** Balance at the original successful transaction; replay does not refresh it. */
|
|
35
35
|
balance: number
|
|
36
36
|
}
|
|
37
|
+
/** Current account display profile, not the selected role or chat identity. */
|
|
38
|
+
export interface PlayerProfile {
|
|
39
|
+
nickname: string
|
|
40
|
+
/** Empty string when no avatar is configured. */
|
|
41
|
+
avatarUrl: string
|
|
42
|
+
bio: string
|
|
43
|
+
}
|
|
37
44
|
export interface SelectedCharacter {
|
|
38
45
|
id: number
|
|
39
46
|
name: string
|
|
@@ -68,6 +75,8 @@ export class GameSDKError extends Error {
|
|
|
68
75
|
export interface GameClient {
|
|
69
76
|
ready(): Promise<void>
|
|
70
77
|
getVIP(): Promise<VIPStatus>
|
|
78
|
+
/** Fetches current profile; no account IDs, login details or credentials. */
|
|
79
|
+
getPlayerProfile(): Promise<PlayerProfile>
|
|
71
80
|
/** Both active VIP and SVIP count as true. */
|
|
72
81
|
isVIP(): Promise<boolean>
|
|
73
82
|
chat(input: ChatInput): Promise<ChatResult>
|
package/src/index.js
CHANGED
|
@@ -117,12 +117,12 @@ export function createGameClient(options = {}) {
|
|
|
117
117
|
const timer = setTimeout(() => controller.abort(), timeout)
|
|
118
118
|
try {
|
|
119
119
|
const response = await fetch(`${base.href.replace(/\/$/, '')}/lunetale/game/runtime/${action}`, {
|
|
120
|
-
method: ['vip', 'character'].includes(action) ? 'GET' : 'POST',
|
|
120
|
+
method: ['vip', 'character', 'player'].includes(action) ? 'GET' : 'POST',
|
|
121
121
|
headers: {
|
|
122
122
|
'Content-Type': 'application/json',
|
|
123
123
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
124
124
|
},
|
|
125
|
-
body: ['vip', 'character'].includes(action) ? undefined : JSON.stringify(payload),
|
|
125
|
+
body: ['vip', 'character', 'player'].includes(action) ? undefined : JSON.stringify(payload),
|
|
126
126
|
signal: controller.signal,
|
|
127
127
|
credentials: 'omit',
|
|
128
128
|
cache: 'no-store',
|
|
@@ -199,6 +199,15 @@ export function createGameClient(options = {}) {
|
|
|
199
199
|
},
|
|
200
200
|
getVIP() { return request('vip') },
|
|
201
201
|
async isVIP() { return (await request('vip')).isVip === true },
|
|
202
|
+
async getPlayerProfile() {
|
|
203
|
+
const { player } = await request('player')
|
|
204
|
+
if (!player || typeof player !== 'object' || Array.isArray(player) ||
|
|
205
|
+
['nickname', 'avatarUrl', 'bio'].some(key => typeof player[key] !== 'string')) {
|
|
206
|
+
throw new GameSDKError('PROTOCOL', '玩家资料响应格式错误')
|
|
207
|
+
}
|
|
208
|
+
// Explicit whitelist: future server fields must not leak account data.
|
|
209
|
+
return { nickname: player.nickname, avatarUrl: player.avatarUrl, bio: player.bio }
|
|
210
|
+
},
|
|
202
211
|
async getSelectedCharacter() {
|
|
203
212
|
const result = await request('character')
|
|
204
213
|
if (!Object.hasOwn(result, 'character') || (result.character !== null &&
|