diff --git a/assets/js/app.jsx b/assets/js/app.jsx
new file mode 100644
index 0000000..b6f2d6d
--- /dev/null
+++ b/assets/js/app.jsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import { createRoot } from 'react-dom/client';
+import MineSeeker from './mine-seeker/MineSeeker';
+
+const wrapper = document.getElementById('mine-wrapper');
+
+createRoot(wrapper).render(
+ ,
+);
diff --git a/assets/js/mine-seeker.js b/assets/js/mine-seeker.js
deleted file mode 100644
index cfb2252..0000000
--- a/assets/js/mine-seeker.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from "react";
-import ReactDOM from "react-dom";
-import MineSeeker from "./mine-seeker/app";
-
-ReactDOM.render(
- ,
- document.getElementById("mine-wrapper"),
-);
diff --git a/assets/js/mine-seeker/MineSeeker.jsx b/assets/js/mine-seeker/MineSeeker.jsx
new file mode 100644
index 0000000..13be55f
--- /dev/null
+++ b/assets/js/mine-seeker/MineSeeker.jsx
@@ -0,0 +1,26 @@
+import React, { useRef } from 'react';
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { GameProvider } from './contexts/GameContext';
+import { GameBoard } from './components/GameBoard';
+
+const queryClient = new QueryClient();
+
+const MineSeeker = ({ env, gameId }) => {
+ const isEnvDev = 'dev' === env;
+ const gameAssoc = useRef('' !== gameId ? gameId : crypto.randomUUID()).current;
+ const gameInherited = '' !== gameId;
+
+ return (
+
+
+
+
+
+ );
+};
+
+export default MineSeeker;
diff --git a/assets/js/mine-seeker/app.js b/assets/js/mine-seeker/app.js
deleted file mode 100644
index eaafd32..0000000
--- a/assets/js/mine-seeker/app.js
+++ /dev/null
@@ -1,428 +0,0 @@
-import React from 'react';
-import GridControl from './grid/grid-control';
-
-class MineSeeker extends React.Component {
- constructor(props) {
- super(props);
-
- let gameAssoc = '' !== props.gameId ? props.gameId : crypto.randomUUID();
- let channel = 'mineseeker/channel/' + gameAssoc;
-
- this.state = {
- env: props.env,
- gameInherited: '' !== props.gameId,
- gameAssoc: gameAssoc,
- channel: channel,
- stepCache: [],
- connectionLost: false,
- end: false,
- };
-
- /** SSE connection (not React state — no re-render needed) */
- this.eventSource = null;
-
- /**
- * Users from GET /api/game/connect (inherited game).
- * Passed to wSubscribe so it can determine the local player's colour.
- */
- this.rpcUsers = null;
- }
-
- currectGridSize() {
- let $field = $('#mine-wrapper .grid');
- $field.height($field.width());
-
- $field = $('#mine-wrapper .grid .field-wrapper');
- $field.height($field.width());
-
- $('#mine-wrapper .grid .field-wrapper .field')
- .height($field.width())
- .css('line-height', ($field.width() - 2) + 'px');
- }
-
- /**
- * THE END
- */
- makeGameEndIfItEnds(bluePoints, redPoints, resign = false, leftMines = []) {
- let redWins = 25 < redPoints,
- blueWins = 25 < bluePoints;
-
- if (redWins || blueWins || resign) {
- this.refs.gridControl.state.sound.won.play();
-
- if (false === resign) {
- this.refs.gridControl.setState({
- overlay: true,
- overlayTitle: (redWins ? 'Red' : 'Blue') + ' wins the game!',
- overlaySubTitle: 'Play again!',
- });
- }
-
- this.refs.gridControl.showLeftMines(leftMines);
- this.refs.gridControl.refs.userControl.setState({ activePlayer: false });
- this.refs.gridControl.refs.userControl.refs.red.setState({ desc: '' });
- this.refs.gridControl.refs.userControl.refs.blue.setState({ desc: '' });
- }
- }
-
- resignProcess(color) {
- this.refs.gridControl.setState({
- overlay: true,
- overlayTitle: color === this.refs.gridControl.state.webPlayer
- ? 'You have been give up'
- : 'Your opponent has been resigned',
- overlaySubTitle: color === this.refs.gridControl.state.webPlayer
- ? 'You LOSE!'
- : 'You WIN!',
- });
-
- this.setState({ end: true });
- this.makeGameEndIfItEnds(0, 0, true);
- }
-
- clickResign() {
- let resignColor = this.refs.gridControl.refs.userControl.state.activePlayer ? 'blue' : 'red';
- this.publishStep({ resign: resignColor });
- this.resignProcess(this.refs.gridControl.state.webPlayer);
- }
-
- clickResignCancel() {
- this.refs.gridControl.setState({ overlay: false });
- }
-
- resign() {
- let users = this.refs.gridControl.refs.userControl,
- activePlayer = users.state.activePlayer ? 'blue' : 'red';
-
- if (this.refs.gridControl.state.webPlayer === activePlayer) {
- this.refs.gridControl.setState({
- overlay: true,
- overlayTitle: 'Are u sure u want to resign?!',
- overlaySubTitle: (
-
- ),
- });
- }
- }
-
- // ------------------------------------------------------------------ //
- // Mercure message handlers (same logic as former WAMP callbacks)
- // ------------------------------------------------------------------ //
-
- wSubscribe(payload, rpcUsers = null) {
- 'dev' === this.state.env && console.info(
- ('undefined' !== typeof payload.user ? payload.user : 'user') + ' has been subscribed to the channel!',
- );
-
- let firstUser = !rpcUsers;
-
- null === this.refs.gridControl.state.webPlayer && this.refs.gridControl.setState({
- webPlayer: payload.user === payload.users.blue
- || (
- firstUser && '' !== payload.users.blueAnon
- || !firstUser && ('' === rpcUsers.blueAnon && '' === rpcUsers.blue)
- )
- ? 'blue' : 'red',
- });
-
- (900 > $(document).width()) && this.currectGridSize();
-
- if (
- 2 === payload.userCnt
- && (
- !this.state.connectionLost
- || this.state.connectionLost && false === this.refs.gridControl.refs.userControl.state.activePlayer && !this.state.end
- )
- ) {
- this.makeGameStart(payload);
- }
- }
-
- wUnsubscribe(payload) {
- 'dev' === this.state.env && console.info(payload.msg);
-
- this.refs.gridControl.setState({
- overlay: true,
- overlayTitle: 'The connection has been lost w/ your friend...',
- overlaySubTitle: 'Please, restart the game!',
- });
- }
-
- /**
- * Opponent's step arrived via Mercure — apply the server-resolved revealed cells.
- */
- wTopic(payload) {
- if (this.refs.gridControl.state.webPlayer !== payload.data.player) {
- if (null === payload.data.resign) {
- 'dev' === this.state.env && console.warn(
- payload.user + ' stepped to ' + payload.data.coords[0] + ',' + payload.data.coords[1],
- );
-
- this.refs.gridControl.refs.userControl.setState({ bombSelected: payload.data.bomb });
- this.refs.gridControl.applyStep(payload.data);
- this.makeGameEndIfItEnds(payload.data.bluePoints, payload.data.redPoints, false, payload.data.leftMines);
- } else {
- this.resignProcess(payload.data.resign);
- }
- }
- }
-
- // ------------------------------------------------------------------ //
- // Mercure / SSE connection
- // ------------------------------------------------------------------ //
-
- handleMercureMessage(payload) {
- let isTopicEvent = 'undefined' !== typeof payload.data;
- let isNotUnsubscribe = 'undefined' === typeof payload.msg;
-
- if (isTopicEvent) {
- this.wTopic(payload);
- } else if (isNotUnsubscribe) {
- this.wSubscribe(payload, this.rpcUsers);
- } else {
- this.wUnsubscribe(payload);
- }
-
- /** Reconnection: replay cached steps once both players are back */
- if (2 === payload.userCnt && this.state.connectionLost) {
- 'dev' === this.state.env && console.info('Reconnection process');
-
- let cache = this.state.stepCache;
- cache.forEach(item => this.publishStep(item));
- this.setState({ connectionLost: false, stepCache: [] });
- }
- }
-
- openEventSource() {
- const wrapper = document.getElementById('mine-wrapper');
- const hubUrl = wrapper.dataset.mercureHubUrl;
- const subscriberJwt = wrapper.dataset.mercureSubscriberJwt;
-
- const url = new URL(hubUrl, window.location.origin);
- url.searchParams.append('topic', this.state.channel);
- if (subscriberJwt) {
- url.searchParams.append('authorization', subscriberJwt);
- }
-
- if (this.eventSource) {
- this.eventSource.close();
- }
-
- this.eventSource = new EventSource(url.toString());
-
- this.eventSource.onmessage = event => {
- this.handleMercureMessage(JSON.parse(event.data));
- };
-
- this.eventSource.onopen = () => {
- 'dev' === this.state.env && console.info('SSE connection opened');
-
- if (this.state.connectionLost) {
- 'dev' === this.state.env && console.info('SSE reconnected — rejoining channel');
- this.joinGame();
- }
- };
-
- this.eventSource.onerror = () => {
- 'dev' === this.state.env && console.error('SSE connection error / lost');
- this.setState({ connectionLost: true });
- };
- }
-
- /**
- * Initialise the grid control with an empty 16×16 grid.
- * For inherited games, previously revealed cells are applied after the grid renders.
- */
- wInit(revealedCells = []) {
- // 16×16 grid of null — cells are filled in lazily as they are revealed by the server
- let emptyGrid = Array.from({ length: 16 }, () => Array(16).fill(null));
-
- this.refs.gridControl.setState({
- grid: emptyGrid,
- channel: this.state.channel,
- desc: {
- buddy: (
-
- Your buddy is
- making a
- move.
-
- ),
- you: (
-
- It is your turn!
- Make a move.
-
- ),
- },
- overlay: true,
- overlayTitle: 'We are waiting for your opponent...',
- overlaySubTitle: this.state.gameAssoc
- ? (
-
-
Share this unique link w/ your opponent
-
-
-
-
Play w/ me!
-
- ) : '',
- renderGridFields: this.state.gameAssoc,
- }, () => {
- // After the grid fields are rendered, apply any historically revealed cells
- revealedCells.forEach(cell => this.refs.gridControl.applyRevealedCell(cell, cell.player));
- });
- }
-
- makeGameStart(payload) {
- this.refs.gridControl.refs.userControl.setState({ activePlayer: 1 });
-
- this.refs.gridControl.refs.userControl.refs.red.setState({
- name: '' !== payload.users.red ? payload.users.red : payload.users.redAnon,
- });
-
- this.refs.gridControl.refs.userControl.refs.blue.setState({
- name: '' !== payload.users.blue ? payload.users.blue : payload.users.blueAnon,
- desc: 'blue' === this.refs.gridControl.state.webPlayer
- ? this.refs.gridControl.state.desc.you
- : this.refs.gridControl.state.desc.buddy,
- active: true,
- });
-
- this.refs.gridControl.setState({ overlay: false });
- }
-
- /** POST /api/game/join — register this player, broadcast subscription event via Mercure */
- joinGame() {
- return fetch('/api/game/join/' + this.state.gameAssoc, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- }).catch(e => 'dev' === this.state.env && console.error('Join error', e));
- }
-
- /** POST /api/game/step — persist a move, fan it out via Mercure, and return revealed cells */
- publishStep(dataPack) {
- return fetch('/api/game/step/' + this.state.gameAssoc, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(dataPack),
- });
- }
-
- // ------------------------------------------------------------------ //
- // Lifecycle
- // ------------------------------------------------------------------ //
-
- async componentDidMount() {
- if (!this.state.connectionLost) {
- try {
- if (this.state.gameInherited) {
- /** Fetch existing player info and previously revealed cells */
- const resp = await fetch('/api/game/connect/' + this.state.gameAssoc);
- const b64 = await resp.text();
- const serverData = JSON.parse(window.atob(b64));
-
- if ('undefined' === typeof serverData.users || null === serverData.users) {
- this.refs.gridControl.setState({
- overlay: true,
- overlayTitle: 'This channel does not exists!',
- overlaySubTitle: Restart game!,
- });
- console.error('This channel does not exists!');
- return;
- }
-
- this.rpcUsers = serverData.users;
- this.openEventSource();
- this.wInit(serverData.revealedCells || []);
-
- } else {
- /** Create the game record — the server generates the grid */
- await fetch('/api/game/start', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ gameAssoc: this.state.gameAssoc }),
- });
-
- this.openEventSource();
- this.wInit();
- }
-
- 'dev' === this.state.env && console.info('Connection initialised — joining channel');
- await this.joinGame();
-
- } catch (e) {
- 'dev' === this.state.env && console.error('Connection error', e);
- setTimeout(() => this.componentDidMount(), 500);
- }
-
- } else {
- /** Hard-reconnect path */
- this.openEventSource();
- }
-
- /** Notify the server when the player closes / navigates away */
- window.addEventListener('pagehide', () => {
- navigator.sendBeacon('/api/game/leave/' + this.state.gameAssoc);
- });
- }
-
- cachePublish(dataPack) {
- let cache = this.state.stepCache;
- cache.push(dataPack);
- this.setState({ stepCache: cache });
- }
-
- async onClick(coords) {
- let activePlayer = this.refs.gridControl.refs.userControl.state.activePlayer ? 'blue' : 'red';
-
- if (!this.refs.gridControl.checkFieldHasBeenNeverClicked(coords[0], coords[1])) {
- return;
- }
-
- if (activePlayer !== this.refs.gridControl.state.webPlayer) {
- return;
- }
-
- let dataPack = {
- coords: coords,
- player: activePlayer,
- bomb: this.refs.gridControl.refs.userControl.state.bombSelected,
- resign: null,
- };
-
- if (this.state.connectionLost) {
- this.cachePublish(dataPack);
- return;
- }
-
- try {
- const resp = await this.publishStep(dataPack);
- const result = await resp.json();
-
- this.refs.gridControl.applyStep(result);
- this.makeGameEndIfItEnds(result.bluePoints, result.redPoints, false, result.leftMines);
- } catch (e) {
- 'dev' === this.state.env && console.error('Step error', e);
- }
- }
-
- render() {
- return (
-
- );
- }
-}
-
-export default MineSeeker;
diff --git a/assets/js/mine-seeker/components/GameBoard.jsx b/assets/js/mine-seeker/components/GameBoard.jsx
new file mode 100644
index 0000000..5b060f6
--- /dev/null
+++ b/assets/js/mine-seeker/components/GameBoard.jsx
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the SplendidBear Websites' projects.
+ *
+ * Copyright (c) 2026 @ www.splendidbear.org
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import React from 'react';
+import { useGame } from '../contexts/GameContext';
+import useServerComm from '../hooks/useServerComm';
+import GridControl from './grid/GridControl';
+
+export const GameBoard = ({ gameAssoc, gameInherited, isEnvDev }) => {
+ const { gridReady } = useGame();
+ const { onClick, resign } = useServerComm(gameAssoc, gameInherited, isEnvDev);
+
+ if (!gridReady) {
+ return (
+
+ );
+ }
+
+ return ;
+};
diff --git a/assets/js/mine-seeker/components/grid/GridControl.jsx b/assets/js/mine-seeker/components/grid/GridControl.jsx
new file mode 100644
index 0000000..4f95d1e
--- /dev/null
+++ b/assets/js/mine-seeker/components/grid/GridControl.jsx
@@ -0,0 +1,69 @@
+import React from 'react';
+import { useGame } from '../../contexts/GameContext';
+import GridField from './GridField';
+import UserControl from '../user/UserControl';
+import { BOMB_SYMBOLS, bombRadius } from '../../constants';
+
+const GridControl = ({ onClick, resign }) => {
+ const {
+ overlay, overlayTitle, overlaySubTitle,
+ webPlayer, activePlayer, mines, foundMines, bombSelected,
+ red, blue, cells, setCells, onBombToggle,
+ } = useGame();
+
+ const handleHover = (row, col) => {
+ if (!bombSelected) return;
+ const activeColor = activePlayer ? 'blue' : 'red';
+ if (activeColor !== webPlayer) return;
+
+ setCells(prev => {
+ const next = prev.map(r => r.map(c =>
+ null !== c.bombTargetArea ? { ...c, bombTargetArea: null } : c,
+ ));
+ bombRadius(row, col, prev.length, prev[0]?.length ?? 0).forEach(([r, c], i) => {
+ if (!next[r]?.[c]) return;
+
+ next[r] = [...next[r]];
+ next[r][c] = { ...next[r][c], bombTargetArea: BOMB_SYMBOLS[i] };
+ });
+ return next;
+ });
+ };
+
+ return (
+
+
+
+
{overlayTitle}
+ {overlaySubTitle}
+
+
+
+
+
+ {cells.flatMap((row, r) =>
+ row.map((cell, c) => (
+ onClick([r, c])}
+ onMouseEnter={() => handleHover(r, c)}
+ />
+ ))
+ )}
+
+
+
+ );
+};
+
+export default GridControl;
diff --git a/assets/js/mine-seeker/components/grid/GridField.jsx b/assets/js/mine-seeker/components/grid/GridField.jsx
new file mode 100644
index 0000000..a22896e
--- /dev/null
+++ b/assets/js/mine-seeker/components/grid/GridField.jsx
@@ -0,0 +1,45 @@
+import React, { memo } from 'react';
+import { IMG } from '../../constants';
+
+const bombSrc = area => {
+ if (null === area) return null;
+ const vert = ['left', 'center', 'right'][area[0]] ?? null;
+ const hor = ['top', 'middle', 'bottom'][area[1]] ?? null;
+ if (null === vert || null === hor) return IMG + 'bg-bomb-empty-outbg.png';
+ return `${IMG}bg-bomb-${hor}-${vert}-outbg.png`;
+};
+
+const GridField = memo(function GridField({ cell, onClick, onMouseEnter }) {
+ const { currentImage, currentObj, active, lastClickedRed, lastClickedBlue, bombTargetArea } = cell;
+
+ const fieldClass = 'field'
+ + (active ? ' active' : '')
+ + (active && 'm' === currentObj ? ' mine' : '')
+ + ' color-' + currentObj;
+
+ const inner = isNaN(currentImage)
+ ? (
+ 
+
+
+ )
+ : currentImage ? {currentImage}
: null;
+
+ const bSrc = bombSrc(bombTargetArea);
+ const showLast = lastClickedRed || lastClickedBlue;
+ const lastClass = 'field-' + (lastClickedRed ? 'red' : 'blue') + '-last last-clicked';
+ const lastSrc = lastClickedRed ? IMG + 'bg-last-red-outbg.png' : IMG + 'bg-last-blue-outbg.png';
+
+ return (
+
+

+ {bSrc &&

}
+ {showLast &&

}
+
+
+ );
+});
+
+export default GridField;
diff --git a/assets/js/mine-seeker/components/user/User.jsx b/assets/js/mine-seeker/components/user/User.jsx
new file mode 100644
index 0000000..eb55adc
--- /dev/null
+++ b/assets/js/mine-seeker/components/user/User.jsx
@@ -0,0 +1,39 @@
+import React, { memo } from 'react';
+
+const SRC = '/images/';
+
+const User = memo(function User({
+ color, webPlayer,
+ name, desc, active, mines, haveBomb, enabledBomb,
+ onClickBombSelector,
+}) {
+ const buzzClass = 'bomb-container'
+ + (active && color === webPlayer && haveBomb && enabledBomb ? ' buzz' : '');
+
+ const bombImg = haveBomb
+ ? SRC + (enabledBomb && active ? 'bg-bomb-outbg.png' : 'bg-bomb-disabled-outbg.png')
+ : SRC + 'bg-bomb-exploded-outbg.png';
+
+ return (
+
+
+
{color}
+ {active &&

}
+

+
+
{name}
+
+
{desc}
+
+

+
{mines}
+
+
+
+
+ );
+});
+
+export default User;
diff --git a/assets/js/mine-seeker/components/user/UserControl.jsx b/assets/js/mine-seeker/components/user/UserControl.jsx
new file mode 100644
index 0000000..3b591b6
--- /dev/null
+++ b/assets/js/mine-seeker/components/user/UserControl.jsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import User from './User';
+
+const UserControl = ({ webPlayer, activePlayer, mines, foundMines, red, blue, onBombToggle, resign }) => {
+ const activeColor = activePlayer ? 'blue' : 'red';
+ const resignClass = 'resign' + (activeColor !== webPlayer ? ' disabled' : '');
+ const minesClass = 'active-mines' + (foundMines ? ' found-mine' : '');
+
+ const handleBombClick = (color, player) => {
+ const p = 'red' === color ? red : blue;
+ if (p.haveBomb && p.enabledBomb && activePlayer === player) {
+ onBombToggle();
+ }
+ };
+
+ return (
+
+
handleBombClick('blue', 1)}
+ />
+
+
+ handleBombClick('red', 0)}
+ />
+
+
+ );
+}
+
+export default UserControl;
diff --git a/assets/js/mine-seeker/constants.js b/assets/js/mine-seeker/constants.js
new file mode 100644
index 0000000..368eccf
--- /dev/null
+++ b/assets/js/mine-seeker/constants.js
@@ -0,0 +1,63 @@
+import React from 'react';
+
+export const ROWS = 16;
+export const COLS = 16;
+export const IMG = '/images/';
+
+export const WAVES = {
+ 1: 'bg-wave-1-outbg.png',
+ 2: 'bg-wave-1-outbg.png',
+ 3: 'bg-wave-2-outbg.png',
+};
+
+export const PLAYER_DEF = {
+ name: '...', desc: '', active: false, mines: 0, haveBomb: true, enabledBomb: true,
+};
+
+export const DESC = {
+ buddy: Your buddy is
making a
move.
,
+ you: It is your turn!
Make a move.
,
+};
+
+export const BOMB_SYMBOLS = [
+ [null, null], [0, 0], [1, 0], [2, 0], [0, 1], [2, 1], [0, 2], [1, 2], [2, 2],
+ [null, null], [null, null], [null, null], [null, null], [null, null], [null, null], [null, null],
+ [null, null], [null, null], [null, null], [null, null], [null, null], [null, null], [null, null],
+ [null, null], [null, null],
+];
+
+export const bombRadius = (row, col, rows, cols) => {
+ const centre = 1 < row && row < rows - 2 && 1 < col && col < cols - 2;
+ if (!centre) {
+ col = Math.max(2, Math.min(col, cols - 3));
+ row = Math.max(2, Math.min(row, rows - 3));
+ }
+ return [
+ [row, col], [row - 2, col - 2], [row - 2, col], [row - 2, col + 2],
+ [row, col - 2], [row, col + 2], [row + 2, col - 2], [row + 2, col],
+ [row + 2, col + 2], [row - 2, col + 1], [row - 2, col - 1],
+ [row - 1, col - 2], [row - 1, col - 1], [row - 1, col], [row - 1, col + 1], [row - 1, col + 2],
+ [row, col - 1], [row, col + 1], [row + 1, col - 2], [row + 1, col - 1], [row + 1, col],
+ [row + 1, col + 1], [row + 1, col + 2], [row + 2, col - 1], [row + 2, col + 1],
+ ];
+};
+
+export const patchCells = (prev, patches) => {
+ const next = prev.map(r => [...r]);
+ for (const { row, col, ...rest } of patches) {
+ next[row][col] = { ...next[row][col], ...rest };
+ }
+ return next;
+};
+
+export const initCells = () =>
+ Array.from({ length: ROWS }, () =>
+ Array.from({ length: COLS }, () => ({
+ currentImage: IMG + WAVES[Math.floor(Math.random() * 3) + 1],
+ currentObj: 'w',
+ active: false,
+ lastClickedRed: false,
+ lastClickedBlue: false,
+ bombTargetArea: null,
+ })),
+ );
diff --git a/assets/js/mine-seeker/contexts/GameContext.jsx b/assets/js/mine-seeker/contexts/GameContext.jsx
new file mode 100644
index 0000000..3c8f4a3
--- /dev/null
+++ b/assets/js/mine-seeker/contexts/GameContext.jsx
@@ -0,0 +1,233 @@
+import React, { createContext, useContext, useRef, useState } from 'react';
+import { Howl } from 'howler';
+import { IMG, PLAYER_DEF, DESC, patchCells, initCells } from '../constants';
+
+// ── Context ──────────────────────────────────────────────────────────────────
+
+const GameContext = createContext(null);
+
+export const useGame = () => useContext(GameContext);
+
+// ── Provider ─────────────────────────────────────────────────────────────────
+
+export const GameProvider = ({ children }) => {
+ // Refs that are read inside async callbacks (stay in sync with state via sync* helpers)
+ const webPlayerRef = useRef(null);
+ const activePlayerRef = useRef(false);
+ const bombSelectedRef = useRef(false);
+ const connectionLostRef = useRef(false);
+ const redRef = useRef({ ...PLAYER_DEF });
+ const blueRef = useRef({ ...PLAYER_DEF });
+ const lastClickedRef = useRef({ red: null, blue: null });
+ const endRef = useRef(false);
+
+ const sounds = useRef({
+ click: new Howl({ src: ['/sound/click.mp3'] }),
+ bomb: new Howl({ src: ['/sound/bomb.mp3'] }),
+ mine: new Howl({ src: ['/sound/mine.mp3'] }),
+ warning: new Howl({ src: ['/sound/warning.mp3'] }),
+ won: new Howl({ src: ['/sound/won.mp3'] }),
+ });
+
+ // Display state
+ const [webPlayer, setWebPlayer] = useState(null);
+ const [activePlayer, setActivePlayer] = useState(false);
+ const [overlay, setOverlay] = useState(true);
+ const [overlayTitle, setOverlayTitle] = useState('');
+ const [overlaySubTitle, setOverlaySubTitle] = useState('');
+ const [mines, setMines] = useState(51);
+ const [bombSelected, setBombSelected] = useState(false);
+ const [foundMines, setFoundMines] = useState(false);
+ const [red, setRed] = useState({ ...PLAYER_DEF });
+ const [blue, setBlue] = useState({ ...PLAYER_DEF });
+ const [cells, setCells] = useState(initCells);
+ const [gridReady, setGridReady] = useState(false);
+ const [connectionLost, setConnectionLost] = useState(false);
+
+ // ── Sync helpers (keep ref + state in lockstep) ──────────────────────────
+ const syncWebPlayer = v => {
+ webPlayerRef.current = v;
+ setWebPlayer(v);
+ };
+ const syncActivePlayer = v => {
+ activePlayerRef.current = v;
+ setActivePlayer(v);
+ };
+ const syncBombSelected = v => {
+ bombSelectedRef.current = v;
+ setBombSelected(v);
+ };
+ const syncConnLost = v => {
+ connectionLostRef.current = v;
+ setConnectionLost(v);
+ };
+ const syncRed = fn => {
+ const n = fn(redRef.current);
+ redRef.current = n;
+ setRed(n);
+ };
+ const syncBlue = fn => {
+ const n = fn(blueRef.current);
+ blueRef.current = n;
+ setBlue(n);
+ };
+
+ // ── Overlay ───────────────────────────────────────────────────────────────
+ const showOverlay = (title, sub) => {
+ setOverlay(true);
+ setOverlayTitle(title);
+ setOverlaySubTitle(sub);
+ };
+
+ const hideOverlay = () => setOverlay(false);
+
+ // ── Cell helpers ──────────────────────────────────────────────────────────
+ const applyRevealedCell = (cell, player, isMainCell = false) => {
+ const { row, col, value } = cell;
+ setCells(prev => {
+ if (prev[row][col].active) return prev;
+ const patch = 'm' === value
+ ? { currentImage: `${IMG}bg-flag-${player}-outbg.png`, currentObj: 'm', active: true }
+ : { currentImage: value, currentObj: value, active: true };
+ if (isMainCell) {
+ patch.lastClickedRed = 'red' === player;
+ patch.lastClickedBlue = 'blue' === player;
+ }
+ return patchCells(prev, [{ row, col, ...patch }]);
+ });
+ if (isMainCell) lastClickedRef.current = { ...lastClickedRef.current, [player]: [row, col] };
+ };
+
+ const showLeftMines = (leftMines = []) => {
+ if (!leftMines.length) return;
+ setCells(prev => {
+ const patches = leftMines
+ .filter(({ row, col }) => !prev[row][col].active)
+ .map(({ row, col }) => ({ row, col, currentImage: IMG + 'bg-left-mine-outbg.png' }));
+ return patches.length ? patchCells(prev, patches) : prev;
+ });
+ };
+
+ // ── Game logic ────────────────────────────────────────────────────────────
+ const changePlayer = () => {
+ const wasColor = activePlayerRef.current ? 'blue' : 'red';
+ const nextColor = activePlayerRef.current ? 'red' : 'blue';
+ const nextVal = activePlayerRef.current ? 0 : 1;
+ const desc = wasColor === webPlayerRef.current ? DESC.buddy : DESC.you;
+
+ syncActivePlayer(nextVal);
+ syncRed(p => ({ ...p, active: 'red' === nextColor, desc: 'red' === nextColor ? desc : '' }));
+ syncBlue(p => ({ ...p, active: 'blue' === nextColor, desc: 'blue' === nextColor ? desc : '' }));
+ };
+
+ const applyStep = stepData => {
+ const { player, bomb: isBomb, minesFound = 0, revealedCells = [], redPoints: rp, bluePoints: bp } = stepData;
+
+ if (isBomb) {
+ sounds.current.bomb.play();
+ } else if (0 < minesFound) {
+ const cur = ('red' === player ? redRef : blueRef).current.mines;
+ sounds.current[20 < cur + minesFound ? 'warning' : 'mine'].play();
+ } else {
+ sounds.current.click.play();
+ }
+
+ const lc = lastClickedRef.current[player];
+ setCells(prev => {
+ let next = prev;
+ if (lc) next = patchCells(next, [{ row: lc[0], col: lc[1], lastClickedRed: false, lastClickedBlue: false }]);
+
+ revealedCells.forEach(({ row, col, value }, idx) => {
+ if (next[row][col].active) return;
+ const patch = 'm' === value
+ ? { currentImage: `${IMG}bg-flag-${player}-outbg.png`, currentObj: 'm', active: true }
+ : { currentImage: value, currentObj: value, active: true };
+ if (0 === idx) {
+ patch.lastClickedRed = 'red' === player;
+ patch.lastClickedBlue = 'blue' === player;
+ }
+ next = patchCells(next, [{ row, col, ...patch }]);
+ });
+
+ if (isBomb) next = next.map(r => r.map(c => null !== c.bombTargetArea ? { ...c, bombTargetArea: null } : c));
+ return next;
+ });
+
+ if (0 < revealedCells.length) {
+ lastClickedRef.current = { ...lastClickedRef.current, [player]: [revealedCells[0].row, revealedCells[0].col] };
+ }
+
+ if (0 < minesFound) {
+ setMines(51 - rp - bp);
+ setFoundMines(true);
+ setTimeout(() => setFoundMines(false), 500);
+ syncRed(p => ({ ...p, mines: 'red' === player ? rp : p.mines }));
+ syncBlue(p => ({ ...p, mines: 'blue' === player ? bp : p.mines }));
+ }
+
+ syncRed(p => ({ ...p, enabledBomb: rp <= bp }));
+ syncBlue(p => ({ ...p, enabledBomb: bp <= rp }));
+
+ if (isBomb || 0 === minesFound) changePlayer();
+
+ if (isBomb) {
+ syncBombSelected(false);
+ syncRed(p => 'red' === player ? { ...p, haveBomb: false } : p);
+ syncBlue(p => 'blue' === player ? { ...p, haveBomb: false } : p);
+ }
+ };
+
+ const makeGameEndIfItEnds = (bluePoints, redPoints, resign = false, leftMines = []) => {
+ const redWins = 25 < redPoints;
+ const blueWins = 25 < bluePoints;
+
+ if (redWins || blueWins || resign) {
+ sounds.current.won.play();
+
+ if (!resign) showOverlay((redWins ? 'Red' : 'Blue') + ' wins the game!', 'Play again!');
+
+ showLeftMines(leftMines);
+ syncActivePlayer(false);
+ syncRed(p => ({ ...p, desc: '' }));
+ syncBlue(p => ({ ...p, desc: '' }));
+ }
+ };
+
+ const resignProcess = color => {
+ const wp = webPlayerRef.current;
+ showOverlay(
+ color === wp ? 'You have been give up' : 'Your opponent has been resigned',
+ color === wp ? 'You LOSE!' : 'You WIN!',
+ );
+ endRef.current = true;
+ makeGameEndIfItEnds(0, 0, true);
+ };
+
+ const onBombToggle = () => {
+ const next = !bombSelectedRef.current;
+ syncBombSelected(next);
+ if (!next) {
+ setCells(prev => prev.map(r => r.map(c => null !== c.bombTargetArea ? { ...c, bombTargetArea: null } : c)));
+ }
+ };
+
+ // ── Context value ─────────────────────────────────────────────────────────
+ const value = {
+ // State (for rendering)
+ webPlayer, activePlayer, overlay, overlayTitle, overlaySubTitle,
+ mines, bombSelected, foundMines, red, blue, cells, gridReady, connectionLost,
+ // Refs (needed by useServerComm for async-safe reads)
+ webPlayerRef, activePlayerRef, bombSelectedRef, connectionLostRef, endRef,
+ // Setters needed by useServerComm
+ setCells, setGridReady,
+ syncWebPlayer, syncActivePlayer, syncBombSelected, syncConnLost, syncRed, syncBlue,
+ // Game logic called by useServerComm
+ showOverlay, hideOverlay,
+ applyRevealedCell, applyStep,
+ makeGameEndIfItEnds, resignProcess,
+ // UI action (bomb toggle is pure state, no server call)
+ onBombToggle,
+ };
+
+ return {children};
+};
diff --git a/assets/js/mine-seeker/grid/grid-control.js b/assets/js/mine-seeker/grid/grid-control.js
deleted file mode 100644
index 449c497..0000000
--- a/assets/js/mine-seeker/grid/grid-control.js
+++ /dev/null
@@ -1,301 +0,0 @@
-import React from 'react';
-import GridField from './grid-field';
-import UserControl from '../user/user-control';
-import { Howl } from 'howler';
-
-class GridControl extends React.Component {
- constructor(props) {
- super(props);
-
- let click = new Howl({ src: ['/sound/click.mp3'] }),
- bomb = new Howl({ src: ['/sound/bomb.mp3'] }),
- mine = new Howl({ src: ['/sound/mine.mp3'] }),
- warning = new Howl({ src: ['/sound/warning.mp3'] }),
- won = new Howl({ src: ['/sound/won.mp3'] });
-
- this.state = {
- env: props.env,
- webPlayer: null,
- grid: null,
- desc: null,
- renderGridFields: false,
- gridFields: [],
- bombFieldCache: [],
- overlay: false,
- overlayTitle: '',
- overlaySubTitle: '',
- sound: {
- click: click,
- bomb: bomb,
- mine: mine,
- warning: warning,
- won: won,
- },
- lastClicked: {
- red: null,
- blue: null,
- },
- };
- }
-
- refString(row, col) {
- return 'gridField_' + row + '_' + col;
- }
-
- checkFieldHasBeenNeverClicked(row, col) {
- return !this.refs[this.refString(row, col)].state.active;
- }
-
- getBombRadius(row, col) {
- let isBombTargetCenter = 1 < row && row < this.state.grid.length - 2 && 1 < col && col < this.state.grid[row].length - 2;
-
- if (!isBombTargetCenter) {
- col = 2 > col ? 2 : col;
- row = 2 > row ? 2 : row;
- row = row > this.state.grid.length - 3 ? this.state.grid.length - 3 : row;
- col = col > this.state.grid[0].length - 3 ? this.state.grid[0].length - 3 : col;
- }
-
- return [
- [row, col], [row - 2, col - 2], [row - 2, col], [row - 2, col + 2], [row, col - 2], [row, col + 2],
- [row + 2, col - 2], [row + 2, col], [row + 2, col + 2], [row - 2, col + 1], [row - 2, col - 1],
- [row - 1, col - 2], [row - 1, col - 1], [row - 1, col], [row - 1, col + 1], [row - 1, col + 2],
- [row, col - 1], [row, col + 1], [row + 1, col - 2], [row + 1, col - 1], [row + 1, col],
- [row + 1, col + 1], [row + 1, col + 2], [row + 2, col - 1], [row + 2, col + 1],
- ];
- }
-
- getBombFieldRadius() {
- return [
- [null, null], [0, 0], [1, 0], [2, 0], [0, 1], [2, 1], [0, 2], [1, 2], [2, 2],
- [null, null], [null, null], [null, null], [null, null], [null, null], [null, null], [null, null],
- [null, null], [null, null], [null, null], [null, null], [null, null], [null, null], [null, null],
- [null, null], [null, null],
- ];
- }
-
- bombClear() {
- if (this.state.bombFieldCache.length) {
- for (var i = 0, j = this.state.bombFieldCache.length; i < j; i++) {
- var cacheItem = this.state.bombFieldCache[i];
- this.refs[this.refString(cacheItem[0], cacheItem[1])]
- .setState({ bombTargetArea: null });
- }
- this.state.bombFieldCache = [];
- }
- }
-
- bombCreate(row, col) {
- var bombFieldSymbols = this.getBombFieldRadius(),
- bombFields = this.getBombRadius(row, col);
-
- for (var i = 0, j = bombFields.length; i < j; i++) {
- this.state.bombFieldCache.push(bombFields[i]);
-
- this.refs[this.refString(bombFields[i][0], bombFields[i][1])]
- .setState({ bombTargetArea: bombFieldSymbols[i] });
- }
- }
-
- /**
- * Show unrevealed mines at the end of the game.
- * leftMines comes from the server and contains only cells not yet revealed.
- */
- showLeftMines(leftMines = []) {
- for (let mine of leftMines) {
- let currentField = this.refs[this.refString(mine.row, mine.col)];
- if (currentField && !currentField.state.active) {
- currentField.setState({
- currentImage: currentField.state.icons.root + currentField.state.icons.left,
- });
- }
- }
- }
-
- /** set __ACTIVE__ player in the UserControl */
- changePlayer() {
- var userControl = this.refs.userControl,
- activePlayer = userControl.state.activePlayer ? 'blue' : 'red',
- inactivePlayer = userControl.state.activePlayer ? 'red' : 'blue';
-
- userControl.setState({ activePlayer: userControl.state.activePlayer ? 0 : 1 });
-
- userControl.refs[activePlayer].setState({ active: false, desc: '' });
- userControl.refs[inactivePlayer].setState({
- active: true,
- desc: activePlayer === this.state.webPlayer
- ? this.state.desc.buddy
- : this.state.desc.you,
- });
- }
-
- /**
- * Apply a single revealed cell to the grid UI.
- * Called both for live steps and when reconstructing the board for a joining player.
- *
- * @param {object} cell - { row, col, value } value is 'm' | 0-8
- * @param {string} player - 'red' | 'blue'
- * @param {boolean} isMainCell - true for the primary clicked cell (sets last-clicked highlight)
- */
- applyRevealedCell(cell, player, isMainCell = false) {
- let ref = this.refs[this.refString(cell.row, cell.col)];
- if (!ref || ref.state.active) {
- return;
- }
-
- if ('m' === cell.value) {
- ref.setState({
- currentImage: ref.state.icons.root + ref.state.icons.flag[player],
- currentObj: 'm',
- active: true,
- });
- } else {
- ref.setState({
- currentImage: cell.value,
- currentObj: cell.value,
- active: true,
- });
- }
-
- if (isMainCell) {
- this.state.lastClicked[player] = [cell.row, cell.col];
- ref.setState({
- lastClickedRed: 'red' === player,
- lastClickedBlue: 'blue' === player,
- });
- }
- }
-
- /**
- * Apply a full step response from the server.
- * stepData shape: { coords, player, bomb, revealedCells, minesFound, redPoints, bluePoints, resign, gameOver,
- * leftMines }
- */
- applyStep(stepData) {
- let player = stepData.player;
- let isBomb = stepData.bomb;
- let minesFound = stepData.minesFound || 0;
- let revealedCells = stepData.revealedCells || [];
-
- // Reset previous last-clicked highlight for this player
- let lastClicked = this.state.lastClicked[player];
- if (lastClicked) {
- let lastRef = this.refs[this.refString(lastClicked[0], lastClicked[1])];
- if (lastRef) {
- lastRef.setState({ lastClickedRed: false, lastClickedBlue: false });
- }
- }
-
- // Sound
- if (isBomb) {
- this.state.sound.bomb.play();
- } else if (0 < minesFound) {
- let currentMines = this.refs.userControl.refs[player].state.mines;
- this.state.sound[20 < (currentMines + minesFound) ? 'warning' : 'mine'].play();
- } else {
- this.state.sound.click.play();
- }
-
- // Apply each revealed cell; first cell gets the last-clicked highlight
- revealedCells.forEach((cell, idx) => {
- this.applyRevealedCell(cell, player, 0 === idx);
- });
-
- // Update scores
- let userControl = this.refs.userControl;
- let inactivePlayer = 'red' === player ? 'blue' : 'red';
-
- if (0 < minesFound) {
- userControl.setState({
- mines: 51 - stepData.redPoints - stepData.bluePoints,
- foundMines: true,
- }, () => {
- setTimeout(() => userControl.setState({ foundMines: false }), 500);
- userControl.refs[player].setState({
- mines: 'red' === player ? stepData.redPoints : stepData.bluePoints,
- });
- });
- }
-
- // Bomb-enabled status: a player may use their bomb when their score <= opponent's
- userControl.refs.red.setState({ enabledBomb: stepData.redPoints <= stepData.bluePoints });
- userControl.refs.blue.setState({ enabledBomb: stepData.bluePoints <= stepData.redPoints });
-
- // Change active player: always after a bomb, or when no mine was found on a normal click
- if (isBomb || 0 === minesFound) {
- this.changePlayer();
- }
-
- // Clean up bomb state
- if (isBomb) {
- userControl.setState({ bombSelected: false });
- userControl.refs[player].setState({ haveBomb: false });
- this.bombClear();
- }
- }
-
- /**
- * On Hover when you want to drop BOMB — show target area overlay
- */
- onHoverGridField(coords) {
- if (this.refs.userControl.state.bombSelected) {
- var activePlayer = this.refs.userControl.state.activePlayer ? 'blue' : 'red';
-
- if (activePlayer === this.state.webPlayer) {
- this.bombClear();
- this.bombCreate(coords[0], coords[1]);
- } else {
- this.refs.userControl.setState({ bombSelected: false });
- }
- }
- }
-
- renderGridFields() {
- for (let i = 0, j = this.state.grid.length; i < j; i++) {
- for (let k = 0, l = this.state.grid[i].length; k < l; k++) {
- this.state.gridFields.push(
- ,
- );
- }
- }
- }
-
- render() {
- /** Render the grid fields just one time in one party #12 */
- this.state.renderGridFields && this.renderGridFields();
- this.state.renderGridFields = false;
-
- return (
-
-
-
-
{this.state.overlayTitle}
- {this.state.overlaySubTitle}
-
-
-
-
-
- <>
- {this.state.gridFields}
- >
-
-
-
- );
- }
-}
-
-export default GridControl;
diff --git a/assets/js/mine-seeker/grid/grid-field.js b/assets/js/mine-seeker/grid/grid-field.js
deleted file mode 100644
index 497e0c7..0000000
--- a/assets/js/mine-seeker/grid/grid-field.js
+++ /dev/null
@@ -1,156 +0,0 @@
-import React from 'react';
-
-class GridField extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- currentObj: 'w',
- currentImage: null,
- active: false,
- lastClickedRed: false,
- lastClickedBlue: false,
- bombTargetArea: null,
- icons: {
- root: '/images/',
- water: {
- 1: 'bg-wave-1-outbg.png',
- 2: 'bg-wave-1-outbg.png',
- 3: 'bg-wave-2-outbg.png',
- },
- flag: {
- red: 'bg-flag-red-outbg.png',
- blue: 'bg-flag-blue-outbg.png',
- },
- target: {
- lastBlue: 'bg-last-blue-outbg.png',
- lastRed: 'bg-last-red-outbg.png',
- crosshair: 'bg-target-outbg.png',
- crosshairBomb: 'bg-target-bomb-outbg.png',
- },
- left: 'bg-left-mine-outbg.png',
- },
- };
- }
-
- componentWillMount() {
- var wave = Math.floor(Math.random() * 3) + 1;
-
- this.setState({
- currentImage: this.state.icons.root + this.state.icons.water[wave],
- });
- }
-
- classNameWhenActive() {
- return 'field'
- + (true === this.state.active ? ' active' : '')
- + (true === this.state.active && 'm' === this.state.currentObj ? ' mine' : '')
- + ' color-' + this.state.currentObj;
- }
-
- currentImage() {
- return isNaN(this.state.currentImage)
- ? (
-
-

-
-
- ) : this.state.currentImage ? {this.state.currentImage}
: '';
- }
-
- lastClickedClass() {
- return 'field-'
- + (this.state.lastClickedRed ? 'red' : '')
- + (this.state.lastClickedBlue ? 'blue' : '') + '-last last-clicked';
- }
-
- lastClickedSrc() {
- return this.state.lastClickedRed
- ? '/images/bg-last-red-outbg.png'
- : '/images/bg-last-blue-outbg.png';
- }
-
- currentLastClicked() {
- return this.state.lastClickedRed || this.state.lastClickedBlue
- ? (
-
- ) : '';
- }
-
- createBombTarget() {
- if (null !== this.state.bombTargetArea) {
- let vert, hor = '';
-
- switch (this.state.bombTargetArea[0]) {
- case 0:
- vert = 'left';
- break;
- case 1:
- vert = 'center';
- break;
- case 2:
- vert = 'right';
- break;
- default:
- vert = null;
- break;
- }
-
- switch (this.state.bombTargetArea[1]) {
- case 0:
- hor = 'top';
- break;
- case 1:
- hor = 'middle';
- break;
- case 2:
- hor = 'bottom';
- break;
- default:
- vert = null;
- break;
- }
-
- var src = null === vert
- ? '/images/bg-bomb-empty-outbg.png'
- : '/images/bg-bomb-' + hor + '-' + vert + '-outbg.png';
-
- return (
-
- );
- }
- }
-
- render() {
- return (
-
-

- {this.createBombTarget()}
- {this.currentLastClicked()}
-
-
- {this.currentImage()}
-
-
-
- );
- }
-}
-
-export default GridField;
diff --git a/assets/js/mine-seeker/hooks/useServerComm.js b/assets/js/mine-seeker/hooks/useServerComm.js
new file mode 100644
index 0000000..55731cc
--- /dev/null
+++ b/assets/js/mine-seeker/hooks/useServerComm.js
@@ -0,0 +1,264 @@
+import React, { useEffect, useRef } from 'react';
+import { useQuery, useMutation } from '@tanstack/react-query';
+import { useGame } from '../contexts/GameContext';
+import { DESC } from '../constants';
+
+/**
+ * Handles all server communication: SSE (Mercure), REST calls, and the
+ * initialization lifecycle. Exposes only the UI-facing callbacks the
+ * component needs: onClick, resign.
+ */
+const useServerComm = (gameAssoc, gameInherited, isEnvDev) => {
+ const {
+ // Async-safe refs
+ webPlayerRef, activePlayerRef, bombSelectedRef, connectionLostRef, endRef,
+ // State setters
+ setGridReady,
+ // Sync helpers
+ syncWebPlayer, syncActivePlayer, syncBombSelected, syncConnLost, syncRed, syncBlue,
+ // Game logic
+ showOverlay, hideOverlay,
+ applyRevealedCell, applyStep,
+ makeGameEndIfItEnds, resignProcess,
+ // Current cells snapshot (for active-check in onClick)
+ cells,
+ } = useGame();
+
+ const eventSourceRef = useRef(null);
+ const rpcUsersRef = useRef(null);
+ const stepCacheRef = useRef([]);
+
+ // ── Helpers ───────────────────────────────────────────────────────────────
+
+ const correctGridSize = () => {
+ let $f = $('#mine-wrapper .grid');
+ $f.height($f.width());
+ $f = $('#mine-wrapper .grid .field-wrapper');
+ $f.height($f.width());
+ $('#mine-wrapper .grid .field-wrapper .field').height($f.width()).css('line-height', ($f.width() - 2) + 'px');
+ };
+
+ // ── REST mutations / queries ──────────────────────────────────────────────
+
+ const connectQuery = useQuery({
+ queryKey: ['game-connect', gameAssoc],
+ queryFn: () => fetch('/api/game/connect/' + gameAssoc)
+ .then(r => r.text())
+ .then(b64 => JSON.parse(window.atob(b64))),
+ enabled: false,
+ retry: false,
+ });
+
+ const startMutation = useMutation({
+ mutationFn: () => fetch('/api/game/start', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ gameAssoc }),
+ }),
+ });
+
+ const joinMutation = useMutation({
+ mutationFn: () => fetch('/api/game/join/' + gameAssoc, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ }).catch(e => isEnvDev && console.error('Join error', e)),
+ });
+
+ const stepMutation = useMutation({
+ mutationFn: dataPack => fetch('/api/game/step/' + gameAssoc, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(dataPack),
+ }).then(r => r.json()),
+ });
+
+ // ── Game-start helpers (triggered by server events) ───────────────────────
+
+ const wInit = (revealedCells = []) => {
+ setGridReady(true);
+ showOverlay('We are waiting for your opponent...', gameAssoc ? (
+
+
Share this unique link w/ your opponent
+
+
+
+
Play w/ me!
+
+ ) : '');
+
+ setTimeout(() => revealedCells.forEach(cell => applyRevealedCell(cell, cell.player)), 0);
+ };
+
+ const makeGameStart = payload => {
+ syncActivePlayer(1);
+ syncRed(p => ({ ...p, name: payload.users.red || payload.users.redAnon || p.name }));
+ syncBlue(p => ({
+ ...p,
+ name: payload.users.blue || payload.users.blueAnon || p.name,
+ desc: 'blue' === webPlayerRef.current ? DESC.you : DESC.buddy,
+ active: true,
+ }));
+ hideOverlay();
+ };
+
+ // ── Mercure / SSE message handlers ───────────────────────────────────────
+
+ const wSubscribe = (payload, rpcUsers = null) => {
+ isEnvDev && console.info((payload.user ?? 'user') + ' subscribed');
+ const firstUser = !rpcUsers;
+
+ if (null === webPlayerRef.current) {
+ const isBlue = payload.user === payload.users.blue
+ || (firstUser ? '' !== payload.users.blueAnon : '' === rpcUsers.blueAnon && '' === rpcUsers.blue);
+ syncWebPlayer(isBlue ? 'blue' : 'red');
+ }
+
+ 900 > $(document).width() && correctGridSize();
+
+ if (
+ 2 === payload.userCnt
+ && (!connectionLostRef.current
+ || (connectionLostRef.current && false === activePlayerRef.current && !endRef.current))
+ ) {
+ makeGameStart(payload);
+ }
+ };
+
+ const wUnsubscribe = payload => {
+ isEnvDev && console.info(payload.msg);
+ showOverlay('The connection has been lost w/ your friend...', 'Please, restart the game!');
+ };
+
+ const wTopic = payload => {
+ if (webPlayerRef.current !== payload.data.player) {
+ if (null === payload.data.resign) {
+ isEnvDev && console.warn(payload.user + ' stepped to ' + payload.data.coords.join(','));
+ syncBombSelected(payload.data.bomb);
+ applyStep(payload.data);
+ makeGameEndIfItEnds(payload.data.bluePoints, payload.data.redPoints, false, payload.data.leftMines);
+ } else {
+ resignProcess(payload.data.resign);
+ }
+ }
+ };
+
+ const handleMercureMessage = payload => {
+ if (undefined !== payload.data) {
+ wTopic(payload);
+ } else if (undefined === payload.msg) {
+ wSubscribe(payload, rpcUsersRef.current);
+ } else {
+ wUnsubscribe(payload);
+ }
+
+ if (2 === payload.userCnt && connectionLostRef.current) {
+ isEnvDev && console.info('Reconnection');
+ stepCacheRef.current.forEach(item => stepMutation.mutate(item));
+ stepCacheRef.current = [];
+ syncConnLost(false);
+ }
+ };
+
+ const openEventSource = () => {
+ const wrapper = document.getElementById('mine-wrapper');
+ const hubUrl = wrapper.dataset.mercureHubUrl;
+ const subscriberJwt = wrapper.dataset.mercureSubscriberJwt;
+ const url = new URL(hubUrl, window.location.origin);
+
+ url.searchParams.append('topic', 'mineseeker/channel/' + gameAssoc);
+ if (subscriberJwt) url.searchParams.append('authorization', subscriberJwt);
+
+ if (eventSourceRef.current) eventSourceRef.current.close();
+
+ const es = new EventSource(url.toString());
+ es.onmessage = e => handleMercureMessage(JSON.parse(e.data));
+ es.onopen = () => {
+ isEnvDev && console.info('SSE opened');
+ if (connectionLostRef.current) { isEnvDev && console.info('SSE reconnected'); joinMutation.mutate(); }
+ };
+ es.onerror = () => { isEnvDev && console.error('SSE error'); syncConnLost(true); };
+ eventSourceRef.current = es;
+ };
+
+ // ── Initialization ────────────────────────────────────────────────────────
+
+ useEffect(() => {
+ (async () => {
+ if (connectionLostRef.current) { openEventSource(); return; }
+ try {
+ if (gameInherited) {
+ const serverData = await connectQuery.refetch().then(r => {
+ if (r.error) throw r.error;
+ return r.data;
+ });
+
+ if ('undefined' === typeof serverData.users || null === serverData.users) {
+ showOverlay('This channel does not exists!', Restart game!);
+ console.error('This channel does not exists!');
+ return;
+ }
+
+ rpcUsersRef.current = serverData.users;
+ openEventSource();
+ wInit(serverData.revealedCells || []);
+ } else {
+ await startMutation.mutateAsync();
+ openEventSource();
+ wInit();
+ }
+
+ isEnvDev && console.info('Connection initialised — joining channel');
+ await joinMutation.mutateAsync();
+ } catch (e) {
+ isEnvDev && console.error('Connection error', e);
+ setTimeout(() => window.location.reload(), 500);
+ }
+ })();
+
+ window.addEventListener('pagehide', () => navigator.sendBeacon('/api/game/leave/' + gameAssoc));
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ // ── UI-facing callbacks ───────────────────────────────────────────────────
+
+ const onClick = async coords => {
+ const activeColor = activePlayerRef.current ? 'blue' : 'red';
+ if (activeColor !== webPlayerRef.current) return;
+
+ const [r, c] = coords;
+ if (cells[r]?.[c]?.active) return;
+
+ const dataPack = { coords, player: activeColor, bomb: bombSelectedRef.current, resign: null };
+
+ if (connectionLostRef.current) { stepCacheRef.current.push(dataPack); return; }
+
+ try {
+ const result = await stepMutation.mutateAsync(dataPack);
+ applyStep(result);
+ makeGameEndIfItEnds(result.bluePoints, result.redPoints, false, result.leftMines);
+ } catch (e) {
+ isEnvDev && console.error('Step error', e);
+ }
+ };
+
+ const clickResign = () => {
+ const color = activePlayerRef.current ? 'blue' : 'red';
+ stepMutation.mutate({ resign: color });
+ resignProcess(webPlayerRef.current);
+ };
+
+ const resign = () => {
+ const activeColor = activePlayerRef.current ? 'blue' : 'red';
+ if (webPlayerRef.current !== activeColor) return;
+ showOverlay('Are u sure u want to resign?!', (
+
+ ));
+ };
+
+ return { onClick, resign };
+};
+
+export default useServerComm;
diff --git a/assets/js/mine-seeker/user/user-control.js b/assets/js/mine-seeker/user/user-control.js
deleted file mode 100644
index 17e16d9..0000000
--- a/assets/js/mine-seeker/user/user-control.js
+++ /dev/null
@@ -1,82 +0,0 @@
-import React from 'react';
-import User from './user';
-
-class UserControl extends React.Component {
- constructor() {
- super();
-
- /**
- * activePlayer - red: 0, blue: 1
- * @type {{activePlayer: boolean, mines: number, bombSelected: boolean, foundMines: boolean}}
- */
- this.state = {
- activePlayer: false,
- mines: 51,
- bombSelected: false,
- foundMines: false,
- };
- }
-
- youCanSelectBomb(activePlayer, clickedPlayer) {
- return this.refs[activePlayer].state.haveBomb
- && this.refs[activePlayer].state.enabledBomb
- && this.state.activePlayer === clickedPlayer;
- }
-
- onClickBombSelector(clickedPlayer) {
- let activePlayer = this.state.activePlayer ? 'blue' : 'red';
-
- if (this.youCanSelectBomb(activePlayer, clickedPlayer)) {
- this.state.bombSelected = !this.state.bombSelected;
-
- if (!this.state.bombSelected) {
- this.props.bombClear();
- }
- }
- }
-
- getResignClass(webPlayer) {
- let activePlayer = 1 === this.state.activePlayer ? 'blue' : 'red';
- return 'resign' + (webPlayer !== activePlayer ? ' disabled' : '');
- }
-
- activeMines() {
- return 'active-mines' + (this.state.foundMines ? ' found-mine' : '');
- }
-
- render() {
- return (
-
- );
- }
-}
-
-export default UserControl;
diff --git a/assets/js/mine-seeker/user/user.js b/assets/js/mine-seeker/user/user.js
deleted file mode 100644
index ff93fa3..0000000
--- a/assets/js/mine-seeker/user/user.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import React from 'react';
-
-class User extends React.Component {
- constructor(props) {
- super(props);
-
- this.state = {
- name: '...',
- desc: '',
- active: props.active,
- color: 'blue' === props.color ? 1 : 0,
- mines: 0,
- srcRoot: '/images/',
- haveBomb: true,
- enabledBomb: true,
- };
- }
-
- setColor(color) {
- return 'user-container user-' + color;
- }
-
- getSrc(color) {
- return this.state.srcRoot + 'bg-flag-' + color + '-outbg.png';
- }
-
- getBombBuzzClass(webPlayer) {
- let activePlayer = 1 === this.state.color ? 'blue' : 'red';
-
- return 'bomb-container'
- + (
- this.state.active && (activePlayer === webPlayer) && this.state.haveBomb && this.state.enabledBomb
- ? ' buzz'
- : ''
- );
- }
-
- getBomb() {
- let src = this.state.srcRoot;
-
- if (this.state.haveBomb) {
- src += this.state.enabledBomb && this.state.active
- ? 'bg-bomb-outbg.png'
- : 'bg-bomb-disabled-outbg.png';
- } else {
- src += 'bg-bomb-exploded-outbg.png';
- }
-
- return src;
- }
-
- getFigure(color) {
- return this.state.srcRoot + 'bg-figure-' + color + '-outbg.png';
- }
-
- getCursor(state, color) {
- return state
- ?
- : '';
- }
-
- render() {
- return (
-
-
-
{this.props.color}
- {this.getCursor(this.props.active, this.props.color)}
-
})
-
-
{this.state.name}
-
-
{this.state.desc}
-
-
})
-
- {this.state.mines}
-
-
-
-
})
-
-
-
-
-
- );
- }
-}
-
-export default User;
diff --git a/eslint.config.mjs b/eslint.config.mjs
index bbf4bdf..17325ce 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -7,6 +7,12 @@ export default [
{
ignores: ['node_modules/**', 'vendor/**', 'var/**', 'public/build/**'],
},
+ {
+ files: ['**/*.jsx'],
+ rules: {
+ 'react/jsx-uses-vars': 'error',
+ },
+ },
{
files: ['**/*.{js,mjs,cjs,jsx,ts,tsx}'],
plugins: {
diff --git a/package-lock.json b/package-lock.json
index 7b29fcb..aec8b64 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,19 +10,17 @@
"license": "UNLICENSED",
"dependencies": {
"@fortawesome/fontawesome-free": "^5.2.0",
- "autobahn": "^19.10.1",
+ "@tanstack/react-query": "^5.97.0",
"bootstrap": "3",
- "buffer": "^5.4.3",
"howler": "^2.1.2",
"jquery": "^3.4.1",
- "js-base64": "^2.1.9",
+ "lodash": "^4.18.1",
"prop-types": "^15.7.2",
- "react": "^16.11.0",
- "react-dom": "^16.11.0",
- "uglify-js": "^2.7.4",
- "uglifycss": "0.0.25"
+ "react": "^19.2.5",
+ "react-dom": "^19.2.5"
},
"devDependencies": {
+ "@babel/core": "^7.29.0",
"@babel/preset-env": "^7.23.0",
"@babel/preset-react": "^7.6.3",
"@eslint/eslintrc": "^3.3.5",
@@ -33,7 +31,7 @@
"babel-loader": "^9.0",
"core-js": "^3.0.0",
"eslint": "^9.0.0",
- "eslint-plugin-react": "^4.0.0",
+ "eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.0.0",
"globals": "^15.0.0",
"sass": "^1.77.0",
@@ -64,6 +62,37 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/core": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
+ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.0",
+ "@babel/generator": "^7.29.0",
+ "@babel/helper-compilation-targets": "^7.28.6",
+ "@babel/helper-module-transforms": "^7.28.6",
+ "@babel/helpers": "^7.28.6",
+ "@babel/parser": "^7.29.0",
+ "@babel/template": "^7.28.6",
+ "@babel/traverse": "^7.29.0",
+ "@babel/types": "^7.29.0",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
"node_modules/@babel/generator": {
"version": "7.29.1",
"dev": true,
@@ -313,6 +342,20 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@babel/helpers": {
+ "version": "7.29.2",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz",
+ "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.28.6",
+ "@babel/types": "^7.29.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/parser": {
"version": "7.29.2",
"dev": true,
@@ -1735,6 +1778,17 @@
"@jridgewell/trace-mapping": "^0.3.24"
}
},
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"dev": true,
@@ -2397,6 +2451,32 @@
"node": ">=10"
}
},
+ "node_modules/@tanstack/query-core": {
+ "version": "5.97.0",
+ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.97.0.tgz",
+ "integrity": "sha512-QdpLP5VzVMgo4VtaPppRA2W04UFjIqX+bxke/ZJhE5cfd5UPkRzqIAJQt9uXkQJjqE8LBOMbKv7f8HCsZltXlg==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
+ "node_modules/@tanstack/react-query": {
+ "version": "5.97.0",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.97.0.tgz",
+ "integrity": "sha512-y4So4eGcQoK2WVMAcDNZE9ofB/p5v1OlKvtc1F3uqHwrtifobT7q+ZnXk2mRkc8E84HKYSlAE9z6HXl2V0+ySQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@tanstack/query-core": "5.97.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "react": "^18 || ^19"
+ }
+ },
"node_modules/@types/body-parser": {
"version": "1.19.6",
"dev": true,
@@ -3149,28 +3229,6 @@
"ajv": "^8.8.2"
}
},
- "node_modules/align-text": {
- "version": "0.1.4",
- "license": "MIT",
- "dependencies": {
- "kind-of": "^3.0.2",
- "longest": "^1.0.1",
- "repeat-string": "^1.5.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/align-text/node_modules/kind-of": {
- "version": "3.2.2",
- "license": "MIT",
- "dependencies": {
- "is-buffer": "^1.1.5"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/ansi-html-community": {
"version": "0.0.8",
"dev": true,
@@ -3234,11 +3292,51 @@
"dev": true,
"license": "Python-2.0"
},
+ "node_modules/array-buffer-byte-length": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
+ "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "is-array-buffer": "^3.0.5"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/array-flatten": {
"version": "1.1.1",
"dev": true,
"license": "MIT"
},
+ "node_modules/array-includes": {
+ "version": "3.1.9",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
+ "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.24.0",
+ "es-object-atoms": "^1.1.1",
+ "get-intrinsic": "^1.3.0",
+ "is-string": "^1.1.1",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/array-union": {
"version": "1.0.2",
"dev": true,
@@ -3258,6 +3356,104 @@
"node": ">=0.10.0"
}
},
+ "node_modules/array.prototype.findlast": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
+ "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flat": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
+ "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flatmap": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
+ "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.tosorted": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
+ "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.3",
+ "es-errors": "^1.3.0",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/arraybuffer.prototype.slice": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
+ "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.1",
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "is-array-buffer": "^3.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/assets-webpack-plugin": {
"version": "7.0.0",
"dev": true,
@@ -3274,27 +3470,14 @@
"webpack": ">=5.0.0"
}
},
- "node_modules/async-limiter": {
- "version": "1.0.1",
- "license": "MIT"
- },
- "node_modules/autobahn": {
- "version": "19.10.1",
+ "node_modules/async-function": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
+ "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
+ "dev": true,
"license": "MIT",
- "dependencies": {
- "cbor": ">= 3.0.0",
- "crypto-js": ">=3.1.8",
- "msgpack5": ">= 3.6.0",
- "tweetnacl": ">= 0.14.3",
- "when": ">= 3.7.7",
- "ws": ">= 1.1.4"
- },
"engines": {
- "node": ">= 4.2.6"
- },
- "optionalDependencies": {
- "bufferutil": ">= 1.2.1",
- "utf-8-validate": ">= 1.2.1"
+ "node": ">= 0.4"
}
},
"node_modules/autoprefixer": {
@@ -3332,6 +3515,22 @@
"postcss": "^8.1.0"
}
},
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/babel-loader": {
"version": "9.2.1",
"dev": true,
@@ -3389,10 +3588,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/base64-js": {
- "version": "1.3.0",
- "license": "MIT"
- },
"node_modules/baseline-browser-mapping": {
"version": "2.10.16",
"dev": true,
@@ -3417,13 +3612,6 @@
"node": "*"
}
},
- "node_modules/bignumber.js": {
- "version": "9.0.0",
- "license": "MIT",
- "engines": {
- "node": "*"
- }
- },
"node_modules/binary-extensions": {
"version": "2.3.0",
"dev": true,
@@ -3435,14 +3623,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/bl": {
- "version": "2.2.0",
- "license": "MIT",
- "dependencies": {
- "readable-stream": "^2.3.5",
- "safe-buffer": "^5.1.1"
- }
- },
"node_modules/body-parser": {
"version": "1.20.4",
"dev": true,
@@ -3568,28 +3748,11 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
- "node_modules/buffer": {
- "version": "5.4.3",
- "license": "MIT",
- "dependencies": {
- "base64-js": "^1.0.2",
- "ieee754": "^1.1.4"
- }
- },
"node_modules/buffer-from": {
"version": "1.1.1",
"dev": true,
"license": "MIT"
},
- "node_modules/bufferutil": {
- "version": "4.0.1",
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "node-gyp-build": "~3.7.0"
- }
- },
"node_modules/bytes": {
"version": "3.0.0",
"dev": true,
@@ -3598,6 +3761,25 @@
"node": ">= 0.8"
}
},
+ "node_modules/call-bind": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
+ "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "get-intrinsic": "^1.3.0",
+ "set-function-length": "^1.2.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"dev": true,
@@ -3676,28 +3858,6 @@
],
"license": "CC-BY-4.0"
},
- "node_modules/cbor": {
- "version": "5.0.1",
- "license": "MIT",
- "dependencies": {
- "bignumber.js": "^9.0.0",
- "nofilter": "^1.0.3"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/center-align": {
- "version": "0.1.3",
- "license": "MIT",
- "dependencies": {
- "align-text": "^0.1.3",
- "lazy-cache": "^1.0.3"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/chalk": {
"version": "4.1.2",
"dev": true,
@@ -3766,15 +3926,6 @@
"webpack": ">=4.0.0 <6.0.0"
}
},
- "node_modules/cliui": {
- "version": "2.1.0",
- "license": "ISC",
- "dependencies": {
- "center-align": "^0.1.1",
- "right-align": "^0.1.1",
- "wordwrap": "0.0.2"
- }
- },
"node_modules/clone-deep": {
"version": "4.0.1",
"dev": true,
@@ -3935,6 +4086,13 @@
"node": ">= 0.6"
}
},
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/cookie": {
"version": "0.7.2",
"dev": true,
@@ -3968,6 +4126,7 @@
},
"node_modules/core-util-is": {
"version": "1.0.2",
+ "dev": true,
"license": "MIT"
},
"node_modules/cross-spawn": {
@@ -3983,10 +4142,6 @@
"node": ">= 8"
}
},
- "node_modules/crypto-js": {
- "version": "3.1.8",
- "license": "MIT"
- },
"node_modules/css-declaration-sorter": {
"version": "7.4.0",
"dev": true,
@@ -4238,6 +4393,60 @@
"dev": true,
"license": "CC0-1.0"
},
+ "node_modules/data-view-buffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
+ "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/data-view-byte-length": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
+ "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/inspect-js"
+ }
+ },
+ "node_modules/data-view-byte-offset": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
+ "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/debug": {
"version": "4.4.3",
"dev": true,
@@ -4254,13 +4463,6 @@
}
}
},
- "node_modules/decamelize": {
- "version": "1.2.0",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -4279,6 +4481,24 @@
"node": ">= 10"
}
},
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/define-lazy-prop": {
"version": "2.0.0",
"dev": true,
@@ -4287,6 +4507,24 @@
"node": ">=8"
}
},
+ "node_modules/define-properties": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.0.1",
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/del": {
"version": "4.1.1",
"dev": true,
@@ -4357,6 +4595,19 @@
"node": ">=6"
}
},
+ "node_modules/doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/dom-converter": {
"version": "0.2.0",
"dev": true,
@@ -4499,6 +4750,75 @@
"stackframe": "^1.3.4"
}
},
+ "node_modules/es-abstract": {
+ "version": "1.24.2",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz",
+ "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.2",
+ "arraybuffer.prototype.slice": "^1.0.4",
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "data-view-buffer": "^1.0.2",
+ "data-view-byte-length": "^1.0.2",
+ "data-view-byte-offset": "^1.0.1",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "es-set-tostringtag": "^2.1.0",
+ "es-to-primitive": "^1.3.0",
+ "function.prototype.name": "^1.1.8",
+ "get-intrinsic": "^1.3.0",
+ "get-proto": "^1.0.1",
+ "get-symbol-description": "^1.1.0",
+ "globalthis": "^1.0.4",
+ "gopd": "^1.2.0",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "internal-slot": "^1.1.0",
+ "is-array-buffer": "^3.0.5",
+ "is-callable": "^1.2.7",
+ "is-data-view": "^1.0.2",
+ "is-negative-zero": "^2.0.3",
+ "is-regex": "^1.2.1",
+ "is-set": "^2.0.3",
+ "is-shared-array-buffer": "^1.0.4",
+ "is-string": "^1.1.1",
+ "is-typed-array": "^1.1.15",
+ "is-weakref": "^1.1.1",
+ "math-intrinsics": "^1.1.0",
+ "object-inspect": "^1.13.4",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.7",
+ "own-keys": "^1.0.1",
+ "regexp.prototype.flags": "^1.5.4",
+ "safe-array-concat": "^1.1.3",
+ "safe-push-apply": "^1.0.0",
+ "safe-regex-test": "^1.1.0",
+ "set-proto": "^1.0.0",
+ "stop-iteration-iterator": "^1.1.0",
+ "string.prototype.trim": "^1.2.10",
+ "string.prototype.trimend": "^1.0.9",
+ "string.prototype.trimstart": "^1.0.8",
+ "typed-array-buffer": "^1.0.3",
+ "typed-array-byte-length": "^1.0.3",
+ "typed-array-byte-offset": "^1.0.4",
+ "typed-array-length": "^1.0.7",
+ "unbox-primitive": "^1.1.0",
+ "which-typed-array": "^1.1.19"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/es-define-property": {
"version": "1.0.1",
"dev": true,
@@ -4515,6 +4835,34 @@
"node": ">= 0.4"
}
},
+ "node_modules/es-iterator-helpers": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.2.tgz",
+ "integrity": "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.9",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.24.2",
+ "es-errors": "^1.3.0",
+ "es-set-tostringtag": "^2.1.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.3.0",
+ "globalthis": "^1.0.4",
+ "gopd": "^1.2.0",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "internal-slot": "^1.1.0",
+ "iterator.prototype": "^1.1.5",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/es-module-lexer": {
"version": "2.0.0",
"dev": true,
@@ -4531,6 +4879,53 @@
"node": ">= 0.4"
}
},
+ "node_modules/es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-shim-unscopables": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
+ "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-to-primitive": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
+ "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.2.7",
+ "is-date-object": "^1.0.5",
+ "is-symbol": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/escalade": {
"version": "3.2.0",
"dev": true,
@@ -4616,11 +5011,37 @@
}
},
"node_modules/eslint-plugin-react": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-4.3.0.tgz",
- "integrity": "sha512-ajQ9S74FUln2GcwgpPUQqRLcT6UFDhvAMIiDX4F68tDnuihNXcAA7LI19MmRGGOuJnpMVDXugJg+wf9K+bf6kg==",
+ "version": "7.37.5",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
+ "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "dependencies": {
+ "array-includes": "^3.1.8",
+ "array.prototype.findlast": "^1.2.5",
+ "array.prototype.flatmap": "^1.3.3",
+ "array.prototype.tosorted": "^1.1.4",
+ "doctrine": "^2.1.0",
+ "es-iterator-helpers": "^1.2.1",
+ "estraverse": "^5.3.0",
+ "hasown": "^2.0.2",
+ "jsx-ast-utils": "^2.4.1 || ^3.0.0",
+ "minimatch": "^3.1.2",
+ "object.entries": "^1.1.9",
+ "object.fromentries": "^2.0.8",
+ "object.values": "^1.2.1",
+ "prop-types": "^15.8.1",
+ "resolve": "^2.0.0-next.5",
+ "semver": "^6.3.1",
+ "string.prototype.matchall": "^4.0.12",
+ "string.prototype.repeat": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependencies": {
+ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
+ }
},
"node_modules/eslint-plugin-react-hooks": {
"version": "5.2.0",
@@ -4635,6 +5056,40 @@
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0"
}
},
+ "node_modules/eslint-plugin-react/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/eslint-plugin-react/node_modules/resolve": {
+ "version": "2.0.0-next.6",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz",
+ "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "is-core-module": "^2.16.1",
+ "node-exports-info": "^1.6.0",
+ "object-keys": "^1.1.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/eslint-scope": {
"version": "5.1.1",
"dev": true,
@@ -5292,6 +5747,22 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/for-each": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
+ "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/forwarded": {
"version": "0.2.0",
"dev": true,
@@ -5353,6 +5824,57 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/function.prototype.name": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
+ "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "functions-have-names": "^1.2.3",
+ "hasown": "^2.0.2",
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/functions-have-names": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/generator-function": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
+ "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"dev": true,
@@ -5407,6 +5929,24 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/get-symbol-description": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
+ "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/glob": {
"version": "7.1.5",
"dev": true,
@@ -5452,6 +5992,23 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/globalthis": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+ "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-properties": "^1.2.1",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/globby": {
"version": "6.1.0",
"dev": true,
@@ -5501,6 +6058,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/has-bigints": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
+ "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/has-flag": {
"version": "4.0.0",
"dev": true,
@@ -5509,6 +6079,35 @@
"node": ">=8"
}
},
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
+ "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/has-symbols": {
"version": "1.1.0",
"dev": true,
@@ -5520,6 +6119,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/hasown": {
"version": "2.0.2",
"dev": true,
@@ -5706,10 +6321,6 @@
"postcss": "^8.1.0"
}
},
- "node_modules/ieee754": {
- "version": "1.1.11",
- "license": "BSD-3-Clause"
- },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -5855,8 +6466,24 @@
},
"node_modules/inherits": {
"version": "2.0.3",
+ "dev": true,
"license": "ISC"
},
+ "node_modules/internal-slot": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
+ "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "hasown": "^2.0.2",
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/interpret": {
"version": "3.1.1",
"dev": true,
@@ -5873,6 +6500,60 @@
"node": ">= 10"
}
},
+ "node_modules/is-array-buffer": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
+ "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-async-function": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
+ "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "async-function": "^1.0.0",
+ "call-bound": "^1.0.3",
+ "get-proto": "^1.0.1",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bigint": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
+ "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-bigints": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-binary-path": {
"version": "2.1.0",
"dev": true,
@@ -5884,9 +6565,35 @@
"node": ">=8"
}
},
- "node_modules/is-buffer": {
- "version": "1.1.6",
- "license": "MIT"
+ "node_modules/is-boolean-object": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
+ "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
"node_modules/is-core-module": {
"version": "2.16.1",
@@ -5902,6 +6609,41 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-data-view": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
+ "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "get-intrinsic": "^1.2.6",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
+ "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-docker": {
"version": "2.2.1",
"dev": true,
@@ -5924,6 +6666,22 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-finalizationregistry": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
+ "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"dev": true,
@@ -5932,6 +6690,26 @@
"node": ">=8"
}
},
+ "node_modules/is-generator-function": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz",
+ "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.4",
+ "generator-function": "^2.0.0",
+ "get-proto": "^1.0.1",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-glob": {
"version": "4.0.3",
"dev": true,
@@ -5943,6 +6721,32 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-map": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+ "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-negative-zero": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
+ "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-number": {
"version": "7.0.0",
"dev": true,
@@ -5951,6 +6755,23 @@
"node": ">=0.12.0"
}
},
+ "node_modules/is-number-object": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
+ "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-path-cwd": {
"version": "2.2.0",
"dev": true,
@@ -6003,6 +6824,54 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-regex": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+ "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-set": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+ "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-shared-array-buffer": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
+ "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-stream": {
"version": "2.0.1",
"dev": true,
@@ -6014,6 +6883,103 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/is-string": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
+ "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
+ "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "has-symbols": "^1.1.0",
+ "safe-regex-test": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
+ "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakmap": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+ "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakref": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
+ "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakset": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
+ "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "get-intrinsic": "^1.2.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/is-wsl": {
"version": "2.2.0",
"dev": true,
@@ -6027,6 +6993,7 @@
},
"node_modules/isarray": {
"version": "1.0.0",
+ "dev": true,
"license": "MIT"
},
"node_modules/isexe": {
@@ -6042,6 +7009,24 @@
"node": ">=0.10.0"
}
},
+ "node_modules/iterator.prototype": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz",
+ "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.6",
+ "get-proto": "^1.0.0",
+ "has-symbols": "^1.1.0",
+ "set-function-name": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/jest-util": {
"version": "29.7.0",
"dev": true,
@@ -6101,10 +7086,6 @@
"version": "3.4.1",
"license": "MIT"
},
- "node_modules/js-base64": {
- "version": "2.4.5",
- "license": "BSD-3-Clause"
- },
"node_modules/js-tokens": {
"version": "4.0.0",
"license": "MIT"
@@ -6168,6 +7149,22 @@
"node": ">=6"
}
},
+ "node_modules/jsx-ast-utils": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
+ "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-includes": "^3.1.6",
+ "array.prototype.flat": "^1.3.1",
+ "object.assign": "^4.1.4",
+ "object.values": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -6195,13 +7192,6 @@
"shell-quote": "^1.8.3"
}
},
- "node_modules/lazy-cache": {
- "version": "1.0.4",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -6254,7 +7244,6 @@
},
"node_modules/lodash": {
"version": "4.18.1",
- "dev": true,
"license": "MIT"
},
"node_modules/lodash.debounce": {
@@ -6279,13 +7268,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/longest": {
- "version": "1.0.1",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/loose-envify": {
"version": "1.4.0",
"license": "MIT",
@@ -6460,16 +7442,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/msgpack5": {
- "version": "4.2.1",
- "license": "MIT",
- "dependencies": {
- "bl": "^2.0.1",
- "inherits": "^2.0.3",
- "readable-stream": "^2.3.6",
- "safe-buffer": "^5.1.2"
- }
- },
"node_modules/multicast-dns": {
"version": "7.2.5",
"dev": true,
@@ -6525,6 +7497,25 @@
"license": "MIT",
"optional": true
},
+ "node_modules/node-exports-info": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz",
+ "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array.prototype.flatmap": "^1.3.3",
+ "es-errors": "^1.3.0",
+ "object.entries": "^1.1.9",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/node-forge": {
"version": "1.4.0",
"dev": true,
@@ -6533,16 +7524,6 @@
"node": ">= 6.13.0"
}
},
- "node_modules/node-gyp-build": {
- "version": "3.7.0",
- "license": "MIT",
- "optional": true,
- "bin": {
- "node-gyp-build": "bin.js",
- "node-gyp-build-optional": "optional.js",
- "node-gyp-build-test": "build-test.js"
- }
- },
"node_modules/node-notifier": {
"version": "9.0.1",
"dev": true,
@@ -6572,13 +7553,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/nofilter": {
- "version": "1.0.3",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/normalize-path": {
"version": "3.0.0",
"dev": true,
@@ -6635,6 +7609,91 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.7",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
+ "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0",
+ "has-symbols": "^1.1.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.entries": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
+ "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.fromentries": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+ "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.values": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
+ "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/obuf": {
"version": "1.1.2",
"dev": true,
@@ -6726,6 +7785,24 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/own-keys": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
+ "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-intrinsic": "^1.2.6",
+ "object-keys": "^1.1.1",
+ "safe-push-apply": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/p-map": {
"version": "2.1.0",
"dev": true,
@@ -6928,6 +8005,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/possible-typed-array-names": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
+ "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/postcss": {
"version": "8.5.9",
"dev": true,
@@ -7488,15 +8575,18 @@
},
"node_modules/process-nextick-args": {
"version": "2.0.0",
+ "dev": true,
"license": "MIT"
},
"node_modules/prop-types": {
- "version": "15.7.2",
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
- "react-is": "^16.8.1"
+ "react-is": "^16.13.1"
}
},
"node_modules/proxy-addr": {
@@ -7582,47 +8672,32 @@
}
},
"node_modules/react": {
- "version": "16.11.0",
+ "version": "19.2.5",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz",
+ "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==",
"license": "MIT",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2"
- },
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
- "version": "16.11.0",
+ "version": "19.2.5",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz",
+ "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==",
"license": "MIT",
"dependencies": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "prop-types": "^15.6.2",
- "scheduler": "^0.17.0"
+ "scheduler": "^0.27.0"
},
"peerDependencies": {
- "react": "^16.0.0"
+ "react": "^19.2.5"
}
},
"node_modules/react-is": {
- "version": "16.11.0",
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT"
},
- "node_modules/readable-stream": {
- "version": "2.3.6",
- "license": "MIT",
- "dependencies": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
"node_modules/readdirp": {
"version": "4.1.2",
"dev": true,
@@ -7646,6 +8721,29 @@
"node": ">= 10.13.0"
}
},
+ "node_modules/reflect.getprototypeof": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
+ "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.9",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.7",
+ "get-proto": "^1.0.1",
+ "which-builtin-type": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/regenerate": {
"version": "1.4.2",
"dev": true,
@@ -7667,6 +8765,27 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/regexp.prototype.flags": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
+ "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-errors": "^1.3.0",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "set-function-name": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/regexpu-core": {
"version": "6.4.0",
"dev": true,
@@ -7730,13 +8849,6 @@
"node": ">=8"
}
},
- "node_modules/repeat-string": {
- "version": "1.6.1",
- "license": "MIT",
- "engines": {
- "node": ">=0.10"
- }
- },
"node_modules/require-from-string": {
"version": "2.0.2",
"dev": true,
@@ -7824,20 +8936,80 @@
"node": ">= 4"
}
},
- "node_modules/right-align": {
- "version": "0.1.3",
+ "node_modules/safe-array-concat": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
+ "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "align-text": "^0.1.1"
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.2",
+ "get-intrinsic": "^1.2.6",
+ "has-symbols": "^1.1.0",
+ "isarray": "^2.0.5"
},
"engines": {
- "node": ">=0.10.0"
+ "node": ">=0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/safe-array-concat/node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/safe-buffer": {
"version": "5.1.2",
+ "dev": true,
"license": "MIT"
},
+ "node_modules/safe-push-apply": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
+ "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-push-apply/node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/safe-regex-test": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+ "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "is-regex": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/safer-buffer": {
"version": "2.1.2",
"dev": true,
@@ -7907,12 +9079,10 @@
}
},
"node_modules/scheduler": {
- "version": "0.17.0",
- "license": "MIT",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1"
- }
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
+ "license": "MIT"
},
"node_modules/schema-utils": {
"version": "4.3.3",
@@ -8099,6 +9269,55 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-function-name": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+ "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "functions-have-names": "^1.2.3",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-proto": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
+ "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/setprototypeof": {
"version": "1.2.0",
"dev": true,
@@ -8312,8 +9531,23 @@
"node": ">= 0.8"
}
},
+ "node_modules/stop-iteration-iterator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
+ "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "internal-slot": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/string_decoder": {
"version": "1.1.1",
+ "dev": true,
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.1.0"
@@ -8351,6 +9585,104 @@
"node": ">=8"
}
},
+ "node_modules/string.prototype.matchall": {
+ "version": "4.0.12",
+ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz",
+ "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.6",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.6",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "internal-slot": "^1.1.0",
+ "regexp.prototype.flags": "^1.5.3",
+ "set-function-name": "^2.0.2",
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.repeat": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
+ "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.5"
+ }
+ },
+ "node_modules/string.prototype.trim": {
+ "version": "1.2.10",
+ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
+ "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.2",
+ "define-data-property": "^1.1.4",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-object-atoms": "^1.0.0",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
+ "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.2",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+ "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/strip-ansi": {
"version": "6.0.1",
"dev": true,
@@ -8713,10 +10045,6 @@
"dev": true,
"license": "Apache-2.0"
},
- "node_modules/tweetnacl": {
- "version": "1.0.1",
- "license": "Unlicense"
- },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -8761,40 +10089,101 @@
"node": ">= 0.6"
}
},
- "node_modules/uglify-js": {
- "version": "2.8.29",
- "license": "BSD-2-Clause",
+ "node_modules/typed-array-buffer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "source-map": "~0.5.1",
- "yargs": "~3.10.0"
- },
- "bin": {
- "uglifyjs": "bin/uglifyjs"
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-typed-array": "^1.1.14"
},
"engines": {
- "node": ">=0.8.0"
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/typed-array-byte-length": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
+ "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.8",
+ "for-each": "^0.3.3",
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.14"
},
- "optionalDependencies": {
- "uglify-to-browserify": "~1.0.0"
- }
- },
- "node_modules/uglify-js/node_modules/source-map": {
- "version": "0.5.7",
- "license": "BSD-3-Clause",
"engines": {
- "node": ">=0.10.0"
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/uglify-to-browserify": {
- "version": "1.0.2",
+ "node_modules/typed-array-byte-offset": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
+ "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
+ "dev": true,
"license": "MIT",
- "optional": true
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "for-each": "^0.3.3",
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.15",
+ "reflect.getprototypeof": "^1.0.9"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
- "node_modules/uglifycss": {
- "version": "0.0.25",
+ "node_modules/typed-array-length": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
+ "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
+ "dev": true,
"license": "MIT",
- "bin": {
- "uglifycss": "uglifycss"
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "is-typed-array": "^1.1.13",
+ "possible-typed-array-names": "^1.0.0",
+ "reflect.getprototypeof": "^1.0.6"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/unbox-primitive": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+ "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "has-bigints": "^1.0.2",
+ "has-symbols": "^1.1.0",
+ "which-boxed-primitive": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/unicode-canonical-property-names-ecmascript": {
@@ -8880,17 +10269,9 @@
"punycode": "^2.1.0"
}
},
- "node_modules/utf-8-validate": {
- "version": "5.0.2",
- "hasInstallScript": true,
- "license": "MIT",
- "optional": true,
- "dependencies": {
- "node-gyp-build": "~3.7.0"
- }
- },
"node_modules/util-deprecate": {
"version": "1.0.2",
+ "dev": true,
"license": "MIT"
},
"node_modules/utila": {
@@ -9270,10 +10651,6 @@
"node": ">=0.8.0"
}
},
- "node_modules/when": {
- "version": "3.7.8",
- "license": "MIT"
- },
"node_modules/which": {
"version": "2.0.2",
"dev": true,
@@ -9288,17 +10665,107 @@
"node": ">= 8"
}
},
+ "node_modules/which-boxed-primitive": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
+ "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-bigint": "^1.1.0",
+ "is-boolean-object": "^1.2.1",
+ "is-number-object": "^1.1.1",
+ "is-string": "^1.1.1",
+ "is-symbol": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-builtin-type": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
+ "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "function.prototype.name": "^1.1.6",
+ "has-tostringtag": "^1.0.2",
+ "is-async-function": "^2.0.0",
+ "is-date-object": "^1.1.0",
+ "is-finalizationregistry": "^1.1.0",
+ "is-generator-function": "^1.0.10",
+ "is-regex": "^1.2.1",
+ "is-weakref": "^1.0.2",
+ "isarray": "^2.0.5",
+ "which-boxed-primitive": "^1.1.0",
+ "which-collection": "^1.0.2",
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-builtin-type/node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/which-collection": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
+ "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-map": "^2.0.3",
+ "is-set": "^2.0.3",
+ "is-weakmap": "^2.0.2",
+ "is-weakset": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.20",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz",
+ "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "for-each": "^0.3.5",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/wildcard": {
"version": "2.0.1",
"dev": true,
"license": "MIT"
},
- "node_modules/window-size": {
- "version": "0.1.0",
- "engines": {
- "node": ">= 0.8.0"
- }
- },
"node_modules/word-wrap": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
@@ -9309,40 +10776,16 @@
"node": ">=0.10.0"
}
},
- "node_modules/wordwrap": {
- "version": "0.0.2",
- "license": "MIT/X11",
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/wrappy": {
"version": "1.0.2",
"dev": true,
"license": "ISC"
},
- "node_modules/ws": {
- "version": "7.2.0",
- "license": "MIT",
- "dependencies": {
- "async-limiter": "^1.0.0"
- }
- },
"node_modules/yallist": {
"version": "3.0.2",
"dev": true,
"license": "ISC"
},
- "node_modules/yargs": {
- "version": "3.10.0",
- "license": "MIT",
- "dependencies": {
- "camelcase": "^1.0.2",
- "cliui": "^2.1.0",
- "decamelize": "^1.0.0",
- "window-size": "0.1.0"
- }
- },
"node_modules/yargs-parser": {
"version": "21.1.1",
"dev": true,
@@ -9351,13 +10794,6 @@
"node": ">=12"
}
},
- "node_modules/yargs/node_modules/camelcase": {
- "version": "1.2.1",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/yocto-queue": {
"version": "1.2.2",
"dev": true,
diff --git a/package.json b/package.json
index 81a2ffa..70b0cc4 100644
--- a/package.json
+++ b/package.json
@@ -14,17 +14,14 @@
"private": true,
"dependencies": {
"@fortawesome/fontawesome-free": "^5.2.0",
+ "@tanstack/react-query": "^5.97.0",
"bootstrap": "3",
- "buffer": "^5.4.3",
"howler": "^2.1.2",
"jquery": "^3.4.1",
- "js-base64": "^2.1.9",
"lodash": "^4.18.1",
"prop-types": "^15.7.2",
- "react": "^16.11.0",
- "react-dom": "^16.11.0",
- "uglify-js": "^2.7.4",
- "uglifycss": "0.0.25"
+ "react": "^19.2.5",
+ "react-dom": "^19.2.5"
},
"devDependencies": {
"@babel/core": "^7.29.0",
@@ -38,7 +35,7 @@
"babel-loader": "^9.0",
"core-js": "^3.0.0",
"eslint": "^9.0.0",
- "eslint-plugin-react": "^4.0.0",
+ "eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.0.0",
"globals": "^15.0.0",
"sass": "^1.77.0",
diff --git a/src/Util/TopicManager.php b/src/Util/TopicManager.php
index 3ba96b9..5263ece 100644
--- a/src/Util/TopicManager.php
+++ b/src/Util/TopicManager.php
@@ -352,9 +352,10 @@ class TopicManager implements TopicManagerInterface
private function getLeftMines(array $grid, array $alreadyRevealed): array
{
$mines = [];
+
foreach ($grid as $r => $row) {
foreach ($row as $c => $value) {
- if ('m' === $value && !isset($alreadyRevealed[$r . ',' . $c])) {
+ if ('m' === $value && !isset($alreadyRevealed["$r,$c"])) {
$mines[] = ['row' => $r, 'col' => $c];
}
}
diff --git a/symfony.lock b/symfony.lock
index da7b284..2edad4d 100644
--- a/symfony.lock
+++ b/symfony.lock
@@ -373,7 +373,7 @@
},
"files": [
"assets/css/app.css",
- "assets/js/app.js",
+ "assets/js/MineSeeker.js",
"config/packages/assets.yaml",
"config/packages/prod/webpack_encore.yaml",
"config/packages/webpack_encore.yaml",
diff --git a/webpack.config.js b/webpack.config.js
index 55e4288..ac6dbb5 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -4,59 +4,59 @@ var webpack = require('webpack');
// Manually configure the runtime environment if not already configured yet by the "encore" command.
// It's useful when you use tools that rely on webpack.config.js file.
if (!Encore.isRuntimeEnvironmentConfigured()) {
- Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
+ Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}
// the project directory where compiled assets will be stored
Encore
- .setOutputPath('public/build/')
- // the public path used by the web server to access the previous directory
- .setPublicPath('/build')
+ .setOutputPath('public/build/')
+// the public path used by the web server to access the previous directory
+ .setPublicPath('/build')
- // .cleanupOutputBeforeBuild()
- .enableBuildNotifications()
- .enableSourceMaps(!Encore.isProduction())
- // uncomment to create hashed filenames (e.g. app.abc123.css)
- .enableVersioning(Encore.isProduction())
+// .cleanupOutputBeforeBuild()
+ .enableBuildNotifications()
+ .enableSourceMaps(!Encore.isProduction())
+// uncomment to create hashed filenames (e.g. app.abc123.css)
+ .enableVersioning(Encore.isProduction())
- // .copyFiles([
- // {from: './public/bundles/goswebsocket/', to: '/[path][name].[ext]', pattern: /\.(js|css|map)$/, includeSubdirectories: false},
- // ])
+// .copyFiles([
+// {from: './public/bundles/goswebsocket/', to: '/[path][name].[ext]', pattern: /\.(js|css|map)$/, includeSubdirectories: false},
+// ])
- // uncomment to define the assets of the project
- // .addEntry('js/app', './assets/js/app.js')
- // .addStyleEntry('css/app', './assets/css/app.scss')
+// uncomment to define the assets of the project
+// .addEntry('js/app', './assets/js/MineSeeker.js')
+// .addStyleEntry('css/app', './assets/css/app.scss')
- // .addEntry('mineseeker', ['babel-polyfill', './assets/js/mine-seeker.js'])
- .addEntry('mineseeker', './assets/js/mine-seeker.js')
- .addEntry('mineseekerStyle', './assets/css/style.mineseeker.scss')
- .addEntry('homeStyle', './assets/css/style.layout.scss')
+// .addEntry('mineseeker', ['babel-polyfill', './assets/js/MineSeeker.js'])
+ .addEntry('mineseeker', './assets/js/app.jsx')
+ .addEntry('mineseekerStyle', './assets/css/style.mineseeker.scss')
+ .addEntry('homeStyle', './assets/css/style.layout.scss')
- // uncomment if you use Sass/SCSS files
- .enableSassLoader(options => {
- options.api = 'modern';
- options.sassOptions = { silenceDeprecations: ['import'] };
- })
- .configureCssLoader(options => {
- // don't process absolute URLs (e.g. /images/...) — served by the web server
- options.url = { filter: url => !url.startsWith('/') };
- })
+// uncomment if you use Sass/SCSS files
+ .enableSassLoader(options => {
+ options.api = 'modern';
+ options.sassOptions = { silenceDeprecations: ['import'] };
+ })
+ .configureCssLoader(options => {
+ // don't process absolute URLs (e.g. /images/...) — served by the web server
+ options.url = { filter: url => !url.startsWith('/') };
+ })
- // provide $/jQuery as global variables for Bootstrap 3 and legacy code
- .addPlugin(new webpack.ProvidePlugin({
- $: 'jquery',
- jQuery: 'jquery',
- 'window.jQuery': 'jquery',
- }))
+// provide $/jQuery as global variables for Bootstrap 3 and legacy code
+ .addPlugin(new webpack.ProvidePlugin({
+ $: 'jquery',
+ jQuery: 'jquery',
+ 'window.jQuery': 'jquery',
+ }))
- // .configureBabel(function (babelConfig) {
- // babelConfig.presets.push('env');
- // })
+ .enableReactPreset()
+ .configureBabel(babelConfig => {
+ const idx = babelConfig.presets.findIndex(p => (Array.isArray(p) ? p[0] : p).includes('preset-react'));
+ if (-1 < idx) babelConfig.presets[idx] = [require.resolve('@babel/preset-react'), { runtime: 'automatic' }];
+ })
- .enableReactPreset()
-
- // .enableSingleRuntimeChunk()
- .disableSingleRuntimeChunk()
+// .enableSingleRuntimeChunk()
+ .disableSingleRuntimeChunk()
;
module.exports = Encore.getWebpackConfig();