@usions/sdk 2.20.2 → 2.22.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/package.json +1 -1
- package/src/browser.js +716 -163
- package/src/modules/backend-channel.js +41 -8
- package/src/modules/core.js +59 -8
- package/src/modules/errors.js +47 -4
- package/src/modules/game-core.js +27 -17
- package/src/modules/game-methods.js +98 -29
- package/src/modules/game-reliability.js +278 -0
- package/src/modules/game-socket.js +24 -7
- package/src/modules/matchmaking.js +53 -11
- package/src/modules/misc.js +7 -2
- package/src/modules/wallet.js +12 -5
- package/types/index.d.ts +123 -6
package/types/index.d.ts
CHANGED
|
@@ -97,7 +97,8 @@ export interface FileStorageModule {
|
|
|
97
97
|
// ─── Wallet ──────────────────────────────────────────────────────
|
|
98
98
|
|
|
99
99
|
export interface WalletModule {
|
|
100
|
-
|
|
100
|
+
/** Cached after the first call; pass `{ fresh: true }` to re-query the host. */
|
|
101
|
+
getBalance(opts?: { fresh?: boolean }): Promise<number>;
|
|
101
102
|
hasCredits(amount: number): Promise<boolean>;
|
|
102
103
|
requestPayment(amount: number, reason: string, data?: PaymentOptions): Promise<PaymentResponse>;
|
|
103
104
|
onBalanceChange(callback: (balance: number) => void): UnsubscribeFn;
|
|
@@ -185,6 +186,9 @@ export interface PlayerJoinedData {
|
|
|
185
186
|
export interface PlayerLeftData {
|
|
186
187
|
room_id: string;
|
|
187
188
|
player_id: string;
|
|
189
|
+
/** Authoritative roster (mirrors PlayerJoinedData) — reconcile membership from either event. */
|
|
190
|
+
player_ids: string[];
|
|
191
|
+
reason?: string;
|
|
188
192
|
}
|
|
189
193
|
|
|
190
194
|
export interface StateUpdateData {
|
|
@@ -274,6 +278,60 @@ export interface GameInviteResult {
|
|
|
274
278
|
invited: string[];
|
|
275
279
|
}
|
|
276
280
|
|
|
281
|
+
/** Unified connection-state machine, identical across all transports. */
|
|
282
|
+
export type GameConnectionState = 'connected' | 'disconnected' | 'rejoining' | 'reconnected';
|
|
283
|
+
|
|
284
|
+
/** Payload of game.onReconnected — fires once after a reconnect's resync. */
|
|
285
|
+
export interface ReconnectedInfo {
|
|
286
|
+
/** The server checkpoint from the resync (may be empty). */
|
|
287
|
+
state: Record<string, any> | null;
|
|
288
|
+
/** Highest action sequence after the resync. */
|
|
289
|
+
lastSequence: number;
|
|
290
|
+
/** True when recovery came through a game:sync payload. */
|
|
291
|
+
viaSync: boolean;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** An action as seen by a syncedState reducer. */
|
|
295
|
+
export interface SyncedStateAction {
|
|
296
|
+
playerId: string;
|
|
297
|
+
type: string;
|
|
298
|
+
data: any;
|
|
299
|
+
/** Authoritative sequence; undefined only for direct-mode local applies. */
|
|
300
|
+
sequence: number | undefined;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Options for game.syncedState(). */
|
|
304
|
+
export interface SyncedStateOptions<S = Record<string, any>> {
|
|
305
|
+
/** Pure reducer applied to every action; default shallow-merges action.data. */
|
|
306
|
+
reduce?: (state: S, action: SyncedStateAction) => S;
|
|
307
|
+
/** Authority checkpoint cadence in actions (1 = every action; 0 disables). */
|
|
308
|
+
checkpointEvery?: number;
|
|
309
|
+
/** Who checkpoints: 'host' (player_ids[0], default) or 'all' participants. */
|
|
310
|
+
authority?: 'host' | 'all';
|
|
311
|
+
/** Default action type used by commit(data) (default 'update'). */
|
|
312
|
+
type?: string;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** Reconnect-safe authoritative shared state (see game.syncedState). */
|
|
316
|
+
export interface SyncedState<S = Record<string, any>> {
|
|
317
|
+
/** Current state value. */
|
|
318
|
+
get(): S;
|
|
319
|
+
/** Commit with the default action type. Applied exactly once via the echo. */
|
|
320
|
+
commit(data: Record<string, any>): Promise<ActionResult>;
|
|
321
|
+
/** Commit a named action; opts forwarded to game.action (nextTurn, …). */
|
|
322
|
+
commit(type: string, data?: Record<string, any>, opts?: GameActionOptions): Promise<ActionResult>;
|
|
323
|
+
/** Subscribe to changes: cb(state, reason). Returns an unsubscribe fn. */
|
|
324
|
+
onChange(callback: (state: S, reason: 'action' | 'recover') => void): UnsubscribeFn;
|
|
325
|
+
/** Whether this client is the checkpointing authority. */
|
|
326
|
+
isAuthority(): boolean;
|
|
327
|
+
/** Force a server checkpoint now (no-op result in direct mode). */
|
|
328
|
+
checkpoint(): Promise<{ success: boolean; error?: string; code?: UsionErrorCode }>;
|
|
329
|
+
/** Sequence of the last action applied into this state. */
|
|
330
|
+
getSequence(): number;
|
|
331
|
+
/** Detach all listeners; the instance stops receiving updates. */
|
|
332
|
+
destroy(): void;
|
|
333
|
+
}
|
|
334
|
+
|
|
277
335
|
export interface GameModule {
|
|
278
336
|
// Connection
|
|
279
337
|
connect(socketUrl?: string, token?: string): Promise<void>;
|
|
@@ -368,6 +426,36 @@ export interface GameModule {
|
|
|
368
426
|
*/
|
|
369
427
|
onRoomAssigned(callback: (data: { roomId: string }) => void): UnsubscribeFn;
|
|
370
428
|
|
|
429
|
+
// ─── Reconnection lifecycle (SDK ≥ 2.21; documented since 2.16) ──────────
|
|
430
|
+
/** Highest action sequence seen (joins, syncs, live actions). */
|
|
431
|
+
getLastSequence(): number;
|
|
432
|
+
/** Highest action sequence applied locally; trails while catching up. */
|
|
433
|
+
getLastAppliedSequence(): number;
|
|
434
|
+
/** Current connection state, synchronously. */
|
|
435
|
+
getConnectionState(): GameConnectionState;
|
|
436
|
+
/**
|
|
437
|
+
* Observe connection-state transitions ('connected' → 'disconnected' →
|
|
438
|
+
* 'rejoining' → 'reconnected' → 'connected') — identical across the socket,
|
|
439
|
+
* embedded-proxy, and direct transports. One hook to drive a
|
|
440
|
+
* "Reconnecting…" overlay and gate input.
|
|
441
|
+
*/
|
|
442
|
+
onConnectionState(callback: (state: GameConnectionState) => void): UnsubscribeFn;
|
|
443
|
+
/**
|
|
444
|
+
* Fires once per reconnect, after the resync completes. Restore local
|
|
445
|
+
* state here — it does NOT fire for a manually-requested sync.
|
|
446
|
+
*/
|
|
447
|
+
onReconnected(callback: (info: ReconnectedInfo) => void): UnsubscribeFn;
|
|
448
|
+
/**
|
|
449
|
+
* Reconnect-safe authoritative shared state. Commits are sequenced actions
|
|
450
|
+
* applied through `reduce` on every client in the same order (deduped by
|
|
451
|
+
* sequence); the authority (player_ids[0] by default) auto-checkpoints via
|
|
452
|
+
* setState, and (re)joining clients recover automatically (load checkpoint,
|
|
453
|
+
* replay the un-checkpointed tail). Use for state that must survive a
|
|
454
|
+
* disconnect — unlike replicate() (realtime, lossy). Degrades to
|
|
455
|
+
* local-apply in direct mode (no platform checkpoint there).
|
|
456
|
+
*/
|
|
457
|
+
syncedState<S = Record<string, any>>(initial: S, opts?: SyncedStateOptions<S>): SyncedState<S>;
|
|
458
|
+
|
|
371
459
|
/**
|
|
372
460
|
* Register an ADDITIONAL event listener. Unlike the onX methods this
|
|
373
461
|
* supports multiple listeners per event, can be called before connect(),
|
|
@@ -817,7 +905,15 @@ export interface UsionSDK {
|
|
|
817
905
|
config: UsionConfig;
|
|
818
906
|
|
|
819
907
|
// Lifecycle
|
|
820
|
-
|
|
908
|
+
/**
|
|
909
|
+
* Initialize the SDK. The callback fires when the host's INIT config
|
|
910
|
+
* arrives; every call also returns a Promise of the same config, so
|
|
911
|
+
* `const config = await Usion.init()` works. `opts.timeout` (ms) rejects
|
|
912
|
+
* the promise with UsionError(INIT_TIMEOUT) when no INIT arrives in time
|
|
913
|
+
* (embedded but host silent). (promise/timeout: SDK ≥ 2.22)
|
|
914
|
+
*/
|
|
915
|
+
init(callback?: (config: UsionConfig) => void, opts?: { timeout?: number }): Promise<UsionConfig>;
|
|
916
|
+
init(opts: { timeout?: number }): Promise<UsionConfig>;
|
|
821
917
|
exit(options?: { backCount?: number }): void;
|
|
822
918
|
|
|
823
919
|
// Theme & Locale
|
|
@@ -862,8 +958,8 @@ export interface UsionSDK {
|
|
|
862
958
|
// Logging
|
|
863
959
|
log(msg: string): void;
|
|
864
960
|
|
|
865
|
-
// Generic event listener
|
|
866
|
-
on(type: string, callback: (data: any) => void):
|
|
961
|
+
// Generic event listener (returns an unsubscribe function)
|
|
962
|
+
on(type: string, callback: (data: any) => void): UnsubscribeFn;
|
|
867
963
|
|
|
868
964
|
// UI helpers
|
|
869
965
|
setLoading(btn: HTMLElement | string, loading: boolean): void;
|
|
@@ -980,8 +1076,14 @@ export interface CloudModule extends CloudScope {
|
|
|
980
1076
|
export interface Match { roomId: string; players: string[]; serviceId?: string; }
|
|
981
1077
|
|
|
982
1078
|
export interface MatchmakingModule {
|
|
983
|
-
/**
|
|
984
|
-
|
|
1079
|
+
/**
|
|
1080
|
+
* Join the quick-match queue; resolves when paired with online strangers.
|
|
1081
|
+
* `opts.timeout` (ms) bounds the wait: on expiry the queue is left and the
|
|
1082
|
+
* promise rejects with UsionError(MATCH_TIMEOUT). A newer find() rejects
|
|
1083
|
+
* the previous one with SUPERSEDED; cancel() rejects it with CANCELLED.
|
|
1084
|
+
* (timeout: SDK ≥ 2.22)
|
|
1085
|
+
*/
|
|
1086
|
+
find(serviceId?: string, opts?: { size?: number; timeout?: number }): Promise<Match>;
|
|
985
1087
|
/** Leave the queue / stop waiting. */
|
|
986
1088
|
cancel(): Promise<any>;
|
|
987
1089
|
/** Called whenever a match is found. */
|
|
@@ -1036,16 +1138,29 @@ export declare const ERROR_CODES: {
|
|
|
1036
1138
|
readonly NO_ROOM: 'NO_ROOM';
|
|
1037
1139
|
readonly ROOM_NOT_FOUND: 'ROOM_NOT_FOUND';
|
|
1038
1140
|
readonly NOT_PARTICIPANT: 'NOT_PARTICIPANT';
|
|
1141
|
+
readonly NOT_IN_ROOM: 'NOT_IN_ROOM';
|
|
1039
1142
|
readonly NOT_AUTHORITY: 'NOT_AUTHORITY';
|
|
1040
1143
|
readonly NOT_AUTHENTICATED: 'NOT_AUTHENTICATED';
|
|
1041
1144
|
readonly JOIN_TIMEOUT: 'JOIN_TIMEOUT';
|
|
1042
1145
|
readonly CONNECT_TIMEOUT: 'CONNECT_TIMEOUT';
|
|
1146
|
+
readonly INIT_TIMEOUT: 'INIT_TIMEOUT';
|
|
1147
|
+
readonly MATCH_TIMEOUT: 'MATCH_TIMEOUT';
|
|
1043
1148
|
readonly STATE_TOO_LARGE: 'STATE_TOO_LARGE';
|
|
1044
1149
|
readonly INVALID_STATE: 'INVALID_STATE';
|
|
1150
|
+
readonly STALE_STATE: 'STALE_STATE';
|
|
1045
1151
|
readonly INVALID_NEXT_TURN: 'INVALID_NEXT_TURN';
|
|
1152
|
+
readonly INVALID_INPUT: 'INVALID_INPUT';
|
|
1153
|
+
readonly NOT_FOUND: 'NOT_FOUND';
|
|
1154
|
+
readonly QUOTA_EXCEEDED: 'QUOTA_EXCEEDED';
|
|
1155
|
+
readonly VALUE_TOO_LARGE: 'VALUE_TOO_LARGE';
|
|
1156
|
+
readonly LOBBY_FULL: 'LOBBY_FULL';
|
|
1157
|
+
readonly LOBBY_CLOSED: 'LOBBY_CLOSED';
|
|
1158
|
+
readonly CONFLICT: 'CONFLICT';
|
|
1046
1159
|
readonly RATE_LIMITED: 'RATE_LIMITED';
|
|
1047
1160
|
readonly REQUEST_TIMEOUT: 'REQUEST_TIMEOUT';
|
|
1048
1161
|
readonly QUEUE_FULL: 'QUEUE_FULL';
|
|
1162
|
+
readonly CANCELLED: 'CANCELLED';
|
|
1163
|
+
readonly SUPERSEDED: 'SUPERSEDED';
|
|
1049
1164
|
readonly UNSUPPORTED: 'UNSUPPORTED';
|
|
1050
1165
|
readonly UNKNOWN: 'UNKNOWN';
|
|
1051
1166
|
};
|
|
@@ -1055,6 +1170,8 @@ export type UsionErrorCode = keyof typeof ERROR_CODES;
|
|
|
1055
1170
|
export declare class UsionError extends Error {
|
|
1056
1171
|
readonly name: 'UsionError';
|
|
1057
1172
|
readonly code: UsionErrorCode;
|
|
1173
|
+
/** Seconds until a RATE_LIMITED call may be retried (when the server sent it). */
|
|
1174
|
+
readonly retryAfter?: number;
|
|
1058
1175
|
constructor(code: UsionErrorCode | string, message?: string);
|
|
1059
1176
|
}
|
|
1060
1177
|
|