From 967a06322072c64db7bc3d8ead9a14ac7fa66221 Mon Sep 17 00:00:00 2001 From: Samuel Elliott Date: Sat, 21 May 2022 23:52:36 +0100 Subject: [PATCH] Move utility functions This avoids importing most dependencies when not used. --- package.json | 8 +- rollup.config.js | 4 +- src/api/f.ts | 2 +- src/api/na.ts | 2 +- src/api/znc-proxy.ts | 2 +- src/api/znc.ts | 2 +- src/app/README.md | 2 +- src/app/{ => main}/electron.ts | 0 src/app/main/index.ts | 6 +- src/app/main/menu.ts | 4 +- src/app/main/na-auth.ts | 4 +- src/app/main/webservices.ts | 4 +- src/app/main/windows.ts | 4 +- src/cli.ts | 4 +- src/cli/android-znca-api-server-frida.ts | 6 +- src/cli/app.ts | 2 +- src/cli/nooklink.ts | 2 +- src/cli/nooklink/dump-newspapers.ts | 3 +- src/cli/nooklink/island.ts | 3 +- src/cli/nooklink/keyboard.ts | 3 +- src/cli/nooklink/newspaper.ts | 3 +- src/cli/nooklink/newspapers.ts | 3 +- src/cli/nooklink/post-reaction.ts | 3 +- src/cli/nooklink/reactions.ts | 3 +- src/cli/nooklink/user.ts | 3 +- src/cli/nooklink/users.ts | 3 +- src/cli/nso.ts | 2 +- src/cli/nso/announcements.ts | 3 +- src/cli/nso/auth.ts | 3 +- src/cli/nso/friends.ts | 4 +- src/cli/nso/http-server.ts | 3 +- src/cli/nso/notify.ts | 3 +- src/cli/nso/permissions.ts | 3 +- src/cli/nso/presence.ts | 3 +- src/cli/nso/token.ts | 3 +- src/cli/nso/user.ts | 3 +- src/cli/nso/webservices.ts | 3 +- src/cli/nso/webservicetoken.ts | 3 +- src/cli/nso/znc-proxy-tokens.ts | 3 +- src/cli/pctl.ts | 2 +- src/cli/pctl/auth.ts | 3 +- src/cli/pctl/daily-summaries.ts | 4 +- src/cli/pctl/devices.ts | 3 +- src/cli/pctl/dump-summaries.ts | 3 +- src/cli/pctl/monthly-summaries.ts | 3 +- src/cli/pctl/monthly-summary.ts | 3 +- src/cli/pctl/settings.ts | 3 +- src/cli/pctl/token.ts | 3 +- src/cli/pctl/user.ts | 3 +- src/cli/splatnet2.ts | 2 +- src/cli/splatnet2/battles.ts | 3 +- src/cli/splatnet2/challenges.ts | 3 +- src/cli/splatnet2/dump-records.ts | 3 +- src/cli/splatnet2/dump-results.ts | 3 +- src/cli/splatnet2/hero.ts | 3 +- src/cli/splatnet2/monitor.ts | 3 +- src/cli/splatnet2/schedule.ts | 3 +- src/cli/splatnet2/stages.ts | 3 +- src/cli/splatnet2/user.ts | 3 +- src/cli/splatnet2/weapons.ts | 3 +- src/cli/update.ts | 3 +- src/cli/users.ts | 3 +- src/cli/util.ts | 3 +- src/cli/util/captureid.ts | 2 +- src/cli/util/discord-activity.ts | 3 +- src/cli/util/discord-rpc.ts | 2 +- src/cli/util/export-discord-titles.ts | 2 +- src/cli/util/validate-discord-titles.ts | 2 +- src/common/auth/moon.ts | 2 +- src/common/auth/nso.ts | 2 +- src/common/notify.ts | 3 +- src/common/presence.ts | 2 +- src/common/splatnet2/monitor.ts | 2 +- src/discord/util.ts | 3 +- src/index.ts | 2 +- src/util.ts | 313 ----------------------- src/util/jwt.ts | 152 +++++++++++ src/util/loop.ts | 66 +++++ src/util/misc.ts | 20 ++ src/util/product.ts | 34 +++ src/util/storage.ts | 17 ++ src/util/yargs.ts | 32 +++ 82 files changed, 458 insertions(+), 398 deletions(-) rename src/app/{ => main}/electron.ts (100%) delete mode 100644 src/util.ts create mode 100644 src/util/jwt.ts create mode 100644 src/util/loop.ts create mode 100644 src/util/misc.ts create mode 100644 src/util/product.ts create mode 100644 src/util/storage.ts create mode 100644 src/util/yargs.ts diff --git a/package.json b/package.json index afc39e2..61792fe 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,7 @@ "files": [ "dist", "!dist/app", - "!dist/app-main-bundle.cjs", - "!dist/cli-bundle.js", + "!dist/bundle", "bin", "resources" ], @@ -82,14 +81,13 @@ "npmRebuild": false, "files": [ "dist/app/bundle", - "dist/app-main-bundle.cjs", - "dist/cli-bundle.js", + "dist/bundle", "!dist/app/package", "resources" ], "asar": false, "extraMetadata": { - "main": "dist/app-main-bundle.cjs" + "main": "dist/bundle/app-main-bundle.cjs" }, "directories": { "output": "dist/app/package" diff --git a/rollup.config.js b/rollup.config.js index 34d4e8b..54e7f37 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -14,7 +14,7 @@ import json from '@rollup/plugin-json'; const cli = { input: 'src/cli-entry.ts', output: { - file: 'dist/cli-bundle.js', + file: 'dist/bundle/cli-bundle.js', format: 'es', inlineDynamicImports: true, }, @@ -48,7 +48,7 @@ const cli = { const app = { input: 'src/app/main/app-entry.cts', output: { - file: 'dist/app-main-bundle.cjs', + file: 'dist/bundle/app-main-bundle.cjs', format: 'cjs', inlineDynamicImports: true, }, diff --git a/src/api/f.ts b/src/api/f.ts index 91b2c63..b325114 100644 --- a/src/api/f.ts +++ b/src/api/f.ts @@ -1,7 +1,7 @@ import fetch from 'node-fetch'; import createDebug from 'debug'; import { ErrorResponse } from './util.js'; -import { version } from '../util.js'; +import { version } from '../util/product.js'; const debugS2s = createDebug('nxapi:api:s2s'); const debugFlapg = createDebug('nxapi:api:flapg'); diff --git a/src/api/na.ts b/src/api/na.ts index 5896f09..20eaede 100644 --- a/src/api/na.ts +++ b/src/api/na.ts @@ -1,7 +1,7 @@ import fetch from 'node-fetch'; import createDebug from 'debug'; import { ErrorResponse } from './util.js'; -import { JwtPayload } from '../util.js'; +import { JwtPayload } from '../util/jwt.js'; const debug = createDebug('nxapi:api:na'); diff --git a/src/api/znc-proxy.ts b/src/api/znc-proxy.ts index abddae9..aade54a 100644 --- a/src/api/znc-proxy.ts +++ b/src/api/znc-proxy.ts @@ -3,7 +3,7 @@ import createDebug from 'debug'; import { ActiveEvent, Announcements, CurrentUser, Event, Friend, Presence, PresencePermissions, User, WebService, WebServiceToken, ZncStatus, ZncSuccessResponse } from './znc-types.js'; import { ErrorResponse } from './util.js'; import ZncApi from './znc.js'; -import { version } from '../util.js'; +import { version } from '../util/product.js'; import { NintendoAccountUser } from './na.js'; import { SavedToken } from '../common/auth/nso.js'; diff --git a/src/api/znc.ts b/src/api/znc.ts index 3b8680e..46cf7c6 100644 --- a/src/api/znc.ts +++ b/src/api/znc.ts @@ -5,7 +5,7 @@ import { flapg, FlapgIid, genfc } from './f.js'; import { AccountLogin, AccountToken, Announcements, CurrentUser, CurrentUserPermissions, Event, Friends, GetActiveEventResult, PresencePermissions, User, WebServices, WebServiceToken, ZncResponse, ZncStatus } from './znc-types.js'; import { getNintendoAccountToken, getNintendoAccountUser, NintendoAccountUser } from './na.js'; import { ErrorResponse } from './util.js'; -import { JwtPayload } from '../util.js'; +import { JwtPayload } from '../util/jwt.js'; const debug = createDebug('nxapi:api:znc'); diff --git a/src/app/README.md b/src/app/README.md index 7b7e2ba..f7d6682 100644 --- a/src/app/README.md +++ b/src/app/README.md @@ -1,7 +1,7 @@ Electron app --- -The Electron app is bundled into ~4 files in `dist/app/bundle` using Rollup. The main process code is not bundled for development, but is when packaging the app at `dist/app-main-bundle.cjs` (with the command line executable at `dist/cli-bundle.js`). +The Electron app is bundled into ~4 files in `dist/app/bundle` using Rollup. The main process code is not bundled for development, but is when packaging the app at `dist/bundle/app-main-bundle.cjs` (with the command line executable at `dist/bundle/cli-bundle.js`). [electron.ts](electron.ts) exports all Electron APIs used in the main process. This is because the `electron` module doesn't actually exist - Electron patches the `require` function, but not the module importer. Additionally Electron does not support using a standard JavaScript module as the app entrypoint, so [main/app-entry.cts](main/app-entry.cts) is used to import the actual app entrypoint after the `ready` event. diff --git a/src/app/electron.ts b/src/app/main/electron.ts similarity index 100% rename from src/app/electron.ts rename to src/app/main/electron.ts diff --git a/src/app/main/index.ts b/src/app/main/index.ts index 7777246..685cdfd 100644 --- a/src/app/main/index.ts +++ b/src/app/main/index.ts @@ -1,4 +1,4 @@ -import { app, BrowserWindow, dialog, ipcMain, nativeImage, Notification } from '../electron.js'; +import { app, BrowserWindow, dialog, ipcMain, nativeImage, Notification } from './electron.js'; import * as path from 'path'; import { EventEmitter } from 'events'; import createDebug from 'debug'; @@ -6,7 +6,6 @@ import * as persist from 'node-persist'; import fetch from 'node-fetch'; import dotenv from 'dotenv'; import dotenvExpand from 'dotenv-expand'; -import { dir, initStorage, LoopResult, paths } from '../../util.js'; import MenuApp from './menu.js'; import { WebServiceIpc } from './webservices.js'; import { createWindow, getWindowConfiguration } from './windows.js'; @@ -16,6 +15,9 @@ import { ErrorResponse } from '../../api/util.js'; import { ZncDiscordPresence } from '../../common/presence.js'; import { NotificationManager } from '../../common/notify.js'; import { getToken } from '../../common/auth/nso.js'; +import { dir } from '../../util/product.js'; +import { initStorage, paths } from '../../util/storage.js'; +import { LoopResult } from '../../util/loop.js'; const debug = createDebug('app:main'); diff --git a/src/app/main/menu.ts b/src/app/main/menu.ts index be5c3c6..d1286eb 100644 --- a/src/app/main/menu.ts +++ b/src/app/main/menu.ts @@ -1,4 +1,4 @@ -import { app, dialog, Menu, Tray, nativeImage, MenuItem } from '../electron.js'; +import { app, dialog, Menu, Tray, nativeImage, MenuItem } from './electron.js'; import createDebug from 'debug'; import { addNsoAccount, addPctlAccount } from './na-auth.js'; import { PresenceMonitorManager, Store } from './index.js'; @@ -6,7 +6,7 @@ import { WebService } from '../../api/znc-types.js'; import openWebService from './webservices.js'; import { getToken, SavedToken } from '../../common/auth/nso.js'; import { SavedMoonToken } from '../../common/auth/moon.js'; -import { dev } from '../../util.js'; +import { dev } from '../../util/product.js'; const debug = createDebug('app:main:menu'); diff --git a/src/app/main/na-auth.ts b/src/app/main/na-auth.ts index 45974e5..2b93e72 100644 --- a/src/app/main/na-auth.ts +++ b/src/app/main/na-auth.ts @@ -2,13 +2,13 @@ import * as crypto from 'crypto'; import createDebug from 'debug'; import * as persist from 'node-persist'; import fetch from 'node-fetch'; -import { BrowserWindow, nativeImage, Notification, session, shell } from '../electron.js'; +import { BrowserWindow, nativeImage, Notification, session, shell } from './electron.js'; import { getNintendoAccountSessionToken, NintendoAccountSessionToken } from '../../api/na.js'; -import { Jwt } from '../../util.js'; import { ZNCA_CLIENT_ID } from '../../api/znc.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'; +import { Jwt } from '../../util/jwt.js'; const debug = createDebug('app:main:na-auth'); diff --git a/src/app/main/webservices.ts b/src/app/main/webservices.ts index 715d1ed..2b6bc4d 100644 --- a/src/app/main/webservices.ts +++ b/src/app/main/webservices.ts @@ -1,8 +1,8 @@ import * as path from 'path'; import createDebug from 'debug'; -import { BrowserWindow, IpcMainInvokeEvent, session, shell, WebContents } from '../electron.js'; +import { BrowserWindow, IpcMainInvokeEvent, session, shell, WebContents } from './electron.js'; import ZncApi from '../../api/znc.js'; -import { dev } from '../../util.js'; +import { dev } from '../../util/product.js'; import { WebService } from '../../api/znc-types.js'; import { bundlepath, Store } from './index.js'; import type { NativeShareRequest, NativeShareUrlRequest } from '../preload-webservice/znca-js-api.js'; diff --git a/src/app/main/windows.ts b/src/app/main/windows.ts index aa24df0..a32e06d 100644 --- a/src/app/main/windows.ts +++ b/src/app/main/windows.ts @@ -1,7 +1,7 @@ -import { app, BrowserWindow, dialog, ipcMain, nativeImage, Notification, WebContents } from '../electron.js'; +import { BrowserWindow, WebContents } from './electron.js'; import * as path from 'path'; import { bundlepath } from './index.js'; -import { dev } from '../../util.js'; +import { dev } from '../../util/product.js'; import { WindowConfiguration, WindowType } from '../common/types.js'; const windows = new Map(); diff --git a/src/cli.ts b/src/cli.ts index 79e0f7a..c802443 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -3,9 +3,11 @@ import createDebug from 'debug'; import Yargs from 'yargs'; import dotenv from 'dotenv'; import dotenvExpand from 'dotenv-expand'; -import { dev, paths, YargsArguments } from './util.js'; import * as commands from './cli/index.js'; import { checkUpdates } from './cli/update.js'; +import { dev } from './util/product.js'; +import { paths } from './util/storage.js'; +import { YargsArguments } from './util/yargs.js'; const debug = createDebug('cli'); diff --git a/src/cli/android-znca-api-server-frida.ts b/src/cli/android-znca-api-server-frida.ts index 811c62c..bc45919 100644 --- a/src/cli/android-znca-api-server-frida.ts +++ b/src/cli/android-znca-api-server-frida.ts @@ -6,10 +6,12 @@ import frida, { Session } from 'frida'; import express from 'express'; import bodyParser from 'body-parser'; import type { Arguments as ParentArguments } from '../cli.js'; -import { ArgumentsCamelCase, Argv, dir, getJwks, initStorage, YargsArguments } from '../util.js'; -import { Jwt } from '../util.js'; import { NintendoAccountIdTokenJwtPayload } from '../api/na.js'; import { ZNCA_CLIENT_ID, ZncJwtPayload } from '../api/znc.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../util/yargs.js'; +import { dir } from '../util/product.js'; +import { initStorage } from '../util/storage.js'; +import { getJwks, Jwt } from '../util/jwt.js'; const debug = createDebug('cli:android-znca-api-server-frida'); const debugApi = createDebug('cli:android-znca-api-server-frida:api'); diff --git a/src/cli/app.ts b/src/cli/app.ts index 4d57a37..2794662 100644 --- a/src/cli/app.ts +++ b/src/cli/app.ts @@ -2,7 +2,7 @@ import { createRequire } from 'module'; import { execFileSync } from 'child_process'; import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../cli.js'; -import { ArgumentsCamelCase, Argv, YargsArguments } from '../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../util/yargs.js'; const debug = createDebug('cli:app'); diff --git a/src/cli/nooklink.ts b/src/cli/nooklink.ts index 3ff2089..e29767b 100644 --- a/src/cli/nooklink.ts +++ b/src/cli/nooklink.ts @@ -1,6 +1,6 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../cli.js'; -import { Argv, YargsArguments } from '../util.js'; +import { Argv, YargsArguments } from '../util/yargs.js'; import * as commands from './nooklink/index.js'; const debug = createDebug('cli:nooklink'); diff --git a/src/cli/nooklink/dump-newspapers.ts b/src/cli/nooklink/dump-newspapers.ts index 9bdedc7..0137b37 100644 --- a/src/cli/nooklink/dump-newspapers.ts +++ b/src/cli/nooklink/dump-newspapers.ts @@ -3,7 +3,8 @@ import * as path from 'path'; import createDebug from 'debug'; import mkdirp from 'mkdirp'; import type { Arguments as ParentArguments } from '../nooklink.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getUserToken } from '../../common/auth/nooklink.js'; const debug = createDebug('cli:nooklink:dump-newspapers'); diff --git a/src/cli/nooklink/island.ts b/src/cli/nooklink/island.ts index 0299283..13458d1 100644 --- a/src/cli/nooklink/island.ts +++ b/src/cli/nooklink/island.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../nooklink.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getUserToken, getWebServiceToken } from '../../common/auth/nooklink.js'; const debug = createDebug('cli:nooklink:island'); diff --git a/src/cli/nooklink/keyboard.ts b/src/cli/nooklink/keyboard.ts index a1acd22..4b6ca39 100644 --- a/src/cli/nooklink/keyboard.ts +++ b/src/cli/nooklink/keyboard.ts @@ -1,7 +1,8 @@ import { promisify } from 'util'; import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../nooklink.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getUserToken } from '../../common/auth/nooklink.js'; const debug = createDebug('cli:nooklink:keyboard'); diff --git a/src/cli/nooklink/newspaper.ts b/src/cli/nooklink/newspaper.ts index 0aa662c..bd0b0f6 100644 --- a/src/cli/nooklink/newspaper.ts +++ b/src/cli/nooklink/newspaper.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../nooklink.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getUserToken } from '../../common/auth/nooklink.js'; const debug = createDebug('cli:nooklink:newspaper'); diff --git a/src/cli/nooklink/newspapers.ts b/src/cli/nooklink/newspapers.ts index 19bec0f..7086945 100644 --- a/src/cli/nooklink/newspapers.ts +++ b/src/cli/nooklink/newspapers.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../nooklink.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getUserToken } from '../../common/auth/nooklink.js'; const debug = createDebug('cli:nooklink:newspapers'); diff --git a/src/cli/nooklink/post-reaction.ts b/src/cli/nooklink/post-reaction.ts index 2ba69ca..25ab983 100644 --- a/src/cli/nooklink/post-reaction.ts +++ b/src/cli/nooklink/post-reaction.ts @@ -1,6 +1,7 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../nooklink.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getUserToken } from '../../common/auth/nooklink.js'; const debug = createDebug('cli:nooklink:post-reaction'); diff --git a/src/cli/nooklink/reactions.ts b/src/cli/nooklink/reactions.ts index a778a56..bdd8b80 100644 --- a/src/cli/nooklink/reactions.ts +++ b/src/cli/nooklink/reactions.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../nooklink.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getUserToken } from '../../common/auth/nooklink.js'; const debug = createDebug('cli:nooklink:reactions'); diff --git a/src/cli/nooklink/user.ts b/src/cli/nooklink/user.ts index 5292529..85d4f7b 100644 --- a/src/cli/nooklink/user.ts +++ b/src/cli/nooklink/user.ts @@ -1,6 +1,7 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../nooklink.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getUserToken } from '../../common/auth/nooklink.js'; const debug = createDebug('cli:nooklink:user'); diff --git a/src/cli/nooklink/users.ts b/src/cli/nooklink/users.ts index 17a5acf..e5e1fad 100644 --- a/src/cli/nooklink/users.ts +++ b/src/cli/nooklink/users.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../nooklink.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getWebServiceToken } from '../../common/auth/nooklink.js'; const debug = createDebug('cli:nooklink:users'); diff --git a/src/cli/nso.ts b/src/cli/nso.ts index 5cdedfc..4e71122 100644 --- a/src/cli/nso.ts +++ b/src/cli/nso.ts @@ -1,6 +1,6 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../cli.js'; -import { Argv, YargsArguments } from '../util.js'; +import { Argv, YargsArguments } from '../util/yargs.js'; import * as commands from './nso/index.js'; const debug = createDebug('cli:nso'); diff --git a/src/cli/nso/announcements.ts b/src/cli/nso/announcements.ts index 4aaeccd..c5b346f 100644 --- a/src/cli/nso/announcements.ts +++ b/src/cli/nso/announcements.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../nso.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getToken } from '../../common/auth/nso.js'; const debug = createDebug('cli:nso:announcements'); diff --git a/src/cli/nso/auth.ts b/src/cli/nso/auth.ts index 0b2a7e5..9739c3d 100644 --- a/src/cli/nso/auth.ts +++ b/src/cli/nso/auth.ts @@ -2,7 +2,8 @@ import * as util from 'util'; import createDebug from 'debug'; import * as crypto from 'crypto'; import type { Arguments as ParentArguments } from '../nso.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +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'; diff --git a/src/cli/nso/friends.ts b/src/cli/nso/friends.ts index 78909fc..6fcc27e 100644 --- a/src/cli/nso/friends.ts +++ b/src/cli/nso/friends.ts @@ -2,7 +2,9 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import { PresenceState } from '../../api/znc-types.js'; import type { Arguments as ParentArguments } from '../nso.js'; -import { ArgumentsCamelCase, Argv, hrduration, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; +import { hrduration } from '../../util/misc.js'; import { getToken } from '../../common/auth/nso.js'; const debug = createDebug('cli:nso:friends'); diff --git a/src/cli/nso/http-server.ts b/src/cli/nso/http-server.ts index 35c4b8c..db76728 100644 --- a/src/cli/nso/http-server.ts +++ b/src/cli/nso/http-server.ts @@ -6,7 +6,8 @@ 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 type { Arguments as ParentArguments } from '../nso.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getToken, SavedToken } from '../../common/auth/nso.js'; import { NotificationManager, ZncNotifications } from '../../common/notify.js'; diff --git a/src/cli/nso/notify.ts b/src/cli/nso/notify.ts index e073de1..96e4070 100644 --- a/src/cli/nso/notify.ts +++ b/src/cli/nso/notify.ts @@ -3,7 +3,8 @@ import createDebug from 'debug'; import persist from 'node-persist'; import notifier from 'node-notifier'; import type { Arguments as ParentArguments } from '../nso.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +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'; diff --git a/src/cli/nso/permissions.ts b/src/cli/nso/permissions.ts index 5eecefc..c55a8cb 100644 --- a/src/cli/nso/permissions.ts +++ b/src/cli/nso/permissions.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import { PresencePermissions } from '../../api/znc-types.js'; import type { Arguments as ParentArguments } from '../nso.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getToken } from '../../common/auth/nso.js'; const debug = createDebug('cli:nso:permissions'); diff --git a/src/cli/nso/presence.ts b/src/cli/nso/presence.ts index d2536b3..b5ed9c9 100644 --- a/src/cli/nso/presence.ts +++ b/src/cli/nso/presence.ts @@ -1,6 +1,7 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../nso.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getToken } from '../../common/auth/nso.js'; import { DiscordPresencePlayTime } from '../../discord/util.js'; import { handleEnableSplatNet2Monitoring } from './notify.js'; diff --git a/src/cli/nso/token.ts b/src/cli/nso/token.ts index 4b7289a..a0a8817 100644 --- a/src/cli/nso/token.ts +++ b/src/cli/nso/token.ts @@ -1,7 +1,8 @@ import * as util from 'util'; import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../nso.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getToken } from '../../common/auth/nso.js'; const debug = createDebug('cli:nso:token'); diff --git a/src/cli/nso/user.ts b/src/cli/nso/user.ts index a9f526a..e538bd1 100644 --- a/src/cli/nso/user.ts +++ b/src/cli/nso/user.ts @@ -1,6 +1,7 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../nso.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getToken } from '../../common/auth/nso.js'; const debug = createDebug('cli:nso:user'); diff --git a/src/cli/nso/webservices.ts b/src/cli/nso/webservices.ts index 18c0171..91691bb 100644 --- a/src/cli/nso/webservices.ts +++ b/src/cli/nso/webservices.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../nso.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getToken } from '../../common/auth/nso.js'; const debug = createDebug('cli:nso:webservices'); diff --git a/src/cli/nso/webservicetoken.ts b/src/cli/nso/webservicetoken.ts index 7047a86..5c18382 100644 --- a/src/cli/nso/webservicetoken.ts +++ b/src/cli/nso/webservicetoken.ts @@ -1,6 +1,7 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../nso.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getToken } from '../../common/auth/nso.js'; const debug = createDebug('cli:nso:webservicetoken'); diff --git a/src/cli/nso/znc-proxy-tokens.ts b/src/cli/nso/znc-proxy-tokens.ts index 301f05f..1d03f26 100644 --- a/src/cli/nso/znc-proxy-tokens.ts +++ b/src/cli/nso/znc-proxy-tokens.ts @@ -2,9 +2,10 @@ import createDebug from 'debug'; import fetch from 'node-fetch'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../nso.js'; -import { Argv, initStorage } from '../../util.js'; import { getToken } from '../../common/auth/nso.js'; import { AuthPolicy, AuthToken } from './http-server.js'; +import { Argv } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; const debug = createDebug('cli:nso:znc-proxy-tokens'); diff --git a/src/cli/pctl.ts b/src/cli/pctl.ts index e842ba8..32cec16 100644 --- a/src/cli/pctl.ts +++ b/src/cli/pctl.ts @@ -1,6 +1,6 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../cli.js'; -import { Argv, YargsArguments } from '../util.js'; +import { Argv, YargsArguments } from '../util/yargs.js'; import * as commands from './pctl/index.js'; const debug = createDebug('cli:pctl'); diff --git a/src/cli/pctl/auth.ts b/src/cli/pctl/auth.ts index ae36bd2..80926ff 100644 --- a/src/cli/pctl/auth.ts +++ b/src/cli/pctl/auth.ts @@ -2,7 +2,8 @@ import * as util from 'util'; import * as crypto from 'crypto'; import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../pctl.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getPctlToken } from '../../common/auth/moon.js'; import { getNintendoAccountSessionToken } from '../../api/na.js'; import { ZNMA_CLIENT_ID } from '../../api/moon.js'; diff --git a/src/cli/pctl/daily-summaries.ts b/src/cli/pctl/daily-summaries.ts index b4702f2..baf8492 100644 --- a/src/cli/pctl/daily-summaries.ts +++ b/src/cli/pctl/daily-summaries.ts @@ -1,7 +1,9 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../pctl.js'; -import { ArgumentsCamelCase, Argv, hrduration, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; +import { hrduration } from '../../util/misc.js'; import { getPctlToken } from '../../common/auth/moon.js'; const debug = createDebug('cli:pctl:daily-summaries'); diff --git a/src/cli/pctl/devices.ts b/src/cli/pctl/devices.ts index 7b9ac10..42e48ec 100644 --- a/src/cli/pctl/devices.ts +++ b/src/cli/pctl/devices.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../pctl.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getPctlToken } from '../../common/auth/moon.js'; const debug = createDebug('cli:pctl:devices'); diff --git a/src/cli/pctl/dump-summaries.ts b/src/cli/pctl/dump-summaries.ts index ec0e95d..575f6e1 100644 --- a/src/cli/pctl/dump-summaries.ts +++ b/src/cli/pctl/dump-summaries.ts @@ -3,7 +3,8 @@ import * as fs from 'fs/promises'; import createDebug from 'debug'; import mkdirp from 'mkdirp'; import type { Arguments as ParentArguments } from '../pctl.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getPctlToken } from '../../common/auth/moon.js'; import { DailySummaryResult } from '../../api/moon-types.js'; import MoonApi from '../../api/moon.js'; diff --git a/src/cli/pctl/monthly-summaries.ts b/src/cli/pctl/monthly-summaries.ts index 88e415d..c8f39f1 100644 --- a/src/cli/pctl/monthly-summaries.ts +++ b/src/cli/pctl/monthly-summaries.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../pctl.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getPctlToken } from '../../common/auth/moon.js'; const debug = createDebug('cli:pctl:monthly-summaries'); diff --git a/src/cli/pctl/monthly-summary.ts b/src/cli/pctl/monthly-summary.ts index f1368bd..0b74ba0 100644 --- a/src/cli/pctl/monthly-summary.ts +++ b/src/cli/pctl/monthly-summary.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../pctl.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getPctlToken } from '../../common/auth/moon.js'; const debug = createDebug('cli:pctl:monthly-summary'); diff --git a/src/cli/pctl/settings.ts b/src/cli/pctl/settings.ts index 66bbb3f..92e9959 100644 --- a/src/cli/pctl/settings.ts +++ b/src/cli/pctl/settings.ts @@ -1,6 +1,7 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../pctl.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getPctlToken } from '../../common/auth/moon.js'; const debug = createDebug('cli:pctl:settings'); diff --git a/src/cli/pctl/token.ts b/src/cli/pctl/token.ts index c0ccff7..3b2d3f6 100644 --- a/src/cli/pctl/token.ts +++ b/src/cli/pctl/token.ts @@ -1,7 +1,8 @@ import * as util from 'util'; import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../pctl.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getPctlToken } from '../../common/auth/moon.js'; const debug = createDebug('cli:pctl:token'); diff --git a/src/cli/pctl/user.ts b/src/cli/pctl/user.ts index e79d955..3be9b40 100644 --- a/src/cli/pctl/user.ts +++ b/src/cli/pctl/user.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../pctl.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; import { getPctlToken } from '../../common/auth/moon.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; const debug = createDebug('cli:pctl:user'); diff --git a/src/cli/splatnet2.ts b/src/cli/splatnet2.ts index 683671e..cdde75e 100644 --- a/src/cli/splatnet2.ts +++ b/src/cli/splatnet2.ts @@ -1,6 +1,6 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../cli.js'; -import { Argv, YargsArguments } from '../util.js'; +import { Argv, YargsArguments } from '../util/yargs.js'; import * as commands from './splatnet2/index.js'; const debug = createDebug('cli:splatnet2'); diff --git a/src/cli/splatnet2/battles.ts b/src/cli/splatnet2/battles.ts index 9016d8c..08fef7e 100644 --- a/src/cli/splatnet2/battles.ts +++ b/src/cli/splatnet2/battles.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../splatnet2.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getIksmToken } from '../../common/auth/splatnet2.js'; const debug = createDebug('cli:splatnet2:battles'); diff --git a/src/cli/splatnet2/challenges.ts b/src/cli/splatnet2/challenges.ts index 1466c17..4372570 100644 --- a/src/cli/splatnet2/challenges.ts +++ b/src/cli/splatnet2/challenges.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../splatnet2.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getIksmToken } from '../../common/auth/splatnet2.js'; const debug = createDebug('cli:splatnet2:challenges'); diff --git a/src/cli/splatnet2/dump-records.ts b/src/cli/splatnet2/dump-records.ts index 3547c21..64a9ba5 100644 --- a/src/cli/splatnet2/dump-records.ts +++ b/src/cli/splatnet2/dump-records.ts @@ -3,7 +3,8 @@ import * as fs from 'fs/promises'; import createDebug from 'debug'; import mkdirp from 'mkdirp'; import type { Arguments as ParentArguments } from '../splatnet2.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getIksmToken } from '../../common/auth/splatnet2.js'; import { dumpChallenges, dumpHeroRecords, dumpProfileImage, dumpRecords } from '../../common/splatnet2/dump-records.js'; diff --git a/src/cli/splatnet2/dump-results.ts b/src/cli/splatnet2/dump-results.ts index b16425f..09018ce 100644 --- a/src/cli/splatnet2/dump-results.ts +++ b/src/cli/splatnet2/dump-results.ts @@ -2,7 +2,8 @@ import * as path from 'path'; import createDebug from 'debug'; import mkdirp from 'mkdirp'; import type { Arguments as ParentArguments } from '../splatnet2.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getIksmToken } from '../../common/auth/splatnet2.js'; import { dumpCoopResults, dumpResults } from '../../common/splatnet2/dump-results.js'; diff --git a/src/cli/splatnet2/hero.ts b/src/cli/splatnet2/hero.ts index 0382776..164db7d 100644 --- a/src/cli/splatnet2/hero.ts +++ b/src/cli/splatnet2/hero.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../splatnet2.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getIksmToken } from '../../common/auth/splatnet2.js'; const debug = createDebug('cli:splatnet2:hero'); diff --git a/src/cli/splatnet2/monitor.ts b/src/cli/splatnet2/monitor.ts index 697e1ca..42afafa 100644 --- a/src/cli/splatnet2/monitor.ts +++ b/src/cli/splatnet2/monitor.ts @@ -1,7 +1,8 @@ import * as path from 'path'; import createDebug from 'debug'; import { getIksmToken } from '../../common/auth/splatnet2.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { Arguments as ParentArguments } from '../splatnet2.js'; import { SplatNet2RecordsMonitor } from '../../common/splatnet2/monitor.js'; diff --git a/src/cli/splatnet2/schedule.ts b/src/cli/splatnet2/schedule.ts index 2d0e11c..5913dde 100644 --- a/src/cli/splatnet2/schedule.ts +++ b/src/cli/splatnet2/schedule.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../splatnet2.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getIksmToken } from '../../common/auth/splatnet2.js'; const debug = createDebug('cli:splatnet2:schedule'); diff --git a/src/cli/splatnet2/stages.ts b/src/cli/splatnet2/stages.ts index 4684c54..f07bccb 100644 --- a/src/cli/splatnet2/stages.ts +++ b/src/cli/splatnet2/stages.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../splatnet2.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getIksmToken } from '../../common/auth/splatnet2.js'; const debug = createDebug('cli:splatnet2:stages'); diff --git a/src/cli/splatnet2/user.ts b/src/cli/splatnet2/user.ts index bc3fdad..d413195 100644 --- a/src/cli/splatnet2/user.ts +++ b/src/cli/splatnet2/user.ts @@ -1,6 +1,7 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../splatnet2.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getIksmToken } from '../../common/auth/splatnet2.js'; const debug = createDebug('cli:splatnet2:user'); diff --git a/src/cli/splatnet2/weapons.ts b/src/cli/splatnet2/weapons.ts index a114732..1e12eda 100644 --- a/src/cli/splatnet2/weapons.ts +++ b/src/cli/splatnet2/weapons.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from '../util/table.js'; import type { Arguments as ParentArguments } from '../splatnet2.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getIksmToken } from '../../common/auth/splatnet2.js'; const debug = createDebug('cli:splatnet2:weapons'); diff --git a/src/cli/update.ts b/src/cli/update.ts index c9cfa12..16aaa87 100644 --- a/src/cli/update.ts +++ b/src/cli/update.ts @@ -3,7 +3,8 @@ import * as fs from 'fs/promises'; import fetch from 'node-fetch'; import createDebug from 'debug'; import mkdirp from 'mkdirp'; -import { dir, paths, version } from '../util.js'; +import { dir, version } from '../util/product.js'; +import { paths } from '../util/storage.js'; const debug = createDebug('cli:update'); diff --git a/src/cli/users.ts b/src/cli/users.ts index 3989a56..7f3d729 100644 --- a/src/cli/users.ts +++ b/src/cli/users.ts @@ -1,7 +1,8 @@ import createDebug from 'debug'; import Table from './util/table.js'; import type { Arguments as ParentArguments } from '../cli.js'; -import { Argv, initStorage } from '../util.js'; +import { Argv } from '../util/yargs.js'; +import { initStorage } from '../util/storage.js'; import { SavedToken } from '../common/auth/nso.js'; import { SavedMoonToken } from '../common/auth/moon.js'; diff --git a/src/cli/util.ts b/src/cli/util.ts index 486dc01..538d8be 100644 --- a/src/cli/util.ts +++ b/src/cli/util.ts @@ -1,6 +1,7 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../cli.js'; -import { Argv, dev, YargsArguments } from '../util.js'; +import { Argv, YargsArguments } from '../util/yargs.js'; +import { dev } from '../util/product.js'; import * as commands from './util/index.js'; const debug = createDebug('cli:util'); diff --git a/src/cli/util/captureid.ts b/src/cli/util/captureid.ts index 0d4e06c..f203bc9 100644 --- a/src/cli/util/captureid.ts +++ b/src/cli/util/captureid.ts @@ -2,7 +2,7 @@ import * as crypto from 'crypto'; import { Buffer } from 'buffer'; import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../util.js'; -import { Argv } from '../../util.js'; +import { Argv } from '../../util/yargs.js'; const debug = createDebug('cli:util:captureid'); diff --git a/src/cli/util/discord-activity.ts b/src/cli/util/discord-activity.ts index 8148c9f..c3c073f 100644 --- a/src/cli/util/discord-activity.ts +++ b/src/cli/util/discord-activity.ts @@ -4,7 +4,8 @@ import { getPresenceFromUrl } from '../../api/znc-proxy.js'; import { ActiveEvent, CurrentUser, Friend, Game, Presence, PresenceState } from '../../api/znc-types.js'; import type { Arguments as ParentArguments } from '../util.js'; import { DiscordPresenceContext, DiscordPresencePlayTime, getDiscordPresence, getInactiveDiscordPresence } from '../../discord/util.js'; -import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; +import { initStorage } from '../../util/storage.js'; import { getToken } from '../../common/auth/nso.js'; const debug = createDebug('cli:util:discord-activity'); diff --git a/src/cli/util/discord-rpc.ts b/src/cli/util/discord-rpc.ts index 79f3b7a..4995251 100644 --- a/src/cli/util/discord-rpc.ts +++ b/src/cli/util/discord-rpc.ts @@ -2,7 +2,7 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../util.js'; import { DiscordRpcClient, getAllIpcSockets } from '../../discord/rpc.js'; import { defaultTitle } from '../../discord/titles.js'; -import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; const debug = createDebug('cli:util:discord-rpc'); debug.enabled = true; diff --git a/src/cli/util/export-discord-titles.ts b/src/cli/util/export-discord-titles.ts index 3760bdb..a34acbf 100644 --- a/src/cli/util/export-discord-titles.ts +++ b/src/cli/util/export-discord-titles.ts @@ -1,7 +1,7 @@ import createDebug from 'debug'; import fetch from 'node-fetch'; import type { Arguments as ParentArguments } from '../util.js'; -import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util.js'; +import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; import { titles as unsorted_titles } from '../../discord/titles.js'; import { DiscordApplicationRpc, getDiscordApplicationRpc } from './discord-activity.js'; import { Title } from '../../discord/util.js'; diff --git a/src/cli/util/validate-discord-titles.ts b/src/cli/util/validate-discord-titles.ts index b58ca21..dd84177 100644 --- a/src/cli/util/validate-discord-titles.ts +++ b/src/cli/util/validate-discord-titles.ts @@ -1,6 +1,6 @@ import createDebug from 'debug'; import type { Arguments as ParentArguments } from '../util.js'; -import { ArgumentsCamelCase } from '../../util.js'; +import { ArgumentsCamelCase } from '../../util/yargs.js'; import * as publishers from '../../discord/titles/index.js'; const debug = createDebug('cli:util:validate-discord-titles'); diff --git a/src/common/auth/moon.ts b/src/common/auth/moon.ts index d1104dd..5c3810a 100644 --- a/src/common/auth/moon.ts +++ b/src/common/auth/moon.ts @@ -2,7 +2,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 { Jwt } from '../../util.js'; +import { Jwt } from '../../util/jwt.js'; import MoonApi from '../../api/moon.js'; const debug = createDebug('nxapi:auth:moon'); diff --git a/src/common/auth/nso.ts b/src/common/auth/nso.ts index f552890..b159ef9 100644 --- a/src/common/auth/nso.ts +++ b/src/common/auth/nso.ts @@ -2,7 +2,7 @@ import createDebug from 'debug'; import * as persist from 'node-persist'; import { FlapgApiResponse } from '../../api/f.js'; import { NintendoAccountSessionTokenJwtPayload, NintendoAccountToken, NintendoAccountUser } from '../../api/na.js'; -import { Jwt } from '../../util.js'; +import { Jwt } from '../../util/jwt.js'; import { AccountLogin } from '../../api/znc-types.js'; import ZncApi, { ZNCA_CLIENT_ID } from '../../api/znc.js'; import ZncProxyApi from '../../api/znc-proxy.js'; diff --git a/src/common/notify.ts b/src/common/notify.ts index 413fea5..5e39521 100644 --- a/src/common/notify.ts +++ b/src/common/notify.ts @@ -1,12 +1,13 @@ import createDebug from 'debug'; import persist from 'node-persist'; -import { getTitleIdFromEcUrl, hrduration, Loop, LoopResult } from '../util.js'; import ZncApi from '../api/znc.js'; import { ActiveEvent, Announcements, CurrentUser, Friend, Game, Presence, PresenceState, WebServices, ZncErrorResponse } from '../api/znc-types.js'; import ZncProxyApi from '../api/znc-proxy.js'; import { ErrorResponse } from '../api/util.js'; import { SavedToken } from './auth/nso.js'; import { SplatNet2RecordsMonitor } from './splatnet2/monitor.js'; +import Loop, { LoopResult } from '../util/loop.js'; +import { getTitleIdFromEcUrl, hrduration } from '../util/misc.js'; const debug = createDebug('nxapi:nso:notify'); const debugFriends = createDebug('nxapi:nso:notify:friends'); diff --git a/src/common/presence.ts b/src/common/presence.ts index a624e57..58b62e4 100644 --- a/src/common/presence.ts +++ b/src/common/presence.ts @@ -2,10 +2,10 @@ import createDebug from 'debug'; import { DiscordRpcClient, findDiscordRpcClient } from '../discord/rpc.js'; import { DiscordPresencePlayTime, DiscordPresenceContext, getDiscordPresence, getInactiveDiscordPresence } from '../discord/util.js'; import { ZncNotifications } from './notify.js'; -import { LoopResult } from '../util.js'; import { getPresenceFromUrl } from '../api/znc-proxy.js'; import { ActiveEvent, CurrentUser, Friend, Presence, PresenceState, ZncErrorResponse } from '../api/znc-types.js'; import { ErrorResponse } from '../api/util.js'; +import { LoopResult } from '../util/loop.js'; const debug = createDebug('nxapi:nso:presence'); const debugProxy = createDebug('nxapi:nso:presence:proxy'); diff --git a/src/common/splatnet2/monitor.ts b/src/common/splatnet2/monitor.ts index 6861eb0..d5e6cd8 100644 --- a/src/common/splatnet2/monitor.ts +++ b/src/common/splatnet2/monitor.ts @@ -5,11 +5,11 @@ import persist from 'node-persist'; import mkdirp from 'mkdirp'; import SplatNet2Api from '../../api/splatnet2.js'; import { renewIksmToken } from '../auth/splatnet2.js'; -import { Loop, LoopResult } from '../../util.js'; import { Records, Stages, WebServiceError } from '../../api/splatnet2-types.js'; import { dumpCoopResults, dumpResults } from './dump-results.js'; import { dumpProfileImage, dumpRecords } from './dump-records.js'; import { ErrorResponse } from '../../api/util.js'; +import Loop, { LoopResult } from '../../util/loop.js'; const debug = createDebug('nxapi:splatnet2:monitor'); diff --git a/src/discord/util.ts b/src/discord/util.ts index 954b53d..710b6b3 100644 --- a/src/discord/util.ts +++ b/src/discord/util.ts @@ -1,7 +1,8 @@ import DiscordRPC from 'discord-rpc'; import { ActiveEvent, CurrentUser, Friend, Game, PresenceState } from '../api/znc-types.js'; import { defaultTitle, titles } from './titles.js'; -import { dev, getTitleIdFromEcUrl, git, hrduration, version } from '../util.js'; +import { dev, git, version } from '../util/product.js'; +import { getTitleIdFromEcUrl, hrduration } from '../util/misc.js'; import { ZncDiscordPresence } from '../common/presence.js'; const product = 'nxapi ' + version + diff --git a/src/index.ts b/src/index.ts index 21a925e..0b9ff0c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,5 +21,5 @@ export { } from './api/nooklink.js'; export * as nooklink from './api/nooklink-types.js'; -export { getTitleIdFromEcUrl } from './util.js'; +export { getTitleIdFromEcUrl } from './util/misc.js'; export { ErrorResponse } from './api/util.js'; diff --git a/src/util.ts b/src/util.ts deleted file mode 100644 index 1c1ce33..0000000 --- a/src/util.ts +++ /dev/null @@ -1,313 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs'; -import * as child_process from 'child_process'; -import * as crypto from 'crypto'; -import * as yargs from 'yargs'; -import createDebug from 'debug'; -import persist from 'node-persist'; -import getPaths from 'env-paths'; -import fetch from 'node-fetch'; - -const debug = createDebug('nxapi:util'); - -export const paths = getPaths('nxapi'); - -// -// Package/version info -// - -export const dir = path.resolve(decodeURI(import.meta.url.substr(process.platform === 'win32' ? 8 : 7)), '..', '..'); -export const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf-8')); -export const version = pkg.version; -export const git = (() => { - try { - fs.statSync(path.join(dir, '.git')); - } catch (err) { - return null; - } - - const options: child_process.ExecSyncOptions = {cwd: dir}; - const revision = child_process.execSync('git rev-parse HEAD', options).toString().trim(); - const branch = child_process.execSync('git rev-parse --abbrev-ref HEAD', options).toString().trim(); - const changed_files = child_process.execSync('git diff --name-only HEAD', options).toString().trim(); - - return { - revision, - branch: branch && branch !== 'HEAD' ? branch : null, - changed_files: changed_files.length ? changed_files.split('\n') : [], - }; -})(); -export const dev = !!git || process.env.NODE_ENV === 'development'; - -// -// Yargs types -// - -export type YargsArguments = T extends yargs.Argv ? R : any; -export type Argv = yargs.Argv; -// export type ArgumentsCamelCase = yargstypes.ArgumentsCamelCase; - -/** Convert literal string types like 'foo-bar' to 'FooBar' */ -type PascalCase = string extends S ? - string : S extends `${infer T}-${infer U}` ? - `${Capitalize}${PascalCase}` : Capitalize; - -/** Convert literal string types like 'foo-bar' to 'fooBar' */ -type CamelCase = string extends S ? - string : S extends `${infer T}-${infer U}` ? - `${T}${PascalCase}` : S; - -/** Convert literal string types like 'foo-bar' to 'fooBar', allowing all `PropertyKey` types */ -type CamelCaseKey = K extends string ? Exclude, ''> : K; - -/** Arguments type, with camelcased keys */ -export type ArgumentsCamelCase = { [key in keyof T as key | CamelCaseKey]: T[key] } & { - /** Non-option arguments */ - _: Array; - /** The script name or node command */ - $0: string; - /** All remaining options */ - [argName: string]: unknown; -}; - -// -// Other -// - -export async function initStorage(dir: string) { - const storage = persist.create({ - dir: path.join(dir, 'persist'), - stringify: data => JSON.stringify(data, null, 4) + '\n', - }); - await storage.init(); - return storage; -} - -export function getTitleIdFromEcUrl(url: string) { - const match = url.match(/^https:\/\/ec\.nintendo\.com\/apps\/([0-9a-f]{16})\//); - return match?.[1] ?? null; -} - -export function hrduration(duration: number, short = false) { - const hours = Math.floor(duration / 60); - const minutes = duration - (hours * 60); - - const hour_str = short ? 'hr' : 'hour'; - const minute_str = short ? 'min' : 'minute'; - - if (hours >= 1) { - return hours + ' ' + hour_str + (hours === 1 ? '' : 's') + - (minutes ? ', ' + minutes + ' ' + minute_str + (minutes === 1 ? '' : 's') : ''); - } else { - return minutes + ' ' + minute_str + (minutes === 1 ? '' : 's'); - } -} - -export abstract class Loop { - update_interval = 60; - - init(): void | Promise {} - - abstract update(): void | Promise; - - protected async loopRun(init = false): Promise { - try { - const result = init ? await this.init() : await this.update(); - - return result ?? (init ? LoopResult.OK_SKIP_INTERVAL : LoopResult.OK); - } catch (err) { - return this.handleError(err as any); - } - } - - async handleError(err: Error): Promise { - throw err; - } - - private is_loop_active = 0; - - async loop(init = false) { - try { - this.is_loop_active++; - - const result = await this.loopRun(init); - - if (result === LoopResult.OK) { - if (this.skip_interval_once) { - this.skip_interval_once = false; - } else { - await new Promise(rs => setTimeout(this.timeout_resolve = rs, this.update_interval * 1000)); - } - } - } finally { - this.is_loop_active--; - this.skip_interval_once = false; - this.timeout_resolve = null; - } - } - - private skip_interval_once = false; - private timeout_resolve: ((value: void) => void) | null = null; - - skipIntervalInCurrentLoop() { - debug('Skip update interval', this.is_loop_active); - if (!this.is_loop_active) return; - - this.skip_interval_once = true; - this.timeout_resolve?.call(null); - } -} - -const LoopRunOk = Symbol('LoopRunOk'); -const LoopRunOkSkipInterval = Symbol('LoopRunOkSkipInterval'); - -export enum LoopResult { - OK = LoopRunOk as any, - OK_SKIP_INTERVAL = LoopRunOkSkipInterval as any, -} - -// -// JSON Web Tokens -// - -export interface JwtHeader { - typ?: 'JWT'; - alg: JwtAlgorithm; - /** Key ID */ - kid?: string; - /** JSON Web Key Set URL */ - jku?: string; -} -export enum JwtAlgorithm { - RS256 = 'RS256', -} - -export interface JwtPayload { - /** Audience */ - aud: string; - /** Expiration timestamp (seconds) */ - exp: number; - /** Issue timestamp (seconds) */ - iat: number; - /** Issuer */ - iss: string; - /** Token ID */ - jti: string; - /** Subject */ - sub: string | number; - /** Token type */ - typ: string; -} - -type JwtVerifier = (data: Buffer, signature: Buffer, key: string) => boolean; - -export class Jwt { - constructor( - readonly header: H, - readonly payload: T - ) {} - - static decode(token: string) { - const [header_str, payload_str, signature_str] = token.split('.', 3); - - const header = JSON.parse(Buffer.from(header_str, 'base64url').toString()); - const payload = JSON.parse(Buffer.from(payload_str, 'base64url').toString()); - const signature = Buffer.from(signature_str, 'base64url'); - - if ('typ' in header && header.typ !== 'JWT') { - throw new Error('Invalid JWT'); - } - - const jwt = new this(header, payload); - return [jwt, signature] as const; - } - - verify(signature: Buffer, key: string, verifier?: JwtVerifier) { - const header_str = Buffer.from(JSON.stringify(this.header)).toString('base64url'); - const payload_str = Buffer.from(JSON.stringify(this.payload)).toString('base64url'); - const sign_data = header_str + '.' + payload_str; - - if (!verifier) { - if (!(this.header.alg in Jwt.verifiers) || !Jwt.verifiers[this.header.alg]) { - throw new Error('Unknown algorithm'); - } - - verifier = Jwt.verifiers[this.header.alg]; - } - - return verifier.call(null, Buffer.from(sign_data), signature, key); - } - - static verifiers: Record = { - [JwtAlgorithm.RS256]: (data, signature, key) => { - const verify = crypto.createVerify('RSA-SHA256'); - verify.end(data); - return verify.verify(key, signature); - }, - }; -} - -// -// JSON Web Key Sets -// -// Used for verifying JSON Web Tokens -// - -export interface Jwks { - keys: Jwk[]; -} -export interface Jwk { - /** Key type */ - kty: string; - use?: JwkUse | string; - key_ops?: JwkKeyOperation | string; - alg?: JwtAlgorithm | string; - /** Key ID */ - kid?: string; - x5u?: string[]; - x5c?: string[]; - x5t?: string; - 'x5t#S256'?: string; -} -export enum JwkUse { - SIGNATURE = 'sig', - ENCRYPTION = 'enc', -} -export enum JwkKeyOperation { - SIGN = 'sign', - VERIFY = 'verify', - ENCRYPT = 'encrypt', - DECRYPT = 'decrypt', - WRAP_KEY = 'wrapKey', - UNWRAP_KEY = 'unwrapKey', - DERIVE_KEY = 'deriveKey', - DERIVE_BITS = 'deriveBits', -} - -interface SavedJwks { - jwks: Jwks; - expires_at: number; -} - -export async function getJwks(url: string, storage?: persist.LocalStorage) { - const cached_keyset: SavedJwks | undefined = await storage?.getItem('Jwks.' + url); - - if (!cached_keyset || cached_keyset.expires_at <= Date.now()) { - debug('Downloading JSON Web Key Set from %s', url); - - const response = await fetch(url); - - const jwks = await response.json() as Jwks; - - const cached_keyset: SavedJwks = { - jwks, - expires_at: Date.now() + (1 * 60 * 60 * 1000), // 1 hour - }; - - await storage?.setItem('Jwks.' + url, cached_keyset); - - return jwks; - } - - return cached_keyset.jwks; -} diff --git a/src/util/jwt.ts b/src/util/jwt.ts new file mode 100644 index 0000000..d31ee39 --- /dev/null +++ b/src/util/jwt.ts @@ -0,0 +1,152 @@ +import * as crypto from 'crypto'; +import createDebug from 'debug'; +import persist from 'node-persist'; +import fetch from 'node-fetch'; + +const debug = createDebug('nxapi:util:jwt'); + +// +// JSON Web Tokens +// + +export interface JwtHeader { + typ?: 'JWT'; + alg: JwtAlgorithm; + /** Key ID */ + kid?: string; + /** JSON Web Key Set URL */ + jku?: string; +} +export enum JwtAlgorithm { + RS256 = 'RS256', +} + +export interface JwtPayload { + /** Audience */ + aud: string; + /** Expiration timestamp (seconds) */ + exp: number; + /** Issue timestamp (seconds) */ + iat: number; + /** Issuer */ + iss: string; + /** Token ID */ + jti: string; + /** Subject */ + sub: string | number; + /** Token type */ + typ: string; +} + +type JwtVerifier = (data: Buffer, signature: Buffer, key: string) => boolean; + +export class Jwt { + constructor( + readonly header: H, + readonly payload: T + ) {} + + static decode(token: string) { + const [header_str, payload_str, signature_str] = token.split('.', 3); + + const header = JSON.parse(Buffer.from(header_str, 'base64url').toString()); + const payload = JSON.parse(Buffer.from(payload_str, 'base64url').toString()); + const signature = Buffer.from(signature_str, 'base64url'); + + if ('typ' in header && header.typ !== 'JWT') { + throw new Error('Invalid JWT'); + } + + const jwt = new this(header, payload); + return [jwt, signature] as const; + } + + verify(signature: Buffer, key: string, verifier?: JwtVerifier) { + const header_str = Buffer.from(JSON.stringify(this.header)).toString('base64url'); + const payload_str = Buffer.from(JSON.stringify(this.payload)).toString('base64url'); + const sign_data = header_str + '.' + payload_str; + + if (!verifier) { + if (!(this.header.alg in Jwt.verifiers) || !Jwt.verifiers[this.header.alg]) { + throw new Error('Unknown algorithm'); + } + + verifier = Jwt.verifiers[this.header.alg]; + } + + return verifier.call(null, Buffer.from(sign_data), signature, key); + } + + static verifiers: Record = { + [JwtAlgorithm.RS256]: (data, signature, key) => { + const verify = crypto.createVerify('RSA-SHA256'); + verify.end(data); + return verify.verify(key, signature); + }, + }; +} + +// +// JSON Web Key Sets +// +// Used for verifying JSON Web Tokens +// + +export interface Jwks { + keys: Jwk[]; +} +export interface Jwk { + /** Key type */ + kty: string; + use?: JwkUse | string; + key_ops?: JwkKeyOperation | string; + alg?: JwtAlgorithm | string; + /** Key ID */ + kid?: string; + x5u?: string[]; + x5c?: string[]; + x5t?: string; + 'x5t#S256'?: string; +} +export enum JwkUse { + SIGNATURE = 'sig', + ENCRYPTION = 'enc', +} +export enum JwkKeyOperation { + SIGN = 'sign', + VERIFY = 'verify', + ENCRYPT = 'encrypt', + DECRYPT = 'decrypt', + WRAP_KEY = 'wrapKey', + UNWRAP_KEY = 'unwrapKey', + DERIVE_KEY = 'deriveKey', + DERIVE_BITS = 'deriveBits', +} + +interface SavedJwks { + jwks: Jwks; + expires_at: number; +} + +export async function getJwks(url: string, storage?: persist.LocalStorage) { + const cached_keyset: SavedJwks | undefined = await storage?.getItem('Jwks.' + url); + + if (!cached_keyset || cached_keyset.expires_at <= Date.now()) { + debug('Downloading JSON Web Key Set from %s', url); + + const response = await fetch(url); + + const jwks = await response.json() as Jwks; + + const cached_keyset: SavedJwks = { + jwks, + expires_at: Date.now() + (1 * 60 * 60 * 1000), // 1 hour + }; + + await storage?.setItem('Jwks.' + url, cached_keyset); + + return jwks; + } + + return cached_keyset.jwks; +} diff --git a/src/util/loop.ts b/src/util/loop.ts new file mode 100644 index 0000000..6045438 --- /dev/null +++ b/src/util/loop.ts @@ -0,0 +1,66 @@ +import createDebug from 'debug'; + +const debug = createDebug('nxapi:util:loop'); + +export default abstract class Loop { + update_interval = 60; + + init(): void | Promise {} + + abstract update(): void | Promise; + + protected async loopRun(init = false): Promise { + try { + const result = init ? await this.init() : await this.update(); + + return result ?? (init ? LoopResult.OK_SKIP_INTERVAL : LoopResult.OK); + } catch (err) { + return this.handleError(err as any); + } + } + + async handleError(err: Error): Promise { + throw err; + } + + private is_loop_active = 0; + + async loop(init = false) { + try { + this.is_loop_active++; + + const result = await this.loopRun(init); + + if (result === LoopResult.OK) { + if (this.skip_interval_once) { + this.skip_interval_once = false; + } else { + await new Promise(rs => setTimeout(this.timeout_resolve = rs, this.update_interval * 1000)); + } + } + } finally { + this.is_loop_active--; + this.skip_interval_once = false; + this.timeout_resolve = null; + } + } + + private skip_interval_once = false; + private timeout_resolve: ((value: void) => void) | null = null; + + skipIntervalInCurrentLoop() { + debug('Skip update interval', this.is_loop_active); + if (!this.is_loop_active) return; + + this.skip_interval_once = true; + this.timeout_resolve?.call(null); + } +} + +const LoopRunOk = Symbol('LoopRunOk'); +const LoopRunOkSkipInterval = Symbol('LoopRunOkSkipInterval'); + +export enum LoopResult { + OK = LoopRunOk as any, + OK_SKIP_INTERVAL = LoopRunOkSkipInterval as any, +} diff --git a/src/util/misc.ts b/src/util/misc.ts new file mode 100644 index 0000000..3086d71 --- /dev/null +++ b/src/util/misc.ts @@ -0,0 +1,20 @@ + +export function getTitleIdFromEcUrl(url: string) { + const match = url.match(/^https:\/\/ec\.nintendo\.com\/apps\/([0-9a-f]{16})\//); + return match?.[1] ?? null; +} + +export function hrduration(duration: number, short = false) { + const hours = Math.floor(duration / 60); + const minutes = duration - (hours * 60); + + const hour_str = short ? 'hr' : 'hour'; + const minute_str = short ? 'min' : 'minute'; + + if (hours >= 1) { + return hours + ' ' + hour_str + (hours === 1 ? '' : 's') + + (minutes ? ', ' + minutes + ' ' + minute_str + (minutes === 1 ? '' : 's') : ''); + } else { + return minutes + ' ' + minute_str + (minutes === 1 ? '' : 's'); + } +} diff --git a/src/util/product.ts b/src/util/product.ts new file mode 100644 index 0000000..c2f1133 --- /dev/null +++ b/src/util/product.ts @@ -0,0 +1,34 @@ +import * as path from 'path'; +import { fileURLToPath } from 'url'; +import * as fs from 'fs'; +import * as child_process from 'child_process'; +import createDebug from 'debug'; + +const debug = createDebug('nxapi:util:product'); + +// +// Package/version info +// + +export const dir = path.resolve(fileURLToPath(import.meta.url), '..', '..', '..'); +export const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf-8')); +export const version = pkg.version; +export const git = (() => { + try { + fs.statSync(path.join(dir, '.git')); + } catch (err) { + return null; + } + + const options: child_process.ExecSyncOptions = {cwd: dir}; + const revision = child_process.execSync('git rev-parse HEAD', options).toString().trim(); + const branch = child_process.execSync('git rev-parse --abbrev-ref HEAD', options).toString().trim(); + const changed_files = child_process.execSync('git diff --name-only HEAD', options).toString().trim(); + + return { + revision, + branch: branch && branch !== 'HEAD' ? branch : null, + changed_files: changed_files.length ? changed_files.split('\n') : [], + }; +})(); +export const dev = !!git || process.env.NODE_ENV === 'development'; diff --git a/src/util/storage.ts b/src/util/storage.ts new file mode 100644 index 0000000..803f32e --- /dev/null +++ b/src/util/storage.ts @@ -0,0 +1,17 @@ +import * as path from 'path'; +import createDebug from 'debug'; +import persist from 'node-persist'; +import getPaths from 'env-paths'; + +const debug = createDebug('nxapi:util:storage'); + +export const paths = getPaths('nxapi'); + +export async function initStorage(dir: string) { + const storage = persist.create({ + dir: path.join(dir, 'persist'), + stringify: data => JSON.stringify(data, null, 4) + '\n', + }); + await storage.init(); + return storage; +} diff --git a/src/util/yargs.ts b/src/util/yargs.ts new file mode 100644 index 0000000..47c96e4 --- /dev/null +++ b/src/util/yargs.ts @@ -0,0 +1,32 @@ +import * as yargs from 'yargs'; + +// +// Yargs types +// + +export type YargsArguments = T extends yargs.Argv ? R : any; +export type Argv = yargs.Argv; +// export type ArgumentsCamelCase = yargstypes.ArgumentsCamelCase; + +/** Convert literal string types like 'foo-bar' to 'FooBar' */ +type PascalCase = string extends S ? + string : S extends `${infer T}-${infer U}` ? + `${Capitalize}${PascalCase}` : Capitalize; + +/** Convert literal string types like 'foo-bar' to 'fooBar' */ +type CamelCase = string extends S ? + string : S extends `${infer T}-${infer U}` ? + `${T}${PascalCase}` : S; + +/** Convert literal string types like 'foo-bar' to 'fooBar', allowing all `PropertyKey` types */ +type CamelCaseKey = K extends string ? Exclude, ''> : K; + +/** Arguments type, with camelcased keys */ +export type ArgumentsCamelCase = { [key in keyof T as key | CamelCaseKey]: T[key] } & { + /** Non-option arguments */ + _: Array; + /** The script name or node command */ + $0: string; + /** All remaining options */ + [argName: string]: unknown; +};