@omen.foundation/game-sdk 1.0.18 → 1.0.20

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
@@ -256,11 +256,19 @@ declare class OmenXServerSDK {
256
256
  cursor?: string;
257
257
  limit?: number;
258
258
  }): Promise<any>;
259
+ /**
260
+ * Product catalog for the authenticated game (from API key).
261
+ * Returns active products with priceUsd and pricesInCurrency (amount per BNB, OMENX, GMT, etc.).
262
+ * Optional chainId for display (defaults to API chain).
263
+ */
264
+ getProducts(chainId?: string): Promise<any>;
259
265
  /**
260
266
  * Purchase Operations
261
267
  */
262
268
  /**
263
- * Create a server-authoritative purchase
269
+ * Create a server-authoritative purchase.
270
+ * For on-chain payment: set paymentCurrency (e.g. "BNB", "OMENX", "GMT") and paymentAmount.
271
+ * Balance is validated for that token on the BNB chain; any token with balance >= paymentAmount is allowed.
264
272
  */
265
273
  createPurchase(params: {
266
274
  playerWallet?: string;
@@ -269,6 +277,12 @@ declare class OmenXServerSDK {
269
277
  sku?: string;
270
278
  quantity?: number;
271
279
  idempotencyKey?: string;
280
+ /** Currency the player pays with (e.g. "BNB", "OMENX", "GMT"). Required when paymentAmount is set. */
281
+ paymentCurrency?: string;
282
+ /** Amount of paymentCurrency to spend. Validated against on-chain balance. */
283
+ paymentAmount?: number;
284
+ /** @deprecated Use paymentCurrency "OMENX" and paymentAmount instead. */
285
+ amountInOmenx?: number;
272
286
  paymentMethod?: string;
273
287
  metadata?: Record<string, any>;
274
288
  }): Promise<any>;
@@ -482,12 +496,19 @@ interface SubscribeWalletRealtimeWithOmenXAuthOptions {
482
496
  walletAddress: string;
483
497
  onBalance?: (payload: RealtimeWalletPayload) => void;
484
498
  onInventory?: (payload: RealtimeWalletPayload) => void;
499
+ /** Optional. Called when the Ably connection fails or is suspended (e.g. server unavailable). App can log or show a non-blocking toast; realtime will degrade gracefully. */
500
+ onConnectionError?: (message: string) => void;
485
501
  }
486
502
  /**
487
503
  * Subscribe to real-time balance and inventory for a wallet using OmenX platform auth.
488
504
  * The SDK fetches a short-lived, subscribe-only Ably token from the OmenX API using your
489
505
  * access token. No Ably API key or .env is required – ideal for third-party developers.
490
506
  *
507
+ * If the token endpoint is unavailable (e.g. backend down), no Ably client is created and
508
+ * the function returns a no-op unsubscribe so the app does not crash. Connection
509
+ * failures/suspensions are handled and reported via onConnectionError so they do not
510
+ * surface as uncaught errors.
511
+ *
491
512
  * Requires the app to have `ably` installed (peer dependency). Call when the user is
492
513
  * logged in; call the returned function on logout or wallet change.
493
514
  */
package/dist/index.d.ts CHANGED
@@ -256,11 +256,19 @@ declare class OmenXServerSDK {
256
256
  cursor?: string;
257
257
  limit?: number;
258
258
  }): Promise<any>;
259
+ /**
260
+ * Product catalog for the authenticated game (from API key).
261
+ * Returns active products with priceUsd and pricesInCurrency (amount per BNB, OMENX, GMT, etc.).
262
+ * Optional chainId for display (defaults to API chain).
263
+ */
264
+ getProducts(chainId?: string): Promise<any>;
259
265
  /**
260
266
  * Purchase Operations
261
267
  */
262
268
  /**
263
- * Create a server-authoritative purchase
269
+ * Create a server-authoritative purchase.
270
+ * For on-chain payment: set paymentCurrency (e.g. "BNB", "OMENX", "GMT") and paymentAmount.
271
+ * Balance is validated for that token on the BNB chain; any token with balance >= paymentAmount is allowed.
264
272
  */
265
273
  createPurchase(params: {
266
274
  playerWallet?: string;
@@ -269,6 +277,12 @@ declare class OmenXServerSDK {
269
277
  sku?: string;
270
278
  quantity?: number;
271
279
  idempotencyKey?: string;
280
+ /** Currency the player pays with (e.g. "BNB", "OMENX", "GMT"). Required when paymentAmount is set. */
281
+ paymentCurrency?: string;
282
+ /** Amount of paymentCurrency to spend. Validated against on-chain balance. */
283
+ paymentAmount?: number;
284
+ /** @deprecated Use paymentCurrency "OMENX" and paymentAmount instead. */
285
+ amountInOmenx?: number;
272
286
  paymentMethod?: string;
273
287
  metadata?: Record<string, any>;
274
288
  }): Promise<any>;
@@ -482,12 +496,19 @@ interface SubscribeWalletRealtimeWithOmenXAuthOptions {
482
496
  walletAddress: string;
483
497
  onBalance?: (payload: RealtimeWalletPayload) => void;
484
498
  onInventory?: (payload: RealtimeWalletPayload) => void;
499
+ /** Optional. Called when the Ably connection fails or is suspended (e.g. server unavailable). App can log or show a non-blocking toast; realtime will degrade gracefully. */
500
+ onConnectionError?: (message: string) => void;
485
501
  }
486
502
  /**
487
503
  * Subscribe to real-time balance and inventory for a wallet using OmenX platform auth.
488
504
  * The SDK fetches a short-lived, subscribe-only Ably token from the OmenX API using your
489
505
  * access token. No Ably API key or .env is required – ideal for third-party developers.
490
506
  *
507
+ * If the token endpoint is unavailable (e.g. backend down), no Ably client is created and
508
+ * the function returns a no-op unsubscribe so the app does not crash. Connection
509
+ * failures/suspensions are handled and reported via onConnectionError so they do not
510
+ * surface as uncaught errors.
511
+ *
491
512
  * Requires the app to have `ably` installed (peer dependency). Call when the user is
492
513
  * logged in; call the returned function on logout or wallet change.
493
514
  */
package/dist/index.js CHANGED
@@ -616,11 +616,23 @@ var OmenXServerSDK = class {
616
616
  );
617
617
  return response.json();
618
618
  }
619
+ /**
620
+ * Product catalog for the authenticated game (from API key).
621
+ * Returns active products with priceUsd and pricesInCurrency (amount per BNB, OMENX, GMT, etc.).
622
+ * Optional chainId for display (defaults to API chain).
623
+ */
624
+ async getProducts(chainId) {
625
+ const params = chainId != null ? `?chainId=${encodeURIComponent(chainId)}` : "";
626
+ const response = await this.apiCall(`/v1/products${params}`);
627
+ return response.json();
628
+ }
619
629
  /**
620
630
  * Purchase Operations
621
631
  */
622
632
  /**
623
- * Create a server-authoritative purchase
633
+ * Create a server-authoritative purchase.
634
+ * For on-chain payment: set paymentCurrency (e.g. "BNB", "OMENX", "GMT") and paymentAmount.
635
+ * Balance is validated for that token on the BNB chain; any token with balance >= paymentAmount is allowed.
624
636
  */
