web-sdk-wrapper 2.0.0
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/web-sdk-wrapper.js +687 -0
- package/dist/web-sdk-wrapper.umd.cjs +7 -0
- package/package.json +37 -0
- package/src/event-emitter.js +33 -0
- package/src/index.js +215 -0
- package/src/networks/base.js +224 -0
- package/src/networks/cool-math-games.js +52 -0
- package/src/networks/crazy-games.js +74 -0
- package/src/networks/freeze-nova.js +175 -0
- package/src/networks/hooda-math.js +6 -0
- package/src/networks/index.js +27 -0
- package/src/networks/poki.js +109 -0
- package/src/networks/xiaomi.js +126 -0
- package/src/script-loader.js +23 -0
- package/src/utils.js +27 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
(function(o,r){typeof exports=="object"&&typeof module<"u"?r(exports):typeof define=="function"&&define.amd?define(["exports"],r):(o=typeof globalThis<"u"?globalThis:o||self,r(o.WebSdkWrapper={}))})(this,(function(o){"use strict";var x=Object.defineProperty;var I=(o,r,c)=>r in o?x(o,r,{enumerable:!0,configurable:!0,writable:!0,value:c}):o[r]=c;var t=(o,r,c)=>I(o,typeof r!="symbol"?r+"":r,c);class r{constructor(){t(this,"name","Unknown");t(this,"capabilities",{ads:!1,interstitialAds:!1,rewardedAds:!1,bannerAds:!1,accounts:!1,tokens:!1});t(this,"scriptSources",[]);t(this,"requiresProduction",!1);t(this,"_sdk",null);t(this,"_gameplayStarted",!1)}async preInit(e){}async init(e){}onLoadingStart(){}onLoadingEnd(){}maybeGameplayStart(){this._gameplayStarted||(this._gameplayStarted=!0,this.onGameplayStart())}maybeGameplayStop(){this._gameplayStarted&&(this._gameplayStarted=!1,this.onGameplayStop())}onGameplayStart(){}onGameplayStop(){}onLevelStart(e){}onReplayLevel(e){}async showInterstitial(){return!1}async showRewarded(e){return!0}login(){return Promise.reject(new Error("Accounts not supported"))}getUser(){return Promise.resolve(null)}getToken(){return Promise.resolve(null)}trackEvent(e,a,n){}openExternalLink(e){window.open(e,"_blank")}}class c extends r{constructor(){super(...arguments);t(this,"name","Poki");t(this,"capabilities",{ads:!0,interstitialAds:!0,rewardedAds:!0,bannerAds:!1,accounts:!0,tokens:!0});t(this,"scriptSources",["https://game-cdn.poki.com/scripts/v2/poki-sdk.js"]);t(this,"requiresProduction",!1);t(this,"_lastBeaconTime",0);t(this,"_maxBeacons",6);t(this,"_beaconInterval",60);t(this,"_gameId",null);t(this,"_doBeacon",!1)}_beacon(a){if(!this._gameId||!this._doBeacon)return;const n=Date.now();n-this._lastBeaconTime<this._beaconInterval*1e3||this._maxBeacons<=0||(this._lastBeaconTime=n,this._maxBeacons--,navigator.sendBeacon(`https://leveldata.poki.io/${a}`,this._gameId))}async init(a){this._sdk=globalThis.PokiSDK,this._sdk.setDebug(a.debug),await this._sdk.init().catch(()=>{});const n=a.data||{};this._gameId=n.poki_gameId,this._doBeacon=n.poki_doBeacon,this._maxBeacons=n.poki_maxBeacons||6,this._beaconInterval=n.poki_beaconInterval||60}onLoadingStart(){this._sdk.gameLoadingStart()}onLoadingEnd(){this._sdk.gameLoadingFinished(),this._beacon("loadingEnd")}onGameplayStart(){this._beacon("gameplayStart"),this._sdk.gameplayStart()}onGameplayStop(){this._beacon("gameplayStop"),this._sdk.gameplayStop()}async showInterstitial(){return this._beacon("interstitial"),await this._sdk.commercialBreak(),!0}async showRewarded(a="small"){return this._beacon("rewarded"),await this._sdk.rewardedBreak({size:a})}login(){return this._sdk.login()}getUser(){return this._sdk.getUser()}getToken(){return this._sdk.getToken()}trackEvent(a,n,i){this._beacon(`${a}_${n}`),this._sdk.measure(a,n,i)}openExternalLink(a){this._sdk&&this._sdk.openExternalLink?this._sdk.openExternalLink(a):super.openExternalLink(a)}}class _ extends r{constructor(){super(...arguments);t(this,"name","CrazyGames");t(this,"capabilities",{ads:!0,interstitialAds:!0,rewardedAds:!0,bannerAds:!0,accounts:!1,tokens:!1});t(this,"scriptSources",["https://sdk.crazygames.com/crazygames-sdk-v1.js"]);t(this,"requiresProduction",!1);t(this,"_lastRequestedAd",null);t(this,"_adResolve",null)}async init(a){var n,i;this._sdk=(i=(n=globalThis==null?void 0:globalThis.CrazyGames)==null?void 0:n.CrazySDK)==null?void 0:i.getInstance(),await new Promise(d=>{this._sdk.addEventListener("adblockDetectionExecuted",()=>{d()}),this._sdk.init()}),this._sdk.addEventListener("adFinished",()=>{this._adResolve&&(this._adResolve(!0),this._adResolve=null)}),this._sdk.addEventListener("adError",()=>{this._adResolve&&(this._adResolve(!1),this._adResolve=null)})}onGameplayStart(){this._sdk.gameplayStart()}onGameplayStop(){this._sdk.gameplayStop()}async showInterstitial(){return new Promise(a=>{this._adResolve=a,this._lastRequestedAd="interstitial",this._sdk.requestAd("midgame")})}async showRewarded(){return new Promise(a=>{this._adResolve=a,this._lastRequestedAd="rewarded",this._sdk.requestAd("rewarded")})}}class g extends r{constructor(){super(...arguments);t(this,"name","CoolMathGames");t(this,"capabilities",{ads:!0,interstitialAds:!0,rewardedAds:!1,bannerAds:!1,accounts:!1,tokens:!1});t(this,"scriptSources",["https://www.coolmathgames.com/sites/default/files/cmg-ads.js"]);t(this,"requiresProduction",!0);t(this,"_adResolve",null)}async init(a){document.addEventListener("adBreakComplete",()=>{this._adResolve&&(this._adResolve(!0),this._adResolve=null)})}onGameplayStart(){parent.cmgGameEvent("start")}onLevelStart(a){parent.cmgGameEvent("start",a.toString())}onReplayLevel(a){parent.cmgGameEvent("replay",a.toString())}async showInterstitial(){return new Promise(a=>{this._adResolve=a,window.cmgAdBreak()})}}class y extends r{constructor(){super(...arguments);t(this,"name","HoodaMath")}}class k extends r{constructor(){super(...arguments);t(this,"name","FreezeNova");t(this,"capabilities",{ads:!0,interstitialAds:!0,rewardedAds:!0,bannerAds:!1,accounts:!1,tokens:!1});t(this,"scriptSources",['https://universal.wgplayer.com/tag/?lh="+window.location.hostname+"&wp="+window.location.pathname+"&ws="+window.location.search']);t(this,"requiresProduction",!0);t(this,"_adResolve",null)}async init(a){const n=a.data||{};window.SubmitLeaderboardScore=function(d){},window.InitExternEval=function(){window.firstInit==null?window.firstInit=1:window.ExternEval()},window.TakeReward=function(){window.adReward=0},window.RewardErrorHandled=function(){window.rewardError=0},window.InitApi=function(d){const l=Math.round(Date.now()/1e3);window.callTime=l-181},window.ExternEval=function(){const d=Math.round(Date.now()/1e3);if(window.callTime!=null&&d-window.callTime>180&&(window.callTime=d,typeof preroll<"u"&&window[preroll.config.loaderObjectName]!=null)){window.adRunning=1;try{window[preroll.config.loaderObjectName].refetchAd(window.ExternEvalResumeGame)}catch(l){console.log(l.message),window.ExternEvalResumeGame()}}},window.ExternEvalResumeGame=function(){window.adRunning=0},window.PreloadRewarded=function(){if(window.rewardedCallbacks==null){window.rewardedCallbacks=!0;try{window[window.preroll.config.loaderObjectName].registerRewardCallbacks({onReady:window.RewardedReady,onSuccess:window.RewardedSuccess,onFail:window.RewardedFail})}catch(d){console.log(d.message)}}},window.ShowRewarded=function(){if(typeof preroll<"u"&&window[preroll.config.loaderObjectName]!=null){window.canReward=0,window.adRunning=1;try{window[preroll.config.loaderObjectName].showRewardAd()}catch(d){console.log(d.message),window.adRunning=0}}},window.RewardedReady=function(){window.rewardedCount==null?(window.rewardedCount=1,window.canReward=1):(window.rewardedCount=window.rewardedCount+1,setTimeout(function(){window.canReward=1},3e4))};const i=this;window.RewardedSuccess=function(){window.adRunning=0,window.adReward=1,i._adResolve&&(i._adResolve(!0),i._adResolve=null)},window.RewardedFail=function(){window.adRunning=0,i._adResolve&&(i._adResolve(!1),i._adResolve=null)},window.OpenLink=function(){},window.adRunning=0,window.adRunningRewarded=0,window.adReward=0,window.rewardError=0,window.canReward=0,window.callTime=0,window.adPlatform=4,window.myLeaderboardScore=0,window.gameLang="en",window.InitApi(n.freezeNova_id||0)}async showInterstitial(){return new Promise(a=>{this._adResolve=a,window.PreloadRewarded(),window.ShowRewarded()})}async showRewarded(){return new Promise(a=>{this._adResolve=a,window.PreloadRewarded(),window.ShowRewarded()})}}class b extends r{constructor(){super(...arguments);t(this,"name","Xiaomi");t(this,"capabilities",{ads:!0,interstitialAds:!0,rewardedAds:!0,bannerAds:!1,accounts:!1,tokens:!1});t(this,"scriptSources",[]);t(this,"requiresProduction",!0);t(this,"_adBreak",null)}async preInit(a){const n=a.data||{},i=document.createElement("script");i.async=!0,i.setAttribute("data-ad-frequency-hint","30s"),i.src=`https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-${n.xiaomi_publisherId}`,i.setAttribute("crossorigin","anonymous"),a.debug&&i.setAttribute("data-adbreak-test","on"),window.adsbygoogle=window.adsbygoogle||[],window.adConfig=function(d){adsbygoogle.push(d)},window.adBreak=window.adConfig,this._adBreak=window.adBreak,document.body.appendChild(i),await new Promise(d=>{i.onload=()=>{if(n.xiaomi_bannerEnabled){const l=document.createElement("ins");l.className="adsbygoogle",l.style.display="block",l.setAttribute("data-ad-client",`ca-${n.xiaomi_publisherId}`),l.setAttribute("data-ad-slot",n.xiaomi_dataAdSlot),l.setAttribute("data-ad-format","auto"),l.setAttribute("data-full-width-responsive","true");const u=n.xiaomi_bannerConainerId||"adSpace";let p=document.getElementById(u);p||(p=document.createElement("div"),p.id=u,document.body.appendChild(p)),p.appendChild(l),(adsbygoogle=window.adsbygoogle||[]).push({})}d()}})}onLoadingStart(){try{funmax&&funmax.loadStart()}catch{console.error("funmax not found")}}onLoadingEnd(){try{funmax&&funmax.loadReady()}catch{console.error("funmax not found")}}async showInterstitial(){return new Promise(a=>{this._adBreak({type:"next",name:"interstitial",beforeAd:()=>{},adBreakDone:()=>{a(!0)}})})}async showRewarded(){return new Promise(a=>{let n=!1;this._adBreak({type:"reward",name:"rewarded",beforeAd:()=>{},adBreakDone:()=>{a(n)},beforeReward:i=>{i()},adDismissed:()=>{n=!1},adViewed:()=>{n=!0}})})}}const m={Poki:c,CrazyGames:_,CoolMathGames:g,HoodaMath:y,FreezeNova:k,Xiaomi:b},S=Object.keys(m),f=new Map;function v(s){if(f.has(s))return f.get(s);const e=new Promise((a,n)=>{const i=document.createElement("script");i.src=s,i.onload=()=>a(),i.onerror=()=>n(new Error(`Failed to load script: ${s}`)),document.head.appendChild(i)});return f.set(s,e),e}const w={};function R(s,e,{once:a=!1}={}){w[s]=w[s]||[],w[s].push({fn:e,once:a})}function h(s,...e){(w[s]||[]).forEach(a=>{a.fn(...e)}),w[s]=(w[s]||[]).filter(a=>!a.once)}function A(){const s=document.createElement("style");s.innerHTML=`
|
|
2
|
+
canvas {
|
|
3
|
+
user-select: none !important;
|
|
4
|
+
-webkit-user-select: none !important;
|
|
5
|
+
-moz-user-select: none !important;
|
|
6
|
+
-ms-user-select: none !important;
|
|
7
|
+
}`,document.head.appendChild(s),window.addEventListener("keydown",e=>{["ArrowDown","ArrowUp"," "].includes(e.key)&&e.preventDefault()}),window.addEventListener("wheel",e=>e.preventDefault(),{passive:!1})}class E{constructor(){t(this,"_adapter",null);t(this,"_enabled",!1)}get enabled(){return this._enabled}get currentSdk(){return this._adapter}async init(e,a=!1,n={}){const i=Object.keys(m).find(u=>u.toLowerCase()===e.toLowerCase()),d=i?m[i]:null;if(!d||(this._adapter=new d,this._adapter.requiresProduction&&a))return;this._enabled=!0;const l={debug:a,data:n};await this._adapter.preInit(l);for(const u of this._adapter.scriptSources)await v(u);await this._adapter.init(l),this.loadingStart()}loadingStart(){this._adapter&&this._adapter.onLoadingStart()}loadingEnd(){this._adapter&&this._adapter.onLoadingEnd()}gameplayStart(){this._adapter&&this._adapter.maybeGameplayStart()}gameplayStop(){this._adapter&&this._adapter.maybeGameplayStop()}levelStart(e){this._adapter&&this._adapter.onLevelStart(e)}replayLevel(e){this._adapter&&this._adapter.onReplayLevel(e)}onUnlockAllLevels(e){window.unlockAllLevels=e}async interstitial(){var n;if(!((n=this._adapter)!=null&&n.capabilities.interstitialAds))return h("adStarted","interstitial"),!1;const e=this._adapter._gameplayStarted;e&&this.gameplayStop(),h("adStarted","interstitial");const a=await this._adapter.showInterstitial();return e&&this.gameplayStart(),a}async rewarded(e){var i;if(!((i=this._adapter)!=null&&i.capabilities.rewardedAds))return h("adStarted","rewarded"),!0;const a=this._adapter._gameplayStarted;a&&this.gameplayStop(),h("adStarted","rewarded");const n=await this._adapter.showRewarded(e);return a&&this.gameplayStart(),n}onAdStarted(e){R("adStarted",e)}hasAds(){var e;return(e=this._adapter)!=null&&e.capabilities.ads?1:0}hasInterstitialAds(){var e;return(e=this._adapter)!=null&&e.capabilities.interstitialAds?1:0}hasRewardedAds(){var e;return(e=this._adapter)!=null&&e.capabilities.rewardedAds?1:0}analyticsEvent({category:e,action:a,label:n}){this._adapter&&this._adapter.trackEvent(e,a,n)}login(){var e;return(e=this._adapter)!=null&&e.capabilities.accounts?this._adapter.login():Promise.reject(new Error("Accounts not supported"))}getUser(){var e;return(e=this._adapter)!=null&&e.capabilities.accounts?this._adapter.getUser():Promise.resolve(null)}getToken(){var e;return(e=this._adapter)!=null&&e.capabilities.tokens?this._adapter.getToken():Promise.resolve(null)}hasAccounts(){var e;return(e=this._adapter)!=null&&e.capabilities.accounts?1:0}hasToken(){var e;return(e=this._adapter)!=null&&e.capabilities.tokens?1:0}openExternalLink(e){if(!this._adapter||!this._enabled){window.open(e,"_blank");return}this._adapter.openExternalLink(e)}}const L=new E;o.NetworkAdapter=r,o.default=L,o.networks=S,o.preventWeirdInputs=A,Object.defineProperties(o,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "web-sdk-wrapper",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Unified wrapper for web game distribution platform SDKs (Poki, CrazyGames, CoolMathGames, and more)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/web-sdk-wrapper.umd.cjs",
|
|
7
|
+
"module": "./dist/web-sdk-wrapper.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/web-sdk-wrapper.js",
|
|
11
|
+
"require": "./dist/web-sdk-wrapper.umd.cjs"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "vite build",
|
|
20
|
+
"dev": "vite",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"sdk",
|
|
25
|
+
"wrapper",
|
|
26
|
+
"poki",
|
|
27
|
+
"crazygames",
|
|
28
|
+
"coolmathgames",
|
|
29
|
+
"web-games",
|
|
30
|
+
"ads",
|
|
31
|
+
"game-sdk"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"vite": "^6.3.2"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const events = {};
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Subscribe to an event.
|
|
5
|
+
* @param {string} event
|
|
6
|
+
* @param {Function} fn
|
|
7
|
+
* @param {{ once?: boolean }} [options]
|
|
8
|
+
*/
|
|
9
|
+
export function listen(event, fn, { once = false } = {}) {
|
|
10
|
+
events[event] = events[event] || [];
|
|
11
|
+
events[event].push({ fn, once });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Subscribe to an event for a single dispatch.
|
|
16
|
+
* @param {string} event
|
|
17
|
+
* @param {Function} fn
|
|
18
|
+
*/
|
|
19
|
+
export function listenOnce(event, fn) {
|
|
20
|
+
listen(event, fn, { once: true });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Dispatch an event to all listeners.
|
|
25
|
+
* @param {string} event
|
|
26
|
+
* @param {...any} data
|
|
27
|
+
*/
|
|
28
|
+
export function dispatch(event, ...data) {
|
|
29
|
+
(events[event] || []).forEach((fnObj) => {
|
|
30
|
+
fnObj.fn(...data);
|
|
31
|
+
});
|
|
32
|
+
events[event] = (events[event] || []).filter((fnObj) => !fnObj.once);
|
|
33
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import registry from "./networks/index.js";
|
|
2
|
+
import { loadScript } from "./script-loader.js";
|
|
3
|
+
import { listen, listenOnce, dispatch } from "./event-emitter.js";
|
|
4
|
+
|
|
5
|
+
export { preventWeirdInputs } from "./utils.js";
|
|
6
|
+
export { NetworkAdapter } from "./networks/base.js";
|
|
7
|
+
export { networks } from "./networks/index.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @class Wrapper
|
|
11
|
+
*
|
|
12
|
+
* Unified facade over multiple web game distribution platform SDKs.
|
|
13
|
+
* Delegates all behavior to the currently active network adapter.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* import Wrapper from "web-sdk-wrapper";
|
|
17
|
+
* await Wrapper.init("Poki", false, { poki_gameId: "abc" });
|
|
18
|
+
* Wrapper.loadingEnd();
|
|
19
|
+
* const rewarded = await Wrapper.rewarded();
|
|
20
|
+
*/
|
|
21
|
+
class Wrapper {
|
|
22
|
+
/** @type {import('./networks/base.js').NetworkAdapter|null} */
|
|
23
|
+
_adapter = null;
|
|
24
|
+
|
|
25
|
+
/** @type {boolean} */
|
|
26
|
+
_enabled = false;
|
|
27
|
+
|
|
28
|
+
get enabled() {
|
|
29
|
+
return this._enabled;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get currentSdk() {
|
|
33
|
+
return this._adapter;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Initialize the wrapper with a specific network.
|
|
38
|
+
* @param {string} name - Network name (case-insensitive)
|
|
39
|
+
* @param {boolean} [debug=false]
|
|
40
|
+
* @param {Object} [data={}] - Network-specific configuration
|
|
41
|
+
* @returns {Promise<void>}
|
|
42
|
+
*/
|
|
43
|
+
async init(name, debug = false, data = {}) {
|
|
44
|
+
const key = Object.keys(registry).find(
|
|
45
|
+
(k) => k.toLowerCase() === name.toLowerCase(),
|
|
46
|
+
);
|
|
47
|
+
const AdapterClass = key ? registry[key] : null;
|
|
48
|
+
if (!AdapterClass) return;
|
|
49
|
+
|
|
50
|
+
this._adapter = new AdapterClass();
|
|
51
|
+
|
|
52
|
+
if (this._adapter.requiresProduction && debug) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this._enabled = true;
|
|
57
|
+
const options = { debug, data };
|
|
58
|
+
|
|
59
|
+
// preInit (before scripts load)
|
|
60
|
+
await this._adapter.preInit(options);
|
|
61
|
+
|
|
62
|
+
// Load SDK scripts
|
|
63
|
+
for (const src of this._adapter.scriptSources) {
|
|
64
|
+
await loadScript(src);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Init adapter (after scripts are loaded)
|
|
68
|
+
await this._adapter.init(options);
|
|
69
|
+
|
|
70
|
+
// Signal loading started
|
|
71
|
+
this.loadingStart();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
loadingStart() {
|
|
75
|
+
if (this._adapter) this._adapter.onLoadingStart();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
loadingEnd() {
|
|
79
|
+
if (this._adapter) this._adapter.onLoadingEnd();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
gameplayStart() {
|
|
83
|
+
if (this._adapter) this._adapter.maybeGameplayStart();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
gameplayStop() {
|
|
87
|
+
if (this._adapter) this._adapter.maybeGameplayStop();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
levelStart(level) {
|
|
91
|
+
if (this._adapter) this._adapter.onLevelStart(level);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
replayLevel(level) {
|
|
95
|
+
if (this._adapter) this._adapter.onReplayLevel(level);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
onUnlockAllLevels(fn) {
|
|
99
|
+
window.unlockAllLevels = fn;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Show an interstitial ad. Auto-pauses/resumes gameplay.
|
|
104
|
+
* @returns {Promise<boolean>}
|
|
105
|
+
*/
|
|
106
|
+
async interstitial() {
|
|
107
|
+
if (!this._adapter?.capabilities.interstitialAds) {
|
|
108
|
+
dispatch("adStarted", "interstitial");
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const wasPlaying = this._adapter._gameplayStarted;
|
|
113
|
+
if (wasPlaying) this.gameplayStop();
|
|
114
|
+
|
|
115
|
+
dispatch("adStarted", "interstitial");
|
|
116
|
+
const success = await this._adapter.showInterstitial();
|
|
117
|
+
|
|
118
|
+
if (wasPlaying) this.gameplayStart();
|
|
119
|
+
return success;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Show a rewarded ad. Auto-pauses/resumes gameplay.
|
|
124
|
+
* @param {string} [size]
|
|
125
|
+
* @returns {Promise<boolean>}
|
|
126
|
+
*/
|
|
127
|
+
async rewarded(size) {
|
|
128
|
+
if (!this._adapter?.capabilities.rewardedAds) {
|
|
129
|
+
dispatch("adStarted", "rewarded");
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const wasPlaying = this._adapter._gameplayStarted;
|
|
134
|
+
if (wasPlaying) this.gameplayStop();
|
|
135
|
+
|
|
136
|
+
dispatch("adStarted", "rewarded");
|
|
137
|
+
const success = await this._adapter.showRewarded(size);
|
|
138
|
+
|
|
139
|
+
if (wasPlaying) this.gameplayStart();
|
|
140
|
+
return success;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Register a callback for when an ad starts.
|
|
145
|
+
* @param {function} fn
|
|
146
|
+
*/
|
|
147
|
+
onAdStarted(fn) {
|
|
148
|
+
listen("adStarted", fn);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** @returns {number} 1 if ads supported, 0 otherwise */
|
|
152
|
+
hasAds() {
|
|
153
|
+
return this._adapter?.capabilities.ads ? 1 : 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** @returns {number} 1 if interstitial ads supported, 0 otherwise */
|
|
157
|
+
hasInterstitialAds() {
|
|
158
|
+
return this._adapter?.capabilities.interstitialAds ? 1 : 0;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** @returns {number} 1 if rewarded ads supported, 0 otherwise */
|
|
162
|
+
hasRewardedAds() {
|
|
163
|
+
return this._adapter?.capabilities.rewardedAds ? 1 : 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Track an analytics event.
|
|
168
|
+
* @param {{ category: string, action: string, label?: string }} event
|
|
169
|
+
*/
|
|
170
|
+
analyticsEvent({ category, action, label }) {
|
|
171
|
+
if (this._adapter) this._adapter.trackEvent(category, action, label);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
login() {
|
|
175
|
+
if (!this._adapter?.capabilities.accounts) {
|
|
176
|
+
return Promise.reject(new Error("Accounts not supported"));
|
|
177
|
+
}
|
|
178
|
+
return this._adapter.login();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
getUser() {
|
|
182
|
+
if (!this._adapter?.capabilities.accounts) {
|
|
183
|
+
return Promise.resolve(null);
|
|
184
|
+
}
|
|
185
|
+
return this._adapter.getUser();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
getToken() {
|
|
189
|
+
if (!this._adapter?.capabilities.tokens) {
|
|
190
|
+
return Promise.resolve(null);
|
|
191
|
+
}
|
|
192
|
+
return this._adapter.getToken();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** @returns {number} 1 if accounts supported, 0 otherwise */
|
|
196
|
+
hasAccounts() {
|
|
197
|
+
return this._adapter?.capabilities.accounts ? 1 : 0;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** @returns {number} 1 if tokens supported, 0 otherwise */
|
|
201
|
+
hasToken() {
|
|
202
|
+
return this._adapter?.capabilities.tokens ? 1 : 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
openExternalLink(url) {
|
|
206
|
+
if (!this._adapter || !this._enabled) {
|
|
207
|
+
window.open(url, "_blank");
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
this._adapter.openExternalLink(url);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Export a singleton instance to match V1 API (import Wrapper from "...")
|
|
215
|
+
export default new Wrapper();
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @class NetworkAdapter
|
|
3
|
+
*
|
|
4
|
+
* Base class for all network adapters. Subclass this and override
|
|
5
|
+
* only the methods your network needs. Everything has a sensible default.
|
|
6
|
+
*
|
|
7
|
+
* ===== Properties to override =====
|
|
8
|
+
*
|
|
9
|
+
* @property {string} name - Network display name (e.g. "Poki")
|
|
10
|
+
*
|
|
11
|
+
* @property {{
|
|
12
|
+
* ads: boolean,
|
|
13
|
+
* interstitialAds: boolean,
|
|
14
|
+
* rewardedAds: boolean,
|
|
15
|
+
* bannerAds: boolean,
|
|
16
|
+
* accounts: boolean,
|
|
17
|
+
* tokens: boolean
|
|
18
|
+
* }} capabilities - What this network supports
|
|
19
|
+
*
|
|
20
|
+
* @property {string[]} scriptSources - SDK script URLs to load before init
|
|
21
|
+
*
|
|
22
|
+
* @property {boolean} requiresProduction - If true, adapter is disabled in debug mode
|
|
23
|
+
*
|
|
24
|
+
* ===== Lifecycle methods to override =====
|
|
25
|
+
*
|
|
26
|
+
* @method preInit - Called before scripts are loaded. Use for early setup.
|
|
27
|
+
* @method init - Called after scripts are loaded. Set up your SDK here.
|
|
28
|
+
* @method onLoadingStart - Game loading started
|
|
29
|
+
* @method onLoadingEnd - Game loading finished
|
|
30
|
+
* @method onGameplayStart - Gameplay session started (has built-in duplicate guard)
|
|
31
|
+
* @method onGameplayStop - Gameplay session stopped (has built-in duplicate guard)
|
|
32
|
+
* @method onLevelStart - Level started (receives level identifier)
|
|
33
|
+
* @method onReplayLevel - Level replayed (receives level identifier)
|
|
34
|
+
*
|
|
35
|
+
* ===== Ad methods to override =====
|
|
36
|
+
*
|
|
37
|
+
* @method showInterstitial - Show an interstitial ad. Return true if shown.
|
|
38
|
+
* @method showRewarded - Show a rewarded ad. Return true if reward was earned.
|
|
39
|
+
*
|
|
40
|
+
* ===== Account methods to override =====
|
|
41
|
+
*
|
|
42
|
+
* @method login - Log in via the platform
|
|
43
|
+
* @method getUser - Get the current user
|
|
44
|
+
* @method getToken - Get an auth token
|
|
45
|
+
*
|
|
46
|
+
* ===== Misc methods to override =====
|
|
47
|
+
*
|
|
48
|
+
* @method trackEvent - Track an analytics event
|
|
49
|
+
* @method openExternalLink - Open a URL (default: window.open)
|
|
50
|
+
*/
|
|
51
|
+
export class NetworkAdapter {
|
|
52
|
+
/** @type {string} */
|
|
53
|
+
name = "Unknown";
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @type {{
|
|
57
|
+
* ads: boolean,
|
|
58
|
+
* interstitialAds: boolean,
|
|
59
|
+
* rewardedAds: boolean,
|
|
60
|
+
* bannerAds: boolean,
|
|
61
|
+
* accounts: boolean,
|
|
62
|
+
* tokens: boolean
|
|
63
|
+
* }}
|
|
64
|
+
*/
|
|
65
|
+
capabilities = {
|
|
66
|
+
ads: false,
|
|
67
|
+
interstitialAds: false,
|
|
68
|
+
rewardedAds: false,
|
|
69
|
+
bannerAds: false,
|
|
70
|
+
accounts: false,
|
|
71
|
+
tokens: false,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** @type {string[]} SDK script URLs to load before init */
|
|
75
|
+
scriptSources = [];
|
|
76
|
+
|
|
77
|
+
/** @type {boolean} If true, adapter is disabled when debug=true */
|
|
78
|
+
requiresProduction = false;
|
|
79
|
+
|
|
80
|
+
/** @type {any} Reference to the loaded SDK object. Set in init(). */
|
|
81
|
+
_sdk = null;
|
|
82
|
+
|
|
83
|
+
/** @type {boolean} Whether a gameplay session is active */
|
|
84
|
+
_gameplayStarted = false;
|
|
85
|
+
|
|
86
|
+
// ========================
|
|
87
|
+
// Lifecycle
|
|
88
|
+
// ========================
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Called before scripts are loaded. Use for early DOM setup or config.
|
|
92
|
+
* @param {{ debug: boolean, data: Object }} options
|
|
93
|
+
* @returns {Promise<void>}
|
|
94
|
+
*/
|
|
95
|
+
async preInit(options) {}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Called after scripts are loaded. Initialize the SDK here.
|
|
99
|
+
* @param {{ debug: boolean, data: Object }} options
|
|
100
|
+
* @returns {Promise<void>}
|
|
101
|
+
*/
|
|
102
|
+
async init(options) {}
|
|
103
|
+
|
|
104
|
+
/** Called when the game starts loading. */
|
|
105
|
+
onLoadingStart() {}
|
|
106
|
+
|
|
107
|
+
/** Called when the game finishes loading. */
|
|
108
|
+
onLoadingEnd() {}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Handles duplicate-call gating for gameplay start.
|
|
112
|
+
* Do NOT override this — override onGameplayStart() instead.
|
|
113
|
+
*/
|
|
114
|
+
maybeGameplayStart() {
|
|
115
|
+
if (this._gameplayStarted) return;
|
|
116
|
+
this._gameplayStarted = true;
|
|
117
|
+
this.onGameplayStart();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Handles duplicate-call gating for gameplay stop.
|
|
122
|
+
* Do NOT override this — override onGameplayStop() instead.
|
|
123
|
+
*/
|
|
124
|
+
maybeGameplayStop() {
|
|
125
|
+
if (!this._gameplayStarted) return;
|
|
126
|
+
this._gameplayStarted = false;
|
|
127
|
+
this.onGameplayStop();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Called when a gameplay session starts.
|
|
132
|
+
* Only called if not already in a gameplay session (gated by maybeGameplayStart).
|
|
133
|
+
* Override this freely — no need to call super.
|
|
134
|
+
*/
|
|
135
|
+
onGameplayStart() {}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Called when a gameplay session stops.
|
|
139
|
+
* Only called if currently in a gameplay session (gated by maybeGameplayStop).
|
|
140
|
+
* Override this freely — no need to call super.
|
|
141
|
+
*/
|
|
142
|
+
onGameplayStop() {}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Called when a level starts.
|
|
146
|
+
* @param {string|number} level
|
|
147
|
+
*/
|
|
148
|
+
onLevelStart(level) {}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Called when a level is replayed.
|
|
152
|
+
* @param {string|number} level
|
|
153
|
+
*/
|
|
154
|
+
onReplayLevel(level) {}
|
|
155
|
+
|
|
156
|
+
// ========================
|
|
157
|
+
// Ads
|
|
158
|
+
// ========================
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Show an interstitial ad.
|
|
162
|
+
* @returns {Promise<boolean>} Whether the ad was shown successfully
|
|
163
|
+
*/
|
|
164
|
+
async showInterstitial() {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Show a rewarded ad.
|
|
170
|
+
* @param {string} [size] - Ad size hint (e.g. "small", "medium")
|
|
171
|
+
* @returns {Promise<boolean>} Whether the reward was earned
|
|
172
|
+
*/
|
|
173
|
+
async showRewarded(size) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ========================
|
|
178
|
+
// Accounts
|
|
179
|
+
// ========================
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Log in via the platform's auth system.
|
|
183
|
+
* @returns {Promise<any>}
|
|
184
|
+
*/
|
|
185
|
+
login() {
|
|
186
|
+
return Promise.reject(new Error("Accounts not supported"));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get the currently logged-in user.
|
|
191
|
+
* @returns {Promise<any>}
|
|
192
|
+
*/
|
|
193
|
+
getUser() {
|
|
194
|
+
return Promise.resolve(null);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Get an auth token for the current user.
|
|
199
|
+
* @returns {Promise<string|null>}
|
|
200
|
+
*/
|
|
201
|
+
getToken() {
|
|
202
|
+
return Promise.resolve(null);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// ========================
|
|
206
|
+
// Misc
|
|
207
|
+
// ========================
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Track an analytics event.
|
|
211
|
+
* @param {string} category
|
|
212
|
+
* @param {string} action
|
|
213
|
+
* @param {string} [label]
|
|
214
|
+
*/
|
|
215
|
+
trackEvent(category, action, label) {}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Open an external link. Default: window.open.
|
|
219
|
+
* @param {string} url
|
|
220
|
+
*/
|
|
221
|
+
openExternalLink(url) {
|
|
222
|
+
window.open(url, "_blank");
|
|
223
|
+
}
|
|
224
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { NetworkAdapter } from "./base.js";
|
|
2
|
+
|
|
3
|
+
export class CoolMathGamesAdapter extends NetworkAdapter {
|
|
4
|
+
name = "CoolMathGames";
|
|
5
|
+
|
|
6
|
+
capabilities = {
|
|
7
|
+
ads: true,
|
|
8
|
+
interstitialAds: true,
|
|
9
|
+
rewardedAds: false,
|
|
10
|
+
bannerAds: false,
|
|
11
|
+
accounts: false,
|
|
12
|
+
tokens: false,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
scriptSources = [
|
|
16
|
+
"https://www.coolmathgames.com/sites/default/files/cmg-ads.js",
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
requiresProduction = true;
|
|
20
|
+
|
|
21
|
+
/** @type {function|null} */
|
|
22
|
+
_adResolve = null;
|
|
23
|
+
|
|
24
|
+
async init(options) {
|
|
25
|
+
// CMG SDK is loaded via script tag and uses document events + parent.cmgGameEvent
|
|
26
|
+
document.addEventListener("adBreakComplete", () => {
|
|
27
|
+
if (this._adResolve) {
|
|
28
|
+
this._adResolve(true);
|
|
29
|
+
this._adResolve = null;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
onGameplayStart() {
|
|
35
|
+
parent.cmgGameEvent("start");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
onLevelStart(level) {
|
|
39
|
+
parent.cmgGameEvent("start", level.toString());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
onReplayLevel(level) {
|
|
43
|
+
parent.cmgGameEvent("replay", level.toString());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async showInterstitial() {
|
|
47
|
+
return new Promise((resolve) => {
|
|
48
|
+
this._adResolve = resolve;
|
|
49
|
+
window.cmgAdBreak();
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { NetworkAdapter } from "./base.js";
|
|
2
|
+
|
|
3
|
+
export class CrazyGamesAdapter extends NetworkAdapter {
|
|
4
|
+
name = "CrazyGames";
|
|
5
|
+
|
|
6
|
+
capabilities = {
|
|
7
|
+
ads: true,
|
|
8
|
+
interstitialAds: true,
|
|
9
|
+
rewardedAds: true,
|
|
10
|
+
bannerAds: true,
|
|
11
|
+
accounts: false,
|
|
12
|
+
tokens: false,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
scriptSources = ["https://sdk.crazygames.com/crazygames-sdk-v1.js"];
|
|
16
|
+
|
|
17
|
+
requiresProduction = false;
|
|
18
|
+
|
|
19
|
+
/** @type {string|null} Tracks which ad type was last requested */
|
|
20
|
+
_lastRequestedAd = null;
|
|
21
|
+
|
|
22
|
+
/** @type {function|null} Resolve function for the current ad promise */
|
|
23
|
+
_adResolve = null;
|
|
24
|
+
|
|
25
|
+
async init(options) {
|
|
26
|
+
this._sdk = globalThis?.CrazyGames?.CrazySDK?.getInstance();
|
|
27
|
+
|
|
28
|
+
await new Promise((resolve) => {
|
|
29
|
+
this._sdk.addEventListener("adblockDetectionExecuted", () => {
|
|
30
|
+
resolve();
|
|
31
|
+
});
|
|
32
|
+
this._sdk.init();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Set up SDK event listeners once
|
|
36
|
+
this._sdk.addEventListener("adFinished", () => {
|
|
37
|
+
if (this._adResolve) {
|
|
38
|
+
this._adResolve(true);
|
|
39
|
+
this._adResolve = null;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
this._sdk.addEventListener("adError", () => {
|
|
44
|
+
if (this._adResolve) {
|
|
45
|
+
this._adResolve(false);
|
|
46
|
+
this._adResolve = null;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
onGameplayStart() {
|
|
52
|
+
this._sdk.gameplayStart();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
onGameplayStop() {
|
|
56
|
+
this._sdk.gameplayStop();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async showInterstitial() {
|
|
60
|
+
return new Promise((resolve) => {
|
|
61
|
+
this._adResolve = resolve;
|
|
62
|
+
this._lastRequestedAd = "interstitial";
|
|
63
|
+
this._sdk.requestAd("midgame");
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async showRewarded() {
|
|
68
|
+
return new Promise((resolve) => {
|
|
69
|
+
this._adResolve = resolve;
|
|
70
|
+
this._lastRequestedAd = "rewarded";
|
|
71
|
+
this._sdk.requestAd("rewarded");
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|