nostr-arena 0.1.1

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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +188 -0
  3. package/dist/__tests__/callbacks.test.d.ts +28 -0
  4. package/dist/__tests__/callbacks.test.d.ts.map +1 -0
  5. package/dist/__tests__/callbacks.test.js +140 -0
  6. package/dist/__tests__/callbacks.test.js.map +1 -0
  7. package/dist/__tests__/config.test.d.ts +18 -0
  8. package/dist/__tests__/config.test.d.ts.map +1 -0
  9. package/dist/__tests__/config.test.js +43 -0
  10. package/dist/__tests__/config.test.js.map +1 -0
  11. package/dist/__tests__/error-handling.test.d.ts +14 -0
  12. package/dist/__tests__/error-handling.test.d.ts.map +1 -0
  13. package/dist/__tests__/error-handling.test.js +199 -0
  14. package/dist/__tests__/error-handling.test.js.map +1 -0
  15. package/dist/__tests__/protocol.test.d.ts +7 -0
  16. package/dist/__tests__/protocol.test.d.ts.map +1 -0
  17. package/dist/__tests__/protocol.test.js +257 -0
  18. package/dist/__tests__/protocol.test.js.map +1 -0
  19. package/dist/__tests__/state-flow.test.d.ts +37 -0
  20. package/dist/__tests__/state-flow.test.d.ts.map +1 -0
  21. package/dist/__tests__/state-flow.test.js +160 -0
  22. package/dist/__tests__/state-flow.test.js.map +1 -0
  23. package/dist/__tests__/timing.test.d.ts +20 -0
  24. package/dist/__tests__/timing.test.d.ts.map +1 -0
  25. package/dist/__tests__/timing.test.js +73 -0
  26. package/dist/__tests__/timing.test.js.map +1 -0
  27. package/dist/core/Arena.d.ts +164 -0
  28. package/dist/core/Arena.d.ts.map +1 -0
  29. package/dist/core/Arena.js +634 -0
  30. package/dist/core/Arena.js.map +1 -0
  31. package/dist/core/NostrClient.d.ts +108 -0
  32. package/dist/core/NostrClient.d.ts.map +1 -0
  33. package/dist/core/NostrClient.js +225 -0
  34. package/dist/core/NostrClient.js.map +1 -0
  35. package/dist/core/index.d.ts +8 -0
  36. package/dist/core/index.d.ts.map +1 -0
  37. package/dist/core/index.js +7 -0
  38. package/dist/core/index.js.map +1 -0
  39. package/dist/index.d.ts +35 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +37 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/proxy.d.ts +36 -0
  44. package/dist/proxy.d.ts.map +1 -0
  45. package/dist/proxy.js +98 -0
  46. package/dist/proxy.js.map +1 -0
  47. package/dist/react/index.d.ts +7 -0
  48. package/dist/react/index.d.ts.map +1 -0
  49. package/dist/react/index.js +6 -0
  50. package/dist/react/index.js.map +1 -0
  51. package/dist/react/useArena.d.ts +74 -0
  52. package/dist/react/useArena.d.ts.map +1 -0
  53. package/dist/react/useArena.js +224 -0
  54. package/dist/react/useArena.js.map +1 -0
  55. package/dist/retry.d.ts +54 -0
  56. package/dist/retry.d.ts.map +1 -0
  57. package/dist/retry.js +82 -0
  58. package/dist/retry.js.map +1 -0
  59. package/dist/testing/MockArena.d.ts +84 -0
  60. package/dist/testing/MockArena.d.ts.map +1 -0
  61. package/dist/testing/MockArena.js +156 -0
  62. package/dist/testing/MockArena.js.map +1 -0
  63. package/dist/testing/index.d.ts +6 -0
  64. package/dist/testing/index.d.ts.map +1 -0
  65. package/dist/testing/index.js +6 -0
  66. package/dist/testing/index.js.map +1 -0
  67. package/dist/types.d.ts +183 -0
  68. package/dist/types.d.ts.map +1 -0
  69. package/dist/types.js +55 -0
  70. package/dist/types.js.map +1 -0
  71. package/package.json +84 -0
