Update config URL and use config data

This commit is contained in:
Samuel Elliott 2022-07-29 17:59:17 +01:00
parent e8e5a2f5a4
commit 2d52f17022
No known key found for this signature in database
GPG Key ID: 8420C7CDE43DC4D6
14 changed files with 227 additions and 94 deletions

View File

@ -1,9 +1,10 @@
{
"require_version": [],
"coral": {
"znca_version": "2.1.1"
"znca_version": "2.2.0"
},
"coral_auth": {
"default": "flapg",
"splatnet2statink": {},
"flapg": {},
"imink": {}

View File

@ -14,6 +14,8 @@ import json from '@rollup/plugin-json';
const dir = path.dirname(fileURLToPath(import.meta.url));
const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf-8'));
const default_remote_config =
JSON.parse(fs.readFileSync(path.join(dir, 'resources', 'common', 'remote-config.json'), 'utf-8'));
const git = (() => {
try {
@ -46,6 +48,7 @@ const replace_options = {
'globalThis.__NXAPI_BUNDLE_PKG__': JSON.stringify(pkg),
'globalThis.__NXAPI_BUNDLE_GIT__': JSON.stringify(git),
'globalThis.__NXAPI_BUNDLE_RELEASE__': JSON.stringify(release),
'globalThis.__NXAPI_BUNDLE_DEFAULT_REMOTE_CONFIG__': JSON.stringify(default_remote_config),
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV ?? 'development'),
},
preventAssignment: true,

View File

@ -55,6 +55,16 @@ export enum CoralStatus {
export type CoralResponse<T = unknown> = CoralSuccessResponse<T> | CoralErrorResponse;
export interface AccountLoginParameter {
naIdToken: string;
naBirthday: string;
naCountry: string;
language: string;
timestamp: string;
requestId: string;
f: string;
}
/** /v3/Account/Login */
export interface AccountLogin {
user: CurrentUser;
@ -71,6 +81,14 @@ export interface AccountLogin {
/** /v3/Account/GetToken */
export type AccountToken = AccountLogin;
export interface AccountTokenParameter {
naIdToken: string;
naBirthday: string;
timestamp: string;
requestId: string;
f: string;
}
/** /v1/Announcement/List */
export type Announcements = Announcement[];
@ -254,6 +272,16 @@ export interface CurrentUserPermissions {
};
}
export interface UpdateCurrentUserPermissionsParameter {
permissions: {
presence: {
toValue: PresencePermissions;
fromValue: PresencePermissions;
};
};
etag: string;
}
/** /v2/Game/GetWebServiceToken */
export interface WebServiceToken {
accessToken: string;

View File

@ -1,9 +1,9 @@
import fetch, { Response } from 'node-fetch';
import { v4 as uuidgen } from 'uuid';
import createDebug from 'debug';
import { f, FlapgIid } from './f.js';
import { AccountLogin, AccountToken, Announcements, CurrentUser, CurrentUserPermissions, Event, Friends, GetActiveEventResult, PresencePermissions, User, WebServices, WebServiceToken, CoralErrorResponse, CoralResponse, CoralStatus, CoralSuccessResponse, FriendCodeUser, FriendCodeUrl } from './coral-types.js';
import { getNintendoAccountToken, getNintendoAccountUser, NintendoAccountUser } from './na.js';
import { f, FlapgIid, FResult } from './f.js';
import { AccountLogin, AccountToken, Announcements, CurrentUser, CurrentUserPermissions, Event, Friends, GetActiveEventResult, PresencePermissions, User, WebServices, WebServiceToken, CoralErrorResponse, CoralResponse, CoralStatus, CoralSuccessResponse, FriendCodeUser, FriendCodeUrl, AccountTokenParameter, AccountLoginParameter } from './coral-types.js';
import { getNintendoAccountToken, getNintendoAccountUser, NintendoAccountToken, NintendoAccountUser } from './na.js';
import { ErrorResponse } from './util.js';
import { JwtPayload } from '../util/jwt.js';
import { getAdditionalUserAgents } from '../util/useragent.js';
@ -26,9 +26,11 @@ export default class CoralApi {
/** @internal */
_renewToken: Promise<void> | null = null;
constructor(
protected constructor(
public token: string,
public useragent: string | null = getAdditionalUserAgents()
public useragent: string | null = getAdditionalUserAgents(),
readonly znca_version = ZNCA_VERSION,
readonly znca_useragent = ZNCA_USER_AGENT,
) {}
async fetch<T = unknown>(
@ -44,10 +46,10 @@ export default class CoralApi {
method: method,
headers: Object.assign({
'X-Platform': ZNCA_PLATFORM,
'X-ProductVersion': ZNCA_VERSION,
'X-ProductVersion': this.znca_version,
'Authorization': 'Bearer ' + this.token,
'Content-Type': 'application/json; charset=utf-8',
'User-Agent': ZNCA_USER_AGENT,
'User-Agent': this.znca_useragent,
}, headers),
body: body,
});
@ -185,22 +187,24 @@ export default class CoralApi {
return this.call<WebServiceToken>('/v2/Game/GetWebServiceToken', req);
}
async getToken(token: string, user: NintendoAccountUser) {
const uuid = uuidgen();
const timestamp = '' + Math.floor(Date.now() / 1000);
async getToken(token: string, user: NintendoAccountUser): Promise<PartialCoralAuthData> {
// Nintendo Account token
const nintendoAccountToken = await getNintendoAccountToken(token, ZNCA_CLIENT_ID);
const id_token = nintendoAccountToken.id_token;
const fdata = await f(id_token, timestamp, uuid, FlapgIid.NSO, this.useragent ?? getAdditionalUserAgents());
const uuid = uuidgen();
const timestamp = '' + Math.floor(Date.now() / 1000);
const req = {
const fdata = await f(
nintendoAccountToken.id_token, timestamp, uuid,
FlapgIid.NSO, this.useragent ?? getAdditionalUserAgents()
);
const req: AccountTokenParameter = {
naBirthday: user.birthday,
timestamp,
f: fdata.f,
requestId: uuid,
naIdToken: id_token,
naIdToken: nintendoAccountToken.id_token,
};
const data = await this.call<AccountToken>('/v3/Account/GetToken', req, false);
@ -216,15 +220,6 @@ export default class CoralApi {
};
}
static async createWithSessionToken(token: string, useragent = getAdditionalUserAgents()) {
const data = await this.loginWithSessionToken(token, useragent);
return {
nso: new this(data.credential.accessToken, useragent),
data,
};
}
async renewToken(token: string, user: NintendoAccountUser) {
const data = await this.getToken(token, user);
@ -233,9 +228,25 @@ export default class CoralApi {
return data;
}
static async loginWithSessionToken(token: string, useragent = getAdditionalUserAgents()) {
const uuid = uuidgen();
const timestamp = '' + Math.floor(Date.now() / 1000);
static async createWithSessionToken(token: string, useragent = getAdditionalUserAgents()) {
const data = await this.loginWithSessionToken(token, useragent);
return {nso: this.createWithSavedToken(data, useragent), data};
}
static createWithSavedToken(data: CoralAuthData, useragent = getAdditionalUserAgents()) {
return new this(
data.credential.accessToken,
useragent,
data.znca_version,
data.znca_useragent,
);
}
static async loginWithSessionToken(token: string, useragent = getAdditionalUserAgents()): Promise<CoralAuthData> {
const { default: { coral: config } } = await import('../common/remote-config.js');
if (!config) throw new Error('Remote configuration prevents Coral authentication');
const znca_useragent = `com.nintendo.znca/${config.znca_version}(${ZNCA_PLATFORM}/${ZNCA_PLATFORM_VERSION})`;
// Nintendo Account token
const nintendoAccountToken = await getNintendoAccountToken(token, ZNCA_CLIENT_ID);
@ -243,29 +254,36 @@ export default class CoralApi {
// Nintendo Account user data
const user = await getNintendoAccountUser(nintendoAccountToken);
const id_token = nintendoAccountToken.id_token;
const fdata = await f(id_token, timestamp, uuid, FlapgIid.NSO, useragent);
const uuid = uuidgen();
const timestamp = '' + Math.floor(Date.now() / 1000);
const fdata = await f(
nintendoAccountToken.id_token, timestamp, uuid,
FlapgIid.NSO, useragent
);
debug('Getting Nintendo Switch Online app token');
const parameter: AccountLoginParameter = {
naIdToken: nintendoAccountToken.id_token,
naBirthday: user.birthday,
naCountry: user.country,
language: user.language,
timestamp,
requestId: uuid,
f: fdata.f,
};
const response = await fetch(ZNC_URL + '/v3/Account/Login', {
method: 'POST',
headers: {
'X-Platform': ZNCA_PLATFORM,
'X-ProductVersion': ZNCA_VERSION,
'X-ProductVersion': config.znca_version,
'Content-Type': 'application/json; charset=utf-8',
'User-Agent': ZNCA_USER_AGENT,
'User-Agent': znca_useragent,
},
body: JSON.stringify({
parameter: {
naIdToken: nintendoAccountToken.id_token,
naBirthday: user.birthday,
naCountry: user.country,
language: user.language,
timestamp,
requestId: uuid,
f: fdata.f,
},
parameter,
}),
});
@ -289,10 +307,27 @@ export default class CoralApi {
f: fdata,
nsoAccount: data.result,
credential: data.result.webApiServerCredential,
znca_version: config.znca_version,
znca_useragent,
};
}
}
export interface CoralAuthData {
uuid: string;
timestamp: string;
nintendoAccountToken: NintendoAccountToken;
user: NintendoAccountUser;
f: FResult;
nsoAccount: AccountLogin;
credential: AccountLogin['webApiServerCredential'];
znca_version: string;
znca_useragent: string;
}
export type PartialCoralAuthData =
Pick<CoralAuthData, 'uuid' | 'timestamp' | 'nintendoAccountToken' | 'f' | 'nsoAccount' | 'credential'>;
export interface CoralJwtPayload extends JwtPayload {
isChildRestricted: boolean;
membership: {

View File

@ -23,6 +23,9 @@ export abstract class ZncaApi {
//
export async function getLoginHash(token: string, timestamp: string | number, useragent?: string) {
const { default: { coral_auth: { splatnet2statink: config } } } = await import('../common/remote-config.js');
if (!config) throw new Error('Remote configuration prevents splatnet2statink API use');
debugS2s('Getting login hash');
const [signal, cancel] = timeoutSignal();
@ -61,6 +64,9 @@ export async function flapg(
token: string, timestamp: string | number, guid: string, iid: FlapgIid,
useragent?: string
) {
const { default: { coral_auth: { flapg: config } } } = await import('../common/remote-config.js');
if (!config) throw new Error('Remote configuration prevents flapg API use');
const hash = await getLoginHash(token, timestamp, useragent);
debugFlapg('Getting f parameter', {
@ -129,6 +135,9 @@ export async function iminkf(
token: string, timestamp: string | number, uuid: string, hash_method: '1' | '2',
useragent?: string
) {
const { default: { coral_auth: { imink: config } } } = await import('../common/remote-config.js');
if (!config) throw new Error('Remote configuration prevents imink API use');
debugImink('Getting f parameter', {
token, timestamp, uuid, hash_method,
});
@ -266,7 +275,7 @@ export async function f(
token: string, timestamp: string | number, uuid: string, type: FlapgIid,
useragent?: string
): Promise<FResult> {
const provider = getZncaApiFromEnvironment(useragent);
const provider = getPreferredZncaApiFromEnvironment(useragent) ?? await getDefaultZncaApi(useragent);
return provider.genf(token, '' + timestamp, uuid, type);
}
@ -291,7 +300,7 @@ export type FResult = {
result: AndroidZncaFResponse;
});
export function getZncaApiFromEnvironment(useragent?: string): ZncaApi {
export function getPreferredZncaApiFromEnvironment(useragent?: string): ZncaApi | null {
if (process.env.NXAPI_ZNCA_API) {
if (process.env.NXAPI_ZNCA_API === 'flapg') {
return new ZncaApiFlapg(useragent);
@ -307,5 +316,22 @@ export function getZncaApiFromEnvironment(useragent?: string): ZncaApi {
return new ZncaApiNxapi(process.env.ZNCA_API_URL, useragent);
}
return new ZncaApiFlapg(useragent);
return null;
}
export async function getDefaultZncaApi(useragent?: string) {
const { default: { coral_auth: { default: provider } } } = await import('../common/remote-config.js');
if (provider === 'flapg') {
return new ZncaApiFlapg(useragent);
}
if (provider === 'imink') {
return new ZncaApiImink(useragent);
}
if (provider[0] === 'nxapi') {
return new ZncaApiNxapi(provider[1], useragent);
}
throw new Error('Invalid znca API provider');
}

View File

@ -1,6 +1,6 @@
import fetch from 'node-fetch';
import createDebug from 'debug';
import { getNintendoAccountToken, getNintendoAccountUser } from './na.js';
import { getNintendoAccountToken, getNintendoAccountUser, NintendoAccountToken, NintendoAccountUser } from './na.js';
import { ErrorResponse } from './util.js';
import { DailySummaries, Devices, MonthlySummaries, MonthlySummary, MoonError, ParentalControlSettingState, SmartDevices, User } from './moon-types.js';
import { timeoutSignal } from '../util/misc.js';
@ -12,11 +12,16 @@ export const ZNMA_CLIENT_ID = '54789befb391a838';
const ZNMA_VERSION = '1.17.0';
const ZNMA_BUILD = '261';
const ZNMA_USER_AGENT = 'moon_ANDROID/' + ZNMA_VERSION + ' (com.nintendo.znma; build:' + ZNMA_BUILD +
'; ANDROID 26)';
export default class MoonApi {
constructor(
protected constructor(
public token: string,
public naId: string
public naId: string,
readonly znma_version = ZNMA_VERSION,
readonly znma_build = ZNMA_BUILD,
readonly znma_useragent = ZNMA_USER_AGENT,
) {}
async fetch<T = unknown>(url: string, method = 'GET', body?: string, headers?: object) {
@ -34,10 +39,9 @@ export default class MoonApi {
'X-Moon-TimeZone': 'Europe/London',
'X-Moon-Os-Language': 'en-GB',
'X-Moon-App-Language': 'en-GB',
'X-Moon-App-Display-Version': ZNMA_VERSION,
'X-Moon-App-Internal-Version': ZNMA_BUILD,
'User-Agent': 'moon_ANDROID/' + ZNMA_VERSION + ' (com.nintendo.znma; build:' + ZNMA_BUILD +
'; ANDROID 26)',
'X-Moon-App-Display-Version': this.znma_version,
'X-Moon-App-Internal-Version': this.znma_build,
'User-Agent': this.znma_useragent,
}, headers),
body,
signal,
@ -82,15 +86,6 @@ export default class MoonApi {
return this.fetch<ParentalControlSettingState>('/v1/devices/' + id + '/parental_control_setting_state');
}
static async createWithSessionToken(token: string) {
const data = await this.loginWithSessionToken(token);
return {
moon: new this(data.nintendoAccountToken.access_token!, data.user.id),
data,
};
}
async renewToken(token: string) {
const data = await MoonApi.loginWithSessionToken(token);
@ -100,7 +95,29 @@ export default class MoonApi {
return data;
}
static async loginWithSessionToken(token: string) {
static async createWithSessionToken(token: string) {
const data = await this.loginWithSessionToken(token);
return {moon: this.createWithSavedToken(data), data};
}
static createWithSavedToken(data: MoonAuthData) {
return new this(
data.nintendoAccountToken.access_token!,
data.user.id,
data.znma_version,
data.znma_build,
data.znma_useragent,
);
}
static async loginWithSessionToken(token: string): Promise<MoonAuthData> {
const { default: { moon: config } } = await import('../common/remote-config.js');
if (!config) throw new Error('Remote configuration prevents Moon authentication');
const znma_useragent = 'moon_ANDROID/' + config.znma_version +
' (com.nintendo.znma; build:' + config.znma_build + '; ANDROID 26)';
// Nintendo Account token
const nintendoAccountToken = await getNintendoAccountToken(token, ZNMA_CLIENT_ID);
@ -110,6 +127,17 @@ export default class MoonApi {
return {
nintendoAccountToken,
user,
znma_version: config.znma_version,
znma_build: config.znma_build,
znma_useragent: znma_useragent,
};
}
}
export interface MoonAuthData {
nintendoAccountToken: NintendoAccountToken;
user: NintendoAccountUser;
znma_version: string;
znma_build: string;
znma_useragent: string;
}

View File

@ -16,6 +16,9 @@ export default class ZncProxyApi implements CoralApi {
/** @internal */
_renewToken: Promise<void> | null = null;
readonly znca_version = '';
readonly znca_useragent = '';
constructor(
private url: string,
// ZncApi uses the NSO token (valid for a few hours)

View File

@ -1,26 +1,16 @@
import createDebug from 'debug';
import * as persist from 'node-persist';
import { Response } from 'node-fetch';
import { FlapgApiResponse, FResult } from '../../api/f.js';
import { NintendoAccountSessionTokenJwtPayload, NintendoAccountToken, NintendoAccountUser } from '../../api/na.js';
import { NintendoAccountSessionTokenJwtPayload } from '../../api/na.js';
import { Jwt } from '../../util/jwt.js';
import { AccountLogin, CoralErrorResponse } from '../../api/coral-types.js';
import CoralApi, { ZNCA_CLIENT_ID } from '../../api/coral.js';
import { CoralErrorResponse } from '../../api/coral-types.js';
import CoralApi, { CoralAuthData, ZNCA_CLIENT_ID } from '../../api/coral.js';
import ZncProxyApi from '../../api/znc-proxy.js';
import { checkUseLimit, SHOULD_LIMIT_USE } from './util.js';
const debug = createDebug('nxapi:auth:nso');
export interface SavedToken {
uuid: string;
timestamp: string;
nintendoAccountToken: NintendoAccountToken;
user: NintendoAccountUser;
f: FResult;
flapg?: FlapgApiResponse['result'];
nsoAccount: AccountLogin;
credential: AccountLogin['webApiServerCredential'];
const debug = createDebug('nxapi:auth:coral');
export interface SavedToken extends CoralAuthData {
expires_at: number;
proxy_url?: string;
}
@ -92,7 +82,7 @@ export async function getToken(
const nso = proxy_url ?
new ZncProxyApi(proxy_url, token) :
new CoralApi(existingToken.credential.accessToken);
CoralApi.createWithSavedToken(existingToken);
nso.onTokenExpired = createTokenExpiredHandler(storage, token, nso, existingToken);
@ -114,7 +104,7 @@ async function renewToken(
const data = await nso.renewToken(token, previousToken.user);
const existingToken: SavedToken = {
user: previousToken.user,
...previousToken,
...data,
expires_at: Date.now() + (data.credential.expiresIn * 1000),
};

View File

@ -1,7 +1,7 @@
import createDebug from 'debug';
import * as persist from 'node-persist';
import { ZNMA_CLIENT_ID } from '../../api/moon.js';
import { NintendoAccountSessionTokenJwtPayload, NintendoAccountToken, NintendoAccountUser } from '../../api/na.js';
import { MoonAuthData, ZNMA_CLIENT_ID } from '../../api/moon.js';
import { NintendoAccountSessionTokenJwtPayload } from '../../api/na.js';
import { Jwt } from '../../util/jwt.js';
import MoonApi from '../../api/moon.js';
import { checkUseLimit, LIMIT_REQUESTS, SHOULD_LIMIT_USE } from './util.js';
@ -11,10 +11,7 @@ const debug = createDebug('nxapi:auth:moon');
// Higher rate limit for parental controls, as the token expires sooner
const LIMIT_PERIOD = 15 * 60 * 1000; // 15 minutes
export interface SavedMoonToken {
nintendoAccountToken: NintendoAccountToken;
user: NintendoAccountUser;
export interface SavedMoonToken extends MoonAuthData {
expires_at: number;
}
@ -66,7 +63,7 @@ export async function getPctlToken(storage: persist.LocalStorage, token: string,
await storage.setItem('NintendoAccountToken-pctl.' + existingToken.user.id, token);
return {
moon: new MoonApi(existingToken.nintendoAccountToken.access_token!, existingToken.user.id),
moon: MoonApi.createWithSavedToken(existingToken),
data: existingToken,
};
}

View File

@ -3,3 +3,4 @@ export const GITHUB_MIRROR_URL = 'https://github.com/samuelthomas2774/nxapi';
export const ISSUES_URL = 'https://github.com/samuelthomas2774/nxapi/issues';
export const ZNCA_API_USE_URL = 'https://gitlab.fancy.org.uk/samuel/nxapi#splatnet2statink-and-flapg';
export const USER_AGENT_INFO_URL = 'https://gitlab.fancy.org.uk/samuel/nxapi#user-agent-strings';
export const CONFIG_URL = 'https://fancy.org.uk/api/nxapi/config';

View File

@ -7,11 +7,11 @@ import { ErrorResponse } from '../api/util.js';
import { timeoutSignal } from '../util/misc.js';
import { getUserAgent } from '../util/useragent.js';
import { paths } from '../util/storage.js';
import { dev, dir, git, version } from '../util/product.js';
import { dev, dir, embedded_default_remote_config, git, version } from '../util/product.js';
import { CONFIG_URL } from './constants.js';
const debug = createDebug('nxapi:remote-config');
const CONFIG_URL = 'https://nxapi.ta.fancy.org.uk/data/config.json';
/** Maximum time in seconds to consider cached data fresh */
const MAX_FRESH = 24 * 60 * 60; // 1 day in seconds
/** Maximum time in seconds to allow using cached data after it's considered stale */
@ -19,7 +19,8 @@ const MAX_STALE = 24 * 60 * 60; // 1 day in seconds
const default_config: NxapiRemoteConfig = {
require_version: [version],
...JSON.parse(await fs.readFile(path.join(dir, 'resources', 'common', 'remote-config.json'), 'utf-8')),
...(embedded_default_remote_config ??
JSON.parse(await fs.readFile(path.join(dir, 'resources', 'common', 'remote-config.json'), 'utf-8'))),
};
async function loadRemoteConfig() {
@ -46,6 +47,8 @@ async function loadRemoteConfig() {
} catch (err) {}
try {
debug('Getting remote config from %s, must revalidate: %s', url, must_revalidate);
const config = await getRemoteConfig(url, undefined, data ? {
previous: data.data,
updated_at: new Date(data.updated_at),
@ -95,8 +98,6 @@ async function getRemoteConfig(url: string, useragent?: string, cache?: {
updated_at: Date;
etag: string | null;
}) {
debug('Getting remote config from %s', url);
const [signal, cancel] = timeoutSignal();
const response = await fetch(url, {
headers: {
@ -159,7 +160,7 @@ export enum RemoteConfigMode {
}
export const mode =
process.env.NXAPI_ENABLE_REMOTE_CONFIG !== '1' ? RemoteConfigMode.DISABLE :
process.env.NXAPI_ENABLE_REMOTE_CONFIG === '0' ? RemoteConfigMode.DISABLE :
process.env.NXAPI_REMOTE_CONFIG_FALLBACK === '1' ? RemoteConfigMode.OPPORTUNISTIC :
RemoteConfigMode.REQUIRE;
@ -176,6 +177,8 @@ if (cache && !config.require_version.includes(version)) {
export default config;
debug('using config', RemoteConfigMode[mode], config);
export interface RemoteConfigCacheData {
created_at: number;
updated_at: number;
@ -200,6 +203,7 @@ export interface NxapiRemoteConfig {
// If null the API should not be used
coral: CoralRemoteConfig | null;
coral_auth: {
default: DefaultZncaApiProvider;
splatnet2statink: {} | null;
flapg: {} | null;
imink: {} | null;
@ -207,6 +211,11 @@ export interface NxapiRemoteConfig {
moon: MoonRemoteConfig | null;
}
export type DefaultZncaApiProvider =
'flapg' |
'imink' |
['nxapi', string];
export interface CoralRemoteConfig {
znca_version: string; // '2.1.1'
}

View File

@ -1,11 +1,17 @@
export { default } from '../api/coral.js';
export {
default,
CoralAuthData,
PartialCoralAuthData,
} from '../api/coral.js';
export * from '../api/coral-types.js';
export { default as ZncProxyApi } from '../api/znc-proxy.js';
export {
ZncaApi,
getZncaApiFromEnvironment,
getPreferredZncaApiFromEnvironment,
getDefaultZncaApi,
f,
ZncaApiFlapg,

View File

@ -1,2 +1,6 @@
export { default } from '../api/moon.js';
export {
default,
MoonAuthData,
} from '../api/moon.js';
export * from '../api/moon-types.js';

View File

@ -23,11 +23,13 @@ declare global {
changed_files: string[];
} | null | undefined;
var __NXAPI_BUNDLE_RELEASE__: string | null | undefined;
var __NXAPI_BUNDLE_DEFAULT_REMOTE_CONFIG__: any | undefined;
}
const embedded_pkg = globalThis.__NXAPI_BUNDLE_PKG__;
const embedded_git = globalThis.__NXAPI_BUNDLE_GIT__;
const embedded_release = globalThis.__NXAPI_BUNDLE_RELEASE__;
export const embedded_default_remote_config = globalThis.__NXAPI_BUNDLE_DEFAULT_REMOTE_CONFIG__;
//
// Package/version info