@omen.foundation/game-sdk 1.0.13 → 1.0.15

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/dist/index.d.mts CHANGED
@@ -74,8 +74,9 @@ interface OmenXGameSDKConfig {
74
74
  interface OAuthOptions {
75
75
  /**
76
76
  * Redirect URI (must be registered in developer portal)
77
+ * If not provided, defaults to `${window.location.origin}/auth/callback`
77
78
  */
78
- redirectUri: string;
79
+ redirectUri?: string;
79
80
  /**
80
81
  * State parameter for CSRF protection (auto-generated if not provided)
81
82
  */
@@ -194,12 +195,19 @@ declare class OmenXServerSDK {
194
195
  /**
195
196
  * Player Operations
196
197
  */
198
+ /**
199
+ * Get full player data: NFTs (system + game) and balances for a wallet.
200
+ * Requires both nfts:read and balances:read scopes.
201
+ */
202
+ getPlayer(wallet: string, chainId: string): Promise<any>;
197
203
  /**
198
204
  * Get native and ERC20 token balances for a wallet
199
205
  */
200
206
  getPlayerBalances(wallet: string, chainId: string): Promise<any>;
201
207
  /**
202
- * Get paginated NFTs for a wallet
208
+ * Get paginated NFTs for a wallet.
209
+ * With no contract: returns OmenX system NFTs (Asset Manager, Faucet, Early Adopter) + game NFTs.
210
+ * With contract: returns only NFTs for that contract.
203
211
  */
204
212
  getPlayerNfts(wallet: string, chainId: string, options?: {
205
213
  contract?: string;
package/dist/index.d.ts CHANGED
@@ -74,8 +74,9 @@ interface OmenXGameSDKConfig {
74
74
  interface OAuthOptions {
75
75
  /**
76
76
  * Redirect URI (must be registered in developer portal)
77
+ * If not provided, defaults to `${window.location.origin}/auth/callback`
77
78
  */
78
- redirectUri: string;
79
+ redirectUri?: string;
79
80
  /**
80
81
  * State parameter for CSRF protection (auto-generated if not provided)
81
82
  */
@@ -194,12 +195,19 @@ declare class OmenXServerSDK {
194
195
  /**
195
196
  * Player Operations
196
197
  */
198
+ /**
199
+ * Get full player data: NFTs (system + game) and balances for a wallet.
200
+ * Requires both nfts:read and balances:read scopes.
201
+ */
202
+ getPlayer(wallet: string, chainId: string): Promise<any>;
197
203
  /**
198
204
  * Get native and ERC20 token balances for a wallet
199
205
  */
200
206
  getPlayerBalances(wallet: string, chainId: string): Promise<any>;
201
207
  /**
202
- * Get paginated NFTs for a wallet
208
+ * Get paginated NFTs for a wallet.
209
+ * With no contract: returns OmenX system NFTs (Asset Manager, Faucet, Early Adopter) + game NFTs.
210
+ * With contract: returns only NFTs for that contract.
203
211
  */
204
212
  getPlayerNfts(wallet: string, chainId: string, options?: {
205
213
  contract?: string;
package/dist/index.js CHANGED
@@ -1,83 +1,34 @@
1
1
  'use strict';
2
2
 
3
- // src/pkce.ts
4
- async function generatePKCE() {
5
- const codeVerifier = generateRandomString(128);
6
- const hash = await sha256(codeVerifier);
7
- const codeChallenge = base64URLEncode(hash);
8
- return { codeVerifier, codeChallenge };
9
- }
10
- function generateRandomString(length) {
11
- const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
12
- const array = new Uint8Array(length);
13
- crypto.getRandomValues(array);
14
- return Array.from(array, (byte) => charset[byte % charset.length]).join("");
15
- }
16
- function base64URLEncode(buffer) {
17
- const base64 = btoa(String.fromCharCode(...new Uint8Array(buffer)));
18
- return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
19
- }
20
- async function sha256(message) {
21
- const encoder = new TextEncoder();
22
- const data = encoder.encode(message);
23
- return crypto.subtle.digest("SHA-256", data);
24
- }
25
-
26
3
  // src/oauth.ts
27
4
  var OAuthFlow = class {
28
5
  constructor(config) {
29
6
  this.config = config;
30
7
  }
31
8
  /**
32
- * Authenticate user via OAuth popup
9
+ * Authenticate user via OAuth 2.0 Authorization Code Grant with PKCE
33
10
  */
34
- async authenticate(options) {
35
- const state = options.state || this.generateState();
36
- try {
37
- const allKeys = Object.keys(localStorage).filter((k) => k.startsWith("omenx_oauth_callback_"));
38
- console.log("[OAuthFlow] \u{1F9F9} Cleaning up old OAuth entries:", { count: allKeys.length });
39
- allKeys.forEach((key) => {
40
- try {
41
- const data = localStorage.getItem(key);
42
- if (data) {
43
- const parsed = JSON.parse(data);
44
- const age = Date.now() - (parsed.timestamp || 0);
45
- if (age > 3e5) {
46
- localStorage.removeItem(key);
47
- console.log("[OAuthFlow] \u{1F5D1}\uFE0F Removed old entry:", key.substring(0, 50) + "...", { age: `${age}ms` });
48
- }
49
- }
50
- } catch (e) {
51
- localStorage.removeItem(key);
52
- }
53
- });
54
- } catch (error) {
55
- console.warn("[OAuthFlow] \u26A0\uFE0F Error cleaning up old entries:", error);
56
- }
57
- let codeChallenge;
58
- let codeVerifier;
59
- if (options.enablePKCE !== false) {
60
- const pkce = await generatePKCE();
61
- codeChallenge = pkce.codeChallenge;
62
- codeVerifier = pkce.codeVerifier;
63
- sessionStorage.setItem(`omenx_pkce_${state}`, codeVerifier);
64
- }
11
+ async authenticate(options = {}) {
12
+ const state = this.generateState();
13
+ const codeVerifier = this.generateCodeVerifier();
14
+ const codeChallenge = await this.generateCodeChallenge(codeVerifier);
65
15
  return new Promise((resolve, reject) => {
66
- const params = new URLSearchParams({
67
- client_id: this.config.gameId,
68
- redirect_uri: options.redirectUri,
69
- response_type: "code",
70
- state
71
- });
72
- if (codeChallenge) {
73
- params.append("code_challenge", codeChallenge);
74
- params.append("code_challenge_method", "S256");
75
- }
76
- const authUrl = `${this.config.oauthAuthorizeUrl}?${params.toString()}`;
16
+ sessionStorage.setItem(`omenx_pkce_${state}`, codeVerifier);
17
+ const redirectUri = options.redirectUri || `${window.location.origin}/auth/callback`;
18
+ const authUrl = new URL(this.config.oauthAuthorizeUrl);
19
+ authUrl.searchParams.set("client_id", this.config.gameId);
20
+ authUrl.searchParams.set("redirect_uri", redirectUri);
21
+ authUrl.searchParams.set("response_type", "code");
22
+ authUrl.searchParams.set("scope", "openid profile email");
23
+ authUrl.searchParams.set("state", state);
24
+ authUrl.searchParams.set("code_challenge", codeChallenge);
25
+ authUrl.searchParams.set("code_challenge_method", "S256");
26
+ const stateStorageKey = `omenx_oauth_state_${state}`;
27
+ sessionStorage.setItem(stateStorageKey, state);
77
28
  const popup = window.open(
78
- authUrl,
79
- "OmenX Authentication",
80
- "width=500,height=600,left=" + (window.screen.width / 2 - 250) + ",top=" + (window.screen.height / 2 - 300)
29
+ authUrl.toString(),
30
+ "OmenX OAuth",
31
+ "width=500,height=600,left=100,top=100"
81
32
  );
82
33
  if (!popup) {
83
34
  const error = new Error("Failed to open popup window. Please allow popups for this site.");
@@ -85,312 +36,92 @@ var OAuthFlow = class {
85
36
  reject(error);
86
37
  return;
87
38
  }
88
- const messageListener = async (event) => {
89
- try {
90
- const currentOrigin = window.location.origin;
91
- if (event.origin !== currentOrigin) {
92
- return;
93
- }
94
- } catch {
95
- }
96
- if (event.data?.type === "OMENX_OAUTH_CODE") {
97
- window.removeEventListener("message", messageListener);
98
- popup.close();
99
- const { code, state: returnedState } = event.data;
100
- if (returnedState !== state) {
101
- const error = new Error("Invalid state parameter. Possible CSRF attack.");
102
- this.config.onError?.(error);
103
- reject(error);
104
- return;
105
- }
106
- const storedCodeVerifier = sessionStorage.getItem(`omenx_pkce_${state}`);
107
- if (storedCodeVerifier) {
108
- sessionStorage.removeItem(`omenx_pkce_${state}`);
109
- codeVerifier = storedCodeVerifier;
110
- }
39
+ try {
40
+ const allKeys = Object.keys(localStorage).filter((k) => k.startsWith("omenx_oauth_callback_"));
41
+ allKeys.forEach((key) => {
111
42
  try {
112
- const tokenResponse = await this.exchangeCodeForToken(code, options.redirectUri, codeVerifier);
113
- await this.config.onTokenReceived(tokenResponse);
114
- resolve(tokenResponse);
115
- } catch (error) {
116
- this.config.onError?.(error);
117
- reject(error);
118
- }
119
- }
120
- };
121
- window.addEventListener("message", messageListener);
122
- const storageListener = (event) => {
123
- if (!event.key || !event.key.startsWith("omenx_oauth_callback_")) {
124
- return;
125
- }
126
- const callbackState = event.key.replace("omenx_oauth_callback_", "");
127
- if (callbackState !== state) {
128
- return;
129
- }
130
- try {
131
- const data = JSON.parse(event.newValue || "{}");
132
- if (data.code && data.state === state) {
133
- console.log("[OAuthFlow] Received OAuth code via localStorage fallback");
134
- messageReceived = true;
135
- window.removeEventListener("storage", storageListener);
136
- window.removeEventListener("message", wrappedMessageListener);
137
- const { code: codeFromStorage } = data;
138
- const storedCodeVerifier = sessionStorage.getItem(`omenx_pkce_${state}`);
139
- let codeVerifier2;
140
- if (storedCodeVerifier) {
141
- sessionStorage.removeItem(`omenx_pkce_${state}`);
142
- codeVerifier2 = storedCodeVerifier;
43
+ const data = localStorage.getItem(key);
44
+ if (data) {
45
+ const parsed = JSON.parse(data);
46
+ const age = Date.now() - (parsed.timestamp || 0);
47
+ if (age > 3e5) {
48
+ localStorage.removeItem(key);
49
+ }
143
50
  }
144
- this.exchangeCodeForToken(codeFromStorage, options.redirectUri, codeVerifier2).then(async (tokenResponse) => {
145
- await this.config.onTokenReceived(tokenResponse);
146
- resolve(tokenResponse);
147
- }).catch((error) => {
148
- this.config.onError?.(error);
149
- reject(error);
150
- });
151
- localStorage.removeItem(event.key);
51
+ } catch (e) {
52
+ localStorage.removeItem(key);
152
53
  }
153
- } catch (error) {
154
- console.error("[OAuthFlow] Error processing localStorage callback:", error);
155
- }
156
- };
157
- window.addEventListener("storage", storageListener);
158
- let pollCount = 0;
159
- const storageKey = `omenx_oauth_callback_${state}`;
160
- const immediateCheck = () => {
161
- const allKeys = Object.keys(localStorage).filter((k) => k.startsWith("omenx_oauth_callback_"));
162
- console.log("[OAuthFlow] \u{1F50D} Immediate localStorage check:", {
163
- count: allKeys.length,
164
- keys: allKeys.map((k) => k.substring(0, 50) + "..."),
165
- lookingFor: storageKey.substring(0, 50) + "...",
166
- expectedState: state.substring(0, 20) + "..."
167
54
  });
168
- for (const key of allKeys) {
169
- const storedData = localStorage.getItem(key);
170
- if (storedData) {
171
- try {
172
- const data = JSON.parse(storedData);
173
- console.log("[OAuthFlow] \u{1F50D} Checking stored key:", {
174
- key: key.substring(0, 50) + "...",
175
- storedState: data.state?.substring(0, 20) + "...",
176
- expectedState: state.substring(0, 20) + "...",
177
- statesMatch: data.state === state,
178
- hasCode: !!data.code,
179
- timestamp: data.timestamp,
180
- age: data.timestamp ? `${Date.now() - data.timestamp}ms` : "unknown"
181
- });
182
- } catch (e) {
183
- console.warn("[OAuthFlow] \u26A0\uFE0F Error parsing stored key:", key, e);
184
- }
185
- }
186
- }
187
- };
188
- immediateCheck();
55
+ } catch (error) {
56
+ }
57
+ const storageKey = `omenx_oauth_callback_${state}`;
58
+ let messageReceived = false;
189
59
  const pollInterval = setInterval(() => {
190
- pollCount++;
191
- const stored = localStorage.getItem(storageKey);
192
- if (pollCount % 10 === 0) {
193
- console.log("[OAuthFlow] \u{1F50D} Polling localStorage...", {
194
- key: storageKey.substring(0, 50) + "...",
195
- found: !!stored,
196
- pollCount,
197
- statePreview: state.substring(0, 20) + "..."
198
- });
199
- if (pollCount % 100 === 0) {
200
- immediateCheck();
201
- }
60
+ if (messageReceived) {
61
+ clearInterval(pollInterval);
62
+ return;
202
63
  }
64
+ const stored = localStorage.getItem(storageKey);
203
65
  if (stored) {
204
66
  try {
205
67
  const data = JSON.parse(stored);
206
- if (pollCount === 1 || pollCount % 10 === 0) {
207
- console.log("[OAuthFlow] \u2705 Found stored data!", {
208
- hasCode: !!data.code,
209
- hasState: !!data.state,
210
- stateMatch: data.state === state,
211
- storedState: data.state?.substring(0, 20) + "...",
212
- expectedState: state.substring(0, 20) + "...",
213
- pollCount
214
- });
215
- }
216
68
  if (data.code && data.state === state) {
217
69
  const age = Date.now() - (data.timestamp || 0);
218
70
  if (age < 3e4) {
219
- console.log("[OAuthFlow] \u2705\u2705\u2705 Processing OAuth callback from localStorage!", {
220
- age: `${age}ms`,
221
- hasCode: !!data.code,
222
- codePreview: data.code.substring(0, 10) + "...",
223
- pollCount
224
- });
71
+ messageReceived = true;
225
72
  clearInterval(pollInterval);
226
- window.removeEventListener("storage", storageListener);
227
- storageListener(new StorageEvent("storage", {
228
- key: storageKey,
229
- newValue: stored,
230
- storageArea: localStorage
231
- }));
73
+ localStorage.removeItem(storageKey);
74
+ sessionStorage.removeItem(`omenx_pkce_${state}`);
75
+ sessionStorage.removeItem(stateStorageKey);
76
+ this.exchangeCodeForToken(data.code, redirectUri, codeVerifier).then(async (tokenResponse) => {
77
+ await this.config.onTokenReceived(tokenResponse);
78
+ if (popup && !popup.closed) {
79
+ try {
80
+ popup.close();
81
+ } catch (e) {
82
+ }
83
+ }
84
+ resolve(tokenResponse);
85
+ }).catch((error) => {
86
+ this.config.onError?.(error);
87
+ reject(error);
88
+ });
232
89
  return;
233
90
  } else {
234
- console.warn("[OAuthFlow] \u26A0\uFE0F Callback data too old, removing:", { age: `${age}ms` });
235
91
  localStorage.removeItem(storageKey);
236
92
  }
237
- } else {
238
- console.warn("[OAuthFlow] \u26A0\uFE0F State mismatch!", {
239
- storedState: data.state?.substring(0, 20) + "...",
240
- expectedState: state.substring(0, 20) + "...",
241
- statesMatch: data.state === state,
242
- storedStateLength: data.state?.length,
243
- expectedStateLength: state.length,
244
- pollCount
245
- });
246
93
  }
247
94
  } catch (error) {
248
- console.error("[OAuthFlow] \u274C Error parsing localStorage callback:", error, {
249
- stored: stored?.substring(0, 100) + "...",
250
- pollCount
251
- });
252
- }
253
- } else {
254
- if (pollCount === 1 || pollCount % 5 === 0) {
255
- const allKeys = Object.keys(localStorage).filter((k) => k.startsWith("omenx_oauth_callback_"));
256
- if (allKeys.length > 0) {
257
- console.log("[OAuthFlow] \u{1F50D} Found localStorage keys (checking all for state match):", {
258
- count: allKeys.length,
259
- keys: allKeys.map((k) => k.substring(0, 50) + "..."),
260
- lookingFor: storageKey.substring(0, 50) + "...",
261
- expectedState: state.substring(0, 20) + "...",
262
- pollCount
263
- });
264
- for (const key of allKeys) {
265
- const storedData = localStorage.getItem(key);
266
- if (storedData) {
267
- try {
268
- const data = JSON.parse(storedData);
269
- const statesMatch = data.state === state;
270
- console.log("[OAuthFlow] \u{1F50D} Checking stored key:", {
271
- key: key.substring(0, 50) + "...",
272
- storedState: data.state?.substring(0, 20) + "...",
273
- expectedState: state.substring(0, 20) + "...",
274
- statesMatch,
275
- storedStateLength: data.state?.length,
276
- expectedStateLength: state.length,
277
- hasCode: !!data.code,
278
- pollCount
279
- });
280
- if (statesMatch && data.code) {
281
- const age = Date.now() - (data.timestamp || 0);
282
- if (age < 3e4) {
283
- console.log("[OAuthFlow] \u2705\u2705\u2705 Found matching state in different key! Processing...", {
284
- key: key.substring(0, 50) + "...",
285
- age: `${age}ms`,
286
- pollCount
287
- });
288
- clearInterval(pollInterval);
289
- window.removeEventListener("storage", storageListener);
290
- storageListener(new StorageEvent("storage", {
291
- key,
292
- newValue: storedData,
293
- storageArea: localStorage
294
- }));
295
- return;
296
- }
297
- }
298
- } catch (e) {
299
- console.warn("[OAuthFlow] \u26A0\uFE0F Error parsing key:", key, e);
300
- }
301
- }
302
- }
303
- }
95
+ console.error("[OAuthFlow] Error parsing localStorage callback:", error);
304
96
  }
305
97
  }
306
98
  }, 100);
307
- let broadcastChannel = null;
308
- try {
309
- broadcastChannel = new BroadcastChannel("omenx_oauth");
310
- const broadcastListener = (event) => {
311
- if (event.data?.type === "OMENX_OAUTH_CODE" && event.data?.state === state) {
312
- console.log("[OAuthFlow] \u2705 Received OAuth code via BroadcastChannel");
313
- messageReceived = true;
314
- clearInterval(pollInterval);
315
- if (broadcastChannel) {
316
- broadcastChannel.onmessage = null;
317
- broadcastChannel.close();
318
- }
319
- window.removeEventListener("message", wrappedMessageListener);
320
- window.removeEventListener("storage", storageListener);
321
- const { code: codeFromBroadcast } = event.data;
322
- const storedCodeVerifier = sessionStorage.getItem(`omenx_pkce_${state}`);
323
- let codeVerifier2;
324
- if (storedCodeVerifier) {
325
- sessionStorage.removeItem(`omenx_pkce_${state}`);
326
- codeVerifier2 = storedCodeVerifier;
327
- }
328
- this.exchangeCodeForToken(codeFromBroadcast, options.redirectUri, codeVerifier2).then(async (tokenResponse) => {
329
- await this.config.onTokenReceived(tokenResponse);
330
- resolve(tokenResponse);
331
- }).catch((error) => {
332
- this.config.onError?.(error);
333
- reject(error);
334
- });
335
- }
336
- };
337
- broadcastChannel.onmessage = broadcastListener;
338
- } catch (error) {
339
- console.warn("[OAuthFlow] BroadcastChannel not supported:", error);
340
- broadcastChannel = null;
341
- }
342
- console.log("[OAuthFlow] \u{1F50D} Starting OAuth flow, listening for callback...", {
343
- state,
344
- statePreview: state.substring(0, 20) + "...",
345
- stateLength: state.length,
346
- hasOpener: !!window.opener,
347
- polling: true,
348
- broadcastChannel: true,
349
- expectedKey: `omenx_oauth_callback_${state}`
350
- });
351
- let messageReceived = false;
352
- const originalMessageListener = messageListener;
353
- const wrappedMessageListener = async (event) => {
354
- messageReceived = true;
355
- clearInterval(pollInterval);
356
- window.removeEventListener("storage", storageListener);
357
- await originalMessageListener(event);
358
- };
359
- window.removeEventListener("message", messageListener);
360
- window.addEventListener("message", wrappedMessageListener);
361
- const isPopupActuallyClosed = () => {
362
- try {
363
- if (!popup.closed) {
364
- return false;
365
- }
366
- try {
367
- const _ = popup.location.href;
368
- return true;
369
- } catch (e) {
370
- return false;
371
- }
372
- } catch (e) {
373
- return false;
374
- }
375
- };
376
99
  const checkClosed = setInterval(() => {
377
100
  if (messageReceived) {
101
+ clearInterval(checkClosed);
378
102
  return;
379
103
  }
380
- if (isPopupActuallyClosed()) {
104
+ let isClosed = false;
105
+ try {
106
+ if (popup.closed) {
107
+ try {
108
+ popup.location.href;
109
+ isClosed = true;
110
+ } catch (e) {
111
+ isClosed = false;
112
+ }
113
+ }
114
+ } catch (e) {
115
+ isClosed = false;
116
+ }
117
+ if (isClosed) {
381
118
  clearInterval(checkClosed);
382
119
  clearInterval(pollInterval);
383
- window.removeEventListener("message", wrappedMessageListener);
384
- window.removeEventListener("storage", storageListener);
385
- if (broadcastChannel) {
386
- broadcastChannel.onmessage = null;
387
- broadcastChannel.close();
388
- }
389
- if (!messageReceived) {
390
- const error = new Error("Authentication was cancelled.");
391
- this.config.onError?.(error);
392
- reject(error);
393
- }
120
+ sessionStorage.removeItem(`omenx_pkce_${state}`);
121
+ sessionStorage.removeItem(stateStorageKey);
122
+ const error = new Error("Authentication was cancelled.");
123
+ this.config.onError?.(error);
124
+ reject(error);
394
125
  }
395
126
  }, 1e3);
396
127
  });
@@ -402,7 +133,8 @@ var OAuthFlow = class {
402
133
  const body = {
403
134
  code,
404
135
  redirect_uri: redirectUri,
405
- grant_type: "authorization_code"
136
+ grant_type: "authorization_code",
137
+ client_id: this.config.gameId
406
138
  };
407
139
  if (codeVerifier) {
408
140
  body.code_verifier = codeVerifier;
@@ -411,8 +143,6 @@ var OAuthFlow = class {
411
143
  method: "POST",
412
144
  headers: {
413
145
  "Content-Type": "application/json"
414
- // Note: API key should be included via Authorization header
415
- // This should be set by the game's backend, not the SDK
416
146
  },
417
147
  body: JSON.stringify(body)
418
148
  });
@@ -430,6 +160,25 @@ var OAuthFlow = class {
430
160
  crypto.getRandomValues(array);
431
161
  return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join("");
432
162
  }
163
+ /**
164
+ * Generate PKCE code verifier
165
+ */
166
+ generateCodeVerifier() {
167
+ const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
168
+ const array = new Uint8Array(128);
169
+ crypto.getRandomValues(array);
170
+ return Array.from(array, (byte) => charset[byte % charset.length]).join("");
171
+ }
172
+ /**
173
+ * Generate PKCE code challenge from verifier
174
+ */
175
+ async generateCodeChallenge(verifier) {
176
+ const encoder = new TextEncoder();
177
+ const data = encoder.encode(verifier);
178
+ const hash = await crypto.subtle.digest("SHA-256", data);
179
+ const base64 = btoa(String.fromCharCode(...new Uint8Array(hash)));
180
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
181
+ }
433
182
  };
434
183
 
435
184
  // src/iframe-auth.ts
@@ -623,7 +372,17 @@ var OmenXGameSDK = class {
623
372
  * Authenticate user via OAuth popup
624
373
  */
625
374
  async authenticate(options) {
626
- return this.oauthFlow.authenticate(options);
375
+ const tokenResponse = await this.oauthFlow.authenticate(options);
376
+ return {
377
+ accessToken: tokenResponse.access_token,
378
+ walletAddress: tokenResponse.user.walletAddress,
379
+ userId: tokenResponse.user.userId,
380
+ profileName: tokenResponse.user.profileName,
381
+ profilePicture: tokenResponse.user.profilePicture,
382
+ email: tokenResponse.user.email,
383
+ gameId: this.config.gameId,
384
+ timestamp: Date.now()
385
+ };
627
386
  }
628
387
  /**
629
388
  * Get current authentication data
@@ -796,22 +555,38 @@ var OmenXServerSDK = class {
796
555
  /**
797
556
  * Player Operations
798
557
  */
558
+ /**
559
+ * Get full player data: NFTs (system + game) and balances for a wallet.
560
+ * Requires both nfts:read and balances:read scopes.
561
+ */
562
+ async getPlayer(wallet, chainId) {
563
+ const response = await this.apiCall(
564
+ `/v1/players/${encodeURIComponent(wallet)}?chainId=${encodeURIComponent(chainId)}`
565
+ );
566
+ return response.json();
567
+ }
799
568
  /**
800
569
  * Get native and ERC20 token balances for a wallet
801
570
  */
802
571
  async getPlayerBalances(wallet, chainId) {
803
- const response = await this.apiCall(`/v1/players/${wallet}/balances?chainId=${chainId}`);
572
+ const response = await this.apiCall(
573
+ `/v1/players/${encodeURIComponent(wallet)}/balances?chainId=${encodeURIComponent(chainId)}`
574
+ );
804
575
  return response.json();
805
576
  }
806
577
  /**
807
- * Get paginated NFTs for a wallet
578
+ * Get paginated NFTs for a wallet.
579
+ * With no contract: returns OmenX system NFTs (Asset Manager, Faucet, Early Adopter) + game NFTs.
580
+ * With contract: returns only NFTs for that contract.
808
581
  */
809
582
  async getPlayerNfts(wallet, chainId, options) {
810
583
  const params = new URLSearchParams({ chainId });
811
- if (options?.contract) params.append("contract", options.contract);
812
- if (options?.cursor) params.append("cursor", options.cursor);
813
- if (options?.limit) params.append("limit", options.limit.toString());
814
- const response = await this.apiCall(`/v1/players/${wallet}/nfts?${params.toString()}`);
584
+ if (options?.contract) params.set("contract", options.contract);
585
+ if (options?.cursor) params.set("cursor", options.cursor);
586
+ if (options?.limit != null) params.set("limit", String(options.limit));
587
+ const response = await this.apiCall(
588
+ `/v1/players/${encodeURIComponent(wallet)}/nfts?${params.toString()}`
589
+ );
815
590
  return response.json();
816
591
  }
817
592
  /**