mirror of
https://github.com/daydreamer-json/ak-endfield-api-archive.git
synced 2026-02-04 06:15:04 +01:00
Add auth test
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
config/config.yaml
|
config/config.yaml
|
||||||
|
memo/
|
||||||
|
|
||||||
# dependencies (bun install)
|
# dependencies (bun install)
|
||||||
node_modules
|
node_modules
|
||||||
|
|||||||
10
bun.lock
10
bun.lock
@@ -5,6 +5,7 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "ak-endfield-api-archive",
|
"name": "ak-endfield-api-archive",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/prompts": "^2.4.9",
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
"cli-table3": "^0.6.5",
|
"cli-table3": "^0.6.5",
|
||||||
"deepmerge": "^4.3.1",
|
"deepmerge": "^4.3.1",
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
"luxon": "^3.7.2",
|
"luxon": "^3.7.2",
|
||||||
"ora": "^9.1.0",
|
"ora": "^9.1.0",
|
||||||
"p-queue": "^9.1.0",
|
"p-queue": "^9.1.0",
|
||||||
|
"prompts": "^2.4.2",
|
||||||
"qs": "^6.14.1",
|
"qs": "^6.14.1",
|
||||||
"semver": "^7.7.3",
|
"semver": "^7.7.3",
|
||||||
"uuid": "^13.0.0",
|
"uuid": "^13.0.0",
|
||||||
@@ -91,6 +93,8 @@
|
|||||||
|
|
||||||
"@types/node": ["@types/node@25.0.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="],
|
"@types/node": ["@types/node@25.0.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="],
|
||||||
|
|
||||||
|
"@types/prompts": ["@types/prompts@2.4.9", "", { "dependencies": { "@types/node": "*", "kleur": "^3.0.3" } }, "sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA=="],
|
||||||
|
|
||||||
"@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="],
|
"@types/qs": ["@types/qs@6.14.0", "", {}, "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ=="],
|
||||||
|
|
||||||
"@types/semver": ["@types/semver@7.7.1", "", {}, "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA=="],
|
"@types/semver": ["@types/semver@7.7.1", "", {}, "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA=="],
|
||||||
@@ -203,6 +207,8 @@
|
|||||||
|
|
||||||
"jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
|
"jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="],
|
||||||
|
|
||||||
|
"kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
|
||||||
|
|
||||||
"ky": ["ky@1.14.2", "", {}, "sha512-q3RBbsO5A5zrPhB6CaCS8ZUv+NWCXv6JJT4Em0i264G9W0fdPB8YRfnnEi7Dm7X7omAkBIPojzYJ2D1oHTHqug=="],
|
"ky": ["ky@1.14.2", "", {}, "sha512-q3RBbsO5A5zrPhB6CaCS8ZUv+NWCXv6JJT4Em0i264G9W0fdPB8YRfnnEi7Dm7X7omAkBIPojzYJ2D1oHTHqug=="],
|
||||||
|
|
||||||
"log-symbols": ["log-symbols@7.0.1", "", { "dependencies": { "is-unicode-supported": "^2.0.0", "yoctocolors": "^2.1.1" } }, "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg=="],
|
"log-symbols": ["log-symbols@7.0.1", "", { "dependencies": { "is-unicode-supported": "^2.0.0", "yoctocolors": "^2.1.1" } }, "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg=="],
|
||||||
@@ -237,6 +243,8 @@
|
|||||||
|
|
||||||
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
|
"prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
|
||||||
|
|
||||||
"pstree.remy": ["pstree.remy@1.1.8", "", {}, "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w=="],
|
"pstree.remy": ["pstree.remy@1.1.8", "", {}, "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w=="],
|
||||||
|
|
||||||
"qs": ["qs@6.14.1", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ=="],
|
"qs": ["qs@6.14.1", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ=="],
|
||||||
@@ -261,6 +269,8 @@
|
|||||||
|
|
||||||
"simple-update-notifier": ["simple-update-notifier@2.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w=="],
|
"simple-update-notifier": ["simple-update-notifier@2.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w=="],
|
||||||
|
|
||||||
|
"sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
|
||||||
|
|
||||||
"stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="],
|
"stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="],
|
||||||
|
|
||||||
"streamroller": ["streamroller@3.1.5", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "fs-extra": "^8.1.0" } }, "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw=="],
|
"streamroller": ["streamroller@3.1.5", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "fs-extra": "^8.1.0" } }, "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw=="],
|
||||||
|
|||||||
@@ -2,15 +2,23 @@ network:
|
|||||||
api:
|
api:
|
||||||
akEndfield:
|
akEndfield:
|
||||||
appCode:
|
appCode:
|
||||||
|
game:
|
||||||
osWinRel: YDUTE5gscDZ229CW
|
osWinRel: YDUTE5gscDZ229CW
|
||||||
launcherAppCode:
|
launcher:
|
||||||
osWinRel: TiaytKBUIEdoEwRT
|
osWinRel: TiaytKBUIEdoEwRT
|
||||||
|
accountService:
|
||||||
|
osWinRel: d9f6dbb6bbd6bb33
|
||||||
|
u8:
|
||||||
|
osWinRel: 973bd727dd11cbb6ead8
|
||||||
|
osWinRel: YDUTE5gscDZ229CW
|
||||||
channel:
|
channel:
|
||||||
osWinRel: 6
|
osWinRel: 6
|
||||||
base:
|
base:
|
||||||
accountService: YXMuZ3J5cGhsaW5lLmNvbQ==
|
accountService: YXMuZ3J5cGhsaW5lLmNvbQ==
|
||||||
launcher: bGF1bmNoZXIuZ3J5cGhsaW5lLmNvbS9hcGk=
|
launcher: bGF1bmNoZXIuZ3J5cGhsaW5lLmNvbS9hcGk=
|
||||||
u8: dTguZ3J5cGhsaW5lLmNvbQ==
|
u8: dTguZ3J5cGhsaW5lLmNvbQ==
|
||||||
|
launcherAppCode:
|
||||||
|
osWinRel: TiaytKBUIEdoEwRT
|
||||||
userAgent:
|
userAgent:
|
||||||
minimum: Mozilla/5.0
|
minimum: Mozilla/5.0
|
||||||
chromeWindows: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
|
chromeWindows: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"start": "bun x biome format --write src && bun x oxfmt && bun src/main.ts"
|
"start": "bun x biome format --write src && bun x oxfmt && bun src/main.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/prompts": "^2.4.9",
|
||||||
"chalk": "^5.6.2",
|
"chalk": "^5.6.2",
|
||||||
"cli-table3": "^0.6.5",
|
"cli-table3": "^0.6.5",
|
||||||
"deepmerge": "^4.3.1",
|
"deepmerge": "^4.3.1",
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
"luxon": "^3.7.2",
|
"luxon": "^3.7.2",
|
||||||
"ora": "^9.1.0",
|
"ora": "^9.1.0",
|
||||||
"p-queue": "^9.1.0",
|
"p-queue": "^9.1.0",
|
||||||
|
"prompts": "^2.4.2",
|
||||||
"qs": "^6.14.1",
|
"qs": "^6.14.1",
|
||||||
"semver": "^7.7.3",
|
"semver": "^7.7.3",
|
||||||
"uuid": "^13.0.0",
|
"uuid": "^13.0.0",
|
||||||
|
|||||||
21
src/cmd.ts
21
src/cmd.ts
@@ -42,6 +42,27 @@ async function parseCommand() {
|
|||||||
},
|
},
|
||||||
wrapHandler(cmds.test),
|
wrapHandler(cmds.test),
|
||||||
)
|
)
|
||||||
|
.command(
|
||||||
|
['authTest [token] [email] [password]'],
|
||||||
|
'Auth test command',
|
||||||
|
(yargs) => {
|
||||||
|
yargs
|
||||||
|
.positional('token', {
|
||||||
|
describe: 'Gryphline account service token',
|
||||||
|
type: 'string',
|
||||||
|
})
|
||||||
|
.positional('email', {
|
||||||
|
describe: 'Gryphline account email address',
|
||||||
|
type: 'string',
|
||||||
|
})
|
||||||
|
.positional('password', {
|
||||||
|
describe: 'Gryphline account password',
|
||||||
|
type: 'string',
|
||||||
|
})
|
||||||
|
.options({});
|
||||||
|
},
|
||||||
|
wrapHandler(cmds.authTest),
|
||||||
|
)
|
||||||
.options({
|
.options({
|
||||||
'log-level': {
|
'log-level': {
|
||||||
desc: 'Set log level (' + TypesLogLevels.LOG_LEVELS_NUM.join(', ') + ')',
|
desc: 'Set log level (' + TypesLogLevels.LOG_LEVELS_NUM.join(', ') + ')',
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import authTest from './cmds/authTest.js';
|
||||||
import test from './cmds/test.js';
|
import test from './cmds/test.js';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
authTest,
|
||||||
test,
|
test,
|
||||||
};
|
};
|
||||||
|
|||||||
163
src/cmds/authTest.ts
Normal file
163
src/cmds/authTest.ts
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
import chalk from 'chalk';
|
||||||
|
import CliTable3 from 'cli-table3';
|
||||||
|
import { HTTPError } from 'ky';
|
||||||
|
import prompts from 'prompts';
|
||||||
|
import apiUtils from '../utils/api.js';
|
||||||
|
import argvUtils from '../utils/argv.js';
|
||||||
|
import appConfig from '../utils/config.js';
|
||||||
|
import exitUtils from '../utils/exit.js';
|
||||||
|
import logger from '../utils/logger.js';
|
||||||
|
import termPrettyUtils from '../utils/termPretty.js';
|
||||||
|
|
||||||
|
async function mainCmdHandler() {
|
||||||
|
const cfg = appConfig.network.api.akEndfield;
|
||||||
|
// const channelStr = String(cfg.channel.osWinRel);
|
||||||
|
|
||||||
|
let needRetrieveToken = false;
|
||||||
|
let oauth2TokenPreRsp = null;
|
||||||
|
if (!('token' in argvUtils.getArgv()) || !argvUtils.getArgv()['token']) {
|
||||||
|
const tokenUserRsp: string = await (async () => {
|
||||||
|
logger.warn('Gryphline account service token has not been specified. Requesting ...');
|
||||||
|
const onCancelFn = () => {
|
||||||
|
logger.error('Aborted');
|
||||||
|
exitUtils.exit(1, null, false);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
await prompts(
|
||||||
|
{ name: 'value', type: 'password', message: 'Enter Gryphline account service token' },
|
||||||
|
{ onCancel: onCancelFn },
|
||||||
|
)
|
||||||
|
).value;
|
||||||
|
})();
|
||||||
|
if (tokenUserRsp === '') {
|
||||||
|
needRetrieveToken = true;
|
||||||
|
} else {
|
||||||
|
argvUtils.setArgv({ ...argvUtils.getArgv(), token: tokenUserRsp });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needRetrieveToken === false) {
|
||||||
|
try {
|
||||||
|
oauth2TokenPreRsp = await apiUtils.apiAkEndfield.accountService.user.oauth2.v2.grant(
|
||||||
|
cfg.appCode.accountService.osWinRel,
|
||||||
|
argvUtils.getArgv()['token'],
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof HTTPError) {
|
||||||
|
if ((await err.response.json()).status === 3) needRetrieveToken = true;
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needRetrieveToken) {
|
||||||
|
await (async () => {
|
||||||
|
const onCancelFn = () => {
|
||||||
|
logger.error('Aborted');
|
||||||
|
exitUtils.exit(1, null, false);
|
||||||
|
};
|
||||||
|
if (!('email' in argvUtils.getArgv())) {
|
||||||
|
logger.warn('Gryphline account email has not been specified. Requesting ...');
|
||||||
|
const emailRsp: number = (
|
||||||
|
await prompts(
|
||||||
|
{
|
||||||
|
...{ name: 'value', type: 'text', message: 'Enter Gryphline account email' },
|
||||||
|
validate: (value) => (Boolean(value) ? true : 'Invalid value'),
|
||||||
|
},
|
||||||
|
{ onCancel: onCancelFn },
|
||||||
|
)
|
||||||
|
).value;
|
||||||
|
argvUtils.setArgv({ ...argvUtils.getArgv(), email: emailRsp });
|
||||||
|
}
|
||||||
|
if (!('password' in argvUtils.getArgv())) {
|
||||||
|
// logger.warn('Gryphline account password has not been specified. Requesting ...');
|
||||||
|
const pwdRsp: number = (
|
||||||
|
await prompts(
|
||||||
|
{
|
||||||
|
...{ name: 'value', type: 'password', message: 'Enter Gryphline account password' },
|
||||||
|
validate: (value) => (Boolean(value) ? true : 'Invalid value'),
|
||||||
|
},
|
||||||
|
{ onCancel: onCancelFn },
|
||||||
|
)
|
||||||
|
).value;
|
||||||
|
argvUtils.setArgv({ ...argvUtils.getArgv(), password: pwdRsp });
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
logger.info('Retrieving account service token ...');
|
||||||
|
const accSrvTokenRsp = await apiUtils.apiAkEndfield.accountService.user.auth.v1.tokenByEmailPassword(
|
||||||
|
argvUtils.getArgv()['email'],
|
||||||
|
argvUtils.getArgv()['password'],
|
||||||
|
);
|
||||||
|
argvUtils.setArgv({ ...argvUtils.getArgv(), token: accSrvTokenRsp.data.token });
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('Retrieving account service OAuth 2.0 token ...');
|
||||||
|
const oauth2TokenRsp = await apiUtils.apiAkEndfield.accountService.user.oauth2.v2.grant(
|
||||||
|
cfg.appCode.accountService.osWinRel,
|
||||||
|
argvUtils.getArgv()['token'],
|
||||||
|
);
|
||||||
|
logger.info('Retrieving u8 access token ...');
|
||||||
|
const u8TokenRsp = await apiUtils.apiAkEndfield.u8.user.auth.v2.tokenByChToken(
|
||||||
|
cfg.appCode.u8.osWinRel,
|
||||||
|
cfg.channel.osWinRel,
|
||||||
|
oauth2TokenRsp.data.code,
|
||||||
|
);
|
||||||
|
logger.info('Authentication successful!');
|
||||||
|
|
||||||
|
logger.info('Retrieving user account data ...');
|
||||||
|
const userAccData = await apiUtils.apiAkEndfield.accountService.user.info.v1.basic(
|
||||||
|
cfg.appCode.accountService.osWinRel,
|
||||||
|
argvUtils.getArgv()['token'],
|
||||||
|
);
|
||||||
|
logger.info('Retrieving user game server data ...');
|
||||||
|
const userGameData = await apiUtils.apiAkEndfield.u8.game.server.v1.serverList(u8TokenRsp.data.token);
|
||||||
|
|
||||||
|
logger.info('Data retrieval completed!');
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
const table = new CliTable3(termPrettyUtils.cliTableConfig.rounded);
|
||||||
|
table.push(
|
||||||
|
...[
|
||||||
|
['Account ID', userAccData.data.hgId],
|
||||||
|
['Email', userAccData.data.realEmail],
|
||||||
|
['Nickname', userAccData.data.nickName === '' ? chalk.dim('(none)') : userAccData.data.nickName],
|
||||||
|
['Age Region', userAccData.data.ageGate.regionInfo['en-us']],
|
||||||
|
].map((e) => [chalk.dim(e[0]), e[1]]),
|
||||||
|
);
|
||||||
|
console.log(table.toString());
|
||||||
|
})();
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
const table = new CliTable3(termPrettyUtils.cliTableConfig.rounded);
|
||||||
|
table.push(
|
||||||
|
...[
|
||||||
|
['ID', 'Time', 'Name', 'Domain', 'Port'].map((e) => chalk.dim(e)),
|
||||||
|
...userGameData.data.serverList.map((e) => [
|
||||||
|
e.serverId,
|
||||||
|
'UTC' + (JSON.parse(e.extension).offsetSeconds < 0 ? '' : '+') + JSON.parse(e.extension).offsetSeconds / 3600,
|
||||||
|
e.serverName,
|
||||||
|
JSON.parse(e.serverDomain)[0].host,
|
||||||
|
JSON.parse(e.serverDomain)[0].port,
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
console.log(table.toString());
|
||||||
|
})();
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
const table = new CliTable3(termPrettyUtils.cliTableConfig.rounded);
|
||||||
|
table.push(
|
||||||
|
...[
|
||||||
|
['ID', 'UID', 'Level', 'Default'].map((e) => chalk.dim(e)),
|
||||||
|
...userGameData.data.serverList.map((e) => [
|
||||||
|
e.serverId,
|
||||||
|
e.roleId,
|
||||||
|
{ hAlign: 'right' as const, content: e.level },
|
||||||
|
e.defaultChoose,
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
console.log(table.toString());
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default mainCmdHandler;
|
||||||
@@ -81,8 +81,8 @@ async function mainCmdHandler() {
|
|||||||
await (async () => {
|
await (async () => {
|
||||||
logger.debug('Fetching latestGame ...');
|
logger.debug('Fetching latestGame ...');
|
||||||
const rsp = await apiUtils.apiAkEndfield.launcher.latestGame(
|
const rsp = await apiUtils.apiAkEndfield.launcher.latestGame(
|
||||||
cfg.appCode.osWinRel,
|
cfg.appCode.game.osWinRel,
|
||||||
cfg.launcherAppCode.osWinRel,
|
cfg.appCode.launcher.osWinRel,
|
||||||
cfg.channel.osWinRel,
|
cfg.channel.osWinRel,
|
||||||
cfg.channel.osWinRel,
|
cfg.channel.osWinRel,
|
||||||
cfg.channel.osWinRel,
|
cfg.channel.osWinRel,
|
||||||
@@ -103,8 +103,8 @@ async function mainCmdHandler() {
|
|||||||
);
|
);
|
||||||
const prettyRsp = {
|
const prettyRsp = {
|
||||||
req: {
|
req: {
|
||||||
appCode: cfg.appCode.osWinRel,
|
appCode: cfg.appCode.game.osWinRel,
|
||||||
launcherAppCode: cfg.launcherAppCode.osWinRel,
|
launcherAppCode: cfg.appCode.launcher.osWinRel,
|
||||||
channel: cfg.channel.osWinRel,
|
channel: cfg.channel.osWinRel,
|
||||||
subChannel: cfg.channel.osWinRel,
|
subChannel: cfg.channel.osWinRel,
|
||||||
launcherSubChannel: cfg.channel.osWinRel,
|
launcherSubChannel: cfg.channel.osWinRel,
|
||||||
@@ -147,7 +147,7 @@ async function mainCmdHandler() {
|
|||||||
for (const versionInfoEntry of versionInfoList) {
|
for (const versionInfoEntry of versionInfoList) {
|
||||||
if (!versionInfoEntry.randStr) throw new Error('version rand_str not found');
|
if (!versionInfoEntry.randStr) throw new Error('version rand_str not found');
|
||||||
const rsp = await apiUtils.apiAkEndfield.launcher.latestGameResources(
|
const rsp = await apiUtils.apiAkEndfield.launcher.latestGameResources(
|
||||||
cfg.appCode.osWinRel,
|
cfg.appCode.game.osWinRel,
|
||||||
versionInfoEntry.versionMinor,
|
versionInfoEntry.versionMinor,
|
||||||
versionInfoEntry.version,
|
versionInfoEntry.version,
|
||||||
versionInfoEntry.randStr,
|
versionInfoEntry.randStr,
|
||||||
@@ -155,7 +155,7 @@ async function mainCmdHandler() {
|
|||||||
logger.info(`Fetched latestGameRes: v${versionInfoEntry.version}, ${rsp.res_version}`);
|
logger.info(`Fetched latestGameRes: v${versionInfoEntry.version}, ${rsp.res_version}`);
|
||||||
const prettyRsp = {
|
const prettyRsp = {
|
||||||
req: {
|
req: {
|
||||||
appCode: cfg.appCode.osWinRel,
|
appCode: cfg.appCode.game.osWinRel,
|
||||||
gameVersion: versionInfoEntry.versionMinor,
|
gameVersion: versionInfoEntry.versionMinor,
|
||||||
version: versionInfoEntry.version,
|
version: versionInfoEntry.version,
|
||||||
randStr: versionInfoEntry.randStr,
|
randStr: versionInfoEntry.randStr,
|
||||||
@@ -178,7 +178,7 @@ async function mainCmdHandler() {
|
|||||||
const launcherTargetAppList = ['EndField', 'official'] as const;
|
const launcherTargetAppList = ['EndField', 'official'] as const;
|
||||||
for (const launcherTargetAppEntry of launcherTargetAppList) {
|
for (const launcherTargetAppEntry of launcherTargetAppList) {
|
||||||
const rsp = await apiUtils.apiAkEndfield.launcher.latestLauncher(
|
const rsp = await apiUtils.apiAkEndfield.launcher.latestLauncher(
|
||||||
cfg.launcherAppCode.osWinRel,
|
cfg.appCode.launcher.osWinRel,
|
||||||
cfg.channel.osWinRel,
|
cfg.channel.osWinRel,
|
||||||
cfg.channel.osWinRel,
|
cfg.channel.osWinRel,
|
||||||
null,
|
null,
|
||||||
@@ -187,7 +187,7 @@ async function mainCmdHandler() {
|
|||||||
logger.info(`Fetched latestLauncher: v${rsp.version}, ${launcherTargetAppEntry}`);
|
logger.info(`Fetched latestLauncher: v${rsp.version}, ${launcherTargetAppEntry}`);
|
||||||
const prettyRsp = {
|
const prettyRsp = {
|
||||||
req: {
|
req: {
|
||||||
appCode: cfg.launcherAppCode.osWinRel,
|
appCode: cfg.appCode.launcher.osWinRel,
|
||||||
channel: cfg.channel.osWinRel,
|
channel: cfg.channel.osWinRel,
|
||||||
subChannel: cfg.channel.osWinRel,
|
subChannel: cfg.channel.osWinRel,
|
||||||
targetApp: launcherTargetAppEntry === 'official' ? null : launcherTargetAppEntry,
|
targetApp: launcherTargetAppEntry === 'official' ? null : launcherTargetAppEntry,
|
||||||
|
|||||||
@@ -106,6 +106,94 @@ type LauncherWebAnnouncement = {
|
|||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type AccSrvUserAuthV1TokenByEmail = {
|
||||||
|
data: {
|
||||||
|
token: string;
|
||||||
|
hgId: string; // hypergryph account id
|
||||||
|
email: string; // obfuscated email
|
||||||
|
isLatestUserAgreement: boolean;
|
||||||
|
};
|
||||||
|
msg: string;
|
||||||
|
status: number;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type AccSrvUserInfoV1Basic = {
|
||||||
|
data: {
|
||||||
|
hgId: string; // hypergryph account id
|
||||||
|
email: string; // obfuscated email
|
||||||
|
realEmail: string; // un-obfuscated email
|
||||||
|
isLatestUserAgreement: boolean;
|
||||||
|
nickName: string;
|
||||||
|
emailSubscription: boolean; // ???
|
||||||
|
extension: { firebaseHashedInfo: string };
|
||||||
|
ageGate: {
|
||||||
|
ageAuthState: number;
|
||||||
|
bindEmail: boolean;
|
||||||
|
parentAuthState: number;
|
||||||
|
regionInfo: Record<
|
||||||
|
| 'de-de'
|
||||||
|
| 'en-us' // Japan
|
||||||
|
| 'es-mx'
|
||||||
|
| 'fr-fr'
|
||||||
|
| 'id-id'
|
||||||
|
| 'it-it'
|
||||||
|
| 'ja-jp' // 日本
|
||||||
|
| 'ko-kr'
|
||||||
|
| 'pt-br'
|
||||||
|
| 'ru-ru'
|
||||||
|
| 'th-th'
|
||||||
|
| 'vi-vn'
|
||||||
|
| 'zh-cn' // 日本
|
||||||
|
| 'zh-tw',
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
regionCode: string; // JP
|
||||||
|
};
|
||||||
|
};
|
||||||
|
msg: string;
|
||||||
|
status: number;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type AccSrvUserOAuth2V2Grant = {
|
||||||
|
data: {
|
||||||
|
uid: string; // ???
|
||||||
|
code: string; // this is channel token
|
||||||
|
};
|
||||||
|
msg: string; // OK, Login status expired.
|
||||||
|
status: number; // 0=OK, 3=expired
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type U8UserAuthV2ChToken = {
|
||||||
|
data: {
|
||||||
|
token: string;
|
||||||
|
isNew: boolean;
|
||||||
|
uid: string; // number, game overall uid?
|
||||||
|
};
|
||||||
|
msg: string;
|
||||||
|
status: number;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type U8GameServerV1ServerList = {
|
||||||
|
data: {
|
||||||
|
serverList: {
|
||||||
|
serverId: string; // number
|
||||||
|
serverName: string; // Asia
|
||||||
|
serverDomain: string; // jsonStr [{"host": "beyond-asiapacific.gryphline.com", "port": 30000}]
|
||||||
|
defaultChoose: boolean;
|
||||||
|
roleId: string; // the so-called UID elsewhere
|
||||||
|
level: number; // playerLv
|
||||||
|
extension: string; // jsonStr {"offsetSeconds": -18000, "monthlyCardOffsetSecond": -18000}
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
msg: string;
|
||||||
|
status: number;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
LauncherLatestGame,
|
LauncherLatestGame,
|
||||||
LauncherLatestGameResources,
|
LauncherLatestGameResources,
|
||||||
@@ -115,4 +203,9 @@ export type {
|
|||||||
LauncherWebMainBgImage,
|
LauncherWebMainBgImage,
|
||||||
LauncherWebBanner,
|
LauncherWebBanner,
|
||||||
LauncherWebAnnouncement,
|
LauncherWebAnnouncement,
|
||||||
|
AccSrvUserAuthV1TokenByEmail,
|
||||||
|
AccSrvUserInfoV1Basic,
|
||||||
|
AccSrvUserOAuth2V2Grant,
|
||||||
|
U8UserAuthV2ChToken,
|
||||||
|
U8GameServerV1ServerList,
|
||||||
};
|
};
|
||||||
|
|||||||
101
src/utils/api.ts
101
src/utils/api.ts
@@ -1,6 +1,6 @@
|
|||||||
import ky from 'ky';
|
import ky from 'ky';
|
||||||
import semver from 'semver';
|
import semver from 'semver';
|
||||||
import * as TypesApiAkEndfield from '../types/api/akEndfield/api.js';
|
import * as TypesApiAkEndfield from '../types/api/akEndfield/Api.js';
|
||||||
import appConfig from './config.js';
|
import appConfig from './config.js';
|
||||||
|
|
||||||
const defaultKySettings = {
|
const defaultKySettings = {
|
||||||
@@ -248,5 +248,104 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
accountService: {
|
||||||
|
user: {
|
||||||
|
auth: {
|
||||||
|
v1: {
|
||||||
|
tokenByEmailPassword: async (
|
||||||
|
email: string,
|
||||||
|
password: string,
|
||||||
|
from: number = 0,
|
||||||
|
): Promise<TypesApiAkEndfield.AccSrvUserAuthV1TokenByEmail> => {
|
||||||
|
const rsp = await ky
|
||||||
|
.post(
|
||||||
|
`https://${appConfig.network.api.akEndfield.base.accountService}/user/auth/v1/token_by_email_password`,
|
||||||
|
{ ...defaultKySettings, json: { email, from, password } },
|
||||||
|
)
|
||||||
|
.json();
|
||||||
|
return rsp as TypesApiAkEndfield.AccSrvUserAuthV1TokenByEmail;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
oauth2: {
|
||||||
|
v2: {
|
||||||
|
grant: async (
|
||||||
|
appCode: string,
|
||||||
|
token: string,
|
||||||
|
type: number = 0,
|
||||||
|
): Promise<TypesApiAkEndfield.AccSrvUserOAuth2V2Grant> => {
|
||||||
|
const rsp = await ky
|
||||||
|
.post(`https://${appConfig.network.api.akEndfield.base.accountService}/user/oauth2/v2/grant`, {
|
||||||
|
...defaultKySettings,
|
||||||
|
json: { appCode, token, type },
|
||||||
|
})
|
||||||
|
.json();
|
||||||
|
return rsp as TypesApiAkEndfield.AccSrvUserOAuth2V2Grant;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
v1: {
|
||||||
|
basic: async (appCode: string, token: string): Promise<TypesApiAkEndfield.AccSrvUserInfoV1Basic> => {
|
||||||
|
const rsp = await ky
|
||||||
|
.get(`https://${appConfig.network.api.akEndfield.base.accountService}/user/info/v1/basic`, {
|
||||||
|
...defaultKySettings,
|
||||||
|
searchParams: { appCode, token },
|
||||||
|
})
|
||||||
|
.json();
|
||||||
|
return rsp as TypesApiAkEndfield.AccSrvUserInfoV1Basic;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
u8: {
|
||||||
|
user: {
|
||||||
|
auth: {
|
||||||
|
v2: {
|
||||||
|
tokenByChToken: async (
|
||||||
|
appCode: string,
|
||||||
|
channelMasterId: number,
|
||||||
|
channelToken: string,
|
||||||
|
platform: number = 2,
|
||||||
|
type: number = 0,
|
||||||
|
): Promise<TypesApiAkEndfield.U8UserAuthV2ChToken> => {
|
||||||
|
const rsp = await ky
|
||||||
|
.post(`https://${appConfig.network.api.akEndfield.base.u8}/u8/user/auth/v2/token_by_channel_token`, {
|
||||||
|
...defaultKySettings,
|
||||||
|
json: {
|
||||||
|
appCode,
|
||||||
|
channelMasterId,
|
||||||
|
channelToken: JSON.stringify({
|
||||||
|
code: channelToken,
|
||||||
|
type: 1,
|
||||||
|
isSuc: true,
|
||||||
|
}),
|
||||||
|
type,
|
||||||
|
platform,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.json();
|
||||||
|
return rsp as TypesApiAkEndfield.U8UserAuthV2ChToken;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
game: {
|
||||||
|
server: {
|
||||||
|
v1: {
|
||||||
|
serverList: async (token: string): Promise<TypesApiAkEndfield.U8GameServerV1ServerList> => {
|
||||||
|
const rsp = await ky
|
||||||
|
.post(`https://${appConfig.network.api.akEndfield.base.u8}/game/server/v1/server_list`, {
|
||||||
|
...defaultKySettings,
|
||||||
|
json: { token },
|
||||||
|
})
|
||||||
|
.json();
|
||||||
|
return rsp as TypesApiAkEndfield.U8GameServerV1ServerList;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,8 +15,12 @@ type ConfigType = AllRequired<
|
|||||||
network: {
|
network: {
|
||||||
api: {
|
api: {
|
||||||
akEndfield: {
|
akEndfield: {
|
||||||
appCode: { osWinRel: string };
|
appCode: {
|
||||||
launcherAppCode: { osWinRel: string };
|
game: { osWinRel: string };
|
||||||
|
launcher: { osWinRel: string };
|
||||||
|
accountService: { osWinRel: string };
|
||||||
|
u8: { osWinRel: string };
|
||||||
|
};
|
||||||
channel: { osWinRel: number };
|
channel: { osWinRel: number };
|
||||||
base: {
|
base: {
|
||||||
accountService: string;
|
accountService: string;
|
||||||
@@ -55,8 +59,12 @@ const initialConfig: ConfigType = {
|
|||||||
network: {
|
network: {
|
||||||
api: {
|
api: {
|
||||||
akEndfield: {
|
akEndfield: {
|
||||||
appCode: { osWinRel: 'YDUTE5gscDZ229CW' },
|
appCode: {
|
||||||
launcherAppCode: { osWinRel: 'TiaytKBUIEdoEwRT' },
|
game: { osWinRel: 'YDUTE5gscDZ229CW' },
|
||||||
|
launcher: { osWinRel: 'TiaytKBUIEdoEwRT' },
|
||||||
|
accountService: { osWinRel: 'd9f6dbb6bbd6bb33' },
|
||||||
|
u8: { osWinRel: '973bd727dd11cbb6ead8' },
|
||||||
|
},
|
||||||
channel: { osWinRel: 6 },
|
channel: { osWinRel: 6 },
|
||||||
base: {
|
base: {
|
||||||
accountService: 'YXMuZ3J5cGhsaW5lLmNvbQ==',
|
accountService: 'YXMuZ3J5cGhsaW5lLmNvbQ==',
|
||||||
|
|||||||
148
src/utils/string.ts
Normal file
148
src/utils/string.ts
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
// === Generated by Qwen3-Max ===
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 元となるURLと相対URLから絶対URLを解決します。
|
||||||
|
* ベースURLがファイルパスを含む場合でも、そのファイルのディレクトリを基準に解決します。
|
||||||
|
*
|
||||||
|
* @param baseUrl - 元となるURL(絶対URL)
|
||||||
|
* @param relativeUrl - 相対URLまたは絶対URL
|
||||||
|
* @returns 解決された絶対URL
|
||||||
|
* @throws URLが無効な場合にエラーをスローします
|
||||||
|
*/
|
||||||
|
function resolveUrl(baseUrl: string, relativeUrl: string): string {
|
||||||
|
try {
|
||||||
|
// 相対URLがすでに絶対URLの場合、そのまま返す
|
||||||
|
if (isAbsoluteUrl(relativeUrl)) {
|
||||||
|
return new URL(relativeUrl).href;
|
||||||
|
}
|
||||||
|
|
||||||
|
// baseUrlをURLとしてパース
|
||||||
|
const base = new URL(baseUrl);
|
||||||
|
|
||||||
|
// ベースURLがファイルパス(末尾が/でない)の場合、
|
||||||
|
// ファイル名を除去してディレクトリパスにする
|
||||||
|
if (!base.pathname.endsWith('/')) {
|
||||||
|
// 最後のスラッシュ以降を除去(ファイル名を削除)
|
||||||
|
const lastSlashIndex = base.pathname.lastIndexOf('/');
|
||||||
|
if (lastSlashIndex !== -1) {
|
||||||
|
base.pathname = base.pathname.substring(0, lastSlashIndex + 1);
|
||||||
|
} else {
|
||||||
|
// パスにスラッシュが含まれていない稀なケース
|
||||||
|
base.pathname = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 相対URLを解決
|
||||||
|
const resolved = new URL(relativeUrl, base);
|
||||||
|
|
||||||
|
return resolved.href;
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`URLの解決に失敗しました: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URLが絶対URLかどうかを判定します。
|
||||||
|
*
|
||||||
|
* @param url - 判定するURL文字列
|
||||||
|
* @returns 絶対URLの場合はtrue、それ以外はfalse
|
||||||
|
*/
|
||||||
|
function isAbsoluteUrl(url: string): boolean {
|
||||||
|
try {
|
||||||
|
return Boolean(new URL(url).protocol);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URLフルパスからファイル名を除いた部分を抽出します
|
||||||
|
* @param url
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function getBaseUrlWithoutLastSegment(url: string): string {
|
||||||
|
const u = new URL(url);
|
||||||
|
const dirPath = u.pathname.split('/').slice(0, -1).join('/');
|
||||||
|
return `${u.origin}${dirPath}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================
|
||||||
|
|
||||||
|
function replaceMultiPatterns(replacements: [RegExp, string][], originalString: string): string {
|
||||||
|
return replacements.reduce((currentString, [pattern, replacement]) => {
|
||||||
|
return currentString.replace(pattern, replacement);
|
||||||
|
}, originalString);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sanitizeFilename(filename: string) {
|
||||||
|
const invalidCharsMap: Record<string, string> = {
|
||||||
|
'\\': '\',
|
||||||
|
'/': '/',
|
||||||
|
':': ':',
|
||||||
|
'*': '*',
|
||||||
|
'?': '?',
|
||||||
|
'"': '"',
|
||||||
|
'<': '<',
|
||||||
|
'>': '>',
|
||||||
|
'|': '|',
|
||||||
|
'&': '&',
|
||||||
|
};
|
||||||
|
return Array.from(filename)
|
||||||
|
.map((char) => invalidCharsMap[char] || char)
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文字列が指定された正規表現パターンにマッチするかを判定する関数
|
||||||
|
*
|
||||||
|
* @param inputStr - チェック対象の文字列
|
||||||
|
* @param regexInclude - マッチが必須の正規表現パターン(少なくとも1つマッチする必要あり)
|
||||||
|
* @param regexExclude - マッチが禁止の正規表現パターン(1つもマッチしてはならない)
|
||||||
|
* @returns
|
||||||
|
* includeパターンが空の場合はexcludeにマッチしない限りtrue
|
||||||
|
* includeパターンがある場合は、少なくとも1つのincludeにマッチし、
|
||||||
|
* かつ全てのexcludeにマッチしない場合のみtrue
|
||||||
|
*/
|
||||||
|
function filterByRegex(
|
||||||
|
inputStr: string,
|
||||||
|
regexInclude: readonly (RegExp | string)[],
|
||||||
|
regexExclude: readonly (RegExp | string)[],
|
||||||
|
): boolean {
|
||||||
|
// 文字列をRegExpに変換するヘルパー関数(グローバルフラグを無効化)
|
||||||
|
const toRegExp = (pattern: RegExp | string): RegExp => {
|
||||||
|
if (pattern instanceof RegExp) {
|
||||||
|
// グローバルフラグ/ステッキーフラグを無効化(test()の状態問題を回避)
|
||||||
|
const flags = pattern.flags.replace(/[gy]/g, '');
|
||||||
|
return new RegExp(pattern.source, flags);
|
||||||
|
}
|
||||||
|
return new RegExp(pattern);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 正規表現を変換(include/exclude両方)
|
||||||
|
const includePatterns = regexInclude.map(toRegExp);
|
||||||
|
const excludePatterns = regexExclude.map(toRegExp);
|
||||||
|
|
||||||
|
// 1. excludeパターンに1つでもマッチしたら即座にfalse
|
||||||
|
if (excludePatterns.some((pattern) => pattern.test(inputStr))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. includeパターンが空の場合はtrue(excludeを通過した時点でOK)
|
||||||
|
if (includePatterns.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. includeパターンに1つでもマッチすればtrue
|
||||||
|
return includePatterns.some((pattern) => pattern.test(inputStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================
|
||||||
|
|
||||||
|
export default {
|
||||||
|
resolveUrl,
|
||||||
|
isAbsoluteUrl,
|
||||||
|
getBaseUrlWithoutLastSegment,
|
||||||
|
replaceMultiPatterns,
|
||||||
|
sanitizeFilename,
|
||||||
|
filterByRegex,
|
||||||
|
};
|
||||||
46
src/utils/termPretty.ts
Normal file
46
src/utils/termPretty.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
const cliTableConfig = {
|
||||||
|
rounded: {
|
||||||
|
chars: {
|
||||||
|
top: '─',
|
||||||
|
'top-mid': '',
|
||||||
|
'top-left': '╭',
|
||||||
|
'top-right': '╮',
|
||||||
|
bottom: '─',
|
||||||
|
'bottom-mid': '',
|
||||||
|
'bottom-left': '╰',
|
||||||
|
'bottom-right': '╯',
|
||||||
|
left: '│',
|
||||||
|
'left-mid': '├',
|
||||||
|
mid: '─',
|
||||||
|
'mid-mid': '',
|
||||||
|
right: '│',
|
||||||
|
'right-mid': '┤',
|
||||||
|
middle: '',
|
||||||
|
},
|
||||||
|
style: { 'padding-left': 1, 'padding-right': 1, head: [''], border: [''], compact: true },
|
||||||
|
},
|
||||||
|
noBorder: {
|
||||||
|
chars: {
|
||||||
|
top: '',
|
||||||
|
'top-mid': '',
|
||||||
|
'top-left': '',
|
||||||
|
'top-right': '',
|
||||||
|
bottom: '',
|
||||||
|
'bottom-mid': '',
|
||||||
|
'bottom-left': '',
|
||||||
|
'bottom-right': '',
|
||||||
|
left: '',
|
||||||
|
'left-mid': '',
|
||||||
|
mid: '',
|
||||||
|
'mid-mid': '',
|
||||||
|
right: '',
|
||||||
|
'right-mid': '',
|
||||||
|
middle: ' ',
|
||||||
|
},
|
||||||
|
style: { 'padding-left': 0, 'padding-right': 0 },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
cliTableConfig,
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user