Help
RSS
API
Feed
Maltego
Contact
Domain > game.dfc.staging.lobsterlab.io
×
More information on this domain is in
AlienVault OTX
Is this malicious?
Yes
No
DNS Resolutions
Date
IP Address
2026-02-05
95.216.10.123
(
ClassC
)
Port 80
HTTP/1.1 301 Moved PermanentlyServer: nginxDate: Thu, 05 Feb 2026 17:39:09 GMTContent-Type: text/htmlContent-Length: 162Connection: keep-aliveLocation: https://game.dfc.staging.lobsterlab.io/ html>head>title>301 Moved Permanently/title>/head>body>center>h1>301 Moved Permanently/h1>/center>hr>center>nginx/center>/body>/html>
Port 443
HTTP/1.1 200 OKServer: nginxDate: Thu, 05 Feb 2026 17:39:09 GMTContent-Type: text/html; charsetutf-8Content-Length: 49003Last-Modified: Thu, 05 Feb 2026 16:48:57 GMTConnection: keep-aliveVary: Accept-EncodingETag: 6984c9f9-bf6bAccess-Control-Allow-Origin: *Access-Control-Allow-Credentials: trueAccess-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUTAccess-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Authorization, Accept, Client-Security-Token, Accept-Encoding, DeviceAccess-Control-Max-Age: 1000Device: android-0.9.1Accept-Ranges: bytes !DOCTYPE html>html langen>head> meta charsetUTF-8> meta nameviewport contentwidthdevice-width, initial-scale1.0, maximum-scale1.0, user-scalableno> title>DFC Widget Integration Guide & Playground/title> style> * { box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol; padding: 20px; margin: 0; line-height: 1.6; color: #333; overflow-x: hidden; } h1, h2, h3 { margin-top: 1.5em; margin-bottom: 0.5em; word-wrap: break-word; } h1 { border-bottom: 2px solid #eee; padding-bottom: 10px; font-size: 1.8em; } h2 { border-bottom: 1px solid #eee; padding-bottom: 5px; font-size: 1.5em; } h3 { font-size: 1.3em; } section { margin-bottom: 40px; } pre { background-color: #f4f4f4; padding: 15px; border-radius: 4px; white-space: pre-wrap; word-break: break-all; overflow-x: auto; max-width: 100%; } code { font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier, monospace; word-break: break-all; } /* Table container for horizontal scroll */ .table-container { overflow-x: auto; margin: 20px 0; border: 1px solid #ddd; border-radius: 4px; } table { width: 100%; border-collapse: collapse; min-width: 600px; /* Minimum width to maintain readability */ } th, td { border: 1px solid #ddd; padding: 8px; text-align: left; word-wrap: break-word; } th { background-color: #f8f8f8; font-weight: bold; white-space: nowrap; } td { vertical-align: top; } /* Mobile table styles */ @media (max-width: 600px) { .table-container { border: none; } table { min-width: unset; width: 100%; border: 0; } table, thead, tbody, th, td, tr { display: block; } thead tr { position: absolute; top: -9999px; left: -9999px; } tr { border: 1px solid #ccc; margin-bottom: 10px; border-radius: 4px; background: #fff; padding: 10px; } td { border: none; border-bottom: 1px solid #eee; position: relative; padding-left: 30%; padding-top: 8px; padding-bottom: 8px; word-wrap: break-word; } td:before { content: attr(data-label) : ; position: absolute; left: 6px; width: 25%; padding-right: 10px; white-space: nowrap; font-weight: bold; color: #666; } td:last-child { border-bottom: 0; } } .widget-container { /* border: 2px dashed #007bff; padding: 15px; min-height: 100px; background-color: #f8f9fa; margin-top: 20px; */ } .controls { margin: 20px 0; padding: 15px; border: 1px solid #ccc; border-radius: 4px; background: #fafafa; } button { margin-right: 8px; margin-bottom: 8px; padding: 8px 16px; border: 1px solid #007bff; background: #007bff; color: white; cursor: pointer; border-radius: 4px; font-size: 14px; } button:hover { background: #0056b3; } button:disabled { background: #6c757d; border-color: #6c757d; cursor: not-allowed; } .status { margin: 10px 0; padding: 10px; border-radius: 4px; background: #d1ecf1; border: 1px solid #bee5eb; word-wrap: break-word; } .error { background: #f8d7da; border-color: #f5c6cb; color: #721c24; } .success { background: #d4edda; border-color: #c3e6cb; color: #155724; } .controls h3 { margin-top: 0; } .controls .input-group { margin-bottom: 15px; } .controls label { display: block; margin-bottom: 5px; font-weight: bold; word-wrap: break-word; } .controls input { padding: 8px; width: 100%; max-width: 100%; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; } /* Mobile specific styles */ @media (max-width: 480px) { body { padding: 10px; font-size: 14px; } h1 { font-size: 1.6em; } h2 { font-size: 1.4em; } h3 { font-size: 1.2em; } .controls { padding: 10px; } button { width: 100%; margin-right: 0; margin-bottom: 8px; padding: 12px; font-size: 16px; /* Prevent zoom on iOS */ } .controls input { font-size: 16px; /* Prevent zoom on iOS */ padding: 12px; } pre { padding: 10px; font-size: 12px; line-height: 1.4; } section { margin-bottom: 30px; } ul, ol { padding-left: 20px; } li { margin-bottom: 5px; } } /style>link relstylesheet hrefstyles.css>/head>body> h1>DFC Game Widget Integration Guide & Playground/h1> p>This page serves as a live documentation and testing environment for the DFC Game Widget./p> p>Current API URL: strong idapiUrl>Loading.../strong>/p> div stylebackground: #f8f9fa; border: 1px solid #dee2e6; border-radius: 4px; padding: 15px; margin: 20px 0;> h3 stylemargin-top: 0;>0.8.3 - Текущая версия/h3> p>strong>Дата:/strong> 25.12.2025 | strong>Тип:/strong> patch/p> h4>Нововведения/h4> ul> li>Замена ссылки при открытии приложения виджета, когда запускается лендинг/li> li>Открытие модального окна для инвентаря на странице Main Storage/li> li>Добавление в глобальную переменную для dfcGame метода openStartScreen()/li> li>Добавление секции Quests - Meme Invasion/li> li>Добавление в секции Storage сегмента инвентаря с NFT/li> /ul> h4>Миграция/h4> p>Миграция не требуется./p> h4>Breaking Changes/h4> p>Отсутствуют./p> p stylemargin-bottom: 0;>em>Полная история изменений доступна в versions.md/em>/p> /div> section iddocs> h2>1. How to Use/h2> p>To embed the widget on your site, include the following scripts in your HTML file, preferably at the end of the code><body>/code> tag. These URLs point to the staging environment./p> pre>code><!-- DFC Widget Scripts --><script srchttps://staging.widget.game.dapp.expert/runtime.js></script><script srchttps://staging.widget.game.dapp.expert/polyfills.js></script><script srchttps://staging.widget.game.dapp.expert/main.js></script>/code>/pre> h3>Widget API/h3> p>The scripts expose a global code>window.dfcGame/code> object with the following API:/p> h4>Core Methods/h4> ul> li>code>window.dfcGame.init(config): Promise<void>/code>: Initializes and renders the widget on the page. It takes an optional configuration object./li> li>code>window.dfcGame.destroy(): void/code>: Destroys the widget instance and removes it from the DOM./li> li>code>window.dfcGame.restart(config): Promise<void>/code>: Restarts the widget with the same or updated configuration./li> li>code>window.dfcGame.waitForReady(timeout): Promise<void>/code>: Waits for the widget API to be fully ready. Timeout in milliseconds (optional)./li> /ul> h4>Screen Navigation/h4> ul> li>code>window.dfcGame.openPlayerScreen(): void/code>: Opens the player profile screen within the widget./li> li>code>window.dfcGame.openCharacterScreen(): void/code>: Opens the character management screen within the widget./li> li>code>window.dfcGame.openStorageScreen(): void/code>: Opens the storage/inventory screen within the widget./li> li>code>window.dfcGame.openQuestsScreen(): void/code>: Opens the quests screen within the widget./li> li>code>window.dfcGame.close(): void/code>: Closes the widget if its currently open./li> /ul> h4>Properties/h4> ul> li>code>window.dfcGame.initialized: boolean/code>: A read-only property that indicates if the widget has been successfully initialized./li> li>code>window.dfcGame.isReady: boolean/code>: A read-only property that indicates if the widget API is ready for use./li> li>code>window.dfcGame.apiUrl: string/code>: The current API URL being used by the widget (read-only)./li> li>code>window.dfcGame.setLocale(locale: string): void/code>: Sets the locale of the widget./li> li>code>window.dfcGame.locale: string | undefined/code>: The current locale of the widget (read-only)./li> li>code>window.dfcGame.appLangs: string/code>: The available languages for the widget (read-only)./li> /ul> h2>2. Configuration Options/h2> p>The code>init/code> function accepts a configuration object with the following optional properties:/p> div classtable-container> table> thead> tr> th>Property/th> th>Type/th> th>Description/th> th>Default/th> /tr> /thead> tbody> tr> td data-labelProperty>code>hostElementSelector/code>/td> td data-labelType>string/td> td data-labelDescription>CSS selector for the HTML element where the widget will be rendered./td> td data-labelDefault>code>body/code> (appended)/td> /tr> tr> td data-labelProperty>code>userCookieName/code>/td> td data-labelType>string/td> td data-labelDescription>Name of the cookie that stores the authenticated users token./td> td data-labelDefault>code>user_token_dev/code>/td> /tr> tr> td data-labelProperty>code>guestCookieName/code>/td> td data-labelType>string/td> td data-labelDescription>Name of the cookie that stores the guest users token./td> td data-labelDefault>code>guest_token_dev/code>/td> /tr> tr> td data-labelProperty>code>wikiUrl/code>/td> td data-labelType>Record<string, string>/td> td data-labelDescription>Map of wiki URLs per language (e.g., code>{ ru: ..., en: ... }/code>). If omitted or empty, the link is hidden./td> td data-labelDefault>em>undefined/em>/td> /tr> tr> td data-labelProperty>code>logoUrl/code>/td> td data-labelType>string/td> td data-labelDescription>URL for the logo in the widgets footer. If provided, the logo becomes a clickable link./td> td data-labelDefault>em>undefined/em>/td> /tr> tr> td data-labelProperty>code>onLoginClick/code>/td> td data-labelType>function/td> td data-labelDescription>A callback function to be executed when the user clicks the Login button. Overrides the default `window.dapp.openLogin` behavior./td> td data-labelDefault>em>undefined/em>/td> /tr> tr> td data-labelProperty>code>onSignupClick/code>/td> td data-labelType>function/td> td data-labelDescription>A callback function to be executed when the user clicks the Sign Up button. Overrides the default `window.dapp.openRegistration` behavior./td> td data-labelDefault>em>undefined/em>/td> /tr> tr> td data-labelProperty>code>onNavigate/code>/td> td data-labelType>function/td> td data-labelDescription>A callback function to be executed when the widget requests navigation to an external page (e.g., Meme Locator). Return code>false/code> to cancel the default navigation./td> td data-labelDefault>em>undefined/em>/td> /tr> tr> td data-labelProperty>code>defightLink/code>/td> td data-labelType>string/td> td data-labelDescription>URL for the DeFight link in the widgets mobile toolbar. If provided, the DeFight icon becomes a clickable link./td> td data-labelDefault>em>undefined/em>/td> /tr> tr> td data-labelProperty>code>dappApiUrl/code>/td> td data-labelType>string/td> td data-labelDescription>Base URL for Dapp (site) API, used by the Meme Locator. If omitted, code>apiUrl/code> is used./td> td data-labelDefault>em>undefined/em>/td> /tr> tr> td data-labelProperty>code>svgSpritePath/code>/td> td data-labelType>string/td> td data-labelDescription>Path to a custom SVG sprite file./td> td data-labelDefault>(Internal path)/td> /tr> tr> td data-labelProperty>code>locale/code>/td> td data-labelType>string/td> td data-labelDescription>Preferred locale for internationalization (e.g., en)./td> td data-labelDefault>Browsers default/td> /tr> tr> td data-labelProperty>code>appLangs/code>/td> td data-labelType>string/td> td data-labelDescription>Array of available languages for the application. (e.g., en, ru)/td> td data-labelDefault>en, ru/td> /tr> /tbody> /table> /div> h2>3. Host Site Integration (Authentication)/h2> p>The widget integrates with your sites authentication system by passing callback functions in the initialization configuration. You must provide `onLoginClick` and `onSignupClick` functions in the config object passed to `window.dfcGame.init()`./p> pre>code>window.dfcGame.init({ // ... other config options onLoginClick: () > { console.log(Host site: onLoginClick triggered); alert(Host site: Login modal would open here.); }, onSignupClick: () > { console.log(Host site: onSignupClick triggered); alert(Host site: Registration modal would open here.); }});/code>/pre> p>The widget will call these functions when the user clicks on the Log In or Sign Up buttons within the widget./p> h3>External Navigation Callback/h3> p>Provide code>onNavigate/code> to intercept external navigation requests (e.g., Meme Locator Visit button). Return code>false/code> to prevent the default code>window.open/code> fallback./p> pre>code>window.dfcGame.init({ // ... other config options onNavigate: ({ url, source }) > { if (source meme-locator && url) { // Host site routing logic here window.location.href url; return false; // prevent default _blank fallback } }});/code>/pre> h3>Widget Loaded Event/h3> p>The DFC Game Widget dispatches a custom code>widgetLoaded/code> event to the host page once it has been fully initialized and is ready for interaction. This event is a reliable signal that the widgets internal services are operational, initial data is loaded, and the UI is fully rendered./p> p>This event is particularly useful for controlling host-site elements, such as hiding a splash screen or preloader, that are displayed while the widget is loading./p> pre>code>document.addEventListener(widgetLoaded, () > { console.log(DFC Widget is fully loaded!); // Add your logic here to hide a splash screen, enable buttons, etc. // For example: // document.getElementById(my-splash-screen).style.display none;});/code>/pre> p>The event is a standard code>CustomEvent/code> with code>bubbles: true/code> and code>composed: true/code>, meaning it will propagate up the DOM tree and traverse Shadow DOM boundaries, making it accessible from the main document./p> /section> section idplayground> h2>4. Live Playground/h2> p>Use the controls below to configure and initialize the widget in the container at the bottom of the page./p> div classcontrols> h3>Initial Configuration/h3> div classinput-group> label forhostElementSelector>Host Element Selector:/label> input typetext idhostElementSelector value#widget-container> /div> div classinput-group> label foruserCookie>User Cookie Name:/label> input typetext iduserCookie valueuser_token_dev> /div> div classinput-group> label forguestCookie>Guest Cookie Name:/label> input typetext idguestCookie valueguest_token_dev> /div> div classinput-group> label>Wiki URLs (per language):/label> div styledisplay: grid; gap: 8px;> div> label forwikiUrl-ru>ru/label> input typetext idwikiUrl-ru valuehttps://dapp.expert/dfc/?langru> /div> div> label forwikiUrl-en>en/label> input typetext idwikiUrl-en valuehttps://dapp.expert/dfc/?langen> /div> /div> /div> div classinput-group> label forlogoUrl>Logo URL:/label> input typetext idlogoUrl valuehttps://dapp.expert/dfc> /div> div classinput-group> label fordefightLink>DeFight Link (for mobile toolbar):/label> input typetext iddefightLink valuehttps://defight.games/> /div> div classinput-group> label fordebugMode>Enable Debug Mode:/label> input typecheckbox iddebugMode styleheight: 40px;> /div> div classinput-group> label forlocale>Init locale:/label> input typetext idlocale valueen> /div> div classinput-group> label forappLangs>App langs:/label> input typetext idappLangs valueen, ru> /div> !-- button idupdateConfigBtn stylemargin-top: 10px;>Update Live Config/button> Feature Removed --> /div> div classcontrols> h3>Authentication State/h3> p>Current Status: strong idauthStatus>Checking.../strong>/p> div classinput-group> label forauthToken>Auth Token (for login):/label> input typetext idauthToken placeholderEnter a user JWT here...> /div> div classinput-group> label forguestToken>Guest Token (optional):/label> input typetext idguestToken placeholderEnter specific guest token or leave blank> /div> button idloginBtn>Login as User/button> button idlogoutBtn>Become Guest (Logout)/button> p stylefont-size: 0.9em; margin-top: 10px;>em>Note: After changing auth state, you must strong>Restart/strong> the widget to see the effect./em>/p> /div> div classcontrols> h3>Actions/h3> button idinitWidget>Initialize Widget/button> button iddestroyWidget disabled>Destroy Widget/button> button idrestartWidget disabled>Restart Widget/button> button idcheckStatus>Check Status/button> br/>br/> button idopenPlayer>Open Player/button> button idopenCharacter>Open Character/button> button idopenStorage>Open Storage/button> button idopenQuests>Open Quests/button> button idcloseWidget>Close Widget/button> /div> div idstatus classstatus>Widget not loaded yet/div> div classcontrols idquestDevTools> h3>Quest Test Tools (DEV)/h3> p stylefont-size: 0.9em; margin-top: 0;>em>Uses Auth Token from Authentication State./em>/p> button idquestResetMain>Reset Main Quest/button> button idquestResetBattlePass>Reset Battle Pass/button> button idquestResetMemeInvasion>Reset Meme Invasion/button> button idquestAddMainItems>Add items to Main Quest/button> div classinput-group> label forquestSeedPlayerId>Player ID (optional):/label> input typetext idquestSeedPlayerId placeholderplayer_id_optional> /div> div classinput-group> label forquestSeedRaritySlug>Rarity slug:/label> select idquestSeedRaritySlug> option valuenormal selected>normal/option> option valuegood>good/option> option valuerare>rare/option> option valueepic>epic/option> option valuelegendary>legendary/option> /select> /div> div classinput-group> label forquestSeedQuantityPerItem>Quantity per item:/label> input typenumber idquestSeedQuantityPerItem min1 value1> /div> button idquestSeedDeployAll>Seed & Deploy All (Main Quest)/button> div classinput-group> label forquestItemRarityId>Add item to inventory (itemDefinitionRarityId):/label> input typetext idquestItemRarityId placeholderitem_definition_rarity_id_here> /div> div classinput-group> label forquestItemQty>Quantity (optional):/label> input typenumber idquestItemQty min1 value1> /div> button idquestAddItem>Add Item/button> div idquestStatus classstatus>Quest tools idle/div> /div> div classwidget-container idwidget-container> dfc-game>/dfc-game> /div> /section> section idsafe-integration> h2>5. IMPORTANT: Safe Integration for Production/h2> p>strong>To prevent NG0908 errors on first load, always wait for the widget API to be ready:/strong>/p> h3>Recommended Integration Code:/h3> pre>code><script> document.addEventListener(DOMContentLoaded, async function() { // Wait for widget API to be ready (recommended for production) if (window.dfcGame && window.dfcGame.waitForReady) { try { await window.dfcGame.waitForReady(10000); // 10 second timeout const widget await window.dfcGame.init({ hostElementSelector: #your-widget-container, onLoginClick: () > { // Your login logic here console.log(Login clicked); }, onSignupClick: () > { // Your signup logic here console.log(Signup clicked); } }); console.log(DFC Widget initialized successfully); } catch (error) { console.error(Failed to initialize DFC Widget:, error); // Retry logic (optional) setTimeout(async () > { try { await window.dfcGame.init(); console.log(DFC Widget initialized on retry); } catch (retryError) { console.error(Widget initialization failed on retry:, retryError); } }, 1000); } } else { console.error(DFC Widget not available); } });</script>/code>/pre> h3>Alternative: Polling Method (for older browsers)/h3> pre>code><script> document.addEventListener(DOMContentLoaded, function() { function initDfcWidget() { if (window.dfcGame && window.dfcGame.isReady) { // Widget API is ready, safe to initialize window.dfcGame.init({ hostElementSelector: #your-widget-container, onLoginClick: function() { console.log(Login clicked); }, onSignupClick: function() { console.log(Signup clicked); } }).then(function() { console.log(DFC Widget initialized successfully); }).catch(function(error) { console.error(Failed to initialize DFC Widget:, error); }); } else { // Widget not ready yet, wait and retry setTimeout(initDfcWidget, 100); } } // Start checking for widget readiness initDfcWidget(); });</script>/code>/pre> h3>Key Points:/h3> ul> li>strong>Always check code>window.dfcGame.isReady/code>/strong> or use code>await window.dfcGame.waitForReady()/code> before calling code>init()/code>/li> li>strong>Never call code>init()/code> immediately/strong> after script load - this causes NG0908 errors/li> li>strong>Implement retry logic/strong> for better user experience/li> li>strong>Use proper error handling/strong> to catch initialization failures/li> /ul> /section>div iddebugLog>/div> !-- The scripts below are for the widget built by `ng build --configurationwidget-dev`. The `dev` script in package.json runs this build and serves this index.html file, so these script tags are required for the playground to work correctly. --> script> document.addEventListener(DOMContentLoaded, function() { const initBtn document.getElementById(initWidget); const destroyBtn document.getElementById(destroyWidget); const restartBtn document.getElementById(restartWidget); const statusBtn document.getElementById(checkStatus); const statusDiv document.getElementById(status); const openPlayerBtn document.getElementById(openPlayer); const openCharacterBtn document.getElementById(openCharacter); const openStorageBtn document.getElementById(openStorage); const openQuestsBtn document.getElementById(openQuests); const closeBtn document.getElementById(closeWidget); // const updateConfigBtn document.getElementById(updateConfigBtn); // Feature removed const hostElementSelectorInput document.getElementById(hostElementSelector); const userCookieInput document.getElementById(userCookie); const guestCookieInput document.getElementById(guestCookie); const wikiUrlRuInput document.getElementById(wikiUrl-ru); const wikiUrlEnInput document.getElementById(wikiUrl-en); const logoUrlInput document.getElementById(logoUrl); const defightLinkInput document.getElementById(defightLink); const debugModeCheckbox document.getElementById(debugMode); const localeInput document.getElementById(locale); const appLangsInput document.getElementById(appLangs); const configInputs hostElementSelectorInput, userCookieInput, guestCookieInput, wikiUrlRuInput, wikiUrlEnInput, logoUrlInput, defightLinkInput, localeInput, appLangsInput; const authTokenInput document.getElementById(authToken); const guestTokenInput document.getElementById(guestToken); const loginBtn document.getElementById(loginBtn); const logoutBtn document.getElementById(logoutBtn); const authStatusSpan document.getElementById(authStatus); const apiUrlSpan document.getElementById(apiUrl); const questResetMainBtn document.getElementById(questResetMain); const questResetBattlePassBtn document.getElementById(questResetBattlePass); const questResetMemeInvasionBtn document.getElementById(questResetMemeInvasion); const questAddMainItemsBtn document.getElementById(questAddMainItems); const questSeedDeployAllBtn document.getElementById(questSeedDeployAll); const questSeedPlayerIdInput document.getElementById(questSeedPlayerId); const questSeedRaritySlugSelect document.getElementById(questSeedRaritySlug); const questSeedQuantityPerItemInput document.getElementById(questSeedQuantityPerItem); const questAddItemBtn document.getElementById(questAddItem); const questItemRarityIdInput document.getElementById(questItemRarityId); const questItemQtyInput document.getElementById(questItemQty); const questStatusDiv document.getElementById(questStatus); function updateStatus(message, type info) { statusDiv.textContent message; statusDiv.className status + type; } function updateQuestStatus(message, type info) { questStatusDiv.textContent message; questStatusDiv.className status + type; } function updateButtons() { const isInitialized window.dfcGame && window.dfcGame.initialized; initBtn.disabled isInitialized; destroyBtn.disabled !isInitialized; restartBtn.disabled !isInitialized; // updateConfigBtn.disabled !isInitialized; // Feature removed // Disable config inputs when widget is running configInputs.forEach(input > input.disabled isInitialized); } function setQuestControlsDisabled(isDisabled) { questResetMainBtn, questResetBattlePassBtn, questResetMemeInvasionBtn, questAddMainItemsBtn, questSeedDeployAllBtn, questSeedPlayerIdInput, questSeedRaritySlugSelect, questSeedQuantityPerItemInput, questAddItemBtn, questItemRarityIdInput, questItemQtyInput, .forEach((el) > { if (el) el.disabled isDisabled; }); } function getApiBaseUrl() { if (window.dfcGame && window.dfcGame.apiUrl) { return window.dfcGame.apiUrl.replace(/\/$/, ); } return null; } function getAuthTokenFromState() { return authTokenInput.value.trim(); } async function postQuestDev(endpoint, payload) { const apiBase getApiBaseUrl(); if (!apiBase) { updateQuestStatus(API URL not available. Initialize widget first., error); return; } const token getAuthTokenFromState(); if (!token) { updateQuestStatus(Auth token is required. Set it in Authentication State., error); return; } setQuestControlsDisabled(true); updateQuestStatus(Request in progress..., info); try { const response await fetch(`${apiBase}${endpoint}`, { method: POST, headers: { Content-Type: application/json, Authorization: `Bearer ${token}`, }, body: JSON.stringify(payload ?? {}), }); const rawText await response.text(); let data null; if (rawText) { try { data JSON.parse(rawText); } catch (parseError) { updateQuestStatus(Transport error: Invalid API response format., error); return; } } if (data && data.isSuccess false) { const detailMessage data.messageDetail?.0?.details?.message; const message detailMessage || data.message || API operation failed; updateQuestStatus(`${data.statusCode ?? ERR} ${message}`, error); return; } if (!response.ok) { updateQuestStatus(`HTTP ${response.status}`, error); return; } updateQuestStatus(OK, success); } catch (error) { updateQuestStatus(`Transport error: ${error.message}`, error); } finally { setQuestControlsDisabled(false); } } function checkDfcGame() { if (!window.dfcGame) { updateStatus(ERROR: window.dfcGame not available. Check if scripts loaded correctly., error); return false; } return true; } function gatherConfig() { const appLangs appLangsInput.value.trim().split(,).map(lang > lang.trim()).filter(Boolean); const wikiUrlMap {}; const wikiCandidates { lang: ru, value: wikiUrlRuInput.value.trim() }, { lang: en, value: wikiUrlEnInput.value.trim() }, ; wikiCandidates.forEach(({ lang, value }) > { if (value) { wikiUrlMaplang value; } }); const config { //hostElementSelector: hostElementSelectorInput.value.trim(), userCookieName: userCookieInput.value.trim(), guestCookieName: guestCookieInput.value.trim(), wikiUrl: Object.keys(wikiUrlMap).length ? wikiUrlMap : undefined, logoUrl: logoUrlInput.value.trim(), defightLink: defightLinkInput.value.trim(), debug: debugModeCheckbox.checked, locale: localeInput.value.trim(), appLangs, onLoginClick: () > { console.log(Host site: onLoginClick triggered); alert(Host site: Login modal would open here.); if (checkDfcGame() && window.dfcGame.close) window.dfcGame.close(); }, onSignupClick: () > { console.log(Host site: onSignupClick triggered); alert(Host site: Registration modal would open here.); if (checkDfcGame() && window.dfcGame.close) window.dfcGame.close(); } }; // Do not pass empty string values, so the component can use its default behavior for (const key in config) { if (!configkey) { delete configkey; } } return config; } initBtn.addEventListener(click, async function() { if (!checkDfcGame()) return; try { updateStatus(Waiting for widget to be ready..., info); // Wait for widget API to be ready await window.dfcGame.waitForReady(10000); updateStatus(Initializing widget..., info); const config gatherConfig(); console.log(Initializing with config:, config); await window.dfcGame.init(config); apiUrlSpan.textContent window.dfcGame.apiUrl || N/A; checkAuthState(); updateStatus(Widget initialized successfully!, success); updateButtons(); } catch (error) { updateStatus(ERROR: + error.message, error); console.error(Widget initialization failed:, error); } }); destroyBtn.addEventListener(click, function() { if (!checkDfcGame()) return; try { window.dfcGame.destroy(); updateStatus(Widget destroyed successfully!, success); updateButtons(); } catch (error) { updateStatus(ERROR: + error.message, error); console.error(Widget destruction failed:, error); } }); restartBtn.addEventListener(click, async function() { if (!checkDfcGame() || !window.dfcGame.initialized) { updateStatus(Cannot restart: Widget not initialized., error); return; } try { updateStatus(Restarting widget..., info); const config gatherConfig(); await window.dfcGame.restart(config); updateStatus(Widget restarted successfully!, success); updateButtons(); } catch (error) { updateStatus(ERROR during restart: + error.message, error); console.error(Widget restart failed:, error); } }); statusBtn.addEventListener(click, function() { if (!checkDfcGame()) return; const isInitialized window.dfcGame.initialized; updateStatus(`Widget status: ${isInitialized ? Initialized : Not initialized}`, isInitialized ? success : info); updateButtons(); }); function openScreenWithDelay(screenOpener) { // Use a timeout to prevent the same click event that opens the widget // from being immediately captured by the backdrop and closing it. setTimeout(() > { if (checkDfcGame() && screenOpener) { screenOpener(); } }, 200); } function buildTestConfig(overrides {}) { const config gatherConfig(); if (!config.hostElementSelector) { config.hostElementSelector #widget-container; } return { ...config, ...overrides }; } async function prepareWidgetForTests(overrides {}) { if (!checkDfcGame()) { throw new Error(window.dfcGame not available); } await window.dfcGame.waitForReady(10000); window.dfcGame.destroy(); await new Promise(resolve > setTimeout(resolve, 50)); const config buildTestConfig(overrides); await window.dfcGame.init(config); apiUrlSpan.textContent window.dfcGame.apiUrl || N/A; checkAuthState(); updateButtons(); return { initialized: window.dfcGame.initialized, isReady: window.dfcGame.isReady }; } window.dfcGameTest { prepare: prepareWidgetForTests, destroy: () > { if (checkDfcGame()) window.dfcGame.destroy(); }, close: () > { if (checkDfcGame() && window.dfcGame.close) window.dfcGame.close(); }, open: (section) > { openScreenWithDelay(() > window.dfcGame.open(section)); }, openPlayerScreen: () > { openScreenWithDelay(() > window.dfcGame.openPlayerScreen()); }, openCharacterScreen: () > { openScreenWithDelay(() > window.dfcGame.openCharacterScreen()); }, openStorageScreen: () > { openScreenWithDelay(() > window.dfcGame.openStorageScreen()); }, openQuestsScreen: () > { openScreenWithDelay(() > window.dfcGame.openQuestsScreen()); }, openStartScreen: () > { openScreenWithDelay(() > window.dfcGame.openStartScreen()); } }; openPlayerBtn.addEventListener(click, () > { openScreenWithDelay(() > window.dfcGame.openPlayerScreen()); }); openCharacterBtn.addEventListener(click, () > { openScreenWithDelay(() > window.dfcGame.openCharacterScreen()); }); openStorageBtn.addEventListener(click, () > { openScreenWithDelay(() > window.dfcGame.openStorageScreen()); }); openQuestsBtn.addEventListener(click, () > { openScreenWithDelay(() > window.dfcGame.openQuestsScreen()); }); closeBtn.addEventListener(click, () > { if (checkDfcGame() && window.dfcGame.close) window.dfcGame.close(); }); /* updateConfigBtn.addEventListener(click, () > { if (!checkDfcGame() || !window.dfcGame.initialized) { updateStatus(Initialize the widget first!, error); return; } const liveWikiUrls {}; { lang: ru, value: wikiUrlRuInput.value.trim() }, { lang: en, value: wikiUrlEnInput.value.trim() }, .forEach(({ lang, value }) > { if (value) { liveWikiUrlslang value; } }); const newConfig { wikiUrl: Object.keys(liveWikiUrls).length ? liveWikiUrls : undefined, logoUrl: logoUrlInput.value.trim() }; console.log(Updating config with:, newConfig); if (window.dfcGame.updateConfig) { window.dfcGame.updateConfig(newConfig); updateStatus(Live config updated!, success); } }); */ function getCookie(name) { const value `; ${document.cookie}`; const parts value.split(`; ${name}`); if (parts.length 2) return parts.pop().split(;).shift(); } function setCookie(name, value, days 1) { let expires ; if (days) { const date new Date(); date.setTime(date.getTime() + (days*24*60*60*1000)); expires ; expires + date.toUTCString(); } document.cookie name + + (value || ) + expires + ; path/; } function deleteCookie(name) { document.cookie name + ; Path/; ExpiresThu, 01 Jan 1970 00:00:01 GMT;; } function checkAuthState() { const userCookieName userCookieInput.value.trim(); const guestCookieName guestCookieInput.value.trim(); const userToken getCookie(userCookieName); const guestToken getCookie(guestCookieName); authTokenInput.value userToken || ; guestTokenInput.value guestToken || ; if (userToken) { authStatusSpan.textContent Logged In (User Token found); authStatusSpan.style.color green; } else if (guestToken) { authStatusSpan.textContent Guest (Guest Token found); authStatusSpan.style.color orange; } else { authStatusSpan.textContent No Session (No token found); authStatusSpan.style.color red; } } loginBtn.addEventListener(click, () > { const userCookieName userCookieInput.value.trim(); const guestCookieName guestCookieInput.value.trim(); const token authTokenInput.value.trim(); if (!token) { updateStatus(Please provide an auth token to log in., error); return; } deleteCookie(guestCookieName); setCookie(userCookieName, token); updateStatus(`User token set in cookie ${userCookieName}. Please restart the widget.`, success); checkAuthState(); }); logoutBtn.addEventListener(click, () > { const userCookieName userCookieInput.value.trim(); const guestCookieName guestCookieInput.value.trim(); let guestToken guestTokenInput.value.trim(); if (!guestToken) { guestToken `guest_session_${Date.now()}`; } deleteCookie(userCookieName); setCookie(guestCookieName, guestToken); updateStatus(`Guest token set in cookie ${guestCookieName}. Please restart the widget.`, success); checkAuthState(); }); questResetMainBtn.addEventListener(click, () > { postQuestDev(/game/quest/serving/clear-states, { questSlug: main-quest }); }); questResetBattlePassBtn.addEventListener(click, () > { postQuestDev(/game/quest/serving/clear-states, { questSlug: battle-pass }); }); questResetMemeInvasionBtn.addEventListener(click, () > { postQuestDev(/game/quest/serving/clear-states, { questSlug: meme-invasion }); }); questAddMainItemsBtn.addEventListener(click, () > { postQuestDev(/game/quest/serving/main-quest/add-items, {}); }); questSeedDeployAllBtn.addEventListener(click, () > { const playerId questSeedPlayerIdInput.value.trim(); const raritySlug questSeedRaritySlugSelect.value; const quantityRaw questSeedQuantityPerItemInput.value.trim(); const parsedQuantity quantityRaw ? Number(quantityRaw) : 1; const quantityPerItem Number.isFinite(parsedQuantity) && parsedQuantity > 0 ? parsedQuantity : 1; if (!raritySlug) { updateQuestStatus(Rarity slug is required., error); return; } const payload { raritySlug, quantityPerItem, }; if (playerId) { payload.playerId playerId; } postQuestDev(/game/quest/serving/main-quest/seed-and-deploy-all, payload); }); questAddItemBtn.addEventListener(click, () > { const itemDefinitionRarityId questItemRarityIdInput.value.trim(); const quantityRaw questItemQtyInput.value.trim(); const parsedQuantity quantityRaw ? Number(quantityRaw) : 1; const quantity Number.isFinite(parsedQuantity) && parsedQuantity > 0 ? parsedQuantity : 1; if (!itemDefinitionRarityId) { updateQuestStatus(Item definition rarity id is required., error); return; } const payload { items: { itemDefinitionRarityId, quantity, }, , }; postQuestDev(/internal/player/inventory/add-item, payload); }); setTimeout(async () > { checkAuthState(); if (checkDfcGame()) { // Check if widget API is ready if (window.dfcGame.isReady) { updateStatus(Scripts loaded. Widget API is ready. Please configure and click Initialize Widget., info); updateButtons(); // NEW: Auto-initialize widget if not already initialized if (!window.dfcGame.initialized) { try { const config gatherConfig(); // console.log(Auto-initializing with config:, config); await window.dfcGame.init(config); apiUrlSpan.textContent window.dfcGame.apiUrl || N/A; checkAuthState(); updateStatus(Widget auto-initialized successfully!, success); updateButtons(); } catch (error) { updateStatus(ERROR during auto-initialization: + error.message, error); console.error(Widget auto-initialization failed:, error); } } } else { updateStatus(Scripts loaded. Waiting for widget API to be ready..., info); updateButtons(); // Wait for API to be ready, then update status try { await window.dfcGame.waitForReady(5000); updateStatus(Widget API is ready. Please configure and click Initialize Widget., info); // NEW: Auto-initialize widget if not already initialized after waiting if (!window.dfcGame.initialized) { try { const config gatherConfig(); await window.dfcGame.init(config); apiUrlSpan.textContent window.dfcGame.apiUrl || N/A; checkAuthState(); updateStatus(Widget auto-initialized successfully!, success); updateButtons(); } catch (error) { updateStatus(ERROR during auto-initialization: + error.message, error); console.error(Widget auto-initialization failed:, error); } } } catch (error) { updateStatus(Widget API not ready within timeout. Click Initialize Widget manually., error); } } } }, 500); // NEW: Listen for custom widgetLoaded event from Angular widget on document document.addEventListener(widgetLoaded, () > { console.log(Host site: DFC Widget is fully loaded and ready!); updateStatus(DFC Widget: Event received! Widget is fully loaded and ready., success); // Use new update function // Client can add logic here to hide splash screen or perform other actions }); }); /script>script srcruntime.js typemodule>/script>script srcpolyfills.js typemodule>/script>script srcmain.js typemodule>/script>/body>/html>
Subdomains
Date
Domain
IP
test1.staging.lobsterlab.io
2026-02-02
95.216.10.123
app.test1.staging.lobsterlab.io
2026-02-02
95.216.10.123
z2s.app.test1.staging.lobsterlab.io
2026-02-02
95.216.10.123
dev.api.file.mira.staging.lobsterlab.io
2026-02-03
95.216.10.123
api.path.mira.staging.lobsterlab.io
2026-02-02
95.216.10.123
dev.origin.bossjob.staging.lobsterlab.io
2026-02-02
95.216.10.123
cec.staging.lobsterlab.io
2026-02-02
95.216.10.123
game.dfc.staging.lobsterlab.io
2026-02-05
95.216.10.123
nft.dfc.staging.lobsterlab.io
2026-02-02
95.216.10.123
dev.dae.staging.lobsterlab.io
2026-02-02
95.216.10.123
update.stage.staging.lobsterlab.io
2026-02-02
95.216.10.123
dev.stage.staging.lobsterlab.io
2026-02-03
95.216.10.123
kiosk.dev.stage.staging.lobsterlab.io
2026-02-02
95.216.10.123
dev.live.staging.lobsterlab.io
2026-02-02
95.216.10.123
hatimaki.app.dev.live.staging.lobsterlab.io
2026-02-02
95.216.10.123
www.immocea.virtuimo.staging.lobsterlab.io
2026-02-02
95.216.10.123
martini.virtuimo.staging.lobsterlab.io
2026-02-02
95.216.10.123
www.bleucitron.virtuimo.staging.lobsterlab.io
2026-02-02
95.216.10.123
api.time.pep.staging.lobsterlab.io
2026-02-02
95.216.10.123
dev.api.tenant.pep.staging.lobsterlab.io
2026-02-02
95.216.10.123
dev.ker.staging.lobsterlab.io
2026-02-02
95.216.10.123
master.staging.lobsterlab.io
2026-02-02
95.216.10.123
app.master.staging.lobsterlab.io
2026-02-02
95.216.10.123
z2s-app.app.master.staging.lobsterlab.io
2026-02-02
95.216.10.123
z2s.app.master.staging.lobsterlab.io
2026-02-02
95.216.10.123
api.budget.staging.lobsterlab.io
2026-02-02
95.216.10.123
www.dev.api.budget.staging.lobsterlab.io
2026-02-02
95.216.10.123
dev.staging.lobsterlab.io
2026-02-02
95.216.10.123
kiosk.dev.staging.lobsterlab.io
2026-02-02
95.216.10.123
captain.dev.staging.lobsterlab.io
2026-02-02
95.216.10.123
z2s.app.dev.staging.lobsterlab.io
2026-02-02
95.216.10.123
sakura-chat.server.dev.staging.lobsterlab.io
2026-02-02
95.216.10.123
View on OTX
|
View on ThreatMiner
Please enable JavaScript to view the
comments powered by Disqus.
Data with thanks to
AlienVault OTX
,
VirusTotal
,
Malwr
and
others
. [
Sitemap
]