@nanotoolkit/game-sdk 0.1.7 → 0.1.8

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,6 +1,6 @@
1
1
  import { parseWireJSON, stringifyWireJSON } from './WireJSON.js';
2
2
 
3
- export const SDK_VERSION = '0.1.7';
3
+ export const SDK_VERSION = '0.1.8';
4
4
 
5
5
  const REQUEST_TIMEOUT_MS = 10000;
6
6
 
@@ -34,6 +34,7 @@ export class SdkError extends Error {
34
34
  super(message);
35
35
  this.name = 'SdkError';
36
36
  this.code = code;
37
+ this.errorMessage = message;
37
38
  this.retryable = RETRYABLE.has(code);
38
39
  }
39
40
  }
@@ -286,7 +287,9 @@ function noteIssue(issue, publish) {
286
287
  )
287
288
  return false;
288
289
  touch(issues, issue.id, { key, rank, issue });
289
- if (issue.result == null && issue.display?.rulesId && lastEntry?.rulesId !== issue.display.rulesId)
290
+ if (publish && issue.result == null &&
291
+ (lastEntry?.issue?.id !== issue.id ||
292
+ (issue.display?.rulesId && lastEntry?.rulesId !== issue.display.rulesId)))
290
293
  refreshEntry();
291
294
  if (issue.ruleType === 'crash' && issue.flowType === 'timed') {
292
295
  const old = [...issues.values()]
@@ -430,6 +433,7 @@ function ensureStateListeners() {
430
433
  issue: lastEntry.issue,
431
434
  lastOpenedIssue: lastEntry.lastOpenedIssue,
432
435
  });
436
+ refreshEntry();
433
437
  });
434
438
  subscribe('game:snapshot', (msg) => {
435
439
  if (inRoom(msg.snapshot)) acceptEntry(msg.snapshot, true);
@@ -524,17 +528,28 @@ function reconcileEntryState() {
524
528
  lastEntry.bets = [...latestBets.values()];
525
529
  }
526
530
  let refreshingEntry = null;
531
+ let refreshAgain = false;
527
532
  function refreshEntry() {
528
- if (!lastEntry || refreshingEntry) return refreshingEntry;
533
+ if (!lastEntry) return;
534
+ if (refreshingEntry) {
535
+ refreshAgain = true;
536
+ return refreshingEntry;
537
+ }
529
538
  const room = lastEntry.gameRoomId;
530
- refreshingEntry = enterGame({ gameRoomId: room })
539
+ const pending = enterGame({ gameRoomId: room });
540
+ const generation = entrySeq;
541
+ refreshingEntry = pending
531
542
  .then((entry) => {
532
- if (entry.gameRoomId === lastEntry?.gameRoomId) emitLocal('snapshot', entry);
543
+ if (generation !== entrySeq || entry.gameRoomId !== lastEntry?.gameRoomId) return;
544
+ emitLocal('snapshot', entry);
533
545
  return Promise.all([getGameBets({ gameRoomId: entry.gameRoomId }), getGameRoomFeed()]);
534
546
  })
535
547
  .catch(() => {})
536
548
  .finally(() => {
537
549
  refreshingEntry = null;
550
+ const repeat = refreshAgain && generation === entrySeq && room === lastEntry?.gameRoomId;
551
+ refreshAgain = false;
552
+ if (repeat) refreshEntry();
538
553
  });
539
554
  return refreshingEntry;
540
555
  }
@@ -721,8 +736,10 @@ export const storage = {
721
736
 
722
737
  function toSdkError(error) {
723
738
  const code = typeof error?.code === 'string' ? error.code : ErrorCode.SERVER;
724
- const message = typeof error?.message === 'string' && error.message.length > 0 ? error.message : code;
739
+ const text = error?.errorMessage ?? error?.message;
740
+ const message = typeof text === 'string' && text.length > 0 ? text : code;
725
741
  const result = new SdkError(code, message);
742
+ if (Number.isInteger(error?.serverCode) && error.serverCode < 0) result.serverCode = error.serverCode;
726
743
  if (error?.details) result.details = error.details;
727
744
  return result;
728
745
  }
package/index.d.ts CHANGED
@@ -28,6 +28,8 @@ export type SdkErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode] | string;
28
28
  export class SdkError extends Error {
29
29
  readonly name: 'SdkError';
30
30
  readonly code: SdkErrorCode;
31
+ readonly serverCode?: number;
32
+ readonly errorMessage: string;
31
33
 
32
34
  readonly retryable: boolean;
33
35
 
@@ -116,6 +118,8 @@ export interface GameEntry {
116
118
  showSeconds?: number;
117
119
  intervalSeconds?: number;
118
120
  alignedCycle?: boolean;
121
+ cycleSeconds?: number;
122
+ readySeconds?: number;
119
123
  allowAdditionalBatches?: boolean;
120
124
  limitsZeroMeansUnlimited?: boolean;
121
125
  [key: string]: unknown;
@@ -263,7 +267,7 @@ export function actGameBet(args: {
263
267
  params?: Record<string, any>;
264
268
  }): Promise<IssueInfo>;
265
269
  export function getGameIssue(args?: { issueId?: WireId }): Promise<IssueInfo | null>;
266
- export function getGameIssues(args?: { earliestId?: WireId; pageSize?: number }): Promise<IssueInfo[]>;
270
+ export function getGameIssues(args?: { gameRoomId?: number; earliestId?: WireId; pageSize?: number }): Promise<IssueInfo[]>;
267
271
  export function getGameBet(args: { betId: WireId; gameRoomId?: number }): Promise<GameBet>;
268
272
 
269
273
  export function getGameBets(args?: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanotoolkit/game-sdk",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",