PageSourceSearch

https://pupwife.com/scripts/casino/casinoWallet.js

js pupwife.com collected 2026-09-30 15:05:07 UTC 9,533 bytes, 260 lines download raw bytes

1/**
2 * Firebase casino wallet — balance, daily claim, cross-device via username.
3 */
4(function (global) {
5    'use strict';
6
7    var walletsRef = null;
8    var leaderboardRef = null;
9    var listener = null;
10    var balanceListeners = [];
11    var state = {
12        balance: null,
13        lastDailyClaimUtc: null,
14        ready: false,
15        denied: false
16    };
17
18    function emitBalance() {
19        for (var i = 0; i < balanceListeners.length; i++) {
20            try {
21                balanceListeners[i](state.balance, state);
22            } catch (e) {}
23        }
24    }
25
26    function isPermissionDenied(err) {
27        if (!err) return false;
28        if (err.code === 'PERMISSION_DENIED') return true;
29        return /permission_denied|permission denied/i.test(String(err.message || ''));
30    }
31
32    function initRefs() {
33        if (typeof firebase === 'undefined' || !firebase.database) return false;
34        walletsRef = firebase.database().ref('casinoWallets');
35        leaderboardRef = firebase.database().ref('casinoLeaderboard');
36        return true;
37    }
38
39    function syncLeaderboard(username, name, balance) {
40        if (!leaderboardRef || !username) return;
41        leaderboardRef.child(username).set({
42            name: name,
43            balance: balance,
44            updatedAt: firebase.database.ServerValue.TIMESTAMP
45        }).catch(function (err) {
46            if (isPermissionDenied(err)) state.denied = true;
47        });
48    }
49
50    function defaultWallet(username, name) {
51        return {
52            name: name,
53            balance: global.CasinoCore.STARTING_BALANCE,
54            lastDailyClaimUtc: '',
55            createdAt: firebase.database.ServerValue.TIMESTAMP,
56            updatedAt: firebase.database.ServerValue.TIMESTAMP
57        };
58    }
59
60    function attachListener(username) {
61        if (listener && listener.ref) {
62            listener.ref.off('value', listener.handler);
63        }
64        listener = null;
65        if (!walletsRef || !username) return;
66
67        var ref = walletsRef.child(username);
68        var handler = function (snap) {
69            if (!snap.exists()) {
70                state.balance = global.CasinoCore.STARTING_BALANCE;
71                state.lastDailyClaimUtc = '';
72                state.ready = true;
73                emitBalance();
74                return;
75            }
76            var val = snap.val();
77            state.balance = val.balance || 0;
78            state.lastDailyClaimUtc = val.lastDailyClaimUtc || '';
79            state.ready = true;
80            emitBalance();
81        };
82        ref.on('value', handler, function (err) {
83            if (isPermissionDenied(err)) state.denied = true;
84        });
85        listener = { ref: ref, handler: handler };
86    }
87
88    function ensureWallet(username) {
89        if (!walletsRef || !username) return Promise.resolve(null);
90        var name = global.CasinoCore.sanitizeUsername(username);
91        var ref = walletsRef.child(username);
92        return ref.transaction(function (current) {
93            if (current !== null) return current;
94            return defaultWallet(username, name);
95        }).then(function (result) {
96            if (result.committed && result.snapshot) {
97                var data = result.snapshot.val();
98                syncLeaderboard(username, data.name || name, data.balance || 0);
99            }
100            return result.snapshot ? result.snapshot.val() : null;
101        });
102    }
103
104    function init() {
105        if (!initRefs()) return Promise.resolve();
106        if (!global.CasinoCore.isCasinoLoggedIn()) {
107            state.ready = true;
108            state.balance = null;
109            emitBalance();
110            return Promise.resolve();
111        }
112
113        var username = global.CasinoCore.getUsername();
114        return ensureWallet(username).then(function () {
115            attachListener(username);
116        });
117    }
118
119    function destroy() {
120        if (listener && listener.ref) {
121            listener.ref.off('value', listener.handler);
122        }
123        listener = null;
124        balanceListeners = [];
125        state = { balance: null, lastDailyClaimUtc: null, ready: false, denied: fal
125se };
126    }
127
128    function onBalance(fn) {
129        if (typeof fn === 'function') balanceListeners.push(fn);
130        if (state.ready) fn(state.balance, state);
131    }
132
133    function canClaimDaily() {
134        if (!global.CasinoCore.isCasinoLoggedIn()) return false;
135        var today = global.CasinoCore.utcDateString();
136        return state.lastDailyClaimUtc !== today;
137    }
138
139    function claimDaily() {
140        if (!global.CasinoCore.isCasinoLoggedIn()) {
141            return Promise.resolve({ ok: false, reason: 'not_logged_in' });
142        }
143        if (!canClaimDaily()) {
144            return Promise.resolve({ ok: false, reason: 'already_claimed' });
145        }
146
147        var username = global.CasinoCore.getUsername();
148        var name = global.CasinoCore.sanitizeUsername(username);
149        var today = global.CasinoCore.utcDateString();
150        var ref = walletsRef.child(username);
151
152        return ref.transaction(function (current) {
153            if (current === null) {
154                return {
155                    name: name,
156                    balance: global.CasinoCore.STARTING_BALANCE + global.CasinoCore.DAILY_BONUS,
157                    lastDailyClaimUtc: today,
158                    createdAt: firebase.database.ServerValue.TIMESTAMP,
159                    updatedAt: firebase.database.ServerValue.TIMESTAMP
160                };
161            }
162            if (current.lastDailyClaimUtc === today) return;
163            return {
164                name: current.name || name,
165                balance: (current.balance || 0) + global.CasinoCore.DAILY_BONUS,
166                lastDailyClaimUtc: today,
167                createdAt: current.createdAt || firebase.database.ServerValue.TIMESTAMP,
168                updatedAt: firebase.database.ServerValue.TIMESTAMP
169            };
170        }).then(function (result) {
171            if (!result.committed) {
172                return { ok: false, reason: 'already_claimed' };
173            }
174            var data = result.snapshot.val();
175            syncLeaderboard(username, data.name || name, data.balance || 0);
176            return { ok: true, balance: data.balance };
177        }).catch(function (err) {
178            if (isPermissionDenied(err)) state.denied = true;
179            return { ok: false, reason: 'error' };
180        });
181    }
182
183    function applyDelta(delta, meta) {
184        if (!global.CasinoCore.isCasinoLoggedIn()) {
185            return Promise.resolve({ ok: false, reason: 'not_logged_in' });
186        }
187        if (!Number.isFinite(delta) || delta === 0) {
188            return Promise.resolve({ ok: false, reason: 'invalid_delta' });
189        }
190
191        var username = global.CasinoCore.getUsername();
192        var name = global.CasinoCore.sanitizeUsername(username);
193        var ref = walletsRef.child(username);
194
195        return ref.transaction(function (current) {
196            if (current === null) {
197                if (delta < 0) return;
198                var start = global.CasinoCore.STARTING_BALANCE + delta;
199                if (start < 0) return;
200                return {
201                    name: name,
202                    balance: start,
203                    lastDailyClaimUtc: '',
204                    createdAt: firebase.database.ServerValue.TIMESTAMP,
205                    updatedAt: firebase.database.ServerValue.TIMESTAMP
206                };
207            }
208            var next = (current.balance || 0) + delta;
209            if (next < 0) return;
210            return {
211                name: current.name || name,
212                balance: next,
213                lastDailyClaimUtc: current.lastDailyClaimUtc || '',
214                createdAt: current.createdAt || firebase.database.ServerValue.TIMESTAMP,
215                updatedAt: firebase.database.ServerValue.TIMESTAMP
216            };
217        }).then(function (result) {
218            if (!result.committed) {
219                return { ok: false, reason: delta < 0 ? 'insufficient' : 'failed' };
220            }
221            var data = result.snapshot.val();
222            syncLeaderboard(username, data.name || name, data.balance || 0);
223            void meta;
224            return { ok: true, balance: data.balance, delta: delta };
225        }).catch(function (err) {
226            if (isPermissionDenied(err)) state.denied = true;
227            return { ok: false, reason: 'error' };
228        });
229    }
230
231    function placeBet(amount) {
232        var bet = Math.floor(Number(amount) || 0);
233        if (bet <= 0) return Promise.resolve({ ok: false, reason: 'invali
233d_bet' });
234        if (state.balance !== null && bet > state.balance) {
235            return Promise.resolve({ ok: false, reason: 'insufficient' });
236        }
237        return applyDelta(-bet, { type: 'bet', amount: bet }).then(function (res) {
238            if (!res.ok) return res;
239            return { ok: true, bet: bet, balance: res.balance };
240        });
241    }
242
243    function payout(amount, meta) {
244        var win = Math.floor(Number(amount) || 0);
245        if (win <= 0) return Promise.resolve({ ok: false, reason: 'invalid_payout' });
246        return applyDelta(win, meta || { type: 'win' });
247    }
248
249    global.CasinoWallet = {
250        init: init,
251        destroy: destroy,
252        onBalance: onBalance,
253        canClaimDaily: canClaimDaily,
254        claimDaily: claimDaily,
255        placeBet: placeBet,
256        payout: payout,
257        applyDelta: applyDelta,
258        getState: function () { return state; }
259    };
260})(typeof window !== 'undefined' ? window : this);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.