mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-08-23 19:15:00 -05:00
Automatically upgrade SplatNet 3 persisted queries
This commit is contained in:
@@ -9,6 +9,9 @@ import { BulletToken } from './splatnet3-types.js';
|
||||
import { defineResponse, ErrorResponse, HasResponse, ResponseSymbol } from './util.js';
|
||||
|
||||
const debug = createDebug('nxapi:api:splatnet3');
|
||||
const debugGraphQl = createDebug('nxapi:api:splatnet3:graphql');
|
||||
debugGraphQl.enabled = true;
|
||||
const debugUpgradeQuery = createDebug('nxapi:api:splatnet3:upgrade-query');
|
||||
|
||||
export const SPLATNET3_WEBSERVICE_ID = 4834290508791808;
|
||||
export const SPLATNET3_WEBSERVICE_URL = 'https://api.lp1.av5ja.srv.nintendo.net';
|
||||
@@ -48,6 +51,17 @@ export interface PersistedQueryResultData {
|
||||
[VariablesSymbol]: {};
|
||||
}
|
||||
|
||||
enum MapQueriesMode {
|
||||
/** NXAPI_SPLATNET3_UPGRADE_QUERIES=0 - never upgrade persisted query IDs (not recommended) */
|
||||
NEVER,
|
||||
/** NXAPI_SPLATNET3_UPGRADE_QUERIES=1 - upgrade persisted query IDs that do not contain potentially breaking changes (not recommended) */
|
||||
ONLY_SAFE_NO_REJECT,
|
||||
/** NXAPI_SPLATNET3_UPGRADE_QUERIES=2 - upgrade persisted query IDs, but reject requests that contain potentially breaking changes */
|
||||
ONLY_SAFE,
|
||||
/** NXAPI_SPLATNET3_UPGRADE_QUERIES=3 - upgrade persisted query IDs, including requests that contain potentially breaking changes (default) */
|
||||
ALL,
|
||||
}
|
||||
|
||||
export default class SplatNet3Api {
|
||||
onTokenShouldRenew: ((remaining: number, res: Response) => Promise<SplatNet3AuthData | void>) | null = null;
|
||||
onTokenExpired: ((res: Response) => Promise<SplatNet3AuthData | void>) | null = null;
|
||||
@@ -59,6 +73,8 @@ export default class SplatNet3Api {
|
||||
protected constructor(
|
||||
public bullet_token: string,
|
||||
public version: string,
|
||||
public map_queries: Partial<Record<string, [/** new query ID */ string, /** unsafe */ boolean]>>,
|
||||
readonly map_queries_mode: MapQueriesMode,
|
||||
public language: string,
|
||||
public useragent: string,
|
||||
) {}
|
||||
@@ -135,6 +151,8 @@ export default class SplatNet3Api {
|
||||
_Variables extends (V extends object ? V : _Id extends KnownRequestId ? VariablesTypes[_Id] : unknown) =
|
||||
(V extends object ? V : _Id extends KnownRequestId ? VariablesTypes[_Id] : unknown),
|
||||
>(id: _Id, variables: _Variables): Promise<PersistedQueryResult<_Result>> {
|
||||
id = this.getUpgradedPersistedQueryId(id) as _Id;
|
||||
|
||||
const req: GraphQLRequest<_Variables> = {
|
||||
variables,
|
||||
extensions: {
|
||||
@@ -163,6 +181,37 @@ export default class SplatNet3Api {
|
||||
return data as PersistedQueryResult<_Result>;
|
||||
}
|
||||
|
||||
getPersistedQueryId(id: RequestId) {
|
||||
return this.getUpgradedPersistedQueryId(id, false);
|
||||
}
|
||||
|
||||
private getUpgradedPersistedQueryId(id: string, reject = true) {
|
||||
if (this.map_queries_mode === MapQueriesMode.NEVER) return id;
|
||||
|
||||
let new_id = id;
|
||||
let unsafe = false;
|
||||
|
||||
while (this.map_queries[new_id]) {
|
||||
const [map_id, map_unsafe] = this.map_queries[new_id]!;
|
||||
|
||||
if (map_unsafe && this.map_queries_mode === MapQueriesMode.ONLY_SAFE && reject) {
|
||||
throw new Error('[splatnet3] Updated persisted query ' + map_id + ' for ' + id +
|
||||
' contains potentially breaking changes');
|
||||
}
|
||||
if (map_unsafe && this.map_queries_mode !== MapQueriesMode.ALL) break;
|
||||
|
||||
new_id = map_id;
|
||||
unsafe = unsafe || map_unsafe;
|
||||
}
|
||||
|
||||
if (reject) {
|
||||
debugUpgradeQuery('Using persisted query %s for %s', new_id, id);
|
||||
if (unsafe) console.warn('[warn] Upgrading SplatNet 3 persisted query %s with potentially breaking changes', id);
|
||||
}
|
||||
|
||||
return new_id;
|
||||
}
|
||||
|
||||
/** * */
|
||||
async getCurrentFest() {
|
||||
return this.persistedQuery(RequestId.CurrentFestQuery, {});
|
||||
@@ -862,6 +911,8 @@ export default class SplatNet3Api {
|
||||
return new this(
|
||||
data.bullet_token.bulletToken,
|
||||
data.version,
|
||||
{},
|
||||
getMapPersistedQueriesModeFromEnvironment(),
|
||||
data.bullet_token.lang,
|
||||
data.useragent,
|
||||
);
|
||||
@@ -871,6 +922,8 @@ export default class SplatNet3Api {
|
||||
return new this(
|
||||
data.bullet_token,
|
||||
data.version,
|
||||
{},
|
||||
getMapPersistedQueriesModeFromEnvironment(),
|
||||
data.language,
|
||||
SPLATNET3_WEBSERVICE_USERAGENT,
|
||||
);
|
||||
@@ -972,6 +1025,15 @@ export default class SplatNet3Api {
|
||||
}
|
||||
}
|
||||
|
||||
function getMapPersistedQueriesModeFromEnvironment(): MapQueriesMode {
|
||||
if (process.env.NXAPI_SPLATNET3_UPGRADE_QUERIES === '0') return MapQueriesMode.NEVER;
|
||||
if (process.env.NXAPI_SPLATNET3_UPGRADE_QUERIES === '1') return MapQueriesMode.ONLY_SAFE_NO_REJECT;
|
||||
if (process.env.NXAPI_SPLATNET3_UPGRADE_QUERIES === '2') return MapQueriesMode.ONLY_SAFE;
|
||||
if (process.env.NXAPI_SPLATNET3_UPGRADE_QUERIES === '3') return MapQueriesMode.ALL;
|
||||
|
||||
return MapQueriesMode.ALL;
|
||||
}
|
||||
|
||||
export interface SplatNet3AuthData {
|
||||
webserviceToken: WebServiceToken;
|
||||
url: string;
|
||||
|
||||
@@ -104,7 +104,7 @@ export async function dumpFestRecords(splatnet: SplatNet3Api, directory: string,
|
||||
|
||||
if (fest_record.state !== FestState.CLOSED) {
|
||||
const filename = 'splatnet3-festvotes-' + id + '-' + Date.now() + '-' +
|
||||
RequestId.DetailVotingStatusQuery + '.json';
|
||||
splatnet.getPersistedQueryId(RequestId.DetailVotingStatusQuery) + '.json';
|
||||
const file = path.join(directory, filename);
|
||||
|
||||
// Fetch this now to match the behavour of Nintendo's app
|
||||
@@ -128,7 +128,8 @@ export async function dumpFestRecords(splatnet: SplatNet3Api, directory: string,
|
||||
}
|
||||
|
||||
if (include_rankings) {
|
||||
const filename = 'splatnet3-festranking-' + id + '-' + RequestId.DetailRankingQuery + '.json';
|
||||
const filename = 'splatnet3-festranking-' + id + '-' +
|
||||
splatnet.getPersistedQueryId(RequestId.DetailRankingQuery) + '.json';
|
||||
const file = path.join(directory, filename);
|
||||
|
||||
try {
|
||||
|
||||
@@ -157,7 +157,8 @@ export async function dumpResults(
|
||||
|
||||
latest_unique_ids.push(id);
|
||||
|
||||
const filename = 'splatnet3-result-' + id + '-' + RequestId.VsHistoryDetailQuery + '.json';
|
||||
const filename = 'splatnet3-result-' + id + '-' +
|
||||
splatnet.getPersistedQueryId(RequestId.VsHistoryDetailQuery) + '.json';
|
||||
const file = path.join(directory, filename);
|
||||
|
||||
try {
|
||||
@@ -195,7 +196,8 @@ export async function dumpResults(
|
||||
|
||||
if (latest_unique_ids.includes(id)) continue;
|
||||
|
||||
const filename = 'splatnet3-result-' + id + '-' + RequestId.VsHistoryDetailQuery + '.json';
|
||||
const filename = 'splatnet3-result-' + id + '-' +
|
||||
splatnet.getPersistedQueryId(RequestId.VsHistoryDetailQuery) + '.json';
|
||||
const file = path.join(directory, filename);
|
||||
|
||||
try {
|
||||
@@ -267,7 +269,8 @@ export async function dumpCoopResults(
|
||||
const match = id_str.match(/^CoopHistoryDetail-(u-[0-9a-z]{20}):((\d{8,}T\d{6})_([0-9a-f-]{36}))$/);
|
||||
const id = match ? match[1] + '-' + match[2] : id_str;
|
||||
|
||||
const filename = 'splatnet3-coop-result-' + id + '-' + RequestId.CoopHistoryDetailQuery + '.json';
|
||||
const filename = 'splatnet3-coop-result-' + id + '-' +
|
||||
splatnet.getPersistedQueryId(RequestId.CoopHistoryDetailQuery) + '.json';
|
||||
const file = path.join(directory, filename);
|
||||
|
||||
try {
|
||||
|
||||
@@ -2,6 +2,9 @@ export {
|
||||
default,
|
||||
CoralAuthData,
|
||||
PartialCoralAuthData,
|
||||
|
||||
ResponseDataSymbol,
|
||||
CorrelationIdSymbol,
|
||||
} from '../api/coral.js';
|
||||
|
||||
export * from '../api/coral-types.js';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export { getTitleIdFromEcUrl } from '../util/misc.js';
|
||||
export { ErrorResponse } from '../api/util.js';
|
||||
export { ErrorResponse, ResponseSymbol } from '../api/util.js';
|
||||
export { addUserAgent } from '../util/useragent.js';
|
||||
|
||||
export { version } from '../util/product.js';
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
export {
|
||||
default as NooklinkApi,
|
||||
NooklinkAuthData,
|
||||
|
||||
NooklinkUserApi,
|
||||
NooklinkUserAuthData,
|
||||
NooklinkUserCliTokenData,
|
||||
|
||||
MessageType,
|
||||
} from '../api/nooklink.js';
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export {
|
||||
default,
|
||||
SplatNet2AuthData,
|
||||
SplatNet2CliTokenData,
|
||||
|
||||
LeagueType,
|
||||
LeagueRegion,
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
export {
|
||||
default,
|
||||
SplatNet3AuthData,
|
||||
SplatNet3CliTokenData,
|
||||
|
||||
RequestIdSymbol,
|
||||
VariablesSymbol,
|
||||
|
||||
XRankingRegion,
|
||||
XRankingLeaderboardType,
|
||||
XRankingLeaderboardRule,
|
||||
} from '../api/splatnet3.js';
|
||||
|
||||
// export * from '../api/splatnet3-types.js';
|
||||
|
||||
Reference in New Issue
Block a user