@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 +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +87 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +87 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
863
|
-
|
|
864
|
-
|
|
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
|
-
|
|
867
|
-
|
|
868
|
-
|
|
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
|
-
|
|
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":";;;;;;;;;AAWO,IAAM,YAAN,MAAgB;AAAA,EAGrB,YAAY,MAAA,EAAyB;AACnC,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAA,CAAa,OAAA,GAAwB,EAAC,EAAgC;AAE1E,IAAA,MAAM,KAAA,GAAQ,KAAK,aAAA,EAAc;AAGjC,IAAA,MAAM,YAAA,GAAe,KAAK,oBAAA,EAAqB;AAC/C,IAAA,MAAM,aAAA,GAAgB,MAAM,IAAA,CAAK,qBAAA,CAAsB,YAAY,CAAA;AAEnE,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AAGtC,MAAA,cAAA,CAAe,OAAA,CAAQ,CAAA,WAAA,EAAc,KAAK,CAAA,CAAA,EAAI,YAAY,CAAA;AAG1D,MAAA,MAAM,cAAc,OAAA,CAAQ,WAAA,IAAe,CAAA,EAAG,MAAA,CAAO,SAAS,MAAM,CAAA,cAAA,CAAA;AACpE,MAAA,MAAM,OAAA,GAAU,IAAI,GAAA,CAAI,IAAA,CAAK,OAAO,iBAAiB,CAAA;AACrD,MAAA,OAAA,CAAQ,YAAA,CAAa,GAAA,CAAI,WAAA,EAAa,IAAA,CAAK,OAAO,MAAM,CAAA;AACxD,MAAA,OAAA,CAAQ,YAAA,CAAa,GAAA,CAAI,cAAA,EAAgB,WAAW,CAAA;AACpD,MAAA,OAAA,CAAQ,YAAA,CAAa,GAAA,CAAI,eAAA,EAAiB,MAAM,CAAA;AAChD,MAAA,OAAA,CAAQ,YAAA,CAAa,GAAA,CAAI,OAAA,EAAS,sBAAsB,CAAA;AACxD,MAAA,OAAA,CAAQ,YAAA,CAAa,GAAA,CAAI,OAAA,EAAS,KAAK,CAAA;AACvC,MAAA,OAAA,CAAQ,YAAA,CAAa,GAAA,CAAI,gBAAA,EAAkB,aAAa,CAAA;AACxD,MAAA,OAAA,CAAQ,YAAA,CAAa,GAAA,CAAI,uBAAA,EAAyB,MAAM,CAAA;AAGxD,MAAA,MAAM,eAAA,GAAkB,qBAAqB,KAAK,CAAA,CAAA;AAClD,MAAA,cAAA,CAAe,OAAA,CAAQ,iBAAiB,KAAK,CAAA;AAG7C,MAAA,MAAM,QAAQ,MAAA,CAAO,IAAA;AAAA,QACnB,QAAQ,QAAA,EAAS;AAAA,QACjB,aAAA;AAAA,QACA;AAAA,OACF;AAEA,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,iEAAiE,CAAA;AACzF,QAAA,IAAA,CAAK,MAAA,CAAO,UAAU,KAAK,CAAA;AAC3B,QAAA,MAAA,CAAO,KAAK,CAAA;AACZ,QAAA;AAAA,MACF;AAGA,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAU,MAAA,CAAO,IAAA,CAAK,YAAY,CAAA,CAAE,OAAO,CAAA,CAAA,KAAK,CAAA,CAAE,UAAA,CAAW,uBAAuB,CAAC,CAAA;AAC3F,QAAA,OAAA,CAAQ,QAAQ,CAAA,GAAA,KAAO;AACrB,UAAA,IAAI;AACF,YAAA,MAAM,IAAA,GAAO,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA;AACrC,YAAA,IAAI,IAAA,EAAM;AACR,cAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAC9B,cAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,EAAI,IAAK,OAAO,SAAA,IAAa,CAAA,CAAA;AAE9C,cAAA,IAAI,MAAM,GAAA,EAAQ;AAChB,gBAAA,YAAA,CAAa,WAAW,GAAG,CAAA;AAAA,cAC7B;AAAA,YACF;AAAA,UACF,SAAS,CAAA,EAAG;AACV,YAAA,YAAA,CAAa,WAAW,GAAG,CAAA;AAAA,UAC7B;AAAA,QACF,CAAC,CAAA;AAAA,MACH,SAAS,KAAA,EAAO;AAAA,MAEhB;AAGA,MAAA,MAAM,UAAA,GAAa,wBAAwB,KAAK,CAAA,CAAA;AAChD,MAAA,IAAI,eAAA,GAAkB,KAAA;AAEtB,MAAA,MAAM,YAAA,GAAe,YAAY,MAAM;AACrC,QAAA,IAAI,eAAA,EAAiB;AACnB,UAAA,aAAA,CAAc,YAAY,CAAA;AAC1B,UAAA;AAAA,QACF;AAEA,QAAA,MAAM,MAAA,GAAS,YAAA,CAAa,OAAA,CAAQ,UAAU,CAAA;AAE9C,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,IAAI;AACF,YAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA;AAG9B,YAAA,IAAI,IAAA,CAAK,IAAA,IAAQ,IAAA,CAAK,KAAA,KAAU,KAAA,EAAO;AACrC,cAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,EAAI,IAAK,KAAK,SAAA,IAAa,CAAA,CAAA;AAC5C,cAAA,IAAI,MAAM,GAAA,EAAO;AACf,gBAAA,eAAA,GAAkB,IAAA;AAClB,gBAAA,aAAA,CAAc,YAAY,CAAA;AAG1B,gBAAA,YAAA,CAAa,WAAW,UAAU,CAAA;AAClC,gBAAA,cAAA,CAAe,UAAA,CAAW,CAAA,WAAA,EAAc,KAAK,CAAA,CAAE,CAAA;AAC/C,gBAAA,cAAA,CAAe,WAAW,eAAe,CAAA;AAGzC,gBAAA,IAAA,CAAK,oBAAA,CAAqB,KAAK,IAAA,EAAM,WAAA,EAAa,YAAY,CAAA,CAC3D,IAAA,CAAK,OAAO,aAAA,KAAkB;AAC7B,kBAAA,MAAM,IAAA,CAAK,MAAA,CAAO,eAAA,CAAgB,aAAa,CAAA;AAE/C,kBAAA,IAAI,KAAA,IAAS,CAAC,KAAA,CAAM,MAAA,EAAQ;AAC1B,oBAAA,IAAI;AACF,sBAAA,KAAA,CAAM,KAAA,EAAM;AAAA,oBACd,SAAS,CAAA,EAAG;AAAA,oBAEZ;AAAA,kBACF;AACA,kBAAA,OAAA,CAAQ,aAAa,CAAA;AAAA,gBACvB,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,KAAA,KAAU;AAChB,kBAAA,IAAA,CAAK,MAAA,CAAO,UAAU,KAAc,CAAA;AACpC,kBAAA,MAAA,CAAO,KAAK,CAAA;AAAA,gBACd,CAAC,CAAA;AACH,gBAAA;AAAA,cACF,CAAA,MAAO;AAEL,gBAAA,YAAA,CAAa,WAAW,UAAU,CAAA;AAAA,cACpC;AAAA,YACF;AAAA,UACF,SAAS,KAAA,EAAO;AACd,YAAA,OAAA,CAAQ,KAAA,CAAM,oDAAoD,KAAK,CAAA;AAAA,UACzE;AAAA,QACF;AAAA,MACF,GAAG,GAAG,CAAA;AAGN,MAAA,MAAM,WAAA,GAAc,YAAY,MAAM;AACpC,QAAA,IAAI,eAAA,EAAiB;AACnB,UAAA,aAAA,CAAc,WAAW,CAAA;AACzB,UAAA;AAAA,QACF;AAGA,QAAA,IAAI,QAAA,GAAW,KAAA;AACf,QAAA,IAAI;AACF,UAAA,IAAI,MAAM,MAAA,EAAQ;AAChB,YAAA,IAAI;AAEF,cAAA,KAAA,CAAM,QAAA,CAAS,IAAA;AACf,cAAA,QAAA,GAAW,IAAA;AAAA,YACb,SAAS,CAAA,EAAG;AAEV,cAAA,QAAA,GAAW,KAAA;AAAA,YACb;AAAA,UACF;AAAA,QACF,SAAS,CAAA,EAAG;AACV,UAAA,QAAA,GAAW,KAAA;AAAA,QACb;AAEA,QAAA,IAAI,QAAA,EAAU;AACZ,UAAA,aAAA,CAAc,WAAW,CAAA;AACzB,UAAA,aAAA,CAAc,YAAY,CAAA;AAG1B,UAAA,cAAA,CAAe,UAAA,CAAW,CAAA,WAAA,EAAc,KAAK,CAAA,CAAE,CAAA;AAC/C,UAAA,cAAA,CAAe,WAAW,eAAe,CAAA;AAEzC,UAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,+BAA+B,CAAA;AACvD,UAAA,IAAA,CAAK,MAAA,CAAO,UAAU,KAAK,CAAA;AAC3B,UAAA,MAAA,CAAO,KAAK,CAAA;AAAA,QACd;AAAA,MACF,GAAG,GAAI,CAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,oBAAA,CACZ,IAAA,EACA,WAAA,EACA,YAAA,EAC6B;AAC7B,IAAA,MAAM,IAAA,GAAY;AAAA,MAChB,IAAA;AAAA,MACA,YAAA,EAAc,WAAA;AAAA,MACd,UAAA,EAAY,oBAAA;AAAA,MACZ,SAAA,EAAW,KAAK,MAAA,CAAO;AAAA,KACzB;AAEA,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,IAAA,CAAK,aAAA,GAAgB,YAAA;AAAA,IACvB;AAEA,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,IAAA,CAAK,OAAO,aAAA,EAAe;AAAA,MACtD,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB;AAAA,OAClB;AAAA,MACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAI;AAAA,KAC1B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,KAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK,CAAE,MAAM,OAAO,EAAE,OAAA,EAAS,mCAAA,EAAoC,CAAE,CAAA;AAClG,MAAA,MAAM,IAAI,KAAA,CAAM,KAAA,CAAM,OAAA,IAAW,mCAAmC,CAAA;AAAA,IACtE;AAEA,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAA,GAAwB;AAC9B,IAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,EAAE,CAAA;AAC/B,IAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAC5B,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,KAAA,EAAO,CAAA,IAAA,KAAQ,KAAK,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,KAAK,EAAE,CAAA;AAAA,EAC9E;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAA,GAA+B;AACrC,IAAA,MAAM,OAAA,GAAU,oEAAA;AAChB,IAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,GAAG,CAAA;AAChC,IAAA,MAAA,CAAO,gBAAgB,KAAK,CAAA;AAC5B,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,KAAA,EAAO,CAAA,IAAA,KAAQ,OAAA,CAAQ,IAAA,GAAO,OAAA,CAAQ,MAAM,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CAAA;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,sBAAsB,QAAA,EAAmC;AACrE,IAAA,MAAM,OAAA,GAAU,IAAI,WAAA,EAAY;AAChC,IAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,MAAA,CAAO,QAAQ,CAAA;AACpC,IAAA,MAAM,OAAO,MAAM,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,WAAW,IAAI,CAAA;AACvD,IAAA,MAAM,MAAA,GAAS,KAAK,MAAA,CAAO,YAAA,CAAa,GAAG,IAAI,UAAA,CAAW,IAAI,CAAC,CAAC,CAAA;AAChE,IAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,IAAA,EAAM,EAAE,CAAA;AAAA,EACxE;AACF,CAAA;;;AC3OO,IAAM,aAAN,MAAiB;AAAA,EAItB,YAAY,MAAA,EAA0B;AAFtC,IAAA,IAAA,CAAQ,eAAA,GAA0D,IAAA;AAGhE,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAA,GAAa;AAEX,IAAA,IAAA,CAAK,WAAA,EAAY;AAGjB,IAAA,IAAA,CAAK,eAAA,GAAkB,CAAC,KAAA,KAAwB;AAE9C,MAAA,IAAI,IAAA,CAAK,OAAO,YAAA,EAAc;AAC5B,QAAA,IAAI;AACF,UAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,IAAA,CAAK,OAAO,YAAY,CAAA;AAClD,UAAA,IAAI,KAAA,CAAM,MAAA,KAAW,SAAA,CAAU,MAAA,EAAQ;AACrC,YAAA;AAAA,UACF;AAAA,QACF,CAAA,CAAA,MAAQ;AAAA,QAER;AAAA,MACF;AAGA,MAAA,IAAI,KAAA,CAAM,IAAA,EAAM,IAAA,KAAS,YAAA,EAAc;AACrC,QAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA;AAG5B,QAAA,IAAI,QAAA,CAAS,MAAA,KAAW,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ;AAC1C,UAAA,IAAA,CAAK,MAAA,CAAO,OAAA,GAAU,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,MAAA,EAAS,QAAA,CAAS,MAAM,CAAA,CAAE,CAAC,CAAA;AAC3G,UAAA;AAAA,QACF;AAGA,QAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,GAAA,EAAI,GAAK,IAAI,EAAA,GAAK,GAAA;AAC9C,QAAA,IAAI,QAAA,CAAS,YAAY,cAAA,EAAgB;AACvC,UAAA,IAAA,CAAK,MAAA,CAAO,OAAA,GAAU,IAAI,KAAA,CAAM,mBAAmB,CAAC,CAAA;AACpD,UAAA;AAAA,QACF;AAEA,QAAA,IAAA,CAAK,MAAA,CAAO,OAAO,QAAQ,CAAA;AAAA,MAC7B;AAAA,IACF,CAAA;AAEA,IAAA,MAAA,CAAO,gBAAA,CAAiB,SAAA,EAAW,IAAA,CAAK,eAAe,CAAA;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAA,GAAoB;AAC1B,IAAA,IAAI,MAAA,CAAO,WAAW,MAAA,EAAQ;AAE5B,MAAA;AAAA,IACF;AAGA,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,MAAA,CAAO,YAAA,IAAgB,GAAA;AACjD,IAAA,MAAA,CAAO,MAAA,CAAO,WAAA;AAAA,MACZ;AAAA,QACE,IAAA,EAAM,oBAAA;AAAA,QACN,MAAA,EAAQ,KAAK,MAAA,CAAO;AAAA,OACtB;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAA,GAAgB;AACd,IAAA,IAAI,KAAK,eAAA,EAAiB;AACxB,MAAA,MAAA,CAAO,mBAAA,CAAoB,SAAA,EAAW,IAAA,CAAK,eAAe,CAAA;AAC1D,MAAA,IAAA,CAAK,eAAA,GAAkB,IAAA;AAAA,IACzB;AAAA,EACF;AACF,CAAA;;;ACzFO,IAAM,eAAN,MAAmB;AAAA,EAGxB,WAAA,CAAY,mBAA2B,aAAA,EAAe;AACpD,IAAA,IAAA,CAAK,gBAAA,GAAmB,gBAAA;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,SAAA,CAAU,QAAA,EAAoB,YAAA,EAAsB,SAAA,EAAyB;AAC3E,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,OAAA,CAAQ,GAAG,IAAA,CAAK,gBAAgB,QAAQ,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAC,CAAA;AAC7E,MAAA,YAAA,CAAa,OAAA,CAAQ,CAAA,EAAG,IAAA,CAAK,gBAAgB,iBAAiB,YAAY,CAAA;AAC1E,MAAA,YAAA,CAAa,OAAA,CAAQ,CAAA,EAAG,IAAA,CAAK,gBAAgB,CAAA,UAAA,CAAA,EAAc,MAAA,CAAO,IAAA,CAAK,GAAA,EAAI,GAAK,SAAA,GAAY,GAAK,CAAC,CAAA;AAAA,IACpG,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,IAAA,CAAK,6CAA6C,KAAK,CAAA;AAAA,IACjE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAA,GAAiC;AAC/B,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,YAAA,CAAa,OAAA,CAAQ,CAAA,EAAG,IAAA,CAAK,gBAAgB,CAAA,IAAA,CAAM,CAAA;AAClE,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,OAAO,IAAA;AAAA,MACT;AACA,MAAA,OAAO,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA,IAC1B,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,IAAA,CAAK,gDAAgD,KAAK,CAAA;AAClE,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,eAAA,GAAiC;AAC/B,IAAA,IAAI;AACF,MAAA,OAAO,YAAA,CAAa,OAAA,CAAQ,CAAA,EAAG,IAAA,CAAK,gBAAgB,CAAA,aAAA,CAAe,CAAA;AAAA,IACrE,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,IAAA,CAAK,oDAAoD,KAAK,CAAA;AACtE,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAA,GAAqB;AACnB,IAAA,IAAI;AACF,MAAA,YAAA,CAAa,UAAA,CAAW,CAAA,EAAG,IAAA,CAAK,gBAAgB,CAAA,IAAA,CAAM,CAAA;AACtD,MAAA,YAAA,CAAa,UAAA,CAAW,CAAA,EAAG,IAAA,CAAK,gBAAgB,CAAA,aAAA,CAAe,CAAA;AAC/D,MAAA,YAAA,CAAa,UAAA,CAAW,CAAA,EAAG,IAAA,CAAK,gBAAgB,CAAA,UAAA,CAAY,CAAA;AAAA,IAC9D,SAAS,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,IAAA,CAAK,2CAA2C,KAAK,CAAA;AAAA,IAC/D;AAAA,EACF;AACF,CAAA;;;AC/CO,IAAM,eAAN,MAAmB;AAAA,EAOxB,YAAY,MAAA,EAA4B;AAJxC,IAAA,IAAA,CAAQ,UAAA,GAAgC,IAAA;AAExC,IAAA,IAAA,CAAQ,eAAA,GAAmC,IAAA;AAIzC,IAAA,MAAM,UAAA,GAAa,OAAO,UAAA,IAAc,6BAAA;AACxC,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,UAAA;AAAA,MACA,iBAAA,EAAmB,MAAA,CAAO,iBAAA,IAAqB,CAAA,EAAG,UAAU,CAAA,mBAAA,CAAA;AAAA,MAC5D,aAAA,EAAe,MAAA,CAAO,aAAA,IAAiB,CAAA,EAAG,UAAU,CAAA,eAAA,CAAA;AAAA,MACpD,MAAA,EAAQ,MAAA,CAAO,MAAA,KAAW,MAAM;AAAA,MAAC,CAAA,CAAA;AAAA,MACjC,WAAA,EAAa,OAAO,WAAA,KAAgB,CAAC,UAAU,OAAA,CAAQ,KAAA,CAAM,2BAA2B,KAAK,CAAA,CAAA;AAAA,MAC7F,QAAA,EAAU,MAAA,CAAO,QAAA,KAAa,MAAM;AAAA,MAAC,CAAA,CAAA;AAAA,MACrC,gBAAA,EAAkB,OAAO,gBAAA,KAAqB,KAAA;AAAA,MAC9C,YAAA,EAAc,OAAO,YAAA,IAAgB,EAAA;AAAA,MACrC,gBAAA,EAAkB,OAAO,gBAAA,IAAoB;AAAA,KAC/C;AAGA,IAAA,IAAA,CAAK,YAAA,GAAe,IAAI,YAAA,CAAa,IAAA,CAAK,OAAO,gBAAgB,CAAA;AACjE,IAAA,IAAA,CAAK,SAAA,GAAY,IAAI,SAAA,CAAU;AAAA,MAC7B,MAAA,EAAQ,KAAK,MAAA,CAAO,MAAA;AAAA,MACpB,iBAAA,EAAmB,KAAK,MAAA,CAAO,iBAAA;AAAA,MAC/B,aAAA,EAAe,KAAK,MAAA,CAAO,aAAA;AAAA,MAC3B,UAAA,EAAY,KAAK,MAAA,CAAO,UAAA;AAAA,MACxB,eAAA,EAAiB,IAAA,CAAK,mBAAA,CAAoB,IAAA,CAAK,IAAI,CAAA;AAAA,MACnD,OAAA,EAAS,KAAK,MAAA,CAAO;AAAA,KACtB,CAAA;AAED,IAAA,IAAI,IAAA,CAAK,OAAO,gBAAA,EAAkB;AAChC,MAAA,IAAA,CAAK,UAAA,GAAa,IAAI,UAAA,CAAW;AAAA,QAC/B,MAAA,EAAQ,KAAK,MAAA,CAAO,MAAA;AAAA,QACpB,YAAA,EAAc,IAAA,CAAK,MAAA,CAAO,YAAA,IAAgB,MAAA;AAAA,QAC1C,MAAA,EAAQ,IAAA,CAAK,cAAA,CAAe,IAAA,CAAK,IAAI,CAAA;AAAA,QACrC,OAAA,EAAS,KAAK,MAAA,CAAO;AAAA,OACtB,CAAA;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,IAAA,GAAsB;AAE1B,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,YAAA,CAAa,aAAA,EAAc;AACnD,IAAA,IAAI,UAAA,EAAY;AAEd,MAAA,MAAM,SAAA,GAAY,UAAA,CAAW,SAAA,GAAa,IAAA,GAAO,GAAA;AACjD,MAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA,EAAW;AAC1B,QAAA,IAAA,CAAK,eAAA,GAAkB,UAAA;AACvB,QAAA,IAAA,CAAK,MAAA,CAAO,OAAO,UAAU,CAAA;AAC7B,QAAA;AAAA,MACF,CAAA,MAAO;AAEL,QAAA,MAAM,YAAA,GAAe,IAAA,CAAK,YAAA,CAAa,eAAA,EAAgB;AACvD,QAAA,IAAI,YAAA,EAAc;AAChB,UAAA,IAAI;AACF,YAAA,MAAM,IAAA,CAAK,mBAAmB,YAAY,CAAA;AAC1C,YAAA;AAAA,UACF,SAAS,KAAA,EAAO;AAEd,YAAA,IAAA,CAAK,aAAa,YAAA,EAAa;AAAA,UACjC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,IAAA,IAAI,IAAA,CAAK,MAAA,CAAO,gBAAA,IAAoB,IAAA,CAAK,eAAe,IAAA,EAAM;AAC5D,MAAA,IAAA,CAAK,WAAW,IAAA,EAAK;AAAA,IACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,OAAA,EAA0C;AAC3D,IAAA,MAAM,aAAA,GAAgB,MAAM,IAAA,CAAK,SAAA,CAAU,aAAa,OAAO,CAAA;AAE/D,IAAA,OAAO;AAAA,MACL,aAAa,aAAA,CAAc,YAAA;AAAA,MAC3B,aAAA,EAAe,cAAc,IAAA,CAAK,aAAA;AAAA,MAClC,MAAA,EAAQ,cAAc,IAAA,CAAK,MAAA;AAAA,MAC3B,WAAA,EAAa,cAAc,IAAA,CAAK,WAAA;AAAA,MAChC,cAAA,EAAgB,cAAc,IAAA,CAAK,cAAA;AAAA,MACnC,KAAA,EAAO,cAAc,IAAA,CAAK,KAAA;AAAA,MAC1B,MAAA,EAAQ,KAAK,MAAA,CAAO,MAAA;AAAA,MACpB,SAAA,EAAW,KAAK,GAAA;AAAI,KACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAAA,GAA+B;AAC7B,IAAA,OAAO,IAAA,CAAK,eAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,eAAA,GAA2B;AACzB,IAAA,OAAO,KAAK,eAAA,KAAoB,IAAA;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAA,GAAwB;AAE5B,IAAA,IAAI,IAAA,CAAK,iBAAiB,WAAA,EAAa;AACrC,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,CAAK,QAAQ,kBAAA,EAAoB;AAAA,UACrC,MAAA,EAAQ,MAAA;AAAA,UACR,IAAA,EAAM,EAAE,KAAA,EAAO,IAAA,CAAK,gBAAgB,WAAA,EAAY;AAAA,UAChD,WAAA,EAAa;AAAA;AAAA,SACd,CAAA;AAAA,MACH,SAAS,KAAA,EAAO;AAEd,QAAA,OAAA,CAAQ,IAAA,CAAK,uCAAuC,KAAK,CAAA;AAAA,MAC3D;AAAA,IACF;AAGA,IAAA,IAAA,CAAK,eAAA,GAAkB,IAAA;AACvB,IAAA,IAAA,CAAK,aAAa,YAAA,EAAa;AAC/B,IAAA,IAAA,CAAK,OAAO,QAAA,EAAS;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAA,CAAQ,QAAA,EAAkB,OAAA,GAA0B,EAAC,EAAsB;AAC/E,IAAA,MAAM,MAAM,QAAA,CAAS,UAAA,CAAW,MAAM,CAAA,GAClC,QAAA,GACA,GAAG,IAAA,CAAK,MAAA,CAAO,UAAU,CAAA,EAAG,SAAS,UAAA,CAAW,GAAG,IAAI,QAAA,GAAW,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAE,CAAA,CAAA;AAEpF,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,cAAA,EAAgB,kBAAA;AAAA,MAChB,GAAG,OAAA,CAAQ;AAAA,KACb;AAGA,IAAA,IAAI,OAAA,CAAQ,WAAA,KAAgB,KAAA,IAAS,IAAA,CAAK,iBAAiB,WAAA,EAAa;AACtE,MAAA,OAAA,CAAQ,eAAe,CAAA,GAAI,CAAA,OAAA,EAAU,IAAA,CAAK,gBAAgB,WAAW,CAAA,CAAA;AAAA,IACvE;AAEA,IAAA,MAAM,YAAA,GAA4B;AAAA,MAChC,MAAA,EAAQ,QAAQ,MAAA,IAAU,KAAA;AAAA,MAC1B;AAAA,KACF;AAEA,IAAA,IAAI,OAAA,CAAQ,IAAA,IAAQ,OAAA,CAAQ,MAAA,KAAW,KAAA,EAAO;AAC5C,MAAA,YAAA,CAAa,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,IAAI,CAAA;AAAA,IACjD;AAEA,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK,YAAY,CAAA;AAG9C,IAAA,IAAI,QAAA,CAAS,MAAA,KAAW,GAAA,IAAO,IAAA,CAAK,eAAA,EAAiB;AACnD,MAAA,MAAM,YAAA,GAAe,IAAA,CAAK,YAAA,CAAa,eAAA,EAAgB;AACvD,MAAA,IAAI,YAAA,EAAc;AAChB,QAAA,IAAI;AACF,UAAA,MAAM,IAAA,CAAK,mBAAmB,YAAY,CAAA;AAE1C,UAAA,IAAI,IAAA,CAAK,iBAAiB,WAAA,EAAa;AACrC,YAAA,OAAA,CAAQ,eAAe,CAAA,GAAI,CAAA,OAAA,EAAU,IAAA,CAAK,gBAAgB,WAAW,CAAA,CAAA;AACrE,YAAA,OAAO,MAAM,GAAA,EAAK,EAAE,GAAG,YAAA,EAAc,SAAS,CAAA;AAAA,UAChD;AAAA,QACF,SAAS,KAAA,EAAO;AAEd,UAAA,MAAM,KAAK,MAAA,EAAO;AAClB,UAAA,MAAM,IAAI,MAAM,6CAA6C,CAAA;AAAA,QAC/D;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,QAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,oBAAoB,aAAA,EAAkD;AAClF,IAAA,MAAM,QAAA,GAAqB;AAAA,MACzB,aAAa,aAAA,CAAc,YAAA;AAAA,MAC3B,aAAA,EAAe,cAAc,IAAA,CAAK,aAAA;AAAA,MAClC,MAAA,EAAQ,cAAc,IAAA,CAAK,MAAA;AAAA,MAC3B,WAAA,EAAa,cAAc,IAAA,CAAK,WAAA;AAAA,MAChC,cAAA,EAAgB,cAAc,IAAA,CAAK,cAAA;AAAA,MACnC,KAAA,EAAO,cAAc,IAAA,CAAK,KAAA;AAAA,MAC1B,MAAA,EAAQ,KAAK,MAAA,CAAO,MAAA;AAAA,MACpB,SAAA,EAAW,KAAK,GAAA;AAAI,KACtB;AAGA,IAAA,IAAA,CAAK,aAAa,SAAA,CAAU,QAAA,EAAU,aAAA,CAAc,aAAA,EAAe,cAAc,UAAU,CAAA;AAG3F,IAAA,IAAA,CAAK,eAAA,GAAkB,QAAA;AACvB,IAAA,IAAA,CAAK,MAAA,CAAO,OAAO,QAAQ,CAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,QAAA,EAA0B;AAE/C,IAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,GAAA,EAAI,GAAK,IAAI,EAAA,GAAK,GAAA;AAC9C,IAAA,IAAI,QAAA,CAAS,YAAY,cAAA,EAAgB;AACvC,MAAA,IAAA,CAAK,MAAA,CAAO,WAAA,CAAY,IAAI,KAAA,CAAM,mBAAmB,CAAC,CAAA;AACtD,MAAA;AAAA,IACF;AAGA,IAAA,IAAA,CAAK,eAAA,GAAkB,QAAA;AACvB,IAAA,IAAA,CAAK,MAAA,CAAO,OAAO,QAAQ,CAAA;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAA,GAA0C;AAC9C,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,aAAa,CAAA;AACjD,IAAA,IAAI,CAAC,QAAA,CAAS,EAAA,EAAI,OAAO,IAAA;AACzB,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,IAAI,IAAA,CAAK,OAAA,IAAW,IAAA,CAAK,IAAA,SAAa,IAAA,CAAK,IAAA;AAC3C,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,uBAAA,GAAkD;AACtD,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,YAAA,EAAa;AACvC,IAAA,IAAI,CAAC,MAAA,EAAQ,IAAA,EAAM,OAAO,IAAA;AAC1B,IAAA,MAAM,QAAQ,MAAA,CAAO,IAAA,CAAK,oBAAA,IAAyB,MAAA,CAAO,KAAK,KAAA,EAAO,uBAAA;AACtE,IAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,SAAS,CAAA,IAAK,KAAA,IAAS,KAAK,KAAA,GAAQ,IAAA;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,mBAAmB,YAAA,EAAqC;AACpE,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,IAAA,CAAK,OAAO,aAAA,EAAe;AAAA,MACtD,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,cAAA,EAAgB;AAAA,OAClB;AAAA,MACA,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,QACnB,UAAA,EAAY,eAAA;AAAA,QACZ,aAAA,EAAe;AAAA,OAChB;AAAA,KACF,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,IAAI,MAAM,yBAAyB,CAAA;AAAA,IAC3C;AAEA,IAAA,MAAM,aAAA,GAAoC,MAAM,QAAA,CAAS,IAAA,EAAK;AAC9D,IAAA,MAAM,IAAA,CAAK,oBAAoB,aAAa,CAAA;AAAA,EAC9C;AACF;;;AC5QO,IAAM,iBAAN,MAAqB;AAAA,EAI1B,YAAY,MAAA,EAAyB;AACnC,IAAA,IAAA,CAAK,SAAS,MAAA,CAAO,MAAA;AACrB,IAAA,IAAA,CAAK,MAAA,GAAS;AAAA,MACZ,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,UAAA,EAAY,OAAO,UAAA,IAAc;AAAA,KACnC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAA,CAAQ,QAAA,EAAkB,OAAA,GAA0B,EAAC,EAAsB;AAC/E,IAAA,MAAM,MAAM,QAAA,CAAS,UAAA,CAAW,MAAM,CAAA,GAClC,QAAA,GACA,GAAG,IAAA,CAAK,MAAA,CAAO,UAAU,CAAA,EAAG,SAAS,UAAA,CAAW,GAAG,IAAI,QAAA,GAAW,CAAA,CAAA,EAAI,QAAQ,CAAA,CAAE,CAAA,CAAA;AAEpF,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,cAAA,EAAgB,kBAAA;AAAA,MAChB,eAAA,EAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,MACtC,GAAG,OAAA,CAAQ;AAAA,KACb;AAEA,IAAA,MAAM,YAAA,GAA4B;AAAA,MAChC,MAAA,EAAQ,QAAQ,MAAA,IAAU,KAAA;AAAA,MAC1B;AAAA,KACF;AAEA,IAAA,IAAI,OAAA,CAAQ,IAAA,IAAQ,OAAA,CAAQ,MAAA,KAAW,KAAA,EAAO;AAC5C,MAAA,YAAA,CAAa,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,IAAI,CAAA;AAAA,IACjD;AAEA,IAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK,YAAY,CAAA;AAE9C,IAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,MAAA,MAAM,YAAY,MAAM,QAAA,CAAS,MAAK,CAAE,KAAA,CAAM,MAAM,eAAe,CAAA;AACnE,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,QAAA,CAAS,MAAM,IAAI,QAAA,CAAS,UAAU,CAAA,GAAA,EAAM,SAAS,CAAA,CAAE,CAAA;AAAA,IAC7F;AAEA,IAAA,OAAO,QAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAA,GAA4B;AAChC,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,cAAc,EAAE,WAAA,EAAa,OAAO,CAAA;AACxE,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAA,GAA8B;AAClC,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,aAAa,CAAA;AACjD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,SAAA,CAAU,MAAA,EAAgB,OAAA,EAA+B;AAC7D,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA;AAAA,MAC1B,eAAe,kBAAA,CAAmB,MAAM,CAAC,CAAA,SAAA,EAAY,kBAAA,CAAmB,OAAO,CAAC,CAAA;AAAA,KAClF;AACA,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAA,CAAkB,MAAA,EAAgB,OAAA,EAA+B;AACrE,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA;AAAA,MAC1B,eAAe,kBAAA,CAAmB,MAAM,CAAC,CAAA,kBAAA,EAAqB,kBAAA,CAAmB,OAAO,CAAC,CAAA;AAAA,KAC3F;AACA,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aAAA,CACJ,MAAA,EACA,OAAA,EACA,OAAA,EAKc;AACd,IAAA,MAAM,MAAA,GAAS,IAAI,eAAA,CAAgB,EAAE,SAAS,CAAA;AAC9C,IAAA,IAAI,SAAS,QAAA,EAAU,MAAA,CAAO,GAAA,CAAI,UAAA,EAAY,QAAQ,QAAQ,CAAA;AAC9D,IAAA,IAAI,SAAS,MAAA,EAAQ,MAAA,CAAO,GAAA,CAAI,QAAA,EAAU,QAAQ,MAAM,CAAA;AACxD,IAAA,IAAI,OAAA,EAAS,SAAS,IAAA,EAAM,MAAA,CAAO,IAAI,OAAA,EAAS,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAC,CAAA;AAErE,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA;AAAA,MAC1B,eAAe,kBAAA,CAAmB,MAAM,CAAC,CAAA,MAAA,EAAS,MAAA,CAAO,UAAU,CAAA;AAAA,KACrE;AACA,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YAAY,OAAA,EAAgC;AAChD,IAAA,MAAM,SAAS,OAAA,IAAW,IAAA,GAAO,YAAY,kBAAA,CAAmB,OAAO,CAAC,CAAA,CAAA,GAAK,EAAA;AAC7E,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,CAAA,YAAA,EAAe,MAAM,CAAA,CAAE,CAAA;AAC3D,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,eAAe,MAAA,EAeJ;AACf,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,eAAA,EAAiB;AAAA,MACnD,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,MAAA;AAAA,MACN,OAAA,EAAS,OAAO,cAAA,GAAiB;AAAA,QAC/B,mBAAmB,MAAA,CAAO;AAAA,OAC5B,GAAI;AAAA,KACL,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,gBAAgB,OAAA,EAAgC;AACpD,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,oBAAoB,CAAA;AACxD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,OAAA,EAAgC;AACnD,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,mBAAmB,CAAA;AACvD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,MAAA,EAIE;AACf,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,eAAA,EAAiB;AAAA,MACnD,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM;AAAA,KACP,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,KAAA,EAIF;AAChB,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,qBAAA,EAAuB;AAAA,MACzD,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,EAAE,KAAA;AAAM,KACf,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAA,CACJ,OAAA,EACA,QAAA,EAMc;AACd,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,CAAA,SAAA,EAAY,OAAO,CAAA,SAAA,CAAA,EAAa;AAAA,MAClE,MAAA,EAAQ,KAAA;AAAA,MACR,IAAA,EAAM;AAAA,KACP,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,OAAA,EAA+B;AAC3C,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,CAAA,SAAA,EAAY,OAAO,CAAA,CAAA,EAAI;AAAA,MACzD,MAAA,EAAQ;AAAA,KACT,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,QAAA,EAAkC;AACpD,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,qBAAA,EAAuB;AAAA,MACzD,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,EAAE,QAAA;AAAS,KAClB,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW,MAAA,EAGA;AACf,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,sBAAA,EAAwB;AAAA,MAC1D,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM;AAAA,KACP,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,eAAe,MAAA,EAO6E;AAChG,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,sBAAA,EAAwB;AAAA,MAC1D,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM;AAAA,KACP,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,kBAAA,CACJ,MAAA,EACA,OAAA,EACwD;AACxD,IAAA,MAAM,IAAI,OAAA,EAAS,SAAA,GAAY,CAAA,WAAA,EAAc,OAAA,CAAQ,SAAS,CAAA,CAAA,GAAK,EAAA;AACnE,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,CAAA,mBAAA,EAAsB,mBAAmB,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,CAAE,CAAA;AAC1F,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA,EAGA,MAAM,YAAA,CACJ,MAAA,EACA,SAAA,EACA,OACA,OAAA,EACqF;AACrF,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,sBAAsB,kBAAA,CAAmB,MAAM,CAAC,CAAA,OAAA,CAAA,EAAW;AAAA,MAC7F,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,EAAE,SAAA,EAAW,KAAA,EAAM;AAAA,MACzB,SAAS,OAAA,EAAS,cAAA,GAAiB,EAAE,iBAAA,EAAmB,OAAA,CAAQ,gBAAe,GAAI;AAAA,KACpF,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA,EAGA,MAAM,mBAAA,CACJ,MAAA,EACA,QAAA,EACA,OACA,OAAA,EAC8C;AAC9C,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,qBAAA,EAAuB;AAAA,MACzD,MAAA,EAAQ,MAAA;AAAA,MACR,MAAM,EAAE,MAAA,EAAQ,UAAU,KAAA,EAAO,OAAA,EAAS,SAAS,OAAA;AAAQ,KAC5D,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA,EAGA,MAAM,aAAA,CAAc,MAAA,EAAgB,QAAA,EAAgE;AAClG,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,qBAAA,EAAuB;AAAA,MACzD,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,EAAE,MAAA,EAAQ,QAAA;AAAS,KAC1B,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA,EAGA,MAAM,gBAAA,CACJ,MAAA,EACA,QAAA,EACA,OAAA,EACkE;AAClE,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,kBAAA,EAAoB;AAAA,MACtD,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,EAAE,MAAA,EAAQ,QAAA,EAAS;AAAA,MACzB,SAAS,OAAA,EAAS,cAAA,GAAiB,EAAE,iBAAA,EAAmB,OAAA,CAAQ,gBAAe,GAAI;AAAA,KACpF,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,iBAAA,CACJ,MAAA,EACA,MAAA,EACA,QAAA,EAC6F;AAC7F,IAAA,MAAM,IAAA,GAAwD,EAAE,MAAA,EAAO;AACvE,IAAA,IAAI,MAAA,KAAW,OAAA,IAAW,QAAA,EAAU,IAAA,CAAK,QAAA,GAAW,QAAA;AACpD,IAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,OAAA,CAAQ,wBAAwB,kBAAA,CAAmB,MAAM,IAAI,QAAA,EAAU;AAAA,MACjG,MAAA,EAAQ,MAAA;AAAA,MACR;AAAA,KACD,CAAA;AACD,IAAA,OAAO,SAAS,IAAA,EAAK;AAAA,EACvB;AACF;ACjXO,IAAM,qBAAA,GAAwB;AAG9B,IAAM,eAAA,GAAkB;AAAA;AAAA,EAE7B,OAAA,EAAS,SAAA;AAAA;AAAA,EAET,SAAA,EAAW;AACb;AAEA,IAAM,YAAA,GAAe,GAAA;AAKrB,SAAS,gBAAgB,MAAA,EAAwB;AAC/C,EAAA,OAAA,CAAQ,MAAA,IAAU,EAAA,EAAI,IAAA,EAAK,CAAE,WAAA,EAAY;AAC3C;AAKO,SAAS,qBAAqB,aAAA,EAA+B;AAClE,EAAA,OAAO,qBAAA,GAAwB,gBAAgB,aAAa,CAAA;AAC9D;AA0BO,SAAS,uBAAA,CACd,IAAA,EACA,aAAA,EACA,SAAA,EAIY;AACZ,EAAA,MAAM,UAAA,GAAa,gBAAgB,aAAa,CAAA;AAChD,EAAA,IAAI,CAAC,UAAA,IAAc,CAAC,qBAAA,CAAsB,IAAA,CAAK,UAAU,CAAA,EAAG;AAC1D,IAAA,OAAO,MAAM;AAAA,IAAC,CAAA;AAAA,EAChB;AAEA,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAEhC,EAAA,MAAM,aAAA,GAAgB,CAAC,OAAA,KAA6C;AAClE,IAAA,MAAM,OAAO,OAAA,CAAQ,IAAA;AACrB,IAAA,IAAI,CAAC,QAAQ,OAAO,IAAA,KAAS,YAAY,OAAO,IAAA,CAAK,YAAY,QAAA,EAAU;AAC3E,IAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA,EAAG;AAC/B,IAAA,IAAI,OAAA,CAAQ,QAAQ,YAAA,EAAc;AAChC,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,MAAA,EAAO,CAAE,MAAK,CAAE,KAAA;AACtC,MAAA,IAAI,KAAA,IAAS,IAAA,EAAM,OAAA,CAAQ,MAAA,CAAO,KAAK,CAAA;AAAA,IACzC;AACA,IAAA,OAAA,CAAQ,GAAA,CAAI,KAAK,OAAO,CAAA;AAExB,IAAA,IAAI,OAAA,CAAQ,IAAA,KAAS,eAAA,CAAgB,OAAA,IAAW,UAAU,SAAA,EAAW;AACnE,MAAA,SAAA,CAAU,UAAU,IAAI,CAAA;AAAA,IAC1B,WAAW,OAAA,CAAQ,IAAA,KAAS,eAAA,CAAgB,SAAA,IAAa,UAAU,WAAA,EAAa;AAC9E,MAAA,SAAA,CAAU,YAAY,IAAI,CAAA;AAAA,IAC5B;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,UAAU,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,oBAAA,CAAqB,UAAU,CAAC,CAAA;AAClE,EAAA,OAAA,CAAQ,UAAU,aAAa,CAAA;AAE/B,EAAA,OAAO,MAAM;AACX,IAAA,OAAA,CAAQ,YAAY,aAAa,CAAA;AAAA,EACnC,CAAA;AACF;AA6BO,SAAS,qCACd,OAAA,EACY;AACZ,EAAA,MAAM,EAAE,UAAA,EAAY,cAAA,EAAgB,eAAe,SAAA,EAAW,WAAA,EAAa,mBAAkB,GAAI,OAAA;AACjG,EAAA,MAAM,UAAA,GAAA,CAAc,aAAA,IAAiB,EAAA,EAAI,IAAA,GAAO,WAAA,EAAY;AAC5D,EAAA,IAAI,CAAC,UAAA,IAAc,CAAC,qBAAA,CAAsB,IAAA,CAAK,UAAU,CAAA,EAAG;AAC1D,IAAA,OAAO,MAAM;AAAA,IAAC,CAAA;AAAA,EAChB;AAEA,EAAA,MAAM,IAAA,GAAO,UAAA,CAAW,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACzC,EAAA,MAAM,qBAAA,GAAwB,CAAC,OAAA,KAA0B;AACvD,IAAA,IAAI,iBAAA,EAAmB;AACrB,MAAA,IAAI;AACF,QAAA,iBAAA,CAAkB,OAAO,CAAA;AAAA,MAC3B,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,IAAA,CAAK,oBAAoB,OAAO,CAAA;AAAA,IAC1C;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,CACnB,YAAA,EACA,QAAA,KACS;AACT,IAAA,cAAA,EAAe,CACZ,IAAA,CAAK,CAAC,KAAA,KAAU;AACf,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA,QAAA,CAAS,qBAAqB,IAAI,CAAA;AAClC,QAAA;AAAA,MACF;AACA,MAAA,OAAO,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA,mBAAA,CAAA,EAAuB;AAAA,QACzC,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS;AAAA,UACP,aAAA,EAAe,UAAU,KAAK,CAAA,CAAA;AAAA,UAC9B,cAAA,EAAgB;AAAA;AAClB,OACD,CAAA;AAAA,IACH,CAAC,CAAA,CACA,IAAA,CAAK,CAAC,GAAA,KAAQ;AACb,MAAA,IAAI,CAAC,GAAA,EAAK;AACV,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,QAAA,OAAO,GAAA,CAAI,IAAA,EAAK,CAAE,IAAA,CAAK,CAAC,IAAA,KAA+B;AACrD,UAAA,QAAA,CAAU,QAAQ,IAAA,CAAK,OAAA,IAAY,GAAA,CAAI,UAAA,IAAc,kBAAkB,IAAI,CAAA;AAAA,QAC7E,CAAC,CAAA;AAAA,MACH;AACA,MAAA,OAAO,GAAA,CAAI,IAAA,EAAK,CAAE,IAAA,CAAK,CAAC,YAAA,KAA0B;AAChD,QAAA,QAAA,CAAS,MAAM,YAAY,CAAA;AAAA,MAC7B,CAAC,CAAA;AAAA,IACH,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAiB;AACvB,MAAA,QAAA,CAAS,eAAe,KAAA,GAAQ,GAAA,CAAI,UAAU,MAAA,CAAO,GAAG,GAAG,IAAI,CAAA;AAAA,IACjE,CAAC,CAAA;AAAA,EACL,CAAA;AAGA,EAAA,IAAI,IAAA,GAA6B,IAAA;AACjC,EAAA,IAAI,kBAAA,GAA0C,IAAA;AAC9C,EAAA,IAAI,SAAA,GAAY,KAAA;AAEhB,EAAA,MAAM,UAAU,MAAY;AAC1B,IAAA,SAAA,GAAY,IAAA;AACZ,IAAA,IAAI,kBAAA,EAAoB;AACtB,MAAA,IAAI;AACF,QAAA,kBAAA,EAAmB;AAAA,MACrB,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,kBAAA,GAAqB,IAAA;AAAA,IACvB;AACA,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,IAAI;AACF,QAAA,IAAA,CAAK,KAAA,EAAM;AAAA,MACb,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,IAAA,GAAO,IAAA;AAAA,IACT;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,cAAA,EAAe,CAAE,IAAA,CAAK,CAAC,KAAA,KAAU;AACpD,IAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AACnB,IAAA,OAAO,KAAA,CAAM,CAAA,EAAG,IAAI,CAAA,mBAAA,CAAA,EAAuB;AAAA,MACzC,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACP,aAAA,EAAe,UAAU,KAAK,CAAA,CAAA;AAAA,QAC9B,cAAA,EAAgB;AAAA;AAClB,KACD,CAAA;AAAA,EACH,CAAC,CAAA;AAED,EAAA,YAAA,CACG,IAAA,CAAK,CAAC,GAAA,KAAQ;AACb,IAAA,IAAI,SAAA,EAAW;AACf,IAAA,IAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,qBAAA,CAAsB,qCAAqC,CAAA;AAC3D,MAAA;AAAA,IACF;AACA,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,qBAAA,CAAsB,CAAA,sBAAA,EAAyB,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AAC3D,MAAA;AAAA,IACF;AACA,IAAA,OAAO,IAAI,IAAA,EAAK;AAAA,EAClB,CAAC,CAAA,CACA,IAAA,CAAK,CAAC,YAAA,KAA0B;AAC/B,IAAA,IAAI,SAAA,IAAa,iBAAiB,MAAA,EAAW;AAC7C,IAAA,IAAA,GAAO,IAAIA,sBAAK,QAAA,CAAS;AAAA;AAAA,MAEvB;AAAA,KACD,CAAA;AAGD,IAAA,IAAA,CAAK,UAAA,CAAW,EAAA,CAAG,QAAA,EAAU,CAAC,WAAA,KAAmD;AAC/E,MAAA,MAAM,GAAA,GAAM,WAAA,EAAa,MAAA,EAAQ,OAAA,IAAW,mBAAA;AAC5C,MAAA,qBAAA,CAAsB,GAAG,CAAA;AAAA,IAC3B,CAAC,CAAA;AACD,IAAA,IAAA,CAAK,UAAA,CAAW,EAAA,CAAG,WAAA,EAAa,CAAC,WAAA,KAAmD;AAClF,MAAA,MAAM,GAAA,GAAM,WAAA,EAAa,MAAA,EAAQ,OAAA,IAAW,kCAAA;AAC5C,MAAA,qBAAA,CAAsB,GAAG,CAAA;AAAA,IAC3B,CAAC,CAAA;AAED,IAAA,kBAAA,GAAqB,uBAAA,CAAwB,MAA0B,aAAA,EAAe;AAAA,MACpF,SAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAiB;AACvB,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,qBAAA,CAAsB,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,uBAAuB,CAAA;AAAA,IACpF;AAAA,EACF,CAAC,CAAA;AAEH,EAAA,OAAO,MAAM;AACX,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AACF","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
|
-
|
|
857
|
-
|
|
858
|
-
|
|
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
|
-
|
|
861
|
-
|
|
862
|
-
|
|
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
|
-
|
|
866
|
-
ably.close();
|
|
943
|
+
cleanup();
|
|
867
944
|
};
|
|
868
945
|
}
|
|
869
946
|
|
package/dist/index.mjs.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":[],"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.
|
|
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",
|