@@ -0,0 +1,74 @@
1
+ /**
2
+ * nostr-battle-room - React Hook
3
+ * React bindings for Arena
4
+ */
5
+ import type { ArenaConfig, ArenaCallbacks, RoomState, OpponentBase } from '../types';
6
+ /**
7
+ * Opponent state with game state
8
+ */
9
+ export interface OpponentState<TGameState> extends OpponentBase {
10
+ gameState: TGameState | null;
11
+ }
12
+ /**
13
+ * Return type for useArena hook
14
+ */
15
+ export interface UseArenaReturn<TGameState> {
16
+ roomState: RoomState;
17
+ opponent: OpponentState<TGameState> | null;
18
+ isConnected: boolean;
19
+ publicKey: string;
20
+ createRoom: (baseUrl?: string) => Promise<string>;
21
+ joinRoom: (roomId: string) => Promise<void>;
22
+ leaveRoom: () => void;
23
+ reconnect: () => Promise<boolean>;
24
+ sendState: (state: TGameState) => void;
25
+ sendGameOver: (reason: string, finalScore?: number) => void;
26
+ requestRematch: () => void;
27
+ acceptRematch: () => void;
28
+ }
29
+ /**
30
+ * React hook for managing a battle room
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * interface MyGameState {
35
+ * score: number;
36
+ * position: { x: number; y: number };
37
+ * }
38
+ *
39
+ * function GameComponent() {
40
+ * const {
41
+ * roomState,
42
+ * opponent,
43
+ * createRoom,
44
+ * joinRoom,
45
+ * sendState,
46
+ * } = useArena<MyGameState>({
47
+ * gameId: 'my-game',
48
+ * onOpponentState: (state) => {
49
+ * console.log('Opponent moved:', state.position);
50
+ * },
51
+ * });
52
+ *
53
+ * // Create a room
54
+ * const handleCreate = async () => {
55
+ * const url = await createRoom();
56
+ * console.log('Share this URL:', url);
57
+ * };
58
+ *
59
+ * // Send game state
60
+ * const handleMove = (x: number, y: number) => {
61
+ * sendState({ score: 100, position: { x, y } });
62
+ * };
63
+ *
64
+ * return (
65
+ * <div>
66
+ * <p>Status: {roomState.status}</p>
67
+ * {opponent && <p>Opponent score: {opponent.gameState?.score}</p>}
68
+ * </div>
69
+ * );
70
+ * }
71
+ * ```
72
+ */
73
+ export declare function useArena<TGameState = Record<string, unknown>>(config: ArenaConfig, callbacks?: ArenaCallbacks<TGameState>): UseArenaReturn<TGameState>;
74
+ //# sourceMappingURL=useArena.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useArena.d.ts","sourceRoot":"","sources":["../../src/react/useArena.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGrF;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,UAAU,CAAE,SAAQ,YAAY;IAC7D,SAAS,EAAE,UAAU,GAAG,IAAI,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc,CAAC,UAAU;IAExC,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAC3C,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAGlB,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAGlC,SAAS,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACvC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3D,MAAM,EAAE,WAAW,EACnB,SAAS,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,GACrC,cAAc,CAAC,UAAU,CAAC,CAuM5B"}
@@ -0,0 +1,224 @@
1
+ /**
2
+ * nostr-battle-room - React Hook
3
+ * React bindings for Arena
4
+ */
5
+ import { useCallback, useEffect, useRef, useState } from 'react';
6
+ import { Arena } from '../core/Arena';
7
+ import { INITIAL_ROOM_STATE } from '../types';
8
+ /**
9
+ * React hook for managing a battle room
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * interface MyGameState {
14
+ * score: number;
15
+ * position: { x: number; y: number };
16
+ * }
17
+ *
18
+ * function GameComponent() {
19
+ * const {
20
+ * roomState,
21
+ * opponent,
22
+ * createRoom,
23
+ * joinRoom,
24
+ * sendState,
25
+ * } = useArena<MyGameState>({
26
+ * gameId: 'my-game',
27
+ * onOpponentState: (state) => {
28
+ * console.log('Opponent moved:', state.position);
29
+ * },
30
+ * });
31
+ *
32
+ * // Create a room
33
+ * const handleCreate = async () => {
34
+ * const url = await createRoom();
35
+ * console.log('Share this URL:', url);
36
+ * };
37
+ *
38
+ * // Send game state
39
+ * const handleMove = (x: number, y: number) => {
40
+ * sendState({ score: 100, position: { x, y } });
41
+ * };
42
+ *
43
+ * return (
44
+ * <div>
45
+ * <p>Status: {roomState.status}</p>
46
+ * {opponent && <p>Opponent score: {opponent.gameState?.score}</p>}
47
+ * </div>
48
+ * );
49
+ * }
50
+ * ```
51
+ */
52
+ export function useArena(config, callbacks) {
53
+ const [roomState, setRoomState] = useState(INITIAL_ROOM_STATE);
54
+ const [opponent, setOpponent] = useState(null);
55
+ const [isConnected, setIsConnected] = useState(false);
56
+ const roomRef = useRef(null);
57
+ const callbacksRef = useRef(callbacks);
58
+ // Keep callbacks ref updated
59
+ useEffect(() => {
60
+ callbacksRef.current = callbacks;
61
+ }, [callbacks]);
62
+ // Initialize Arena
63
+ useEffect(() => {
64
+ const room = new Arena(config);
65
+ // Register callbacks that update React state
66
+ room.onOpponentJoin((publicKey) => {
67
+ setOpponent({
68
+ publicKey,
69
+ gameState: null,
70
+ isConnected: true,
71
+ lastHeartbeat: Date.now(),
72
+ rematchRequested: false,
73
+ });
74
+ setRoomState((prev) => ({ ...prev, status: 'ready' }));
75
+ callbacksRef.current?.onOpponentJoin?.(publicKey);
76
+ });
77
+ room.onOpponentState((state) => {
78
+ setOpponent((prev) => prev
79
+ ? {
80
+ ...prev,
81
+ gameState: state,
82
+ lastHeartbeat: Date.now(),
83
+ isConnected: true,
84
+ }
85
+ : null);
86
+ callbacksRef.current?.onOpponentState?.(state);
87
+ });
88
+ room.onOpponentDisconnect(() => {
89
+ setOpponent((prev) => (prev ? { ...prev, isConnected: false } : null));
90
+ callbacksRef.current?.onOpponentDisconnect?.();
91
+ });
92
+ room.onOpponentGameOver((reason, finalScore) => {
93
+ setRoomState((prev) => ({ ...prev, status: 'finished', rematchRequested: false }));
94
+ setOpponent((prev) => (prev ? { ...prev, rematchRequested: false } : null));
95
+ callbacksRef.current?.onOpponentGameOver?.(reason, finalScore);
96
+ });
97
+ room.onRematchRequested(() => {
98
+ setOpponent((prev) => (prev ? { ...prev, rematchRequested: true } : null));
99
+ callbacksRef.current?.onRematchRequested?.();
100
+ });
101
+ room.onRematchStart((newSeed) => {
102
+ setRoomState((prev) => ({
103
+ ...prev,
104
+ seed: newSeed,
105
+ status: 'ready',
106
+ rematchRequested: false,
107
+ }));
108
+ setOpponent((prev) => (prev ? { ...prev, gameState: null, rematchRequested: false } : null));
109
+ callbacksRef.current?.onRematchStart?.(newSeed);
110
+ });
111
+ room.onError((error) => {
112
+ callbacksRef.current?.onError?.(error);
113
+ });
114
+ room.connect();
115
+ setIsConnected(true);
116
+ roomRef.current = room;
117
+ return () => {
118
+ room.disconnect();
119
+ roomRef.current = null;
120
+ };
121
+ // Note: config should be stable (memoized) by the caller
122
+ // eslint-disable-next-line react-hooks/exhaustive-deps
123
+ }, [config.gameId]);
124
+ // Create room
125
+ const createRoom = useCallback(async (baseUrl) => {
126
+ if (!roomRef.current)
127
+ throw new Error('Arena not initialized');
128
+ const url = await roomRef.current.create(baseUrl);
129
+ setRoomState(roomRef.current.roomState);
130
+ return url;
131
+ }, []);
132
+ // Join room
133
+ const joinRoom = useCallback(async (roomId) => {
134
+ if (!roomRef.current)
135
+ throw new Error('Arena not initialized');
136
+ try {
137
+ await roomRef.current.join(roomId);
138
+ setRoomState(roomRef.current.roomState);
139
+ const opp = roomRef.current.opponent;
140
+ if (opp) {
141
+ setOpponent({
142
+ publicKey: opp.publicKey,
143
+ gameState: opp.gameState ?? null,
144
+ isConnected: opp.isConnected,
145
+ lastHeartbeat: opp.lastHeartbeat,
146
+ rematchRequested: opp.rematchRequested,
147
+ });
148
+ }
149
+ }
150
+ catch (error) {
151
+ // Reset state on join failure
152
+ setRoomState(INITIAL_ROOM_STATE);
153
+ setOpponent(null);
154
+ throw error;
155
+ }
156
+ }, []);
157
+ // Leave room
158
+ const leaveRoom = useCallback(() => {
159
+ if (!roomRef.current)
160
+ return;
161
+ roomRef.current.leave();
162
+ setRoomState(INITIAL_ROOM_STATE);
163
+ setOpponent(null);
164
+ }, []);
165
+ // Reconnect
166
+ const reconnect = useCallback(async () => {
167
+ if (!roomRef.current)
168
+ return false;
169
+ const success = await roomRef.current.reconnect();
170
+ if (success) {
171
+ setRoomState(roomRef.current.roomState);
172
+ const opp = roomRef.current.opponent;
173
+ if (opp) {
174
+ setOpponent({
175
+ publicKey: opp.publicKey,
176
+ gameState: opp.gameState ?? null,
177
+ isConnected: opp.isConnected,
178
+ lastHeartbeat: opp.lastHeartbeat,
179
+ rematchRequested: opp.rematchRequested,
180
+ });
181
+ }
182
+ }
183
+ return success;
184
+ }, []);
185
+ // Send state
186
+ const sendState = useCallback((state) => {
187
+ roomRef.current?.sendState(state);
188
+ }, []);
189
+ // Send game over
190
+ const sendGameOver = useCallback((reason, finalScore) => {
191
+ roomRef.current?.sendGameOver(reason, finalScore);
192
+ setRoomState((prev) => ({ ...prev, status: 'finished' }));
193
+ }, []);
194
+ // Request rematch
195
+ const requestRematch = useCallback(() => {
196
+ if (!roomRef.current)
197
+ return;
198
+ roomRef.current.requestRematch();
199
+ setRoomState((prev) => ({ ...prev, rematchRequested: true }));
200
+ // If opponent already requested, trigger acceptRematch
201
+ if (opponent?.rematchRequested) {
202
+ roomRef.current.acceptRematch();
203
+ }
204
+ }, [opponent?.rematchRequested]);
205
+ // Accept rematch
206
+ const acceptRematch = useCallback(() => {
207
+ roomRef.current?.acceptRematch();
208
+ }, []);
209
+ return {
210
+ roomState,
211
+ opponent,
212
+ isConnected,
213
+ publicKey: roomRef.current?.publicKey ?? '',
214
+ createRoom,
215
+ joinRoom,
216
+ leaveRoom,
217
+ reconnect,
218
+ sendState,
219
+ sendGameOver,
220
+ requestRematch,
221
+ acceptRematch,
222
+ };
223
+ }
224
+ //# sourceMappingURL=useArena.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useArena.js","sourceRoot":"","sources":["../../src/react/useArena.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAgC9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,MAAM,UAAU,QAAQ,CACtB,MAAmB,EACnB,SAAsC;IAEtC,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAY,kBAAkB,CAAC,CAAC;IAC1E,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAmC,IAAI,CAAC,CAAC;IACjF,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEtD,MAAM,OAAO,GAAG,MAAM,CAA2B,IAAI,CAAC,CAAC;IACvD,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAEvC,6BAA6B;IAC7B,SAAS,CAAC,GAAG,EAAE;QACb,YAAY,CAAC,OAAO,GAAG,SAAS,CAAC;IACnC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEhB,mBAAmB;IACnB,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,IAAI,GAAG,IAAI,KAAK,CAAa,MAAM,CAAC,CAAC;QAE3C,6CAA6C;QAC7C,IAAI,CAAC,cAAc,CAAC,CAAC,SAAiB,EAAE,EAAE;YACxC,WAAW,CAAC;gBACV,SAAS;gBACT,SAAS,EAAE,IAAI;gBACf,WAAW,EAAE,IAAI;gBACjB,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE;gBACzB,gBAAgB,EAAE,KAAK;aACxB,CAAC,CAAC;YACH,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;YACvD,YAAY,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC,SAAS,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,CAAC,CAAC,KAAiB,EAAE,EAAE;YACzC,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CACnB,IAAI;gBACF,CAAC,CAAC;oBACE,GAAG,IAAI;oBACP,SAAS,EAAE,KAAK;oBAChB,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE;oBACzB,WAAW,EAAE,IAAI;iBAClB;gBACH,CAAC,CAAC,IAAI,CACT,CAAC;YACF,YAAY,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC,KAAK,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE;YAC7B,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACvE,YAAY,CAAC,OAAO,EAAE,oBAAoB,EAAE,EAAE,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,kBAAkB,CAAC,CAAC,MAAc,EAAE,UAAmB,EAAE,EAAE;YAC9D,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YACnF,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5E,YAAY,CAAC,OAAO,EAAE,kBAAkB,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,kBAAkB,CAAC,GAAG,EAAE;YAC3B,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAC3E,YAAY,CAAC,OAAO,EAAE,kBAAkB,EAAE,EAAE,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,cAAc,CAAC,CAAC,OAAe,EAAE,EAAE;YACtC,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBACtB,GAAG,IAAI;gBACP,IAAI,EAAE,OAAO;gBACb,MAAM,EAAE,OAAO;gBACf,gBAAgB,EAAE,KAAK;aACxB,CAAC,CAAC,CAAC;YACJ,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAC7F,YAAY,CAAC,OAAO,EAAE,cAAc,EAAE,CAAC,OAAO,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,CAAC,KAAY,EAAE,EAAE;YAC5B,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,cAAc,CAAC,IAAI,CAAC,CAAC;QAErB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QAEvB,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,UAAU,EAAE,CAAC;YAClB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;QACzB,CAAC,CAAC;QACF,yDAAyD;QACzD,uDAAuD;IACzD,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAEpB,cAAc;IACd,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,EAAE,OAAgB,EAAmB,EAAE;QACzE,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAE/D,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClD,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACxC,OAAO,GAAG,CAAC;IACb,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,YAAY;IACZ,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,EAAE,MAAc,EAAiB,EAAE;QACnE,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAE/D,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACnC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAExC,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;YACrC,IAAI,GAAG,EAAE,CAAC;gBACR,WAAW,CAAC;oBACV,SAAS,EAAE,GAAG,CAAC,SAAS;oBACxB,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,IAAI;oBAChC,WAAW,EAAE,GAAG,CAAC,WAAW;oBAC5B,aAAa,EAAE,GAAG,CAAC,aAAa;oBAChC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;iBACvC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,8BAA8B;YAC9B,YAAY,CAAC,kBAAkB,CAAC,CAAC;YACjC,WAAW,CAAC,IAAI,CAAC,CAAC;YAClB,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,aAAa;IACb,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;QACjC,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,OAAO;QAE7B,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACxB,YAAY,CAAC,kBAAkB,CAAC,CAAC;QACjC,WAAW,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,YAAY;IACZ,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,IAAsB,EAAE;QACzD,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAEnC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QAClD,IAAI,OAAO,EAAE,CAAC;YACZ,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAExC,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;YACrC,IAAI,GAAG,EAAE,CAAC;gBACR,WAAW,CAAC;oBACV,SAAS,EAAE,GAAG,CAAC,SAAS;oBACxB,SAAS,EAAE,GAAG,CAAC,SAAS,IAAI,IAAI;oBAChC,WAAW,EAAE,GAAG,CAAC,WAAW;oBAC5B,aAAa,EAAE,GAAG,CAAC,aAAa;oBAChC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;iBACvC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,aAAa;IACb,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,KAAiB,EAAE,EAAE;QAClD,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,iBAAiB;IACjB,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,MAAc,EAAE,UAAmB,EAAE,EAAE;QACvE,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAClD,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;IAC5D,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,kBAAkB;IAClB,MAAM,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE;QACtC,IAAI,CAAC,OAAO,CAAC,OAAO;YAAE,OAAO;QAE7B,OAAO,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QACjC,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAE9D,uDAAuD;QACvD,IAAI,QAAQ,EAAE,gBAAgB,EAAE,CAAC;YAC/B,OAAO,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;QAClC,CAAC;IACH,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAEjC,iBAAiB;IACjB,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,EAAE;QACrC,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,CAAC;IACnC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL,SAAS;QACT,QAAQ;QACR,WAAW;QACX,SAAS,EAAE,OAAO,CAAC,OAAO,EAAE,SAAS,IAAI,EAAE;QAE3C,UAAU;QACV,QAAQ;QACR,SAAS;QACT,SAAS;QAET,SAAS;QACT,YAAY;QACZ,cAAc;QACd,aAAa;KACd,CAAC;AACJ,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * nostr-battle-room - Retry Utilities
3
+ * Exponential backoff retry logic for network operations
4
+ */
5
+ export interface RetryOptions {
6
+ /** Maximum number of retry attempts (default: 3) */
7
+ maxAttempts?: number;
8
+ /** Initial delay in ms (default: 1000) */
9
+ initialDelay?: number;
10
+ /** Maximum delay in ms (default: 10000) */
11
+ maxDelay?: number;
12
+ /** Backoff multiplier (default: 2) */
13
+ backoffMultiplier?: number;
14
+ /** Called on each retry attempt */
15
+ onRetry?: (attempt: number, error: Error, delay: number) => void;
16
+ }
17
+ /**
18
+ * Execute a function with exponential backoff retry
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const result = await withRetry(
23
+ * () => fetchData(),
24
+ * { maxAttempts: 3, initialDelay: 1000 }
25
+ * );
26
+ * ```
27
+ */
28
+ export declare function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
29
+ /**
30
+ * Create a promise that rejects after specified timeout
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const result = await Promise.race([
35
+ * fetchData(),
36
+ * timeout(5000, 'Fetch timed out')
37
+ * ]);
38
+ * ```
39
+ */
40
+ export declare function timeout<T = never>(ms: number, message?: string): Promise<T>;
41
+ /**
42
+ * Execute a function with timeout
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const result = await withTimeout(
47
+ * () => fetchData(),
48
+ * 5000,
49
+ * 'Fetch timed out'
50
+ * );
51
+ * ```
52
+ */
53
+ export declare function withTimeout<T>(fn: () => Promise<T>, ms: number, message?: string): Promise<T>;
54
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mCAAmC;IACnC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAClE;AAgBD;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,CAAC,CAAC,CA2B/F;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,CAAC,GAAG,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,SAAwB,GAAG,OAAO,CAAC,CAAC,CAAC,CAI1F;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAAC,CAAC,EACjC,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,EAAE,EAAE,MAAM,EACV,OAAO,SAAwB,GAC9B,OAAO,CAAC,CAAC,CAAC,CAEZ"}
package/dist/retry.js ADDED
@@ -0,0 +1,82 @@
1
+ /**
2
+ * nostr-battle-room - Retry Utilities
3
+ * Exponential backoff retry logic for network operations
4
+ */
5
+ const DEFAULT_RETRY_OPTIONS = {
6
+ maxAttempts: 3,
7
+ initialDelay: 1000,
8
+ maxDelay: 10000,
9
+ backoffMultiplier: 2,
10
+ };
11
+ /**
12
+ * Sleep for specified milliseconds
13
+ */
14
+ function sleep(ms) {
15
+ return new Promise((resolve) => setTimeout(resolve, ms));
16
+ }
17
+ /**
18
+ * Execute a function with exponential backoff retry
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const result = await withRetry(
23
+ * () => fetchData(),
24
+ * { maxAttempts: 3, initialDelay: 1000 }
25
+ * );
26
+ * ```
27
+ */
28
+ export async function withRetry(fn, options = {}) {
29
+ const opts = { ...DEFAULT_RETRY_OPTIONS, ...options };
30
+ let lastError = null;
31
+ let delay = opts.initialDelay;
32
+ for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {
33
+ try {
34
+ return await fn();
35
+ }
36
+ catch (error) {
37
+ lastError = error instanceof Error ? error : new Error(String(error));
38
+ if (attempt === opts.maxAttempts) {
39
+ break;
40
+ }
41
+ // Call onRetry callback if provided
42
+ opts.onRetry?.(attempt, lastError, delay);
43
+ // Wait before next retry
44
+ await sleep(delay);
45
+ // Increase delay with exponential backoff
46
+ delay = Math.min(delay * opts.backoffMultiplier, opts.maxDelay);
47
+ }
48
+ }
49
+ throw lastError;
50
+ }
51
+ /**
52
+ * Create a promise that rejects after specified timeout
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * const result = await Promise.race([
57
+ * fetchData(),
58
+ * timeout(5000, 'Fetch timed out')
59
+ * ]);
60
+ * ```
61
+ */
62
+ export function timeout(ms, message = 'Operation timed out') {
63
+ return new Promise((_, reject) => {
64
+ setTimeout(() => reject(new Error(message)), ms);
65
+ });
66
+ }
67
+ /**
68
+ * Execute a function with timeout
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const result = await withTimeout(
73
+ * () => fetchData(),
74
+ * 5000,
75
+ * 'Fetch timed out'
76
+ * );
77
+ * ```
78
+ */
79
+ export async function withTimeout(fn, ms, message = 'Operation timed out') {
80
+ return Promise.race([fn(), timeout(ms, message)]);
81
+ }
82
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH,MAAM,qBAAqB,GAA4C;IACrE,WAAW,EAAE,CAAC;IACd,YAAY,EAAE,IAAI;IAClB,QAAQ,EAAE,KAAK;IACf,iBAAiB,EAAE,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAI,EAAoB,EAAE,UAAwB,EAAE;IACjF,MAAM,IAAI,GAAG,EAAE,GAAG,qBAAqB,EAAE,GAAG,OAAO,EAAE,CAAC;IACtD,IAAI,SAAS,GAAiB,IAAI,CAAC;IACnC,IAAI,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC;IAE9B,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QAC7D,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAEtE,IAAI,OAAO,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjC,MAAM;YACR,CAAC;YAED,oCAAoC;YACpC,IAAI,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;YAE1C,yBAAyB;YACzB,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;YAEnB,0CAA0C;YAC1C,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAED,MAAM,SAAS,CAAC;AAClB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,OAAO,CAAY,EAAU,EAAE,OAAO,GAAG,qBAAqB;IAC5E,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;QAC/B,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,EAAoB,EACpB,EAAU,EACV,OAAO,GAAG,qBAAqB;IAE/B,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAI,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * nostr-battle-room - MockArena
3
+ * Testing utilities for battle room
4
+ */
5
+ import type { RoomState, OpponentBase, ArenaCallbacks, ArenaEventName } from '../types';
6
+ /**
7
+ * Map event names to callback keys
8
+ */
9
+ type EventToCallback<TGameState> = {
10
+ opponentJoin: ArenaCallbacks<TGameState>['onOpponentJoin'];
11
+ opponentState: ArenaCallbacks<TGameState>['onOpponentState'];
12
+ opponentDisconnect: ArenaCallbacks<TGameState>['onOpponentDisconnect'];
13
+ opponentGameOver: ArenaCallbacks<TGameState>['onOpponentGameOver'];
14
+ rematchRequested: ArenaCallbacks<TGameState>['onRematchRequested'];
15
+ rematchStart: ArenaCallbacks<TGameState>['onRematchStart'];
16
+ error: ArenaCallbacks<TGameState>['onError'];
17
+ };
18
+ /**
19
+ * Mock opponent state
20
+ */
21
+ interface MockOpponentState<TGameState> extends OpponentBase {
22
+ gameState: TGameState | null;
23
+ }
24
+ /**
25
+ * MockArena - For testing without real Nostr connections
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const mock = new MockArena<MyGameState>({ gameId: 'test' });
30
+ *
31
+ * // Simulate opponent joining
32
+ * mock.simulateOpponentJoin('pubkey123');
33
+ *
34
+ * // Simulate opponent state update
35
+ * mock.simulateOpponentState({ score: 100 });
36
+ *
37
+ * // Simulate opponent disconnect
38
+ * mock.simulateOpponentDisconnect();
39
+ * ```
40
+ */
41
+ export declare class MockArena<TGameState = Record<string, unknown>> {
42
+ private _roomState;
43
+ private _opponent;
44
+ private callbacks;
45
+ constructor(_config: {
46
+ gameId: string;
47
+ });
48
+ get roomState(): Readonly<RoomState>;
49
+ get opponent(): Readonly<MockOpponentState<TGameState>> | null;
50
+ get isConnected(): boolean;
51
+ get publicKey(): string;
52
+ on<K extends ArenaEventName>(event: K, callback: NonNullable<EventToCallback<TGameState>[K]>): this;
53
+ connect(): void;
54
+ disconnect(): void;
55
+ create(): Promise<string>;
56
+ join(roomId: string): Promise<void>;
57
+ leave(): void;
58
+ sendState(_state: TGameState): void;
59
+ sendGameOver(_reason: string, _finalScore?: number): void;
60
+ requestRematch(): void;
61
+ acceptRematch(): void;
62
+ /**
63
+ * Simulate an opponent joining the room
64
+ */
65
+ simulateOpponentJoin(publicKey?: string): void;
66
+ /**
67
+ * Simulate opponent state update
68
+ */
69
+ simulateOpponentState(state: TGameState): void;
70
+ /**
71
+ * Simulate opponent disconnection
72
+ */
73
+ simulateOpponentDisconnect(): void;
74
+ /**
75
+ * Simulate opponent game over
76
+ */
77
+ simulateOpponentGameOver(reason: string, finalScore?: number): void;
78
+ /**
79
+ * Simulate opponent rematch request
80
+ */
81
+ simulateRematchRequested(): void;
82
+ }
83
+ export {};
84
+ //# sourceMappingURL=MockArena.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MockArena.d.ts","sourceRoot":"","sources":["../../src/testing/MockArena.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAGxF;;GAEG;AACH,KAAK,eAAe,CAAC,UAAU,IAAI;IACjC,YAAY,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAC3D,aAAa,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC7D,kBAAkB,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC,sBAAsB,CAAC,CAAC;IACvE,gBAAgB,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC,oBAAoB,CAAC,CAAC;IACnE,gBAAgB,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC,oBAAoB,CAAC,CAAC;IACnE,YAAY,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAC3D,KAAK,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC;CAC9C,CAAC;AAEF;;GAEG;AACH,UAAU,iBAAiB,CAAC,UAAU,CAAE,SAAQ,YAAY;IAC1D,SAAS,EAAE,UAAU,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,SAAS,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACzD,OAAO,CAAC,UAAU,CAAwC;IAC1D,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,SAAS,CAAkC;gBAEvC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE;IAIvC,IAAI,SAAS,IAAI,QAAQ,CAAC,SAAS,CAAC,CAEnC;IAED,IAAI,QAAQ,IAAI,QAAQ,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI,CAE7D;IAED,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,EAAE,CAAC,CAAC,SAAS,cAAc,EACzB,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,WAAW,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GACpD,IAAI;IAOP,OAAO,IAAI,IAAI;IAIf,UAAU,IAAI,IAAI;IAIZ,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAYzB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzC,KAAK,IAAI,IAAI;IAKb,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAInC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAIzD,cAAc,IAAI,IAAI;IAItB,aAAa,IAAI,IAAI;IAkBrB;;OAEG;IACH,oBAAoB,CAAC,SAAS,GAAE,MAA0B,GAAG,IAAI;IAYjE;;OAEG;IACH,qBAAqB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAY9C;;OAEG;IACH,0BAA0B,IAAI,IAAI;IAOlC;;OAEG;IACH,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAKnE;;OAEG;IACH,wBAAwB,IAAI,IAAI;CAMjC"}