diff --git a/ReactMap.js b/ReactMap.js index dfaba0c21..f6eb348d4 100644 --- a/ReactMap.js +++ b/ReactMap.js @@ -5,10 +5,8 @@ const { build } = require('vite') const { log, HELPERS } = require('@rm/logger') const { generate } = require('@rm/masterfile') -const viteConfig = require('./vite.config') - generate(true).then(() => - build(viteConfig({ mode: 'production', command: 'build' })) + build() .then(() => log.info(HELPERS.build, 'React Map Compiled')) .then(() => require('./server/src/index')), ) diff --git a/package.json b/package.json index 9ae093451..9ca3500db 100644 --- a/package.json +++ b/package.json @@ -149,8 +149,8 @@ "i18next-http-backend": "^1.4.0", "knex": "^2.4.2", "leaflet": "1.9.4", - "leaflet.locatecontrol": "^0.79.0", - "lodash.debounce": "^4.0.8", + "leaflet.locatecontrol": "0.73.0", + "lodash": "^4.17.21", "moment-timezone": "^0.5.43", "morgan": "^1.10.0", "mysql2": "^3.4.0", diff --git a/packages/config/package.json b/packages/config/package.json index 05338c042..d567ae97d 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -15,6 +15,6 @@ "prettier:fix": "prettier --write \"**/*.{css,html,js,jsx,yml}\"" }, "dependencies": { - "config": "^3.3.9" + "config": "^3.3.10" } } diff --git a/packages/masterfile/lib/index.js b/packages/masterfile/lib/index.js index e9ff8862a..9f0dca0ea 100644 --- a/packages/masterfile/lib/index.js +++ b/packages/masterfile/lib/index.js @@ -28,6 +28,7 @@ Object.entries(defaultRarity).forEach(([tier, pokemon]) => { * @returns */ const generate = async (save = false, historicRarity = {}, dbRarity = {}) => { + log.info(HELPERS.masterfile, 'generating masterfile') try { if (!endpoint) throw new Error('No masterfile endpoint') @@ -68,7 +69,7 @@ const generate = async (save = false, historicRarity = {}, dbRarity = {}) => { } if (save) { - fs.promises.writeFile( + await fs.promises.writeFile( resolve(`${__dirname}/data/masterfile.json`), JSON.stringify(newMf, null, 2), 'utf8', @@ -87,9 +88,7 @@ const generate = async (save = false, historicRarity = {}, dbRarity = {}) => { module.exports.generate = generate if (require.main === module) { - generate(true).then(() => - log.info(HELPERS.masterfile, 'Masterfile generated'), - ) + generate(true).then(() => log.info(HELPERS.masterfile, 'OK')) } const read = () => { diff --git a/packages/types/lib/general.d.ts b/packages/types/lib/general.d.ts index 0bd1a0c62..434de68db 100644 --- a/packages/types/lib/general.d.ts +++ b/packages/types/lib/general.d.ts @@ -128,3 +128,20 @@ export interface RMSliderProps { values: number[] handleChange: RMSliderHandleChange } + +export type ScanTypes = 'scanNext' | 'scanZone' + +export interface ScanOnDemandData { + typeName: ScanTypes + type: 'scan_next' + scanCoords?: [number, number][] + scanLocation?: [number, number] + scanSize?: number + cooldown?: number +} + +export interface ScanOnDemandReq { + category: ScanTypes | 'getQueue' + method: HttpMethod + data?: ScanOnDemandData +} diff --git a/packages/types/lib/server.d.ts b/packages/types/lib/server.d.ts index 382ad0110..ce9cf387f 100644 --- a/packages/types/lib/server.d.ts +++ b/packages/types/lib/server.d.ts @@ -139,7 +139,7 @@ export interface GqlContext { user: string transaction: Transaction operation: 'query' | 'mutation' - startTime: number + startTime?: number } export interface Permissions { diff --git a/server/src/configs/default.json b/server/src/configs/default.json index 54a733e39..9379317fe 100644 --- a/server/src/configs/default.json +++ b/server/src/configs/default.json @@ -595,13 +595,14 @@ }, "scanner": { "backendConfig": { - "platform": "rdm/mad", + "platform": "rdm/mad/custom", "apiEndpoint": "http://ip:port/api/", "headers": [], "apiUsername": "username", "apiPassword": "password", "queueRefreshInterval": 5, - "sendDiscordMessage": true + "sendDiscordMessage": true, + "sendTelegramMessage": true }, "scanNext": { "enabled": false, @@ -681,6 +682,10 @@ { "name": "telegram", "type": "telegram", + "logGroupId": "", + "scanNextLogGroupId": "", + "scanZoneLogGroupId": "", + "eventLogGroupId": "", "enabled": false, "botToken": "", "groups": [], diff --git a/server/src/graphql/resolvers.js b/server/src/graphql/resolvers.js index b8c40e586..7351fd43a 100644 --- a/server/src/graphql/resolvers.js +++ b/server/src/graphql/resolvers.js @@ -6,7 +6,6 @@ const config = require('@rm/config') const buildDefaultFilters = require('../services/filters/builder/base') const filterComponents = require('../services/functions/filterComponents') -const { filterRTree } = require('../services/functions/filterRTree') const validateSelectedWebhook = require('../services/functions/validateSelectedWebhook') const PoracleAPI = require('../services/api/Poracle') const { geocoder } = require('../services/geocoder') @@ -14,6 +13,7 @@ const scannerApi = require('../services/api/scannerApi') const getPolyVector = require('../services/functions/getPolyVector') const getPlacementCells = require('../services/functions/getPlacementCells') const getTypeCells = require('../services/functions/getTypeCells') +const { getValidCoords } = require('../services/functions/getValidCoords') /** @type {import("@apollo/server").ApolloServerOptions['resolvers']} */ const resolvers = { @@ -106,22 +106,8 @@ const resolvers = { return !!results.length }, /** @param {unknown} _ @param {{ mode: 'scanNext' | 'scanZone' }} args */ - checkValidScan: (_, { mode, points }, { perms }) => { - if (perms?.scanner.includes(mode)) { - const areaRestrictions = - config.getSafe(`scanner.${mode}.${mode}AreaRestriction`) || [] - - const validPoints = points.map((point) => - filterRTree( - { lat: point[0], lon: point[1] }, - perms.areaRestrictions, - areaRestrictions, - ), - ) - return validPoints - } - return [] - }, + checkValidScan: (_, { mode, points }, { perms }) => + getValidCoords(mode, points, perms), /** @param {unknown} _ @param {{ component: 'loginPage' | 'donationPage' | 'messageOfTheDay' }} args */ customComponent: (_, { component }, { perms, req, user }) => { switch (component) { @@ -521,16 +507,9 @@ const resolvers = { })) } if (category === 'invasion') { - const { invasions } = Event.masterfile result.invasion = result.invasion.map((x) => ({ ...x, - real_grunt_id: - +Object.keys(invasions).find( - (key) => - invasions[key]?.type?.toLowerCase() === - x.grunt_type.toLowerCase() && - invasions[key].gender === (x.gender || 1), - ) || 0, + real_grunt_id: PoracleAPI.getRealGruntId(x, Event.invasions), })) } if (category === 'raid') { @@ -539,7 +518,6 @@ const resolvers = { allMoves: x.move === 9000, })) } - return result } return {} @@ -598,20 +576,33 @@ const resolvers = { } return {} }, + /** @param {unknown} _ @param {import('@rm/types').ScanOnDemandReq} args */ scanner: (_, args, { req, perms }) => { const { category, method, data } = args - if (data?.cooldown) { - req.session.cooldown = Math.max( - req.session.cooldown || 0, - data.cooldown || 0, - ) - req.session.save() - } if (category === 'getQueue') { return scannerApi(category, method, data, req?.user) } - if (perms?.scanner?.includes(category)) { - return scannerApi(category, method, data, req?.user) + if ( + perms?.scanner?.includes(category) && + (!req.session.cooldown || req.session.cooldown < Date.now()) + ) { + const validCoords = getValidCoords(category, data?.scanCoords, perms) + + const cooldown = + config.getSafe(`scanner.${category}.userCooldownSeconds`) * + validCoords.filter(Boolean).length * + 1000 + + Date.now() + req.session.cooldown = cooldown + return scannerApi( + category, + method, + { + ...data, + scanCoords: data.scanCoords?.filter((__, i) => validCoords[i]), + }, + req?.user, + ) } return {} }, @@ -665,6 +656,27 @@ const resolvers = { status, data, ) + if (category === 'pokemon') { + result.pokemon = result.pokemon.map((x) => ({ + ...x, + allForms: !x.form, + pvpEntry: !!x.pvp_ranking_league, + xs: x.max_weight !== 9000000, + xl: x.min_weight !== 0, + })) + } + if (category === 'invasion') { + result.invasion = result.invasion.map((x) => ({ + ...x, + real_grunt_id: PoracleAPI.getRealGruntId(x, Event.invasions), + })) + } + if (category === 'raid') { + result.raid = result.raid.map((x) => ({ + ...x, + allMoves: x.move === 9000, + })) + } return result } return {} diff --git a/server/src/graphql/server.js b/server/src/graphql/server.js index 9b850c21f..8245656b5 100644 --- a/server/src/graphql/server.js +++ b/server/src/graphql/server.js @@ -8,6 +8,10 @@ const { GraphQLFileLoader } = require('@graphql-tools/graphql-file-loader') const { ApolloServerPluginDrainHttpServer, } = require('@apollo/server/plugin/drainHttpServer') +const { + ApolloServerPluginLandingPageDisabled, +} = require('@apollo/server/plugin/disabled') + const config = require('@rm/config') const { log, HELPERS } = require('@rm/logger') @@ -28,7 +32,7 @@ async function startApollo(httpServer) { const apolloServer = new ApolloServer({ typeDefs, resolvers, - introspection: config.getSafe('devOptions.enabled'), + introspection: config.getSafe('devOptions.graphiql'), formatError: (e) => { let customMessage = '' if ( @@ -76,12 +80,14 @@ async function startApollo(httpServer) { error: (...e) => log.error(HELPERS.gql, ...e), }, plugins: [ + ApolloServerPluginLandingPageDisabled(), ApolloServerPluginDrainHttpServer({ httpServer }), { async requestDidStart(requestContext) { requestContext.contextValue.startTime = Date.now() - - log.debug(requestContext.request?.variables?.filters) + if (requestContext.request?.variables?.filters) { + log.debug(requestContext.request?.variables?.filters) + } return { async willSendResponse(context) { const filterCount = Object.keys( diff --git a/server/src/index.js b/server/src/index.js index 578dcee3e..15ececc5d 100644 --- a/server/src/index.js +++ b/server/src/index.js @@ -62,9 +62,8 @@ if (sentry.enabled || process.env.SENTRY_DSN) { ...Sentry.autoDiscoverNodePerformanceMonitoringIntegrations(), ], tracesSampleRate: - parseFloat( - process.env.SENTRY_TRACES_SAMPLE_RATE || sentry.tracesSampleRate, - ) || 0.1, + +(process.env.SENTRY_TRACES_SAMPLE_RATE || sentry.tracesSampleRate) || + 0.1, release: pkg.version, }) @@ -215,10 +214,10 @@ app.use((err, req, res, next) => { startApollo(httpServer).then((server) => { app.use( '/graphql', - cors(), + cors({ origin: '/' }), json(), expressMiddleware(server, { - context: ({ req, res }) => { + context: async ({ req, res }) => { const perms = req.user ? req.user.perms : req.session.perms const user = req?.user?.username || '' const id = req?.user?.id || 0 diff --git a/server/src/models/Pokestop.js b/server/src/models/Pokestop.js index f94b6be5e..3028ec903 100644 --- a/server/src/models/Pokestop.js +++ b/server/src/models/Pokestop.js @@ -207,6 +207,7 @@ class Pokestop extends Model { const general = [] const rocketPokemon = [] const displayTypes = [] + let hasShowcase = false // preps arrays for interested objects Object.keys(args.filters).forEach((pokestop) => { switch (pokestop.charAt(0)) { @@ -214,7 +215,7 @@ class Pokestop extends Model { break case 'f': case 'h': - // do nothing + hasShowcase = true break case 'd': stardust.push(pokestop.slice(1).split('-')[0]) @@ -254,6 +255,7 @@ class Pokestop extends Model { break } }) + if (hasShowcase) displayTypes.push('9') // builds the query query.andWhere((stops) => { @@ -705,8 +707,8 @@ class Pokestop extends Model { .filter((event) => isMad && !hasMultiInvasions ? MADE_UP_MAD_INVASIONS.includes(event.grunt_type) || - (!event.grunt_type && filters[`b${event.display_type}`]) - : !event.grunt_type && filters[`b${event.display_type}`], + !event.grunt_type + : !event.grunt_type, ) .map((event) => ({ event_expire_timestamp: event.incident_expire_timestamp, @@ -739,7 +741,7 @@ class Pokestop extends Model { ] : event.showcase_pokemon_type_id ? filters[`h${event.showcase_pokemon_type_id}`] - : true, + : filters[`b${event.display_type}`], ) } if ( diff --git a/server/src/services/DiscordClient.js b/server/src/services/DiscordClient.js index 75c4d4007..4c18a90a3 100644 --- a/server/src/services/DiscordClient.js +++ b/server/src/services/DiscordClient.js @@ -219,7 +219,10 @@ class DiscordClient { } } - /** @param {import('discord.js').APIEmbed} embed @param {string} channel */ + /** + * @param {import('discord.js').APIEmbed} embed + * @param {keyof DiscordClient['loggingChannels']} channel + */ async sendMessage(embed, channel = 'main') { const safeChannel = this.loggingChannels[channel] if (!safeChannel || typeof embed !== 'object') { diff --git a/server/src/services/EventManager.js b/server/src/services/EventManager.js index e23f03db9..ef8e13260 100644 --- a/server/src/services/EventManager.js +++ b/server/src/services/EventManager.js @@ -116,19 +116,23 @@ class EventManager { /** * - * @param {import('discord.js').APIEmbed} embed + * @param {import('discord.js').APIEmbed | string} embed * @param {string} [clientName] */ async chatLog(embed, clientName) { if (clientName) { const client = this.Clients[clientName] - if ('sendMessage' in client) { + if ('discordEvents' in client && typeof embed === 'object') { + await client.sendMessage(embed, 'event') + } else if (typeof embed === 'string') { await client.sendMessage(embed, 'event') } } else { await Promise.allSettled( Object.values(this.Clients).map(async (client) => { - if ('sendMessage' in client) { + if ('discordEvents' in client && typeof embed === 'object') { + await client.sendMessage(embed, 'event') + } else if (typeof embed === 'string') { await client.sendMessage(embed, 'event') } }), diff --git a/server/src/services/TelegramClient.js b/server/src/services/TelegramClient.js index 37d1f8235..80bab455d 100644 --- a/server/src/services/TelegramClient.js +++ b/server/src/services/TelegramClient.js @@ -27,6 +27,12 @@ class TelegramClient { this.alwaysEnabledPerms = config.getSafe( 'authentication.alwaysEnabledPerms', ) + this.loggingChannels = { + main: strategy.logGroupId, + event: strategy.eventLogGroupId, + scanNext: strategy.scanNextLogGroupId, + scanZone: strategy.scanZoneLogGroupId, + } } /** @param {TGUser} user */ @@ -194,6 +200,45 @@ class TelegramClient { } } + /** + * + * @param {string} text + * @param {keyof TelegramClient['loggingChannels']} channel + */ + async sendMessage(text, channel = 'main') { + if (!this.loggingChannels[channel]) return + try { + const response = await fetch( + `https://api.telegram.org/bot${this.strategy.botToken}/sendMessage`, + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + chat_id: this.loggingChannels[channel], + parse_mode: 'HTML', + disable_web_page_preview: true, + text, + }), + }, + ) + if (!response.ok) { + throw new Error( + `Telegram API error: ${response.status} ${response.statusText}`, + ) + } + log.info( + HELPERS.custom(this.rmStrategy, '#26A8EA'), + `${channel} Log Sent`, + ) + } catch (e) { + log.error( + HELPERS.custom(this.rmStrategy, '#26A8EA'), + `Error sending ${channel} Log`, + e, + ) + } + } + initPassport() { passport.use( this.rmStrategy, diff --git a/server/src/services/api/Poracle.js b/server/src/services/api/Poracle.js index d2c21da37..1ca622c53 100644 --- a/server/src/services/api/Poracle.js +++ b/server/src/services/api/Poracle.js @@ -1231,6 +1231,23 @@ class PoracleAPI { // this.disabledHooks.forEach((hook) => delete poracleUiObj[hook]) return poracleUiObj } + + /** + * + * @param {import('@rm/types').PoracleInvasion} item + * @param {import('@rm/types').Masterfile['invasions']} invasions + */ + static getRealGruntId(item, invasions) { + return ( + +Object.keys(invasions).find( + (key) => + invasions[key]?.type?.toLowerCase() === + item.grunt_type.toLowerCase() && + (invasions[key]?.gender === 0 || + invasions[key].gender === (item.gender || 1)), + ) || 0 + ) + } } module.exports = PoracleAPI diff --git a/server/src/services/api/scannerApi.js b/server/src/services/api/scannerApi.js index 85d443ff8..296507f28 100644 --- a/server/src/services/api/scannerApi.js +++ b/server/src/services/api/scannerApi.js @@ -1,10 +1,14 @@ -/* eslint-disable no-nested-ternary */ +// @ts-check const { default: fetch } = require('node-fetch') const NodeCache = require('node-cache') const config = require('@rm/config') const { log, HELPERS } = require('@rm/logger') + +const { getCache, setCache } = require('../cache') const Clients = require('../Clients') +const TelegramClient = require('../TelegramClient') +const DiscordClient = require('../DiscordClient') const scannerQueue = { scanNext: {}, @@ -13,6 +17,52 @@ const scannerQueue = { const userCache = new NodeCache({ stdTTL: 60 * 60 * 24 }) +const onShutdown = async () => { + const cacheObj = {} + userCache.keys().forEach((key) => { + cacheObj[key] = userCache.get(key) + }) + await setCache('scanUserHistory.json', cacheObj) +} +process.on('SIGINT', async () => { + await onShutdown() + process.exit(0) +}) +process.on('SIGTERM', async () => { + await onShutdown() + process.exit(0) +}) +process.on('SIGUSR1', async () => { + await onShutdown() + process.exit(0) +}) +process.on('SIGUSR2', async () => { + await onShutdown() + process.exit(0) +}) + +Object.entries(getCache('scanUserHistory.json', {})).forEach(([k, v]) => + userCache.set(k, v), +) + +const backendConfig = config.getSafe('scanner.backendConfig') + +const dateFormat = new Intl.DateTimeFormat(undefined, { + dateStyle: 'short', + timeStyle: 'medium', +}) +const timeFormat = new Intl.DateTimeFormat(undefined, { + timeStyle: 'medium', +}) + +/** + * + * @param {import('packages/types/lib').ScanOnDemandReq['category']} category + * @param {import('packages/types/lib').ScanOnDemandReq['method']} method + * @param {import('packages/types/lib').ScanOnDemandReq['data']} data + * @param {Partial} user + * @returns + */ async function scannerApi( category, method, @@ -26,12 +76,12 @@ async function scannerApi( }, config.api.fetchTimeoutMs) const coords = - config.scanner.backendConfig.platform === 'mad' + backendConfig.platform === 'mad' ? [ parseFloat(data.scanCoords[0][0].toFixed(5)), parseFloat(data.scanCoords[0][1].toFixed(5)), ] - : config.scanner.backendConfig.platform === 'custom' + : backendConfig.platform === 'custom' ? data.scanCoords?.map((coord) => [ parseFloat(coord[0].toFixed(5)), parseFloat(coord[1].toFixed(5)), @@ -43,28 +93,25 @@ async function scannerApi( try { const headers = Object.fromEntries( - config.scanner.backendConfig.headers.map((header) => [ + backendConfig.headers.map((header) => [ typeof header === 'string' ? header : header.key || header.name, typeof header === 'string' ? header : header.value, ]), ) - switch (config.scanner.backendConfig.platform) { + switch (backendConfig.platform) { case 'mad': case 'rdm': Object.assign(headers, { Authorization: `Basic ${Buffer.from( - `${config.scanner.backendConfig.apiUsername}:${config.scanner.backendConfig.apiPassword}`, + `${backendConfig.apiUsername}:${backendConfig.apiPassword}`, ).toString('base64')}`, }) break case 'custom': - if ( - config.scanner.backendConfig.apiUsername || - config.scanner.backendConfig.apiPassword - ) { + if (backendConfig.apiUsername || backendConfig.apiPassword) { Object.assign(headers, { Authorization: `Basic ${Buffer.from( - `${config.scanner.backendConfig.apiUsername}:${config.scanner.backendConfig.apiPassword}`, + `${backendConfig.apiUsername}:${backendConfig.apiPassword}`, ).toString('base64')}`, }) } @@ -72,10 +119,11 @@ async function scannerApi( default: break } - const payloadObj = /** @type {{ url: string, options: RequestInit }} */ ({ - url: '', - options: {}, - }) + const payloadObj = + /** @type {{ url: string, options: import('node-fetch').RequestInit }} */ ({ + url: '', + options: {}, + }) const cache = userCache.has(user.id) ? userCache.get(user.id) : { coordinates: 0, requests: 0 } @@ -94,11 +142,11 @@ async function scannerApi( 5, )},${data.scanLocation[1].toFixed(5)}`, ) - switch (config.scanner.backendConfig.platform) { + switch (backendConfig.platform) { case 'mad': Object.assign(payloadObj, { url: `${ - config.scanner.backendConfig.apiEndpoint + backendConfig.apiEndpoint }/send_gps?origin=${encodeURIComponent( config.scanner.scanNext.scanNextDevice, )}&coords=${JSON.stringify(coords)}&sleeptime=${ @@ -110,7 +158,7 @@ async function scannerApi( case 'rdm': Object.assign(payloadObj, { url: `${ - config.scanner.backendConfig.apiEndpoint + backendConfig.apiEndpoint }/set_data?scan_next=true&instance=${encodeURIComponent( config.scanner.scanNext.scanNextInstance, )}&coords=${JSON.stringify(coords)}`, @@ -119,7 +167,7 @@ async function scannerApi( break case 'custom': Object.assign(payloadObj, { - url: config.scanner.backendConfig.apiEndpoint, + url: backendConfig.apiEndpoint, options: { method: 'POST', headers, @@ -144,10 +192,10 @@ async function scannerApi( 5, )},${data.scanLocation[1].toFixed(5)}`, ) - switch (config.scanner.backendConfig.platform) { + switch (backendConfig.platform) { case 'custom': Object.assign(payloadObj, { - url: config.scanner.backendConfig.apiEndpoint, + url: backendConfig.apiEndpoint, options: { method: 'POST', headers, @@ -158,7 +206,7 @@ async function scannerApi( default: Object.assign(payloadObj, { url: `${ - config.scanner.backendConfig.apiEndpoint + backendConfig.apiEndpoint }/set_data?scan_next=true&instance=${encodeURIComponent( config.scanner.scanZone.scanZoneInstance, )}&coords=${JSON.stringify(coords)}`, @@ -170,7 +218,7 @@ async function scannerApi( case 'getQueue': if ( scannerQueue[data.typeName].timestamp > - Date.now() - config.scanner.backendConfig.queueRefreshInterval * 1000 + Date.now() - backendConfig.queueRefreshInterval * 1000 ) { log.info( HELPERS.scanner, @@ -181,16 +229,16 @@ async function scannerApi( return { status: 'ok', message: scannerQueue[data.typeName].queue } } log.info(HELPERS.scanner, `Getting queue for method ${data.typeName}`) - switch (config.scanner.backendConfig.platform) { + switch (backendConfig.platform) { case 'custom': Object.assign(payloadObj, { - url: `${config.scanner.backendConfig.apiEndpoint}/queue`, + url: `${backendConfig.apiEndpoint}/queue`, options: { method, headers }, }) break default: Object.assign(payloadObj, { - url: `${config.scanner.backendConfig.apiEndpoint}/get_data?${ + url: `${backendConfig.apiEndpoint}/get_data?${ data.type }=true&queue_size=true&instance=${encodeURIComponent( config.scanner[data.typeName][`${data.typeName}Instance`], @@ -232,7 +280,7 @@ async function scannerApi( (scannerResponse.status === 200 || scannerResponse.status === 201) && category === 'getQueue' ) { - if (config.scanner.backendConfig.platform === 'custom') { + if (backendConfig.platform === 'custom') { const { queue } = await scannerResponse.json() log.info( HELPERS.scanner, @@ -256,70 +304,90 @@ async function scannerApi( return { status: 'ok', message: queueData.size } } - if ( - Clients[user.rmStrategy]?.sendMessage && - config.scanner.backendConfig.sendDiscordMessage - ) { + if (backendConfig.sendTelegramMessage || backendConfig.sendDiscordMessage) { const capitalized = category.replace('scan', 'Scan ') const updatedCache = userCache.get(user.id) const trimmed = coords .filter((_c, i) => i < 25) .map((c) => - config.scanner.backendConfig.platform === 'custom' + backendConfig.platform === 'custom' ? `${c[0]}, ${c[1]}` - : `${c.lat}, ${c.lon}`, + : typeof c === 'object' + ? `${'lat' in c && c.lat}, ${'lon' in c && c.lon}` + : c, ) .join('\n') - switch (user.strategy) { - case 'discord': - Clients[user.rmStrategy].sendMessage( - { - title: `${capitalized} Request`, - author: { - name: user.username, - icon_url: `https://cdn.discordapp.com/avatars/${user.discordId}/${user.avatar}.png`, + const client = Clients[user.rmStrategy] + if ( + client instanceof TelegramClient && + backendConfig.sendTelegramMessage + ) { + client.sendMessage( + `${capitalized} Request\nSize: ${ + data.scanSize + }\nCoordinates: ${coords.length}\nCenter: ${data.scanLocation + ?.map((c) => c.toFixed(5)) + .join(', ')}\n\nUser History\nUsername: ${ + user.username || user.telegramId + }\nTotal Requests: ${ + updatedCache?.requests || 0 + }\nTotal Coordinates: ${ + updatedCache?.coordinates || 0 + }\n\n${dateFormat.format(Date.now())}`, + category === 'getQueue' ? 'main' : category, + ) + } else if ( + client instanceof DiscordClient && + backendConfig.sendDiscordMessage + ) { + client.sendMessage( + { + title: `${capitalized} Request`, + author: { + name: user.username, + icon_url: `https://cdn.discordapp.com/avatars/${user.discordId}/${user.avatar}.png`, + }, + thumbnail: { + url: + config.authentication.strategies.find( + (strategy) => strategy.name === user.rmStrategy, + )?.thumbnailUrl ?? + `https://user-images.githubusercontent.com/58572875/167069223-745a139d-f485-45e3-a25c-93ec4d09779c.png`, + }, + footer: { + text: timeFormat.format(Date.now()), + }, + description: `<@${user.discordId}>\n${capitalized} Size: ${data.scanSize}\nCoordinates: ${coords.length}\n`, + fields: [ + { + name: `User History`, + value: `Total Requests: ${ + updatedCache?.requests || 0 + }\nTotal Coordinates: ${updatedCache?.coordinates || 0}`, + inline: true, }, - thumbnail: { - url: - config.authentication.strategies.find( - (strategy) => strategy.name === user.rmStrategy, - )?.thumbnailUrl ?? - `https://user-images.githubusercontent.com/58572875/167069223-745a139d-f485-45e3-a25c-93ec4d09779c.png`, + { + name: 'Instance', + value: `${ + backendConfig.platform === 'mad' + ? `Device: ${config.scanner.scanNext.scanNextDevice}` + : '' + }\nName: ${ + config.scanner[category]?.[`${category}Instance`] || '-' + }\nQueue: ${scannerQueue[category]?.queue || 0}`, + inline: true, }, - timestamp: new Date(), - description: `<@${user.discordId}>\n${capitalized} Size: ${data.scanSize}\nCoordinates: ${coords.length}\n`, - fields: [ - { - name: `User History`, - value: `Total Requests: ${ - updatedCache?.requests || 0 - }\nTotal Coordinates: ${updatedCache?.coordinates || 0}`, - inline: true, - }, - { - name: 'Instance', - value: `${ - config.scanner.backendConfig.platform === 'mad' - ? `Device: ${config.scanner.scanNext.scanNextDevice}` - : '' - }\nName: ${ - config.scanner[category]?.[`${category}Instance`] || '-' - }\nQueue: ${scannerQueue[category]?.queue || 0}`, - inline: true, - }, - { - name: `Coordinates (${coords.length})`, - value: - coords.length > 25 - ? `${trimmed}\n...${coords.length - 25} more` - : trimmed, - }, - ], - }, - category, - ) - break - default: + { + name: `Coordinates (${coords.length})`, + value: + coords.length > 25 + ? `${trimmed}\n...${coords.length - 25} more` + : trimmed, + }, + ], + }, + category === 'getQueue' ? 'main' : category, + ) } } diff --git a/server/src/services/functions/getValidCoords.js b/server/src/services/functions/getValidCoords.js new file mode 100644 index 000000000..4c3cbcf53 --- /dev/null +++ b/server/src/services/functions/getValidCoords.js @@ -0,0 +1,34 @@ +// @ts-check +const config = require('@rm/config') + +const { filterRTree } = require('./filterRTree') + +/** + * + * @param {'scanNext' | 'scanZone'} mode + * @param {[number, number][]} points + * @param {import('@rm/types').Permissions} perms + */ +function getValidCoords(mode, points, perms) { + if (perms?.scanner?.includes(mode) && points?.length) { + const configString = + mode === 'scanNext' + ? 'scanner.scanNext.scanNextAreaRestriction' + : 'scanner.scanZone.scanZoneAreaRestriction' + const areaRestrictions = config.getSafe(configString) || [] + + const validPoints = points.map((point) => + filterRTree( + { lat: point[0], lon: point[1] }, + perms.areaRestrictions, + areaRestrictions, + ), + ) + return validPoints + } + return [] +} + +module.exports = { + getValidCoords, +} diff --git a/src/assets/css/main.css b/src/assets/css/main.css index 6523efe9d..f7025d4ae 100644 --- a/src/assets/css/main.css +++ b/src/assets/css/main.css @@ -55,11 +55,6 @@ body { border-radius: 0.5rem !important; } -.leaflet-control-locate > a { - font-size: 16.8px; - padding-left: 1.5px; -} - .table-pvp { margin-left: auto; margin-right: auto; diff --git a/src/components/layout/dialogs/scanner/ScanDialog.jsx b/src/components/layout/dialogs/scanner/ScanDialog.jsx index 641e9433d..73092d48f 100644 --- a/src/components/layout/dialogs/scanner/ScanDialog.jsx +++ b/src/components/layout/dialogs/scanner/ScanDialog.jsx @@ -26,6 +26,20 @@ export default function ScanDialog() { if (scanZone) return setScanMode('scanZoneMode') }, [scanNext, scanZone]) + const footerOptions = React.useMemo( + () => + /** @type {import('@components/layout/general/Footer').FooterButton[]} */ ([ + { + name: 'close', + icon: 'Clear', + color: 'primary', + align: 'right', + action: handleClose, + }, + ]), + [handleClose], + ) + return ( - {t(`scan_${scanMode}`)} + {scanMode && t(`scan_${scanMode}`)} -
+
) } diff --git a/src/components/layout/dialogs/scanner/scanZone/PopupContent.jsx b/src/components/layout/dialogs/scanner/scanZone/PopupContent.jsx index 07583b8d5..16640fdb6 100644 --- a/src/components/layout/dialogs/scanner/scanZone/PopupContent.jsx +++ b/src/components/layout/dialogs/scanner/scanZone/PopupContent.jsx @@ -2,7 +2,7 @@ import * as React from 'react' import { Button, ButtonGroup, Slider, List, ListItem } from '@mui/material' import { useTranslation } from 'react-i18next' -import debounce from 'lodash.debounce' +import { debounce } from 'lodash' import AdvancedAccordion from '@components/layout/custom/AdvancedAccordion' import { RADIUS_CHOICES } from '@assets/constants' diff --git a/src/components/layout/dialogs/search/useSendSearch.js b/src/components/layout/dialogs/search/useSendSearch.js index 86c4eef23..7652fdc3b 100644 --- a/src/components/layout/dialogs/search/useSendSearch.js +++ b/src/components/layout/dialogs/search/useSendSearch.js @@ -1,7 +1,7 @@ import { useState, useCallback, useMemo, useEffect } from 'react' import { useLazyQuery } from '@apollo/client' import { useTranslation } from 'react-i18next' -import debounce from 'lodash.debounce' +import { debounce } from 'lodash' import Query from '@services/Query' import Utility from '@services/Utility' diff --git a/src/components/layout/dialogs/webhooks/Manage.jsx b/src/components/layout/dialogs/webhooks/Manage.jsx index cfb4211a1..2993b0ba8 100644 --- a/src/components/layout/dialogs/webhooks/Manage.jsx +++ b/src/components/layout/dialogs/webhooks/Manage.jsx @@ -38,10 +38,11 @@ export default function Manage() { const feedbackLink = useMemory((s) => s.config.links.feedbackLink) const filters = useGenFullFilters() + const liveFilters = useWebhookStore((s) => s.tempFilters) /** @type {ReturnType>} */ const dialogRef = React.useRef(null) - const [addNew, setAddNew] = React.useState(false) + const [addNew, setAddNew] = React.useState({ open: false, save: false }) const [height, setHeight] = React.useState(0) const footerButtons = React.useMemo(() => { @@ -55,19 +56,19 @@ export default function Manage() { color: 'success', }, { - name: addNew + name: addNew.open ? 'save' : category === 'human' ? t('manage_profiles') : t('add_new', { category: t(category) }), - action: () => setAddNew((prev) => !prev), + action: () => setAddNew({ open: true, save: false }), key: 'addNew', - icon: addNew ? 'Save' : 'Add', + icon: addNew.open ? 'Save' : 'Add', disabled: !categories.length, color: 'secondary', }, ] - if (!addNew) { + if (!addNew.open) { buttons.push({ name: 'close', action: setMode, @@ -83,13 +84,13 @@ export default function Manage() { Utility.analytics('Webhook', `${category} Webhook Page`, category, true) useWebhookStore.setState({ tempFilters: { ...filters[category] } }) setSelected()() - if (dialogRef.current && !addNew) { + if (dialogRef.current && !addNew.open) { setHeight(dialogRef.current.clientHeight) } }, [category]) React.useEffect(() => { - if (!addNew && category !== 'human') { + if (!addNew.open && addNew.save && category !== 'human') { const { tempFilters } = useWebhookStore.getState() const values = Poracle.processor( category, @@ -122,18 +123,18 @@ export default function Manage() { const tabValue = categories.findIndex((x) => x === category) - return category !== 'human' && addNew ? ( + return category !== 'human' && addNew.open ? ( setAddNew(false)} + titleAction={() => setAddNew({ open: false, save: false })} extraButtons={[ { name: 'save', - action: () => setAddNew(false), + action: () => setAddNew({ open: false, save: true }), icon: 'Save', color: 'secondary', }, @@ -146,9 +147,12 @@ export default function Manage() {
- + {categories.map((each) => ( - + {category !== 'human' && ( @@ -175,7 +179,7 @@ export default function Manage() { - + {category === 'human' && } diff --git a/src/components/layout/dialogs/webhooks/WebhookAdv.jsx b/src/components/layout/dialogs/webhooks/WebhookAdv.jsx index a2c20676a..82ce2cfb7 100644 --- a/src/components/layout/dialogs/webhooks/WebhookAdv.jsx +++ b/src/components/layout/dialogs/webhooks/WebhookAdv.jsx @@ -71,6 +71,7 @@ const skipFields = new Set([ 'shiny', 'everything_individually', 'all', + 'real_grunt_id', ]) const wildCards = { @@ -97,6 +98,20 @@ export default function WebhookAdvanced() { const { pokemon, moves, types } = useMemory((s) => s.masterfile) const isMobile = useMemory((s) => s.isMobile) + const [filterValues, setFilterValues] = React.useState( + tempFilters?.template + ? Poracle.reactMapFriendly(tempFilters) + : { + ...Poracle.reactMapFriendly(info?.defaults), + profile_no: human.current_profile_no, + }, + ) + const [poracleValues, setPoracleValues] = React.useState( + tempFilters?.template + ? tempFilters + : { ...info?.defaults, profile_no: human.current_profile_no }, + ) + Utility.analytics(`/poracle/${category}`) const [search, { data, previousData, loading }] = useLazyQuery( @@ -112,19 +127,6 @@ export default function WebhookAdvanced() { }, ) const fetchedData = data || previousData - const [filterValues, setFilterValues] = React.useState( - tempFilters?.template - ? Poracle.reactMapFriendly(tempFilters) - : { - ...Poracle.reactMapFriendly(info?.defaults), - profile_no: human.current_profile_no, - }, - ) - const [poracleValues, setPoracleValues] = React.useState( - tempFilters?.template - ? tempFilters - : { ...info?.defaults, profile_no: human.current_profile_no }, - ) React.useEffect(() => { setPoracleValues( @@ -142,6 +144,13 @@ export default function WebhookAdvanced() { ) }, [tempFilters, id, human.current_profile_no, info?.defaults]) + React.useEffect(() => { + setPoracleValues((prev) => ({ + ...prev, + everything_individually: !!selectedIds.length, + })) + }, [selectedIds]) + const handleSlider = React.useCallback( (low, high) => (name, values) => { setFilterValues((prev) => ({ ...prev, [name]: values })) @@ -757,54 +766,57 @@ export default function WebhookAdvanced() { } const handleClose = (save, filterId, filterToSave) => { - if (save) { - if (filterId === 'global' && filterToSave) { - const newFilters = {} - const wc = wildCards[category] || ['0-0'] - if (filterToSave.everything_individually !== false) { - selectedIds.forEach((item) => { - if (!wc.includes(item)) { + const realSave = typeof save === 'boolean' && save + if (realSave) { + useWebhookStore.setState((prev) => { + if (filterId === 'global' && filterToSave) { + const newFilters = {} + const wc = wildCards[category] || ['0-0'] + if (filterToSave.everything_individually !== false) { + selectedIds.forEach((item) => { newFilters[item] = { - ...tempFilters[item], + ...prev.tempFilters[item], ...filterToSave, enabled: true, } - } - }) - } else { - wc.forEach((item) => { - newFilters[item] = { - ...tempFilters[item], - ...filterToSave, - enabled: true, - } - }) + }) + } else { + wc.forEach((item) => { + newFilters[item] = { + ...prev.tempFilters[item], + ...filterToSave, + enabled: true, + } + }) + } + return { + tempFilters: { + ...prev.tempFilters, + ...newFilters, + [filterId]: { ...filterToSave }, + }, + } } - useWebhookStore.setState((prev) => ({ - tempFilters: { - ...prev.tempFilters, - ...newFilters, - [filterId]: { ...filterToSave }, - }, - })) - } else if (filterId && filterToSave) { - useWebhookStore.setState((prev) => ({ - tempFilters: { - ...prev.tempFilters, - [filterId]: { - ...prev.tempFilters[id], - ...filterToSave, - enabled: true, + if (filterId && filterToSave) { + return { + tempFilters: { + ...prev.tempFilters, + [filterId]: { + ...prev.tempFilters[id], + ...filterToSave, + enabled: true, + }, }, - }, - })) - } + } + } + return prev + }) } else { useWebhookStore.setState((prev) => ({ tempFilters: { ...prev.tempFilters, [filterId]: { ...info?.defaults } }, })) } - if (onClose) onClose(poracleValues) + if (onClose) onClose(poracleValues, realSave) useWebhookStore.setState((prev) => ({ advanced: { ...prev.advanced, open: false, selectedIds: [] }, })) @@ -818,7 +830,7 @@ export default function WebhookAdvanced() { icon: 'Save', }, ], - [id, poracleValues], + [id, poracleValues, selectedIds], ) if (!info || !tempFilters) return null diff --git a/src/components/layout/dialogs/webhooks/store.js b/src/components/layout/dialogs/webhooks/store.js index c81999884..6b46dee95 100644 --- a/src/components/layout/dialogs/webhooks/store.js +++ b/src/components/layout/dialogs/webhooks/store.js @@ -34,7 +34,7 @@ import { create } from 'zustand' * category: string * selectedIds: string[] * open: boolean - * onClose?: (newFilters: object) => void + * onClose?: (newFilters: object, save?: boolean) => void * } * }} WebhookStore * @type {import("zustand").UseBoundStore>} @@ -127,3 +127,19 @@ export const setSelected = (id) => () => { selected: id ? { ...prev.selected, [id]: !prev.selected[id] } : {}, })) } + +/** + * @param {boolean} enabled + * @param {string[]} ids + */ +export const applyToAllWebhooks = (enabled, ids) => { + const selected = new Set(ids) + useWebhookStore.setState((prev) => ({ + tempFilters: Object.fromEntries( + Object.entries(prev.tempFilters).map(([k, v]) => [ + k, + selected.has(k) ? { ...v, enabled } : v, + ]), + ), + })) +} diff --git a/src/components/layout/dialogs/webhooks/tiles/TrackedTile.jsx b/src/components/layout/dialogs/webhooks/tiles/TrackedTile.jsx index 5f9d44d05..0683e75d7 100644 --- a/src/components/layout/dialogs/webhooks/tiles/TrackedTile.jsx +++ b/src/components/layout/dialogs/webhooks/tiles/TrackedTile.jsx @@ -1,7 +1,11 @@ import * as React from 'react' import DeleteForever from '@mui/icons-material/DeleteForever' import Edit from '@mui/icons-material/Edit' -import { Grid, Typography, IconButton, Checkbox, Box } from '@mui/material' +import Grid2 from '@mui/material/Unstable_Grid2/Grid2' +import Typography from '@mui/material/Typography' +import IconButton from '@mui/material/IconButton' +import Checkbox from '@mui/material/Checkbox' +import Box from '@mui/material/Box' import Utility from '@services/Utility' import Poracle from '@services/Poracle' @@ -14,7 +18,7 @@ import { useWebhookStore, setSelected } from '../store' export default function TrackedTile({ index }) { const category = useWebhookStore((s) => s.category) const item = useWebhookStore((s) => s[category][index]) - const id = Poracle.getId(item, category) + const id = Poracle.getId(item) const advOpen = useWebhookStore((s) => s.advanced) const selected = useWebhookStore((s) => (item ? s.selected[item.uid] : false)) const defaults = useWebhookStore((s) => s.context.ui[category].defaults) @@ -28,18 +32,20 @@ export default function TrackedTile({ index }) { }, })) } - }, [advOpen, id]) + }, [advOpen, id, item]) const onClose = React.useCallback( - (newFilter) => { - apolloClient.mutate({ - mutation: webhookNodes[category], - variables: { - data: Poracle.processor(category, [newFilter], defaults), - status: 'POST', - category, - }, - }) + (newFilter, save) => { + if (save) { + apolloClient.mutate({ + mutation: webhookNodes[category], + variables: { + data: Poracle.processor(category, [newFilter], defaults), + status: 'POST', + category, + }, + }) + } }, [category, defaults], ) @@ -47,28 +53,27 @@ export default function TrackedTile({ index }) { if (!item) return   return ( - - + {id} - - + + {item.description || Poracle.generateDescription(item, category)} - - + + - - + + ) } diff --git a/src/components/layout/general/Menu.jsx b/src/components/layout/general/Menu.jsx index 161979c66..0908fe26c 100644 --- a/src/components/layout/general/Menu.jsx +++ b/src/components/layout/general/Menu.jsx @@ -14,11 +14,12 @@ import useFilter from '@hooks/useFilter' import Header from '@components/layout/general/Header' import Footer from '@components/layout/general/Footer' import { applyToAll } from '@services/filtering/applyToAll' +import useGetAvailable from '@hooks/useGetAvailable' import OptionsContainer from '../dialogs/filters/OptionsContainer' import { VirtualGrid } from './VirtualGrid' import { GenericSearch } from '../drawer/ItemSearch' -import { useWebhookStore } from '../dialogs/webhooks/store' +import { applyToAllWebhooks, useWebhookStore } from '../dialogs/webhooks/store' /** * @param {{ @@ -42,6 +43,8 @@ export default function Menu({ titleAction, extraButtons, }) { + useGetAvailable(category) + Utility.analytics(`/advanced/${category}`) const isMobile = useMemory((s) => s.isMobile) @@ -86,10 +89,10 @@ export default function Menu({ name: 'apply_to_all', action: () => (webhookCategory ? useWebhookStore : useLayoutStore).setState({ - advancedFilter: { + [webhookCategory ? 'advanced' : 'advancedFilter']: { open: true, id: 'global', - category, + category: webhookCategory || category, selectedIds: filteredArr, }, }), @@ -98,24 +101,23 @@ export default function Menu({ { name: 'disable_all', action: () => - applyToAll( - { enabled: false }, - category, - filteredArr, - !webhookCategory, - ), + webhookCategory + ? applyToAllWebhooks(false, filteredArr) + : applyToAll({ enabled: false }, category, filteredArr), icon: 'Clear', color: 'error', }, { name: 'enable_all', action: () => - applyToAll( - { enabled: true }, - category, - filteredArr, - !webhookCategory, - ), + webhookCategory + ? applyToAllWebhooks(true, filteredArr) + : applyToAll( + { enabled: true }, + category, + filteredArr, + !webhookCategory, + ), icon: 'Check', color: 'success', }, diff --git a/src/hooks/useRefresh.js b/src/hooks/useRefresh.js index 5c747a568..1a892147d 100644 --- a/src/hooks/useRefresh.js +++ b/src/hooks/useRefresh.js @@ -34,7 +34,8 @@ export default function useRefresh() { useEffect(() => { if (data?.available) { - const { masterfile, filters, icons, audio } = data.available + const { masterfile, filters, icons, audio, questConditions } = + data.available const { icons: userIcons, audio: userAudio } = useStorage.getState() const existing = useMemory.getState() @@ -73,12 +74,16 @@ export default function useRefresh() { JSON.stringify(masterfile.questRewardTypes), ) } - useMemory.setState({ + useMemory.setState((prev) => ({ masterfile, filters, Icons, Audio, - }) + available: { + ...prev.available, + questConditions, + }, + })) useStorage.setState((prev) => ({ filters: deepMerge({}, filters, prev.filters), })) diff --git a/src/hooks/useTranslateById.js b/src/hooks/useTranslateById.js index 58725b266..497d909cc 100644 --- a/src/hooks/useTranslateById.js +++ b/src/hooks/useTranslateById.js @@ -37,6 +37,14 @@ export function useTranslateById(options = {}) { if (id === 'global' || id === 'all') { return i18n.t(id) } + if ( + id === '0-0' || + id === 'e90' || + id === 'r90' || + id === 't4' || + id === 'i0' + ) + return i18n.t('poke_global') switch (id.charAt(0)) { case 'b': // event stops diff --git a/src/services/Poracle.js b/src/services/Poracle.js index 55870360f..79c5e7af5 100644 --- a/src/services/Poracle.js +++ b/src/services/Poracle.js @@ -1,7 +1,6 @@ // @ts-check import { t } from 'i18next' import { useWebhookStore } from '@components/layout/dialogs/webhooks/store' -import { useMemory } from '@hooks/useMemory' export default class Poracle { static getMapCategory(poracleCategory) { @@ -50,7 +49,6 @@ export default class Poracle { static getId(item) { if (!item) return '' - const { invasions } = useMemory.getState().masterfile const { category } = useWebhookStore.getState() switch (category) { @@ -63,12 +61,7 @@ export default class Poracle { ? 'kecleon' : item.grunt_type === 'showcase' ? 'showcase' - : `i${Object.keys(invasions).find( - (x) => - invasions[x].type?.toLowerCase() === - item.grunt_type.toLowerCase() && - invasions[x].gender === (item.gender || 1), - )}` + : `i${item.real_grunt_id}` case 'lure': return `l${item.lure_id}` case 'gym': @@ -317,7 +310,15 @@ export default class Poracle { switch (category) { case 'invasion': { let name = t( - item.real_grunt_id ? `grunt_${item.real_grunt_id}` : 'poke_global', + item.grunt_type === 'gold-stop' + ? 'gold_stop' + : item.grunt_type === 'kecleon' + ? 'poke_352' + : item.grunt_type === 'showcase' + ? 'showcase' + : item.real_grunt_id + ? `grunt_${item.real_grunt_id}` + : 'poke_global', ) if (!item.gender) name = name.replace(/\(.+?\)/g, `(${t('all')})`) return `${name}${item.clean ? ` | ${t('clean')} ` : ''}${ diff --git a/src/services/apollo/index.js b/src/services/apollo/index.js index 56c3f38d5..8f445e874 100644 --- a/src/services/apollo/index.js +++ b/src/services/apollo/index.js @@ -7,50 +7,7 @@ const abortableLink = new AbortableLink() export const apolloCache = new InMemoryCache({ typePolicies: { - Query: { - // fields: { - // badges: { - // merge(existing, incoming) { - // return incoming - // }, - // }, - // devices: { - // merge(existing, incoming) { - // return incoming - // }, - // }, - // gyms: { - // merge(existing, incoming) { - // return incoming - // }, - // }, - // nests: { - // merge(existing, incoming) { - // return incoming - // }, - // }, - // pokemon: { - // merge(existing, incoming) { - // return incoming - // }, - // }, - // pokestops: { - // merge(existing, incoming) { - // return incoming - // }, - // }, - // portals: { - // merge(existing, incoming) { - // return incoming - // }, - // }, - // spawnpoints: { - // merge(existing, incoming) { - // return incoming - // }, - // }, - // }, - }, + Query: {}, SearchQuest: { keyFields: ['id', 'with_ar'], }, @@ -84,20 +41,6 @@ export const apolloCache = new InMemoryCache({ PoracleWeather: { keyFields: ['uid'], }, - // Pokestop: { - // fields: { - // quests: { - // merge(existing, incoming) { - // return incoming - // }, - // }, - // invasions: { - // merge(existing, incoming) { - // return incoming - // }, - // }, - // }, - // }, }, }) diff --git a/vite.config.js b/vite.config.js index bba132b8f..79db95c1a 100644 --- a/vite.config.js +++ b/vite.config.js @@ -2,7 +2,7 @@ /* eslint-disable no-continue */ /* eslint-disable import/no-extraneous-dependencies */ -const { defineConfig, loadEnv } = require('vite') +const { defineConfig, loadEnv, createLogger } = require('vite') const { default: react } = require('@vitejs/plugin-react') const { default: checker } = require('vite-plugin-checker') const removeFiles = require('rollup-plugin-delete') @@ -20,6 +20,11 @@ const { muteWarningsPlugin, } = require('@rm/vite-plugins') +const defaultLogger = createLogger() +const logLevel = config.getSafe('devOptions.logLevel') +const viteLogLevel = + logLevel === 'debug' || logLevel === 'trace' ? 'info' : logLevel + const viteConfig = defineConfig(({ mode }) => { const env = loadEnv(mode, resolve(process.cwd(), './'), '') const isRelease = process.argv.includes('-r') @@ -159,6 +164,14 @@ const viteConfig = defineConfig(({ mode }) => { }, }, }, + logLevel: viteLogLevel, + customLogger: { + ...defaultLogger, + error: (message) => log.error(HELPERS.build, message), + warn: (message) => log.warn(HELPERS.build, message), + info: (message) => log.info(HELPERS.build, message), + // debug: (message) => log.debug(HELPERS.build, message), + }, server: { host: '0.0.0.0', open: true, diff --git a/yarn.lock b/yarn.lock index faaf94330..8e1831dbb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3560,10 +3560,10 @@ config-chain@^1.1.11: ini "^1.3.4" proto-list "~1.2.1" -config@^3.3.9: - version "3.3.9" - resolved "https://registry.yarnpkg.com/config/-/config-3.3.9.tgz#27fae95b43e0e1d5723e54143c090954d8e49572" - integrity sha512-G17nfe+cY7kR0wVpc49NCYvNtelm/pPy8czHoFkAgtV1lkmcp7DHtWCdDu+C9Z7gb2WVqa9Tm3uF9aKaPbCfhg== +config@^3.3.10: + version "3.3.10" + resolved "https://registry.yarnpkg.com/config/-/config-3.3.10.tgz#effb354d15accfb6e2b50e1d626944c635ad1189" + integrity sha512-9Kl3LpQ6zj93KaqgfIMTcpwTpgozFOqNl/Dk7mjras1BgGIOlqxWkyIGeU1my+sRuskRYwrCATgCk1RjAnRPGA== dependencies: json5 "^2.2.3" @@ -6093,10 +6093,10 @@ language-tags@^1.0.9: dependencies: language-subtag-registry "^0.3.20" -leaflet.locatecontrol@^0.79.0: - version "0.79.0" - resolved "https://registry.yarnpkg.com/leaflet.locatecontrol/-/leaflet.locatecontrol-0.79.0.tgz#0236b87c699a49f9ddb2f289941fbc0d3c3f8b62" - integrity sha512-h64QIHFkypYdr90lkSfjKvPvvk8/b8UnP3m9WuoWdp5p2AaCWC0T1NVwyuj4rd5U4fBW3tQt4ppmZ2LceHMIDg== +leaflet.locatecontrol@0.73.0: + version "0.73.0" + resolved "https://registry.yarnpkg.com/leaflet.locatecontrol/-/leaflet.locatecontrol-0.73.0.tgz#768d9edb0470f86c913ea6c2a70ec62380fd45c5" + integrity sha512-e6v6SyDU2nzG5AiH80eH7qhXw5J+EfgmEFHkuzTRC9jqCSbfAm/3HlZDuoa9WYsaZbn5ovvqNeaLW/JSMsgg5g== leaflet@1.9.4: version "1.9.4"