mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-04-24 15:07:05 -05:00
Switch to undici
This commit is contained in:
parent
10a6784fa7
commit
d7a64b9807
52
package-lock.json
generated
52
package-lock.json
generated
|
|
@ -26,6 +26,7 @@
|
|||
"splatnet3-types": "^0.2.20230601143335",
|
||||
"supports-color": "^8.1.1",
|
||||
"tslib": "^2.4.1",
|
||||
"undici": "^5.22.1",
|
||||
"uuid": "^8.3.2",
|
||||
"yargs": "^17.6.2"
|
||||
},
|
||||
|
|
@ -1198,6 +1199,17 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
||||
"dependencies": {
|
||||
"streamsearch": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
|
|
@ -4069,6 +4081,14 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/streamsearch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
|
|
@ -4400,6 +4420,17 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "5.22.1",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz",
|
||||
"integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==",
|
||||
"dependencies": {
|
||||
"busboy": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
|
|
@ -5553,6 +5584,14 @@
|
|||
"integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
|
||||
"dev": true
|
||||
},
|
||||
"busboy": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
||||
"requires": {
|
||||
"streamsearch": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
|
|
@ -7757,6 +7796,11 @@
|
|||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
|
||||
},
|
||||
"streamsearch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
|
|
@ -7994,6 +8038,14 @@
|
|||
"integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==",
|
||||
"dev": true
|
||||
},
|
||||
"undici": {
|
||||
"version": "5.22.1",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.22.1.tgz",
|
||||
"integrity": "sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==",
|
||||
"requires": {
|
||||
"busboy": "^1.6.0"
|
||||
}
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
"splatnet3-types": "^0.2.20230601143335",
|
||||
"supports-color": "^8.1.1",
|
||||
"tslib": "^2.4.1",
|
||||
"undici": "^5.22.1",
|
||||
"uuid": "^8.3.2",
|
||||
"yargs": "^17.6.2"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import fetch, { Response } from 'node-fetch';
|
||||
import { fetch, Response } from 'undici';
|
||||
import { v4 as uuidgen } from 'uuid';
|
||||
import createDebug from '../util/debug.js';
|
||||
import { JwtPayload } from '../util/jwt.js';
|
||||
|
|
@ -145,7 +145,7 @@ export default class CoralApi implements CoralApiInterface {
|
|||
debug('fetch %s %s, response %s', method, url, response.status);
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new CoralErrorResponse('[znc] Non-200 status code', response, await response.text());
|
||||
throw await CoralErrorResponse.fromResponse(response, '[znc] Non-200 status code');
|
||||
}
|
||||
|
||||
const data = await response.json() as CoralResponse<T>;
|
||||
|
|
@ -449,7 +449,7 @@ export default class CoralApi implements CoralApiInterface {
|
|||
debug('fetch %s %s, response %s', 'POST', '/v3/Account/Login', response.status);
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new CoralErrorResponse('[znc] Non-200 status code', response, await response.text());
|
||||
throw await CoralErrorResponse.fromResponse(response, '[znc] Non-200 status code');
|
||||
}
|
||||
|
||||
const data = await response.json() as CoralResponse<AccountLogin>;
|
||||
|
|
|
|||
10
src/api/f.ts
10
src/api/f.ts
|
|
@ -1,5 +1,5 @@
|
|||
import process from 'node:process';
|
||||
import fetch, { Headers } from 'node-fetch';
|
||||
import { fetch, Headers } from 'undici';
|
||||
import { v4 as uuidgen } from 'uuid';
|
||||
import { defineResponse, ErrorResponse } from './util.js';
|
||||
import createDebug from '../util/debug.js';
|
||||
|
|
@ -61,7 +61,7 @@ export async function flapg(
|
|||
}).finally(cancel);
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new ErrorResponse<FlapgApiError>('[flapg] Non-200 status code', response, await response.text());
|
||||
throw await ErrorResponse.fromResponse(response, '[flapg] Non-200 status code');
|
||||
}
|
||||
|
||||
const data = await response.json() as FlapgApiResponse;
|
||||
|
|
@ -142,13 +142,13 @@ export async function iminkf(
|
|||
}).finally(cancel);
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new ErrorResponse<IminkFError>('[imink] Non-200 status code', response, await response.text());
|
||||
throw await ErrorResponse.fromResponse(response, '[imink] Non-200 status code');
|
||||
}
|
||||
|
||||
const data = await response.json() as IminkFResponse | IminkFError;
|
||||
|
||||
if ('error' in data) {
|
||||
throw new ErrorResponse<IminkFError>('[imink] ' + data.reason, response, data);
|
||||
throw new ErrorResponse('[imink] ' + data.reason, response, data);
|
||||
}
|
||||
|
||||
debugImink('Got f parameter "%s"', data.f);
|
||||
|
|
@ -229,7 +229,7 @@ export async function genf(
|
|||
}).finally(cancel);
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new ErrorResponse<AndroidZncaFError>('[znca-api] Non-200 status code', response, await response.text());
|
||||
throw await ErrorResponse.fromResponse(response, '[znca-api] Non-200 status code');
|
||||
}
|
||||
|
||||
const data = await response.json() as AndroidZncaFResponse | AndroidZncaFError;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import fetch, { Response } from 'node-fetch';
|
||||
import { fetch, Response } from 'undici';
|
||||
import { generateAuthData, getNintendoAccountToken, getNintendoAccountUser, NintendoAccountSessionAuthorisation, NintendoAccountToken, NintendoAccountUser } from './na.js';
|
||||
import { defineResponse, ErrorResponse, HasResponse } from './util.js';
|
||||
import { DailySummaries, Devices, MonthlySummaries, MonthlySummary, MoonError, ParentalControlSettingState, SmartDevices, User } from './moon-types.js';
|
||||
|
|
@ -86,7 +86,7 @@ export default class MoonApi {
|
|||
}
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new MoonErrorResponse('[moon] Non-200 status code', response, await response.text());
|
||||
throw await MoonErrorResponse.fromResponse(response, '[moon] Non-200 status code');
|
||||
}
|
||||
|
||||
const data = await response.json() as T | MoonError;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as crypto from 'node:crypto';
|
||||
import fetch, { Response } from 'node-fetch';
|
||||
import { fetch, Response } from 'undici';
|
||||
import { defineResponse, ErrorResponse, HasResponse } from './util.js';
|
||||
import createDebug from '../util/debug.js';
|
||||
import { JwtPayload } from '../util/jwt.js';
|
||||
|
|
@ -127,7 +127,7 @@ export async function getNintendoAccountSessionToken(code: string, verifier: str
|
|||
}).finally(cancel);
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new NintendoAccountAuthErrorResponse('[na] Non-200 status code', response, await response.text());
|
||||
throw await NintendoAccountAuthErrorResponse.fromResponse(response, '[na] Non-200 status code');
|
||||
}
|
||||
|
||||
const token = await response.json() as NintendoAccountSessionToken | NintendoAccountAuthError | NintendoAccountError;
|
||||
|
|
@ -164,7 +164,7 @@ export async function getNintendoAccountToken(token: string, client_id: string)
|
|||
}).finally(cancel);
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new NintendoAccountAuthErrorResponse('[na] Non-200 status code', response, await response.text());
|
||||
throw await NintendoAccountAuthErrorResponse.fromResponse(response, '[na] Non-200 status code');
|
||||
}
|
||||
|
||||
const nintendoAccountToken = await response.json() as NintendoAccountToken | NintendoAccountAuthError | NintendoAccountError;
|
||||
|
|
@ -198,7 +198,7 @@ export async function getNintendoAccountUser(token: NintendoAccountToken) {
|
|||
}).finally(cancel);
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new NintendoAccountErrorResponse('[na] Non-200 status code', response, await response.text());
|
||||
throw await NintendoAccountErrorResponse.fromResponse(response, '[na] Non-200 status code');
|
||||
}
|
||||
|
||||
const user = await response.json() as NintendoAccountUser | NintendoAccountError;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import fetch, { Response } from 'node-fetch';
|
||||
import { fetch, FormData, Response } from 'undici';
|
||||
import { WebServiceToken } from './coral-types.js';
|
||||
import { NintendoAccountUser } from './na.js';
|
||||
import { defineResponse, ErrorResponse, HasResponse } from './util.js';
|
||||
|
|
@ -81,7 +81,7 @@ export default class NooklinkApi {
|
|||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new NooklinkErrorResponse('[nooklink] Non-2xx status code', response, await response.text());
|
||||
throw await NooklinkErrorResponse.fromResponse(response, '[nooklink] Non-2xx status code');
|
||||
}
|
||||
|
||||
const data = await response.json() as T | WebServiceError;
|
||||
|
|
@ -172,12 +172,12 @@ export default class NooklinkApi {
|
|||
|
||||
debug('fetch %s %s, response %s', 'GET', url, response.status);
|
||||
|
||||
const body = await response.text();
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new NooklinkErrorResponse('[nooklink] Non-200 status code', response, body);
|
||||
throw await NooklinkErrorResponse.fromResponse(response, '[nooklink] Non-200 status code');
|
||||
}
|
||||
|
||||
const body = await response.text();
|
||||
|
||||
const cookies = response.headers.get('Set-Cookie');
|
||||
const match = cookies?.match(/\b_gtoken=([^;]*)(;(\s*((?!expires)[a-z]+=([^;]*));?)*(\s*(expires=([^;]*));?)?|$)/i);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import fetch from 'node-fetch';
|
||||
import { Cookie, fetch, FormData, getSetCookies } from 'undici';
|
||||
import { v4 as uuidgen } from 'uuid';
|
||||
import { WebServiceToken } from './coral-types.js';
|
||||
import { NintendoAccountUser } from './na.js';
|
||||
|
|
@ -63,7 +63,7 @@ export default class SplatNet2Api {
|
|||
}
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new SplatNet2ErrorResponse('[splatnet2] Non-200 status code', response, await response.text());
|
||||
throw await SplatNet2ErrorResponse.fromResponse(response, '[splatnet2] Non-200 status code');
|
||||
}
|
||||
|
||||
updateIksmSessionLastUsed.handler?.call(null, this.iksm_session);
|
||||
|
|
@ -302,27 +302,22 @@ ${colour}
|
|||
|
||||
debug('fetch %s %s, response %s', 'GET', url, response.status);
|
||||
|
||||
const body = await response.text();
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new SplatNet2ErrorResponse('[splatnet2] Non-200 status code', response, body);
|
||||
throw await SplatNet2ErrorResponse.fromResponse(response, '[splatnet2] Non-200 status code');
|
||||
}
|
||||
|
||||
const cookies = response.headers.get('Set-Cookie');
|
||||
const match = cookies?.match(/\biksm_session=([^;]*)(;(\s*((?!expires)[a-z]+=([^;]*));?)*(\s*(expires=([^;]*));?)?|$)/i);
|
||||
const body = await response.text();
|
||||
|
||||
if (!match) {
|
||||
const cookies = getSetCookies(response.headers);
|
||||
const iksm_session = cookies.find(c => c.name === 'iksm_session');
|
||||
|
||||
if (!iksm_session) {
|
||||
throw new SplatNet2ErrorResponse('[splatnet2] Response didn\'t include iksm_session cookie', response, body);
|
||||
}
|
||||
|
||||
const iksm_session = decodeURIComponent(match[1]);
|
||||
// Nintendo sets the expires field to an invalid timestamp - browsers don't care but Data.parse does
|
||||
const expires = decodeURIComponent(match[8] || '')
|
||||
.replace(/(\b)(\d{1,2})-([a-z]{3})-(\d{4})(\b)/gi, '$1$2 $3 $4$5');
|
||||
const expires_at: number = (iksm_session.expires as Date)?.getTime() ?? Date.now() + 24 * 60 * 60 * 1000;
|
||||
|
||||
debug('iksm_session %s, expires %s', iksm_session.replace(/^(.{6}).*/, '$1****'), expires);
|
||||
|
||||
const expires_at = expires ? Date.parse(expires) : Date.now() + 24 * 60 * 60 * 1000;
|
||||
debug('iksm_session %s, expires %s', iksm_session.value.replace(/^(.{6}).*/, '$1****'), iksm_session.expires);
|
||||
|
||||
const ml = body.match(/<html(?:\s+[a-z0-9-]+(?:=(?:"[^"]*"|[^\s>]*))?)*\s+lang=(?:"([^"]*)"|([^\s>]*))/i);
|
||||
const mr = body.match(/<html(?:\s+[a-z0-9-]+(?:=(?:"[^"]*"|[^\s>]*))?)*\s+data-region=(?:"([^"]*)"|([^\s>]*))/i);
|
||||
|
|
@ -345,14 +340,14 @@ ${colour}
|
|||
return {
|
||||
webserviceToken,
|
||||
url: url.toString(),
|
||||
cookies: cookies!,
|
||||
cookies,
|
||||
body,
|
||||
language,
|
||||
region,
|
||||
user_id,
|
||||
nsa_id,
|
||||
|
||||
iksm_session,
|
||||
iksm_session: iksm_session.value,
|
||||
expires_at,
|
||||
useragent: SPLATNET2_WEBSERVICE_USERAGENT,
|
||||
};
|
||||
|
|
@ -364,7 +359,7 @@ export class SplatNet2ErrorResponse extends ErrorResponse<WebServiceError> {}
|
|||
export interface SplatNet2AuthData {
|
||||
webserviceToken: WebServiceToken;
|
||||
url: string;
|
||||
cookies: string;
|
||||
cookies: string | Cookie[];
|
||||
body: string;
|
||||
|
||||
language: string;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import fetch, { Response } from 'node-fetch';
|
||||
import { fetch, Response } from 'undici';
|
||||
import { BankaraBattleHistoriesRefetchResult, BankaraBattleHistoriesRefetchVariables, GraphQLError, GraphQLErrorResponse, GraphQLRequest, GraphQLResponse, GraphQLSuccessResponse, KnownRequestId, LatestBattleHistoriesRefetchResult, LatestBattleHistoriesRefetchVariables, MyOutfitInput, PagerUpdateBattleHistoriesByVsModeResult, PagerUpdateBattleHistoriesByVsModeVariables, PrivateBattleHistoriesRefetchResult, PrivateBattleHistoriesRefetchVariables, RegularBattleHistoriesRefetchResult, RegularBattleHistoriesRefetchVariables, RequestId, ResultTypes, VariablesTypes, XBattleHistoriesRefetchResult, XBattleHistoriesRefetchVariables } from 'splatnet3-types/splatnet3';
|
||||
import { WebServiceToken } from './coral-types.js';
|
||||
import { CoralApiInterface } from './coral.js';
|
||||
|
|
@ -102,7 +102,7 @@ export default class SplatNet3Api {
|
|||
) {}
|
||||
|
||||
async fetch<T = unknown>(
|
||||
url: string, method = 'GET', body?: string | FormData, headers?: object,
|
||||
url: string, method = 'GET', body?: string, headers?: object,
|
||||
/** @internal */ _log?: string,
|
||||
/** @internal */ _attempt = 0,
|
||||
): Promise<HasResponse<T, Response>> {
|
||||
|
|
@ -153,7 +153,7 @@ export default class SplatNet3Api {
|
|||
}
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new SplatNet3ErrorResponse('[splatnet3] Non-200 status code', response, await response.text());
|
||||
throw await SplatNet3ErrorResponse.fromResponse(response, '[splatnet3] Non-200 status code');
|
||||
}
|
||||
|
||||
const remaining = parseInt(response.headers.get('x-bullettoken-remaining') ?? '0');
|
||||
|
|
@ -1029,12 +1029,12 @@ export default class SplatNet3Api {
|
|||
|
||||
debug('fetch %s %s, response %s', 'GET', url, response.status);
|
||||
|
||||
const body = await response.text();
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new SplatNet3ErrorResponse('[splatnet3] Non-200 status code', response, body);
|
||||
throw await SplatNet3ErrorResponse.fromResponse(response, '[splatnet3] Non-200 status code');
|
||||
}
|
||||
|
||||
const body = await response.text();
|
||||
|
||||
const cookies = response.headers.get('Set-Cookie');
|
||||
|
||||
const [signal2, cancel2] = timeoutSignal();
|
||||
|
|
@ -1058,8 +1058,8 @@ export default class SplatNet3Api {
|
|||
debug('fetch %s %s, response %s', 'POST', '/bullet_tokens', response.status);
|
||||
|
||||
const error: SplatNet3AuthErrorCode | undefined = AUTH_ERROR_CODES[tr.status as keyof typeof AUTH_ERROR_CODES];
|
||||
if (error) throw new SplatNet3AuthErrorResponse('[splatnet3] ' + error, tr, await tr.text(), error);
|
||||
if (tr.status !== 201) throw new SplatNet3ErrorResponse('[splatnet3] Non-201 status code', tr, await tr.text());
|
||||
if (error) throw await SplatNet3AuthErrorResponse.fromResponse(tr, '[splatnet3] ' + error);
|
||||
if (tr.status !== 201) throw await SplatNet3ErrorResponse.fromResponse(tr, '[splatnet3] Non-201 status code');
|
||||
|
||||
const bullet_token = await tr.json() as BulletToken;
|
||||
const created_at = Date.now();
|
||||
|
|
@ -1099,7 +1099,8 @@ export class SplatNet3AuthErrorResponse extends SplatNet3ErrorResponse {
|
|||
constructor(
|
||||
message: string, response: Response | globalThis.Response,
|
||||
body?: string | unknown | undefined,
|
||||
readonly code = SplatNet3AuthErrorCode.ERROR_SERVER,
|
||||
readonly code = AUTH_ERROR_CODES[response.status as keyof typeof AUTH_ERROR_CODES] ??
|
||||
SplatNet3AuthErrorCode.ERROR_SERVER,
|
||||
) {
|
||||
super(message, response, body);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import * as util from 'node:util';
|
||||
import { Response as NodeFetchResponse } from 'node-fetch';
|
||||
import { Response as UndiciResponse } from 'undici';
|
||||
|
||||
export const ResponseSymbol = Symbol('Response');
|
||||
const ErrorResponseSymbol = Symbol('IsErrorResponse');
|
||||
|
|
@ -20,13 +21,17 @@ export class ErrorResponse<T = unknown> extends Error {
|
|||
|
||||
constructor(
|
||||
message: string,
|
||||
readonly response: Response | NodeFetchResponse,
|
||||
body?: string | T
|
||||
readonly response: Response | NodeFetchResponse | UndiciResponse,
|
||||
body?: string | ArrayBuffer | T
|
||||
) {
|
||||
super(message);
|
||||
|
||||
Object.defineProperty(this, ErrorResponseSymbol, {enumerable: false, value: ErrorResponseSymbol});
|
||||
|
||||
if (body instanceof ArrayBuffer) {
|
||||
body = (new TextDecoder()).decode(body);
|
||||
}
|
||||
|
||||
if (typeof body === 'string') {
|
||||
this.body = body;
|
||||
try {
|
||||
|
|
@ -50,6 +55,12 @@ export class ErrorResponse<T = unknown> extends Error {
|
|||
(lines.length ? '\n' + lines.join('\n') : ''),
|
||||
});
|
||||
}
|
||||
|
||||
static async fromResponse(response: UndiciResponse, message: string) {
|
||||
const body = await response.arrayBuffer();
|
||||
|
||||
return new this(message, response, body);
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(ErrorResponse, Symbol.hasInstance, {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import fetch, { Response } from 'node-fetch';
|
||||
import { fetch, Response } from 'undici';
|
||||
import { ActiveEvent, Announcements, CurrentUser, Event, Friend, Presence, PresencePermissions, User, WebService, WebServiceToken, CoralStatus, CoralSuccessResponse, FriendCodeUser, FriendCodeUrl } from './coral-types.js';
|
||||
import { defineResponse, ErrorResponse, ResponseSymbol } from './util.js';
|
||||
import { CoralApiInterface, CoralAuthData, CorrelationIdSymbol, PartialCoralAuthData, ResponseDataSymbol, Result } from './coral.js';
|
||||
|
|
@ -34,7 +34,7 @@ export default class ZncProxyApi implements CoralApiInterface {
|
|||
debug('fetch %s %s, response %s', method, url, response.status);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new ZncProxyErrorResponse('[zncproxy] Non-2xx status code', response, await response.text());
|
||||
throw await ZncProxyErrorResponse.fromResponse(response, '[zncproxy] Non-2xx status code');
|
||||
}
|
||||
|
||||
const data = (response.status === 204 ? {} : await response.json()) as T;
|
||||
|
|
@ -229,11 +229,11 @@ export async function getPresenceFromUrl(presence_url: string, useragent?: strin
|
|||
debug('fetch %s %s, response %s', 'GET', presence_url, response.status);
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new ZncProxyErrorResponse('[zncproxy] Unknown error', response, await response.text());
|
||||
throw await ZncProxyErrorResponse.fromResponse(response, '[zncproxy] Non-200 status code');
|
||||
}
|
||||
|
||||
if (!response.headers.get('Content-Type')?.match(/^application\/json(;|$)$/)) {
|
||||
controller.abort();
|
||||
response.body?.cancel();
|
||||
throw new ZncProxyErrorResponse('[zncproxy] Unacceptable content type', response);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { BrowserWindow, dialog, Menu, MenuItem, MessageBoxOptions, nativeImage } from './electron.js';
|
||||
import path from 'node:path';
|
||||
import { Buffer } from 'node:buffer';
|
||||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import { dir } from '../../util/product.js';
|
||||
import { App, Store } from './index.js';
|
||||
import { SavedToken } from '../../common/auth/coral.js';
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { constants } from 'node:fs';
|
|||
import * as fs from 'node:fs/promises';
|
||||
import { Buffer } from 'node:buffer';
|
||||
import * as util from 'node:util';
|
||||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import { Store } from './index.js';
|
||||
import { createWebServiceWindow } from './windows.js';
|
||||
import { askUserForUri, showErrorDialog } from './util.js';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { getToken } from '../../common/auth/coral.js';
|
||||
|
|
@ -7,6 +7,7 @@ import createDebug from '../../util/debug.js';
|
|||
import { Argv } from '../../util/yargs.js';
|
||||
import { initStorage } from '../../util/storage.js';
|
||||
import { getUserAgent } from '../../util/useragent.js';
|
||||
import { ErrorResponse } from '../../api/util.js';
|
||||
|
||||
const debug = createDebug('cli:nso:znc-proxy-tokens');
|
||||
|
||||
|
|
@ -164,7 +165,7 @@ export function builder(yargs: Argv<ParentArguments>) {
|
|||
debug('fetch %s %s, response %d', 'DELETE', '/token', response.status);
|
||||
|
||||
if (response.status !== 204) {
|
||||
throw new Error('Unknown error ' + response.status);
|
||||
throw await ErrorResponse.fromResponse(response, 'Non-204 status code');
|
||||
}
|
||||
|
||||
console.warn('Deleted access token');
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import * as os from 'node:os';
|
|||
import * as fs from 'node:fs/promises';
|
||||
import * as path from 'node:path';
|
||||
import express, { Request, Response } from 'express';
|
||||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import * as persist from 'node-persist';
|
||||
import mkdirp from 'mkdirp';
|
||||
import { BankaraMatchSetting_schedule, CoopRule, CoopSetting_schedule, DetailFestRecordDetailResult, DetailVotingStatusResult, FestMatchSetting_schedule, FestRecordResult, FestState, FestTeam_schedule, FestTeam_votingStatus, FestVoteState, Fest_schedule, FriendListResult, FriendOnlineState, Friend_friendList, GraphQLSuccessResponse, KnownRequestId, LeagueMatchSetting_schedule, RegularMatchSetting_schedule, StageScheduleResult, XMatchSetting_schedule } from 'splatnet3-types/splatnet3';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import * as path from 'node:path';
|
||||
import * as fs from 'node:fs/promises';
|
||||
import mkdirp from 'mkdirp';
|
||||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import { PhotoAlbumResult } from 'splatnet3-types/splatnet3';
|
||||
import type { Arguments as ParentArguments } from '../splatnet3.js';
|
||||
import createDebug from '../../util/debug.js';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import process from 'node:process';
|
||||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import { getPresenceFromUrl } from '../../api/znc-proxy.js';
|
||||
import { ActiveEvent, CurrentUser, Friend, Game, Presence, PresenceState } from '../../api/coral-types.js';
|
||||
import type { Arguments as ParentArguments } from '../util.js';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import type { Arguments as ParentArguments } from '../util.js';
|
||||
import createDebug from '../../util/debug.js';
|
||||
import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Response } from 'node-fetch';
|
||||
import { Response } from 'undici';
|
||||
import CoralApi, { CoralApiInterface, CoralAuthData, Result, ZNCA_CLIENT_ID } from '../api/coral.js';
|
||||
import { Announcements, Friends, Friend, GetActiveEventResult, WebServices, CoralError } from '../api/coral-types.js';
|
||||
import ZncProxyApi from '../api/znc-proxy.js';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Response } from 'node-fetch';
|
||||
import { Response } from 'undici';
|
||||
import { ConfigureAnalyticsResult, CurrentFestResult, DetailVotingStatusResult, FriendListResult, Friend_friendList, HomeResult, StageScheduleResult } from 'splatnet3-types/splatnet3';
|
||||
import createDebug from '../util/debug.js';
|
||||
import { ZNCA_CLIENT_ID } from '../api/coral.js';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as persist from 'node-persist';
|
||||
import { Response } from 'node-fetch';
|
||||
import { Response } from 'undici';
|
||||
import CoralApi, { CoralAuthData, ZNCA_CLIENT_ID } from '../../api/coral.js';
|
||||
import { CoralError } from '../../api/coral-types.js';
|
||||
import ZncProxyApi from '../../api/znc-proxy.js';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as persist from 'node-persist';
|
||||
import { Response } from 'node-fetch';
|
||||
import { Response } from 'undici';
|
||||
import { MoonAuthData, ZNMA_CLIENT_ID } from '../../api/moon.js';
|
||||
import { NintendoAccountSessionTokenJwtPayload } from '../../api/na.js';
|
||||
import createDebug from '../../util/debug.js';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import persist from 'node-persist';
|
||||
import { Response } from 'node-fetch';
|
||||
import { Response } from 'undici';
|
||||
import { getToken, Login } from './coral.js';
|
||||
import NooklinkApi, { NooklinkAuthData, NooklinkUserApi, NooklinkUserAuthData } from '../../api/nooklink.js';
|
||||
import { Users, WebServiceError } from '../../api/nooklink-types.js';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import persist from 'node-persist';
|
||||
import { Response } from 'node-fetch';
|
||||
import { Response } from 'undici';
|
||||
import { getToken, Login, SavedToken } from './coral.js';
|
||||
import SplatNet3Api, { SplatNet3AuthData, SplatNet3AuthErrorCode, SplatNet3AuthErrorResponse } from '../../api/splatnet3.js';
|
||||
import { checkMembershipActive, checkUseLimit, SHOULD_LIMIT_USE } from './util.js';
|
||||
|
|
|
|||
|
|
@ -46,7 +46,9 @@ class RateLimitAttempt {
|
|||
readonly storage: persist.LocalStorage,
|
||||
readonly key: string, readonly user: string,
|
||||
readonly time = Date.now(),
|
||||
) {}
|
||||
) {
|
||||
Object.defineProperty(this, 'storage', {configurable: true, enumerable: false, value: storage});
|
||||
}
|
||||
|
||||
async recordError(err: Error | unknown) {
|
||||
const error_description = ErrorDescription.getErrorDescription(err);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import * as path from 'node:path';
|
||||
import * as fs from 'node:fs/promises';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import mkdirp from 'mkdirp';
|
||||
import { ErrorResponse, ResponseSymbol } from '../api/util.js';
|
||||
import createDebug from '../util/debug.js';
|
||||
|
|
@ -124,7 +124,7 @@ async function loadRemoteConfig() {
|
|||
version,
|
||||
revision: git?.revision ?? null,
|
||||
url: response.url,
|
||||
headers: response.headers.raw(),
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
data: config,
|
||||
};
|
||||
|
||||
|
|
@ -241,7 +241,7 @@ export interface RemoteConfigCacheData {
|
|||
version: string;
|
||||
revision: string | null;
|
||||
url: string;
|
||||
headers: Record<string, string[]>;
|
||||
headers: Record<string, string> | Record<string, string[]>;
|
||||
data: NxapiRemoteConfig;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import * as path from 'node:path';
|
|||
import * as fs from 'node:fs/promises';
|
||||
import * as crypto from 'node:crypto';
|
||||
import { Buffer } from 'node:buffer';
|
||||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import SplatNet2Api, { ShareColour } from '../../api/splatnet2.js';
|
||||
import { Challenge, NicknameAndIcon, Records, Stages } from '../../api/splatnet2-types.js';
|
||||
import createDebug from '../../util/debug.js';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import * as path from 'node:path';
|
||||
import * as fs from 'node:fs/promises';
|
||||
import { Buffer } from 'node:buffer';
|
||||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import SplatNet2Api from '../../api/splatnet2.js';
|
||||
import { NicknameAndIcon } from '../../api/splatnet2-types.js';
|
||||
import createDebug from '../../util/debug.js';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as path from 'node:path';
|
||||
import * as fs from 'node:fs/promises';
|
||||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import mkdirp from 'mkdirp';
|
||||
import createDebug from '../util/debug.js';
|
||||
import { dir, docker, version } from '../util/product.js';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import process from 'node:process';
|
||||
import * as net from 'node:net';
|
||||
import { EventEmitter } from 'node:events';
|
||||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import DiscordRPC from 'discord-rpc';
|
||||
// @ts-expect-error
|
||||
import __BaseIpcTransport from 'discord-rpc/src/transports/ipc.js';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import * as util from 'node:util';
|
||||
import { AbortError } from 'node-fetch';
|
||||
import { errors } from 'undici';
|
||||
import createDebug from './debug.js';
|
||||
import Loop, { LoopResult } from './loop.js';
|
||||
import { TemporaryErrorSymbol } from './misc.js';
|
||||
|
|
@ -75,6 +76,22 @@ export async function handleError(
|
|||
} else if (err instanceof AbortError) {
|
||||
debug('Request aborted (timeout?), waiting %ds before retrying', loop.update_interval, err);
|
||||
|
||||
return LoopResult.OK;
|
||||
} else if (err instanceof errors.ConnectTimeoutError) {
|
||||
debug('Request timeout (connect), waiting %ds before retrying', loop.update_interval, err);
|
||||
|
||||
return LoopResult.OK;
|
||||
} else if (err instanceof errors.HeadersTimeoutError) {
|
||||
debug('Request timeout (headers), waiting %ds before retrying', loop.update_interval, err);
|
||||
|
||||
return LoopResult.OK;
|
||||
} else if (err instanceof errors.BodyTimeoutError) {
|
||||
debug('Request timeout (body), waiting %ds before retrying', loop.update_interval, err);
|
||||
|
||||
return LoopResult.OK;
|
||||
} else if (err instanceof errors.RequestAbortedError) {
|
||||
debug('Request aborted, waiting %ds before retrying', loop.update_interval, err);
|
||||
|
||||
return LoopResult.OK;
|
||||
} else if ('code' in err && (err as any).type === 'system' && err.code && err.code in temporary_system_errors) {
|
||||
const desc = temporary_system_errors[err.code as keyof typeof temporary_system_errors];
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import * as crypto from 'node:crypto';
|
||||
import { Buffer } from 'node:buffer';
|
||||
import persist from 'node-persist';
|
||||
import fetch from 'node-fetch';
|
||||
import { fetch } from 'undici';
|
||||
import createDebug from './debug.js';
|
||||
import { timeoutSignal } from './misc.js';
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user