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,156 @@
1
+ /**
2
+ * nostr-battle-room - MockArena
3
+ * Testing utilities for battle room
4
+ */
5
+ import { INITIAL_ROOM_STATE, generateSeed, generateRoomId } from '../types';
6
+ /**
7
+ * MockArena - For testing without real Nostr connections
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const mock = new MockArena<MyGameState>({ gameId: 'test' });
12
+ *
13
+ * // Simulate opponent joining
14
+ * mock.simulateOpponentJoin('pubkey123');
15
+ *
16
+ * // Simulate opponent state update
17
+ * mock.simulateOpponentState({ score: 100 });
18
+ *
19
+ * // Simulate opponent disconnect
20
+ * mock.simulateOpponentDisconnect();
21
+ * ```
22
+ */
23
+ export class MockArena {
24
+ constructor(_config) {
25
+ this._roomState = { ...INITIAL_ROOM_STATE };
26
+ this._opponent = null;
27
+ this.callbacks = {};
28
+ // Config is accepted but not used in mock
29
+ }
30
+ get roomState() {
31
+ return this._roomState;
32
+ }
33
+ get opponent() {
34
+ return this._opponent;
35
+ }
36
+ get isConnected() {
37
+ return true;
38
+ }
39
+ get publicKey() {
40
+ return 'mock-public-key';
41
+ }
42
+ on(event, callback) {
43
+ const callbackKey = `on${event.charAt(0).toUpperCase()}${event.slice(1)}`;
44
+ this.callbacks[callbackKey] = callback;
45
+ return this;
46
+ }
47
+ connect() {
48
+ // No-op
49
+ }
50
+ disconnect() {
51
+ // No-op
52
+ }
53
+ async create() {
54
+ const roomId = generateRoomId();
55
+ this._roomState = {
56
+ roomId,
57
+ status: 'waiting',
58
+ isHost: true,
59
+ seed: generateSeed(),
60
+ createdAt: Date.now(),
61
+ };
62
+ return `https://example.com/battle/${roomId}`;
63
+ }
64
+ async join(roomId) {
65
+ this._roomState = {
66
+ roomId,
67
+ status: 'ready',
68
+ isHost: false,
69
+ seed: generateSeed(),
70
+ createdAt: Date.now(),
71
+ };
72
+ }
73
+ leave() {
74
+ this._roomState = { ...INITIAL_ROOM_STATE };
75
+ this._opponent = null;
76
+ }
77
+ sendState(_state) {
78
+ // No-op in mock
79
+ }
80
+ sendGameOver(_reason, _finalScore) {
81
+ this._roomState = { ...this._roomState, status: 'finished' };
82
+ }
83
+ requestRematch() {
84
+ this._roomState = { ...this._roomState, rematchRequested: true };
85
+ }
86
+ acceptRematch() {
87
+ const newSeed = generateSeed();
88
+ this._roomState = {
89
+ ...this._roomState,
90
+ seed: newSeed,
91
+ status: 'ready',
92
+ rematchRequested: false,
93
+ };
94
+ if (this._opponent) {
95
+ this._opponent = { ...this._opponent, gameState: null, rematchRequested: false };
96
+ }
97
+ this.callbacks.onRematchStart?.(newSeed);
98
+ }
99
+ // ==========================================================================
100
+ // Simulation methods (for testing)
101
+ // ==========================================================================
102
+ /**
103
+ * Simulate an opponent joining the room
104
+ */
105
+ simulateOpponentJoin(publicKey = 'opponent-pubkey') {
106
+ this._opponent = {
107
+ publicKey,
108
+ gameState: null,
109
+ isConnected: true,
110
+ lastHeartbeat: Date.now(),
111
+ rematchRequested: false,
112
+ };
113
+ this._roomState = { ...this._roomState, status: 'ready' };
114
+ this.callbacks.onOpponentJoin?.(publicKey);
115
+ }
116
+ /**
117
+ * Simulate opponent state update
118
+ */
119
+ simulateOpponentState(state) {
120
+ if (this._opponent) {
121
+ this._opponent = {
122
+ ...this._opponent,
123
+ gameState: state,
124
+ lastHeartbeat: Date.now(),
125
+ isConnected: true,
126
+ };
127
+ }
128
+ this.callbacks.onOpponentState?.(state);
129
+ }
130
+ /**
131
+ * Simulate opponent disconnection
132
+ */
133
+ simulateOpponentDisconnect() {
134
+ if (this._opponent) {
135
+ this._opponent = { ...this._opponent, isConnected: false };
136
+ }
137
+ this.callbacks.onOpponentDisconnect?.();
138
+ }
139
+ /**
140
+ * Simulate opponent game over
141
+ */
142
+ simulateOpponentGameOver(reason, finalScore) {
143
+ this._roomState = { ...this._roomState, status: 'finished' };
144
+ this.callbacks.onOpponentGameOver?.(reason, finalScore);
145
+ }
146
+ /**
147
+ * Simulate opponent rematch request
148
+ */
149
+ simulateRematchRequested() {
150
+ if (this._opponent) {
151
+ this._opponent = { ...this._opponent, rematchRequested: true };
152
+ }
153
+ this.callbacks.onRematchRequested?.();
154
+ }
155
+ }
156
+ //# sourceMappingURL=MockArena.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MockArena.js","sourceRoot":"","sources":["../../src/testing/MockArena.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * nostr-battle-room - Testing exports
3
+ * Mock implementations for testing
4
+ */
5
+ export { MockArena } from './MockArena';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * nostr-battle-room - Testing exports
3
+ * Mock implementations for testing
4
+ */
5
+ export { MockArena } from './MockArena';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,183 @@
1
+ /**
2
+ * nostr-battle-room - Types
3
+ * Generic types for Nostr-based multiplayer game rooms
4
+ */
5
+ /**
6
+ * Configuration for Arena
7
+ */
8
+ export interface ArenaConfig {
9
+ /** Unique identifier for the game (e.g., 'sasso', 'tetris') */
10
+ gameId: string;
11
+ /** Nostr relay URLs */
12
+ relays?: string[];
13
+ /** Room expiration time in ms (default: 600000 = 10 minutes) */
14
+ roomExpiry?: number;
15
+ /** Heartbeat interval in ms (default: 3000 = 3 seconds) */
16
+ heartbeatInterval?: number;
17
+ /** Disconnect threshold in ms (default: 10000 = 10 seconds) */
18
+ disconnectThreshold?: number;
19
+ /** State update throttle in ms (default: 100) */
20
+ stateThrottle?: number;
21
+ /** Join timeout in ms (default: 30000 = 30 seconds) */
22
+ joinTimeout?: number;
23
+ }
24
+ /**
25
+ * Default configuration values
26
+ */
27
+ export declare const DEFAULT_CONFIG: Required<Omit<ArenaConfig, 'gameId'>>;
28
+ /**
29
+ * Room status
30
+ */
31
+ export type RoomStatus = 'idle' | 'creating' | 'waiting' | 'joining' | 'ready' | 'playing' | 'finished';
32
+ /**
33
+ * Room state (game-agnostic)
34
+ */
35
+ export interface RoomState {
36
+ roomId: string | null;
37
+ status: RoomStatus;
38
+ isHost: boolean;
39
+ seed: number;
40
+ createdAt?: number;
41
+ rematchRequested?: boolean;
42
+ }
43
+ /**
44
+ * Initial room state
45
+ */
46
+ export declare const INITIAL_ROOM_STATE: RoomState;
47
+ /**
48
+ * Base opponent information (game-agnostic)
49
+ */
50
+ export interface OpponentBase {
51
+ publicKey: string;
52
+ isConnected: boolean;
53
+ lastHeartbeat?: number;
54
+ rematchRequested?: boolean;
55
+ }
56
+ /**
57
+ * Opponent state with generic game state
58
+ */
59
+ export interface OpponentState<TGameState = Record<string, unknown>> extends OpponentBase {
60
+ gameState: TGameState;
61
+ }
62
+ /**
63
+ * Nostr event kinds used by the library
64
+ */
65
+ export declare const NOSTR_KINDS: {
66
+ /** Replaceable event for room metadata */
67
+ readonly ROOM: 30078;
68
+ /** Ephemeral event for game state (not stored by relays) */
69
+ readonly EPHEMERAL: 25000;
70
+ };
71
+ /**
72
+ * Nostr event structure
73
+ */
74
+ export interface NostrEvent {
75
+ id?: string;
76
+ pubkey?: string;
77
+ created_at?: number;
78
+ kind: number;
79
+ tags: string[][];
80
+ content: string;
81
+ sig?: string;
82
+ }
83
+ /**
84
+ * Room creation event
85
+ */
86
+ export interface RoomEventContent {
87
+ type: 'room';
88
+ status: 'waiting' | 'playing' | 'finished';
89
+ seed: number;
90
+ hostPubkey: string;
91
+ }
92
+ /**
93
+ * Join event (player joining a room)
94
+ */
95
+ export interface JoinEventContent {
96
+ type: 'join';
97
+ playerPubkey: string;
98
+ }
99
+ /**
100
+ * Generic game state event
101
+ */
102
+ export interface StateEventContent<TGameState = Record<string, unknown>> {
103
+ type: 'state';
104
+ gameState: TGameState;
105
+ }
106
+ /**
107
+ * Game over event
108
+ */
109
+ export interface GameOverEventContent {
110
+ type: 'gameover';
111
+ reason: string;
112
+ finalScore?: number;
113
+ winner?: string;
114
+ }
115
+ /**
116
+ * Rematch event
117
+ */
118
+ export interface RematchEventContent {
119
+ type: 'rematch';
120
+ action: 'request' | 'accept';
121
+ newSeed?: number;
122
+ }
123
+ /**
124
+ * Heartbeat event
125
+ */
126
+ export interface HeartbeatEventContent {
127
+ type: 'heartbeat';
128
+ timestamp: number;
129
+ }
130
+ /**
131
+ * All possible event content types
132
+ */
133
+ export type BattleEventContent<TGameState = Record<string, unknown>> = RoomEventContent | JoinEventContent | StateEventContent<TGameState> | GameOverEventContent | RematchEventContent | HeartbeatEventContent;
134
+ /**
135
+ * Event names for Arena
136
+ */
137
+ export type ArenaEventName = 'opponentJoin' | 'opponentState' | 'opponentDisconnect' | 'opponentGameOver' | 'rematchRequested' | 'rematchStart' | 'error';
138
+ /**
139
+ * Event callbacks for Arena
140
+ */
141
+ export interface ArenaCallbacks<TGameState = Record<string, unknown>> {
142
+ /** Called when opponent joins the room */
143
+ onOpponentJoin?: (publicKey: string) => void;
144
+ /** Called when opponent's game state is updated */
145
+ onOpponentState?: (state: TGameState) => void;
146
+ /** Called when opponent disconnects */
147
+ onOpponentDisconnect?: () => void;
148
+ /** Called when opponent sends game over */
149
+ onOpponentGameOver?: (reason: string, finalScore?: number) => void;
150
+ /** Called when opponent requests rematch */
151
+ onRematchRequested?: () => void;
152
+ /** Called when rematch is accepted (by either party) */
153
+ onRematchStart?: (newSeed: number) => void;
154
+ /** Called on any error */
155
+ onError?: (error: Error) => void;
156
+ }
157
+ /**
158
+ * Data stored in localStorage for reconnection
159
+ */
160
+ export interface StoredRoomData {
161
+ roomId: string;
162
+ isHost: boolean;
163
+ seed: number;
164
+ createdAt: number;
165
+ opponentPubkey?: string;
166
+ }
167
+ /**
168
+ * Function to unsubscribe from events
169
+ */
170
+ export type Unsubscribe = () => void;
171
+ /**
172
+ * Generate room tag from game ID and room ID
173
+ */
174
+ export declare function createRoomTag(gameId: string, roomId: string): string;
175
+ /**
176
+ * Generate a random seed
177
+ */
178
+ export declare function generateSeed(): number;
179
+ /**
180
+ * Generate a unique room ID
181
+ */
182
+ export declare function generateRoomId(): string;
183
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * nostr-battle-room - Types
3
+ * Generic types for Nostr-based multiplayer game rooms
4
+ */
5
+ /**
6
+ * Default configuration values
7
+ */
8
+ export const DEFAULT_CONFIG = {
9
+ relays: ['wss://relay.damus.io', 'wss://nos.lol', 'wss://relay.nostr.band'],
10
+ roomExpiry: 600000,
11
+ heartbeatInterval: 3000,
12
+ disconnectThreshold: 10000,
13
+ stateThrottle: 100,
14
+ joinTimeout: 30000,
15
+ };
16
+ /**
17
+ * Initial room state
18
+ */
19
+ export const INITIAL_ROOM_STATE = {
20
+ roomId: null,
21
+ status: 'idle',
22
+ isHost: false,
23
+ seed: 0,
24
+ };
25
+ // =============================================================================
26
+ // Nostr Types
27
+ // =============================================================================
28
+ /**
29
+ * Nostr event kinds used by the library
30
+ */
31
+ export const NOSTR_KINDS = {
32
+ /** Replaceable event for room metadata */
33
+ ROOM: 30078,
34
+ /** Ephemeral event for game state (not stored by relays) */
35
+ EPHEMERAL: 25000,
36
+ };
37
+ /**
38
+ * Generate room tag from game ID and room ID
39
+ */
40
+ export function createRoomTag(gameId, roomId) {
41
+ return `${gameId}-room-${roomId}`;
42
+ }
43
+ /**
44
+ * Generate a random seed
45
+ */
46
+ export function generateSeed() {
47
+ return Math.floor(Math.random() * 0x7fffffff);
48
+ }
49
+ /**
50
+ * Generate a unique room ID
51
+ */
52
+ export function generateRoomId() {
53
+ return `${Date.now().toString(36)}-${Math.random().toString(36).substr(2, 9)}`;
54
+ }
55
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAgCH;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAA0C;IACnE,MAAM,EAAE,CAAC,sBAAsB,EAAE,eAAe,EAAE,wBAAwB,CAAC;IAC3E,UAAU,EAAE,MAAM;IAClB,iBAAiB,EAAE,IAAI;IACvB,mBAAmB,EAAE,KAAK;IAC1B,aAAa,EAAE,GAAG;IAClB,WAAW,EAAE,KAAK;CACnB,CAAC;AA8BF;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAc;IAC3C,MAAM,EAAE,IAAI;IACZ,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,KAAK;IACb,IAAI,EAAE,CAAC;CACR,CAAC;AAuBF,gFAAgF;AAChF,cAAc;AACd,gFAAgF;AAEhF;;GAEG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,0CAA0C;IAC1C,IAAI,EAAE,KAAK;IACX,4DAA4D;IAC5D,SAAS,EAAE,KAAK;CACR,CAAC;AAwJX;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,MAAc;IAC1D,OAAO,GAAG,MAAM,SAAS,MAAM,EAAE,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACjF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "nostr-arena",
3
+ "version": "0.1.1",
4
+ "description": "Nostr-based real-time multiplayer game arena. No server required.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./react": {
15
+ "import": "./dist/react/index.js",
16
+ "types": "./dist/react/index.d.ts"
17
+ },
18
+ "./testing": {
19
+ "import": "./dist/testing/index.js",
20
+ "types": "./dist/testing/index.d.ts"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsc",
28
+ "dev": "tsc --watch",
29
+ "clean": "rm -rf dist",
30
+ "prepare": "npm run build",
31
+ "test": "vitest run",
32
+ "test:watch": "vitest"
33
+ },
34
+ "keywords": [
35
+ "nostr",
36
+ "multiplayer",
37
+ "game",
38
+ "battle",
39
+ "matchmaking",
40
+ "p2p",
41
+ "realtime",
42
+ "websocket",
43
+ "decentralized"
44
+ ],
45
+ "author": {
46
+ "name": "kako-jun",
47
+ "url": "https://github.com/kako-jun"
48
+ },
49
+ "license": "MIT",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git+https://github.com/kako-jun/nostr-arena.git"
53
+ },
54
+ "homepage": "https://github.com/kako-jun/nostr-arena#readme",
55
+ "bugs": {
56
+ "url": "https://github.com/kako-jun/nostr-arena/issues"
57
+ },
58
+ "peerDependencies": {
59
+ "nostr-tools": "^2.0.0",
60
+ "react": "^18.0.0 || ^19.0.0",
61
+ "ws": "^8.0.0",
62
+ "https-proxy-agent": "^7.0.0"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "react": {
66
+ "optional": true
67
+ },
68
+ "ws": {
69
+ "optional": true
70
+ },
71
+ "https-proxy-agent": {
72
+ "optional": true
73
+ }
74
+ },
75
+ "devDependencies": {
76
+ "typescript": "~5.6.2",
77
+ "@types/react": "^19.0.0",
78
+ "@types/ws": "^8.5.0",
79
+ "ws": "^8.18.0",
80
+ "https-proxy-agent": "^7.0.0",
81
+ "vitest": "^2.0.0",
82
+ "nostr-tools": "^2.10.0"
83
+ }
84
+ }