@sleeperhq/mini-core 1.2.1 → 1.2.3
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,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
export default SleeperActions;
|
|
1
|
+
import { NavigationTabId } from './types';
|
|
2
|
+
export type SleeperActions = {
|
|
3
|
+
navigate: (navTabType: NavigationTabId, args?: any) => void;
|
|
4
|
+
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { User,
|
|
2
|
-
import SleeperActions from './sleeper_actions';
|
|
1
|
+
import { User, League, LeaguesMap, RostersInLeagueMap, UserMap, MatchupsInLeagueMap, UsersInLeagueMap, PlayoffsInLeagueMap, TransactionsInLeagueMap, TransactionsMap, SportInfoMap, DraftsInLeagueMap, DraftPickTradesInLeagueMap, DraftPicksInDraftMap, PlayersInSportMap } from './types';
|
|
2
|
+
import type { SleeperActions } from './sleeper_actions';
|
|
3
|
+
|
|
3
4
|
declare class SleeperContext {
|
|
4
5
|
static apiLevel: string;
|
|
5
6
|
user: User;
|
|
6
|
-
navigation: Navigation;
|
|
7
7
|
league: League;
|
|
8
8
|
leaguesMap: LeaguesMap;
|
|
9
9
|
userLeagueList: string[];
|
|
@@ -20,6 +20,5 @@ declare class SleeperContext {
|
|
|
20
20
|
draftPicksInDraftMap: DraftPicksInDraftMap;
|
|
21
21
|
playersInSportMap: PlayersInSportMap;
|
|
22
22
|
actions: SleeperActions;
|
|
23
|
-
constructor();
|
|
24
23
|
}
|
|
25
24
|
export default SleeperContext;
|
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
import { NAVIGATION_ID, NAVIGATION_TYPE } from './redux/native_nav/constants.d';
|
|
2
1
|
import { League, Roster, User, MatchupLeg, LeagueTransaction, Draft, DraftPick, RosterDraftPick, Player } from './shared/graphql.d';
|
|
3
|
-
export type
|
|
4
|
-
export type NavigationTypeId = typeof NAVIGATION_ID[keyof typeof NAVIGATION_ID];
|
|
2
|
+
export type NavigationTabId = 'LeaguesIndexScreen' | 'LeaguesDetailScreen' | 'ScoreIndexScreen' | 'ScoreDetailScreen' | 'PicksIndexScreen' | 'FeedIndexScreen' | 'WebviewScreen' | 'ManageChannelsScreen' | 'InboxIndexScreen' | 'MinisIndexScreen' | 'ManageChannelsScreen' | 'InboxIndexScreen' | 'MinisIndexScreen';
|
|
5
3
|
export * from './shared/graphql.d';
|
|
6
|
-
export type Navigation = {
|
|
7
|
-
selectedNavType: NavigationType;
|
|
8
|
-
selectedNavTypeId: NavigationTypeId;
|
|
9
|
-
selectedNavData: {};
|
|
10
|
-
};
|
|
11
4
|
export type LeagueId = string;
|
|
12
5
|
export type RosterId = string;
|
|
13
6
|
export type UserId = string;
|
|
@@ -34,18 +27,18 @@ export type Bracket = {
|
|
|
34
27
|
export type BracketSet = {
|
|
35
28
|
bracket: Bracket[];
|
|
36
29
|
loserBracket: Bracket[];
|
|
37
|
-
}
|
|
30
|
+
};
|
|
38
31
|
export type SportInfo = {
|
|
39
32
|
season_type: string;
|
|
40
33
|
season: string;
|
|
41
|
-
week
|
|
42
|
-
display_week
|
|
43
|
-
leg
|
|
44
|
-
league_season
|
|
45
|
-
league_create_season
|
|
46
|
-
previous_season
|
|
47
|
-
season_start_date
|
|
48
|
-
season_end_date
|
|
34
|
+
week?: number;
|
|
35
|
+
display_week?: number;
|
|
36
|
+
leg?: number;
|
|
37
|
+
league_season?: string;
|
|
38
|
+
league_create_season?: string;
|
|
39
|
+
previous_season?: string;
|
|
40
|
+
season_start_date?: string;
|
|
41
|
+
season_end_date?: string;
|
|
49
42
|
};
|
|
50
43
|
export type LeaguesMap = Record<LeagueId, League>;
|
|
51
44
|
export type RostersMap = Record<RosterId, Roster>;
|
|
@@ -53,7 +46,7 @@ export type RostersInLeagueMap = Record<LeagueId, RostersMap>;
|
|
|
53
46
|
export type UserMap = Record<UserId, User>;
|
|
54
47
|
export type MathchupWeekMap = Record<MatchupWeek, MatchupLeg>;
|
|
55
48
|
export type MatchupsInLeagueMap = Record<LeagueId, MathchupWeekMap>;
|
|
56
|
-
export type UsersInLeagueMap = Record<LeagueId,
|
|
49
|
+
export type UsersInLeagueMap = Record<LeagueId, UserMap>;
|
|
57
50
|
export type PlayoffsInLeagueMap = Record<LeagueId, BracketSet>;
|
|
58
51
|
export type TransactionsInLeagueMap = Record<LeagueId, TransactionId[]>;
|
|
59
52
|
export type TransactionsMap = Record<TransactionId, LeagueTransaction>;
|
|
@@ -63,3 +56,17 @@ export type DraftPickTradesInLeagueMap = Record<LeagueId, RosterDraftPick[]>;
|
|
|
63
56
|
export type DraftPicksInDraftMap = Record<DraftId, DraftPick[]>;
|
|
64
57
|
export type PlayersMap = Record<PlayerId, Player>;
|
|
65
58
|
export type PlayersInSportMap = Record<SportType, PlayersMap>;
|
|
59
|
+
export declare enum MiniCategory {
|
|
60
|
+
DEVELOPER = "Developer",
|
|
61
|
+
FEATURED = "Featured",
|
|
62
|
+
GAMES = "Games",
|
|
63
|
+
SPORTUTILITY = "Sport Utility"
|
|
64
|
+
}
|
|
65
|
+
export type Mini = {
|
|
66
|
+
name: string;
|
|
67
|
+
description: string;
|
|
68
|
+
image: string;
|
|
69
|
+
category: MiniCategory;
|
|
70
|
+
id: string;
|
|
71
|
+
};
|
|
72
|
+
export type VersionMap = Record<string, Mini>;
|
|
@@ -21,3 +21,11 @@ export declare const NAVIGATION_ID: {
|
|
|
21
21
|
readonly MENTIONS: 6;
|
|
22
22
|
readonly FRIENDS: 7;
|
|
23
23
|
};
|
|
24
|
+
export declare const NAVIGATION_TAB_ID: {
|
|
25
|
+
readonly FantasyTab: "FantasyTab";
|
|
26
|
+
readonly ScoresTab: "ScoresTab";
|
|
27
|
+
readonly GamesTab: "GamesTab";
|
|
28
|
+
readonly FeedTab: "FeedTab";
|
|
29
|
+
readonly InboxTab: "InboxTab";
|
|
30
|
+
readonly MinisTab: "MinisTab";
|
|
31
|
+
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import React, {useEffect, useRef, useState} from 'react';
|
|
2
|
+
import {Platform} from 'react-native';
|
|
3
|
+
import {Config, SocketMessage} from '../types';
|
|
4
|
+
import { ScriptLocatorResolver, ScriptManager, Federated } from '@callstack/repack/client';
|
|
5
|
+
import NetInfo from '@react-native-community/netinfo';
|
|
6
|
+
import TcpSocket from 'react-native-tcp-socket';
|
|
7
|
+
import { fetchMainVersionMap, getMainUrl } from './url_resolver';
|
|
8
|
+
|
|
9
|
+
let config: Config;
|
|
10
|
+
const RETRY_TIMER = 5000;
|
|
11
|
+
|
|
12
|
+
const DevServer = props => {
|
|
13
|
+
const connection = useRef<TcpSocket.Socket>();
|
|
14
|
+
const partialMessage = useRef('');
|
|
15
|
+
const messageLength = useRef(0);
|
|
16
|
+
const messageType = useRef('');
|
|
17
|
+
const _retryTimer = useRef<NodeJS.Timeout>();
|
|
18
|
+
|
|
19
|
+
const [data, setData] = useState({
|
|
20
|
+
platform: '',
|
|
21
|
+
binaryVersion: '',
|
|
22
|
+
dist: '',
|
|
23
|
+
isStaging: false,
|
|
24
|
+
});
|
|
25
|
+
const _dataRef = useRef<typeof data>();
|
|
26
|
+
const _versionMap = useRef<Record<string, string>>();
|
|
27
|
+
|
|
28
|
+
const _onConnected = async (value: boolean) => {
|
|
29
|
+
props.onConnected(value);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const onSocket = (handler) => msg => {
|
|
33
|
+
let msgString: string = msg.toString();
|
|
34
|
+
while (msgString.length > 0) {
|
|
35
|
+
if (messageLength.current === 0) {
|
|
36
|
+
const delimit = msgString.indexOf('\n');
|
|
37
|
+
if (delimit === -1) {
|
|
38
|
+
console.log("[Sleeper] Message header not found, throwing out message.");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const header = msgString.substring(0, delimit);
|
|
43
|
+
try {
|
|
44
|
+
const headerObject = JSON.parse(header);
|
|
45
|
+
messageType.current = headerObject.type;
|
|
46
|
+
messageLength.current = headerObject.size;
|
|
47
|
+
} catch (e) {
|
|
48
|
+
console.log("[Sleeper] Message header malformed, throwing out message.");
|
|
49
|
+
messageLength.current = 0;
|
|
50
|
+
messageType.current = '';
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
msgString = msgString.substring(delimit + 1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const partialLength = messageLength.current - partialMessage.current.length;
|
|
58
|
+
if (partialLength < 0) {
|
|
59
|
+
// We need to wait for more data
|
|
60
|
+
partialMessage.current += msgString;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const remainingLength = msgString.length - partialLength;
|
|
65
|
+
if (remainingLength === 0) {
|
|
66
|
+
// We have the full message
|
|
67
|
+
partialMessage.current += msgString;
|
|
68
|
+
msgString = '';
|
|
69
|
+
if (config.logsEnabled) console.log("[Sleeper] Message built.", partialMessage.current.length);
|
|
70
|
+
|
|
71
|
+
} else {
|
|
72
|
+
// We have more than the full message
|
|
73
|
+
partialMessage.current += msgString.substring(0, partialLength);
|
|
74
|
+
msgString = msgString.substring(partialLength);
|
|
75
|
+
|
|
76
|
+
if (remainingLength <= 0) {
|
|
77
|
+
// We have less than the full message
|
|
78
|
+
if (config.logsEnabled) console.log("[Sleeper] Building message: ", partialMessage.current.length, messageLength.current, remainingLength);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const json = JSON.parse(partialMessage.current);
|
|
85
|
+
partialMessage.current = '';
|
|
86
|
+
messageLength.current = 0;
|
|
87
|
+
|
|
88
|
+
// Set connection data
|
|
89
|
+
if (json._platform || json._binaryVersion || json._dist || json._isStaging) {
|
|
90
|
+
if (config.logsEnabled) console.log("[Sleeper] Processing context data:", json._platform, json._binaryVersion, json._dist, json._isStaging);
|
|
91
|
+
setData({
|
|
92
|
+
platform: json._platform,
|
|
93
|
+
binaryVersion: json._binaryVersion,
|
|
94
|
+
dist: json._dist,
|
|
95
|
+
isStaging: json._isStaging,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (messageType.current === 'context') {
|
|
100
|
+
// We should have a context object now
|
|
101
|
+
const context = new Proxy(json, handler);
|
|
102
|
+
props.onContextChanged(context);
|
|
103
|
+
} else if (messageType.current === `partialContext`) {
|
|
104
|
+
// We are updating a partial Context
|
|
105
|
+
props.onContextUpdated(json)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
messageType.current = '';
|
|
109
|
+
} catch (e) {
|
|
110
|
+
console.log("[Sleeper] Failed to parse message: ", e);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const sendContextRequest = (socket, propertyPath) => {
|
|
117
|
+
const message: SocketMessage = {_contextGet: propertyPath};
|
|
118
|
+
const json = JSON.stringify(message);
|
|
119
|
+
try {
|
|
120
|
+
socket?.write(json + '\n');
|
|
121
|
+
} catch (e) {
|
|
122
|
+
console.log("[Sleeper] Failed to send context request: ", e);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const proxyHandler = (socket) => {
|
|
127
|
+
return {
|
|
128
|
+
get: (target, property) => {
|
|
129
|
+
let value = Reflect.get(target, property);
|
|
130
|
+
|
|
131
|
+
// Check if we need to add a proxy to this object
|
|
132
|
+
if (!!value && typeof value === 'object' && !value._isProxy && value._isProxyInternal) {
|
|
133
|
+
const isLeaf = !value._continueProxy;
|
|
134
|
+
// Adding proxies to objects
|
|
135
|
+
const handler = proxyHandlerChild(socket, property, isLeaf);
|
|
136
|
+
const proxiedValue = new Proxy(value, handler);
|
|
137
|
+
Reflect.set(target, property, proxiedValue);
|
|
138
|
+
value = proxiedValue;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const proxyHandlerChild = (socket, path, isLeaf) => {
|
|
147
|
+
return {
|
|
148
|
+
get: (target, property) => {
|
|
149
|
+
// Check if a proxy was already added to this object
|
|
150
|
+
if (property === '_isProxy') {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const value = Reflect.get(target, property);
|
|
155
|
+
const fullPropertyPath = `${path}.${property}`;
|
|
156
|
+
|
|
157
|
+
// If the value is undefined, we need to request it from the server
|
|
158
|
+
if (value === undefined && isLeaf) {
|
|
159
|
+
if (config.logsEnabled) console.log("[Sleeper] Requesting context value: ", fullPropertyPath);
|
|
160
|
+
sendContextRequest(socket, fullPropertyPath);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Check if we need to add a second layer proxy to this object
|
|
164
|
+
if (!isLeaf && !value?._isProxy) {
|
|
165
|
+
const nextLeaf = true; // Currently we only support 2 layers of proxies
|
|
166
|
+
// Adding proxies to objects
|
|
167
|
+
// These proxies aren't stored in the context object so we will regenerate them every time
|
|
168
|
+
const handler = proxyHandlerChild(socket, fullPropertyPath, nextLeaf);
|
|
169
|
+
if (value === undefined) {
|
|
170
|
+
return new Proxy({}, handler);
|
|
171
|
+
} else {
|
|
172
|
+
return new Proxy(value, handler);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const startSocket = async () => {
|
|
182
|
+
const netInfo = await NetInfo.fetch();
|
|
183
|
+
const netInfoDetails = netInfo?.details;
|
|
184
|
+
const ipAddress = netInfoDetails?.ipAddress;
|
|
185
|
+
|
|
186
|
+
if (!netInfoDetails || !('ipAddress' in netInfoDetails)) {
|
|
187
|
+
console.error('[Sleeper] Failed to determine local IP address.');
|
|
188
|
+
return stopSocket();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
connection.current = TcpSocket.createConnection({
|
|
192
|
+
port: config.remoteSocketPort || 9092,
|
|
193
|
+
host: config.remoteIP,
|
|
194
|
+
localAddress: ipAddress,
|
|
195
|
+
reuseAddress: true,
|
|
196
|
+
}, () => {
|
|
197
|
+
// When we establish a connection, send the IP address to the server
|
|
198
|
+
const message: SocketMessage = {
|
|
199
|
+
_ip: ipAddress,
|
|
200
|
+
_name: config.name,
|
|
201
|
+
};
|
|
202
|
+
const json = JSON.stringify(message);
|
|
203
|
+
console.log('[Sleeper] Send IP address: ', ipAddress, config.name);
|
|
204
|
+
try {
|
|
205
|
+
connection.current?.write(json + '\n', "utf8", (error) => {
|
|
206
|
+
if (error) {
|
|
207
|
+
return stopSocket();
|
|
208
|
+
}
|
|
209
|
+
console.log('[Sleeper] Connected to the Sleeper App.');
|
|
210
|
+
_onConnected(true);
|
|
211
|
+
});
|
|
212
|
+
} catch (e) {
|
|
213
|
+
return stopSocket();
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
connection.current.on('data', (data, ...args) => {
|
|
218
|
+
const handler = proxyHandler(connection.current);
|
|
219
|
+
const onSocketHandler = onSocket(handler);
|
|
220
|
+
onSocketHandler(data);
|
|
221
|
+
});
|
|
222
|
+
connection.current.on('error', err => {
|
|
223
|
+
return stopSocket();
|
|
224
|
+
});
|
|
225
|
+
connection.current.on('close', (hadError) => {
|
|
226
|
+
return stopSocket();
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const stopSocket = (retry = true) => {
|
|
231
|
+
_onConnected(false);
|
|
232
|
+
|
|
233
|
+
if (connection.current) {
|
|
234
|
+
connection.current.destroy();
|
|
235
|
+
connection.current = undefined;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Any time the socket is closed, attempt to connect again.
|
|
239
|
+
if (retry) {
|
|
240
|
+
clearTimeout(_retryTimer.current);
|
|
241
|
+
_retryTimer.current = setTimeout(() => {
|
|
242
|
+
console.log('[Sleeper] Unable to connect to sleeper, retrying...');
|
|
243
|
+
startSocket();
|
|
244
|
+
}, RETRY_TIMER);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const _waitForInitialization = () => {
|
|
249
|
+
return new Promise<void>((resolve) => {
|
|
250
|
+
(function checkData() {
|
|
251
|
+
let isInitialized = !!_dataRef.current?.dist;
|
|
252
|
+
|
|
253
|
+
// Non-staging builds also require a version map to be defined.
|
|
254
|
+
if (!_dataRef.current?.isStaging) {
|
|
255
|
+
isInitialized = !!_versionMap.current;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (isInitialized) return resolve();
|
|
259
|
+
setTimeout(checkData, 1000);
|
|
260
|
+
})();
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const _resolveRemoteChunk: ScriptLocatorResolver = async (scriptId: string, caller: string) => {
|
|
265
|
+
await _waitForInitialization();
|
|
266
|
+
|
|
267
|
+
const bundleName = !caller ? `${scriptId}.container.bundle` : `${scriptId}.chunk.bundle`;
|
|
268
|
+
|
|
269
|
+
// Try to resolve URL based on scriptId and caller
|
|
270
|
+
const url = getMainUrl(scriptId, caller, {
|
|
271
|
+
platform: _dataRef.current?.platform,
|
|
272
|
+
bundleVersion: _versionMap.current?.[bundleName],
|
|
273
|
+
binaryVersion: _dataRef.current?.binaryVersion,
|
|
274
|
+
dist: _dataRef.current?.dist,
|
|
275
|
+
isStaging: _dataRef.current?.isStaging,
|
|
276
|
+
remoteIP: config.remoteIP,
|
|
277
|
+
dev: config.dev,
|
|
278
|
+
});
|
|
279
|
+
const query = config.dev ? {platform: Platform.OS} : undefined;
|
|
280
|
+
|
|
281
|
+
if (config.logsEnabled) console.log('[Sleeper] load script:', scriptId, caller, url);
|
|
282
|
+
return {url, query};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const _fetchVersionMap = async (platform, binaryVersion, dist) => {
|
|
286
|
+
_versionMap.current = await fetchMainVersionMap(platform, binaryVersion, dist);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
useEffect(() => {
|
|
290
|
+
_dataRef.current = data;
|
|
291
|
+
if (!data.platform || !data.binaryVersion || !data.dist) return;
|
|
292
|
+
|
|
293
|
+
_fetchVersionMap(data.platform, data.binaryVersion, data.dist);
|
|
294
|
+
}, [data.platform, data.binaryVersion, data.dist, data.isStaging]);
|
|
295
|
+
|
|
296
|
+
useEffect(() => {
|
|
297
|
+
if (!config) {
|
|
298
|
+
console.error('[Sleeper] No config file specified. Please make sure you call DevServer.init() early in the app lifecycle.');
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
ScriptManager.shared.addResolver(_resolveRemoteChunk.bind(this));
|
|
303
|
+
startSocket();
|
|
304
|
+
|
|
305
|
+
return () => {
|
|
306
|
+
stopSocket(false);
|
|
307
|
+
};
|
|
308
|
+
}, []);
|
|
309
|
+
|
|
310
|
+
return <></>;
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
DevServer.init = (_config: Config) => {
|
|
314
|
+
config = _config;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export default DevServer;
|