@wovoon/polaris 0.4.3 → 0.5.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/dist/client.d.ts CHANGED
@@ -70,7 +70,9 @@ export declare class PolarisClient {
70
70
  * 重连安全:同一客户端对同一房间再次调用 room(roomId) 会自动断开旧连接——
71
71
  * 做"重连房间"按钮时直接再调一次 room() 即可,无需(但也不妨)先 leave() 旧的。
72
72
  */
73
- room(roomId: string): {
73
+ room(roomId: string, options?: {
74
+ mode?: string;
75
+ }): {
74
76
  send: (data: unknown) => void;
75
77
  leave: () => void;
76
78
  onMessage: (callback: (payload: {
@@ -86,6 +88,13 @@ export declare class PolarisClient {
86
88
  add: (data: T) => Promise<PolarisDocumentView>;
87
89
  set: (id: string, data: T) => Promise<PolarisDocumentView>;
88
90
  remove: (id: string) => Promise<unknown>;
91
+ /** onChange(cb):集合被写入(玩家/云函数/权威房间)时回调 {action,id}——收到后重查。 */
92
+ onChange: (cb: (notice: {
93
+ action: string;
94
+ id: string;
95
+ }) => void) => {
96
+ close: () => void;
97
+ };
89
98
  };
90
99
  }
91
100
  export { parseData };
package/dist/client.js CHANGED
@@ -102,7 +102,7 @@ export class PolarisClient {
102
102
  * 重连安全:同一客户端对同一房间再次调用 room(roomId) 会自动断开旧连接——
103
103
  * 做"重连房间"按钮时直接再调一次 room() 即可,无需(但也不妨)先 leave() 旧的。
104
104
  */
105
- room(roomId) {
105
+ room(roomId, options) {
106
106
  if (!roomId)
107
107
  throw new PolarisError("room(roomId) 需要房间号", "WOVOON_ARGUMENT");
108
108
  this.activeRooms.get(roomId)?.leave();
@@ -121,7 +121,13 @@ export class PolarisClient {
121
121
  };
122
122
  const handle = {
123
123
  send: (data) => {
124
- if (socket && socket.readyState === 1)
124
+ if (!socket || socket.readyState !== 1)
125
+ return;
126
+ if (data instanceof ArrayBuffer)
127
+ socket.send(data);
128
+ else if (data instanceof Uint8Array)
129
+ socket.send(data.buffer);
130
+ else
125
131
  socket.send(JSON.stringify({ type: "msg", data }));
126
132
  },
127
133
  leave: () => {
@@ -150,10 +156,19 @@ export class PolarisClient {
150
156
  const scheme = origin.startsWith("https") ? "wss" : "ws";
151
157
  const roomPath = `/api/cloud/rooms/${data.appId}/${encodeURIComponent(roomId)}`;
152
158
  const sid = /[?&#]wovoon_play_sid=([0-9a-fA-F-]{36})(?:&|$)/.exec(String(location.hash ?? ""))?.[1];
153
- const query = sid ? `${roomPath.includes("?") ? "&" : "?"}wovoon_play_sid=${sid}` : "";
154
- socket = new WebSocket(`${scheme}://${origin.replace(/^https?:\/\//, "")}${roomPath}${query}`);
159
+ const query = [];
160
+ if (sid)
161
+ query.push(`wovoon_play_sid=${sid}`);
162
+ if (options?.mode)
163
+ query.push(`mode=${encodeURIComponent(options.mode)}`);
164
+ socket = new WebSocket(`${scheme}://${origin.replace(/^https?:\/\//, "")}${roomPath}${query.length ? "?" + query.join("&") : ""}`);
165
+ socket.binaryType = "arraybuffer";
155
166
  socket.onopen = () => { this.activeRooms.set(roomId, handle); };
156
167
  socket.onmessage = (event) => {
168
+ if (event.data instanceof ArrayBuffer) {
169
+ emit("message", { binary: true, data: new Uint8Array(event.data) });
170
+ return;
171
+ }
157
172
  let frame = null;
158
173
  try {
159
174
  frame = JSON.parse(String(event.data));
@@ -207,7 +222,58 @@ export class PolarisClient {
207
222
  add: (data) => docUrl().then((url) => client.request("POST", url, { data: JSON.stringify(data ?? {}) })),
208
223
  set: (id, data) => docUrl(id).then((url) => client.request("PUT", url, { data: JSON.stringify(data ?? {}) })),
209
224
  remove: (id) => docUrl(id).then((url) => client.request("DELETE", url)),
225
+ /** onChange(cb):集合被写入(玩家/云函数/权威房间)时回调 {action,id}——收到后重查。 */
226
+ onChange: (cb) => {
227
+ return watchCollections(client, name, cb);
228
+ },
210
229
  };
211
230
  }
212
231
  }
232
+ const collectionsWatch = { listeners: [], socket: null };
233
+ function attachCollectionsWatch(client) {
234
+ if (collectionsWatch.socket || typeof WebSocket === "undefined")
235
+ return;
236
+ client.session().then((data) => {
237
+ const wsBase = String(globalThis.__wovoonRuntimeWsBase ?? "").replace(/\/+$/, "");
238
+ const origin = wsBase || `${location.protocol}//${location.host}`;
239
+ const scheme = origin.startsWith("https") ? "wss" : "ws";
240
+ const sid = /[?&#]wovoon_play_sid=([0-9a-fA-F-]{36})(?:&|$)/.exec(String(location.hash ?? ""))?.[1];
241
+ const query = sid ? `?wovoon_play_sid=${sid}` : "";
242
+ const socket = new WebSocket(`${scheme}://${origin.replace(/^https?:\/\//, "")}/api/cloud/rooms/${data.appId}/__collections${query}`);
243
+ collectionsWatch.socket = socket;
244
+ socket.onmessage = (event) => {
245
+ try {
246
+ const frame = JSON.parse(String(event.data));
247
+ if (frame?.type !== "docs")
248
+ return;
249
+ for (const listener of collectionsWatch.listeners) {
250
+ if (listener.collection === frame.collection && frame.action && frame.id) {
251
+ try {
252
+ listener.cb({ action: frame.action, id: frame.id });
253
+ }
254
+ catch { /* 监听器异常不中断 */ }
255
+ }
256
+ }
257
+ }
258
+ catch { /* 非 JSON 帧忽略 */ }
259
+ };
260
+ socket.onclose = () => {
261
+ collectionsWatch.socket = null;
262
+ if (collectionsWatch.listeners.length)
263
+ setTimeout(() => attachCollectionsWatch(client), 2000);
264
+ };
265
+ }).catch(() => { });
266
+ }
267
+ function watchCollections(client, collection, cb) {
268
+ const listener = { collection, cb };
269
+ collectionsWatch.listeners.push(listener);
270
+ attachCollectionsWatch(client);
271
+ return {
272
+ close: () => {
273
+ const index = collectionsWatch.listeners.indexOf(listener);
274
+ if (index >= 0)
275
+ collectionsWatch.listeners.splice(index, 1);
276
+ },
277
+ };
278
+ }
213
279
  export { parseData };
package/dist/protocol.js CHANGED
@@ -9,7 +9,7 @@ export function isValidCollectionName(name) {
9
9
  return COLLECTION_NAME_PATTERN.test(name);
10
10
  }
11
11
  /** manifest 里单个能力名的完整合法形态(与平台 AssetSecurityScanner.parseContract 的校验一致)。 */
12
- export const CAPABILITY_PATTERN = /^(identity|function|room|collection:[a-z][a-z0-9_]{1,31})$/;
12
+ export const CAPABILITY_PATTERN = /^(identity|function|room|room:competitive|gamelogic|collection:[a-z][a-z0-9_]{1,31})$/;
13
13
  export function isValidCapability(value) {
14
14
  return CAPABILITY_PATTERN.test(value);
15
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wovoon/polaris",
3
- "version": "0.4.3",
3
+ "version": "0.5.0",
4
4
  "description": "wovoon Polaris SDK——wovoon 大后台云能力客户端(身份/数据集合/云函数/房间实时),协议 1",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",