@dimcool/dimclaw 0.1.30 → 0.1.32
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.js +295 -149
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32218,7 +32218,7 @@ var require_money = __commonJS2({
|
|
|
32218
32218
|
"../utils/dist/money.js"(exports) {
|
|
32219
32219
|
"use strict";
|
|
32220
32220
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32221
|
-
exports.SOL_LAMPORTS = exports.MICRO_UNITS = void 0;
|
|
32221
|
+
exports.SOL_MINT = exports.SOL_LAMPORTS = exports.MICRO_UNITS = void 0;
|
|
32222
32222
|
exports.isSolMint = isSolMint;
|
|
32223
32223
|
exports.formatMoneyMinor = formatMoneyMinor2;
|
|
32224
32224
|
exports.toMajor = toMajor2;
|
|
@@ -32231,12 +32231,12 @@ var require_money = __commonJS2({
|
|
|
32231
32231
|
exports.formatMoneyMinorCompact = formatMoneyMinorCompact;
|
|
32232
32232
|
exports.MICRO_UNITS = 1e6;
|
|
32233
32233
|
exports.SOL_LAMPORTS = 1e9;
|
|
32234
|
-
|
|
32234
|
+
exports.SOL_MINT = "SOL";
|
|
32235
32235
|
var SOL_SYSTEM_PROGRAM = "11111111111111111111111111111111";
|
|
32236
32236
|
function isSolMint(mint) {
|
|
32237
32237
|
if (!mint)
|
|
32238
32238
|
return false;
|
|
32239
|
-
return mint ===
|
|
32239
|
+
return mint === exports.SOL_MINT || mint === SOL_SYSTEM_PROGRAM;
|
|
32240
32240
|
}
|
|
32241
32241
|
function formatMoneyMinor2(amountMinor, fractionDigits = 2) {
|
|
32242
32242
|
return (amountMinor / exports.MICRO_UNITS).toFixed(fractionDigits);
|
|
@@ -32340,7 +32340,7 @@ var require_dist = __commonJS2({
|
|
|
32340
32340
|
"../utils/dist/index.js"(exports) {
|
|
32341
32341
|
"use strict";
|
|
32342
32342
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32343
|
-
exports.formatMoneyMinorCompact = exports.formatCurrencyPartsForToken = exports.formatCurrencyParts = exports.kformatMoney = exports.kformat = exports.formatSolMinor = exports.toSolMajor = exports.toMajor = exports.formatMoneyMinor = exports.isSolMint = exports.SOL_LAMPORTS = exports.MICRO_UNITS = void 0;
|
|
32343
|
+
exports.formatMoneyMinorCompact = exports.formatCurrencyPartsForToken = exports.formatCurrencyParts = exports.kformatMoney = exports.kformat = exports.formatSolMinor = exports.toSolMajor = exports.toMajor = exports.formatMoneyMinor = exports.isSolMint = exports.SOL_MINT = exports.SOL_LAMPORTS = exports.MICRO_UNITS = void 0;
|
|
32344
32344
|
var money_1 = require_money();
|
|
32345
32345
|
Object.defineProperty(exports, "MICRO_UNITS", { enumerable: true, get: function() {
|
|
32346
32346
|
return money_1.MICRO_UNITS;
|
|
@@ -32348,6 +32348,9 @@ var require_dist = __commonJS2({
|
|
|
32348
32348
|
Object.defineProperty(exports, "SOL_LAMPORTS", { enumerable: true, get: function() {
|
|
32349
32349
|
return money_1.SOL_LAMPORTS;
|
|
32350
32350
|
} });
|
|
32351
|
+
Object.defineProperty(exports, "SOL_MINT", { enumerable: true, get: function() {
|
|
32352
|
+
return money_1.SOL_MINT;
|
|
32353
|
+
} });
|
|
32351
32354
|
Object.defineProperty(exports, "isSolMint", { enumerable: true, get: function() {
|
|
32352
32355
|
return money_1.isSolMint;
|
|
32353
32356
|
} });
|
|
@@ -32884,6 +32887,9 @@ var Admin = class {
|
|
|
32884
32887
|
this.http = http2;
|
|
32885
32888
|
this.logger = logger2;
|
|
32886
32889
|
}
|
|
32890
|
+
async getInternalBots() {
|
|
32891
|
+
return this.http.get("/admin/internal-bots");
|
|
32892
|
+
}
|
|
32887
32893
|
async getUserById(id) {
|
|
32888
32894
|
return this.http.get(`/admin/users/${id}`);
|
|
32889
32895
|
}
|
|
@@ -33235,6 +33241,13 @@ var Lobbies = class {
|
|
|
33235
33241
|
setLobbyStore(store) {
|
|
33236
33242
|
this.lobbyStore = store;
|
|
33237
33243
|
}
|
|
33244
|
+
/**
|
|
33245
|
+
* Create a new game lobby.
|
|
33246
|
+
*
|
|
33247
|
+
* **Important:** Creating a lobby automatically closes and refunds any
|
|
33248
|
+
* existing open or queued lobby for this user. You do not need to manually
|
|
33249
|
+
* leave or cancel a previous lobby before calling this.
|
|
33250
|
+
*/
|
|
33238
33251
|
async createLobby(gameType, betAmount) {
|
|
33239
33252
|
return this.http.post("/lobbies", { gameType, betAmount });
|
|
33240
33253
|
}
|
|
@@ -33298,21 +33311,6 @@ var Lobbies = class {
|
|
|
33298
33311
|
async deleteLobby(lobbyId) {
|
|
33299
33312
|
return this.http.delete(`/lobbies/admin/${lobbyId}`);
|
|
33300
33313
|
}
|
|
33301
|
-
/**
|
|
33302
|
-
* Play again: Create a new lobby and prepare deposit in one flow.
|
|
33303
|
-
* Returns the lobby and unsigned transaction that needs to be signed.
|
|
33304
|
-
* @param gameType - The game type to play again
|
|
33305
|
-
* @param betAmount - The bet amount (same as previous game)
|
|
33306
|
-
* @param escrow - The escrow service instance (from sdk.escrow)
|
|
33307
|
-
*/
|
|
33308
|
-
async playAgain(gameType, betAmount, escrow) {
|
|
33309
|
-
const lobby = await this.createLobby(gameType, betAmount);
|
|
33310
|
-
const { transaction } = await escrow.prepareAndStartDeposit(lobby.id);
|
|
33311
|
-
return {
|
|
33312
|
-
lobby,
|
|
33313
|
-
unsignedTransaction: transaction
|
|
33314
|
-
};
|
|
33315
|
-
}
|
|
33316
33314
|
};
|
|
33317
33315
|
var Games = class {
|
|
33318
33316
|
constructor(http2, wallet, logger2) {
|
|
@@ -33832,6 +33830,7 @@ var Achievements = class {
|
|
|
33832
33830
|
return this.http.get(`/achievements/users/${userId}`);
|
|
33833
33831
|
}
|
|
33834
33832
|
};
|
|
33833
|
+
var import_utils14 = __toESM2(require_dist(), 1);
|
|
33835
33834
|
var MIN_TRANSFER_AMOUNT = 5e4;
|
|
33836
33835
|
var MIN_SOL_TRANSFER_AMOUNT = 1e6;
|
|
33837
33836
|
var Wallet = class {
|
|
@@ -35507,8 +35506,21 @@ function createGameActionsStore(transport) {
|
|
|
35507
35506
|
});
|
|
35508
35507
|
};
|
|
35509
35508
|
const isNonRpsState = (state) => Boolean(state && !isRpsState(state));
|
|
35509
|
+
const pendingEvents = /* @__PURE__ */ new Map();
|
|
35510
|
+
function enqueue(gameId, event) {
|
|
35511
|
+
const q = pendingEvents.get(gameId) ?? [];
|
|
35512
|
+
q.push(event);
|
|
35513
|
+
pendingEvents.set(gameId, q);
|
|
35514
|
+
}
|
|
35515
|
+
function drainQueue(gameId) {
|
|
35516
|
+
const q = pendingEvents.get(gameId);
|
|
35517
|
+
if (!q?.length) return;
|
|
35518
|
+
pendingEvents.delete(gameId);
|
|
35519
|
+
for (const ev of q) applyWsEvent(ev);
|
|
35520
|
+
}
|
|
35510
35521
|
const setBaseState = (gameId, state) => {
|
|
35511
35522
|
updateState(gameId, state);
|
|
35523
|
+
drainQueue(gameId);
|
|
35512
35524
|
};
|
|
35513
35525
|
const clearState = (gameId) => {
|
|
35514
35526
|
store.updateState((state) => {
|
|
@@ -35518,6 +35530,7 @@ function createGameActionsStore(transport) {
|
|
|
35518
35530
|
const { [gameId]: _, ...rest } = state.statesByGameId;
|
|
35519
35531
|
return { ...state, statesByGameId: rest };
|
|
35520
35532
|
});
|
|
35533
|
+
pendingEvents.delete(gameId);
|
|
35521
35534
|
};
|
|
35522
35535
|
const applyWsEvent = (event) => {
|
|
35523
35536
|
switch (event.event) {
|
|
@@ -35536,7 +35549,10 @@ function createGameActionsStore(transport) {
|
|
|
35536
35549
|
}
|
|
35537
35550
|
case "game:rps:starting": {
|
|
35538
35551
|
const current = store.getState().statesByGameId[event.payload.gameId];
|
|
35539
|
-
if (!current || !isRpsState(current))
|
|
35552
|
+
if (!current || !isRpsState(current)) {
|
|
35553
|
+
enqueue(event.payload.gameId, event);
|
|
35554
|
+
return;
|
|
35555
|
+
}
|
|
35540
35556
|
const betAmount = typeof event.payload.betAmount === "number" ? event.payload.betAmount : void 0;
|
|
35541
35557
|
const startedAt = typeof event.payload.startedAt === "string" ? event.payload.startedAt : current.roundState.startedAt;
|
|
35542
35558
|
const bufferEndsAt = typeof event.payload.bufferEndsAt === "string" ? event.payload.bufferEndsAt : current.roundState.selectionEndsAt;
|
|
@@ -35557,7 +35573,10 @@ function createGameActionsStore(transport) {
|
|
|
35557
35573
|
}
|
|
35558
35574
|
case "game:rps:round:started": {
|
|
35559
35575
|
const current = store.getState().statesByGameId[event.payload.gameId];
|
|
35560
|
-
if (!current || !isRpsState(current))
|
|
35576
|
+
if (!current || !isRpsState(current)) {
|
|
35577
|
+
enqueue(event.payload.gameId, event);
|
|
35578
|
+
return;
|
|
35579
|
+
}
|
|
35561
35580
|
const actions = {};
|
|
35562
35581
|
const baseUsers = /* @__PURE__ */ new Set();
|
|
35563
35582
|
Object.keys(current.roundState.actions).forEach(
|
|
@@ -35591,7 +35610,10 @@ function createGameActionsStore(transport) {
|
|
|
35591
35610
|
}
|
|
35592
35611
|
case "game:rps:action:received": {
|
|
35593
35612
|
const current = store.getState().statesByGameId[event.payload.gameId];
|
|
35594
|
-
if (!current || !isRpsState(current))
|
|
35613
|
+
if (!current || !isRpsState(current)) {
|
|
35614
|
+
enqueue(event.payload.gameId, event);
|
|
35615
|
+
return;
|
|
35616
|
+
}
|
|
35595
35617
|
const updated = {
|
|
35596
35618
|
...current,
|
|
35597
35619
|
roundState: {
|
|
@@ -35610,7 +35632,10 @@ function createGameActionsStore(transport) {
|
|
|
35610
35632
|
}
|
|
35611
35633
|
case "game:rps:timer:cutoff": {
|
|
35612
35634
|
const current = store.getState().statesByGameId[event.payload.gameId];
|
|
35613
|
-
if (!current || !isRpsState(current))
|
|
35635
|
+
if (!current || !isRpsState(current)) {
|
|
35636
|
+
enqueue(event.payload.gameId, event);
|
|
35637
|
+
return;
|
|
35638
|
+
}
|
|
35614
35639
|
const updated = {
|
|
35615
35640
|
...current,
|
|
35616
35641
|
roundState: {
|
|
@@ -35624,7 +35649,10 @@ function createGameActionsStore(transport) {
|
|
|
35624
35649
|
}
|
|
35625
35650
|
case "game:rps:round:reveal": {
|
|
35626
35651
|
const current = store.getState().statesByGameId[event.payload.gameId];
|
|
35627
|
-
if (!current || !isRpsState(current))
|
|
35652
|
+
if (!current || !isRpsState(current)) {
|
|
35653
|
+
enqueue(event.payload.gameId, event);
|
|
35654
|
+
return;
|
|
35655
|
+
}
|
|
35628
35656
|
const actions = {};
|
|
35629
35657
|
const payloadActions = event.payload.actions;
|
|
35630
35658
|
Object.keys(payloadActions || {}).forEach((userId) => {
|
|
@@ -35648,7 +35676,10 @@ function createGameActionsStore(transport) {
|
|
|
35648
35676
|
}
|
|
35649
35677
|
case "game:rps:round:completed": {
|
|
35650
35678
|
const current = store.getState().statesByGameId[event.payload.gameId];
|
|
35651
|
-
if (!current || !isRpsState(current))
|
|
35679
|
+
if (!current || !isRpsState(current)) {
|
|
35680
|
+
enqueue(event.payload.gameId, event);
|
|
35681
|
+
return;
|
|
35682
|
+
}
|
|
35652
35683
|
const roundHistory = [
|
|
35653
35684
|
...current.roundHistory || [],
|
|
35654
35685
|
{
|
|
@@ -35673,7 +35704,10 @@ function createGameActionsStore(transport) {
|
|
|
35673
35704
|
}
|
|
35674
35705
|
case "game:rps:timeout": {
|
|
35675
35706
|
const current = store.getState().statesByGameId[event.payload.gameId];
|
|
35676
|
-
if (!current || !isRpsState(current))
|
|
35707
|
+
if (!current || !isRpsState(current)) {
|
|
35708
|
+
enqueue(event.payload.gameId, event);
|
|
35709
|
+
return;
|
|
35710
|
+
}
|
|
35677
35711
|
const timedOutUser = event.payload.playerId;
|
|
35678
35712
|
const action = event.payload.action;
|
|
35679
35713
|
const updated = {
|
|
@@ -35698,7 +35732,10 @@ function createGameActionsStore(transport) {
|
|
|
35698
35732
|
const payload = event.payload;
|
|
35699
35733
|
const { gameId } = payload;
|
|
35700
35734
|
const current = store.getState().statesByGameId[gameId];
|
|
35701
|
-
if (!current)
|
|
35735
|
+
if (!current) {
|
|
35736
|
+
enqueue(gameId, event);
|
|
35737
|
+
return;
|
|
35738
|
+
}
|
|
35702
35739
|
const updated = isRpsCompletionPayload(payload) && isRpsState(current) ? {
|
|
35703
35740
|
...current,
|
|
35704
35741
|
status: "completed",
|
|
@@ -35747,11 +35784,15 @@ function createGameActionsStore(transport) {
|
|
|
35747
35784
|
const current = store.getState().statesByGameId[gameId];
|
|
35748
35785
|
const updated = current ? { ...current, ...incoming } : incoming;
|
|
35749
35786
|
updateState(gameId, updated);
|
|
35787
|
+
drainQueue(gameId);
|
|
35750
35788
|
break;
|
|
35751
35789
|
}
|
|
35752
35790
|
case "game:rematch:requested": {
|
|
35753
35791
|
const current = store.getState().statesByGameId[event.payload.gameId];
|
|
35754
|
-
if (!current)
|
|
35792
|
+
if (!current) {
|
|
35793
|
+
enqueue(event.payload.gameId, event);
|
|
35794
|
+
return;
|
|
35795
|
+
}
|
|
35755
35796
|
const requestedBy = event.payload.requestedBy;
|
|
35756
35797
|
const userId = event.payload.userId;
|
|
35757
35798
|
const requested = new Set(
|
|
@@ -35767,7 +35808,10 @@ function createGameActionsStore(transport) {
|
|
|
35767
35808
|
}
|
|
35768
35809
|
case "game:rematch:cancelled": {
|
|
35769
35810
|
const current = store.getState().statesByGameId[event.payload.gameId];
|
|
35770
|
-
if (!current)
|
|
35811
|
+
if (!current) {
|
|
35812
|
+
enqueue(event.payload.gameId, event);
|
|
35813
|
+
return;
|
|
35814
|
+
}
|
|
35771
35815
|
const requestedBy = event.payload.requestedBy ?? [];
|
|
35772
35816
|
const updated = {
|
|
35773
35817
|
...current,
|
|
@@ -35778,7 +35822,10 @@ function createGameActionsStore(transport) {
|
|
|
35778
35822
|
}
|
|
35779
35823
|
case "game:rematch:started": {
|
|
35780
35824
|
const current = store.getState().statesByGameId[event.payload.gameId];
|
|
35781
|
-
if (!current)
|
|
35825
|
+
if (!current) {
|
|
35826
|
+
enqueue(event.payload.gameId, event);
|
|
35827
|
+
return;
|
|
35828
|
+
}
|
|
35782
35829
|
const updated = {
|
|
35783
35830
|
...current,
|
|
35784
35831
|
rematchRequestedBy: event.payload.playerIds ?? []
|
|
@@ -35789,7 +35836,10 @@ function createGameActionsStore(transport) {
|
|
|
35789
35836
|
case "game:pot:updated": {
|
|
35790
35837
|
const { gameId, totalPotMinor } = event.payload;
|
|
35791
35838
|
const current = store.getState().statesByGameId[gameId];
|
|
35792
|
-
if (!current)
|
|
35839
|
+
if (!current) {
|
|
35840
|
+
enqueue(gameId, event);
|
|
35841
|
+
return;
|
|
35842
|
+
}
|
|
35793
35843
|
const updated = {
|
|
35794
35844
|
...current,
|
|
35795
35845
|
totalPotMinor
|
|
@@ -35802,12 +35852,123 @@ function createGameActionsStore(transport) {
|
|
|
35802
35852
|
}
|
|
35803
35853
|
};
|
|
35804
35854
|
const joinGame = (gameId) => transport.joinRoom(`game:${gameId}`);
|
|
35855
|
+
const getCountdownDigit = (gameId, nowMs) => {
|
|
35856
|
+
const state = store.getState().statesByGameId[gameId];
|
|
35857
|
+
if (!state) return null;
|
|
35858
|
+
if (isRpsState(state)) {
|
|
35859
|
+
if (state.roundState.phase !== "starting") return null;
|
|
35860
|
+
const remaining = new Date(state.roundState.selectionEndsAt).getTime() - nowMs;
|
|
35861
|
+
if (remaining <= 0) return null;
|
|
35862
|
+
return Math.ceil(remaining / 1e3);
|
|
35863
|
+
}
|
|
35864
|
+
const bufferEndsAt = state.bufferEndsAt;
|
|
35865
|
+
if (bufferEndsAt) {
|
|
35866
|
+
const remaining = new Date(bufferEndsAt).getTime() - nowMs;
|
|
35867
|
+
if (remaining <= 0) return null;
|
|
35868
|
+
return Math.ceil(remaining / 1e3);
|
|
35869
|
+
}
|
|
35870
|
+
return null;
|
|
35871
|
+
};
|
|
35872
|
+
const getChessClockTimes = (gameId, nowMs) => {
|
|
35873
|
+
const state = store.getState().statesByGameId[gameId];
|
|
35874
|
+
if (!state || state.gameType !== "chess") return null;
|
|
35875
|
+
const s = state;
|
|
35876
|
+
let whiteMs = s.whiteTimeMs ?? 0;
|
|
35877
|
+
let blackMs = s.blackTimeMs ?? 0;
|
|
35878
|
+
if (s.status === "active" && s.currentPlayerId) {
|
|
35879
|
+
const startedAt = Date.parse(s.turnStartedAt);
|
|
35880
|
+
if (!Number.isNaN(startedAt)) {
|
|
35881
|
+
const elapsed = Math.max(0, nowMs - startedAt);
|
|
35882
|
+
if (s.currentPlayerId === s.whitePlayerId) {
|
|
35883
|
+
whiteMs = Math.max(0, whiteMs - elapsed);
|
|
35884
|
+
} else if (s.currentPlayerId === s.blackPlayerId) {
|
|
35885
|
+
blackMs = Math.max(0, blackMs - elapsed);
|
|
35886
|
+
}
|
|
35887
|
+
}
|
|
35888
|
+
}
|
|
35889
|
+
return { whiteTimeMs: whiteMs, blackTimeMs: blackMs };
|
|
35890
|
+
};
|
|
35891
|
+
const getChessCapturedPieces = (gameId) => {
|
|
35892
|
+
const state = store.getState().statesByGameId[gameId];
|
|
35893
|
+
if (!state || state.gameType !== "chess") return null;
|
|
35894
|
+
const fen = state.fen;
|
|
35895
|
+
if (!fen) return { capturedByWhite: [], capturedByBlack: [] };
|
|
35896
|
+
const placement = fen.split(" ")[0];
|
|
35897
|
+
const white = {};
|
|
35898
|
+
const black = {};
|
|
35899
|
+
for (const char of placement) {
|
|
35900
|
+
if (char === "/" || char >= "1" && char <= "8") continue;
|
|
35901
|
+
const lower = char.toLowerCase();
|
|
35902
|
+
if (char === lower) {
|
|
35903
|
+
black[lower] = (black[lower] ?? 0) + 1;
|
|
35904
|
+
} else {
|
|
35905
|
+
white[lower] = (white[lower] ?? 0) + 1;
|
|
35906
|
+
}
|
|
35907
|
+
}
|
|
35908
|
+
const INITIAL = {
|
|
35909
|
+
p: 8,
|
|
35910
|
+
r: 2,
|
|
35911
|
+
n: 2,
|
|
35912
|
+
b: 2,
|
|
35913
|
+
q: 1,
|
|
35914
|
+
k: 1
|
|
35915
|
+
};
|
|
35916
|
+
const capturedByWhite = [];
|
|
35917
|
+
const capturedByBlack = [];
|
|
35918
|
+
for (const [type2, initial] of Object.entries(INITIAL)) {
|
|
35919
|
+
const missingBlack = initial - (black[type2] ?? 0);
|
|
35920
|
+
for (let i = 0; i < missingBlack; i++) capturedByWhite.push(`b${type2}`);
|
|
35921
|
+
const missingWhite = initial - (white[type2] ?? 0);
|
|
35922
|
+
for (let i = 0; i < missingWhite; i++) capturedByBlack.push(`w${type2}`);
|
|
35923
|
+
}
|
|
35924
|
+
return { capturedByWhite, capturedByBlack };
|
|
35925
|
+
};
|
|
35926
|
+
const getTicTacToeClockTimes = (gameId, nowMs) => {
|
|
35927
|
+
const state = store.getState().statesByGameId[gameId];
|
|
35928
|
+
if (!state || state.gameType !== "tic-tac-toe") return null;
|
|
35929
|
+
const s = state;
|
|
35930
|
+
let xMs = s.xTimeMs ?? 0;
|
|
35931
|
+
let oMs = s.oTimeMs ?? 0;
|
|
35932
|
+
if (s.status === "active" && s.currentPlayerId) {
|
|
35933
|
+
const currentMark = s.playerMarks[s.currentPlayerId];
|
|
35934
|
+
const startedAt = Date.parse(s.turnStartedAt);
|
|
35935
|
+
if (!Number.isNaN(startedAt)) {
|
|
35936
|
+
const elapsed = Math.max(0, nowMs - startedAt);
|
|
35937
|
+
if (currentMark === "X") xMs = Math.max(0, xMs - elapsed);
|
|
35938
|
+
else if (currentMark === "O") oMs = Math.max(0, oMs - elapsed);
|
|
35939
|
+
}
|
|
35940
|
+
}
|
|
35941
|
+
return { xTimeMs: xMs, oTimeMs: oMs };
|
|
35942
|
+
};
|
|
35943
|
+
const getConnect4ClockTimes = (gameId, nowMs) => {
|
|
35944
|
+
const state = store.getState().statesByGameId[gameId];
|
|
35945
|
+
if (!state || state.gameType !== "connect-four") return null;
|
|
35946
|
+
const s = state;
|
|
35947
|
+
let redMs = s.redTimeMs ?? 0;
|
|
35948
|
+
let yellowMs = s.yellowTimeMs ?? 0;
|
|
35949
|
+
if (s.status === "active" && s.currentPlayerId) {
|
|
35950
|
+
const currentColor = s.playerColors[s.currentPlayerId];
|
|
35951
|
+
const startedAt = Date.parse(s.turnStartedAt);
|
|
35952
|
+
if (!Number.isNaN(startedAt)) {
|
|
35953
|
+
const elapsed = Math.max(0, nowMs - startedAt);
|
|
35954
|
+
if (currentColor === "RED") redMs = Math.max(0, redMs - elapsed);
|
|
35955
|
+
else if (currentColor === "YELLOW")
|
|
35956
|
+
yellowMs = Math.max(0, yellowMs - elapsed);
|
|
35957
|
+
}
|
|
35958
|
+
}
|
|
35959
|
+
return { redTimeMs: redMs, yellowTimeMs: yellowMs };
|
|
35960
|
+
};
|
|
35805
35961
|
return {
|
|
35806
35962
|
store,
|
|
35807
35963
|
setBaseState,
|
|
35808
35964
|
clearState,
|
|
35809
35965
|
applyWsEvent,
|
|
35810
|
-
joinGame
|
|
35966
|
+
joinGame,
|
|
35967
|
+
getCountdownDigit,
|
|
35968
|
+
getChessClockTimes,
|
|
35969
|
+
getChessCapturedPieces,
|
|
35970
|
+
getTicTacToeClockTimes,
|
|
35971
|
+
getConnect4ClockTimes
|
|
35811
35972
|
};
|
|
35812
35973
|
}
|
|
35813
35974
|
function isRpsState(state) {
|
|
@@ -36465,12 +36626,14 @@ var WsRouter = class {
|
|
|
36465
36626
|
}
|
|
36466
36627
|
const decoded = decodeWsEvent(eventName, payload);
|
|
36467
36628
|
if (!decoded) return;
|
|
36468
|
-
|
|
36469
|
-
|
|
36470
|
-
this.deps.
|
|
36471
|
-
this.deps.
|
|
36472
|
-
this.deps.
|
|
36473
|
-
this.deps.
|
|
36629
|
+
const serverTs = payload !== null && typeof payload === "object" ? payload._serverTs : void 0;
|
|
36630
|
+
const event = serverTs !== void 0 ? { ...decoded, _serverTs: serverTs } : decoded;
|
|
36631
|
+
this.deps.lobbyStore.applyWsEvent(event);
|
|
36632
|
+
this.deps.gameStore.applyWsEvent(event);
|
|
36633
|
+
this.deps.gameActionsStore.applyWsEvent(event);
|
|
36634
|
+
this.deps.chatStore.applyWsEvent(event);
|
|
36635
|
+
this.deps.dmThreadsStore.applyWsEvent(event);
|
|
36636
|
+
this.deps.notificationsStore.applyWsEvent(event);
|
|
36474
36637
|
});
|
|
36475
36638
|
}
|
|
36476
36639
|
stop() {
|
|
@@ -36482,12 +36645,14 @@ var WsRouter = class {
|
|
|
36482
36645
|
this.transport.subscribeEvent(eventName, (payload) => {
|
|
36483
36646
|
const decoded = decodeWsEvent(eventName, payload);
|
|
36484
36647
|
if (!decoded) return;
|
|
36485
|
-
|
|
36486
|
-
|
|
36487
|
-
this.deps.
|
|
36488
|
-
this.deps.
|
|
36489
|
-
this.deps.
|
|
36490
|
-
this.deps.
|
|
36648
|
+
const serverTs = payload !== null && typeof payload === "object" ? payload._serverTs : void 0;
|
|
36649
|
+
const event = serverTs !== void 0 ? { ...decoded, _serverTs: serverTs } : decoded;
|
|
36650
|
+
this.deps.lobbyStore.applyWsEvent(event);
|
|
36651
|
+
this.deps.gameStore.applyWsEvent(event);
|
|
36652
|
+
this.deps.gameActionsStore.applyWsEvent(event);
|
|
36653
|
+
this.deps.chatStore.applyWsEvent(event);
|
|
36654
|
+
this.deps.dmThreadsStore.applyWsEvent(event);
|
|
36655
|
+
this.deps.notificationsStore.applyWsEvent(event);
|
|
36491
36656
|
});
|
|
36492
36657
|
}
|
|
36493
36658
|
}
|
|
@@ -36625,10 +36790,11 @@ var SDK = class {
|
|
|
36625
36790
|
return { ...result, lobby };
|
|
36626
36791
|
}
|
|
36627
36792
|
};
|
|
36628
|
-
var
|
|
36629
|
-
var export_MICRO_UNITS =
|
|
36630
|
-
var
|
|
36631
|
-
var
|
|
36793
|
+
var import_utils22 = __toESM2(require_dist(), 1);
|
|
36794
|
+
var export_MICRO_UNITS = import_utils22.MICRO_UNITS;
|
|
36795
|
+
var export_SOL_MINT = import_utils14.SOL_MINT;
|
|
36796
|
+
var export_formatMoneyMinor = import_utils22.formatMoneyMinor;
|
|
36797
|
+
var export_toMajor = import_utils22.toMajor;
|
|
36632
36798
|
|
|
36633
36799
|
// ../dim-agent-core/node_modules/bs58/node_modules/base-x/src/esm/index.js
|
|
36634
36800
|
function base2(ALPHABET3) {
|
|
@@ -36767,6 +36933,28 @@ var esm_default4 = esm_default3(ALPHABET2);
|
|
|
36767
36933
|
|
|
36768
36934
|
// ../dim-agent-core/src/client.ts
|
|
36769
36935
|
var import_tweetnacl = __toESM(require_nacl_fast(), 1);
|
|
36936
|
+
function decodeJwtSub(token) {
|
|
36937
|
+
try {
|
|
36938
|
+
const parts2 = token.split(".");
|
|
36939
|
+
if (parts2.length < 2) return null;
|
|
36940
|
+
const base64 = parts2[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
36941
|
+
const json = Buffer.from(base64, "base64").toString("utf-8");
|
|
36942
|
+
const parsed = JSON.parse(json);
|
|
36943
|
+
return typeof parsed.sub === "string" ? parsed.sub : null;
|
|
36944
|
+
} catch {
|
|
36945
|
+
return null;
|
|
36946
|
+
}
|
|
36947
|
+
}
|
|
36948
|
+
function signatureToBytes(sig) {
|
|
36949
|
+
if (sig.includes("-") || sig.includes("_")) {
|
|
36950
|
+
const padded = sig.replace(/-/g, "+").replace(/_/g, "/") + "==".slice(sig.length % 4 === 0 ? 4 : sig.length % 4);
|
|
36951
|
+
return new Uint8Array(Buffer.from(padded, "base64"));
|
|
36952
|
+
}
|
|
36953
|
+
if (/[+/=]/.test(sig)) {
|
|
36954
|
+
return new Uint8Array(Buffer.from(sig, "base64"));
|
|
36955
|
+
}
|
|
36956
|
+
return esm_default4.decode(sig);
|
|
36957
|
+
}
|
|
36770
36958
|
var DimAgentClient = class {
|
|
36771
36959
|
sdk;
|
|
36772
36960
|
agentConfig;
|
|
@@ -36793,10 +36981,19 @@ var DimAgentClient = class {
|
|
|
36793
36981
|
} else {
|
|
36794
36982
|
this.keypair = null;
|
|
36795
36983
|
}
|
|
36984
|
+
const storage = new NodeStorage();
|
|
36985
|
+
if (config.accessToken) {
|
|
36986
|
+
storage.set(TOKEN_KEY, config.accessToken);
|
|
36987
|
+
const sub = decodeJwtSub(config.accessToken);
|
|
36988
|
+
if (sub) {
|
|
36989
|
+
this.authenticated = true;
|
|
36990
|
+
this.userId = sub;
|
|
36991
|
+
}
|
|
36992
|
+
}
|
|
36796
36993
|
this.sdk = new SDK({
|
|
36797
36994
|
appId: "dim-agents",
|
|
36798
36995
|
baseUrl: config.apiUrl || "https://api.dim.cool",
|
|
36799
|
-
storage
|
|
36996
|
+
storage,
|
|
36800
36997
|
autoPay: {
|
|
36801
36998
|
enabled: !this.externalSignerMode,
|
|
36802
36999
|
maxAmountMinor: 25e3,
|
|
@@ -36900,10 +37097,10 @@ var DimAgentClient = class {
|
|
|
36900
37097
|
/**
|
|
36901
37098
|
* Complete authentication using an externally provided signature (external signer mode).
|
|
36902
37099
|
* @param address - Solana wallet address (base58)
|
|
36903
|
-
* @param
|
|
37100
|
+
* @param signature - Detached ed25519 signature in base58, base64, or base64url (from sign_solana_message)
|
|
36904
37101
|
*/
|
|
36905
|
-
async completeAuth(address,
|
|
36906
|
-
const signatureBytes =
|
|
37102
|
+
async completeAuth(address, signature) {
|
|
37103
|
+
const signatureBytes = signatureToBytes(signature);
|
|
36907
37104
|
const signedMessage = Buffer.from(signatureBytes).toString("base64");
|
|
36908
37105
|
const response = await this.sdk.auth.loginWithExternalSignature(
|
|
36909
37106
|
address,
|
|
@@ -37057,7 +37254,7 @@ async function requestAuthMessage(client, args) {
|
|
|
37057
37254
|
data: {
|
|
37058
37255
|
message,
|
|
37059
37256
|
address: args.address,
|
|
37060
|
-
nextStep: 'Sign this message with sign_solana_message (networkId: "solana:mainnet"), then call dim_complete_login with the address and the base58
|
|
37257
|
+
nextStep: 'Sign this message with sign_solana_message (networkId: "solana:mainnet"), then call dim_complete_login with the address and the signature. Accepted formats: base58, base64, or base64url (all formats returned by wallet MCPs are accepted).'
|
|
37061
37258
|
}
|
|
37062
37259
|
};
|
|
37063
37260
|
} catch (error) {
|
|
@@ -38303,58 +38500,6 @@ function raceTimeout(promise, ms) {
|
|
|
38303
38500
|
});
|
|
38304
38501
|
}
|
|
38305
38502
|
|
|
38306
|
-
// ../dim-agent-core/src/tools/challenges.ts
|
|
38307
|
-
async function challengeUser(client, args) {
|
|
38308
|
-
try {
|
|
38309
|
-
if (!args.targetUsername && !args.targetUserId) {
|
|
38310
|
-
return {
|
|
38311
|
-
error: "Must provide either targetUsername or targetUserId.",
|
|
38312
|
-
isError: true
|
|
38313
|
-
};
|
|
38314
|
-
}
|
|
38315
|
-
const spendErr = client.checkSpendLimit(args.amount, true);
|
|
38316
|
-
if (spendErr) return { error: spendErr, isError: true };
|
|
38317
|
-
const amountMinor = Math.round(args.amount * 1e6);
|
|
38318
|
-
const result = await client.sdk.challenges.create({
|
|
38319
|
-
gameType: args.gameType,
|
|
38320
|
-
amount: amountMinor,
|
|
38321
|
-
targetUsername: args.targetUsername,
|
|
38322
|
-
targetUserId: args.targetUserId
|
|
38323
|
-
});
|
|
38324
|
-
client.recordSpend(amountMinor);
|
|
38325
|
-
return {
|
|
38326
|
-
data: {
|
|
38327
|
-
...result,
|
|
38328
|
-
amountFormatted: `$${args.amount.toFixed(2)}`,
|
|
38329
|
-
hint: "The challenged user will receive a notification. When they accept, a lobby is created automatically."
|
|
38330
|
-
}
|
|
38331
|
-
};
|
|
38332
|
-
} catch (error) {
|
|
38333
|
-
return {
|
|
38334
|
-
error: `Failed to create challenge: ${error instanceof Error ? error.message : String(error)}`,
|
|
38335
|
-
isError: true
|
|
38336
|
-
};
|
|
38337
|
-
}
|
|
38338
|
-
}
|
|
38339
|
-
async function acceptChallenge(client, args) {
|
|
38340
|
-
try {
|
|
38341
|
-
const result = await client.sdk.challenges.accept(args.challengeId);
|
|
38342
|
-
const spectateUrl = result.gameId ? await getSpectateUrl(client) : null;
|
|
38343
|
-
return {
|
|
38344
|
-
data: {
|
|
38345
|
-
...result,
|
|
38346
|
-
...spectateUrl && { spectateUrl },
|
|
38347
|
-
hint: result.gameId ? `Game started! Call dim_game_loop with gameId "${result.gameId}".${spectateUrl ? ` Tell the user they can spectate at ${spectateUrl}` : ""}` : `Lobby created: ${result.lobbyId}. Use dim_join_queue to start matchmaking.`
|
|
38348
|
-
}
|
|
38349
|
-
};
|
|
38350
|
-
} catch (error) {
|
|
38351
|
-
return {
|
|
38352
|
-
error: `Failed to accept challenge: ${error instanceof Error ? error.message : String(error)}`,
|
|
38353
|
-
isError: true
|
|
38354
|
-
};
|
|
38355
|
-
}
|
|
38356
|
-
}
|
|
38357
|
-
|
|
38358
38503
|
// ../dim-agent-core/src/tools/referrals.ts
|
|
38359
38504
|
async function getReferralSummary(client) {
|
|
38360
38505
|
try {
|
|
@@ -39231,6 +39376,22 @@ async function getGameHistory(client, args) {
|
|
|
39231
39376
|
};
|
|
39232
39377
|
}
|
|
39233
39378
|
}
|
|
39379
|
+
async function reportUser(client, args) {
|
|
39380
|
+
try {
|
|
39381
|
+
await client.sdk.reports.create(args.userId, args.reason);
|
|
39382
|
+
return {
|
|
39383
|
+
data: {
|
|
39384
|
+
success: true,
|
|
39385
|
+
hint: "Report submitted. The DIM moderation team will review it."
|
|
39386
|
+
}
|
|
39387
|
+
};
|
|
39388
|
+
} catch (error) {
|
|
39389
|
+
return {
|
|
39390
|
+
error: `Failed to report user: ${error instanceof Error ? error.message : String(error)}`,
|
|
39391
|
+
isError: true
|
|
39392
|
+
};
|
|
39393
|
+
}
|
|
39394
|
+
}
|
|
39234
39395
|
async function getMyStats(client) {
|
|
39235
39396
|
try {
|
|
39236
39397
|
if (!client.currentUserId) {
|
|
@@ -39276,7 +39437,7 @@ var TOOL_DEFINITIONS = [
|
|
|
39276
39437
|
},
|
|
39277
39438
|
{
|
|
39278
39439
|
name: "dim_complete_login",
|
|
39279
|
-
description: "External wallet login step 2: provide the wallet address and
|
|
39440
|
+
description: "External wallet login step 2: provide the wallet address and signature from sign_solana_message to complete authentication with DIM.",
|
|
39280
39441
|
params: {
|
|
39281
39442
|
address: {
|
|
39282
39443
|
type: "string",
|
|
@@ -39285,7 +39446,7 @@ var TOOL_DEFINITIONS = [
|
|
|
39285
39446
|
},
|
|
39286
39447
|
signature: {
|
|
39287
39448
|
type: "string",
|
|
39288
|
-
description: "
|
|
39449
|
+
description: "Signature from sign_solana_message \u2014 base58, base64, or base64url accepted",
|
|
39289
39450
|
required: true
|
|
39290
39451
|
}
|
|
39291
39452
|
},
|
|
@@ -39729,9 +39890,26 @@ var TOOL_DEFINITIONS = [
|
|
|
39729
39890
|
params: {},
|
|
39730
39891
|
execute: (c) => getMyStats(c)
|
|
39731
39892
|
},
|
|
39893
|
+
{
|
|
39894
|
+
name: "dim_report_user",
|
|
39895
|
+
description: "Report a user for cheating, harassment, or other violations. Rate limited to 5 reports per hour.",
|
|
39896
|
+
params: {
|
|
39897
|
+
userId: {
|
|
39898
|
+
type: "string",
|
|
39899
|
+
description: "The ID of the user to report",
|
|
39900
|
+
required: true
|
|
39901
|
+
},
|
|
39902
|
+
reason: {
|
|
39903
|
+
type: "string",
|
|
39904
|
+
description: "Reason for the report (max 300 characters)",
|
|
39905
|
+
required: true
|
|
39906
|
+
}
|
|
39907
|
+
},
|
|
39908
|
+
execute: (c, a) => reportUser(c, a)
|
|
39909
|
+
},
|
|
39732
39910
|
{
|
|
39733
39911
|
name: "dim_create_lobby",
|
|
39734
|
-
description: "Create a new game lobby. Bet amount is in USDC dollars (e.g., 1.00 for $1.00). A 1% fee (min 1 cent) is charged per player.",
|
|
39912
|
+
description: "Create a new game lobby. Bet amount is in USDC dollars (e.g., 1.00 for $1.00). A 1% fee (min 1 cent) is charged per player. NOTE: Creating a lobby automatically closes and refunds any previous open or queued lobby for this user \u2014 you do not need to clean up manually.",
|
|
39735
39913
|
params: {
|
|
39736
39914
|
gameType: {
|
|
39737
39915
|
type: "string",
|
|
@@ -39945,45 +40123,6 @@ var TOOL_DEFINITIONS = [
|
|
|
39945
40123
|
},
|
|
39946
40124
|
execute: (c, a) => inviteToLobby(c, a)
|
|
39947
40125
|
},
|
|
39948
|
-
// ── Challenges ───────────────────────────────────────────────────────
|
|
39949
|
-
{
|
|
39950
|
-
name: "dim_challenge_user",
|
|
39951
|
-
description: "Challenge a specific user to a game. This is the best way to invite someone you are chatting with \u2014 they get a notification and can accept directly. Prefer this over creating a lobby when you know who you want to play. Amount must be between $1 and $1000.",
|
|
39952
|
-
params: {
|
|
39953
|
-
gameType: { type: "string", description: "Game type", required: true },
|
|
39954
|
-
amount: {
|
|
39955
|
-
type: "number",
|
|
39956
|
-
description: "Challenge amount in USDC dollars",
|
|
39957
|
-
required: true,
|
|
39958
|
-
min: 1,
|
|
39959
|
-
max: 1e3
|
|
39960
|
-
},
|
|
39961
|
-
targetUsername: {
|
|
39962
|
-
type: "string",
|
|
39963
|
-
description: "Username of the user to challenge"
|
|
39964
|
-
},
|
|
39965
|
-
targetUserId: {
|
|
39966
|
-
type: "string",
|
|
39967
|
-
description: "User ID of the user to challenge"
|
|
39968
|
-
}
|
|
39969
|
-
},
|
|
39970
|
-
execute: (c, a) => challengeUser(
|
|
39971
|
-
c,
|
|
39972
|
-
a
|
|
39973
|
-
)
|
|
39974
|
-
},
|
|
39975
|
-
{
|
|
39976
|
-
name: "dim_accept_challenge",
|
|
39977
|
-
description: "Accept a challenge that was sent to you.",
|
|
39978
|
-
params: {
|
|
39979
|
-
challengeId: {
|
|
39980
|
-
type: "string",
|
|
39981
|
-
description: "The challenge ID to accept",
|
|
39982
|
-
required: true
|
|
39983
|
-
}
|
|
39984
|
-
},
|
|
39985
|
-
execute: (c, a) => acceptChallenge(c, a)
|
|
39986
|
-
},
|
|
39987
40126
|
// ── Referrals ────────────────────────────────────────────────────────
|
|
39988
40127
|
{
|
|
39989
40128
|
name: "dim_get_referral_summary",
|
|
@@ -40256,7 +40395,7 @@ var TOOL_DEFINITIONS = [
|
|
|
40256
40395
|
// ── Notifications & Events ───────────────────────────────────────────
|
|
40257
40396
|
{
|
|
40258
40397
|
name: "dim_get_pending_events",
|
|
40259
|
-
description: "Drain buffered real-time events (DMs,
|
|
40398
|
+
description: "Drain buffered real-time events (DMs, game turns, match notifications). Call regularly to stay aware.",
|
|
40260
40399
|
params: {},
|
|
40261
40400
|
execute: (c) => getPendingEvents(c)
|
|
40262
40401
|
},
|
|
@@ -40293,11 +40432,18 @@ async function executeWithAuthRetry(client, tool, params) {
|
|
|
40293
40432
|
if (tool.name === "dim_login") {
|
|
40294
40433
|
return tool.execute(client, params);
|
|
40295
40434
|
}
|
|
40435
|
+
if (client.externalSignerMode) {
|
|
40436
|
+
return tool.execute(client, params);
|
|
40437
|
+
}
|
|
40296
40438
|
try {
|
|
40297
40439
|
const result = await tool.execute(client, params);
|
|
40298
40440
|
if (!result.error && !result.isError) return result;
|
|
40299
40441
|
if (!isUnauthorizedResult(result)) return result;
|
|
40300
|
-
|
|
40442
|
+
try {
|
|
40443
|
+
await client.authenticate();
|
|
40444
|
+
} catch {
|
|
40445
|
+
return { error: UNAUTHORIZED_MESSAGE, isError: true };
|
|
40446
|
+
}
|
|
40301
40447
|
const retryResult = await tool.execute(client, params);
|
|
40302
40448
|
if (retryResult.isError || retryResult.error) {
|
|
40303
40449
|
if (isUnauthorizedResult(retryResult)) {
|
package/package.json
CHANGED