@nanotoolkit/game-sdk 0.1.9 → 0.1.11

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.
@@ -1,7 +1,7 @@
1
1
  import { parseWireJSON, stringifyWireJSON } from './WireJSON.js';
2
2
  import { GameState } from './GameState.js';
3
3
 
4
- export const SDK_VERSION = '0.1.9';
4
+ export const SDK_VERSION = '0.1.11';
5
5
 
6
6
  const REQUEST_TIMEOUT_MS = 10000;
7
7
 
@@ -123,6 +123,7 @@ export function ready(bundleId, onInit) {
123
123
  });
124
124
  subscribe('game:ping', (msg) => send({ type: 'game:pong', echo: msg.ts }));
125
125
  ensureBackListener();
126
+ ensureExitListener();
126
127
  ensureStateListeners();
127
128
  subscribe('game:init', (msg) => {
128
129
  if (initState) return;
@@ -132,7 +133,7 @@ export function ready(bundleId, onInit) {
132
133
  settleInit(publicInit(msg));
133
134
  for (const run of initWaiters.splice(0)) run();
134
135
  });
135
- send({ type: 'game:ready', game: bundleId, sdk: SDK_VERSION });
136
+ send({ type: 'game:ready', game: bundleId, sdk: SDK_VERSION, exitLifecycle: 1 });
136
137
  }
137
138
  if (typeof onInit === 'function') initPromise.then(onInit);
138
139
  return initPromise;
@@ -155,6 +156,22 @@ export function serverNow() {
155
156
  }
156
157
 
157
158
  const backHandlers = new Set();
159
+ const exitHandlers = new Set();
160
+
161
+ function ensureExitListener() {
162
+ if (ensureExitListener.done) return;
163
+ ensureExitListener.done = true;
164
+ let lastSequence = null;
165
+ subscribe('game:will_exit', (msg) => {
166
+ if (msg.seq !== lastSequence) {
167
+ lastSequence = msg.seq;
168
+ for (const handler of [...exitHandlers]) {
169
+ try { handler(); } catch (error) { console.error('[game-sdk] handler error', error); }
170
+ }
171
+ }
172
+ send({ type: 'game:exit_ready', seq: msg.seq });
173
+ });
174
+ }
158
175
 
159
176
  function ensureBackListener() {
160
177
  if (ensureBackListener.done) return;
@@ -205,6 +222,11 @@ function emitLocal(event, payload) {
205
222
 
206
223
  export function on(event, handler) {
207
224
  if (typeof handler !== 'function') throw new TypeError('invalid handler');
225
+ if (event === 'willExit') {
226
+ ensureExitListener();
227
+ exitHandlers.add(handler);
228
+ return () => exitHandlers.delete(handler);
229
+ }
208
230
  if (event === 'back') {
209
231
  ensureBackListener();
210
232
  backHandlers.add(handler);
@@ -225,7 +247,7 @@ export function on(event, handler) {
225
247
  const spec = EVENTS[event];
226
248
  if (!spec)
227
249
  throw new TypeError(
228
- `invalid event: ${event} / ${[...Object.keys(EVENTS), 'back', ...Object.keys(localHandlers)].join(
250
+ `invalid event: ${event} / ${[...Object.keys(EVENTS), 'back', 'willExit', ...Object.keys(localHandlers)].join(
229
251
  ' / ',
230
252
  )}`,
231
253
  );
@@ -409,6 +431,7 @@ function ensureStateListeners() {
409
431
  const directory = roomDirectory ?? lastEntry;
410
432
  if (!directory || msg.rooms?.gameId !== directory.gameId || !Array.isArray(msg.rooms.rooms)) return;
411
433
  const known = new Map((directory.rooms ?? []).map((room) => [room.id, room]));
434
+ const updates = new Map(msg.rooms.rooms.map((room) => [room.id, room]));
412
435
  if (msg.rooms.rooms.some((room) => !known.has(room.id))) {
413
436
  getGameRooms().catch(() => {});
414
437
  return;
@@ -417,9 +440,10 @@ function ensureStateListeners() {
417
440
  ...directory,
418
441
  ...msg.rooms,
419
442
  topic: roomDirectory?.topic ?? lastEntry?.roomsTopic ?? 'game:' + directory.gameId,
420
- rooms: msg.rooms.rooms.map((room) => ({
421
- ...known.get(room.id),
443
+ rooms: (directory.rooms ?? []).filter((room) => updates.has(room.id)).map((room) => ({
422
444
  ...room,
445
+ onlineCount: updates.get(room.id).onlineCount,
446
+ targetTime: updates.get(room.id).targetTime,
423
447
  })),
424
448
  };
425
449
  if (lastEntry?.gameId === roomDirectory.gameId) lastEntry.rooms = roomDirectory.rooms;
package/index.d.ts CHANGED
@@ -83,6 +83,7 @@ export interface GameRoom {
83
83
  id: number;
84
84
  gameId: number;
85
85
  roomName: string;
86
+ roomIcon: string | null;
86
87
  position: number;
87
88
  onlineCount: number;
88
89
  targetTime: number;
@@ -294,6 +295,7 @@ export function watchIssues(): () => void;
294
295
  export interface EventPayloads {
295
296
  pause: undefined;
296
297
  resume: undefined;
298
+ willExit: undefined;
297
299
  theme: { dark: boolean };
298
300
  lang: { lang: string };
299
301
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanotoolkit/game-sdk",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",