625
637
  async createPurchase(params) {
626
638
  const response = await this.apiCall("/v1/purchases", {
@@ -825,13 +837,23 @@ function subscribeWalletRealtime(ably, walletAddress, callbacks) {
825
837
  };
826
838
  }
827
839
  function subscribeWalletRealtimeWithOmenXAuth(options) {
828
- const { apiBaseUrl, getAccessToken, walletAddress, onBalance, onInventory } = options;
840
+ const { apiBaseUrl, getAccessToken, walletAddress, onBalance, onInventory, onConnectionError } = options;
829
841
  const normalized = (walletAddress || "").trim().toLowerCase();
830
842
  if (!normalized || !/^0x[a-fa-f0-9]{40}$/.test(normalized)) {
831
843
  return () => {
832
844
  };
833
845
  }
834
846
  const base = apiBaseUrl.replace(/\/$/, "");
847
+ const reportConnectionError = (message) => {
848
+ if (onConnectionError) {
849
+ try {
850
+ onConnectionError(message);
851
+ } catch {
852
+ }
853
+ } else {
854
+ console.warn("[OmenX Realtime]", message);
855
+ }
856
+ };
835
857
  const authCallback = (_tokenParams, callback) => {
836
858
  getAccessToken().then((token) => {
837
859
  if (!token) {
@@ -859,17 +881,72 @@ function subscribeWalletRealtimeWithOmenXAuth(options) {
859
881
  callback(err instanceof Error ? err.message : String(err), null);
860
882
  });
861
883
  };
862
- const ably = new Ably__default.default.Realtime({
863
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
864
- authCallback
884
+ let ably = null;
885
+ let unsubscribeChannel = null;
886
+ let cancelled = false;
887
+ const cleanup = () => {
888
+ cancelled = true;
889
+ if (unsubscribeChannel) {
890
+ try {
891
+ unsubscribeChannel();
892
+ } catch {
893
+ }
894
+ unsubscribeChannel = null;
895
+ }
896
+ if (ably) {
897
+ try {
898
+ ably.close();
899
+ } catch {
900
+ }
901
+ ably = null;
902
+ }
903
+ };
904
+ const tokenPromise = getAccessToken().then((token) => {
905
+ if (!token) return null;
906
+ return fetch(`${base}/api/sdk/ably-token`, {
907
+ method: "POST",
908
+ headers: {
909
+ Authorization: `Bearer ${token}`,
910
+ "Content-Type": "application/json"
911
+ }
912
+ });
865
913
  });
866
- const unsubscribe = subscribeWalletRealtime(ably, walletAddress, {
867
- onBalance,
868
- onInventory
914
+ tokenPromise.then((res) => {
915
+ if (cancelled) return;
916
+ if (res === null) {
917
+ reportConnectionError("Realtime skipped: not authenticated");
918
+ return;
919
+ }
920
+ if (!res.ok) {
921
+ reportConnectionError(`Realtime unavailable: ${res.status}`);
922
+ return;
923
+ }
924
+ return res.json();
925
+ }).then((tokenRequest) => {
926
+ if (cancelled || tokenRequest === void 0) return;
927
+ ably = new Ably__default.default.Realtime({
928
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
929
+ authCallback
930
+ });
931
+ ably.connection.on("failed", (stateChange) => {
932
+ const msg = stateChange?.reason?.message ?? "Connection failed";
933
+ reportConnectionError(msg);
934
+ });
935
+ ably.connection.on("suspended", (stateChange) => {
936
+ const msg = stateChange?.reason?.message ?? "Connection to server unavailable";
937
+ reportConnectionError(msg);
938
+ });
939
+ unsubscribeChannel = subscribeWalletRealtime(ably, walletAddress, {
940
+ onBalance,
941
+ onInventory
942
+ });
943
+ }).catch((err) => {
944
+ if (!cancelled) {
945
+ reportConnectionError(err instanceof Error ? err.message : "Realtime setup failed");
946
+ }
869
947
  });
870
948
  return () => {
871
- unsubscribe();
872
- ably.close();
949
+ cleanup();
873
950
  };
874
951
  }
875
952
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/oauth.ts","../src/iframe-auth.ts","../src/token-manager.ts","../src/sdk.ts","../src/server-sdk.ts","../src/realtime.ts"],"names":["Ably"],"mappings":"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","file":"index.js","sourcesContent":["import type { OAuthTokenResponse, OAuthOptions } from './types';\r\n\r\ninterface OAuthFlowConfig {\r\n gameId: string;\r\n oauthAuthorizeUrl: string;\r\n oauthTokenUrl: string;\r\n apiBaseUrl: string;\r\n onTokenReceived: (token: OAuthTokenResponse) => Promise<void>;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\nexport class OAuthFlow {\r\n private config: OAuthFlowConfig;\r\n\r\n constructor(config: OAuthFlowConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Authenticate user via OAuth 2.0 Authorization Code Grant with PKCE\r\n */\r\n async authenticate(options: OAuthOptions = {}): Promise<OAuthTokenResponse> {\r\n // Generate state for CSRF protection\r\n const state = this.generateState();\r\n \r\n // Generate PKCE code verifier and challenge\r\n const codeVerifier = this.generateCodeVerifier();\r\n const codeChallenge = await this.generateCodeChallenge(codeVerifier);\r\n \r\n return new Promise((resolve, reject) => {\r\n \r\n // Store code verifier in sessionStorage for later use\r\n sessionStorage.setItem(`omenx_pkce_${state}`, codeVerifier);\r\n \r\n // Build authorization URL\r\n const redirectUri = options.redirectUri || `${window.location.origin}/auth/callback`;\r\n const authUrl = new URL(this.config.oauthAuthorizeUrl);\r\n authUrl.searchParams.set('client_id', this.config.gameId);\r\n authUrl.searchParams.set('redirect_uri', redirectUri);\r\n authUrl.searchParams.set('response_type', 'code');\r\n authUrl.searchParams.set('scope', 'openid profile email');\r\n authUrl.searchParams.set('state', state);\r\n authUrl.searchParams.set('code_challenge', codeChallenge);\r\n authUrl.searchParams.set('code_challenge_method', 'S256');\r\n \r\n // Store state for verification\r\n const stateStorageKey = `omenx_oauth_state_${state}`;\r\n sessionStorage.setItem(stateStorageKey, state);\r\n \r\n // Open popup window\r\n const popup = window.open(\r\n authUrl.toString(),\r\n 'OmenX OAuth',\r\n 'width=500,height=600,left=100,top=100'\r\n );\r\n\r\n if (!popup) {\r\n const error = new Error('Failed to open popup window. Please allow popups for this site.');\r\n this.config.onError?.(error);\r\n reject(error);\r\n return;\r\n }\r\n\r\n // Clean up old OAuth callback entries from localStorage\r\n try {\r\n const allKeys = Object.keys(localStorage).filter(k => k.startsWith('omenx_oauth_callback_'));\r\n allKeys.forEach(key => {\r\n try {\r\n const data = localStorage.getItem(key);\r\n if (data) {\r\n const parsed = JSON.parse(data);\r\n const age = Date.now() - (parsed.timestamp || 0);\r\n // Remove entries older than 5 minutes\r\n if (age > 300000) {\r\n localStorage.removeItem(key);\r\n }\r\n }\r\n } catch (e) {\r\n localStorage.removeItem(key);\r\n }\r\n });\r\n } catch (error) {\r\n // Ignore cleanup errors\r\n }\r\n\r\n // Poll localStorage for callback data\r\n const storageKey = `omenx_oauth_callback_${state}`;\r\n let messageReceived = false;\r\n \r\n const pollInterval = setInterval(() => {\r\n if (messageReceived) {\r\n clearInterval(pollInterval);\r\n return;\r\n }\r\n \r\n const stored = localStorage.getItem(storageKey);\r\n \r\n if (stored) {\r\n try {\r\n const data = JSON.parse(stored);\r\n \r\n // Validate state and check timestamp\r\n if (data.code && data.state === state) {\r\n const age = Date.now() - (data.timestamp || 0);\r\n if (age < 30000) { // 30 second timeout\r\n messageReceived = true;\r\n clearInterval(pollInterval);\r\n \r\n // Clean up\r\n localStorage.removeItem(storageKey);\r\n sessionStorage.removeItem(`omenx_pkce_${state}`);\r\n sessionStorage.removeItem(stateStorageKey);\r\n \r\n // Exchange code for token\r\n this.exchangeCodeForToken(data.code, redirectUri, codeVerifier)\r\n .then(async (tokenResponse) => {\r\n await this.config.onTokenReceived(tokenResponse);\r\n // Close popup after successful token exchange\r\n if (popup && !popup.closed) {\r\n try {\r\n popup.close();\r\n } catch (e) {\r\n // Ignore errors closing popup\r\n }\r\n }\r\n resolve(tokenResponse);\r\n })\r\n .catch((error) => {\r\n this.config.onError?.(error as Error);\r\n reject(error);\r\n });\r\n return;\r\n } else {\r\n // Data too old, remove it\r\n localStorage.removeItem(storageKey);\r\n }\r\n }\r\n } catch (error) {\r\n console.error('[OAuthFlow] Error parsing localStorage callback:', error);\r\n }\r\n }\r\n }, 100); // Poll every 100ms\r\n \r\n // Check if popup was closed without completing auth\r\n const checkClosed = setInterval(() => {\r\n if (messageReceived) {\r\n clearInterval(checkClosed);\r\n return;\r\n }\r\n \r\n // Check if popup is actually closed\r\n let isClosed = false;\r\n try {\r\n if (popup.closed) {\r\n try {\r\n // Try to access location to verify it's actually closed\r\n popup.location.href; // Accessing this will throw if popup is on different origin\r\n isClosed = true;\r\n } catch (e) {\r\n // Can't access location - popup is on different origin (still open)\r\n isClosed = false;\r\n }\r\n }\r\n } catch (e) {\r\n isClosed = false;\r\n }\r\n \r\n if (isClosed) {\r\n clearInterval(checkClosed);\r\n clearInterval(pollInterval);\r\n \r\n // Clean up\r\n sessionStorage.removeItem(`omenx_pkce_${state}`);\r\n sessionStorage.removeItem(stateStorageKey);\r\n \r\n const error = new Error('Authentication was cancelled.');\r\n this.config.onError?.(error);\r\n reject(error);\r\n }\r\n }, 1000);\r\n });\r\n }\r\n\r\n /**\r\n * Exchange authorization code for access token\r\n */\r\n private async exchangeCodeForToken(\r\n code: string,\r\n redirectUri: string,\r\n codeVerifier?: string\r\n ): Promise<OAuthTokenResponse> {\r\n const body: any = {\r\n code,\r\n redirect_uri: redirectUri,\r\n grant_type: 'authorization_code',\r\n client_id: this.config.gameId,\r\n };\r\n\r\n if (codeVerifier) {\r\n body.code_verifier = codeVerifier;\r\n }\r\n\r\n const response = await fetch(this.config.oauthTokenUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.json().catch(() => ({ message: 'Failed to exchange code for token' }));\r\n throw new Error(error.message || 'Failed to exchange code for token');\r\n }\r\n\r\n return response.json();\r\n }\r\n\r\n /**\r\n * Generate random state for CSRF protection\r\n */\r\n private generateState(): string {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\r\n }\r\n\r\n /**\r\n * Generate PKCE code verifier\r\n */\r\n private generateCodeVerifier(): string {\r\n const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';\r\n const array = new Uint8Array(128);\r\n crypto.getRandomValues(array);\r\n return Array.from(array, byte => charset[byte % charset.length]).join('');\r\n }\r\n\r\n /**\r\n * Generate PKCE code challenge from verifier\r\n */\r\n private async generateCodeChallenge(verifier: string): Promise<string> {\r\n const encoder = new TextEncoder();\r\n const data = encoder.encode(verifier);\r\n const hash = await crypto.subtle.digest('SHA-256', data);\r\n const base64 = btoa(String.fromCharCode(...new Uint8Array(hash)));\r\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\r\n }\r\n}\r\n","import type { AuthData } from './types';\r\n\r\ninterface IframeAuthConfig {\r\n gameId: string;\r\n parentOrigin?: string;\r\n onAuth: (authData: AuthData) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/**\r\n * Handles authentication data passed from parent window via postMessage\r\n */\r\nexport class IframeAuth {\r\n private config: IframeAuthConfig;\r\n private messageListener: ((event: MessageEvent) => void) | null = null;\r\n\r\n constructor(config: IframeAuthConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Initialize iframe authentication listener\r\n */\r\n init(): void {\r\n // Request auth data from parent\r\n this.requestAuth();\r\n\r\n // Listen for auth data from parent\r\n this.messageListener = (event: MessageEvent) => {\r\n // Validate origin if specified\r\n if (this.config.parentOrigin) {\r\n try {\r\n const parentUrl = new URL(this.config.parentOrigin);\r\n if (event.origin !== parentUrl.origin) {\r\n return;\r\n }\r\n } catch {\r\n // If we can't parse parent origin, skip validation (development)\r\n }\r\n }\r\n\r\n // Handle auth data\r\n if (event.data?.type === 'OMENX_AUTH') {\r\n const authData = event.data.payload as AuthData;\r\n\r\n // Validate game ID\r\n if (authData.gameId !== this.config.gameId) {\r\n this.config.onError?.(new Error(`Game ID mismatch. Expected ${this.config.gameId}, got ${authData.gameId}`));\r\n return;\r\n }\r\n\r\n // Validate timestamp (5 minute expiry)\r\n const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);\r\n if (authData.timestamp < fiveMinutesAgo) {\r\n this.config.onError?.(new Error('Auth data expired'));\r\n return;\r\n }\r\n\r\n this.config.onAuth(authData);\r\n }\r\n };\r\n\r\n window.addEventListener('message', this.messageListener);\r\n }\r\n\r\n /**\r\n * Request authentication data from parent window\r\n */\r\n private requestAuth(): void {\r\n if (window.parent === window) {\r\n // Not in an iframe\r\n return;\r\n }\r\n\r\n // Send request to parent\r\n const parentOrigin = this.config.parentOrigin || '*';\r\n window.parent.postMessage(\r\n {\r\n type: 'OMENX_AUTH_REQUEST',\r\n gameId: this.config.gameId,\r\n },\r\n parentOrigin\r\n );\r\n }\r\n\r\n /**\r\n * Cleanup\r\n */\r\n destroy(): void {\r\n if (this.messageListener) {\r\n window.removeEventListener('message', this.messageListener);\r\n this.messageListener = null;\r\n }\r\n }\r\n}\r\n","import type { AuthData } from './types';\r\n\r\n/**\r\n * Manages token storage and retrieval\r\n */\r\nexport class TokenManager {\r\n private storageKeyPrefix: string;\r\n\r\n constructor(storageKeyPrefix: string = 'omenx_game_') {\r\n this.storageKeyPrefix = storageKeyPrefix;\r\n }\r\n\r\n /**\r\n * Store authentication data\r\n */\r\n storeAuth(authData: AuthData, refreshToken: string, expiresIn: number): void {\r\n try {\r\n localStorage.setItem(`${this.storageKeyPrefix}auth`, JSON.stringify(authData));\r\n localStorage.setItem(`${this.storageKeyPrefix}refresh_token`, refreshToken);\r\n localStorage.setItem(`${this.storageKeyPrefix}expires_at`, String(Date.now() + (expiresIn * 1000)));\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to store auth data:', error);\r\n }\r\n }\r\n\r\n /**\r\n * Get stored authentication data\r\n */\r\n getStoredAuth(): AuthData | null {\r\n try {\r\n const stored = localStorage.getItem(`${this.storageKeyPrefix}auth`);\r\n if (!stored) {\r\n return null;\r\n }\r\n return JSON.parse(stored) as AuthData;\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to retrieve auth data:', error);\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Get stored refresh token\r\n */\r\n getRefreshToken(): string | null {\r\n try {\r\n return localStorage.getItem(`${this.storageKeyPrefix}refresh_token`);\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to retrieve refresh token:', error);\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Clear all stored authentication data\r\n */\r\n clearStorage(): void {\r\n try {\r\n localStorage.removeItem(`${this.storageKeyPrefix}auth`);\r\n localStorage.removeItem(`${this.storageKeyPrefix}refresh_token`);\r\n localStorage.removeItem(`${this.storageKeyPrefix}expires_at`);\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to clear storage:', error);\r\n }\r\n }\r\n}\r\n","import type {\r\n OmenXGameSDKConfig,\r\n AuthData,\r\n OAuthOptions,\r\n OAuthTokenResponse,\r\n ApiCallOptions,\r\n VipStatus,\r\n} from './types';\r\nimport { OAuthFlow } from './oauth';\r\nimport { IframeAuth } from './iframe-auth';\r\nimport { TokenManager } from './token-manager';\r\n\r\n/**\r\n * OmenX Game SDK\r\n * \r\n * Provides authentication and API integration for games on the OmenX platform.\r\n * Supports both OAuth-style authentication and iframe authentication passing.\r\n */\r\nexport class OmenXGameSDK {\r\n private config: Required<OmenXGameSDKConfig>;\r\n private oauthFlow: OAuthFlow;\r\n private iframeAuth: IframeAuth | null = null;\r\n private tokenManager: TokenManager;\r\n private currentAuthData: AuthData | null = null;\r\n\r\n constructor(config: OmenXGameSDKConfig) {\r\n // Set defaults\r\n const apiBaseUrl = config.apiBaseUrl || 'https://api.omen.foundation';\r\n this.config = {\r\n gameId: config.gameId,\r\n apiBaseUrl: apiBaseUrl,\r\n oauthAuthorizeUrl: config.oauthAuthorizeUrl || `${apiBaseUrl}/v1/oauth/authorize`,\r\n oauthTokenUrl: config.oauthTokenUrl || `${apiBaseUrl}/v1/oauth/token`,\r\n onAuth: config.onAuth || (() => {}),\r\n onAuthError: config.onAuthError || ((error) => console.error('[OmenX SDK] Auth error:', error)),\r\n onLogout: config.onLogout || (() => {}),\r\n enableIframeAuth: config.enableIframeAuth !== false,\r\n parentOrigin: config.parentOrigin ?? '',\r\n storageKeyPrefix: config.storageKeyPrefix || 'omenx_game_',\r\n };\r\n\r\n // Initialize components\r\n this.tokenManager = new TokenManager(this.config.storageKeyPrefix);\r\n this.oauthFlow = new OAuthFlow({\r\n gameId: this.config.gameId,\r\n oauthAuthorizeUrl: this.config.oauthAuthorizeUrl,\r\n oauthTokenUrl: this.config.oauthTokenUrl,\r\n apiBaseUrl: this.config.apiBaseUrl,\r\n onTokenReceived: this.handleTokenReceived.bind(this),\r\n onError: this.config.onAuthError,\r\n });\r\n\r\n if (this.config.enableIframeAuth) {\r\n this.iframeAuth = new IframeAuth({\r\n gameId: this.config.gameId,\r\n parentOrigin: this.config.parentOrigin || undefined,\r\n onAuth: this.handleAuthData.bind(this),\r\n onError: this.config.onAuthError,\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Initialize the SDK\r\n * Call this after creating an instance\r\n */\r\n async init(): Promise<void> {\r\n // Try to restore from stored token\r\n const storedAuth = this.tokenManager.getStoredAuth();\r\n if (storedAuth) {\r\n // Check if token is still valid (not expired)\r\n const expiresAt = storedAuth.timestamp + (3600 * 1000); // 1 hour default\r\n if (Date.now() < expiresAt) {\r\n this.currentAuthData = storedAuth;\r\n this.config.onAuth(storedAuth);\r\n return;\r\n } else {\r\n // Token expired, try to refresh\r\n const refreshToken = this.tokenManager.getRefreshToken();\r\n if (refreshToken) {\r\n try {\r\n await this.refreshAccessToken(refreshToken);\r\n return;\r\n } catch (error) {\r\n // Refresh failed, clear storage\r\n this.tokenManager.clearStorage();\r\n }\r\n }\r\n }\r\n }\r\n\r\n // If iframe auth is enabled, try to get auth from parent\r\n if (this.config.enableIframeAuth && this.iframeAuth !== null) {\r\n this.iframeAuth.init();\r\n }\r\n }\r\n\r\n /**\r\n * Authenticate user via OAuth popup\r\n */\r\n async authenticate(options: OAuthOptions): Promise<AuthData> {\r\n const tokenResponse = await this.oauthFlow.authenticate(options);\r\n // Convert OAuthTokenResponse to AuthData\r\n return {\r\n accessToken: tokenResponse.access_token,\r\n walletAddress: tokenResponse.user.walletAddress,\r\n userId: tokenResponse.user.userId,\r\n profileName: tokenResponse.user.profileName,\r\n profilePicture: tokenResponse.user.profilePicture,\r\n email: tokenResponse.user.email,\r\n gameId: this.config.gameId,\r\n timestamp: Date.now(),\r\n };\r\n }\r\n\r\n /**\r\n * Get current authentication data\r\n */\r\n getAuthData(): AuthData | null {\r\n return this.currentAuthData;\r\n }\r\n\r\n /**\r\n * Check if user is authenticated\r\n */\r\n isAuthenticated(): boolean {\r\n return this.currentAuthData !== null;\r\n }\r\n\r\n /**\r\n * Logout user\r\n */\r\n async logout(): Promise<void> {\r\n // Revoke token if we have one\r\n if (this.currentAuthData?.accessToken) {\r\n try {\r\n await this.apiCall('/v1/oauth/revoke', {\r\n method: 'POST',\r\n body: { token: this.currentAuthData.accessToken },\r\n includeAuth: false, // Don't include auth header for revoke\r\n });\r\n } catch (error) {\r\n // Ignore errors on revoke\r\n console.warn('[OmenX SDK] Failed to revoke token:', error);\r\n }\r\n }\r\n\r\n // Clear local state\r\n this.currentAuthData = null;\r\n this.tokenManager.clearStorage();\r\n this.config.onLogout();\r\n }\r\n\r\n /**\r\n * Make an authenticated API call\r\n */\r\n async apiCall(endpoint: string, options: ApiCallOptions = {}): Promise<Response> {\r\n const url = endpoint.startsWith('http') \r\n ? endpoint \r\n : `${this.config.apiBaseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;\r\n\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n ...options.headers,\r\n };\r\n\r\n // Add authentication header if needed\r\n if (options.includeAuth !== false && this.currentAuthData?.accessToken) {\r\n headers['Authorization'] = `Bearer ${this.currentAuthData.accessToken}`;\r\n }\r\n\r\n const fetchOptions: RequestInit = {\r\n method: options.method || 'GET',\r\n headers,\r\n };\r\n\r\n if (options.body && options.method !== 'GET') {\r\n fetchOptions.body = JSON.stringify(options.body);\r\n }\r\n\r\n const response = await fetch(url, fetchOptions);\r\n\r\n // If unauthorized, try to refresh token\r\n if (response.status === 401 && this.currentAuthData) {\r\n const refreshToken = this.tokenManager.getRefreshToken();\r\n if (refreshToken) {\r\n try {\r\n await this.refreshAccessToken(refreshToken);\r\n // Retry the request with new token\r\n if (this.currentAuthData?.accessToken) {\r\n headers['Authorization'] = `Bearer ${this.currentAuthData.accessToken}`;\r\n return fetch(url, { ...fetchOptions, headers });\r\n }\r\n } catch (error) {\r\n // Refresh failed, logout\r\n await this.logout();\r\n throw new Error('Authentication expired. Please login again.');\r\n }\r\n }\r\n }\r\n\r\n return response;\r\n }\r\n\r\n /**\r\n * Handle token received from OAuth flow\r\n */\r\n private async handleTokenReceived(tokenResponse: OAuthTokenResponse): Promise<void> {\r\n const authData: AuthData = {\r\n accessToken: tokenResponse.access_token,\r\n walletAddress: tokenResponse.user.walletAddress,\r\n userId: tokenResponse.user.userId,\r\n profileName: tokenResponse.user.profileName,\r\n profilePicture: tokenResponse.user.profilePicture,\r\n email: tokenResponse.user.email,\r\n gameId: this.config.gameId,\r\n timestamp: Date.now(),\r\n };\r\n\r\n // Store tokens\r\n this.tokenManager.storeAuth(authData, tokenResponse.refresh_token, tokenResponse.expires_in);\r\n\r\n // Update current auth\r\n this.currentAuthData = authData;\r\n this.config.onAuth(authData);\r\n }\r\n\r\n /**\r\n * Handle auth data from iframe\r\n */\r\n private handleAuthData(authData: AuthData): void {\r\n // Validate timestamp (5 minute expiry)\r\n const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);\r\n if (authData.timestamp < fiveMinutesAgo) {\r\n this.config.onAuthError(new Error('Auth data expired'));\r\n return;\r\n }\r\n\r\n // Update current auth\r\n this.currentAuthData = authData;\r\n this.config.onAuth(authData);\r\n }\r\n\r\n /**\r\n * Get current VIP status for the authenticated user (tier, allocation, claimable, perks).\r\n * Games can read tier.gameBonusPointsLevel (1–21) for Alpha/Beta access or in-game gifts.\r\n */\r\n async getVipStatus(): Promise<VipStatus | null> {\r\n const response = await this.apiCall('/api/vip/me');\r\n if (!response.ok) return null;\r\n const data = await response.json();\r\n if (data.success && data.data) return data.data as VipStatus;\r\n return null;\r\n }\r\n\r\n /**\r\n * Get the current user's game bonus points level (1–21) from their VIP tier.\r\n * Use for Game Alpha Access (e.g. level >= 6), Game Beta Access (e.g. level >= 1), or in-game gifts.\r\n */\r\n async getGameBonusPointsLevel(): Promise<number | null> {\r\n const status = await this.getVipStatus();\r\n if (!status?.tier) return null;\r\n const level = status.tier.gameBonusPointsLevel ?? (status.tier.perks?.GAME_BONUS_POINTS_LEVEL as number);\r\n return typeof level === 'number' && level >= 1 && level <= 21 ? level : null;\r\n }\r\n\r\n /**\r\n * Refresh access token using refresh token\r\n */\r\n private async refreshAccessToken(refreshToken: string): Promise<void> {\r\n const response = await fetch(this.config.oauthTokenUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n grant_type: 'refresh_token',\r\n refresh_token: refreshToken,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error('Failed to refresh token');\r\n }\r\n\r\n const tokenResponse: OAuthTokenResponse = await response.json();\r\n await this.handleTokenReceived(tokenResponse);\r\n }\r\n}\r\n","import type { ApiCallOptions } from './types';\n\ninterface ServerSDKConfig {\n /**\n * Your developer API key (from developer portal)\n */\n apiKey: string;\n\n /**\n * OmenX API base URL (default: https://api.omen.foundation)\n */\n apiBaseUrl?: string;\n}\n\n/**\n * OmenX Game SDK - Server Mode\n * \n * For Node.js backends using developer API keys.\n * This mode allows server-to-server communication with the OmenX API.\n */\nexport class OmenXServerSDK {\n private config: Required<ServerSDKConfig>;\n private apiKey: string;\n\n constructor(config: ServerSDKConfig) {\n this.apiKey = config.apiKey;\n this.config = {\n apiKey: config.apiKey,\n apiBaseUrl: config.apiBaseUrl || 'https://api.omen.foundation',\n };\n }\n\n /**\n * Make an authenticated API call using the developer API key\n */\n async apiCall(endpoint: string, options: ApiCallOptions = {}): Promise<Response> {\n const url = endpoint.startsWith('http') \n ? endpoint \n : `${this.config.apiBaseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n ...options.headers,\n };\n\n const fetchOptions: RequestInit = {\n method: options.method || 'GET',\n headers,\n };\n\n if (options.body && options.method !== 'GET') {\n fetchOptions.body = JSON.stringify(options.body);\n }\n\n const response = await fetch(url, fetchOptions);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new Error(`API call failed: ${response.status} ${response.statusText} - ${errorText}`);\n }\n\n return response;\n }\n\n /**\n * Health check\n */\n async healthCheck(): Promise<any> {\n const response = await this.apiCall('/v1/health', { includeAuth: false });\n return response.json();\n }\n\n /**\n * Get API key information\n */\n async getApiKeyInfo(): Promise<any> {\n const response = await this.apiCall('/v1/auth/me');\n return response.json();\n }\n\n /**\n * Player Operations\n */\n\n /**\n * Get full player data: NFTs (system + game) and balances for a wallet.\n * Requires both nfts:read and balances:read scopes.\n */\n async getPlayer(wallet: string, chainId: string): Promise<any> {\n const response = await this.apiCall(\n `/v1/players/${encodeURIComponent(wallet)}?chainId=${encodeURIComponent(chainId)}`\n );\n return response.json();\n }\n\n /**\n * Get native and ERC20 token balances for a wallet\n */\n async getPlayerBalances(wallet: string, chainId: string): Promise<any> {\n const response = await this.apiCall(\n `/v1/players/${encodeURIComponent(wallet)}/balances?chainId=${encodeURIComponent(chainId)}`\n );\n return response.json();\n }\n\n /**\n * Get paginated NFTs for a wallet.\n * With no contract: returns OmenX system NFTs (Asset Manager, Faucet, Early Adopter) + game NFTs.\n * With contract: returns only NFTs for that contract.\n */\n async getPlayerNfts(\n wallet: string,\n chainId: string,\n options?: {\n contract?: string;\n cursor?: string;\n limit?: number;\n }\n ): Promise<any> {\n const params = new URLSearchParams({ chainId });\n if (options?.contract) params.set('contract', options.contract);\n if (options?.cursor) params.set('cursor', options.cursor);\n if (options?.limit != null) params.set('limit', String(options.limit));\n\n const response = await this.apiCall(\n `/v1/players/${encodeURIComponent(wallet)}/nfts?${params.toString()}`\n );\n return response.json();\n }\n\n /**\n * Purchase Operations\n */\n\n /**\n * Create a server-authoritative purchase\n */\n async createPurchase(params: {\n playerWallet?: string;\n walletAddress?: string; // Legacy field name\n skuId?: string;\n sku?: string; // Legacy field name\n quantity?: number;\n idempotencyKey?: string;\n paymentMethod?: string;\n metadata?: Record<string, any>;\n }): Promise<any> {\n const response = await this.apiCall('/v1/purchases', {\n method: 'POST',\n body: params,\n headers: params.idempotencyKey ? {\n 'Idempotency-Key': params.idempotencyKey,\n } : undefined,\n });\n return response.json();\n }\n\n /**\n * NFT Template Operations\n */\n\n /**\n * Get all NFT templates for the authenticated game (game is derived from API key).\n * gameId is optional and ignored by the API; included for backward compatibility.\n */\n async getNftTemplates(_gameId?: string): Promise<any> {\n const response = await this.apiCall('/v1/nfts/templates');\n return response.json();\n }\n\n /**\n * Get NFT contract address for the authenticated game (game is derived from API key).\n * gameId is optional and ignored by the API; included for backward compatibility.\n */\n async getNftContract(_gameId?: string): Promise<any> {\n const response = await this.apiCall('/v1/nfts/contract');\n return response.json();\n }\n\n /**\n * Mint NFTs (single or batch)\n */\n async mintNfts(params: {\n templateId: string;\n recipientAddress: string;\n quantity: number;\n }): Promise<any> {\n const response = await this.apiCall('/v1/nfts/mint', {\n method: 'POST',\n body: params,\n });\n return response.json();\n }\n\n /**\n * Batch mint NFTs\n */\n async batchMintNfts(mints: Array<{\n templateId: string;\n recipientAddress: string;\n quantity: number;\n }>): Promise<any> {\n const response = await this.apiCall('/v1/nfts/mint/batch', {\n method: 'POST',\n body: { mints },\n });\n return response.json();\n }\n\n /**\n * Update NFT metadata\n */\n async updateNftMetadata(\n tokenId: string,\n metadata: {\n attributes?: Record<string, string | number | boolean>;\n name?: string;\n description?: string;\n imageUrl?: string;\n }\n ): Promise<any> {\n const response = await this.apiCall(`/v1/nfts/${tokenId}/metadata`, {\n method: 'PUT',\n body: metadata,\n });\n return response.json();\n }\n\n /**\n * Burn NFT (single)\n */\n async burnNft(tokenId: string): Promise<any> {\n const response = await this.apiCall(`/v1/nfts/${tokenId}`, {\n method: 'DELETE',\n });\n return response.json();\n }\n\n /**\n * Batch burn NFTs\n */\n async batchBurnNfts(tokenIds: string[]): Promise<any> {\n const response = await this.apiCall('/v1/nfts/burn/batch', {\n method: 'POST',\n body: { tokenIds },\n });\n return response.json();\n }\n\n /**\n * Pack opener - mint random NFTs from a drop table\n */\n async packOpener(params: {\n dropTableId: string;\n recipientAddress: string;\n }): Promise<any> {\n const response = await this.apiCall('/v1/nfts/pack-opener', {\n method: 'POST',\n body: params,\n });\n return response.json();\n }\n\n /**\n * VIP Points (Developer pool)\n * Requires scope: vip_points:write.\n * Grants VIP points to a player from this game's allocated pool. Enforces total allocation and max per quest.\n * Call from your game backend only (API key auth); not for client-side use.\n */\n async grantVipPoints(params: {\n /** Player wallet address (0x-prefixed, 40 hex chars). */\n wallet: string;\n /** Points to grant (positive integer). Capped by pool remaining and max per quest. */\n amount: number;\n /** Optional quest/activity id for idempotency or auditing. */\n questId?: string;\n }): Promise<{ success: boolean; data?: { wallet: string; amount: number; phaseIndex?: number } }> {\n const response = await this.apiCall('/v1/vip/grant-points', {\n method: 'POST',\n body: params,\n });\n return response.json();\n }\n\n /**\n * Quests API (game quests only).\n * Requires scope: quests:read for getQuestsForPlayer; quests:write for assign, progress, complete, claim.\n */\n\n /** Get assigned quests for a player. Optional questType filter. */\n async getQuestsForPlayer(\n wallet: string,\n options?: { questType?: 'daily' | 'weekly' | 'monthly' | 'oneTime' }\n ): Promise<{ success: boolean; data: { quests: any[] } }> {\n const q = options?.questType ? `?questType=${options.questType}` : '';\n const response = await this.apiCall(`/v1/quests/players/${encodeURIComponent(wallet)}${q}`);\n return response.json();\n }\n\n /** Assign quests of a type to a player. Use idempotencyKey for safe retries. */\n async assignQuests(\n wallet: string,\n questType: 'daily' | 'weekly' | 'monthly' | 'oneTime',\n count: number,\n options?: { idempotencyKey?: string }\n ): Promise<{ success: boolean; data: { assigned: number; assignmentIds?: string[] } }> {\n const response = await this.apiCall(`/v1/quests/players/${encodeURIComponent(wallet)}/assign`, {\n method: 'POST',\n body: { questType, count },\n headers: options?.idempotencyKey ? { 'Idempotency-Key': options.idempotencyKey } : undefined,\n });\n return response.json();\n }\n\n /** Report progress for a quest step. Quest auto-completes when all steps meet targets. */\n async reportQuestProgress(\n wallet: string,\n questKey: string,\n value: number,\n options?: { stepKey?: string }\n ): Promise<{ success: boolean; data?: object }> {\n const response = await this.apiCall('/v1/quests/progress', {\n method: 'POST',\n body: { wallet, questKey, value, stepKey: options?.stepKey },\n });\n return response.json();\n }\n\n /** Mark a quest complete (all steps set to targets). */\n async completeQuest(wallet: string, questKey: string): Promise<{ success: boolean; data?: object }> {\n const response = await this.apiCall('/v1/quests/complete', {\n method: 'POST',\n body: { wallet, questKey },\n });\n return response.json();\n }\n\n /** Claim VIP reward for a completed quest (from game pool). Use idempotencyKey for safe retries. */\n async claimQuestReward(\n wallet: string,\n questKey: string,\n options?: { idempotencyKey?: string }\n ): Promise<{ success: boolean; data?: { pointsGranted?: number } }> {\n const response = await this.apiCall('/v1/quests/claim', {\n method: 'POST',\n body: { wallet, questKey },\n headers: options?.idempotencyKey ? { 'Idempotency-Key': options.idempotencyKey } : undefined,\n });\n return response.json();\n }\n\n /**\n * Reset or wipe a player's quest state for this game. Requires quests:write.\n * - wipe: delete all quest assignments for this game for the player.\n * - reset: delete assignments for the specified questKey only (questKey required).\n */\n async resetPlayerQuests(\n wallet: string,\n action: 'wipe' | 'reset',\n questKey?: string\n ): Promise<{ success: boolean; data: { action: string; deleted: number; questKey?: string } }> {\n const body: { action: 'wipe' | 'reset'; questKey?: string } = { action };\n if (action === 'reset' && questKey) body.questKey = questKey;\n const response = await this.apiCall('/v1/quests/players/' + encodeURIComponent(wallet) + '/reset', {\n method: 'POST',\n body,\n });\n return response.json();\n }\n}\n","/**\r\n * Real-time wallet updates (balance & inventory) for game clients.\r\n * Subscribe to the per-wallet Ably channel so the game stays in sync when the user\r\n * spends or receives OmenX / NFTs on the website or in another client.\r\n *\r\n * Two options:\r\n * 1. subscribeWalletRealtimeWithOmenXAuth – no API key needed; SDK gets a scoped token from the OmenX platform using your access token.\r\n * 2. subscribeWalletRealtime – pass your own Ably Realtime instance (e.g. from an API key or your own token).\r\n */\r\n\r\nimport Ably from 'ably';\r\n\r\n/** Payload for balance and inventory events. Use eventId for idempotency (ignore if already processed). */\r\nexport interface RealtimeWalletPayload {\r\n eventId: string;\r\n timestamp: number;\r\n reason?: string;\r\n}\r\n\r\n/** Ably channel name prefix. Full channel = \"wallet:\" + normalized wallet address. */\r\nexport const WALLET_CHANNEL_PREFIX = 'wallet:';\r\n\r\n/** Event names published by the OmenX backend on the wallet channel. */\r\nexport const REALTIME_EVENTS = {\r\n /** Currency balance changed. Refetch via GetPlayerBalances or your balance API. */\r\n balance: 'balance',\r\n /** NFT/inventory changed. Refetch via GetPlayerNfts or your inventory API (cache is source of truth). */\r\n inventory: 'inventory',\r\n} as const;\r\n\r\nconst MAX_SEEN_IDS = 200;\r\n\r\n/**\r\n * Normalize wallet address for channel name (lowercase, no 0x prefix change).\r\n */\r\nfunction normalizeWallet(wallet: string): string {\r\n return (wallet || '').trim().toLowerCase();\r\n}\r\n\r\n/**\r\n * Get the Ably channel name for a wallet. Use this when subscribing with your Ably client.\r\n */\r\nexport function getWalletChannelName(walletAddress: string): string {\r\n return WALLET_CHANNEL_PREFIX + normalizeWallet(walletAddress);\r\n}\r\n\r\n/**\r\n * Minimal Ably Realtime interface so the SDK works with any Ably.Realtime instance.\r\n * The app provides the real Ably client from AblyProvider or new Ably.Realtime({ key }).\r\n */\r\nexport interface AblyRealtimeLike {\r\n channels: {\r\n get(name: string): {\r\n subscribe(eventOrCallback: string | ((message: { name: string; data: unknown }) => void), callback?: (message: { name: string; data: unknown }) => void): void;\r\n unsubscribe(eventOrCallback?: string | ((message: { name: string; data: unknown }) => void), callback?: (message: { name: string; data: unknown }) => void): void;\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * Subscribe to real-time balance and inventory events for a wallet.\r\n * Call when the user logs in; call the returned unsubscribe when they log out or wallet changes.\r\n *\r\n * Uses eventId to dedupe (ignores already-seen events). Refetch in your app on each callback.\r\n *\r\n * @param ably - Ably Realtime instance (e.g. from useAbly() or new Ably.Realtime({ key }))\r\n * @param walletAddress - Current player wallet (0x...)\r\n * @param callbacks - onBalance and/or onInventory; each receives the payload (eventId, timestamp, reason?)\r\n * @returns Unsubscribe function\r\n */\r\nexport function subscribeWalletRealtime(\r\n ably: AblyRealtimeLike,\r\n walletAddress: string,\r\n callbacks: {\r\n onBalance?: (payload: RealtimeWalletPayload) => void;\r\n onInventory?: (payload: RealtimeWalletPayload) => void;\r\n }\r\n): () => void {\r\n const normalized = normalizeWallet(walletAddress);\r\n if (!normalized || !/^0x[a-fa-f0-9]{40}$/.test(normalized)) {\r\n return () => {};\r\n }\r\n\r\n const seenIds = new Set<string>();\r\n\r\n const handleMessage = (message: { name: string; data: unknown }) => {\r\n const data = message.data as RealtimeWalletPayload | undefined;\r\n if (!data || typeof data !== 'object' || typeof data.eventId !== 'string') return;\r\n if (seenIds.has(data.eventId)) return;\r\n if (seenIds.size >= MAX_SEEN_IDS) {\r\n const first = seenIds.values().next().value;\r\n if (first != null) seenIds.delete(first);\r\n }\r\n seenIds.add(data.eventId);\r\n\r\n if (message.name === REALTIME_EVENTS.balance && callbacks.onBalance) {\r\n callbacks.onBalance(data);\r\n } else if (message.name === REALTIME_EVENTS.inventory && callbacks.onInventory) {\r\n callbacks.onInventory(data);\r\n }\r\n };\r\n\r\n const channel = ably.channels.get(getWalletChannelName(normalized));\r\n channel.subscribe(handleMessage);\r\n\r\n return () => {\r\n channel.unsubscribe(handleMessage);\r\n };\r\n}\r\n\r\n/** Options for subscribing via OmenX platform token (no Ably API key required). */\r\nexport interface SubscribeWalletRealtimeWithOmenXAuthOptions {\r\n /** Base URL of the OmenX API (e.g. https://api.omen.foundation). No trailing slash. */\r\n apiBaseUrl: string;\r\n /** Returns the current OmenX access token (from your OAuth flow). Called when Ably needs to authenticate. */\r\n getAccessToken: () => Promise<string | null>;\r\n /** Wallet address (0x...) to subscribe to. Must match the wallet in the access token. */\r\n walletAddress: string;\r\n onBalance?: (payload: RealtimeWalletPayload) => void;\r\n onInventory?: (payload: RealtimeWalletPayload) => void;\r\n}\r\n\r\n/**\r\n * Subscribe to real-time balance and inventory for a wallet using OmenX platform auth.\r\n * The SDK fetches a short-lived, subscribe-only Ably token from the OmenX API using your\r\n * access token. No Ably API key or .env is required – ideal for third-party developers.\r\n *\r\n * Requires the app to have `ably` installed (peer dependency). Call when the user is\r\n * logged in; call the returned function on logout or wallet change.\r\n */\r\nexport function subscribeWalletRealtimeWithOmenXAuth(\r\n options: SubscribeWalletRealtimeWithOmenXAuthOptions\r\n): () => void {\r\n const { apiBaseUrl, getAccessToken, walletAddress, onBalance, onInventory } = options;\r\n const normalized = (walletAddress || '').trim().toLowerCase();\r\n if (!normalized || !/^0x[a-fa-f0-9]{40}$/.test(normalized)) {\r\n return () => {};\r\n }\r\n\r\n const base = apiBaseUrl.replace(/\\/$/, '');\r\n const authCallback = (\r\n _tokenParams: unknown,\r\n callback: (error: string | null, tokenRequestOrDetails: unknown) => void\r\n ): void => {\r\n getAccessToken()\r\n .then((token) => {\r\n if (!token) {\r\n callback('Not authenticated', null);\r\n return;\r\n }\r\n return fetch(`${base}/api/sdk/ably-token`, {\r\n method: 'POST',\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n });\r\n })\r\n .then((res) => {\r\n if (!res) return;\r\n if (!res.ok) {\r\n return res.json().then((body: { message?: string }) => {\r\n callback((body && body.message) || res.statusText || 'Request failed', null);\r\n });\r\n }\r\n return res.json().then((tokenRequest: unknown) => {\r\n callback(null, tokenRequest);\r\n });\r\n })\r\n .catch((err: unknown) => {\r\n callback(err instanceof Error ? err.message : String(err), null);\r\n });\r\n };\r\n const ably = new Ably.Realtime({\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n authCallback: authCallback as any,\r\n });\r\n\r\n const unsubscribe = subscribeWalletRealtime(ably as AblyRealtimeLike, walletAddress, {\r\n onBalance,\r\n onInventory,\r\n });\r\n\r\n return () => {\r\n unsubscribe();\r\n ably.close();\r\n };\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/oauth.ts","../src/iframe-auth.ts","../src/token-manager.ts","../src/sdk.ts","../src/server-sdk.ts","../src/realtime.ts"],"names":["Ably"],"mappings":"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","file":"index.js","sourcesContent":["import type { OAuthTokenResponse, OAuthOptions } from './types';\r\n\r\ninterface OAuthFlowConfig {\r\n gameId: string;\r\n oauthAuthorizeUrl: string;\r\n oauthTokenUrl: string;\r\n apiBaseUrl: string;\r\n onTokenReceived: (token: OAuthTokenResponse) => Promise<void>;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\nexport class OAuthFlow {\r\n private config: OAuthFlowConfig;\r\n\r\n constructor(config: OAuthFlowConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Authenticate user via OAuth 2.0 Authorization Code Grant with PKCE\r\n */\r\n async authenticate(options: OAuthOptions = {}): Promise<OAuthTokenResponse> {\r\n // Generate state for CSRF protection\r\n const state = this.generateState();\r\n \r\n // Generate PKCE code verifier and challenge\r\n const codeVerifier = this.generateCodeVerifier();\r\n const codeChallenge = await this.generateCodeChallenge(codeVerifier);\r\n \r\n return new Promise((resolve, reject) => {\r\n \r\n // Store code verifier in sessionStorage for later use\r\n sessionStorage.setItem(`omenx_pkce_${state}`, codeVerifier);\r\n \r\n // Build authorization URL\r\n const redirectUri = options.redirectUri || `${window.location.origin}/auth/callback`;\r\n const authUrl = new URL(this.config.oauthAuthorizeUrl);\r\n authUrl.searchParams.set('client_id', this.config.gameId);\r\n authUrl.searchParams.set('redirect_uri', redirectUri);\r\n authUrl.searchParams.set('response_type', 'code');\r\n authUrl.searchParams.set('scope', 'openid profile email');\r\n authUrl.searchParams.set('state', state);\r\n authUrl.searchParams.set('code_challenge', codeChallenge);\r\n authUrl.searchParams.set('code_challenge_method', 'S256');\r\n \r\n // Store state for verification\r\n const stateStorageKey = `omenx_oauth_state_${state}`;\r\n sessionStorage.setItem(stateStorageKey, state);\r\n \r\n // Open popup window\r\n const popup = window.open(\r\n authUrl.toString(),\r\n 'OmenX OAuth',\r\n 'width=500,height=600,left=100,top=100'\r\n );\r\n\r\n if (!popup) {\r\n const error = new Error('Failed to open popup window. Please allow popups for this site.');\r\n this.config.onError?.(error);\r\n reject(error);\r\n return;\r\n }\r\n\r\n // Clean up old OAuth callback entries from localStorage\r\n try {\r\n const allKeys = Object.keys(localStorage).filter(k => k.startsWith('omenx_oauth_callback_'));\r\n allKeys.forEach(key => {\r\n try {\r\n const data = localStorage.getItem(key);\r\n if (data) {\r\n const parsed = JSON.parse(data);\r\n const age = Date.now() - (parsed.timestamp || 0);\r\n // Remove entries older than 5 minutes\r\n if (age > 300000) {\r\n localStorage.removeItem(key);\r\n }\r\n }\r\n } catch (e) {\r\n localStorage.removeItem(key);\r\n }\r\n });\r\n } catch (error) {\r\n // Ignore cleanup errors\r\n }\r\n\r\n // Poll localStorage for callback data\r\n const storageKey = `omenx_oauth_callback_${state}`;\r\n let messageReceived = false;\r\n \r\n const pollInterval = setInterval(() => {\r\n if (messageReceived) {\r\n clearInterval(pollInterval);\r\n return;\r\n }\r\n \r\n const stored = localStorage.getItem(storageKey);\r\n \r\n if (stored) {\r\n try {\r\n const data = JSON.parse(stored);\r\n \r\n // Validate state and check timestamp\r\n if (data.code && data.state === state) {\r\n const age = Date.now() - (data.timestamp || 0);\r\n if (age < 30000) { // 30 second timeout\r\n messageReceived = true;\r\n clearInterval(pollInterval);\r\n \r\n // Clean up\r\n localStorage.removeItem(storageKey);\r\n sessionStorage.removeItem(`omenx_pkce_${state}`);\r\n sessionStorage.removeItem(stateStorageKey);\r\n \r\n // Exchange code for token\r\n this.exchangeCodeForToken(data.code, redirectUri, codeVerifier)\r\n .then(async (tokenResponse) => {\r\n await this.config.onTokenReceived(tokenResponse);\r\n // Close popup after successful token exchange\r\n if (popup && !popup.closed) {\r\n try {\r\n popup.close();\r\n } catch (e) {\r\n // Ignore errors closing popup\r\n }\r\n }\r\n resolve(tokenResponse);\r\n })\r\n .catch((error) => {\r\n this.config.onError?.(error as Error);\r\n reject(error);\r\n });\r\n return;\r\n } else {\r\n // Data too old, remove it\r\n localStorage.removeItem(storageKey);\r\n }\r\n }\r\n } catch (error) {\r\n console.error('[OAuthFlow] Error parsing localStorage callback:', error);\r\n }\r\n }\r\n }, 100); // Poll every 100ms\r\n \r\n // Check if popup was closed without completing auth\r\n const checkClosed = setInterval(() => {\r\n if (messageReceived) {\r\n clearInterval(checkClosed);\r\n return;\r\n }\r\n \r\n // Check if popup is actually closed\r\n let isClosed = false;\r\n try {\r\n if (popup.closed) {\r\n try {\r\n // Try to access location to verify it's actually closed\r\n popup.location.href; // Accessing this will throw if popup is on different origin\r\n isClosed = true;\r\n } catch (e) {\r\n // Can't access location - popup is on different origin (still open)\r\n isClosed = false;\r\n }\r\n }\r\n } catch (e) {\r\n isClosed = false;\r\n }\r\n \r\n if (isClosed) {\r\n clearInterval(checkClosed);\r\n clearInterval(pollInterval);\r\n \r\n // Clean up\r\n sessionStorage.removeItem(`omenx_pkce_${state}`);\r\n sessionStorage.removeItem(stateStorageKey);\r\n \r\n const error = new Error('Authentication was cancelled.');\r\n this.config.onError?.(error);\r\n reject(error);\r\n }\r\n }, 1000);\r\n });\r\n }\r\n\r\n /**\r\n * Exchange authorization code for access token\r\n */\r\n private async exchangeCodeForToken(\r\n code: string,\r\n redirectUri: string,\r\n codeVerifier?: string\r\n ): Promise<OAuthTokenResponse> {\r\n const body: any = {\r\n code,\r\n redirect_uri: redirectUri,\r\n grant_type: 'authorization_code',\r\n client_id: this.config.gameId,\r\n };\r\n\r\n if (codeVerifier) {\r\n body.code_verifier = codeVerifier;\r\n }\r\n\r\n const response = await fetch(this.config.oauthTokenUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.json().catch(() => ({ message: 'Failed to exchange code for token' }));\r\n throw new Error(error.message || 'Failed to exchange code for token');\r\n }\r\n\r\n return response.json();\r\n }\r\n\r\n /**\r\n * Generate random state for CSRF protection\r\n */\r\n private generateState(): string {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\r\n }\r\n\r\n /**\r\n * Generate PKCE code verifier\r\n */\r\n private generateCodeVerifier(): string {\r\n const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';\r\n const array = new Uint8Array(128);\r\n crypto.getRandomValues(array);\r\n return Array.from(array, byte => charset[byte % charset.length]).join('');\r\n }\r\n\r\n /**\r\n * Generate PKCE code challenge from verifier\r\n */\r\n private async generateCodeChallenge(verifier: string): Promise<string> {\r\n const encoder = new TextEncoder();\r\n const data = encoder.encode(verifier);\r\n const hash = await crypto.subtle.digest('SHA-256', data);\r\n const base64 = btoa(String.fromCharCode(...new Uint8Array(hash)));\r\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\r\n }\r\n}\r\n","import type { AuthData } from './types';\r\n\r\ninterface IframeAuthConfig {\r\n gameId: string;\r\n parentOrigin?: string;\r\n onAuth: (authData: AuthData) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/**\r\n * Handles authentication data passed from parent window via postMessage\r\n */\r\nexport class IframeAuth {\r\n private config: IframeAuthConfig;\r\n private messageListener: ((event: MessageEvent) => void) | null = null;\r\n\r\n constructor(config: IframeAuthConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Initialize iframe authentication listener\r\n */\r\n init(): void {\r\n // Request auth data from parent\r\n this.requestAuth();\r\n\r\n // Listen for auth data from parent\r\n this.messageListener = (event: MessageEvent) => {\r\n // Validate origin if specified\r\n if (this.config.parentOrigin) {\r\n try {\r\n const parentUrl = new URL(this.config.parentOrigin);\r\n if (event.origin !== parentUrl.origin) {\r\n return;\r\n }\r\n } catch {\r\n // If we can't parse parent origin, skip validation (development)\r\n }\r\n }\r\n\r\n // Handle auth data\r\n if (event.data?.type === 'OMENX_AUTH') {\r\n const authData = event.data.payload as AuthData;\r\n\r\n // Validate game ID\r\n if (authData.gameId !== this.config.gameId) {\r\n this.config.onError?.(new Error(`Game ID mismatch. Expected ${this.config.gameId}, got ${authData.gameId}`));\r\n return;\r\n }\r\n\r\n // Validate timestamp (5 minute expiry)\r\n const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);\r\n if (authData.timestamp < fiveMinutesAgo) {\r\n this.config.onError?.(new Error('Auth data expired'));\r\n return;\r\n }\r\n\r\n this.config.onAuth(authData);\r\n }\r\n };\r\n\r\n window.addEventListener('message', this.messageListener);\r\n }\r\n\r\n /**\r\n * Request authentication data from parent window\r\n */\r\n private requestAuth(): void {\r\n if (window.parent === window) {\r\n // Not in an iframe\r\n return;\r\n }\r\n\r\n // Send request to parent\r\n const parentOrigin = this.config.parentOrigin || '*';\r\n window.parent.postMessage(\r\n {\r\n type: 'OMENX_AUTH_REQUEST',\r\n gameId: this.config.gameId,\r\n },\r\n parentOrigin\r\n );\r\n }\r\n\r\n /**\r\n * Cleanup\r\n */\r\n destroy(): void {\r\n if (this.messageListener) {\r\n window.removeEventListener('message', this.messageListener);\r\n this.messageListener = null;\r\n }\r\n }\r\n}\r\n","import type { AuthData } from './types';\r\n\r\n/**\r\n * Manages token storage and retrieval\r\n */\r\nexport class TokenManager {\r\n private storageKeyPrefix: string;\r\n\r\n constructor(storageKeyPrefix: string = 'omenx_game_') {\r\n this.storageKeyPrefix = storageKeyPrefix;\r\n }\r\n\r\n /**\r\n * Store authentication data\r\n */\r\n storeAuth(authData: AuthData, refreshToken: string, expiresIn: number): void {\r\n try {\r\n localStorage.setItem(`${this.storageKeyPrefix}auth`, JSON.stringify(authData));\r\n localStorage.setItem(`${this.storageKeyPrefix}refresh_token`, refreshToken);\r\n localStorage.setItem(`${this.storageKeyPrefix}expires_at`, String(Date.now() + (expiresIn * 1000)));\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to store auth data:', error);\r\n }\r\n }\r\n\r\n /**\r\n * Get stored authentication data\r\n */\r\n getStoredAuth(): AuthData | null {\r\n try {\r\n const stored = localStorage.getItem(`${this.storageKeyPrefix}auth`);\r\n if (!stored) {\r\n return null;\r\n }\r\n return JSON.parse(stored) as AuthData;\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to retrieve auth data:', error);\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Get stored refresh token\r\n */\r\n getRefreshToken(): string | null {\r\n try {\r\n return localStorage.getItem(`${this.storageKeyPrefix}refresh_token`);\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to retrieve refresh token:', error);\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Clear all stored authentication data\r\n */\r\n clearStorage(): void {\r\n try {\r\n localStorage.removeItem(`${this.storageKeyPrefix}auth`);\r\n localStorage.removeItem(`${this.storageKeyPrefix}refresh_token`);\r\n localStorage.removeItem(`${this.storageKeyPrefix}expires_at`);\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to clear storage:', error);\r\n }\r\n }\r\n}\r\n","import type {\r\n OmenXGameSDKConfig,\r\n AuthData,\r\n OAuthOptions,\r\n OAuthTokenResponse,\r\n ApiCallOptions,\r\n VipStatus,\r\n} from './types';\r\nimport { OAuthFlow } from './oauth';\r\nimport { IframeAuth } from './iframe-auth';\r\nimport { TokenManager } from './token-manager';\r\n\r\n/**\r\n * OmenX Game SDK\r\n * \r\n * Provides authentication and API integration for games on the OmenX platform.\r\n * Supports both OAuth-style authentication and iframe authentication passing.\r\n */\r\nexport class OmenXGameSDK {\r\n private config: Required<OmenXGameSDKConfig>;\r\n private oauthFlow: OAuthFlow;\r\n private iframeAuth: IframeAuth | null = null;\r\n private tokenManager: TokenManager;\r\n private currentAuthData: AuthData | null = null;\r\n\r\n constructor(config: OmenXGameSDKConfig) {\r\n // Set defaults\r\n const apiBaseUrl = config.apiBaseUrl || 'https://api.omen.foundation';\r\n this.config = {\r\n gameId: config.gameId,\r\n apiBaseUrl: apiBaseUrl,\r\n oauthAuthorizeUrl: config.oauthAuthorizeUrl || `${apiBaseUrl}/v1/oauth/authorize`,\r\n oauthTokenUrl: config.oauthTokenUrl || `${apiBaseUrl}/v1/oauth/token`,\r\n onAuth: config.onAuth || (() => {}),\r\n onAuthError: config.onAuthError || ((error) => console.error('[OmenX SDK] Auth error:', error)),\r\n onLogout: config.onLogout || (() => {}),\r\n enableIframeAuth: config.enableIframeAuth !== false,\r\n parentOrigin: config.parentOrigin ?? '',\r\n storageKeyPrefix: config.storageKeyPrefix || 'omenx_game_',\r\n };\r\n\r\n // Initialize components\r\n this.tokenManager = new TokenManager(this.config.storageKeyPrefix);\r\n this.oauthFlow = new OAuthFlow({\r\n gameId: this.config.gameId,\r\n oauthAuthorizeUrl: this.config.oauthAuthorizeUrl,\r\n oauthTokenUrl: this.config.oauthTokenUrl,\r\n apiBaseUrl: this.config.apiBaseUrl,\r\n onTokenReceived: this.handleTokenReceived.bind(this),\r\n onError: this.config.onAuthError,\r\n });\r\n\r\n if (this.config.enableIframeAuth) {\r\n this.iframeAuth = new IframeAuth({\r\n gameId: this.config.gameId,\r\n parentOrigin: this.config.parentOrigin || undefined,\r\n onAuth: this.handleAuthData.bind(this),\r\n onError: this.config.onAuthError,\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Initialize the SDK\r\n * Call this after creating an instance\r\n */\r\n async init(): Promise<void> {\r\n // Try to restore from stored token\r\n const storedAuth = this.tokenManager.getStoredAuth();\r\n if (storedAuth) {\r\n // Check if token is still valid (not expired)\r\n const expiresAt = storedAuth.timestamp + (3600 * 1000); // 1 hour default\r\n if (Date.now() < expiresAt) {\r\n this.currentAuthData = storedAuth;\r\n this.config.onAuth(storedAuth);\r\n return;\r\n } else {\r\n // Token expired, try to refresh\r\n const refreshToken = this.tokenManager.getRefreshToken();\r\n if (refreshToken) {\r\n try {\r\n await this.refreshAccessToken(refreshToken);\r\n return;\r\n } catch (error) {\r\n // Refresh failed, clear storage\r\n this.tokenManager.clearStorage();\r\n }\r\n }\r\n }\r\n }\r\n\r\n // If iframe auth is enabled, try to get auth from parent\r\n if (this.config.enableIframeAuth && this.iframeAuth !== null) {\r\n this.iframeAuth.init();\r\n }\r\n }\r\n\r\n /**\r\n * Authenticate user via OAuth popup\r\n */\r\n async authenticate(options: OAuthOptions): Promise<AuthData> {\r\n const tokenResponse = await this.oauthFlow.authenticate(options);\r\n // Convert OAuthTokenResponse to AuthData\r\n return {\r\n accessToken: tokenResponse.access_token,\r\n walletAddress: tokenResponse.user.walletAddress,\r\n userId: tokenResponse.user.userId,\r\n profileName: tokenResponse.user.profileName,\r\n profilePicture: tokenResponse.user.profilePicture,\r\n email: tokenResponse.user.email,\r\n gameId: this.config.gameId,\r\n timestamp: Date.now(),\r\n };\r\n }\r\n\r\n /**\r\n * Get current authentication data\r\n */\r\n getAuthData(): AuthData | null {\r\n return this.currentAuthData;\r\n }\r\n\r\n /**\r\n * Check if user is authenticated\r\n */\r\n isAuthenticated(): boolean {\r\n return this.currentAuthData !== null;\r\n }\r\n\r\n /**\r\n * Logout user\r\n */\r\n async logout(): Promise<void> {\r\n // Revoke token if we have one\r\n if (this.currentAuthData?.accessToken) {\r\n try {\r\n await this.apiCall('/v1/oauth/revoke', {\r\n method: 'POST',\r\n body: { token: this.currentAuthData.accessToken },\r\n includeAuth: false, // Don't include auth header for revoke\r\n });\r\n } catch (error) {\r\n // Ignore errors on revoke\r\n console.warn('[OmenX SDK] Failed to revoke token:', error);\r\n }\r\n }\r\n\r\n // Clear local state\r\n this.currentAuthData = null;\r\n this.tokenManager.clearStorage();\r\n this.config.onLogout();\r\n }\r\n\r\n /**\r\n * Make an authenticated API call\r\n */\r\n async apiCall(endpoint: string, options: ApiCallOptions = {}): Promise<Response> {\r\n const url = endpoint.startsWith('http') \r\n ? endpoint \r\n : `${this.config.apiBaseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;\r\n\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n ...options.headers,\r\n };\r\n\r\n // Add authentication header if needed\r\n if (options.includeAuth !== false && this.currentAuthData?.accessToken) {\r\n headers['Authorization'] = `Bearer ${this.currentAuthData.accessToken}`;\r\n }\r\n\r\n const fetchOptions: RequestInit = {\r\n method: options.method || 'GET',\r\n headers,\r\n };\r\n\r\n if (options.body && options.method !== 'GET') {\r\n fetchOptions.body = JSON.stringify(options.body);\r\n }\r\n\r\n const response = await fetch(url, fetchOptions);\r\n\r\n // If unauthorized, try to refresh token\r\n if (response.status === 401 && this.currentAuthData) {\r\n const refreshToken = this.tokenManager.getRefreshToken();\r\n if (refreshToken) {\r\n try {\r\n await this.refreshAccessToken(refreshToken);\r\n // Retry the request with new token\r\n if (this.currentAuthData?.accessToken) {\r\n headers['Authorization'] = `Bearer ${this.currentAuthData.accessToken}`;\r\n return fetch(url, { ...fetchOptions, headers });\r\n }\r\n } catch (error) {\r\n // Refresh failed, logout\r\n await this.logout();\r\n throw new Error('Authentication expired. Please login again.');\r\n }\r\n }\r\n }\r\n\r\n return response;\r\n }\r\n\r\n /**\r\n * Handle token received from OAuth flow\r\n */\r\n private async handleTokenReceived(tokenResponse: OAuthTokenResponse): Promise<void> {\r\n const authData: AuthData = {\r\n accessToken: tokenResponse.access_token,\r\n walletAddress: tokenResponse.user.walletAddress,\r\n userId: tokenResponse.user.userId,\r\n profileName: tokenResponse.user.profileName,\r\n profilePicture: tokenResponse.user.profilePicture,\r\n email: tokenResponse.user.email,\r\n gameId: this.config.gameId,\r\n timestamp: Date.now(),\r\n };\r\n\r\n // Store tokens\r\n this.tokenManager.storeAuth(authData, tokenResponse.refresh_token, tokenResponse.expires_in);\r\n\r\n // Update current auth\r\n this.currentAuthData = authData;\r\n this.config.onAuth(authData);\r\n }\r\n\r\n /**\r\n * Handle auth data from iframe\r\n */\r\n private handleAuthData(authData: AuthData): void {\r\n // Validate timestamp (5 minute expiry)\r\n const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);\r\n if (authData.timestamp < fiveMinutesAgo) {\r\n this.config.onAuthError(new Error('Auth data expired'));\r\n return;\r\n }\r\n\r\n // Update current auth\r\n this.currentAuthData = authData;\r\n this.config.onAuth(authData);\r\n }\r\n\r\n /**\r\n * Get current VIP status for the authenticated user (tier, allocation, claimable, perks).\r\n * Games can read tier.gameBonusPointsLevel (1–21) for Alpha/Beta access or in-game gifts.\r\n */\r\n async getVipStatus(): Promise<VipStatus | null> {\r\n const response = await this.apiCall('/api/vip/me');\r\n if (!response.ok) return null;\r\n const data = await response.json();\r\n if (data.success && data.data) return data.data as VipStatus;\r\n return null;\r\n }\r\n\r\n /**\r\n * Get the current user's game bonus points level (1–21) from their VIP tier.\r\n * Use for Game Alpha Access (e.g. level >= 6), Game Beta Access (e.g. level >= 1), or in-game gifts.\r\n */\r\n async getGameBonusPointsLevel(): Promise<number | null> {\r\n const status = await this.getVipStatus();\r\n if (!status?.tier) return null;\r\n const level = status.tier.gameBonusPointsLevel ?? (status.tier.perks?.GAME_BONUS_POINTS_LEVEL as number);\r\n return typeof level === 'number' && level >= 1 && level <= 21 ? level : null;\r\n }\r\n\r\n /**\r\n * Refresh access token using refresh token\r\n */\r\n private async refreshAccessToken(refreshToken: string): Promise<void> {\r\n const response = await fetch(this.config.oauthTokenUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n grant_type: 'refresh_token',\r\n refresh_token: refreshToken,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error('Failed to refresh token');\r\n }\r\n\r\n const tokenResponse: OAuthTokenResponse = await response.json();\r\n await this.handleTokenReceived(tokenResponse);\r\n }\r\n}\r\n","import type { ApiCallOptions } from './types';\n\ninterface ServerSDKConfig {\n /**\n * Your developer API key (from developer portal)\n */\n apiKey: string;\n\n /**\n * OmenX API base URL (default: https://api.omen.foundation)\n */\n apiBaseUrl?: string;\n}\n\n/**\n * OmenX Game SDK - Server Mode\n * \n * For Node.js backends using developer API keys.\n * This mode allows server-to-server communication with the OmenX API.\n */\nexport class OmenXServerSDK {\n private config: Required<ServerSDKConfig>;\n private apiKey: string;\n\n constructor(config: ServerSDKConfig) {\n this.apiKey = config.apiKey;\n this.config = {\n apiKey: config.apiKey,\n apiBaseUrl: config.apiBaseUrl || 'https://api.omen.foundation',\n };\n }\n\n /**\n * Make an authenticated API call using the developer API key\n */\n async apiCall(endpoint: string, options: ApiCallOptions = {}): Promise<Response> {\n const url = endpoint.startsWith('http') \n ? endpoint \n : `${this.config.apiBaseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n ...options.headers,\n };\n\n const fetchOptions: RequestInit = {\n method: options.method || 'GET',\n headers,\n };\n\n if (options.body && options.method !== 'GET') {\n fetchOptions.body = JSON.stringify(options.body);\n }\n\n const response = await fetch(url, fetchOptions);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new Error(`API call failed: ${response.status} ${response.statusText} - ${errorText}`);\n }\n\n return response;\n }\n\n /**\n * Health check\n */\n async healthCheck(): Promise<any> {\n const response = await this.apiCall('/v1/health', { includeAuth: false });\n return response.json();\n }\n\n /**\n * Get API key information\n */\n async getApiKeyInfo(): Promise<any> {\n const response = await this.apiCall('/v1/auth/me');\n return response.json();\n }\n\n /**\n * Player Operations\n */\n\n /**\n * Get full player data: NFTs (system + game) and balances for a wallet.\n * Requires both nfts:read and balances:read scopes.\n */\n async getPlayer(wallet: string, chainId: string): Promise<any> {\n const response = await this.apiCall(\n `/v1/players/${encodeURIComponent(wallet)}?chainId=${encodeURIComponent(chainId)}`\n );\n return response.json();\n }\n\n /**\n * Get native and ERC20 token balances for a wallet\n */\n async getPlayerBalances(wallet: string, chainId: string): Promise<any> {\n const response = await this.apiCall(\n `/v1/players/${encodeURIComponent(wallet)}/balances?chainId=${encodeURIComponent(chainId)}`\n );\n return response.json();\n }\n\n /**\n * Get paginated NFTs for a wallet.\n * With no contract: returns OmenX system NFTs (Asset Manager, Faucet, Early Adopter) + game NFTs.\n * With contract: returns only NFTs for that contract.\n */\n async getPlayerNfts(\n wallet: string,\n chainId: string,\n options?: {\n contract?: string;\n cursor?: string;\n limit?: number;\n }\n ): Promise<any> {\n const params = new URLSearchParams({ chainId });\n if (options?.contract) params.set('contract', options.contract);\n if (options?.cursor) params.set('cursor', options.cursor);\n if (options?.limit != null) params.set('limit', String(options.limit));\n\n const response = await this.apiCall(\n `/v1/players/${encodeURIComponent(wallet)}/nfts?${params.toString()}`\n );\n return response.json();\n }\n\n /**\n * Product catalog for the authenticated game (from API key).\n * Returns active products with priceUsd and pricesInCurrency (amount per BNB, OMENX, GMT, etc.).\n * Optional chainId for display (defaults to API chain).\n */\n async getProducts(chainId?: string): Promise<any> {\n const params = chainId != null ? `?chainId=${encodeURIComponent(chainId)}` : '';\n const response = await this.apiCall(`/v1/products${params}`);\n return response.json();\n }\n\n /**\n * Purchase Operations\n */\n\n /**\n * Create a server-authoritative purchase.\n * For on-chain payment: set paymentCurrency (e.g. \"BNB\", \"OMENX\", \"GMT\") and paymentAmount.\n * Balance is validated for that token on the BNB chain; any token with balance >= paymentAmount is allowed.\n */\n async createPurchase(params: {\n playerWallet?: string;\n walletAddress?: string; // Legacy field name\n skuId?: string;\n sku?: string; // Legacy field name\n quantity?: number;\n idempotencyKey?: string;\n /** Currency the player pays with (e.g. \"BNB\", \"OMENX\", \"GMT\"). Required when paymentAmount is set. */\n paymentCurrency?: string;\n /** Amount of paymentCurrency to spend. Validated against on-chain balance. */\n paymentAmount?: number;\n /** @deprecated Use paymentCurrency \"OMENX\" and paymentAmount instead. */\n amountInOmenx?: number;\n paymentMethod?: string;\n metadata?: Record<string, any>;\n }): Promise<any> {\n const response = await this.apiCall('/v1/purchases', {\n method: 'POST',\n body: params,\n headers: params.idempotencyKey ? {\n 'Idempotency-Key': params.idempotencyKey,\n } : undefined,\n });\n return response.json();\n }\n\n /**\n * NFT Template Operations\n */\n\n /**\n * Get all NFT templates for the authenticated game (game is derived from API key).\n * gameId is optional and ignored by the API; included for backward compatibility.\n */\n async getNftTemplates(_gameId?: string): Promise<any> {\n const response = await this.apiCall('/v1/nfts/templates');\n return response.json();\n }\n\n /**\n * Get NFT contract address for the authenticated game (game is derived from API key).\n * gameId is optional and ignored by the API; included for backward compatibility.\n */\n async getNftContract(_gameId?: string): Promise<any> {\n const response = await this.apiCall('/v1/nfts/contract');\n return response.json();\n }\n\n /**\n * Mint NFTs (single or batch)\n */\n async mintNfts(params: {\n templateId: string;\n recipientAddress: string;\n quantity: number;\n }): Promise<any> {\n const response = await this.apiCall('/v1/nfts/mint', {\n method: 'POST',\n body: params,\n });\n return response.json();\n }\n\n /**\n * Batch mint NFTs\n */\n async batchMintNfts(mints: Array<{\n templateId: string;\n recipientAddress: string;\n quantity: number;\n }>): Promise<any> {\n const response = await this.apiCall('/v1/nfts/mint/batch', {\n method: 'POST',\n body: { mints },\n });\n return response.json();\n }\n\n /**\n * Update NFT metadata\n */\n async updateNftMetadata(\n tokenId: string,\n metadata: {\n attributes?: Record<string, string | number | boolean>;\n name?: string;\n description?: string;\n imageUrl?: string;\n }\n ): Promise<any> {\n const response = await this.apiCall(`/v1/nfts/${tokenId}/metadata`, {\n method: 'PUT',\n body: metadata,\n });\n return response.json();\n }\n\n /**\n * Burn NFT (single)\n */\n async burnNft(tokenId: string): Promise<any> {\n const response = await this.apiCall(`/v1/nfts/${tokenId}`, {\n method: 'DELETE',\n });\n return response.json();\n }\n\n /**\n * Batch burn NFTs\n */\n async batchBurnNfts(tokenIds: string[]): Promise<any> {\n const response = await this.apiCall('/v1/nfts/burn/batch', {\n method: 'POST',\n body: { tokenIds },\n });\n return response.json();\n }\n\n /**\n * Pack opener - mint random NFTs from a drop table\n */\n async packOpener(params: {\n dropTableId: string;\n recipientAddress: string;\n }): Promise<any> {\n const response = await this.apiCall('/v1/nfts/pack-opener', {\n method: 'POST',\n body: params,\n });\n return response.json();\n }\n\n /**\n * VIP Points (Developer pool)\n * Requires scope: vip_points:write.\n * Grants VIP points to a player from this game's allocated pool. Enforces total allocation and max per quest.\n * Call from your game backend only (API key auth); not for client-side use.\n */\n async grantVipPoints(params: {\n /** Player wallet address (0x-prefixed, 40 hex chars). */\n wallet: string;\n /** Points to grant (positive integer). Capped by pool remaining and max per quest. */\n amount: number;\n /** Optional quest/activity id for idempotency or auditing. */\n questId?: string;\n }): Promise<{ success: boolean; data?: { wallet: string; amount: number; phaseIndex?: number } }> {\n const response = await this.apiCall('/v1/vip/grant-points', {\n method: 'POST',\n body: params,\n });\n return response.json();\n }\n\n /**\n * Quests API (game quests only).\n * Requires scope: quests:read for getQuestsForPlayer; quests:write for assign, progress, complete, claim.\n */\n\n /** Get assigned quests for a player. Optional questType filter. */\n async getQuestsForPlayer(\n wallet: string,\n options?: { questType?: 'daily' | 'weekly' | 'monthly' | 'oneTime' }\n ): Promise<{ success: boolean; data: { quests: any[] } }> {\n const q = options?.questType ? `?questType=${options.questType}` : '';\n const response = await this.apiCall(`/v1/quests/players/${encodeURIComponent(wallet)}${q}`);\n return response.json();\n }\n\n /** Assign quests of a type to a player. Use idempotencyKey for safe retries. */\n async assignQuests(\n wallet: string,\n questType: 'daily' | 'weekly' | 'monthly' | 'oneTime',\n count: number,\n options?: { idempotencyKey?: string }\n ): Promise<{ success: boolean; data: { assigned: number; assignmentIds?: string[] } }> {\n const response = await this.apiCall(`/v1/quests/players/${encodeURIComponent(wallet)}/assign`, {\n method: 'POST',\n body: { questType, count },\n headers: options?.idempotencyKey ? { 'Idempotency-Key': options.idempotencyKey } : undefined,\n });\n return response.json();\n }\n\n /** Report progress for a quest step. Quest auto-completes when all steps meet targets. */\n async reportQuestProgress(\n wallet: string,\n questKey: string,\n value: number,\n options?: { stepKey?: string }\n ): Promise<{ success: boolean; data?: object }> {\n const response = await this.apiCall('/v1/quests/progress', {\n method: 'POST',\n body: { wallet, questKey, value, stepKey: options?.stepKey },\n });\n return response.json();\n }\n\n /** Mark a quest complete (all steps set to targets). */\n async completeQuest(wallet: string, questKey: string): Promise<{ success: boolean; data?: object }> {\n const response = await this.apiCall('/v1/quests/complete', {\n method: 'POST',\n body: { wallet, questKey },\n });\n return response.json();\n }\n\n /** Claim VIP reward for a completed quest (from game pool). Use idempotencyKey for safe retries. */\n async claimQuestReward(\n wallet: string,\n questKey: string,\n options?: { idempotencyKey?: string }\n ): Promise<{ success: boolean; data?: { pointsGranted?: number } }> {\n const response = await this.apiCall('/v1/quests/claim', {\n method: 'POST',\n body: { wallet, questKey },\n headers: options?.idempotencyKey ? { 'Idempotency-Key': options.idempotencyKey } : undefined,\n });\n return response.json();\n }\n\n /**\n * Reset or wipe a player's quest state for this game. Requires quests:write.\n * - wipe: delete all quest assignments for this game for the player.\n * - reset: delete assignments for the specified questKey only (questKey required).\n */\n async resetPlayerQuests(\n wallet: string,\n action: 'wipe' | 'reset',\n questKey?: string\n ): Promise<{ success: boolean; data: { action: string; deleted: number; questKey?: string } }> {\n const body: { action: 'wipe' | 'reset'; questKey?: string } = { action };\n if (action === 'reset' && questKey) body.questKey = questKey;\n const response = await this.apiCall('/v1/quests/players/' + encodeURIComponent(wallet) + '/reset', {\n method: 'POST',\n body,\n });\n return response.json();\n }\n}\n","/**\r\n * Real-time wallet updates (balance & inventory) for game clients.\r\n * Subscribe to the per-wallet Ably channel so the game stays in sync when the user\r\n * spends or receives OmenX / NFTs on the website or in another client.\r\n *\r\n * Two options:\r\n * 1. subscribeWalletRealtimeWithOmenXAuth – no API key needed; SDK gets a scoped token from the OmenX platform using your access token.\r\n * 2. subscribeWalletRealtime – pass your own Ably Realtime instance (e.g. from an API key or your own token).\r\n */\r\n\r\nimport Ably from 'ably';\r\n\r\n/** Payload for balance and inventory events. Use eventId for idempotency (ignore if already processed). */\r\nexport interface RealtimeWalletPayload {\r\n eventId: string;\r\n timestamp: number;\r\n reason?: string;\r\n}\r\n\r\n/** Ably channel name prefix. Full channel = \"wallet:\" + normalized wallet address. */\r\nexport const WALLET_CHANNEL_PREFIX = 'wallet:';\r\n\r\n/** Event names published by the OmenX backend on the wallet channel. */\r\nexport const REALTIME_EVENTS = {\r\n /** Currency balance changed. Refetch via GetPlayerBalances or your balance API. */\r\n balance: 'balance',\r\n /** NFT/inventory changed. Refetch via GetPlayerNfts or your inventory API (cache is source of truth). */\r\n inventory: 'inventory',\r\n} as const;\r\n\r\nconst MAX_SEEN_IDS = 200;\r\n\r\n/**\r\n * Normalize wallet address for channel name (lowercase, no 0x prefix change).\r\n */\r\nfunction normalizeWallet(wallet: string): string {\r\n return (wallet || '').trim().toLowerCase();\r\n}\r\n\r\n/**\r\n * Get the Ably channel name for a wallet. Use this when subscribing with your Ably client.\r\n */\r\nexport function getWalletChannelName(walletAddress: string): string {\r\n return WALLET_CHANNEL_PREFIX + normalizeWallet(walletAddress);\r\n}\r\n\r\n/**\r\n * Minimal Ably Realtime interface so the SDK works with any Ably.Realtime instance.\r\n * The app provides the real Ably client from AblyProvider or new Ably.Realtime({ key }).\r\n */\r\nexport interface AblyRealtimeLike {\r\n channels: {\r\n get(name: string): {\r\n subscribe(eventOrCallback: string | ((message: { name: string; data: unknown }) => void), callback?: (message: { name: string; data: unknown }) => void): void;\r\n unsubscribe(eventOrCallback?: string | ((message: { name: string; data: unknown }) => void), callback?: (message: { name: string; data: unknown }) => void): void;\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * Subscribe to real-time balance and inventory events for a wallet.\r\n * Call when the user logs in; call the returned unsubscribe when they log out or wallet changes.\r\n *\r\n * Uses eventId to dedupe (ignores already-seen events). Refetch in your app on each callback.\r\n *\r\n * @param ably - Ably Realtime instance (e.g. from useAbly() or new Ably.Realtime({ key }))\r\n * @param walletAddress - Current player wallet (0x...)\r\n * @param callbacks - onBalance and/or onInventory; each receives the payload (eventId, timestamp, reason?)\r\n * @returns Unsubscribe function\r\n */\r\nexport function subscribeWalletRealtime(\r\n ably: AblyRealtimeLike,\r\n walletAddress: string,\r\n callbacks: {\r\n onBalance?: (payload: RealtimeWalletPayload) => void;\r\n onInventory?: (payload: RealtimeWalletPayload) => void;\r\n }\r\n): () => void {\r\n const normalized = normalizeWallet(walletAddress);\r\n if (!normalized || !/^0x[a-fa-f0-9]{40}$/.test(normalized)) {\r\n return () => {};\r\n }\r\n\r\n const seenIds = new Set<string>();\r\n\r\n const handleMessage = (message: { name: string; data: unknown }) => {\r\n const data = message.data as RealtimeWalletPayload | undefined;\r\n if (!data || typeof data !== 'object' || typeof data.eventId !== 'string') return;\r\n if (seenIds.has(data.eventId)) return;\r\n if (seenIds.size >= MAX_SEEN_IDS) {\r\n const first = seenIds.values().next().value;\r\n if (first != null) seenIds.delete(first);\r\n }\r\n seenIds.add(data.eventId);\r\n\r\n if (message.name === REALTIME_EVENTS.balance && callbacks.onBalance) {\r\n callbacks.onBalance(data);\r\n } else if (message.name === REALTIME_EVENTS.inventory && callbacks.onInventory) {\r\n callbacks.onInventory(data);\r\n }\r\n };\r\n\r\n const channel = ably.channels.get(getWalletChannelName(normalized));\r\n channel.subscribe(handleMessage);\r\n\r\n return () => {\r\n channel.unsubscribe(handleMessage);\r\n };\r\n}\r\n\r\n/** Options for subscribing via OmenX platform token (no Ably API key required). */\r\nexport interface SubscribeWalletRealtimeWithOmenXAuthOptions {\r\n /** Base URL of the OmenX API (e.g. https://api.omen.foundation). No trailing slash. */\r\n apiBaseUrl: string;\r\n /** Returns the current OmenX access token (from your OAuth flow). Called when Ably needs to authenticate. */\r\n getAccessToken: () => Promise<string | null>;\r\n /** Wallet address (0x...) to subscribe to. Must match the wallet in the access token. */\r\n walletAddress: string;\r\n onBalance?: (payload: RealtimeWalletPayload) => void;\r\n onInventory?: (payload: RealtimeWalletPayload) => void;\r\n /** Optional. Called when the Ably connection fails or is suspended (e.g. server unavailable). App can log or show a non-blocking toast; realtime will degrade gracefully. */\r\n onConnectionError?: (message: string) => void;\r\n}\r\n\r\n/**\r\n * Subscribe to real-time balance and inventory for a wallet using OmenX platform auth.\r\n * The SDK fetches a short-lived, subscribe-only Ably token from the OmenX API using your\r\n * access token. No Ably API key or .env is required – ideal for third-party developers.\r\n *\r\n * If the token endpoint is unavailable (e.g. backend down), no Ably client is created and\r\n * the function returns a no-op unsubscribe so the app does not crash. Connection\r\n * failures/suspensions are handled and reported via onConnectionError so they do not\r\n * surface as uncaught errors.\r\n *\r\n * Requires the app to have `ably` installed (peer dependency). Call when the user is\r\n * logged in; call the returned function on logout or wallet change.\r\n */\r\nexport function subscribeWalletRealtimeWithOmenXAuth(\r\n options: SubscribeWalletRealtimeWithOmenXAuthOptions\r\n): () => void {\r\n const { apiBaseUrl, getAccessToken, walletAddress, onBalance, onInventory, onConnectionError } = options;\r\n const normalized = (walletAddress || '').trim().toLowerCase();\r\n if (!normalized || !/^0x[a-fa-f0-9]{40}$/.test(normalized)) {\r\n return () => {};\r\n }\r\n\r\n const base = apiBaseUrl.replace(/\\/$/, '');\r\n const reportConnectionError = (message: string): void => {\r\n if (onConnectionError) {\r\n try {\r\n onConnectionError(message);\r\n } catch {\r\n // ignore app callback errors\r\n }\r\n } else {\r\n console.warn('[OmenX Realtime]', message);\r\n }\r\n };\r\n\r\n const authCallback = (\r\n _tokenParams: unknown,\r\n callback: (error: string | null, tokenRequestOrDetails: unknown) => void\r\n ): void => {\r\n getAccessToken()\r\n .then((token) => {\r\n if (!token) {\r\n callback('Not authenticated', null);\r\n return;\r\n }\r\n return fetch(`${base}/api/sdk/ably-token`, {\r\n method: 'POST',\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n });\r\n })\r\n .then((res) => {\r\n if (!res) return;\r\n if (!res.ok) {\r\n return res.json().then((body: { message?: string }) => {\r\n callback((body && body.message) || res.statusText || 'Request failed', null);\r\n });\r\n }\r\n return res.json().then((tokenRequest: unknown) => {\r\n callback(null, tokenRequest);\r\n });\r\n })\r\n .catch((err: unknown) => {\r\n callback(err instanceof Error ? err.message : String(err), null);\r\n });\r\n };\r\n\r\n // Pre-flight: try to get a token before creating Ably. If backend is unreachable, we never create the client so we avoid \"Connection to server unavailable\" uncaught errors.\r\n let ably: Ably.Realtime | null = null;\r\n let unsubscribeChannel: (() => void) | null = null;\r\n let cancelled = false;\r\n\r\n const cleanup = (): void => {\r\n cancelled = true;\r\n if (unsubscribeChannel) {\r\n try {\r\n unsubscribeChannel();\r\n } catch {\r\n // ignore\r\n }\r\n unsubscribeChannel = null;\r\n }\r\n if (ably) {\r\n try {\r\n ably.close();\r\n } catch {\r\n // ignore\r\n }\r\n ably = null;\r\n }\r\n };\r\n\r\n const tokenPromise = getAccessToken().then((token) => {\r\n if (!token) return null;\r\n return fetch(`${base}/api/sdk/ably-token`, {\r\n method: 'POST',\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n });\r\n });\r\n\r\n tokenPromise\r\n .then((res) => {\r\n if (cancelled) return;\r\n if (res === null) {\r\n reportConnectionError('Realtime skipped: not authenticated');\r\n return;\r\n }\r\n if (!res.ok) {\r\n reportConnectionError(`Realtime unavailable: ${res.status}`);\r\n return;\r\n }\r\n return res.json();\r\n })\r\n .then((tokenRequest: unknown) => {\r\n if (cancelled || tokenRequest === undefined) return;\r\n ably = new Ably.Realtime({\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n authCallback: authCallback as any,\r\n });\r\n\r\n // Handle connection failures so they don't surface as uncaught errors\r\n ably.connection.on('failed', (stateChange: { reason?: { message?: string } }) => {\r\n const msg = stateChange?.reason?.message ?? 'Connection failed';\r\n reportConnectionError(msg);\r\n });\r\n ably.connection.on('suspended', (stateChange: { reason?: { message?: string } }) => {\r\n const msg = stateChange?.reason?.message ?? 'Connection to server unavailable';\r\n reportConnectionError(msg);\r\n });\r\n\r\n unsubscribeChannel = subscribeWalletRealtime(ably as AblyRealtimeLike, walletAddress, {\r\n onBalance,\r\n onInventory,\r\n });\r\n })\r\n .catch((err: unknown) => {\r\n if (!cancelled) {\r\n reportConnectionError(err instanceof Error ? err.message : 'Realtime setup failed');\r\n }\r\n });\r\n\r\n return () => {\r\n cleanup();\r\n };\r\n}\r\n"]}
package/dist/index.mjs CHANGED
@@ -610,11 +610,23 @@ var OmenXServerSDK = class {
610
610
  );
611
611
  return response.json();
612
612
  }
613
+ /**
614
+ * Product catalog for the authenticated game (from API key).
615
+ * Returns active products with priceUsd and pricesInCurrency (amount per BNB, OMENX, GMT, etc.).
616
+ * Optional chainId for display (defaults to API chain).
617
+ */
618
+ async getProducts(chainId) {
619
+ const params = chainId != null ? `?chainId=${encodeURIComponent(chainId)}` : "";
620
+ const response = await this.apiCall(`/v1/products${params}`);
621
+ return response.json();
622
+ }
613
623
  /**
614
624
  * Purchase Operations
615
625
  */
616
626
  /**
617
- * Create a server-authoritative purchase
627
+ * Create a server-authoritative purchase.
628
+ * For on-chain payment: set paymentCurrency (e.g. "BNB", "OMENX", "GMT") and paymentAmount.
629
+ * Balance is validated for that token on the BNB chain; any token with balance >= paymentAmount is allowed.
618
630
  */
619
631
  async createPurchase(params) {
620
632
  const response = await this.apiCall("/v1/purchases", {
@@ -819,13 +831,23 @@ function subscribeWalletRealtime(ably, walletAddress, callbacks) {
819
831
  };
820
832
  }
821
833
  function subscribeWalletRealtimeWithOmenXAuth(options) {
822
- const { apiBaseUrl, getAccessToken, walletAddress, onBalance, onInventory } = options;
834
+ const { apiBaseUrl, getAccessToken, walletAddress, onBalance, onInventory, onConnectionError } = options;
823
835
  const normalized = (walletAddress || "").trim().toLowerCase();
824
836
  if (!normalized || !/^0x[a-fa-f0-9]{40}$/.test(normalized)) {
825
837
  return () => {
826
838
  };
827
839
  }
828
840
  const base = apiBaseUrl.replace(/\/$/, "");
841
+ const reportConnectionError = (message) => {
842
+ if (onConnectionError) {
843
+ try {
844
+ onConnectionError(message);
845
+ } catch {
846
+ }
847
+ } else {
848
+ console.warn("[OmenX Realtime]", message);
849
+ }
850
+ };
829
851
  const authCallback = (_tokenParams, callback) => {
830
852
  getAccessToken().then((token) => {
831
853
  if (!token) {
@@ -853,17 +875,72 @@ function subscribeWalletRealtimeWithOmenXAuth(options) {
853
875
  callback(err instanceof Error ? err.message : String(err), null);
854
876
  });
855
877
  };
856
- const ably = new Ably.Realtime({
857
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
858
- authCallback
878
+ let ably = null;
879
+ let unsubscribeChannel = null;
880
+ let cancelled = false;
881
+ const cleanup = () => {
882
+ cancelled = true;
883
+ if (unsubscribeChannel) {
884
+ try {
885
+ unsubscribeChannel();
886
+ } catch {
887
+ }
888
+ unsubscribeChannel = null;
889
+ }
890
+ if (ably) {
891
+ try {
892
+ ably.close();
893
+ } catch {
894
+ }
895
+ ably = null;
896
+ }
897
+ };
898
+ const tokenPromise = getAccessToken().then((token) => {
899
+ if (!token) return null;
900
+ return fetch(`${base}/api/sdk/ably-token`, {
901
+ method: "POST",
902
+ headers: {
903
+ Authorization: `Bearer ${token}`,
904
+ "Content-Type": "application/json"
905
+ }
906
+ });
859
907
  });
860
- const unsubscribe = subscribeWalletRealtime(ably, walletAddress, {
861
- onBalance,
862
- onInventory
908
+ tokenPromise.then((res) => {
909
+ if (cancelled) return;
910
+ if (res === null) {
911
+ reportConnectionError("Realtime skipped: not authenticated");
912
+ return;
913
+ }
914
+ if (!res.ok) {
915
+ reportConnectionError(`Realtime unavailable: ${res.status}`);
916
+ return;
917
+ }
918
+ return res.json();
919
+ }).then((tokenRequest) => {
920
+ if (cancelled || tokenRequest === void 0) return;
921
+ ably = new Ably.Realtime({
922
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
923
+ authCallback
924
+ });
925
+ ably.connection.on("failed", (stateChange) => {
926
+ const msg = stateChange?.reason?.message ?? "Connection failed";
927
+ reportConnectionError(msg);
928
+ });
929
+ ably.connection.on("suspended", (stateChange) => {
930
+ const msg = stateChange?.reason?.message ?? "Connection to server unavailable";
931
+ reportConnectionError(msg);
932
+ });
933
+ unsubscribeChannel = subscribeWalletRealtime(ably, walletAddress, {
934
+ onBalance,
935
+ onInventory
936
+ });
937
+ }).catch((err) => {
938
+ if (!cancelled) {
939
+ reportConnectionError(err instanceof Error ? err.message : "Realtime setup failed");
940
+ }
863
941
  });
864
942
  return () => {
865
- unsubscribe();
866
- ably.close();
943
+ cleanup();
867
944
  };
868
945
  }
869
946
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/oauth.ts","../src/iframe-auth.ts","../src/token-manager.ts","../src/sdk.ts","../src/server-sdk.ts","../src/realtime.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { OAuthTokenResponse, OAuthOptions } from './types';\r\n\r\ninterface OAuthFlowConfig {\r\n gameId: string;\r\n oauthAuthorizeUrl: string;\r\n oauthTokenUrl: string;\r\n apiBaseUrl: string;\r\n onTokenReceived: (token: OAuthTokenResponse) => Promise<void>;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\nexport class OAuthFlow {\r\n private config: OAuthFlowConfig;\r\n\r\n constructor(config: OAuthFlowConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Authenticate user via OAuth 2.0 Authorization Code Grant with PKCE\r\n */\r\n async authenticate(options: OAuthOptions = {}): Promise<OAuthTokenResponse> {\r\n // Generate state for CSRF protection\r\n const state = this.generateState();\r\n \r\n // Generate PKCE code verifier and challenge\r\n const codeVerifier = this.generateCodeVerifier();\r\n const codeChallenge = await this.generateCodeChallenge(codeVerifier);\r\n \r\n return new Promise((resolve, reject) => {\r\n \r\n // Store code verifier in sessionStorage for later use\r\n sessionStorage.setItem(`omenx_pkce_${state}`, codeVerifier);\r\n \r\n // Build authorization URL\r\n const redirectUri = options.redirectUri || `${window.location.origin}/auth/callback`;\r\n const authUrl = new URL(this.config.oauthAuthorizeUrl);\r\n authUrl.searchParams.set('client_id', this.config.gameId);\r\n authUrl.searchParams.set('redirect_uri', redirectUri);\r\n authUrl.searchParams.set('response_type', 'code');\r\n authUrl.searchParams.set('scope', 'openid profile email');\r\n authUrl.searchParams.set('state', state);\r\n authUrl.searchParams.set('code_challenge', codeChallenge);\r\n authUrl.searchParams.set('code_challenge_method', 'S256');\r\n \r\n // Store state for verification\r\n const stateStorageKey = `omenx_oauth_state_${state}`;\r\n sessionStorage.setItem(stateStorageKey, state);\r\n \r\n // Open popup window\r\n const popup = window.open(\r\n authUrl.toString(),\r\n 'OmenX OAuth',\r\n 'width=500,height=600,left=100,top=100'\r\n );\r\n\r\n if (!popup) {\r\n const error = new Error('Failed to open popup window. Please allow popups for this site.');\r\n this.config.onError?.(error);\r\n reject(error);\r\n return;\r\n }\r\n\r\n // Clean up old OAuth callback entries from localStorage\r\n try {\r\n const allKeys = Object.keys(localStorage).filter(k => k.startsWith('omenx_oauth_callback_'));\r\n allKeys.forEach(key => {\r\n try {\r\n const data = localStorage.getItem(key);\r\n if (data) {\r\n const parsed = JSON.parse(data);\r\n const age = Date.now() - (parsed.timestamp || 0);\r\n // Remove entries older than 5 minutes\r\n if (age > 300000) {\r\n localStorage.removeItem(key);\r\n }\r\n }\r\n } catch (e) {\r\n localStorage.removeItem(key);\r\n }\r\n });\r\n } catch (error) {\r\n // Ignore cleanup errors\r\n }\r\n\r\n // Poll localStorage for callback data\r\n const storageKey = `omenx_oauth_callback_${state}`;\r\n let messageReceived = false;\r\n \r\n const pollInterval = setInterval(() => {\r\n if (messageReceived) {\r\n clearInterval(pollInterval);\r\n return;\r\n }\r\n \r\n const stored = localStorage.getItem(storageKey);\r\n \r\n if (stored) {\r\n try {\r\n const data = JSON.parse(stored);\r\n \r\n // Validate state and check timestamp\r\n if (data.code && data.state === state) {\r\n const age = Date.now() - (data.timestamp || 0);\r\n if (age < 30000) { // 30 second timeout\r\n messageReceived = true;\r\n clearInterval(pollInterval);\r\n \r\n // Clean up\r\n localStorage.removeItem(storageKey);\r\n sessionStorage.removeItem(`omenx_pkce_${state}`);\r\n sessionStorage.removeItem(stateStorageKey);\r\n \r\n // Exchange code for token\r\n this.exchangeCodeForToken(data.code, redirectUri, codeVerifier)\r\n .then(async (tokenResponse) => {\r\n await this.config.onTokenReceived(tokenResponse);\r\n // Close popup after successful token exchange\r\n if (popup && !popup.closed) {\r\n try {\r\n popup.close();\r\n } catch (e) {\r\n // Ignore errors closing popup\r\n }\r\n }\r\n resolve(tokenResponse);\r\n })\r\n .catch((error) => {\r\n this.config.onError?.(error as Error);\r\n reject(error);\r\n });\r\n return;\r\n } else {\r\n // Data too old, remove it\r\n localStorage.removeItem(storageKey);\r\n }\r\n }\r\n } catch (error) {\r\n console.error('[OAuthFlow] Error parsing localStorage callback:', error);\r\n }\r\n }\r\n }, 100); // Poll every 100ms\r\n \r\n // Check if popup was closed without completing auth\r\n const checkClosed = setInterval(() => {\r\n if (messageReceived) {\r\n clearInterval(checkClosed);\r\n return;\r\n }\r\n \r\n // Check if popup is actually closed\r\n let isClosed = false;\r\n try {\r\n if (popup.closed) {\r\n try {\r\n // Try to access location to verify it's actually closed\r\n popup.location.href; // Accessing this will throw if popup is on different origin\r\n isClosed = true;\r\n } catch (e) {\r\n // Can't access location - popup is on different origin (still open)\r\n isClosed = false;\r\n }\r\n }\r\n } catch (e) {\r\n isClosed = false;\r\n }\r\n \r\n if (isClosed) {\r\n clearInterval(checkClosed);\r\n clearInterval(pollInterval);\r\n \r\n // Clean up\r\n sessionStorage.removeItem(`omenx_pkce_${state}`);\r\n sessionStorage.removeItem(stateStorageKey);\r\n \r\n const error = new Error('Authentication was cancelled.');\r\n this.config.onError?.(error);\r\n reject(error);\r\n }\r\n }, 1000);\r\n });\r\n }\r\n\r\n /**\r\n * Exchange authorization code for access token\r\n */\r\n private async exchangeCodeForToken(\r\n code: string,\r\n redirectUri: string,\r\n codeVerifier?: string\r\n ): Promise<OAuthTokenResponse> {\r\n const body: any = {\r\n code,\r\n redirect_uri: redirectUri,\r\n grant_type: 'authorization_code',\r\n client_id: this.config.gameId,\r\n };\r\n\r\n if (codeVerifier) {\r\n body.code_verifier = codeVerifier;\r\n }\r\n\r\n const response = await fetch(this.config.oauthTokenUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.json().catch(() => ({ message: 'Failed to exchange code for token' }));\r\n throw new Error(error.message || 'Failed to exchange code for token');\r\n }\r\n\r\n return response.json();\r\n }\r\n\r\n /**\r\n * Generate random state for CSRF protection\r\n */\r\n private generateState(): string {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\r\n }\r\n\r\n /**\r\n * Generate PKCE code verifier\r\n */\r\n private generateCodeVerifier(): string {\r\n const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';\r\n const array = new Uint8Array(128);\r\n crypto.getRandomValues(array);\r\n return Array.from(array, byte => charset[byte % charset.length]).join('');\r\n }\r\n\r\n /**\r\n * Generate PKCE code challenge from verifier\r\n */\r\n private async generateCodeChallenge(verifier: string): Promise<string> {\r\n const encoder = new TextEncoder();\r\n const data = encoder.encode(verifier);\r\n const hash = await crypto.subtle.digest('SHA-256', data);\r\n const base64 = btoa(String.fromCharCode(...new Uint8Array(hash)));\r\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\r\n }\r\n}\r\n","import type { AuthData } from './types';\r\n\r\ninterface IframeAuthConfig {\r\n gameId: string;\r\n parentOrigin?: string;\r\n onAuth: (authData: AuthData) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/**\r\n * Handles authentication data passed from parent window via postMessage\r\n */\r\nexport class IframeAuth {\r\n private config: IframeAuthConfig;\r\n private messageListener: ((event: MessageEvent) => void) | null = null;\r\n\r\n constructor(config: IframeAuthConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Initialize iframe authentication listener\r\n */\r\n init(): void {\r\n // Request auth data from parent\r\n this.requestAuth();\r\n\r\n // Listen for auth data from parent\r\n this.messageListener = (event: MessageEvent) => {\r\n // Validate origin if specified\r\n if (this.config.parentOrigin) {\r\n try {\r\n const parentUrl = new URL(this.config.parentOrigin);\r\n if (event.origin !== parentUrl.origin) {\r\n return;\r\n }\r\n } catch {\r\n // If we can't parse parent origin, skip validation (development)\r\n }\r\n }\r\n\r\n // Handle auth data\r\n if (event.data?.type === 'OMENX_AUTH') {\r\n const authData = event.data.payload as AuthData;\r\n\r\n // Validate game ID\r\n if (authData.gameId !== this.config.gameId) {\r\n this.config.onError?.(new Error(`Game ID mismatch. Expected ${this.config.gameId}, got ${authData.gameId}`));\r\n return;\r\n }\r\n\r\n // Validate timestamp (5 minute expiry)\r\n const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);\r\n if (authData.timestamp < fiveMinutesAgo) {\r\n this.config.onError?.(new Error('Auth data expired'));\r\n return;\r\n }\r\n\r\n this.config.onAuth(authData);\r\n }\r\n };\r\n\r\n window.addEventListener('message', this.messageListener);\r\n }\r\n\r\n /**\r\n * Request authentication data from parent window\r\n */\r\n private requestAuth(): void {\r\n if (window.parent === window) {\r\n // Not in an iframe\r\n return;\r\n }\r\n\r\n // Send request to parent\r\n const parentOrigin = this.config.parentOrigin || '*';\r\n window.parent.postMessage(\r\n {\r\n type: 'OMENX_AUTH_REQUEST',\r\n gameId: this.config.gameId,\r\n },\r\n parentOrigin\r\n );\r\n }\r\n\r\n /**\r\n * Cleanup\r\n */\r\n destroy(): void {\r\n if (this.messageListener) {\r\n window.removeEventListener('message', this.messageListener);\r\n this.messageListener = null;\r\n }\r\n }\r\n}\r\n","import type { AuthData } from './types';\r\n\r\n/**\r\n * Manages token storage and retrieval\r\n */\r\nexport class TokenManager {\r\n private storageKeyPrefix: string;\r\n\r\n constructor(storageKeyPrefix: string = 'omenx_game_') {\r\n this.storageKeyPrefix = storageKeyPrefix;\r\n }\r\n\r\n /**\r\n * Store authentication data\r\n */\r\n storeAuth(authData: AuthData, refreshToken: string, expiresIn: number): void {\r\n try {\r\n localStorage.setItem(`${this.storageKeyPrefix}auth`, JSON.stringify(authData));\r\n localStorage.setItem(`${this.storageKeyPrefix}refresh_token`, refreshToken);\r\n localStorage.setItem(`${this.storageKeyPrefix}expires_at`, String(Date.now() + (expiresIn * 1000)));\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to store auth data:', error);\r\n }\r\n }\r\n\r\n /**\r\n * Get stored authentication data\r\n */\r\n getStoredAuth(): AuthData | null {\r\n try {\r\n const stored = localStorage.getItem(`${this.storageKeyPrefix}auth`);\r\n if (!stored) {\r\n return null;\r\n }\r\n return JSON.parse(stored) as AuthData;\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to retrieve auth data:', error);\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Get stored refresh token\r\n */\r\n getRefreshToken(): string | null {\r\n try {\r\n return localStorage.getItem(`${this.storageKeyPrefix}refresh_token`);\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to retrieve refresh token:', error);\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Clear all stored authentication data\r\n */\r\n clearStorage(): void {\r\n try {\r\n localStorage.removeItem(`${this.storageKeyPrefix}auth`);\r\n localStorage.removeItem(`${this.storageKeyPrefix}refresh_token`);\r\n localStorage.removeItem(`${this.storageKeyPrefix}expires_at`);\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to clear storage:', error);\r\n }\r\n }\r\n}\r\n","import type {\r\n OmenXGameSDKConfig,\r\n AuthData,\r\n OAuthOptions,\r\n OAuthTokenResponse,\r\n ApiCallOptions,\r\n VipStatus,\r\n} from './types';\r\nimport { OAuthFlow } from './oauth';\r\nimport { IframeAuth } from './iframe-auth';\r\nimport { TokenManager } from './token-manager';\r\n\r\n/**\r\n * OmenX Game SDK\r\n * \r\n * Provides authentication and API integration for games on the OmenX platform.\r\n * Supports both OAuth-style authentication and iframe authentication passing.\r\n */\r\nexport class OmenXGameSDK {\r\n private config: Required<OmenXGameSDKConfig>;\r\n private oauthFlow: OAuthFlow;\r\n private iframeAuth: IframeAuth | null = null;\r\n private tokenManager: TokenManager;\r\n private currentAuthData: AuthData | null = null;\r\n\r\n constructor(config: OmenXGameSDKConfig) {\r\n // Set defaults\r\n const apiBaseUrl = config.apiBaseUrl || 'https://api.omen.foundation';\r\n this.config = {\r\n gameId: config.gameId,\r\n apiBaseUrl: apiBaseUrl,\r\n oauthAuthorizeUrl: config.oauthAuthorizeUrl || `${apiBaseUrl}/v1/oauth/authorize`,\r\n oauthTokenUrl: config.oauthTokenUrl || `${apiBaseUrl}/v1/oauth/token`,\r\n onAuth: config.onAuth || (() => {}),\r\n onAuthError: config.onAuthError || ((error) => console.error('[OmenX SDK] Auth error:', error)),\r\n onLogout: config.onLogout || (() => {}),\r\n enableIframeAuth: config.enableIframeAuth !== false,\r\n parentOrigin: config.parentOrigin ?? '',\r\n storageKeyPrefix: config.storageKeyPrefix || 'omenx_game_',\r\n };\r\n\r\n // Initialize components\r\n this.tokenManager = new TokenManager(this.config.storageKeyPrefix);\r\n this.oauthFlow = new OAuthFlow({\r\n gameId: this.config.gameId,\r\n oauthAuthorizeUrl: this.config.oauthAuthorizeUrl,\r\n oauthTokenUrl: this.config.oauthTokenUrl,\r\n apiBaseUrl: this.config.apiBaseUrl,\r\n onTokenReceived: this.handleTokenReceived.bind(this),\r\n onError: this.config.onAuthError,\r\n });\r\n\r\n if (this.config.enableIframeAuth) {\r\n this.iframeAuth = new IframeAuth({\r\n gameId: this.config.gameId,\r\n parentOrigin: this.config.parentOrigin || undefined,\r\n onAuth: this.handleAuthData.bind(this),\r\n onError: this.config.onAuthError,\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Initialize the SDK\r\n * Call this after creating an instance\r\n */\r\n async init(): Promise<void> {\r\n // Try to restore from stored token\r\n const storedAuth = this.tokenManager.getStoredAuth();\r\n if (storedAuth) {\r\n // Check if token is still valid (not expired)\r\n const expiresAt = storedAuth.timestamp + (3600 * 1000); // 1 hour default\r\n if (Date.now() < expiresAt) {\r\n this.currentAuthData = storedAuth;\r\n this.config.onAuth(storedAuth);\r\n return;\r\n } else {\r\n // Token expired, try to refresh\r\n const refreshToken = this.tokenManager.getRefreshToken();\r\n if (refreshToken) {\r\n try {\r\n await this.refreshAccessToken(refreshToken);\r\n return;\r\n } catch (error) {\r\n // Refresh failed, clear storage\r\n this.tokenManager.clearStorage();\r\n }\r\n }\r\n }\r\n }\r\n\r\n // If iframe auth is enabled, try to get auth from parent\r\n if (this.config.enableIframeAuth && this.iframeAuth !== null) {\r\n this.iframeAuth.init();\r\n }\r\n }\r\n\r\n /**\r\n * Authenticate user via OAuth popup\r\n */\r\n async authenticate(options: OAuthOptions): Promise<AuthData> {\r\n const tokenResponse = await this.oauthFlow.authenticate(options);\r\n // Convert OAuthTokenResponse to AuthData\r\n return {\r\n accessToken: tokenResponse.access_token,\r\n walletAddress: tokenResponse.user.walletAddress,\r\n userId: tokenResponse.user.userId,\r\n profileName: tokenResponse.user.profileName,\r\n profilePicture: tokenResponse.user.profilePicture,\r\n email: tokenResponse.user.email,\r\n gameId: this.config.gameId,\r\n timestamp: Date.now(),\r\n };\r\n }\r\n\r\n /**\r\n * Get current authentication data\r\n */\r\n getAuthData(): AuthData | null {\r\n return this.currentAuthData;\r\n }\r\n\r\n /**\r\n * Check if user is authenticated\r\n */\r\n isAuthenticated(): boolean {\r\n return this.currentAuthData !== null;\r\n }\r\n\r\n /**\r\n * Logout user\r\n */\r\n async logout(): Promise<void> {\r\n // Revoke token if we have one\r\n if (this.currentAuthData?.accessToken) {\r\n try {\r\n await this.apiCall('/v1/oauth/revoke', {\r\n method: 'POST',\r\n body: { token: this.currentAuthData.accessToken },\r\n includeAuth: false, // Don't include auth header for revoke\r\n });\r\n } catch (error) {\r\n // Ignore errors on revoke\r\n console.warn('[OmenX SDK] Failed to revoke token:', error);\r\n }\r\n }\r\n\r\n // Clear local state\r\n this.currentAuthData = null;\r\n this.tokenManager.clearStorage();\r\n this.config.onLogout();\r\n }\r\n\r\n /**\r\n * Make an authenticated API call\r\n */\r\n async apiCall(endpoint: string, options: ApiCallOptions = {}): Promise<Response> {\r\n const url = endpoint.startsWith('http') \r\n ? endpoint \r\n : `${this.config.apiBaseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;\r\n\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n ...options.headers,\r\n };\r\n\r\n // Add authentication header if needed\r\n if (options.includeAuth !== false && this.currentAuthData?.accessToken) {\r\n headers['Authorization'] = `Bearer ${this.currentAuthData.accessToken}`;\r\n }\r\n\r\n const fetchOptions: RequestInit = {\r\n method: options.method || 'GET',\r\n headers,\r\n };\r\n\r\n if (options.body && options.method !== 'GET') {\r\n fetchOptions.body = JSON.stringify(options.body);\r\n }\r\n\r\n const response = await fetch(url, fetchOptions);\r\n\r\n // If unauthorized, try to refresh token\r\n if (response.status === 401 && this.currentAuthData) {\r\n const refreshToken = this.tokenManager.getRefreshToken();\r\n if (refreshToken) {\r\n try {\r\n await this.refreshAccessToken(refreshToken);\r\n // Retry the request with new token\r\n if (this.currentAuthData?.accessToken) {\r\n headers['Authorization'] = `Bearer ${this.currentAuthData.accessToken}`;\r\n return fetch(url, { ...fetchOptions, headers });\r\n }\r\n } catch (error) {\r\n // Refresh failed, logout\r\n await this.logout();\r\n throw new Error('Authentication expired. Please login again.');\r\n }\r\n }\r\n }\r\n\r\n return response;\r\n }\r\n\r\n /**\r\n * Handle token received from OAuth flow\r\n */\r\n private async handleTokenReceived(tokenResponse: OAuthTokenResponse): Promise<void> {\r\n const authData: AuthData = {\r\n accessToken: tokenResponse.access_token,\r\n walletAddress: tokenResponse.user.walletAddress,\r\n userId: tokenResponse.user.userId,\r\n profileName: tokenResponse.user.profileName,\r\n profilePicture: tokenResponse.user.profilePicture,\r\n email: tokenResponse.user.email,\r\n gameId: this.config.gameId,\r\n timestamp: Date.now(),\r\n };\r\n\r\n // Store tokens\r\n this.tokenManager.storeAuth(authData, tokenResponse.refresh_token, tokenResponse.expires_in);\r\n\r\n // Update current auth\r\n this.currentAuthData = authData;\r\n this.config.onAuth(authData);\r\n }\r\n\r\n /**\r\n * Handle auth data from iframe\r\n */\r\n private handleAuthData(authData: AuthData): void {\r\n // Validate timestamp (5 minute expiry)\r\n const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);\r\n if (authData.timestamp < fiveMinutesAgo) {\r\n this.config.onAuthError(new Error('Auth data expired'));\r\n return;\r\n }\r\n\r\n // Update current auth\r\n this.currentAuthData = authData;\r\n this.config.onAuth(authData);\r\n }\r\n\r\n /**\r\n * Get current VIP status for the authenticated user (tier, allocation, claimable, perks).\r\n * Games can read tier.gameBonusPointsLevel (1–21) for Alpha/Beta access or in-game gifts.\r\n */\r\n async getVipStatus(): Promise<VipStatus | null> {\r\n const response = await this.apiCall('/api/vip/me');\r\n if (!response.ok) return null;\r\n const data = await response.json();\r\n if (data.success && data.data) return data.data as VipStatus;\r\n return null;\r\n }\r\n\r\n /**\r\n * Get the current user's game bonus points level (1–21) from their VIP tier.\r\n * Use for Game Alpha Access (e.g. level >= 6), Game Beta Access (e.g. level >= 1), or in-game gifts.\r\n */\r\n async getGameBonusPointsLevel(): Promise<number | null> {\r\n const status = await this.getVipStatus();\r\n if (!status?.tier) return null;\r\n const level = status.tier.gameBonusPointsLevel ?? (status.tier.perks?.GAME_BONUS_POINTS_LEVEL as number);\r\n return typeof level === 'number' && level >= 1 && level <= 21 ? level : null;\r\n }\r\n\r\n /**\r\n * Refresh access token using refresh token\r\n */\r\n private async refreshAccessToken(refreshToken: string): Promise<void> {\r\n const response = await fetch(this.config.oauthTokenUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n grant_type: 'refresh_token',\r\n refresh_token: refreshToken,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error('Failed to refresh token');\r\n }\r\n\r\n const tokenResponse: OAuthTokenResponse = await response.json();\r\n await this.handleTokenReceived(tokenResponse);\r\n }\r\n}\r\n","import type { ApiCallOptions } from './types';\n\ninterface ServerSDKConfig {\n /**\n * Your developer API key (from developer portal)\n */\n apiKey: string;\n\n /**\n * OmenX API base URL (default: https://api.omen.foundation)\n */\n apiBaseUrl?: string;\n}\n\n/**\n * OmenX Game SDK - Server Mode\n * \n * For Node.js backends using developer API keys.\n * This mode allows server-to-server communication with the OmenX API.\n */\nexport class OmenXServerSDK {\n private config: Required<ServerSDKConfig>;\n private apiKey: string;\n\n constructor(config: ServerSDKConfig) {\n this.apiKey = config.apiKey;\n this.config = {\n apiKey: config.apiKey,\n apiBaseUrl: config.apiBaseUrl || 'https://api.omen.foundation',\n };\n }\n\n /**\n * Make an authenticated API call using the developer API key\n */\n async apiCall(endpoint: string, options: ApiCallOptions = {}): Promise<Response> {\n const url = endpoint.startsWith('http') \n ? endpoint \n : `${this.config.apiBaseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n ...options.headers,\n };\n\n const fetchOptions: RequestInit = {\n method: options.method || 'GET',\n headers,\n };\n\n if (options.body && options.method !== 'GET') {\n fetchOptions.body = JSON.stringify(options.body);\n }\n\n const response = await fetch(url, fetchOptions);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new Error(`API call failed: ${response.status} ${response.statusText} - ${errorText}`);\n }\n\n return response;\n }\n\n /**\n * Health check\n */\n async healthCheck(): Promise<any> {\n const response = await this.apiCall('/v1/health', { includeAuth: false });\n return response.json();\n }\n\n /**\n * Get API key information\n */\n async getApiKeyInfo(): Promise<any> {\n const response = await this.apiCall('/v1/auth/me');\n return response.json();\n }\n\n /**\n * Player Operations\n */\n\n /**\n * Get full player data: NFTs (system + game) and balances for a wallet.\n * Requires both nfts:read and balances:read scopes.\n */\n async getPlayer(wallet: string, chainId: string): Promise<any> {\n const response = await this.apiCall(\n `/v1/players/${encodeURIComponent(wallet)}?chainId=${encodeURIComponent(chainId)}`\n );\n return response.json();\n }\n\n /**\n * Get native and ERC20 token balances for a wallet\n */\n async getPlayerBalances(wallet: string, chainId: string): Promise<any> {\n const response = await this.apiCall(\n `/v1/players/${encodeURIComponent(wallet)}/balances?chainId=${encodeURIComponent(chainId)}`\n );\n return response.json();\n }\n\n /**\n * Get paginated NFTs for a wallet.\n * With no contract: returns OmenX system NFTs (Asset Manager, Faucet, Early Adopter) + game NFTs.\n * With contract: returns only NFTs for that contract.\n */\n async getPlayerNfts(\n wallet: string,\n chainId: string,\n options?: {\n contract?: string;\n cursor?: string;\n limit?: number;\n }\n ): Promise<any> {\n const params = new URLSearchParams({ chainId });\n if (options?.contract) params.set('contract', options.contract);\n if (options?.cursor) params.set('cursor', options.cursor);\n if (options?.limit != null) params.set('limit', String(options.limit));\n\n const response = await this.apiCall(\n `/v1/players/${encodeURIComponent(wallet)}/nfts?${params.toString()}`\n );\n return response.json();\n }\n\n /**\n * Purchase Operations\n */\n\n /**\n * Create a server-authoritative purchase\n */\n async createPurchase(params: {\n playerWallet?: string;\n walletAddress?: string; // Legacy field name\n skuId?: string;\n sku?: string; // Legacy field name\n quantity?: number;\n idempotencyKey?: string;\n paymentMethod?: string;\n metadata?: Record<string, any>;\n }): Promise<any> {\n const response = await this.apiCall('/v1/purchases', {\n method: 'POST',\n body: params,\n headers: params.idempotencyKey ? {\n 'Idempotency-Key': params.idempotencyKey,\n } : undefined,\n });\n return response.json();\n }\n\n /**\n * NFT Template Operations\n */\n\n /**\n * Get all NFT templates for the authenticated game (game is derived from API key).\n * gameId is optional and ignored by the API; included for backward compatibility.\n */\n async getNftTemplates(_gameId?: string): Promise<any> {\n const response = await this.apiCall('/v1/nfts/templates');\n return response.json();\n }\n\n /**\n * Get NFT contract address for the authenticated game (game is derived from API key).\n * gameId is optional and ignored by the API; included for backward compatibility.\n */\n async getNftContract(_gameId?: string): Promise<any> {\n const response = await this.apiCall('/v1/nfts/contract');\n return response.json();\n }\n\n /**\n * Mint NFTs (single or batch)\n */\n async mintNfts(params: {\n templateId: string;\n recipientAddress: string;\n quantity: number;\n }): Promise<any> {\n const response = await this.apiCall('/v1/nfts/mint', {\n method: 'POST',\n body: params,\n });\n return response.json();\n }\n\n /**\n * Batch mint NFTs\n */\n async batchMintNfts(mints: Array<{\n templateId: string;\n recipientAddress: string;\n quantity: number;\n }>): Promise<any> {\n const response = await this.apiCall('/v1/nfts/mint/batch', {\n method: 'POST',\n body: { mints },\n });\n return response.json();\n }\n\n /**\n * Update NFT metadata\n */\n async updateNftMetadata(\n tokenId: string,\n metadata: {\n attributes?: Record<string, string | number | boolean>;\n name?: string;\n description?: string;\n imageUrl?: string;\n }\n ): Promise<any> {\n const response = await this.apiCall(`/v1/nfts/${tokenId}/metadata`, {\n method: 'PUT',\n body: metadata,\n });\n return response.json();\n }\n\n /**\n * Burn NFT (single)\n */\n async burnNft(tokenId: string): Promise<any> {\n const response = await this.apiCall(`/v1/nfts/${tokenId}`, {\n method: 'DELETE',\n });\n return response.json();\n }\n\n /**\n * Batch burn NFTs\n */\n async batchBurnNfts(tokenIds: string[]): Promise<any> {\n const response = await this.apiCall('/v1/nfts/burn/batch', {\n method: 'POST',\n body: { tokenIds },\n });\n return response.json();\n }\n\n /**\n * Pack opener - mint random NFTs from a drop table\n */\n async packOpener(params: {\n dropTableId: string;\n recipientAddress: string;\n }): Promise<any> {\n const response = await this.apiCall('/v1/nfts/pack-opener', {\n method: 'POST',\n body: params,\n });\n return response.json();\n }\n\n /**\n * VIP Points (Developer pool)\n * Requires scope: vip_points:write.\n * Grants VIP points to a player from this game's allocated pool. Enforces total allocation and max per quest.\n * Call from your game backend only (API key auth); not for client-side use.\n */\n async grantVipPoints(params: {\n /** Player wallet address (0x-prefixed, 40 hex chars). */\n wallet: string;\n /** Points to grant (positive integer). Capped by pool remaining and max per quest. */\n amount: number;\n /** Optional quest/activity id for idempotency or auditing. */\n questId?: string;\n }): Promise<{ success: boolean; data?: { wallet: string; amount: number; phaseIndex?: number } }> {\n const response = await this.apiCall('/v1/vip/grant-points', {\n method: 'POST',\n body: params,\n });\n return response.json();\n }\n\n /**\n * Quests API (game quests only).\n * Requires scope: quests:read for getQuestsForPlayer; quests:write for assign, progress, complete, claim.\n */\n\n /** Get assigned quests for a player. Optional questType filter. */\n async getQuestsForPlayer(\n wallet: string,\n options?: { questType?: 'daily' | 'weekly' | 'monthly' | 'oneTime' }\n ): Promise<{ success: boolean; data: { quests: any[] } }> {\n const q = options?.questType ? `?questType=${options.questType}` : '';\n const response = await this.apiCall(`/v1/quests/players/${encodeURIComponent(wallet)}${q}`);\n return response.json();\n }\n\n /** Assign quests of a type to a player. Use idempotencyKey for safe retries. */\n async assignQuests(\n wallet: string,\n questType: 'daily' | 'weekly' | 'monthly' | 'oneTime',\n count: number,\n options?: { idempotencyKey?: string }\n ): Promise<{ success: boolean; data: { assigned: number; assignmentIds?: string[] } }> {\n const response = await this.apiCall(`/v1/quests/players/${encodeURIComponent(wallet)}/assign`, {\n method: 'POST',\n body: { questType, count },\n headers: options?.idempotencyKey ? { 'Idempotency-Key': options.idempotencyKey } : undefined,\n });\n return response.json();\n }\n\n /** Report progress for a quest step. Quest auto-completes when all steps meet targets. */\n async reportQuestProgress(\n wallet: string,\n questKey: string,\n value: number,\n options?: { stepKey?: string }\n ): Promise<{ success: boolean; data?: object }> {\n const response = await this.apiCall('/v1/quests/progress', {\n method: 'POST',\n body: { wallet, questKey, value, stepKey: options?.stepKey },\n });\n return response.json();\n }\n\n /** Mark a quest complete (all steps set to targets). */\n async completeQuest(wallet: string, questKey: string): Promise<{ success: boolean; data?: object }> {\n const response = await this.apiCall('/v1/quests/complete', {\n method: 'POST',\n body: { wallet, questKey },\n });\n return response.json();\n }\n\n /** Claim VIP reward for a completed quest (from game pool). Use idempotencyKey for safe retries. */\n async claimQuestReward(\n wallet: string,\n questKey: string,\n options?: { idempotencyKey?: string }\n ): Promise<{ success: boolean; data?: { pointsGranted?: number } }> {\n const response = await this.apiCall('/v1/quests/claim', {\n method: 'POST',\n body: { wallet, questKey },\n headers: options?.idempotencyKey ? { 'Idempotency-Key': options.idempotencyKey } : undefined,\n });\n return response.json();\n }\n\n /**\n * Reset or wipe a player's quest state for this game. Requires quests:write.\n * - wipe: delete all quest assignments for this game for the player.\n * - reset: delete assignments for the specified questKey only (questKey required).\n */\n async resetPlayerQuests(\n wallet: string,\n action: 'wipe' | 'reset',\n questKey?: string\n ): Promise<{ success: boolean; data: { action: string; deleted: number; questKey?: string } }> {\n const body: { action: 'wipe' | 'reset'; questKey?: string } = { action };\n if (action === 'reset' && questKey) body.questKey = questKey;\n const response = await this.apiCall('/v1/quests/players/' + encodeURIComponent(wallet) + '/reset', {\n method: 'POST',\n body,\n });\n return response.json();\n }\n}\n","/**\r\n * Real-time wallet updates (balance & inventory) for game clients.\r\n * Subscribe to the per-wallet Ably channel so the game stays in sync when the user\r\n * spends or receives OmenX / NFTs on the website or in another client.\r\n *\r\n * Two options:\r\n * 1. subscribeWalletRealtimeWithOmenXAuth – no API key needed; SDK gets a scoped token from the OmenX platform using your access token.\r\n * 2. subscribeWalletRealtime – pass your own Ably Realtime instance (e.g. from an API key or your own token).\r\n */\r\n\r\nimport Ably from 'ably';\r\n\r\n/** Payload for balance and inventory events. Use eventId for idempotency (ignore if already processed). */\r\nexport interface RealtimeWalletPayload {\r\n eventId: string;\r\n timestamp: number;\r\n reason?: string;\r\n}\r\n\r\n/** Ably channel name prefix. Full channel = \"wallet:\" + normalized wallet address. */\r\nexport const WALLET_CHANNEL_PREFIX = 'wallet:';\r\n\r\n/** Event names published by the OmenX backend on the wallet channel. */\r\nexport const REALTIME_EVENTS = {\r\n /** Currency balance changed. Refetch via GetPlayerBalances or your balance API. */\r\n balance: 'balance',\r\n /** NFT/inventory changed. Refetch via GetPlayerNfts or your inventory API (cache is source of truth). */\r\n inventory: 'inventory',\r\n} as const;\r\n\r\nconst MAX_SEEN_IDS = 200;\r\n\r\n/**\r\n * Normalize wallet address for channel name (lowercase, no 0x prefix change).\r\n */\r\nfunction normalizeWallet(wallet: string): string {\r\n return (wallet || '').trim().toLowerCase();\r\n}\r\n\r\n/**\r\n * Get the Ably channel name for a wallet. Use this when subscribing with your Ably client.\r\n */\r\nexport function getWalletChannelName(walletAddress: string): string {\r\n return WALLET_CHANNEL_PREFIX + normalizeWallet(walletAddress);\r\n}\r\n\r\n/**\r\n * Minimal Ably Realtime interface so the SDK works with any Ably.Realtime instance.\r\n * The app provides the real Ably client from AblyProvider or new Ably.Realtime({ key }).\r\n */\r\nexport interface AblyRealtimeLike {\r\n channels: {\r\n get(name: string): {\r\n subscribe(eventOrCallback: string | ((message: { name: string; data: unknown }) => void), callback?: (message: { name: string; data: unknown }) => void): void;\r\n unsubscribe(eventOrCallback?: string | ((message: { name: string; data: unknown }) => void), callback?: (message: { name: string; data: unknown }) => void): void;\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * Subscribe to real-time balance and inventory events for a wallet.\r\n * Call when the user logs in; call the returned unsubscribe when they log out or wallet changes.\r\n *\r\n * Uses eventId to dedupe (ignores already-seen events). Refetch in your app on each callback.\r\n *\r\n * @param ably - Ably Realtime instance (e.g. from useAbly() or new Ably.Realtime({ key }))\r\n * @param walletAddress - Current player wallet (0x...)\r\n * @param callbacks - onBalance and/or onInventory; each receives the payload (eventId, timestamp, reason?)\r\n * @returns Unsubscribe function\r\n */\r\nexport function subscribeWalletRealtime(\r\n ably: AblyRealtimeLike,\r\n walletAddress: string,\r\n callbacks: {\r\n onBalance?: (payload: RealtimeWalletPayload) => void;\r\n onInventory?: (payload: RealtimeWalletPayload) => void;\r\n }\r\n): () => void {\r\n const normalized = normalizeWallet(walletAddress);\r\n if (!normalized || !/^0x[a-fa-f0-9]{40}$/.test(normalized)) {\r\n return () => {};\r\n }\r\n\r\n const seenIds = new Set<string>();\r\n\r\n const handleMessage = (message: { name: string; data: unknown }) => {\r\n const data = message.data as RealtimeWalletPayload | undefined;\r\n if (!data || typeof data !== 'object' || typeof data.eventId !== 'string') return;\r\n if (seenIds.has(data.eventId)) return;\r\n if (seenIds.size >= MAX_SEEN_IDS) {\r\n const first = seenIds.values().next().value;\r\n if (first != null) seenIds.delete(first);\r\n }\r\n seenIds.add(data.eventId);\r\n\r\n if (message.name === REALTIME_EVENTS.balance && callbacks.onBalance) {\r\n callbacks.onBalance(data);\r\n } else if (message.name === REALTIME_EVENTS.inventory && callbacks.onInventory) {\r\n callbacks.onInventory(data);\r\n }\r\n };\r\n\r\n const channel = ably.channels.get(getWalletChannelName(normalized));\r\n channel.subscribe(handleMessage);\r\n\r\n return () => {\r\n channel.unsubscribe(handleMessage);\r\n };\r\n}\r\n\r\n/** Options for subscribing via OmenX platform token (no Ably API key required). */\r\nexport interface SubscribeWalletRealtimeWithOmenXAuthOptions {\r\n /** Base URL of the OmenX API (e.g. https://api.omen.foundation). No trailing slash. */\r\n apiBaseUrl: string;\r\n /** Returns the current OmenX access token (from your OAuth flow). Called when Ably needs to authenticate. */\r\n getAccessToken: () => Promise<string | null>;\r\n /** Wallet address (0x...) to subscribe to. Must match the wallet in the access token. */\r\n walletAddress: string;\r\n onBalance?: (payload: RealtimeWalletPayload) => void;\r\n onInventory?: (payload: RealtimeWalletPayload) => void;\r\n}\r\n\r\n/**\r\n * Subscribe to real-time balance and inventory for a wallet using OmenX platform auth.\r\n * The SDK fetches a short-lived, subscribe-only Ably token from the OmenX API using your\r\n * access token. No Ably API key or .env is required – ideal for third-party developers.\r\n *\r\n * Requires the app to have `ably` installed (peer dependency). Call when the user is\r\n * logged in; call the returned function on logout or wallet change.\r\n */\r\nexport function subscribeWalletRealtimeWithOmenXAuth(\r\n options: SubscribeWalletRealtimeWithOmenXAuthOptions\r\n): () => void {\r\n const { apiBaseUrl, getAccessToken, walletAddress, onBalance, onInventory } = options;\r\n const normalized = (walletAddress || '').trim().toLowerCase();\r\n if (!normalized || !/^0x[a-fa-f0-9]{40}$/.test(normalized)) {\r\n return () => {};\r\n }\r\n\r\n const base = apiBaseUrl.replace(/\\/$/, '');\r\n const authCallback = (\r\n _tokenParams: unknown,\r\n callback: (error: string | null, tokenRequestOrDetails: unknown) => void\r\n ): void => {\r\n getAccessToken()\r\n .then((token) => {\r\n if (!token) {\r\n callback('Not authenticated', null);\r\n return;\r\n }\r\n return fetch(`${base}/api/sdk/ably-token`, {\r\n method: 'POST',\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n });\r\n })\r\n .then((res) => {\r\n if (!res) return;\r\n if (!res.ok) {\r\n return res.json().then((body: { message?: string }) => {\r\n callback((body && body.message) || res.statusText || 'Request failed', null);\r\n });\r\n }\r\n return res.json().then((tokenRequest: unknown) => {\r\n callback(null, tokenRequest);\r\n });\r\n })\r\n .catch((err: unknown) => {\r\n callback(err instanceof Error ? err.message : String(err), null);\r\n });\r\n };\r\n const ably = new Ably.Realtime({\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n authCallback: authCallback as any,\r\n });\r\n\r\n const unsubscribe = subscribeWalletRealtime(ably as AblyRealtimeLike, walletAddress, {\r\n onBalance,\r\n onInventory,\r\n });\r\n\r\n return () => {\r\n unsubscribe();\r\n ably.close();\r\n };\r\n}\r\n"]}
1
+ {"version":3,"sources":["../src/oauth.ts","../src/iframe-auth.ts","../src/token-manager.ts","../src/sdk.ts","../src/server-sdk.ts","../src/realtime.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { OAuthTokenResponse, OAuthOptions } from './types';\r\n\r\ninterface OAuthFlowConfig {\r\n gameId: string;\r\n oauthAuthorizeUrl: string;\r\n oauthTokenUrl: string;\r\n apiBaseUrl: string;\r\n onTokenReceived: (token: OAuthTokenResponse) => Promise<void>;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\nexport class OAuthFlow {\r\n private config: OAuthFlowConfig;\r\n\r\n constructor(config: OAuthFlowConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Authenticate user via OAuth 2.0 Authorization Code Grant with PKCE\r\n */\r\n async authenticate(options: OAuthOptions = {}): Promise<OAuthTokenResponse> {\r\n // Generate state for CSRF protection\r\n const state = this.generateState();\r\n \r\n // Generate PKCE code verifier and challenge\r\n const codeVerifier = this.generateCodeVerifier();\r\n const codeChallenge = await this.generateCodeChallenge(codeVerifier);\r\n \r\n return new Promise((resolve, reject) => {\r\n \r\n // Store code verifier in sessionStorage for later use\r\n sessionStorage.setItem(`omenx_pkce_${state}`, codeVerifier);\r\n \r\n // Build authorization URL\r\n const redirectUri = options.redirectUri || `${window.location.origin}/auth/callback`;\r\n const authUrl = new URL(this.config.oauthAuthorizeUrl);\r\n authUrl.searchParams.set('client_id', this.config.gameId);\r\n authUrl.searchParams.set('redirect_uri', redirectUri);\r\n authUrl.searchParams.set('response_type', 'code');\r\n authUrl.searchParams.set('scope', 'openid profile email');\r\n authUrl.searchParams.set('state', state);\r\n authUrl.searchParams.set('code_challenge', codeChallenge);\r\n authUrl.searchParams.set('code_challenge_method', 'S256');\r\n \r\n // Store state for verification\r\n const stateStorageKey = `omenx_oauth_state_${state}`;\r\n sessionStorage.setItem(stateStorageKey, state);\r\n \r\n // Open popup window\r\n const popup = window.open(\r\n authUrl.toString(),\r\n 'OmenX OAuth',\r\n 'width=500,height=600,left=100,top=100'\r\n );\r\n\r\n if (!popup) {\r\n const error = new Error('Failed to open popup window. Please allow popups for this site.');\r\n this.config.onError?.(error);\r\n reject(error);\r\n return;\r\n }\r\n\r\n // Clean up old OAuth callback entries from localStorage\r\n try {\r\n const allKeys = Object.keys(localStorage).filter(k => k.startsWith('omenx_oauth_callback_'));\r\n allKeys.forEach(key => {\r\n try {\r\n const data = localStorage.getItem(key);\r\n if (data) {\r\n const parsed = JSON.parse(data);\r\n const age = Date.now() - (parsed.timestamp || 0);\r\n // Remove entries older than 5 minutes\r\n if (age > 300000) {\r\n localStorage.removeItem(key);\r\n }\r\n }\r\n } catch (e) {\r\n localStorage.removeItem(key);\r\n }\r\n });\r\n } catch (error) {\r\n // Ignore cleanup errors\r\n }\r\n\r\n // Poll localStorage for callback data\r\n const storageKey = `omenx_oauth_callback_${state}`;\r\n let messageReceived = false;\r\n \r\n const pollInterval = setInterval(() => {\r\n if (messageReceived) {\r\n clearInterval(pollInterval);\r\n return;\r\n }\r\n \r\n const stored = localStorage.getItem(storageKey);\r\n \r\n if (stored) {\r\n try {\r\n const data = JSON.parse(stored);\r\n \r\n // Validate state and check timestamp\r\n if (data.code && data.state === state) {\r\n const age = Date.now() - (data.timestamp || 0);\r\n if (age < 30000) { // 30 second timeout\r\n messageReceived = true;\r\n clearInterval(pollInterval);\r\n \r\n // Clean up\r\n localStorage.removeItem(storageKey);\r\n sessionStorage.removeItem(`omenx_pkce_${state}`);\r\n sessionStorage.removeItem(stateStorageKey);\r\n \r\n // Exchange code for token\r\n this.exchangeCodeForToken(data.code, redirectUri, codeVerifier)\r\n .then(async (tokenResponse) => {\r\n await this.config.onTokenReceived(tokenResponse);\r\n // Close popup after successful token exchange\r\n if (popup && !popup.closed) {\r\n try {\r\n popup.close();\r\n } catch (e) {\r\n // Ignore errors closing popup\r\n }\r\n }\r\n resolve(tokenResponse);\r\n })\r\n .catch((error) => {\r\n this.config.onError?.(error as Error);\r\n reject(error);\r\n });\r\n return;\r\n } else {\r\n // Data too old, remove it\r\n localStorage.removeItem(storageKey);\r\n }\r\n }\r\n } catch (error) {\r\n console.error('[OAuthFlow] Error parsing localStorage callback:', error);\r\n }\r\n }\r\n }, 100); // Poll every 100ms\r\n \r\n // Check if popup was closed without completing auth\r\n const checkClosed = setInterval(() => {\r\n if (messageReceived) {\r\n clearInterval(checkClosed);\r\n return;\r\n }\r\n \r\n // Check if popup is actually closed\r\n let isClosed = false;\r\n try {\r\n if (popup.closed) {\r\n try {\r\n // Try to access location to verify it's actually closed\r\n popup.location.href; // Accessing this will throw if popup is on different origin\r\n isClosed = true;\r\n } catch (e) {\r\n // Can't access location - popup is on different origin (still open)\r\n isClosed = false;\r\n }\r\n }\r\n } catch (e) {\r\n isClosed = false;\r\n }\r\n \r\n if (isClosed) {\r\n clearInterval(checkClosed);\r\n clearInterval(pollInterval);\r\n \r\n // Clean up\r\n sessionStorage.removeItem(`omenx_pkce_${state}`);\r\n sessionStorage.removeItem(stateStorageKey);\r\n \r\n const error = new Error('Authentication was cancelled.');\r\n this.config.onError?.(error);\r\n reject(error);\r\n }\r\n }, 1000);\r\n });\r\n }\r\n\r\n /**\r\n * Exchange authorization code for access token\r\n */\r\n private async exchangeCodeForToken(\r\n code: string,\r\n redirectUri: string,\r\n codeVerifier?: string\r\n ): Promise<OAuthTokenResponse> {\r\n const body: any = {\r\n code,\r\n redirect_uri: redirectUri,\r\n grant_type: 'authorization_code',\r\n client_id: this.config.gameId,\r\n };\r\n\r\n if (codeVerifier) {\r\n body.code_verifier = codeVerifier;\r\n }\r\n\r\n const response = await fetch(this.config.oauthTokenUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.json().catch(() => ({ message: 'Failed to exchange code for token' }));\r\n throw new Error(error.message || 'Failed to exchange code for token');\r\n }\r\n\r\n return response.json();\r\n }\r\n\r\n /**\r\n * Generate random state for CSRF protection\r\n */\r\n private generateState(): string {\r\n const array = new Uint8Array(32);\r\n crypto.getRandomValues(array);\r\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\r\n }\r\n\r\n /**\r\n * Generate PKCE code verifier\r\n */\r\n private generateCodeVerifier(): string {\r\n const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';\r\n const array = new Uint8Array(128);\r\n crypto.getRandomValues(array);\r\n return Array.from(array, byte => charset[byte % charset.length]).join('');\r\n }\r\n\r\n /**\r\n * Generate PKCE code challenge from verifier\r\n */\r\n private async generateCodeChallenge(verifier: string): Promise<string> {\r\n const encoder = new TextEncoder();\r\n const data = encoder.encode(verifier);\r\n const hash = await crypto.subtle.digest('SHA-256', data);\r\n const base64 = btoa(String.fromCharCode(...new Uint8Array(hash)));\r\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\r\n }\r\n}\r\n","import type { AuthData } from './types';\r\n\r\ninterface IframeAuthConfig {\r\n gameId: string;\r\n parentOrigin?: string;\r\n onAuth: (authData: AuthData) => void;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/**\r\n * Handles authentication data passed from parent window via postMessage\r\n */\r\nexport class IframeAuth {\r\n private config: IframeAuthConfig;\r\n private messageListener: ((event: MessageEvent) => void) | null = null;\r\n\r\n constructor(config: IframeAuthConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Initialize iframe authentication listener\r\n */\r\n init(): void {\r\n // Request auth data from parent\r\n this.requestAuth();\r\n\r\n // Listen for auth data from parent\r\n this.messageListener = (event: MessageEvent) => {\r\n // Validate origin if specified\r\n if (this.config.parentOrigin) {\r\n try {\r\n const parentUrl = new URL(this.config.parentOrigin);\r\n if (event.origin !== parentUrl.origin) {\r\n return;\r\n }\r\n } catch {\r\n // If we can't parse parent origin, skip validation (development)\r\n }\r\n }\r\n\r\n // Handle auth data\r\n if (event.data?.type === 'OMENX_AUTH') {\r\n const authData = event.data.payload as AuthData;\r\n\r\n // Validate game ID\r\n if (authData.gameId !== this.config.gameId) {\r\n this.config.onError?.(new Error(`Game ID mismatch. Expected ${this.config.gameId}, got ${authData.gameId}`));\r\n return;\r\n }\r\n\r\n // Validate timestamp (5 minute expiry)\r\n const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);\r\n if (authData.timestamp < fiveMinutesAgo) {\r\n this.config.onError?.(new Error('Auth data expired'));\r\n return;\r\n }\r\n\r\n this.config.onAuth(authData);\r\n }\r\n };\r\n\r\n window.addEventListener('message', this.messageListener);\r\n }\r\n\r\n /**\r\n * Request authentication data from parent window\r\n */\r\n private requestAuth(): void {\r\n if (window.parent === window) {\r\n // Not in an iframe\r\n return;\r\n }\r\n\r\n // Send request to parent\r\n const parentOrigin = this.config.parentOrigin || '*';\r\n window.parent.postMessage(\r\n {\r\n type: 'OMENX_AUTH_REQUEST',\r\n gameId: this.config.gameId,\r\n },\r\n parentOrigin\r\n );\r\n }\r\n\r\n /**\r\n * Cleanup\r\n */\r\n destroy(): void {\r\n if (this.messageListener) {\r\n window.removeEventListener('message', this.messageListener);\r\n this.messageListener = null;\r\n }\r\n }\r\n}\r\n","import type { AuthData } from './types';\r\n\r\n/**\r\n * Manages token storage and retrieval\r\n */\r\nexport class TokenManager {\r\n private storageKeyPrefix: string;\r\n\r\n constructor(storageKeyPrefix: string = 'omenx_game_') {\r\n this.storageKeyPrefix = storageKeyPrefix;\r\n }\r\n\r\n /**\r\n * Store authentication data\r\n */\r\n storeAuth(authData: AuthData, refreshToken: string, expiresIn: number): void {\r\n try {\r\n localStorage.setItem(`${this.storageKeyPrefix}auth`, JSON.stringify(authData));\r\n localStorage.setItem(`${this.storageKeyPrefix}refresh_token`, refreshToken);\r\n localStorage.setItem(`${this.storageKeyPrefix}expires_at`, String(Date.now() + (expiresIn * 1000)));\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to store auth data:', error);\r\n }\r\n }\r\n\r\n /**\r\n * Get stored authentication data\r\n */\r\n getStoredAuth(): AuthData | null {\r\n try {\r\n const stored = localStorage.getItem(`${this.storageKeyPrefix}auth`);\r\n if (!stored) {\r\n return null;\r\n }\r\n return JSON.parse(stored) as AuthData;\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to retrieve auth data:', error);\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Get stored refresh token\r\n */\r\n getRefreshToken(): string | null {\r\n try {\r\n return localStorage.getItem(`${this.storageKeyPrefix}refresh_token`);\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to retrieve refresh token:', error);\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * Clear all stored authentication data\r\n */\r\n clearStorage(): void {\r\n try {\r\n localStorage.removeItem(`${this.storageKeyPrefix}auth`);\r\n localStorage.removeItem(`${this.storageKeyPrefix}refresh_token`);\r\n localStorage.removeItem(`${this.storageKeyPrefix}expires_at`);\r\n } catch (error) {\r\n console.warn('[TokenManager] Failed to clear storage:', error);\r\n }\r\n }\r\n}\r\n","import type {\r\n OmenXGameSDKConfig,\r\n AuthData,\r\n OAuthOptions,\r\n OAuthTokenResponse,\r\n ApiCallOptions,\r\n VipStatus,\r\n} from './types';\r\nimport { OAuthFlow } from './oauth';\r\nimport { IframeAuth } from './iframe-auth';\r\nimport { TokenManager } from './token-manager';\r\n\r\n/**\r\n * OmenX Game SDK\r\n * \r\n * Provides authentication and API integration for games on the OmenX platform.\r\n * Supports both OAuth-style authentication and iframe authentication passing.\r\n */\r\nexport class OmenXGameSDK {\r\n private config: Required<OmenXGameSDKConfig>;\r\n private oauthFlow: OAuthFlow;\r\n private iframeAuth: IframeAuth | null = null;\r\n private tokenManager: TokenManager;\r\n private currentAuthData: AuthData | null = null;\r\n\r\n constructor(config: OmenXGameSDKConfig) {\r\n // Set defaults\r\n const apiBaseUrl = config.apiBaseUrl || 'https://api.omen.foundation';\r\n this.config = {\r\n gameId: config.gameId,\r\n apiBaseUrl: apiBaseUrl,\r\n oauthAuthorizeUrl: config.oauthAuthorizeUrl || `${apiBaseUrl}/v1/oauth/authorize`,\r\n oauthTokenUrl: config.oauthTokenUrl || `${apiBaseUrl}/v1/oauth/token`,\r\n onAuth: config.onAuth || (() => {}),\r\n onAuthError: config.onAuthError || ((error) => console.error('[OmenX SDK] Auth error:', error)),\r\n onLogout: config.onLogout || (() => {}),\r\n enableIframeAuth: config.enableIframeAuth !== false,\r\n parentOrigin: config.parentOrigin ?? '',\r\n storageKeyPrefix: config.storageKeyPrefix || 'omenx_game_',\r\n };\r\n\r\n // Initialize components\r\n this.tokenManager = new TokenManager(this.config.storageKeyPrefix);\r\n this.oauthFlow = new OAuthFlow({\r\n gameId: this.config.gameId,\r\n oauthAuthorizeUrl: this.config.oauthAuthorizeUrl,\r\n oauthTokenUrl: this.config.oauthTokenUrl,\r\n apiBaseUrl: this.config.apiBaseUrl,\r\n onTokenReceived: this.handleTokenReceived.bind(this),\r\n onError: this.config.onAuthError,\r\n });\r\n\r\n if (this.config.enableIframeAuth) {\r\n this.iframeAuth = new IframeAuth({\r\n gameId: this.config.gameId,\r\n parentOrigin: this.config.parentOrigin || undefined,\r\n onAuth: this.handleAuthData.bind(this),\r\n onError: this.config.onAuthError,\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Initialize the SDK\r\n * Call this after creating an instance\r\n */\r\n async init(): Promise<void> {\r\n // Try to restore from stored token\r\n const storedAuth = this.tokenManager.getStoredAuth();\r\n if (storedAuth) {\r\n // Check if token is still valid (not expired)\r\n const expiresAt = storedAuth.timestamp + (3600 * 1000); // 1 hour default\r\n if (Date.now() < expiresAt) {\r\n this.currentAuthData = storedAuth;\r\n this.config.onAuth(storedAuth);\r\n return;\r\n } else {\r\n // Token expired, try to refresh\r\n const refreshToken = this.tokenManager.getRefreshToken();\r\n if (refreshToken) {\r\n try {\r\n await this.refreshAccessToken(refreshToken);\r\n return;\r\n } catch (error) {\r\n // Refresh failed, clear storage\r\n this.tokenManager.clearStorage();\r\n }\r\n }\r\n }\r\n }\r\n\r\n // If iframe auth is enabled, try to get auth from parent\r\n if (this.config.enableIframeAuth && this.iframeAuth !== null) {\r\n this.iframeAuth.init();\r\n }\r\n }\r\n\r\n /**\r\n * Authenticate user via OAuth popup\r\n */\r\n async authenticate(options: OAuthOptions): Promise<AuthData> {\r\n const tokenResponse = await this.oauthFlow.authenticate(options);\r\n // Convert OAuthTokenResponse to AuthData\r\n return {\r\n accessToken: tokenResponse.access_token,\r\n walletAddress: tokenResponse.user.walletAddress,\r\n userId: tokenResponse.user.userId,\r\n profileName: tokenResponse.user.profileName,\r\n profilePicture: tokenResponse.user.profilePicture,\r\n email: tokenResponse.user.email,\r\n gameId: this.config.gameId,\r\n timestamp: Date.now(),\r\n };\r\n }\r\n\r\n /**\r\n * Get current authentication data\r\n */\r\n getAuthData(): AuthData | null {\r\n return this.currentAuthData;\r\n }\r\n\r\n /**\r\n * Check if user is authenticated\r\n */\r\n isAuthenticated(): boolean {\r\n return this.currentAuthData !== null;\r\n }\r\n\r\n /**\r\n * Logout user\r\n */\r\n async logout(): Promise<void> {\r\n // Revoke token if we have one\r\n if (this.currentAuthData?.accessToken) {\r\n try {\r\n await this.apiCall('/v1/oauth/revoke', {\r\n method: 'POST',\r\n body: { token: this.currentAuthData.accessToken },\r\n includeAuth: false, // Don't include auth header for revoke\r\n });\r\n } catch (error) {\r\n // Ignore errors on revoke\r\n console.warn('[OmenX SDK] Failed to revoke token:', error);\r\n }\r\n }\r\n\r\n // Clear local state\r\n this.currentAuthData = null;\r\n this.tokenManager.clearStorage();\r\n this.config.onLogout();\r\n }\r\n\r\n /**\r\n * Make an authenticated API call\r\n */\r\n async apiCall(endpoint: string, options: ApiCallOptions = {}): Promise<Response> {\r\n const url = endpoint.startsWith('http') \r\n ? endpoint \r\n : `${this.config.apiBaseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;\r\n\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n ...options.headers,\r\n };\r\n\r\n // Add authentication header if needed\r\n if (options.includeAuth !== false && this.currentAuthData?.accessToken) {\r\n headers['Authorization'] = `Bearer ${this.currentAuthData.accessToken}`;\r\n }\r\n\r\n const fetchOptions: RequestInit = {\r\n method: options.method || 'GET',\r\n headers,\r\n };\r\n\r\n if (options.body && options.method !== 'GET') {\r\n fetchOptions.body = JSON.stringify(options.body);\r\n }\r\n\r\n const response = await fetch(url, fetchOptions);\r\n\r\n // If unauthorized, try to refresh token\r\n if (response.status === 401 && this.currentAuthData) {\r\n const refreshToken = this.tokenManager.getRefreshToken();\r\n if (refreshToken) {\r\n try {\r\n await this.refreshAccessToken(refreshToken);\r\n // Retry the request with new token\r\n if (this.currentAuthData?.accessToken) {\r\n headers['Authorization'] = `Bearer ${this.currentAuthData.accessToken}`;\r\n return fetch(url, { ...fetchOptions, headers });\r\n }\r\n } catch (error) {\r\n // Refresh failed, logout\r\n await this.logout();\r\n throw new Error('Authentication expired. Please login again.');\r\n }\r\n }\r\n }\r\n\r\n return response;\r\n }\r\n\r\n /**\r\n * Handle token received from OAuth flow\r\n */\r\n private async handleTokenReceived(tokenResponse: OAuthTokenResponse): Promise<void> {\r\n const authData: AuthData = {\r\n accessToken: tokenResponse.access_token,\r\n walletAddress: tokenResponse.user.walletAddress,\r\n userId: tokenResponse.user.userId,\r\n profileName: tokenResponse.user.profileName,\r\n profilePicture: tokenResponse.user.profilePicture,\r\n email: tokenResponse.user.email,\r\n gameId: this.config.gameId,\r\n timestamp: Date.now(),\r\n };\r\n\r\n // Store tokens\r\n this.tokenManager.storeAuth(authData, tokenResponse.refresh_token, tokenResponse.expires_in);\r\n\r\n // Update current auth\r\n this.currentAuthData = authData;\r\n this.config.onAuth(authData);\r\n }\r\n\r\n /**\r\n * Handle auth data from iframe\r\n */\r\n private handleAuthData(authData: AuthData): void {\r\n // Validate timestamp (5 minute expiry)\r\n const fiveMinutesAgo = Date.now() - (5 * 60 * 1000);\r\n if (authData.timestamp < fiveMinutesAgo) {\r\n this.config.onAuthError(new Error('Auth data expired'));\r\n return;\r\n }\r\n\r\n // Update current auth\r\n this.currentAuthData = authData;\r\n this.config.onAuth(authData);\r\n }\r\n\r\n /**\r\n * Get current VIP status for the authenticated user (tier, allocation, claimable, perks).\r\n * Games can read tier.gameBonusPointsLevel (1–21) for Alpha/Beta access or in-game gifts.\r\n */\r\n async getVipStatus(): Promise<VipStatus | null> {\r\n const response = await this.apiCall('/api/vip/me');\r\n if (!response.ok) return null;\r\n const data = await response.json();\r\n if (data.success && data.data) return data.data as VipStatus;\r\n return null;\r\n }\r\n\r\n /**\r\n * Get the current user's game bonus points level (1–21) from their VIP tier.\r\n * Use for Game Alpha Access (e.g. level >= 6), Game Beta Access (e.g. level >= 1), or in-game gifts.\r\n */\r\n async getGameBonusPointsLevel(): Promise<number | null> {\r\n const status = await this.getVipStatus();\r\n if (!status?.tier) return null;\r\n const level = status.tier.gameBonusPointsLevel ?? (status.tier.perks?.GAME_BONUS_POINTS_LEVEL as number);\r\n return typeof level === 'number' && level >= 1 && level <= 21 ? level : null;\r\n }\r\n\r\n /**\r\n * Refresh access token using refresh token\r\n */\r\n private async refreshAccessToken(refreshToken: string): Promise<void> {\r\n const response = await fetch(this.config.oauthTokenUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n grant_type: 'refresh_token',\r\n refresh_token: refreshToken,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error('Failed to refresh token');\r\n }\r\n\r\n const tokenResponse: OAuthTokenResponse = await response.json();\r\n await this.handleTokenReceived(tokenResponse);\r\n }\r\n}\r\n","import type { ApiCallOptions } from './types';\n\ninterface ServerSDKConfig {\n /**\n * Your developer API key (from developer portal)\n */\n apiKey: string;\n\n /**\n * OmenX API base URL (default: https://api.omen.foundation)\n */\n apiBaseUrl?: string;\n}\n\n/**\n * OmenX Game SDK - Server Mode\n * \n * For Node.js backends using developer API keys.\n * This mode allows server-to-server communication with the OmenX API.\n */\nexport class OmenXServerSDK {\n private config: Required<ServerSDKConfig>;\n private apiKey: string;\n\n constructor(config: ServerSDKConfig) {\n this.apiKey = config.apiKey;\n this.config = {\n apiKey: config.apiKey,\n apiBaseUrl: config.apiBaseUrl || 'https://api.omen.foundation',\n };\n }\n\n /**\n * Make an authenticated API call using the developer API key\n */\n async apiCall(endpoint: string, options: ApiCallOptions = {}): Promise<Response> {\n const url = endpoint.startsWith('http') \n ? endpoint \n : `${this.config.apiBaseUrl}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`;\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.apiKey}`,\n ...options.headers,\n };\n\n const fetchOptions: RequestInit = {\n method: options.method || 'GET',\n headers,\n };\n\n if (options.body && options.method !== 'GET') {\n fetchOptions.body = JSON.stringify(options.body);\n }\n\n const response = await fetch(url, fetchOptions);\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'Unknown error');\n throw new Error(`API call failed: ${response.status} ${response.statusText} - ${errorText}`);\n }\n\n return response;\n }\n\n /**\n * Health check\n */\n async healthCheck(): Promise<any> {\n const response = await this.apiCall('/v1/health', { includeAuth: false });\n return response.json();\n }\n\n /**\n * Get API key information\n */\n async getApiKeyInfo(): Promise<any> {\n const response = await this.apiCall('/v1/auth/me');\n return response.json();\n }\n\n /**\n * Player Operations\n */\n\n /**\n * Get full player data: NFTs (system + game) and balances for a wallet.\n * Requires both nfts:read and balances:read scopes.\n */\n async getPlayer(wallet: string, chainId: string): Promise<any> {\n const response = await this.apiCall(\n `/v1/players/${encodeURIComponent(wallet)}?chainId=${encodeURIComponent(chainId)}`\n );\n return response.json();\n }\n\n /**\n * Get native and ERC20 token balances for a wallet\n */\n async getPlayerBalances(wallet: string, chainId: string): Promise<any> {\n const response = await this.apiCall(\n `/v1/players/${encodeURIComponent(wallet)}/balances?chainId=${encodeURIComponent(chainId)}`\n );\n return response.json();\n }\n\n /**\n * Get paginated NFTs for a wallet.\n * With no contract: returns OmenX system NFTs (Asset Manager, Faucet, Early Adopter) + game NFTs.\n * With contract: returns only NFTs for that contract.\n */\n async getPlayerNfts(\n wallet: string,\n chainId: string,\n options?: {\n contract?: string;\n cursor?: string;\n limit?: number;\n }\n ): Promise<any> {\n const params = new URLSearchParams({ chainId });\n if (options?.contract) params.set('contract', options.contract);\n if (options?.cursor) params.set('cursor', options.cursor);\n if (options?.limit != null) params.set('limit', String(options.limit));\n\n const response = await this.apiCall(\n `/v1/players/${encodeURIComponent(wallet)}/nfts?${params.toString()}`\n );\n return response.json();\n }\n\n /**\n * Product catalog for the authenticated game (from API key).\n * Returns active products with priceUsd and pricesInCurrency (amount per BNB, OMENX, GMT, etc.).\n * Optional chainId for display (defaults to API chain).\n */\n async getProducts(chainId?: string): Promise<any> {\n const params = chainId != null ? `?chainId=${encodeURIComponent(chainId)}` : '';\n const response = await this.apiCall(`/v1/products${params}`);\n return response.json();\n }\n\n /**\n * Purchase Operations\n */\n\n /**\n * Create a server-authoritative purchase.\n * For on-chain payment: set paymentCurrency (e.g. \"BNB\", \"OMENX\", \"GMT\") and paymentAmount.\n * Balance is validated for that token on the BNB chain; any token with balance >= paymentAmount is allowed.\n */\n async createPurchase(params: {\n playerWallet?: string;\n walletAddress?: string; // Legacy field name\n skuId?: string;\n sku?: string; // Legacy field name\n quantity?: number;\n idempotencyKey?: string;\n /** Currency the player pays with (e.g. \"BNB\", \"OMENX\", \"GMT\"). Required when paymentAmount is set. */\n paymentCurrency?: string;\n /** Amount of paymentCurrency to spend. Validated against on-chain balance. */\n paymentAmount?: number;\n /** @deprecated Use paymentCurrency \"OMENX\" and paymentAmount instead. */\n amountInOmenx?: number;\n paymentMethod?: string;\n metadata?: Record<string, any>;\n }): Promise<any> {\n const response = await this.apiCall('/v1/purchases', {\n method: 'POST',\n body: params,\n headers: params.idempotencyKey ? {\n 'Idempotency-Key': params.idempotencyKey,\n } : undefined,\n });\n return response.json();\n }\n\n /**\n * NFT Template Operations\n */\n\n /**\n * Get all NFT templates for the authenticated game (game is derived from API key).\n * gameId is optional and ignored by the API; included for backward compatibility.\n */\n async getNftTemplates(_gameId?: string): Promise<any> {\n const response = await this.apiCall('/v1/nfts/templates');\n return response.json();\n }\n\n /**\n * Get NFT contract address for the authenticated game (game is derived from API key).\n * gameId is optional and ignored by the API; included for backward compatibility.\n */\n async getNftContract(_gameId?: string): Promise<any> {\n const response = await this.apiCall('/v1/nfts/contract');\n return response.json();\n }\n\n /**\n * Mint NFTs (single or batch)\n */\n async mintNfts(params: {\n templateId: string;\n recipientAddress: string;\n quantity: number;\n }): Promise<any> {\n const response = await this.apiCall('/v1/nfts/mint', {\n method: 'POST',\n body: params,\n });\n return response.json();\n }\n\n /**\n * Batch mint NFTs\n */\n async batchMintNfts(mints: Array<{\n templateId: string;\n recipientAddress: string;\n quantity: number;\n }>): Promise<any> {\n const response = await this.apiCall('/v1/nfts/mint/batch', {\n method: 'POST',\n body: { mints },\n });\n return response.json();\n }\n\n /**\n * Update NFT metadata\n */\n async updateNftMetadata(\n tokenId: string,\n metadata: {\n attributes?: Record<string, string | number | boolean>;\n name?: string;\n description?: string;\n imageUrl?: string;\n }\n ): Promise<any> {\n const response = await this.apiCall(`/v1/nfts/${tokenId}/metadata`, {\n method: 'PUT',\n body: metadata,\n });\n return response.json();\n }\n\n /**\n * Burn NFT (single)\n */\n async burnNft(tokenId: string): Promise<any> {\n const response = await this.apiCall(`/v1/nfts/${tokenId}`, {\n method: 'DELETE',\n });\n return response.json();\n }\n\n /**\n * Batch burn NFTs\n */\n async batchBurnNfts(tokenIds: string[]): Promise<any> {\n const response = await this.apiCall('/v1/nfts/burn/batch', {\n method: 'POST',\n body: { tokenIds },\n });\n return response.json();\n }\n\n /**\n * Pack opener - mint random NFTs from a drop table\n */\n async packOpener(params: {\n dropTableId: string;\n recipientAddress: string;\n }): Promise<any> {\n const response = await this.apiCall('/v1/nfts/pack-opener', {\n method: 'POST',\n body: params,\n });\n return response.json();\n }\n\n /**\n * VIP Points (Developer pool)\n * Requires scope: vip_points:write.\n * Grants VIP points to a player from this game's allocated pool. Enforces total allocation and max per quest.\n * Call from your game backend only (API key auth); not for client-side use.\n */\n async grantVipPoints(params: {\n /** Player wallet address (0x-prefixed, 40 hex chars). */\n wallet: string;\n /** Points to grant (positive integer). Capped by pool remaining and max per quest. */\n amount: number;\n /** Optional quest/activity id for idempotency or auditing. */\n questId?: string;\n }): Promise<{ success: boolean; data?: { wallet: string; amount: number; phaseIndex?: number } }> {\n const response = await this.apiCall('/v1/vip/grant-points', {\n method: 'POST',\n body: params,\n });\n return response.json();\n }\n\n /**\n * Quests API (game quests only).\n * Requires scope: quests:read for getQuestsForPlayer; quests:write for assign, progress, complete, claim.\n */\n\n /** Get assigned quests for a player. Optional questType filter. */\n async getQuestsForPlayer(\n wallet: string,\n options?: { questType?: 'daily' | 'weekly' | 'monthly' | 'oneTime' }\n ): Promise<{ success: boolean; data: { quests: any[] } }> {\n const q = options?.questType ? `?questType=${options.questType}` : '';\n const response = await this.apiCall(`/v1/quests/players/${encodeURIComponent(wallet)}${q}`);\n return response.json();\n }\n\n /** Assign quests of a type to a player. Use idempotencyKey for safe retries. */\n async assignQuests(\n wallet: string,\n questType: 'daily' | 'weekly' | 'monthly' | 'oneTime',\n count: number,\n options?: { idempotencyKey?: string }\n ): Promise<{ success: boolean; data: { assigned: number; assignmentIds?: string[] } }> {\n const response = await this.apiCall(`/v1/quests/players/${encodeURIComponent(wallet)}/assign`, {\n method: 'POST',\n body: { questType, count },\n headers: options?.idempotencyKey ? { 'Idempotency-Key': options.idempotencyKey } : undefined,\n });\n return response.json();\n }\n\n /** Report progress for a quest step. Quest auto-completes when all steps meet targets. */\n async reportQuestProgress(\n wallet: string,\n questKey: string,\n value: number,\n options?: { stepKey?: string }\n ): Promise<{ success: boolean; data?: object }> {\n const response = await this.apiCall('/v1/quests/progress', {\n method: 'POST',\n body: { wallet, questKey, value, stepKey: options?.stepKey },\n });\n return response.json();\n }\n\n /** Mark a quest complete (all steps set to targets). */\n async completeQuest(wallet: string, questKey: string): Promise<{ success: boolean; data?: object }> {\n const response = await this.apiCall('/v1/quests/complete', {\n method: 'POST',\n body: { wallet, questKey },\n });\n return response.json();\n }\n\n /** Claim VIP reward for a completed quest (from game pool). Use idempotencyKey for safe retries. */\n async claimQuestReward(\n wallet: string,\n questKey: string,\n options?: { idempotencyKey?: string }\n ): Promise<{ success: boolean; data?: { pointsGranted?: number } }> {\n const response = await this.apiCall('/v1/quests/claim', {\n method: 'POST',\n body: { wallet, questKey },\n headers: options?.idempotencyKey ? { 'Idempotency-Key': options.idempotencyKey } : undefined,\n });\n return response.json();\n }\n\n /**\n * Reset or wipe a player's quest state for this game. Requires quests:write.\n * - wipe: delete all quest assignments for this game for the player.\n * - reset: delete assignments for the specified questKey only (questKey required).\n */\n async resetPlayerQuests(\n wallet: string,\n action: 'wipe' | 'reset',\n questKey?: string\n ): Promise<{ success: boolean; data: { action: string; deleted: number; questKey?: string } }> {\n const body: { action: 'wipe' | 'reset'; questKey?: string } = { action };\n if (action === 'reset' && questKey) body.questKey = questKey;\n const response = await this.apiCall('/v1/quests/players/' + encodeURIComponent(wallet) + '/reset', {\n method: 'POST',\n body,\n });\n return response.json();\n }\n}\n","/**\r\n * Real-time wallet updates (balance & inventory) for game clients.\r\n * Subscribe to the per-wallet Ably channel so the game stays in sync when the user\r\n * spends or receives OmenX / NFTs on the website or in another client.\r\n *\r\n * Two options:\r\n * 1. subscribeWalletRealtimeWithOmenXAuth – no API key needed; SDK gets a scoped token from the OmenX platform using your access token.\r\n * 2. subscribeWalletRealtime – pass your own Ably Realtime instance (e.g. from an API key or your own token).\r\n */\r\n\r\nimport Ably from 'ably';\r\n\r\n/** Payload for balance and inventory events. Use eventId for idempotency (ignore if already processed). */\r\nexport interface RealtimeWalletPayload {\r\n eventId: string;\r\n timestamp: number;\r\n reason?: string;\r\n}\r\n\r\n/** Ably channel name prefix. Full channel = \"wallet:\" + normalized wallet address. */\r\nexport const WALLET_CHANNEL_PREFIX = 'wallet:';\r\n\r\n/** Event names published by the OmenX backend on the wallet channel. */\r\nexport const REALTIME_EVENTS = {\r\n /** Currency balance changed. Refetch via GetPlayerBalances or your balance API. */\r\n balance: 'balance',\r\n /** NFT/inventory changed. Refetch via GetPlayerNfts or your inventory API (cache is source of truth). */\r\n inventory: 'inventory',\r\n} as const;\r\n\r\nconst MAX_SEEN_IDS = 200;\r\n\r\n/**\r\n * Normalize wallet address for channel name (lowercase, no 0x prefix change).\r\n */\r\nfunction normalizeWallet(wallet: string): string {\r\n return (wallet || '').trim().toLowerCase();\r\n}\r\n\r\n/**\r\n * Get the Ably channel name for a wallet. Use this when subscribing with your Ably client.\r\n */\r\nexport function getWalletChannelName(walletAddress: string): string {\r\n return WALLET_CHANNEL_PREFIX + normalizeWallet(walletAddress);\r\n}\r\n\r\n/**\r\n * Minimal Ably Realtime interface so the SDK works with any Ably.Realtime instance.\r\n * The app provides the real Ably client from AblyProvider or new Ably.Realtime({ key }).\r\n */\r\nexport interface AblyRealtimeLike {\r\n channels: {\r\n get(name: string): {\r\n subscribe(eventOrCallback: string | ((message: { name: string; data: unknown }) => void), callback?: (message: { name: string; data: unknown }) => void): void;\r\n unsubscribe(eventOrCallback?: string | ((message: { name: string; data: unknown }) => void), callback?: (message: { name: string; data: unknown }) => void): void;\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * Subscribe to real-time balance and inventory events for a wallet.\r\n * Call when the user logs in; call the returned unsubscribe when they log out or wallet changes.\r\n *\r\n * Uses eventId to dedupe (ignores already-seen events). Refetch in your app on each callback.\r\n *\r\n * @param ably - Ably Realtime instance (e.g. from useAbly() or new Ably.Realtime({ key }))\r\n * @param walletAddress - Current player wallet (0x...)\r\n * @param callbacks - onBalance and/or onInventory; each receives the payload (eventId, timestamp, reason?)\r\n * @returns Unsubscribe function\r\n */\r\nexport function subscribeWalletRealtime(\r\n ably: AblyRealtimeLike,\r\n walletAddress: string,\r\n callbacks: {\r\n onBalance?: (payload: RealtimeWalletPayload) => void;\r\n onInventory?: (payload: RealtimeWalletPayload) => void;\r\n }\r\n): () => void {\r\n const normalized = normalizeWallet(walletAddress);\r\n if (!normalized || !/^0x[a-fa-f0-9]{40}$/.test(normalized)) {\r\n return () => {};\r\n }\r\n\r\n const seenIds = new Set<string>();\r\n\r\n const handleMessage = (message: { name: string; data: unknown }) => {\r\n const data = message.data as RealtimeWalletPayload | undefined;\r\n if (!data || typeof data !== 'object' || typeof data.eventId !== 'string') return;\r\n if (seenIds.has(data.eventId)) return;\r\n if (seenIds.size >= MAX_SEEN_IDS) {\r\n const first = seenIds.values().next().value;\r\n if (first != null) seenIds.delete(first);\r\n }\r\n seenIds.add(data.eventId);\r\n\r\n if (message.name === REALTIME_EVENTS.balance && callbacks.onBalance) {\r\n callbacks.onBalance(data);\r\n } else if (message.name === REALTIME_EVENTS.inventory && callbacks.onInventory) {\r\n callbacks.onInventory(data);\r\n }\r\n };\r\n\r\n const channel = ably.channels.get(getWalletChannelName(normalized));\r\n channel.subscribe(handleMessage);\r\n\r\n return () => {\r\n channel.unsubscribe(handleMessage);\r\n };\r\n}\r\n\r\n/** Options for subscribing via OmenX platform token (no Ably API key required). */\r\nexport interface SubscribeWalletRealtimeWithOmenXAuthOptions {\r\n /** Base URL of the OmenX API (e.g. https://api.omen.foundation). No trailing slash. */\r\n apiBaseUrl: string;\r\n /** Returns the current OmenX access token (from your OAuth flow). Called when Ably needs to authenticate. */\r\n getAccessToken: () => Promise<string | null>;\r\n /** Wallet address (0x...) to subscribe to. Must match the wallet in the access token. */\r\n walletAddress: string;\r\n onBalance?: (payload: RealtimeWalletPayload) => void;\r\n onInventory?: (payload: RealtimeWalletPayload) => void;\r\n /** Optional. Called when the Ably connection fails or is suspended (e.g. server unavailable). App can log or show a non-blocking toast; realtime will degrade gracefully. */\r\n onConnectionError?: (message: string) => void;\r\n}\r\n\r\n/**\r\n * Subscribe to real-time balance and inventory for a wallet using OmenX platform auth.\r\n * The SDK fetches a short-lived, subscribe-only Ably token from the OmenX API using your\r\n * access token. No Ably API key or .env is required – ideal for third-party developers.\r\n *\r\n * If the token endpoint is unavailable (e.g. backend down), no Ably client is created and\r\n * the function returns a no-op unsubscribe so the app does not crash. Connection\r\n * failures/suspensions are handled and reported via onConnectionError so they do not\r\n * surface as uncaught errors.\r\n *\r\n * Requires the app to have `ably` installed (peer dependency). Call when the user is\r\n * logged in; call the returned function on logout or wallet change.\r\n */\r\nexport function subscribeWalletRealtimeWithOmenXAuth(\r\n options: SubscribeWalletRealtimeWithOmenXAuthOptions\r\n): () => void {\r\n const { apiBaseUrl, getAccessToken, walletAddress, onBalance, onInventory, onConnectionError } = options;\r\n const normalized = (walletAddress || '').trim().toLowerCase();\r\n if (!normalized || !/^0x[a-fa-f0-9]{40}$/.test(normalized)) {\r\n return () => {};\r\n }\r\n\r\n const base = apiBaseUrl.replace(/\\/$/, '');\r\n const reportConnectionError = (message: string): void => {\r\n if (onConnectionError) {\r\n try {\r\n onConnectionError(message);\r\n } catch {\r\n // ignore app callback errors\r\n }\r\n } else {\r\n console.warn('[OmenX Realtime]', message);\r\n }\r\n };\r\n\r\n const authCallback = (\r\n _tokenParams: unknown,\r\n callback: (error: string | null, tokenRequestOrDetails: unknown) => void\r\n ): void => {\r\n getAccessToken()\r\n .then((token) => {\r\n if (!token) {\r\n callback('Not authenticated', null);\r\n return;\r\n }\r\n return fetch(`${base}/api/sdk/ably-token`, {\r\n method: 'POST',\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n });\r\n })\r\n .then((res) => {\r\n if (!res) return;\r\n if (!res.ok) {\r\n return res.json().then((body: { message?: string }) => {\r\n callback((body && body.message) || res.statusText || 'Request failed', null);\r\n });\r\n }\r\n return res.json().then((tokenRequest: unknown) => {\r\n callback(null, tokenRequest);\r\n });\r\n })\r\n .catch((err: unknown) => {\r\n callback(err instanceof Error ? err.message : String(err), null);\r\n });\r\n };\r\n\r\n // Pre-flight: try to get a token before creating Ably. If backend is unreachable, we never create the client so we avoid \"Connection to server unavailable\" uncaught errors.\r\n let ably: Ably.Realtime | null = null;\r\n let unsubscribeChannel: (() => void) | null = null;\r\n let cancelled = false;\r\n\r\n const cleanup = (): void => {\r\n cancelled = true;\r\n if (unsubscribeChannel) {\r\n try {\r\n unsubscribeChannel();\r\n } catch {\r\n // ignore\r\n }\r\n unsubscribeChannel = null;\r\n }\r\n if (ably) {\r\n try {\r\n ably.close();\r\n } catch {\r\n // ignore\r\n }\r\n ably = null;\r\n }\r\n };\r\n\r\n const tokenPromise = getAccessToken().then((token) => {\r\n if (!token) return null;\r\n return fetch(`${base}/api/sdk/ably-token`, {\r\n method: 'POST',\r\n headers: {\r\n Authorization: `Bearer ${token}`,\r\n 'Content-Type': 'application/json',\r\n },\r\n });\r\n });\r\n\r\n tokenPromise\r\n .then((res) => {\r\n if (cancelled) return;\r\n if (res === null) {\r\n reportConnectionError('Realtime skipped: not authenticated');\r\n return;\r\n }\r\n if (!res.ok) {\r\n reportConnectionError(`Realtime unavailable: ${res.status}`);\r\n return;\r\n }\r\n return res.json();\r\n })\r\n .then((tokenRequest: unknown) => {\r\n if (cancelled || tokenRequest === undefined) return;\r\n ably = new Ably.Realtime({\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n authCallback: authCallback as any,\r\n });\r\n\r\n // Handle connection failures so they don't surface as uncaught errors\r\n ably.connection.on('failed', (stateChange: { reason?: { message?: string } }) => {\r\n const msg = stateChange?.reason?.message ?? 'Connection failed';\r\n reportConnectionError(msg);\r\n });\r\n ably.connection.on('suspended', (stateChange: { reason?: { message?: string } }) => {\r\n const msg = stateChange?.reason?.message ?? 'Connection to server unavailable';\r\n reportConnectionError(msg);\r\n });\r\n\r\n unsubscribeChannel = subscribeWalletRealtime(ably as AblyRealtimeLike, walletAddress, {\r\n onBalance,\r\n onInventory,\r\n });\r\n })\r\n .catch((err: unknown) => {\r\n if (!cancelled) {\r\n reportConnectionError(err instanceof Error ? err.message : 'Realtime setup failed');\r\n }\r\n });\r\n\r\n return () => {\r\n cleanup();\r\n };\r\n}\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omen.foundation/game-sdk",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "OmenX Game SDK for web applications - OAuth authentication, API integration, and real-time balance/inventory updates",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",