Rename most instances of znc to coral

This commit is contained in:
Samuel Elliott 2022-06-28 19:21:33 +01:00
parent a2f3abaebd
commit a6a69b1799
No known key found for this signature in database
GPG Key ID: 8420C7CDE43DC4D6
37 changed files with 197 additions and 165 deletions

View File

@ -1,16 +1,16 @@
export interface ZncSuccessResponse<T = unknown> {
status: ZncStatus.OK;
export interface CoralSuccessResponse<T = unknown> {
status: CoralStatus.OK;
result: T;
correlationId: string;
}
export interface ZncErrorResponse {
status: ZncStatus | number;
export interface CoralErrorResponse {
status: CoralStatus | number;
errorMessage: string;
correlationId: string;
}
export enum ZncStatus {
export enum CoralStatus {
OK = 0,
BAD_REQUEST = 9400,
@ -43,7 +43,7 @@ export enum ZncStatus {
// UNKNOWN = -1,
}
export type ZncResponse<T = unknown> = ZncSuccessResponse<T> | ZncErrorResponse;
export type CoralResponse<T = unknown> = CoralSuccessResponse<T> | CoralErrorResponse;
/** /v3/Account/Login */
export interface AccountLogin {

View File

@ -2,12 +2,12 @@ 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, ZncErrorResponse, ZncResponse, ZncStatus, ZncSuccessResponse } from './znc-types.js';
import { AccountLogin, AccountToken, Announcements, CurrentUser, CurrentUserPermissions, Event, Friends, GetActiveEventResult, PresencePermissions, User, WebServices, WebServiceToken, CoralErrorResponse, CoralResponse, CoralStatus, CoralSuccessResponse } from './coral-types.js';
import { getNintendoAccountToken, getNintendoAccountUser, NintendoAccountUser } from './na.js';
import { ErrorResponse } from './util.js';
import { JwtPayload } from '../util/jwt.js';
const debug = createDebug('nxapi:api:znc');
const debug = createDebug('nxapi:api:coral');
const ZNCA_PLATFORM = 'Android';
const ZNCA_PLATFORM_VERSION = '8.0.0';
@ -17,23 +17,23 @@ const ZNCA_USER_AGENT = `com.nintendo.znca/${ZNCA_VERSION}(${ZNCA_PLATFORM}/${ZN
const ZNC_URL = 'https://api-lp1.znc.srv.nintendo.net';
export const ZNCA_CLIENT_ID = '71b963c1b7b6d119';
export default class ZncApi {
export default class CoralApi {
static useragent: string | null = null;
onTokenExpired: ((data: ZncErrorResponse, res: Response) => Promise<void>) | null = null;
onTokenExpired: ((data: CoralErrorResponse, res: Response) => Promise<void>) | null = null;
/** @internal */
_renewToken: Promise<void> | null = null;
constructor(
public token: string,
public useragent: string | null = ZncApi.useragent
public useragent: string | null = CoralApi.useragent
) {}
async fetch<T = unknown>(
url: string, method = 'GET', body?: string, headers?: object,
/** @internal */ _autoRenewToken = true,
/** @internal */ _attempt = 0
): Promise<ZncSuccessResponse<T>> {
): Promise<CoralSuccessResponse<T>> {
if (this._renewToken && _autoRenewToken) {
await this._renewToken;
}
@ -52,9 +52,9 @@ export default class ZncApi {
debug('fetch %s %s, response %s', method, url, response.status);
const data = await response.json() as ZncResponse<T>;
const data = await response.json() as CoralResponse<T>;
if (data.status === ZncStatus.TOKEN_EXPIRED && _autoRenewToken && !_attempt && this.onTokenExpired) {
if (data.status === CoralStatus.TOKEN_EXPIRED && _autoRenewToken && !_attempt && this.onTokenExpired) {
// _renewToken will be awaited when calling fetch
this._renewToken = this._renewToken ?? this.onTokenExpired.call(null, data, response).finally(() => {
this._renewToken = null;
@ -65,7 +65,7 @@ export default class ZncApi {
if ('errorMessage' in data) {
throw new ErrorResponse('[znc] ' + data.errorMessage, response, data);
}
if (data.status !== ZncStatus.OK) {
if (data.status !== CoralStatus.OK) {
throw new ErrorResponse('[znc] Unknown error', response, data);
}
@ -194,7 +194,7 @@ export default class ZncApi {
};
}
static async createWithSessionToken(token: string, useragent = ZncApi.useragent) {
static async createWithSessionToken(token: string, useragent = CoralApi.useragent) {
const data = await this.loginWithSessionToken(token, useragent);
return {
@ -211,7 +211,7 @@ export default class ZncApi {
return data;
}
static async loginWithSessionToken(token: string, useragent = ZncApi.useragent) {
static async loginWithSessionToken(token: string, useragent = CoralApi.useragent) {
const uuid = uuidgen();
const timestamp = '' + Math.floor(Date.now() / 1000);
@ -248,7 +248,7 @@ export default class ZncApi {
});
debug('fetch %s %s, response %s', 'POST', '/v3/Account/Login', response.status);
const data = await response.json() as ZncResponse<AccountLogin>;
const data = await response.json() as CoralResponse<AccountLogin>;
if ('errorMessage' in data) {
throw new ErrorResponse('[znc] ' + data.errorMessage, response, data);
@ -271,7 +271,7 @@ export default class ZncApi {
}
}
export interface ZncJwtPayload extends JwtPayload {
export interface CoralJwtPayload extends JwtPayload {
isChildRestricted: boolean;
membership: {
active: boolean;
@ -280,18 +280,18 @@ export interface ZncJwtPayload extends JwtPayload {
exp: number;
iat: number;
iss: 'api-lp1.znc.srv.nintendo.net';
/** User ID (CurrentUser.id, not CurrentUser.nsaID) */
/** Coral user ID (CurrentUser.id, not CurrentUser.nsaID) */
sub: number;
typ: 'id_token';
}
export interface ZncWebServiceJwtPayload extends JwtPayload {
export interface CoralWebServiceJwtPayload extends JwtPayload {
isChildRestricted: boolean;
aud: string;
exp: number;
iat: number;
iss: 'api-lp1.znc.srv.nintendo.net';
jti: string;
/** User ID (CurrentUser.id, not CurrentUser.nsaID) */
/** Coral user ID (CurrentUser.id, not CurrentUser.nsaID) */
sub: number;
links: {
networkServiceAccount: {

View File

@ -10,6 +10,14 @@ const debugFlapg = createDebug('nxapi:api:flapg');
const debugImink = createDebug('nxapi:api:imink');
const debugZncaApi = createDebug('nxapi:api:znca-api');
abstract class ZncaApi {
constructor(
public useragent?: string
) {}
abstract genf(token: string, timestamp: string, uuid: string, type: FlapgIid): Promise<FResult>;
}
//
// splatnet2statink + flapg
//
@ -96,6 +104,23 @@ export interface FlapgApiResponse {
};
}
export class ZncaApiFlapg extends ZncaApi {
async getLoginHash(id_token: string, timestamp: string) {
return getLoginHash(id_token, timestamp, this.useragent);
}
async genf(token: string, timestamp: string, uuid: string, type: FlapgIid) {
const result = await flapg(token, timestamp, uuid, type, this.useragent);
return {
provider: 'flapg' as const,
token, timestamp, uuid, type,
f: result.result.f,
result,
};
}
}
//
// imink
//
@ -151,6 +176,19 @@ export interface IminkFError {
error: true;
}
export class ZncaApiImink extends ZncaApi {
async genf(token: string, timestamp: string, uuid: string, type: FlapgIid) {
const result = await iminkf(token, timestamp, uuid, type === FlapgIid.APP ? '2' : '1', this.useragent);
return {
provider: 'imink' as const,
token, timestamp, uuid, type,
f: result.f,
result,
};
}
}
//
// nxapi znca API server
//
@ -206,43 +244,32 @@ export interface AndroidZncaFError {
error: string;
}
export async function f(
token: string, timestamp: string | number, uuid: string, type: FlapgIid,
useragent?: string,
provider: FApi = getEnvApi()
): Promise<FResult> {
if (provider === 'flapg') {
const result = await flapg(token, timestamp, uuid, type, useragent);
return {
provider: 'flapg',
token, timestamp: '' + timestamp, uuid, type,
f: result.result.f, result,
};
}
if (provider === 'imink') {
const result = await iminkf(token, timestamp, uuid, type === FlapgIid.APP ? '2' : '1', useragent);
return {
provider: 'imink',
token, timestamp: '' + timestamp, uuid, type,
f: result.f, result,
};
}
if (provider[0] === 'nxapi') {
const result = await genf(provider[1], token, timestamp, uuid, type, useragent);
return {
provider: 'nxapi', url: provider[1],
token, timestamp: '' + timestamp, uuid, type,
f: result.f, result,
};
export class ZncaApiNxapi extends ZncaApi {
constructor(readonly url: string, useragent?: string) {
super(useragent);
}
throw new Error('Unknown znca API provider');
async genf(token: string, timestamp: string, uuid: string, type: FlapgIid) {
const result = await genf(this.url + '/f', token, timestamp, uuid, type, this.useragent);
return {
provider: 'nxapi' as const,
url: this.url + '/f',
token, timestamp, uuid, type,
f: result.f,
result,
};
}
}
export type FApi =
'flapg' |
'imink' |
['nxapi', string];
export async function f(
token: string, timestamp: string | number, uuid: string, type: FlapgIid,
useragent?: string
): Promise<FResult> {
const provider = getZncaApiFromEnvironment(useragent);
return provider.genf(token, '' + timestamp, uuid, type);
}
export type FResult = {
provider: string;
@ -264,21 +291,21 @@ export type FResult = {
result: AndroidZncaFResponse;
});
function getEnvApi(): FApi {
function getZncaApiFromEnvironment(useragent?: string): ZncaApi {
if (process.env.NXAPI_ZNCA_API) {
if (process.env.NXAPI_ZNCA_API === 'flapg') {
return 'flapg';
return new ZncaApiFlapg(useragent);
}
if (process.env.NXAPI_ZNCA_API === 'imink') {
return 'imink';
return new ZncaApiImink(useragent);
}
throw new Error('Unknown znca API provider');
}
if (process.env.ZNCA_API_URL) {
return ['nxapi', process.env.ZNCA_API_URL + '/f'];
return new ZncaApiNxapi(process.env.ZNCA_API_URL, useragent);
}
return 'flapg';
return new ZncaApiFlapg(useragent);
}

View File

@ -1,9 +1,9 @@
import fetch from 'node-fetch';
import createDebug from 'debug';
import { WebServiceToken } from './znc-types.js';
import { WebServiceToken } from './coral-types.js';
import { NintendoAccountUser } from './na.js';
import { ErrorResponse } from './util.js';
import ZncApi from './znc.js';
import CoralApi from './coral.js';
import { WebServiceError, Users, AuthToken, UserProfile, Newspapers, Newspaper, Emoticons, Reaction, IslandProfile } from './nooklink-types.js';
import { timeoutSignal } from '../util/misc.js';
@ -76,8 +76,8 @@ export default class NooklinkApi {
};
}
static async createWithZnc(nso: ZncApi, user: NintendoAccountUser) {
const data = await this.loginWithZnc(nso, user);
static async createWithCoral(nso: CoralApi, user: NintendoAccountUser) {
const data = await this.loginWithCoral(nso, user);
return {
nooklink: new this(data.gtoken, data.useragent),
@ -85,7 +85,7 @@ export default class NooklinkApi {
};
}
static async loginWithZnc(nso: ZncApi, user: NintendoAccountUser) {
static async loginWithCoral(nso: CoralApi, user: NintendoAccountUser) {
const webserviceToken = await nso.getWebServiceToken(NOOKLINK_WEBSERVICE_ID);
return this.loginWithWebServiceToken(webserviceToken.result, user);

View File

@ -1,10 +1,10 @@
import fetch from 'node-fetch';
import createDebug from 'debug';
import { v4 as uuidgen } from 'uuid';
import { WebServiceToken } from './znc-types.js';
import { WebServiceToken } from './coral-types.js';
import { NintendoAccountUser } from './na.js';
import { ErrorResponse } from './util.js';
import ZncApi from './znc.js';
import CoralApi from './coral.js';
import { ActiveFestivals, CoopResult, CoopResults, CoopSchedules, HeroRecords, NicknameAndIcons, PastFestivals, Records, Result, Results, Schedules, ShareResponse, ShopMerchandises, Stages, Timeline, WebServiceError, XPowerRankingSummary } from './splatnet2-types.js';
import { timeoutSignal } from '../util/misc.js';
import { toSeasonId, Rule as XPowerRankingRule } from './splatnet2-xrank.js';
@ -211,8 +211,8 @@ ${colour}
});
}
static async createWithZnc(nso: ZncApi, user: NintendoAccountUser) {
const data = await this.loginWithZnc(nso, user);
static async createWithCoral(nso: CoralApi, user: NintendoAccountUser) {
const data = await this.loginWithCoral(nso, user);
return {
splatnet: new this(data.iksm_session, data.useragent),
@ -220,7 +220,7 @@ ${colour}
};
}
static async loginWithZnc(nso: ZncApi, user: NintendoAccountUser) {
static async loginWithCoral(nso: CoralApi, user: NintendoAccountUser) {
const webserviceToken = await nso.getWebServiceToken(SPLATNET2_WEBSERVICE_ID);
return this.loginWithWebServiceToken(webserviceToken.result, user);

View File

@ -1,8 +1,8 @@
import fetch, { Response } from 'node-fetch';
import createDebug from 'debug';
import { ActiveEvent, Announcements, CurrentUser, Event, Friend, Presence, PresencePermissions, User, WebService, WebServiceToken, ZncErrorResponse, ZncStatus, ZncSuccessResponse } from './znc-types.js';
import { ActiveEvent, Announcements, CurrentUser, Event, Friend, Presence, PresencePermissions, User, WebService, WebServiceToken, CoralErrorResponse, CoralStatus, CoralSuccessResponse } from './coral-types.js';
import { ErrorResponse } from './util.js';
import ZncApi from './znc.js';
import CoralApi from './coral.js';
import { version } from '../util/product.js';
import { NintendoAccountUser } from './na.js';
import { SavedToken } from '../common/auth/nso.js';
@ -10,11 +10,11 @@ import { timeoutSignal } from '../util/misc.js';
const debug = createDebug('nxapi:api:znc-proxy');
export default class ZncProxyApi implements ZncApi {
export default class ZncProxyApi implements CoralApi {
static useragent: string | null = null;
// Not used by ZncProxyApi
onTokenExpired: ((data: ZncErrorResponse, res: Response) => Promise<void>) | null = null;
onTokenExpired: ((data: CoralErrorResponse, res: Response) => Promise<void>) | null = null;
/** @internal */
_renewToken: Promise<void> | null = null;
@ -51,64 +51,64 @@ export default class ZncProxyApi implements ZncApi {
return data;
}
async call<T = unknown>(url: string, parameter = {}): Promise<ZncSuccessResponse<T>> {
async call<T = unknown>(url: string, parameter = {}): Promise<CoralSuccessResponse<T>> {
throw new Error('Not supported in ZncProxyApi');
}
async getAnnouncements() {
const response = await this.fetch<{announcements: Announcements}>('/announcements');
return {status: ZncStatus.OK as const, result: response.announcements, correlationId: ''};
return {status: CoralStatus.OK as const, result: response.announcements, correlationId: ''};
}
async getFriendList() {
const response = await this.fetch<{friends: Friend[]}>('/friends');
return {status: ZncStatus.OK as const, result: response, correlationId: ''};
return {status: CoralStatus.OK as const, result: response, correlationId: ''};
}
async addFavouriteFriend(nsaid: string) {
await this.fetch('/friend/' + nsaid, 'POST', JSON.stringify({
isFavoriteFriend: true,
}));
return {status: ZncStatus.OK as const, result: {}, correlationId: ''};
return {status: CoralStatus.OK as const, result: {}, correlationId: ''};
}
async removeFavouriteFriend(nsaid: string) {
await this.fetch('/friend/' + nsaid, 'POST', JSON.stringify({
isFavoriteFriend: false,
}));
return {status: ZncStatus.OK as const, result: {}, correlationId: ''};
return {status: CoralStatus.OK as const, result: {}, correlationId: ''};
}
async getWebServices() {
const response = await this.fetch<{webservices: WebService[]}>('/webservices');
return {status: ZncStatus.OK as const, result: response.webservices, correlationId: ''};
return {status: CoralStatus.OK as const, result: response.webservices, correlationId: ''};
}
async getActiveEvent() {
const response = await this.fetch<{activeevent: ActiveEvent}>('/activeevent');
return {status: ZncStatus.OK as const, result: response.activeevent, correlationId: ''};
return {status: CoralStatus.OK as const, result: response.activeevent, correlationId: ''};
}
async getEvent(id: number) {
const response = await this.fetch<{event: Event}>('/event/' + id);
return {status: ZncStatus.OK as const, result: response.event, correlationId: ''};
return {status: CoralStatus.OK as const, result: response.event, correlationId: ''};
}
async getUser(id: number) {
const response = await this.fetch<{user: User}>('/user/' + id);
return {status: ZncStatus.OK as const, result: response.user, correlationId: ''};
return {status: CoralStatus.OK as const, result: response.user, correlationId: ''};
}
async getCurrentUser() {
const response = await this.fetch<{user: CurrentUser}>('/user');
return {status: ZncStatus.OK as const, result: response.user, correlationId: ''};
return {status: CoralStatus.OK as const, result: response.user, correlationId: ''};
}
async getCurrentUserPermissions() {
const user = await this.getCurrentUser();
return {
status: ZncStatus.OK as const,
status: CoralStatus.OK as const,
result: {
etag: user.result.etag,
permissions: user.result.permissions,
@ -119,16 +119,16 @@ export default class ZncProxyApi implements ZncApi {
async updateCurrentUserPermissions(
to: PresencePermissions, from: PresencePermissions, etag: string
): Promise<ZncSuccessResponse<{}>> {
): Promise<CoralSuccessResponse<{}>> {
throw new Error('Not supported in ZncProxyApi');
}
async getWebServiceToken(id: string) {
const response = await this.fetch<{token: WebServiceToken}>('/webservice/' + id + '/token');
return {status: ZncStatus.OK as const, result: response.token, correlationId: ''};
return {status: CoralStatus.OK as const, result: response.token, correlationId: ''};
}
async getToken(token: string, user: NintendoAccountUser): ReturnType<ZncApi['getToken']> {
async getToken(token: string, user: NintendoAccountUser): ReturnType<CoralApi['getToken']> {
throw new Error('Not supported in ZncProxyApi');
}

View File

@ -12,7 +12,7 @@ export interface DiscordSetupProps {
}
enum DiscordSourceType {
ZNC,
CORAL,
URL,
NONE,
}
@ -30,7 +30,7 @@ export default function DiscordSetup(props: DiscordSetupProps) {
const [discord_presence_source, discord_presence_source_state] = useDiscordPresenceSource();
const [selectedMode, setSelectedMode] = useState(props.users?.length && props.friend_nsa_id ?
DiscordSourceType.ZNC : DiscordSourceType.NONE);
DiscordSourceType.CORAL : DiscordSourceType.NONE);
const [selectedUserId, setSelectedUserId] = useState<string | null>(null);
const [selectedFriendNsaId, setSelectedFriendNsaId] = useState<string | null>(props.friend_nsa_id ?? null);
const [presenceUrl, setPresenceUrl] = useState('');
@ -38,9 +38,9 @@ export default function DiscordSetup(props: DiscordSetupProps) {
useEffect(() => {
if (!discord_presence_source) {
setSelectedMode(props.users?.length && props.friend_nsa_id ?
DiscordSourceType.ZNC : DiscordSourceType.NONE);
DiscordSourceType.CORAL : DiscordSourceType.NONE);
} else if ('na_id' in discord_presence_source) {
setSelectedMode(DiscordSourceType.ZNC);
setSelectedMode(DiscordSourceType.CORAL);
setSelectedUserId(discord_presence_source.na_id);
setSelectedFriendNsaId(discord_presence_source.friend_nsa_id ?? null);
} else if ('url' in discord_presence_source) {
@ -72,7 +72,7 @@ export default function DiscordSetup(props: DiscordSetupProps) {
}, [friends, user]);
const save = useCallback(async () => {
if (selectedMode === DiscordSourceType.ZNC) {
if (selectedMode === DiscordSourceType.CORAL) {
if (!selectedUserId?.match(/^[0-9a-f]{16}$/)) throw new Error('Invalid Nintendo Account ID');
if (!selectedFriendNsaId?.match(/^[0-9a-f]{16}$/)) throw new Error('Invalid friend Network Service Account ID');
@ -106,13 +106,13 @@ export default function DiscordSetup(props: DiscordSetupProps) {
style={[styles.picker, theme.picker]}
>
<Picker.Item label="Select a user that is friends with the user you want to share"
value={DiscordSourceType.ZNC} />
value={DiscordSourceType.CORAL} />
<Picker.Item label="Enter a URL that returns the presence data you want to share"
value={DiscordSourceType.URL} />
<Picker.Item label="Disable" value={DiscordSourceType.NONE} />
</Picker>
{selectedMode === DiscordSourceType.ZNC ? <>
{selectedMode === DiscordSourceType.CORAL ? <>
<Text style={[styles.header, theme.text]}>2. Select user</Text>
<Text style={[styles.help, theme.text]}>This user must be friends with the user you want to share.</Text>

View File

@ -3,7 +3,7 @@
import React, { useCallback, useEffect } from 'react';
import { ActivityIndicator, Image, StyleSheet, Text, TouchableOpacity, useColorScheme, View } from 'react-native';
import { CheckBox } from 'react-native-web';
import { Game, Presence, PresencePermissions, PresenceState } from '../../../api/znc-types.js';
import { Game, Presence, PresencePermissions, PresenceState } from '../../../api/coral-types.js';
import { getTitleIdFromEcUrl, hrduration } from '../../../util/misc.js';
import { Button } from '../components/index.js';
import { DEFAULT_ACCENT_COLOUR, TEXT_COLOUR_ACTIVE, TEXT_COLOUR_DARK, TEXT_COLOUR_LIGHT } from '../constants.js';

View File

@ -2,7 +2,7 @@ import React, { useCallback, useMemo } from 'react';
import { Image, StyleSheet, Text, View } from 'react-native';
import ipc, { events } from '../ipc.js';
import { getAccounts, RequestState, useAccentColour, useAsync, useColourScheme, useDiscordPresenceSource, useEventListener, User } from '../util.js';
import { Friend, PresencePermissions } from '../../../api/znc-types.js';
import { Friend, PresencePermissions } from '../../../api/coral-types.js';
import { TEXT_COLOUR_DARK, TEXT_COLOUR_LIGHT } from '../constants.js';
import Section from './section.js';
import { Button } from '../components/index.js';

View File

@ -3,7 +3,7 @@ import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { User } from 'discord-rpc';
import ipc, { events } from '../ipc.js';
import { RequestState, useAsync, useEventListener } from '../util.js';
import { DiscordPresenceSource, DiscordPresenceSourceUrl, DiscordPresenceSourceZnc } from '../../common/types.js';
import { DiscordPresenceSource, DiscordPresenceSourceUrl, DiscordPresenceSourceCoral } from '../../common/types.js';
import { DiscordPresence } from '../../../discord/util.js';
import { DISCORD_COLOUR, TEXT_COLOUR_DARK } from '../constants.js';
@ -24,7 +24,7 @@ export default function DiscordPresenceSource(props: {
function renderDiscordPresenceSource(source: DiscordPresenceSource | null) {
if (source && 'na_id' in source) {
return <DiscordPresenceSourceZnc source={source} />;
return <DiscordPresenceSourceCoral source={source} />;
} else if (source && 'url' in source) {
return <DiscordPresenceSourceUrl source={source} />;
} else {
@ -32,8 +32,8 @@ function renderDiscordPresenceSource(source: DiscordPresenceSource | null) {
}
}
function DiscordPresenceSourceZnc(props: {
source: DiscordPresenceSourceZnc;
function DiscordPresenceSourceCoral(props: {
source: DiscordPresenceSourceCoral;
}) {
const [token] = useAsync(useCallback(() =>
ipc.getNintendoAccountNsoToken(props.source.na_id), [ipc, props.source.na_id]));

View File

@ -2,7 +2,7 @@ import React from 'react';
import { Image, StyleSheet, Text, View } from 'react-native';
import ipc from '../ipc.js';
import { useAccentColour, useColourScheme, User } from '../util.js';
import { ActiveEvent } from '../../../api/znc-types.js';
import { ActiveEvent } from '../../../api/coral-types.js';
import { TEXT_COLOUR_DARK, TEXT_COLOUR_LIGHT } from '../constants.js';
import Section from './section.js';
import { Button } from '../components/index.js';

View File

@ -2,7 +2,7 @@ import React, { useCallback } from 'react';
import { Image, ImageStyle, Platform, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import ipc from '../ipc.js';
import { useColourScheme, User } from '../util.js';
import { Friend, Presence, PresenceState } from '../../../api/znc-types.js';
import { Friend, Presence, PresenceState } from '../../../api/coral-types.js';
import { TEXT_COLOUR_ACTIVE, TEXT_COLOUR_DARK, TEXT_COLOUR_LIGHT } from '../constants.js';
import Section from './section.js';

View File

@ -2,7 +2,7 @@ import React from 'react';
import { Image, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import ipc from '../ipc.js';
import { useColourScheme, User } from '../util.js';
import { WebService } from '../../../api/znc-types.js';
import { WebService } from '../../../api/coral-types.js';
import { TEXT_COLOUR_DARK, TEXT_COLOUR_LIGHT } from '../constants.js';
import Section from './section.js';

View File

@ -28,8 +28,8 @@ export interface DiscordPresenceConfiguration {
show_play_time?: DiscordPresencePlayTime;
}
export type DiscordPresenceSource = DiscordPresenceSourceZnc | DiscordPresenceSourceUrl;
export interface DiscordPresenceSourceZnc {
export type DiscordPresenceSource = DiscordPresenceSourceCoral | DiscordPresenceSourceUrl;
export interface DiscordPresenceSourceCoral {
na_id: string;
friend_nsa_id?: string;
}

View File

@ -5,7 +5,7 @@ import { User } from 'discord-rpc';
import openWebService, { WebServiceIpc } from './webservices.js';
import { createWindow, getWindowConfiguration } from './windows.js';
import { DiscordPresenceConfiguration, DiscordPresenceSource, WindowType } from '../common/types.js';
import { CurrentUser, Friend, Game, PresenceState, WebService } from '../../api/znc-types.js';
import { CurrentUser, Friend, Game, PresenceState, WebService } from '../../api/coral-types.js';
import { addNsoAccount, addPctlAccount } from './na-auth.js';
import { App } from './index.js';
import { NintendoAccountUser } from '../../api/na.js';

View File

@ -2,7 +2,7 @@ import { app, dialog, Menu, Tray, nativeImage, MenuItem } from './electron.js';
import createDebug from 'debug';
import { addNsoAccount, addPctlAccount } from './na-auth.js';
import { App } from './index.js';
import { WebService } from '../../api/znc-types.js';
import { WebService } from '../../api/coral-types.js';
import openWebService from './webservices.js';
import { SavedToken } from '../../common/auth/nso.js';
import { SavedMoonToken } from '../../common/auth/moon.js';

View File

@ -1,6 +1,6 @@
import { dialog, Notification } from './electron.js';
import createDebug from 'debug';
import { CurrentUser, Friend, Game, ZncErrorResponse } from '../../api/znc-types.js';
import { CurrentUser, Friend, Game, CoralErrorResponse } from '../../api/coral-types.js';
import { ErrorResponse } from '../../api/util.js';
import { ZncDiscordPresence, ZncProxyDiscordPresence } from '../../common/presence.js';
import { NotificationManager } from '../../common/notify.js';
@ -295,7 +295,7 @@ export class EmbeddedPresenceMonitor extends ZncDiscordPresence {
}
}
async handleError(err: ErrorResponse<ZncErrorResponse> | NodeJS.ErrnoException): Promise<LoopResult> {
async handleError(err: ErrorResponse<CoralErrorResponse> | NodeJS.ErrnoException): Promise<LoopResult> {
try {
return await super.handleError(err);
} catch (err) {
@ -361,7 +361,7 @@ export class EmbeddedProxyPresenceMonitor extends ZncProxyDiscordPresence {
}
}
async handleError(err: ErrorResponse<ZncErrorResponse> | NodeJS.ErrnoException): Promise<LoopResult> {
async handleError(err: ErrorResponse<CoralErrorResponse> | NodeJS.ErrnoException): Promise<LoopResult> {
try {
return await super.handleError(err);
} catch (err) {

View File

@ -4,7 +4,7 @@ import createDebug from 'debug';
import * as persist from 'node-persist';
import { BrowserWindow, dialog, MessageBoxOptions, Notification, session, shell } from './electron.js';
import { getNintendoAccountSessionToken, NintendoAccountSessionToken } from '../../api/na.js';
import { ZNCA_CLIENT_ID } from '../../api/znc.js';
import { ZNCA_CLIENT_ID } from '../../api/coral.js';
import { ZNMA_CLIENT_ID } from '../../api/moon.js';
import { getToken, SavedToken } from '../../common/auth/nso.js';
import { getPctlToken, SavedMoonToken } from '../../common/auth/moon.js';

View File

@ -5,9 +5,9 @@ import { Buffer } from 'node:buffer';
import createDebug from 'debug';
import { app, BrowserWindow, dialog, IpcMainInvokeEvent, Menu, MenuItem, nativeTheme, ShareMenu, shell, WebContents } from './electron.js';
import fetch from 'node-fetch';
import ZncApi from '../../api/znc.js';
import CoralApi from '../../api/coral.js';
import { dev } from '../../util/product.js';
import { WebService } from '../../api/znc-types.js';
import { WebService } from '../../api/coral-types.js';
import { Store } from './index.js';
import type { NativeShareRequest, NativeShareUrlRequest } from '../preload-webservice/znca-js-api.js';
import { SavedToken } from '../../common/auth/nso.js';
@ -16,10 +16,10 @@ import { createWebServiceWindow } from './windows.js';
const debug = createDebug('app:main:webservices');
const windows = new Map<string, BrowserWindow>();
const windowapi = new WeakMap<WebContents, [Store, string, ZncApi, SavedToken, WebService]>();
const windowapi = new WeakMap<WebContents, [Store, string, CoralApi, SavedToken, WebService]>();
export default async function openWebService(
store: Store, token: string, nso: ZncApi, data: SavedToken,
store: Store, token: string, nso: CoralApi, data: SavedToken,
webservice: WebService, qs?: string
) {
const windowid = data.nsoAccount.user.nsaId + ':' + webservice.id;

View File

@ -4,7 +4,7 @@ import { dev } from '../../util/product.js';
import { WindowConfiguration, WindowType } from '../common/types.js';
import { bundlepath } from './util.js';
import { app_menu, createWindowMenu } from './app-menu.js';
import { WebService } from '../../api/znc-types.js';
import { WebService } from '../../api/coral-types.js';
const windows = new WeakMap<WebContents, WindowConfiguration>();
const menus = new WeakMap<BrowserWindow, Menu>();

View File

@ -8,7 +8,7 @@ import type { DiscordPresenceConfiguration, DiscordPresenceSource, WindowConfigu
import type { SavedToken } from '../../common/auth/nso.js';
import type { SavedMoonToken } from '../../common/auth/moon.js';
import type { UpdateCacheData } from '../../common/update.js';
import type { Announcements, CurrentUser, Friend, GetActiveEventResult, WebService, WebServices } from '../../api/znc-types.js';
import type { Announcements, CurrentUser, Friend, GetActiveEventResult, WebService, WebServices } from '../../api/coral-types.js';
import type { DiscordPresence } from '../../discord/util.js';
import type { NintendoAccountUser } from '../../api/na.js';
import type { DiscordSetupProps } from '../browser/discord/index.js';

View File

@ -10,7 +10,7 @@ import bodyParser from 'body-parser';
import mkdirp from 'mkdirp';
import type { Arguments as ParentArguments } from '../cli.js';
import { NintendoAccountIdTokenJwtPayload } from '../api/na.js';
import { ZNCA_CLIENT_ID, ZncJwtPayload } from '../api/znc.js';
import { CoralJwtPayload, ZNCA_CLIENT_ID } from '../api/coral.js';
import { ArgumentsCamelCase, Argv, YargsArguments } from '../util/yargs.js';
import { initStorage, paths } from '../util/storage.js';
import { getJwks, Jwt } from '../util/jwt.js';
@ -139,7 +139,7 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
}
try {
const [jwt, sig] = Jwt.decode<NintendoAccountIdTokenJwtPayload | ZncJwtPayload>(data.token);
const [jwt, sig] = Jwt.decode<NintendoAccountIdTokenJwtPayload | CoralJwtPayload>(data.token);
const check_signature = jwt.payload.iss === 'https://accounts.nintendo.com';

View File

@ -5,7 +5,7 @@ import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js';
import { initStorage } from '../../util/storage.js';
import { getToken } from '../../common/auth/nso.js';
import { getNintendoAccountSessionToken } from '../../api/na.js';
import { ZNCA_CLIENT_ID } from '../../api/znc.js';
import { ZNCA_CLIENT_ID } from '../../api/coral.js';
import prompt from '../util/prompt.js';
const debug = createDebug('cli:nso:auth');

View File

@ -1,6 +1,6 @@
import createDebug from 'debug';
import Table from '../util/table.js';
import { PresenceState } from '../../api/znc-types.js';
import { PresenceState } from '../../api/coral-types.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js';
import { initStorage } from '../../util/storage.js';

View File

@ -4,8 +4,8 @@ import * as persist from 'node-persist';
import express, { Request, Response } from 'express';
import bodyParser from 'body-parser';
import { v4 as uuidgen } from 'uuid';
import { Announcement, CurrentUser, Friend, GetActiveEventResult, Presence, WebService } from '../../api/znc-types.js';
import ZncApi from '../../api/znc.js';
import { Announcement, CurrentUser, Friend, GetActiveEventResult, Presence, WebService } from '../../api/coral-types.js';
import CoralApi from '../../api/coral.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js';
import { initStorage } from '../../util/storage.js';
@ -18,7 +18,7 @@ import { AuthPolicy, AuthToken, ZncPresenceEventStreamEvent } from '../../api/zn
declare global {
namespace Express {
interface Request {
znc?: ZncApi;
znc?: CoralApi;
zncAuth?: SavedToken;
zncAuthPolicy?: AuthPolicy;
@ -126,7 +126,7 @@ function createApp(
}));
}
const znc_auth_promise = new Map</** session token */ string, Promise<{nso: ZncApi, data: SavedToken;}>>();
const znc_auth_promise = new Map</** session token */ string, Promise<{nso: CoralApi, data: SavedToken;}>>();
const znc_auth_timeout = new Map</** session token */ string, NodeJS.Timeout>();
const nsoAuth: express.RequestHandler = async (req, res, next) => {

View File

@ -7,7 +7,7 @@ import { initStorage } from '../../util/storage.js';
import { getToken } from '../../common/auth/nso.js';
import { getIksmToken } from '../../common/auth/splatnet2.js';
import { EmbeddedSplatNet2Monitor, NotificationManager, ZncNotifications } from '../../common/notify.js';
import { CurrentUser, Friend, Game } from '../../api/znc-types.js';
import { CurrentUser, Friend, Game } from '../../api/coral-types.js';
const debug = createDebug('cli:nso:notify');

View File

@ -1,5 +1,5 @@
import createDebug from 'debug';
import { PresencePermissions } from '../../api/znc-types.js';
import { PresencePermissions } from '../../api/coral-types.js';
import type { Arguments as ParentArguments } from '../nso.js';
import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js';
import { initStorage } from '../../util/storage.js';

View File

@ -2,7 +2,7 @@ import process from 'node:process';
import createDebug from 'debug';
import fetch from 'node-fetch';
import { getPresenceFromUrl } from '../../api/znc-proxy.js';
import { ActiveEvent, CurrentUser, Friend, Game, Presence, PresenceState } from '../../api/znc-types.js';
import { ActiveEvent, CurrentUser, Friend, Game, Presence, PresenceState } from '../../api/coral-types.js';
import type { Arguments as ParentArguments } from '../util.js';
import { DiscordPresenceContext, DiscordPresencePlayTime, getDiscordPresence, getInactiveDiscordPresence } from '../../discord/util.js';
import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js';
@ -84,7 +84,7 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
const [presence, user, friendcode, activeevent] =
argv.presenceJson ? await getPresenceFromJson(argv.presenceJson) :
argv.presenceUrl ? await getPresenceFromUrl(argv.presenceUrl) :
await getPresenceFromZnc(argv);
await getPresenceFromCoral(argv);
const discordpresence = getActivityFromPresence(argv, presence, user, friendcode, activeevent);
const application = argv.showDiscordApplication ?
@ -137,7 +137,7 @@ async function getPresenceFromJson(json: string) {
return [presence] as const;
}
async function getPresenceFromZnc(argv: ArgumentsCamelCase<Arguments>) {
async function getPresenceFromCoral(argv: ArgumentsCamelCase<Arguments>) {
const storage = await initStorage(argv.dataPath);
const usernsid = argv.user ?? await storage.getItem('SelectedUser');

View File

@ -3,7 +3,7 @@ import persist from 'node-persist';
import { getToken } from './nso.js';
import NooklinkApi, { NooklinkUserApi } from '../../api/nooklink.js';
import { AuthToken, Users } from '../../api/nooklink-types.js';
import { WebServiceToken } from '../../api/znc-types.js';
import { WebServiceToken } from '../../api/coral-types.js';
const debug = createDebug('nxapi:auth:nooklink');
@ -38,7 +38,7 @@ export async function getWebServiceToken(
const {nso, data} = await getToken(storage, token, proxy_url);
const existingToken: SavedToken = await NooklinkApi.loginWithZnc(nso, data.user);
const existingToken: SavedToken = await NooklinkApi.loginWithCoral(nso, data.user);
await storage.setItem('NookToken.' + token, existingToken);

View File

@ -4,8 +4,8 @@ import { Response } from 'node-fetch';
import { FlapgApiResponse, FResult } from '../../api/f.js';
import { NintendoAccountSessionTokenJwtPayload, NintendoAccountToken, NintendoAccountUser } from '../../api/na.js';
import { Jwt } from '../../util/jwt.js';
import { AccountLogin, ZncErrorResponse } from '../../api/znc-types.js';
import ZncApi, { ZNCA_CLIENT_ID } from '../../api/znc.js';
import { AccountLogin, CoralErrorResponse } from '../../api/coral-types.js';
import CoralApi, { ZNCA_CLIENT_ID } from '../../api/coral.js';
import ZncProxyApi from '../../api/znc-proxy.js';
const debug = createDebug('nxapi:auth:nso');
@ -29,7 +29,7 @@ export async function getToken(storage: persist.LocalStorage, token: string, pro
data: SavedToken;
}>
export async function getToken(storage: persist.LocalStorage, token: string, proxy_url?: string): Promise<{
nso: ZncApi;
nso: CoralApi;
data: SavedToken;
}>
export async function getToken(storage: persist.LocalStorage, token: string, proxy_url?: string) {
@ -63,7 +63,7 @@ export async function getToken(storage: persist.LocalStorage, token: string, pro
const {nso, data} = proxy_url ?
await ZncProxyApi.createWithSessionToken(proxy_url, token) :
await ZncApi.createWithSessionToken(token);
await CoralApi.createWithSessionToken(token);
const existingToken: SavedToken = {
...data,
@ -83,7 +83,7 @@ export async function getToken(storage: persist.LocalStorage, token: string, pro
const nso = proxy_url ?
new ZncProxyApi(proxy_url, token) :
new ZncApi(existingToken.credential.accessToken);
new CoralApi(existingToken.credential.accessToken);
nso.onTokenExpired = createTokenExpiredHandler(storage, token, nso, existingToken);
@ -91,16 +91,16 @@ export async function getToken(storage: persist.LocalStorage, token: string, pro
}
function createTokenExpiredHandler(
storage: persist.LocalStorage, token: string, nso: ZncApi, existingToken: SavedToken
storage: persist.LocalStorage, token: string, nso: CoralApi, existingToken: SavedToken
) {
return (data: ZncErrorResponse, response: Response) => {
return (data: CoralErrorResponse, response: Response) => {
debug('Token expired', existingToken.user.id, data);
return renewToken(storage, token, nso, existingToken);
};
}
async function renewToken(
storage: persist.LocalStorage, token: string, nso: ZncApi, previousToken: SavedToken
storage: persist.LocalStorage, token: string, nso: CoralApi, previousToken: SavedToken
) {
const data = await nso.renewToken(token, previousToken.user);

View File

@ -4,7 +4,7 @@ import createDebug from 'debug';
import persist from 'node-persist';
import { getToken } from './nso.js';
import SplatNet2Api, { updateIksmSessionLastUsed } from '../../api/splatnet2.js';
import { WebServiceToken } from '../../api/znc-types.js';
import { WebServiceToken } from '../../api/coral-types.js';
const debug = createDebug('nxapi:auth:splatnet2');
@ -49,7 +49,7 @@ export async function getIksmToken(storage: persist.LocalStorage, token: string,
const {nso, data} = await getToken(storage, token, proxy_url);
const existingToken: SavedIksmSessionToken = await SplatNet2Api.loginWithZnc(nso, data.user);
const existingToken: SavedIksmSessionToken = await SplatNet2Api.loginWithCoral(nso, data.user);
await storage.setItem('IksmToken.' + token, existingToken);
@ -81,7 +81,7 @@ export async function renewIksmToken(splatnet: SplatNet2Api, storage: persist.Lo
const {nso, data} = await getToken(storage, token, proxy_url);
const existingToken: SavedIksmSessionToken = await SplatNet2Api.loginWithZnc(nso, data.user);
const existingToken: SavedIksmSessionToken = await SplatNet2Api.loginWithCoral(nso, data.user);
await storage.setItem('IksmToken.' + token, existingToken);

View File

@ -1,7 +1,7 @@
import createDebug from 'debug';
import persist from 'node-persist';
import ZncApi from '../api/znc.js';
import { ActiveEvent, Announcements, CurrentUser, Friend, Game, Presence, PresenceState, WebServices, ZncErrorResponse } from '../api/znc-types.js';
import CoralApi from '../api/coral.js';
import { ActiveEvent, Announcements, CurrentUser, Friend, Game, Presence, PresenceState, WebServices, CoralErrorResponse } from '../api/coral-types.js';
import ZncProxyApi from '../api/znc-proxy.js';
import { ErrorResponse } from '../api/util.js';
import { SavedToken } from './auth/nso.js';
@ -25,7 +25,7 @@ export class ZncNotifications extends Loop {
constructor(
public storage: persist.LocalStorage,
public token: string,
public nso: ZncApi,
public nso: CoralApi,
public data: Omit<SavedToken, 'expires_at'>,
public user?: CoralUser,
) {
@ -178,7 +178,7 @@ export class ZncNotifications extends Loop {
if (user) await this.updatePresenceForSplatNet2Monitors([user]);
}
async handleError(err: ErrorResponse<ZncErrorResponse> | NodeJS.ErrnoException): Promise<LoopResult> {
async handleError(err: ErrorResponse<CoralErrorResponse> | NodeJS.ErrnoException): Promise<LoopResult> {
if ('code' in err && (err as any).type === 'system' && err.code === 'ETIMEDOUT') {
debug('Request timed out, waiting %ds before retrying', this.update_interval, err);

View File

@ -3,7 +3,7 @@ import { DiscordRpcClient, findDiscordRpcClient } from '../discord/rpc.js';
import { DiscordPresencePlayTime, DiscordPresenceContext, getDiscordPresence, getInactiveDiscordPresence, DiscordPresence } from '../discord/util.js';
import { EmbeddedSplatNet2Monitor, ZncNotifications } from './notify.js';
import { getPresenceFromUrl } from '../api/znc-proxy.js';
import { ActiveEvent, CurrentUser, Friend, Game, Presence, PresenceState, ZncErrorResponse } from '../api/znc-types.js';
import { ActiveEvent, CurrentUser, Friend, Game, Presence, PresenceState, CoralErrorResponse } from '../api/coral-types.js';
import { ErrorResponse } from '../api/util.js';
import Loop, { LoopResult } from '../util/loop.js';
import { getTitleIdFromEcUrl } from '../index.js';
@ -302,7 +302,7 @@ export class ZncDiscordPresence extends ZncNotifications {
if (user) await this.updatePresenceForSplatNet2Monitors([user]);
}
async handleError(err: ErrorResponse<ZncErrorResponse> | NodeJS.ErrnoException): Promise<LoopResult> {
async handleError(err: ErrorResponse<CoralErrorResponse> | NodeJS.ErrnoException): Promise<LoopResult> {
this.discord.onError(err);
return super.handleError(err);

View File

@ -1,8 +1,8 @@
import createDebug from 'debug';
import * as persist from 'node-persist';
import ZncApi from '../api/znc.js';
import CoralApi from '../api/coral.js';
import ZncProxyApi from '../api/znc-proxy.js';
import { Announcements, Friends, GetActiveEventResult, WebServices, ZncSuccessResponse } from '../api/znc-types.js';
import { Announcements, Friends, GetActiveEventResult, WebServices, CoralSuccessResponse } from '../api/coral-types.js';
import { getToken, SavedToken } from './auth/nso.js';
import { Jwt } from '../util/jwt.js';
import { NintendoAccountSessionTokenJwtPayload } from '../api/na.js';
@ -65,16 +65,16 @@ export default class Users<T extends UserData> {
}
}
export interface CoralUserData<T extends ZncApi = ZncApi> extends UserData {
export interface CoralUserData<T extends CoralApi = CoralApi> extends UserData {
nso: T;
data: SavedToken;
announcements: ZncSuccessResponse<Announcements>;
friends: ZncSuccessResponse<Friends>;
webservices: ZncSuccessResponse<WebServices>;
active_event: ZncSuccessResponse<GetActiveEventResult>;
announcements: CoralSuccessResponse<Announcements>;
friends: CoralSuccessResponse<Friends>;
webservices: CoralSuccessResponse<WebServices>;
active_event: CoralSuccessResponse<GetActiveEventResult>;
}
export class CoralUser<T extends ZncApi = ZncApi> implements CoralUserData<T> {
export class CoralUser<T extends CoralApi = CoralApi> implements CoralUserData<T> {
created_at = Date.now();
expires_at = Infinity;
@ -90,10 +90,10 @@ export class CoralUser<T extends ZncApi = ZncApi> implements CoralUserData<T> {
constructor(
public nso: T,
public data: SavedToken,
public announcements: ZncSuccessResponse<Announcements>,
public friends: ZncSuccessResponse<Friends>,
public webservices: ZncSuccessResponse<WebServices>,
public active_event: ZncSuccessResponse<GetActiveEventResult>,
public announcements: CoralSuccessResponse<Announcements>,
public friends: CoralSuccessResponse<Friends>,
public webservices: CoralSuccessResponse<WebServices>,
public active_event: CoralSuccessResponse<GetActiveEventResult>,
) {}
private async update(key: keyof CoralUser['updated'], callback: () => Promise<void>, ttl: number) {

View File

@ -28,6 +28,8 @@ https://ec.nintendo.com/apps/0100f8f0000a2000/GB?lang=en-GB
In this link, the title ID is `0100f8f0000a2000`.
The title ID of friends games can also be found using the Electron app, by pressing a friend's name.
### 2. Nintendo Switch Parental Controls title download notifications
The title ID of any applications you download are recorded in daily summaries in the Nintendo Switch Parental Controls app. The title doesn't need to be used and the download can be cancelled immediately - it only needs to be queued. This is recorded when queuing downloads of application titles and does not include addon content or update data titles, so the application must be archived or deleted for this to be recorded again.

View File

@ -1,5 +1,5 @@
import DiscordRPC from 'discord-rpc';
import { ActiveEvent, CurrentUser, Friend, Game, PresenceState } from '../api/znc-types.js';
import { ActiveEvent, CurrentUser, Friend, Game, PresenceState } from '../api/coral-types.js';
import { defaultTitle, titles } from './titles.js';
import { product } from '../util/product.js';
import { getTitleIdFromEcUrl, hrduration } from '../util/misc.js';

View File

@ -1,6 +1,9 @@
export { default as ZncApi } from './api/znc.js';
export { default as CoralApi } from './api/coral.js';
export { /** @deprecated */ default as ZncApi } from './api/coral.js';
export { default as ZncProxyApi } from './api/znc-proxy.js';
export * as znc from './api/znc-types.js';
export * as coral from './api/coral-types.js';
/** @deprecated */
export * as znc from './api/coral-types.js';
export { default as MoonApi } from './api/moon.js';
export * as moon from './api/moon-types.js';
export * as na from './api/na.js';