From b9c2d4253acd15567b01156c64aaa90622991a4e Mon Sep 17 00:00:00 2001 From: daydreamer-json Date: Thu, 22 Jan 2026 18:48:17 +0900 Subject: [PATCH] Hello --- .editorconfig | 8 + .github/workflows/main.yml | 38 + .gitignore | 35 + .oxfmtrc.json | 20 + .vscode/settings.json | 23 + LICENSE | 661 ++++++++++++++++++ README.md | 3 + biome.json | 38 + bun.lock | 332 +++++++++ config/config.yaml | 30 + output/akEndfield/launcher/game/6/all.json | 212 ++++++ output/akEndfield/launcher/game/6/latest.json | 209 ++++++ .../akEndfield/launcher/game/6/v1.0.13.json | 209 ++++++ .../launcher/game_resources/6/all.json | 29 + .../launcher/game_resources/6/latest.json | 26 + .../launcher/game_resources/6/v1.0.13.json | 26 + .../launcher/launcher/EndField/6/all.json | 21 + .../launcher/launcher/EndField/6/latest.json | 18 + .../launcher/launcher/EndField/6/v1.0.0.json | 18 + .../launcher/launcher/official/6/all.json | 21 + .../launcher/launcher/official/6/latest.json | 18 + .../launcher/launcher/official/6/v1.0.0.json | 18 + package.json | 52 ++ src/cmd.ts | 76 ++ src/cmds.ts | 5 + src/cmds/test.ts | 236 +++++++ src/main.ts | 18 + src/types/LogLevels.ts | 15 + src/types/api/akEndfield/Api.ts | 118 ++++ src/utils/api.ts | 252 +++++++ src/utils/argv.ts | 13 + src/utils/config.ts | 120 ++++ src/utils/configEmbed.ts | 6 + src/utils/exit.ts | 50 ++ src/utils/file.ts | 117 ++++ src/utils/logger.ts | 25 + src/utils/math.ts | 90 +++ src/utils/omitDeep.ts | 125 ++++ tsconfig.json | 15 + 39 files changed, 3346 insertions(+) create mode 100644 .editorconfig create mode 100644 .github/workflows/main.yml create mode 100644 .gitignore create mode 100644 .oxfmtrc.json create mode 100644 .vscode/settings.json create mode 100644 LICENSE create mode 100644 README.md create mode 100644 biome.json create mode 100644 bun.lock create mode 100644 config/config.yaml create mode 100644 output/akEndfield/launcher/game/6/all.json create mode 100644 output/akEndfield/launcher/game/6/latest.json create mode 100644 output/akEndfield/launcher/game/6/v1.0.13.json create mode 100644 output/akEndfield/launcher/game_resources/6/all.json create mode 100644 output/akEndfield/launcher/game_resources/6/latest.json create mode 100644 output/akEndfield/launcher/game_resources/6/v1.0.13.json create mode 100644 output/akEndfield/launcher/launcher/EndField/6/all.json create mode 100644 output/akEndfield/launcher/launcher/EndField/6/latest.json create mode 100644 output/akEndfield/launcher/launcher/EndField/6/v1.0.0.json create mode 100644 output/akEndfield/launcher/launcher/official/6/all.json create mode 100644 output/akEndfield/launcher/launcher/official/6/latest.json create mode 100644 output/akEndfield/launcher/launcher/official/6/v1.0.0.json create mode 100644 package.json create mode 100644 src/cmd.ts create mode 100644 src/cmds.ts create mode 100644 src/cmds/test.ts create mode 100644 src/main.ts create mode 100644 src/types/LogLevels.ts create mode 100644 src/types/api/akEndfield/Api.ts create mode 100644 src/utils/api.ts create mode 100644 src/utils/argv.ts create mode 100644 src/utils/config.ts create mode 100644 src/utils/configEmbed.ts create mode 100644 src/utils/exit.ts create mode 100644 src/utils/file.ts create mode 100644 src/utils/logger.ts create mode 100644 src/utils/math.ts create mode 100644 src/utils/omitDeep.ts create mode 100644 tsconfig.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9aa5361 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..04c2c08 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,38 @@ +name: Auto API update check +permissions: + actions: write + checks: write + contents: write +on: + # Scheduled trigger is disabled by default + # Uncommenting the following two lines will enable it + # schedule: + # - cron: '0 16 * * *' + workflow_dispatch: + repository_dispatch: +jobs: + run: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + - name: Install dependencies + run: bun install + - name: Run script + uses: nick-fields/retry@v3 + with: + max_attempts: 5 + timeout_minutes: 10 + command: bun run src/main.ts test + - name: Format output data + run: bun x oxfmt output + - name: Git staging, commit, push + continue-on-error: true + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add output + git commit -m '[Auto] API update' + git push diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..30a7a91 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# dependencies (bun install) +node_modules + +# output +out +dist +*.tgz + +# code coverage +coverage +*.lcov + +# logs +logs +_.log +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# caches +.eslintcache +.cache +*.tsbuildinfo +.parcel-cache + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 0000000..f9072f6 --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,20 @@ +{ + "$schema": "./node_modules/oxfmt/configuration_schema.json", + "ignorePatterns": [], + "useTabs": false, + "printWidth": 120, + "tabWidth": 2, + "endOfLine": "lf", + "arrowParens": "always", + "bracketSameLine": false, + "bracketSpacing": true, + "htmlWhitespaceSensitivity": "css", + "insertFinalNewline": true, + "jsxSingleQuote": true, + "objectWrap": "preserve", + "proseWrap": "preserve", + "quoteProps": "as-needed", + "semi": true, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d539965 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,23 @@ +{ + "editor.formatOnSave": true, + "editor.defaultFormatter": "biomejs.biome", + "[json]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[javascript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "editor.codeActionsOnSave": { + "source.fixAll.biome": "explicit", + "source.organizeImports.biome": "explicit" + } +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..83c1d0b --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# ak-endfield-api-archive + +This project was created using `bun init` in bun v1.3.5. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime. diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..86ebb55 --- /dev/null +++ b/biome.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.2.4/schema.json", + "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true }, + "files": { "ignoreUnknown": false, "includes": ["**"] }, + "formatter": { + "enabled": true, + "useEditorconfig": true, + "formatWithErrors": false, + "indentStyle": "space", + "indentWidth": 2, + "lineEnding": "lf", + "lineWidth": 120, + "attributePosition": "auto", + "bracketSpacing": true + }, + "linter": { "enabled": false, "rules": { "recommended": true } }, + "javascript": { + "formatter": { + "jsxQuoteStyle": "single", + "quoteProperties": "asNeeded", + "trailingCommas": "all", + "semicolons": "always", + "arrowParentheses": "always", + "bracketSameLine": false, + "quoteStyle": "single", + "attributePosition": "auto", + "bracketSpacing": true + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..96b5289 --- /dev/null +++ b/bun.lock @@ -0,0 +1,332 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "ak-endfield-api-archive", + "dependencies": { + "chalk": "^5.6.2", + "cli-table3": "^0.6.5", + "deepmerge": "^4.3.1", + "ky": "^1.14.2", + "log4js": "^6.9.1", + "luxon": "^3.7.2", + "ora": "^9.1.0", + "p-queue": "^9.1.0", + "qs": "^6.14.1", + "semver": "^7.7.3", + "uuid": "^13.0.0", + "yaml": "^2.8.2", + "yargs": "^18.0.0", + }, + "devDependencies": { + "@biomejs/biome": "^2.3.11", + "@tsconfig/bun": "^1.0.10", + "@tsconfig/node24": "^24.0.4", + "@tsconfig/recommended": "^1.0.13", + "@tsconfig/strictest": "^2.0.8", + "@types/bun": "latest", + "@types/luxon": "^3.7.1", + "@types/node": "^25.0.9", + "@types/qs": "^6.14.0", + "@types/semver": "^7.7.1", + "@types/uuid": "^11.0.0", + "@types/yargs": "^17.0.35", + "nodemon": "^3.1.11", + "oxfmt": "^0.26.0", + }, + "peerDependencies": { + "typescript": "^5", + }, + }, + }, + "packages": { + "@biomejs/biome": ["@biomejs/biome@2.3.11", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.11", "@biomejs/cli-darwin-x64": "2.3.11", "@biomejs/cli-linux-arm64": "2.3.11", "@biomejs/cli-linux-arm64-musl": "2.3.11", "@biomejs/cli-linux-x64": "2.3.11", "@biomejs/cli-linux-x64-musl": "2.3.11", "@biomejs/cli-win32-arm64": "2.3.11", "@biomejs/cli-win32-x64": "2.3.11" }, "bin": { "biome": "bin/biome" } }, "sha512-/zt+6qazBWguPG6+eWmiELqO+9jRsMZ/DBU3lfuU2ngtIQYzymocHhKiZRyrbra4aCOoyTg/BmY+6WH5mv9xmQ=="], + + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/uXXkBcPKVQY7rc9Ys2CrlirBJYbpESEDme7RKiBD6MmqR2w3j0+ZZXRIL2xiaNPsIMMNhP1YnA+jRRxoOAFrA=="], + + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-fh7nnvbweDPm2xEmFjfmq7zSUiox88plgdHF9OIW4i99WnXrAC3o2P3ag9judoUMv8FCSUnlwJCM1B64nO5Fbg=="], + + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-l4xkGa9E7Uc0/05qU2lMYfN1H+fzzkHgaJoy98wO+b/7Gl78srbCRRgwYSW+BTLixTBrM6Ede5NSBwt7rd/i6g=="], + + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-XPSQ+XIPZMLaZ6zveQdwNjbX+QdROEd1zPgMwD47zvHV+tCGB88VH+aynyGxAHdzL+Tm/+DtKST5SECs4iwCLg=="], + + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-/1s9V/H3cSe0r0Mv/Z8JryF5x9ywRxywomqZVLHAoa/uN0eY7F8gEngWKNS5vbbN/BsfpCG5yeBT5ENh50Frxg=="], + + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-vU7a8wLs5C9yJ4CB8a44r12aXYb8yYgBn+WeyzbMjaCMklzCv1oXr8x+VEyWodgJt9bDmhiaW/I0RHbn7rsNmw=="], + + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-PZQ6ElCOnkYapSsysiTy0+fYX+agXPlWugh6+eQ6uPKI3vKAqNp6TnMhoM3oY2NltSB89hz59o8xIfOdyhi9Iw=="], + + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.11", "", { "os": "win32", "cpu": "x64" }, "sha512-43VrG813EW+b5+YbDbz31uUsheX+qFKCpXeY9kfdAx+ww3naKxeVkTD9zLIWxUPfJquANMHrmW3wbe/037G0Qg=="], + + "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], + + "@oxfmt/darwin-arm64": ["@oxfmt/darwin-arm64@0.26.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-AAGc+8CffkiWeVgtWf4dPfQwHEE5c/j/8NWH7VGVxxJRCZFdmWcqCXprvL2H6qZFewvDLrFbuSPRCqYCpYGaTQ=="], + + "@oxfmt/darwin-x64": ["@oxfmt/darwin-x64@0.26.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-xFx5ijCTjw577wJvFlZEMmKDnp3HSCcbYdCsLRmC5i3TZZiDe9DEYh3P46uqhzj8BkEw1Vm1ZCWdl48aEYAzvQ=="], + + "@oxfmt/linux-arm64-gnu": ["@oxfmt/linux-arm64-gnu@0.26.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-GubkQeQT5d3B/Jx/IiR7NMkSmXrCZcVI0BPh1i7mpFi8HgD1hQ/LbhiBKAMsMqs5bbugdQOgBEl8bOhe8JhW1g=="], + + "@oxfmt/linux-arm64-musl": ["@oxfmt/linux-arm64-musl@0.26.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-OEypUwK69bFPj+aa3/LYCnlIUPgoOLu//WNcriwpnWNmt47808Ht7RJSg+MNK8a7pSZHpXJ5/E6CRK/OTwFdaQ=="], + + "@oxfmt/linux-x64-gnu": ["@oxfmt/linux-x64-gnu@0.26.0", "", { "os": "linux", "cpu": "x64" }, "sha512-xO6iEW2bC6ZHyOTPmPWrg/nM6xgzyRPaS84rATy6F8d79wz69LdRdJ3l/PXlkqhi7XoxhvX4ExysA0Nf10ZZEQ=="], + + "@oxfmt/linux-x64-musl": ["@oxfmt/linux-x64-musl@0.26.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Z3KuZFC+MIuAyFCXBHY71kCsdRq1ulbsbzTe71v+hrEv7zVBn6yzql+/AZcgfIaKzWO9OXNuz5WWLWDmVALwow=="], + + "@oxfmt/win32-arm64": ["@oxfmt/win32-arm64@0.26.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-3zRbqwVWK1mDhRhTknlQFpRFL9GhEB5GfU6U7wawnuEwpvi39q91kJ+SRJvJnhyPCARkjZBd1V8XnweN5IFd1g=="], + + "@oxfmt/win32-x64": ["@oxfmt/win32-x64@0.26.0", "", { "os": "win32", "cpu": "x64" }, "sha512-m8TfIljU22i9UEIkD+slGPifTFeaCwIUfxszN3E6ABWP1KQbtwSw9Ak0TdoikibvukF/dtbeyG3WW63jv9DnEg=="], + + "@tsconfig/bun": ["@tsconfig/bun@1.0.10", "", {}, "sha512-5AV5YknQjNyoYzZ/8NG0dawqew/wH+x7ANiCfCIn29qo0cdbd1EryvFD1k5NSZWLBMOI/fGqMIaxi58GPIP9Cg=="], + + "@tsconfig/node24": ["@tsconfig/node24@24.0.4", "", {}, "sha512-2A933l5P5oCbv6qSxHs7ckKwobs8BDAe9SJ/Xr2Hy+nDlwmLE1GhFh/g/vXGRZWgxBg9nX/5piDtHR9Dkw/XuA=="], + + "@tsconfig/recommended": ["@tsconfig/recommended@1.0.13", "", {}, "sha512-sySRuBfMKyKO/j2ZAhR8kSembhjuPEV4Ra3AHtmWLq51+iGaudr45crPSzNC5b7/Ctrh9dfUpBuTlYrH6rM58Q=="], + + "@tsconfig/strictest": ["@tsconfig/strictest@2.0.8", "", {}, "sha512-XnQ7vNz5HRN0r88GYf1J9JJjqtZPiHt2woGJOo2dYqyHGGcd6OLGqSlBB6p1j9mpzja6Oe5BoPqWmeDx6X9rLw=="], + + "@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="], + + "@types/luxon": ["@types/luxon@3.7.1", "", {}, "sha512-H3iskjFIAn5SlJU7OuxUmTEpebK6TKB8rxZShDslBMZJ5u9S//KM1sbdAisiSrqwLQncVjnpi2OK2J51h+4lsg=="], + + "@types/node": ["@types/node@25.0.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="], + + "@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/uuid": ["@types/uuid@11.0.0", "", { "dependencies": { "uuid": "*" } }, "sha512-HVyk8nj2m+jcFRNazzqyVKiZezyhDKrGUA3jlEcg/nZ6Ms+qHwocba1Y/AaVaznJTAM9xpdFSh+ptbNrhOGvZA=="], + + "@types/yargs": ["@types/yargs@17.0.35", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg=="], + + "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], + + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + + "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], + + "cli-spinners": ["cli-spinners@3.4.0", "", {}, "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw=="], + + "cli-table3": ["cli-table3@0.6.5", "", { "dependencies": { "string-width": "^4.2.0" }, "optionalDependencies": { "@colors/colors": "1.5.0" } }, "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ=="], + + "cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "date-format": ["date-format@4.0.14", "", {}, "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], + + "fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "ignore-by-default": ["ignore-by-default@1.0.1", "", {}, "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA=="], + + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="], + + "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + + "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=="], + + "log4js": ["log4js@6.9.1", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "flatted": "^3.2.7", "rfdc": "^1.3.0", "streamroller": "^3.1.5" } }, "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g=="], + + "luxon": ["luxon@3.7.2", "", {}, "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], + + "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "nodemon": ["nodemon@3.1.11", "", { "dependencies": { "chokidar": "^3.5.2", "debug": "^4", "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", "semver": "^7.5.3", "simple-update-notifier": "^2.0.0", "supports-color": "^5.5.0", "touch": "^3.1.0", "undefsafe": "^2.0.5" }, "bin": { "nodemon": "bin/nodemon.js" } }, "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], + + "ora": ["ora@9.1.0", "", { "dependencies": { "chalk": "^5.6.2", "cli-cursor": "^5.0.0", "cli-spinners": "^3.2.0", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.1.0", "log-symbols": "^7.0.1", "stdin-discarder": "^0.2.2", "string-width": "^8.1.0" } }, "sha512-53uuLsXHOAJl5zLrUrzY9/kE+uIFEx7iaH4g2BIJQK4LZjY4LpCCYZVKDWIkL+F01wAaCg93duQ1whnK/AmY1A=="], + + "oxfmt": ["oxfmt@0.26.0", "", { "dependencies": { "tinypool": "2.0.0" }, "optionalDependencies": { "@oxfmt/darwin-arm64": "0.26.0", "@oxfmt/darwin-x64": "0.26.0", "@oxfmt/linux-arm64-gnu": "0.26.0", "@oxfmt/linux-arm64-musl": "0.26.0", "@oxfmt/linux-x64-gnu": "0.26.0", "@oxfmt/linux-x64-musl": "0.26.0", "@oxfmt/win32-arm64": "0.26.0", "@oxfmt/win32-x64": "0.26.0" }, "bin": { "oxfmt": "bin/oxfmt" } }, "sha512-UDD1wFNwfeorMm2ZY0xy1KRAAvJ5NjKBfbDmiMwGP7baEHTq65cYpC0aPP+BGHc8weXUbSZaK8MdGyvuRUvS4Q=="], + + "p-queue": ["p-queue@9.1.0", "", { "dependencies": { "eventemitter3": "^5.0.1", "p-timeout": "^7.0.0" } }, "sha512-O/ZPaXuQV29uSLbxWBGGZO1mCQXV2BLIwUr59JUU9SoH76mnYvtms7aafH/isNSNGwuEfP6W/4xD0/TJXxrizw=="], + + "p-timeout": ["p-timeout@7.0.1", "", {}, "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg=="], + + "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "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=="], + + "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], + + "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], + + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "simple-update-notifier": ["simple-update-notifier@2.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w=="], + + "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=="], + + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + + "tinypool": ["tinypool@2.0.0", "", {}, "sha512-/RX9RzeH2xU5ADE7n2Ykvmi9ED3FBGPAjw9u3zucrNNaEBIO0HPSYgL0NT7+3p147ojeSdaVu08F6hjpv31HJg=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "touch": ["touch@3.1.1", "", { "bin": { "nodetouch": "bin/nodetouch.js" } }, "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "undefsafe": ["undefsafe@2.0.5", "", {}, "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA=="], + + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + + "uuid": ["uuid@13.0.0", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w=="], + + "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], + + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="], + + "yargs": ["yargs@18.0.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^7.2.0", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg=="], + + "yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], + + "yoctocolors": ["yoctocolors@2.1.2", "", {}, "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug=="], + + "cliui/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + + "cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "ora/string-width": ["string-width@8.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg=="], + + "wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + + "wrap-ansi/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "yargs/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + + "cliui/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + + "cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "ora/string-width/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + + "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "yargs/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + + "yargs/string-width/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "ora/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + } +} diff --git a/config/config.yaml b/config/config.yaml new file mode 100644 index 0000000..58851b9 --- /dev/null +++ b/config/config.yaml @@ -0,0 +1,30 @@ +network: + api: + akEndfield: + appCode: + osWinRel: YDUTE5gscDZ229CW + launcherAppCode: + osWinRel: TiaytKBUIEdoEwRT + channel: + osWinRel: 6 + base: + accountService: YXMuZ3J5cGhsaW5lLmNvbQ== + launcher: bGF1bmNoZXIuZ3J5cGhsaW5lLmNvbS9hcGk= + u8: dTguZ3J5cGhsaW5lLmNvbQ== + userAgent: + minimum: Mozilla/5.0 + chromeWindows: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 + (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 + curl: curl/8.4.0 + ios: Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 + (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1 + timeout: 20000 + retryCount: 5 +threadCount: + network: 16 +cli: + autoExit: false +logger: + logLevel: 0 + useCustomLayout: true + customLayoutPattern: "%[%d{hh:mm:ss.SSS} %-5.0p >%] %m" diff --git a/output/akEndfield/launcher/game/6/all.json b/output/akEndfield/launcher/game/6/all.json new file mode 100644 index 0000000..f9c4065 --- /dev/null +++ b/output/akEndfield/launcher/game/6/all.json @@ -0,0 +1,212 @@ +[ + { + "updatedAt": "2026-01-22T17:31:25.044+09:00", + "req": { + "appCode": "YDUTE5gscDZ229CW", + "launcherAppCode": "TiaytKBUIEdoEwRT", + "channel": 6, + "subChannel": 6, + "launcherSubChannel": 6 + }, + "rsp": { + "action": 1, + "version": "1.0.13", + "request_version": "", + "pkg": { + "packs": [ + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.001", + "md5": "a9293f997725d61d71187c57209e636e", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.002", + "md5": "02c003418063205264e5aee87e36f9cb", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.003", + "md5": "9d5cf81af11b85b0367344317cbf5e9f", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.004", + "md5": "dc0d26102e181de1a22b4f3094318a08", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.005", + "md5": "da021e3d3e75ac991778eca3aa90e6cc", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.006", + "md5": "f82ce5ea69d62ffe262c3950a595883e", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.007", + "md5": "e58bb7f771e83821ad634ace3c526698", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.008", + "md5": "7239c3f35d3abad970eceef387c05572", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.009", + "md5": "ce8087310741f0ab07019f4dc783c525", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.010", + "md5": "037649cb0c44b5b10498e4a1ce60dece", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.011", + "md5": "436e2bf3dd2760fb76d8026a7952cf35", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.012", + "md5": "3001d1cbfaa53f8be93be410bcc1780d", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.013", + "md5": "dd1d9a851caf1d4c0970695d99e4b8ac", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.014", + "md5": "5c170b17e37631b5859ef3fb9a46ec60", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.015", + "md5": "4796753e929d523351fd763968d2d7c3", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.016", + "md5": "0287f48269c73ef89da165e633e084d3", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.017", + "md5": "fd3041f85e74b2089d6ff2d740de9785", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.018", + "md5": "693b185f634ba58cd0dd442eb413827f", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.019", + "md5": "f10d3a8d3ef155bd6d2e4613b5e0e6fc", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.020", + "md5": "d8934b6db9372c4876ca5f1e623875ca", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.021", + "md5": "cbb96b0248fa01c42b657899a850b291", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.022", + "md5": "3e73fcef3b876467011df062e7a34b4b", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.023", + "md5": "c34300069b5583b418a10b70cab436eb", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.024", + "md5": "19b5cafa5fe8af5549fbe3a50a79ef5a", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.025", + "md5": "0a32c4951d576d02fd121aa9155f3233", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.026", + "md5": "be4383a5cbbfeb8fe7b0a7c47e3bd5ec", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.027", + "md5": "2264449764ed50609415a12c97e3b2fe", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.028", + "md5": "c7b298c5eed57379465cc6683de69f3d", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.029", + "md5": "fedaf3f16eb3e7daec12c9d617b608cd", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.030", + "md5": "1f6a074fe86e49a93adb0eb3719d7d0a", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.031", + "md5": "a18df89af4fdf15c3d0c529c44634120", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.032", + "md5": "46210e8a82e41c2562ee34bf67d3ab32", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.033", + "md5": "f3bc56bbcc7cec7a7eabb6dcc8f75ccc", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.034", + "md5": "fa540c8f605d3e748c8f94889e6880f0", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.035", + "md5": "16c65c2d5db089f7b3bdb4da64aa0807", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.036", + "md5": "9d95ea1486e5cf51d3adf555660a0de6", + "package_size": "498841721" + } + ], + "total_size": "83929662707", + "file_path": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/files", + "url": "", + "md5": "", + "package_size": "0", + "file_id": "0", + "sub_channel": "6", + "game_files_md5": "51c60b7a0ce37270a65dee790c531f02" + }, + "patch": null, + "state": 0, + "launcher_action": 0 + } + } +] diff --git a/output/akEndfield/launcher/game/6/latest.json b/output/akEndfield/launcher/game/6/latest.json new file mode 100644 index 0000000..e4734af --- /dev/null +++ b/output/akEndfield/launcher/game/6/latest.json @@ -0,0 +1,209 @@ +{ + "req": { + "appCode": "YDUTE5gscDZ229CW", + "launcherAppCode": "TiaytKBUIEdoEwRT", + "channel": 6, + "subChannel": 6, + "launcherSubChannel": 6 + }, + "rsp": { + "action": 1, + "version": "1.0.13", + "request_version": "", + "pkg": { + "packs": [ + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.001", + "md5": "a9293f997725d61d71187c57209e636e", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.002", + "md5": "02c003418063205264e5aee87e36f9cb", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.003", + "md5": "9d5cf81af11b85b0367344317cbf5e9f", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.004", + "md5": "dc0d26102e181de1a22b4f3094318a08", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.005", + "md5": "da021e3d3e75ac991778eca3aa90e6cc", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.006", + "md5": "f82ce5ea69d62ffe262c3950a595883e", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.007", + "md5": "e58bb7f771e83821ad634ace3c526698", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.008", + "md5": "7239c3f35d3abad970eceef387c05572", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.009", + "md5": "ce8087310741f0ab07019f4dc783c525", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.010", + "md5": "037649cb0c44b5b10498e4a1ce60dece", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.011", + "md5": "436e2bf3dd2760fb76d8026a7952cf35", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.012", + "md5": "3001d1cbfaa53f8be93be410bcc1780d", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.013", + "md5": "dd1d9a851caf1d4c0970695d99e4b8ac", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.014", + "md5": "5c170b17e37631b5859ef3fb9a46ec60", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.015", + "md5": "4796753e929d523351fd763968d2d7c3", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.016", + "md5": "0287f48269c73ef89da165e633e084d3", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.017", + "md5": "fd3041f85e74b2089d6ff2d740de9785", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.018", + "md5": "693b185f634ba58cd0dd442eb413827f", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.019", + "md5": "f10d3a8d3ef155bd6d2e4613b5e0e6fc", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.020", + "md5": "d8934b6db9372c4876ca5f1e623875ca", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.021", + "md5": "cbb96b0248fa01c42b657899a850b291", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.022", + "md5": "3e73fcef3b876467011df062e7a34b4b", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.023", + "md5": "c34300069b5583b418a10b70cab436eb", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.024", + "md5": "19b5cafa5fe8af5549fbe3a50a79ef5a", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.025", + "md5": "0a32c4951d576d02fd121aa9155f3233", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.026", + "md5": "be4383a5cbbfeb8fe7b0a7c47e3bd5ec", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.027", + "md5": "2264449764ed50609415a12c97e3b2fe", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.028", + "md5": "c7b298c5eed57379465cc6683de69f3d", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.029", + "md5": "fedaf3f16eb3e7daec12c9d617b608cd", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.030", + "md5": "1f6a074fe86e49a93adb0eb3719d7d0a", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.031", + "md5": "a18df89af4fdf15c3d0c529c44634120", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.032", + "md5": "46210e8a82e41c2562ee34bf67d3ab32", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.033", + "md5": "f3bc56bbcc7cec7a7eabb6dcc8f75ccc", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.034", + "md5": "fa540c8f605d3e748c8f94889e6880f0", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.035", + "md5": "16c65c2d5db089f7b3bdb4da64aa0807", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.036", + "md5": "9d95ea1486e5cf51d3adf555660a0de6", + "package_size": "498841721" + } + ], + "total_size": "83929662707", + "file_path": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/files", + "url": "", + "md5": "", + "package_size": "0", + "file_id": "0", + "sub_channel": "6", + "game_files_md5": "51c60b7a0ce37270a65dee790c531f02" + }, + "patch": null, + "state": 0, + "launcher_action": 0 + } +} diff --git a/output/akEndfield/launcher/game/6/v1.0.13.json b/output/akEndfield/launcher/game/6/v1.0.13.json new file mode 100644 index 0000000..e4734af --- /dev/null +++ b/output/akEndfield/launcher/game/6/v1.0.13.json @@ -0,0 +1,209 @@ +{ + "req": { + "appCode": "YDUTE5gscDZ229CW", + "launcherAppCode": "TiaytKBUIEdoEwRT", + "channel": 6, + "subChannel": 6, + "launcherSubChannel": 6 + }, + "rsp": { + "action": 1, + "version": "1.0.13", + "request_version": "", + "pkg": { + "packs": [ + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.001", + "md5": "a9293f997725d61d71187c57209e636e", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.002", + "md5": "02c003418063205264e5aee87e36f9cb", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.003", + "md5": "9d5cf81af11b85b0367344317cbf5e9f", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.004", + "md5": "dc0d26102e181de1a22b4f3094318a08", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.005", + "md5": "da021e3d3e75ac991778eca3aa90e6cc", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.006", + "md5": "f82ce5ea69d62ffe262c3950a595883e", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.007", + "md5": "e58bb7f771e83821ad634ace3c526698", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.008", + "md5": "7239c3f35d3abad970eceef387c05572", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.009", + "md5": "ce8087310741f0ab07019f4dc783c525", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.010", + "md5": "037649cb0c44b5b10498e4a1ce60dece", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.011", + "md5": "436e2bf3dd2760fb76d8026a7952cf35", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.012", + "md5": "3001d1cbfaa53f8be93be410bcc1780d", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.013", + "md5": "dd1d9a851caf1d4c0970695d99e4b8ac", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.014", + "md5": "5c170b17e37631b5859ef3fb9a46ec60", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.015", + "md5": "4796753e929d523351fd763968d2d7c3", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.016", + "md5": "0287f48269c73ef89da165e633e084d3", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.017", + "md5": "fd3041f85e74b2089d6ff2d740de9785", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.018", + "md5": "693b185f634ba58cd0dd442eb413827f", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.019", + "md5": "f10d3a8d3ef155bd6d2e4613b5e0e6fc", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.020", + "md5": "d8934b6db9372c4876ca5f1e623875ca", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.021", + "md5": "cbb96b0248fa01c42b657899a850b291", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.022", + "md5": "3e73fcef3b876467011df062e7a34b4b", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.023", + "md5": "c34300069b5583b418a10b70cab436eb", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.024", + "md5": "19b5cafa5fe8af5549fbe3a50a79ef5a", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.025", + "md5": "0a32c4951d576d02fd121aa9155f3233", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.026", + "md5": "be4383a5cbbfeb8fe7b0a7c47e3bd5ec", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.027", + "md5": "2264449764ed50609415a12c97e3b2fe", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.028", + "md5": "c7b298c5eed57379465cc6683de69f3d", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.029", + "md5": "fedaf3f16eb3e7daec12c9d617b608cd", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.030", + "md5": "1f6a074fe86e49a93adb0eb3719d7d0a", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.031", + "md5": "a18df89af4fdf15c3d0c529c44634120", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.032", + "md5": "46210e8a82e41c2562ee34bf67d3ab32", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.033", + "md5": "f3bc56bbcc7cec7a7eabb6dcc8f75ccc", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.034", + "md5": "fa540c8f605d3e748c8f94889e6880f0", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.035", + "md5": "16c65c2d5db089f7b3bdb4da64aa0807", + "package_size": "1073741824" + }, + { + "url": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/packs/Beyond_Release_v1d0-Rel-os-5157154-10_prod_obt_official.zip.036", + "md5": "9d95ea1486e5cf51d3adf555660a0de6", + "package_size": "498841721" + } + ], + "total_size": "83929662707", + "file_path": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/update/6/6/Windows/1.0.13_i5QZm30fLgOWSldR/files", + "url": "", + "md5": "", + "package_size": "0", + "file_id": "0", + "sub_channel": "6", + "game_files_md5": "51c60b7a0ce37270a65dee790c531f02" + }, + "patch": null, + "state": 0, + "launcher_action": 0 + } +} diff --git a/output/akEndfield/launcher/game_resources/6/all.json b/output/akEndfield/launcher/game_resources/6/all.json new file mode 100644 index 0000000..f8b736a --- /dev/null +++ b/output/akEndfield/launcher/game_resources/6/all.json @@ -0,0 +1,29 @@ +[ + { + "updatedAt": "2026-01-22T18:32:24.241+09:00", + "req": { + "appCode": "YDUTE5gscDZ229CW", + "gameVersion": "1.0", + "version": "1.0.13", + "randStr": "i5QZm30fLgOWSldR" + }, + "rsp": { + "resources": [ + { + "name": "main", + "version": "5327933-13", + "path": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/resource/Windows/main/5327933-13_pYX1R4dE1CSyfylE/files" + }, + { + "name": "initial", + "version": "5327933-13", + "path": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/resource/Windows/initial/5327933-13_MxibWISDlHu4FYDu/files" + } + ], + "configs": "{\"kick_flag\":false}", + "res_version": "initial_5327933-13_main_5327933-13", + "patch_index_path": "", + "domain": "https://beyond.hg-cdn.com" + } + } +] diff --git a/output/akEndfield/launcher/game_resources/6/latest.json b/output/akEndfield/launcher/game_resources/6/latest.json new file mode 100644 index 0000000..af157e8 --- /dev/null +++ b/output/akEndfield/launcher/game_resources/6/latest.json @@ -0,0 +1,26 @@ +{ + "req": { + "appCode": "YDUTE5gscDZ229CW", + "gameVersion": "1.0", + "version": "1.0.13", + "randStr": "i5QZm30fLgOWSldR" + }, + "rsp": { + "resources": [ + { + "name": "main", + "version": "5327933-13", + "path": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/resource/Windows/main/5327933-13_pYX1R4dE1CSyfylE/files" + }, + { + "name": "initial", + "version": "5327933-13", + "path": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/resource/Windows/initial/5327933-13_MxibWISDlHu4FYDu/files" + } + ], + "configs": "{\"kick_flag\":false}", + "res_version": "initial_5327933-13_main_5327933-13", + "patch_index_path": "", + "domain": "https://beyond.hg-cdn.com" + } +} diff --git a/output/akEndfield/launcher/game_resources/6/v1.0.13.json b/output/akEndfield/launcher/game_resources/6/v1.0.13.json new file mode 100644 index 0000000..af157e8 --- /dev/null +++ b/output/akEndfield/launcher/game_resources/6/v1.0.13.json @@ -0,0 +1,26 @@ +{ + "req": { + "appCode": "YDUTE5gscDZ229CW", + "gameVersion": "1.0", + "version": "1.0.13", + "randStr": "i5QZm30fLgOWSldR" + }, + "rsp": { + "resources": [ + { + "name": "main", + "version": "5327933-13", + "path": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/resource/Windows/main/5327933-13_pYX1R4dE1CSyfylE/files" + }, + { + "name": "initial", + "version": "5327933-13", + "path": "https://beyond.hg-cdn.com/YDUTE5gscDZ229CW/1.0/resource/Windows/initial/5327933-13_MxibWISDlHu4FYDu/files" + } + ], + "configs": "{\"kick_flag\":false}", + "res_version": "initial_5327933-13_main_5327933-13", + "patch_index_path": "", + "domain": "https://beyond.hg-cdn.com" + } +} diff --git a/output/akEndfield/launcher/launcher/EndField/6/all.json b/output/akEndfield/launcher/launcher/EndField/6/all.json new file mode 100644 index 0000000..6dc1fe2 --- /dev/null +++ b/output/akEndfield/launcher/launcher/EndField/6/all.json @@ -0,0 +1,21 @@ +[ + { + "updatedAt": "2026-01-22T18:44:29.086+09:00", + "req": { + "appCode": "TiaytKBUIEdoEwRT", + "channel": 6, + "subChannel": 6, + "targetApp": "EndField" + }, + "rsp": { + "action": 1, + "version": "1.0.0", + "request_version": "", + "zip_package_url": "https://launcher.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.0.0/6/6/D6KGicSF/GRYPHLINK_1.0.0_6_6_official.zip", + "md5": "fe71ba125d1b1c30d4bf1c05d7af4be6", + "package_size": "111189744", + "total_size": "360836427", + "description": "" + } + } +] \ No newline at end of file diff --git a/output/akEndfield/launcher/launcher/EndField/6/latest.json b/output/akEndfield/launcher/launcher/EndField/6/latest.json new file mode 100644 index 0000000..1e27b3c --- /dev/null +++ b/output/akEndfield/launcher/launcher/EndField/6/latest.json @@ -0,0 +1,18 @@ +{ + "req": { + "appCode": "TiaytKBUIEdoEwRT", + "channel": 6, + "subChannel": 6, + "targetApp": "EndField" + }, + "rsp": { + "action": 1, + "version": "1.0.0", + "request_version": "", + "zip_package_url": "https://launcher.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.0.0/6/6/D6KGicSF/GRYPHLINK_1.0.0_6_6_official.zip", + "md5": "fe71ba125d1b1c30d4bf1c05d7af4be6", + "package_size": "111189744", + "total_size": "360836427", + "description": "" + } +} \ No newline at end of file diff --git a/output/akEndfield/launcher/launcher/EndField/6/v1.0.0.json b/output/akEndfield/launcher/launcher/EndField/6/v1.0.0.json new file mode 100644 index 0000000..1e27b3c --- /dev/null +++ b/output/akEndfield/launcher/launcher/EndField/6/v1.0.0.json @@ -0,0 +1,18 @@ +{ + "req": { + "appCode": "TiaytKBUIEdoEwRT", + "channel": 6, + "subChannel": 6, + "targetApp": "EndField" + }, + "rsp": { + "action": 1, + "version": "1.0.0", + "request_version": "", + "zip_package_url": "https://launcher.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.0.0/6/6/D6KGicSF/GRYPHLINK_1.0.0_6_6_official.zip", + "md5": "fe71ba125d1b1c30d4bf1c05d7af4be6", + "package_size": "111189744", + "total_size": "360836427", + "description": "" + } +} \ No newline at end of file diff --git a/output/akEndfield/launcher/launcher/official/6/all.json b/output/akEndfield/launcher/launcher/official/6/all.json new file mode 100644 index 0000000..856587b --- /dev/null +++ b/output/akEndfield/launcher/launcher/official/6/all.json @@ -0,0 +1,21 @@ +[ + { + "updatedAt": "2026-01-22T18:44:47.563+09:00", + "req": { + "appCode": "TiaytKBUIEdoEwRT", + "channel": 6, + "subChannel": 6, + "targetApp": null + }, + "rsp": { + "action": 1, + "version": "1.0.0", + "request_version": "", + "zip_package_url": "https://launcher.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.0.0/6/6/D6KGicSF/GRYPHLINK_1.0.0_6_6_official.zip", + "md5": "fe71ba125d1b1c30d4bf1c05d7af4be6", + "package_size": "111189744", + "total_size": "360836427", + "description": "" + } + } +] \ No newline at end of file diff --git a/output/akEndfield/launcher/launcher/official/6/latest.json b/output/akEndfield/launcher/launcher/official/6/latest.json new file mode 100644 index 0000000..b1fa277 --- /dev/null +++ b/output/akEndfield/launcher/launcher/official/6/latest.json @@ -0,0 +1,18 @@ +{ + "req": { + "appCode": "TiaytKBUIEdoEwRT", + "channel": 6, + "subChannel": 6, + "targetApp": null + }, + "rsp": { + "action": 1, + "version": "1.0.0", + "request_version": "", + "zip_package_url": "https://launcher.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.0.0/6/6/D6KGicSF/GRYPHLINK_1.0.0_6_6_official.zip", + "md5": "fe71ba125d1b1c30d4bf1c05d7af4be6", + "package_size": "111189744", + "total_size": "360836427", + "description": "" + } +} \ No newline at end of file diff --git a/output/akEndfield/launcher/launcher/official/6/v1.0.0.json b/output/akEndfield/launcher/launcher/official/6/v1.0.0.json new file mode 100644 index 0000000..b1fa277 --- /dev/null +++ b/output/akEndfield/launcher/launcher/official/6/v1.0.0.json @@ -0,0 +1,18 @@ +{ + "req": { + "appCode": "TiaytKBUIEdoEwRT", + "channel": 6, + "subChannel": 6, + "targetApp": null + }, + "rsp": { + "action": 1, + "version": "1.0.0", + "request_version": "", + "zip_package_url": "https://launcher.hg-cdn.com/TiaytKBUIEdoEwRT/launcher/1.0.0/6/6/D6KGicSF/GRYPHLINK_1.0.0_6_6_official.zip", + "md5": "fe71ba125d1b1c30d4bf1c05d7af4be6", + "package_size": "111189744", + "total_size": "360836427", + "description": "" + } +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..cd53f97 --- /dev/null +++ b/package.json @@ -0,0 +1,52 @@ +{ + "name": "ak-endfield-api-archive", + "version": "0.1.0", + "description": "Arknights Endfield game API response archive", + "author": "daydreamer-json (https://github.com/daydreamer-json)", + "license": "AGPL-3.0-or-later", + "module": "src/main.ts", + "type": "module", + "private": true, + "repository": { + "type": "git", + "url": "git+https://github.com/daydreamer-json/ak-endfield-api-archive.git" + }, + "scripts": { + "format": "bun x biome format --write src && bun x oxfmt", + "start": "bun x biome format --write src && bun x oxfmt && bun src/main.ts" + }, + "dependencies": { + "chalk": "^5.6.2", + "cli-table3": "^0.6.5", + "deepmerge": "^4.3.1", + "ky": "^1.14.2", + "log4js": "^6.9.1", + "luxon": "^3.7.2", + "ora": "^9.1.0", + "p-queue": "^9.1.0", + "qs": "^6.14.1", + "semver": "^7.7.3", + "uuid": "^13.0.0", + "yaml": "^2.8.2", + "yargs": "^18.0.0" + }, + "devDependencies": { + "@biomejs/biome": "^2.3.11", + "@tsconfig/bun": "^1.0.10", + "@tsconfig/node24": "^24.0.4", + "@tsconfig/recommended": "^1.0.13", + "@tsconfig/strictest": "^2.0.8", + "@types/bun": "latest", + "@types/luxon": "^3.7.1", + "@types/node": "^25.0.9", + "@types/qs": "^6.14.0", + "@types/semver": "^7.7.1", + "@types/uuid": "^11.0.0", + "@types/yargs": "^17.0.35", + "nodemon": "^3.1.11", + "oxfmt": "^0.26.0" + }, + "peerDependencies": { + "typescript": "^5" + } +} diff --git a/src/cmd.ts b/src/cmd.ts new file mode 100644 index 0000000..b35d09d --- /dev/null +++ b/src/cmd.ts @@ -0,0 +1,76 @@ +import yargs from 'yargs'; +import { hideBin } from 'yargs/helpers'; +import cmds from './cmds.js'; +import * as TypesLogLevels from './types/LogLevels.js'; +import argvUtils from './utils/argv.js'; +import appConfig from './utils/config.js'; +import configEmbed from './utils/configEmbed.js'; +import exitUtils from './utils/exit.js'; +import logger from './utils/logger.js'; + +if (configEmbed.VERSION_NUMBER === null) throw new Error('Embed VERSION_NUMBER is null'); + +function wrapHandler(handler: (argv: any) => Promise) { + return async (argv: any) => { + try { + await handler(argv); + await exitUtils.exit(0); + } catch (error) { + logger.error('Error caught:', error); + await exitUtils.exit(1); + } + }; +} + +async function parseCommand() { + const yargsInstance = yargs(hideBin(process.argv)); + await yargsInstance + .command( + ['test'], + 'Test command', + (yargs) => { + yargs.options({ + 'output-dir': { + alias: ['o'], + desc: 'Output root directory', + default: appConfig.file.outputDirPath, + normalize: true, + type: 'string', + }, + }); + }, + wrapHandler(cmds.test), + ) + .options({ + 'log-level': { + desc: 'Set log level (' + TypesLogLevels.LOG_LEVELS_NUM.join(', ') + ')', + default: appConfig.logger.logLevel, + type: 'number', + coerce: (arg: number): TypesLogLevels.LogLevelString => { + if (arg < TypesLogLevels.LOG_LEVELS_NUM[0] || arg > TypesLogLevels.LOG_LEVELS_NUM.slice(-1)[0]!) { + throw new Error(`Invalid log level: ${arg} (Expected: ${TypesLogLevels.LOG_LEVELS_NUM.join(', ')})`); + } else { + return TypesLogLevels.LOG_LEVELS[arg as TypesLogLevels.LogLevelNumber]; + } + }, + }, + }) + .middleware(async (argv) => { + argvUtils.setArgv(argv); + logger.level = argvUtils.getArgv()['logLevel']; + logger.trace('Process started: ' + `${configEmbed.APPLICATION_NAME} v${configEmbed.VERSION_NUMBER}`); + }) + .scriptName(configEmbed.APPLICATION_NAME) + .version(String(configEmbed.VERSION_NUMBER)) + .usage('$0 [argument] [option]') + .help() + .alias('help', 'h') + .alias('help', '?') + .alias('version', 'V') + .demandCommand(1) + .strict() + .recommendCommands() + .parse(); +} + +export default parseCommand; diff --git a/src/cmds.ts b/src/cmds.ts new file mode 100644 index 0000000..bfe883f --- /dev/null +++ b/src/cmds.ts @@ -0,0 +1,5 @@ +import test from './cmds/test.js'; + +export default { + test, +}; diff --git a/src/cmds/test.ts b/src/cmds/test.ts new file mode 100644 index 0000000..19e0784 --- /dev/null +++ b/src/cmds/test.ts @@ -0,0 +1,236 @@ +import path from 'node:path'; +import { DateTime } from 'luxon'; +import semver from 'semver'; +import apiUtils from '../utils/api.js'; +import argvUtils from '../utils/argv.js'; +import appConfig from '../utils/config.js'; +import logger from '../utils/logger.js'; + +async function mainCmdHandler() { + const cfg = appConfig.network.api.akEndfield; + + await (async () => { + const channel = appConfig.network.api.akEndfield.channel.osWinRel; + logger.debug('apiAkEndfield.launcher.latestGame fetching ...'); + console.log( + await apiUtils.apiAkEndfield.launcher.latestGame( + appConfig.network.api.akEndfield.appCode.osWinRel, + appConfig.network.api.akEndfield.launcherAppCode.osWinRel, + channel, + channel, + channel, + null, + ), + ); + logger.debug('apiAkEndfield.launcher.latestLauncher fetching ...'); + console.log( + await apiUtils.apiAkEndfield.launcher.latestLauncher( + appConfig.network.api.akEndfield.launcherAppCode.osWinRel, + channel, + channel, + null, + null, + ), + ); + logger.debug('apiAkEndfield.launcher.web fetching ...'); + for (const fn of [ + apiUtils.apiAkEndfield.launcher.web.sidebar, + apiUtils.apiAkEndfield.launcher.web.singleEnt, + apiUtils.apiAkEndfield.launcher.web.mainBgImage, + apiUtils.apiAkEndfield.launcher.web.banner, + apiUtils.apiAkEndfield.launcher.web.announcement, + ]) { + console.dir(await fn(appConfig.network.api.akEndfield.appCode.osWinRel, channel, channel, 'ja-jp'), { + depth: null, + }); + } + })(); + + await (async () => { + const rsp = await apiUtils.apiAkEndfield.launcher.latestGame( + cfg.appCode.osWinRel, + cfg.launcherAppCode.osWinRel, + cfg.channel.osWinRel, + cfg.channel.osWinRel, + cfg.channel.osWinRel, + null, + ); + const prettyRsp = { + req: { + appCode: cfg.appCode.osWinRel, + launcherAppCode: cfg.launcherAppCode.osWinRel, + channel: cfg.channel.osWinRel, + subChannel: cfg.channel.osWinRel, + launcherSubChannel: cfg.channel.osWinRel, + }, + rsp, + }; + const filePathBase = path.join( + argvUtils.getArgv()['outputDir'], + 'akEndfield', + 'launcher', + 'game', + String(cfg.channel.osWinRel), + ); + for (const filePath of [path.join(filePathBase, 'latest.json'), path.join(filePathBase, `v${rsp.version}.json`)]) { + if ( + (await Bun.file(filePath).exists()) === false || + JSON.stringify(await Bun.file(filePath).json()) !== JSON.stringify(prettyRsp) + ) { + await Bun.write(filePath, JSON.stringify(prettyRsp, null, 2)); + } + } + await (async () => { + let needWrite: boolean = true; + const tmp: ({ updatedAt: string } & typeof prettyRsp)[] = await Bun.file( + path.join(filePathBase, 'all.json'), + ).json(); + for (const dataStr of tmp.map((e) => JSON.stringify({ req: e.req, rsp: e.rsp }))) { + if (dataStr === JSON.stringify(prettyRsp)) { + needWrite = false; + } + } + if (needWrite) { + tmp.push({ updatedAt: DateTime.now().toISO(), ...prettyRsp }); + await Bun.write(path.join(filePathBase, 'all.json'), JSON.stringify(tmp, null, 2)); + } + })(); + })(); + + await (async () => { + const versionInfoList = ( + ( + await Bun.file( + path.join( + argvUtils.getArgv()['outputDir'], + 'akEndfield', + 'launcher', + 'game', + String(cfg.channel.osWinRel), + 'all.json', + ), + ).json() + ).map((e: any) => e.rsp) as Awaited>[] + ) + .map((e) => ({ + version: e.version, + versionMinor: semver.major(e.version) + '.' + semver.minor(e.version), + randStr: /_([^/]+)\/.+?$/.exec(e.pkg.file_path)![1], + })) + .sort((a, b) => semver.compare(b.version, a.version)); + const filePathBase = path.join( + argvUtils.getArgv()['outputDir'], + 'akEndfield', + 'launcher', + 'game_resources', + String(cfg.channel.osWinRel), + ); + let isLatestWrote: boolean = false; + for (const versionInfoEntry of versionInfoList) { + if (!versionInfoEntry.randStr) throw new Error('version rand_str not found'); + const rsp = await apiUtils.apiAkEndfield.launcher.latestGameResources( + cfg.appCode.osWinRel, + versionInfoEntry.versionMinor, + versionInfoEntry.version, + versionInfoEntry.randStr, + ); + const prettyRsp = { + req: { + appCode: cfg.appCode.osWinRel, + gameVersion: versionInfoEntry.versionMinor, + version: versionInfoEntry.version, + randStr: versionInfoEntry.randStr, + }, + rsp, + }; + if (isLatestWrote === false) { + if ( + (await Bun.file(path.join(filePathBase, 'latest.json')).exists()) === false || + JSON.stringify(await Bun.file(path.join(filePathBase, 'latest.json')).json()) !== JSON.stringify(prettyRsp) + ) { + await Bun.write(path.join(filePathBase, 'latest.json'), JSON.stringify(prettyRsp, null, 2)); + } + isLatestWrote = true; + } + for (const filePath of [path.join(filePathBase, `v${versionInfoEntry.version}.json`)]) { + if ( + (await Bun.file(filePath).exists()) === false || + JSON.stringify(await Bun.file(filePath).json()) !== JSON.stringify(prettyRsp) + ) { + await Bun.write(filePath, JSON.stringify(prettyRsp, null, 2)); + } + } + await (async () => { + let needWrite: boolean = true; + const tmp: ({ updatedAt: string } & typeof prettyRsp)[] = await Bun.file( + path.join(filePathBase, 'all.json'), + ).json(); + for (const dataStr of tmp.map((e) => JSON.stringify({ req: e.req, rsp: e.rsp }))) { + if (dataStr === JSON.stringify(prettyRsp)) needWrite = false; + } + if (needWrite) { + tmp.push({ updatedAt: DateTime.now().toISO(), ...prettyRsp }); + await Bun.write(path.join(filePathBase, 'all.json'), JSON.stringify(tmp, null, 2)); + } + })(); + } + })(); + + await (async () => { + const launcherTargetAppList = ['EndField', 'official'] as const; + for (const launcherTargetAppEntry of launcherTargetAppList) { + const rsp = await apiUtils.apiAkEndfield.launcher.latestLauncher( + cfg.launcherAppCode.osWinRel, + cfg.channel.osWinRel, + cfg.channel.osWinRel, + null, + launcherTargetAppEntry === 'official' ? null : launcherTargetAppEntry, + ); + const prettyRsp = { + req: { + appCode: cfg.launcherAppCode.osWinRel, + channel: cfg.channel.osWinRel, + subChannel: cfg.channel.osWinRel, + targetApp: launcherTargetAppEntry === 'official' ? null : launcherTargetAppEntry, + }, + rsp, + }; + const filePathBase = path.join( + argvUtils.getArgv()['outputDir'], + 'akEndfield', + 'launcher', + 'launcher', + launcherTargetAppEntry, + String(cfg.channel.osWinRel), + ); + for (const filePath of [ + path.join(filePathBase, 'latest.json'), + path.join(filePathBase, `v${rsp.version}.json`), + ]) { + if ( + (await Bun.file(filePath).exists()) === false || + JSON.stringify(await Bun.file(filePath).json()) !== JSON.stringify(prettyRsp) + ) { + await Bun.write(filePath, JSON.stringify(prettyRsp, null, 2)); + } + } + await (async () => { + let needWrite: boolean = true; + const tmp: ({ updatedAt: string } & typeof prettyRsp)[] = await Bun.file( + path.join(filePathBase, 'all.json'), + ).json(); + for (const dataStr of tmp.map((e) => JSON.stringify({ req: e.req, rsp: e.rsp }))) { + if (dataStr === JSON.stringify(prettyRsp)) { + needWrite = false; + } + } + if (needWrite) { + tmp.push({ updatedAt: DateTime.now().toISO(), ...prettyRsp }); + await Bun.write(path.join(filePathBase, 'all.json'), JSON.stringify(tmp, null, 2)); + } + })(); + } + })(); +} + +export default mainCmdHandler; diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..29c3cee --- /dev/null +++ b/src/main.ts @@ -0,0 +1,18 @@ +#!/usr/bin/env node + +import childProcess from 'node:child_process'; +import util from 'node:util'; +import parseCommand from './cmd.js'; +import exitUtils from './utils/exit.js'; + +async function main(): Promise { + try { + process.platform === 'win32' ? await util.promisify(childProcess.exec)('chcp 65001') : undefined; + await parseCommand(); + } catch (error) { + console.log(error); + exitUtils.pressAnyKeyToExit(1); + } +} + +await main(); diff --git a/src/types/LogLevels.ts b/src/types/LogLevels.ts new file mode 100644 index 0000000..920906e --- /dev/null +++ b/src/types/LogLevels.ts @@ -0,0 +1,15 @@ +const LOG_LEVELS = { + 0: 'trace', + 1: 'debug', + 2: 'info', + 3: 'warn', + 4: 'error', + 5: 'fatal', +} as const; +const LOG_LEVELS_NUM = [0, 1, 2, 3, 4, 5] as const; + +type LogLevelNumber = keyof typeof LOG_LEVELS; +type LogLevelString = (typeof LOG_LEVELS)[LogLevelNumber]; + +export type { LogLevelNumber, LogLevelString }; +export { LOG_LEVELS, LOG_LEVELS_NUM }; diff --git a/src/types/api/akEndfield/Api.ts b/src/types/api/akEndfield/Api.ts new file mode 100644 index 0000000..3d10c20 --- /dev/null +++ b/src/types/api/akEndfield/Api.ts @@ -0,0 +1,118 @@ +type LauncherLatestGame = { + action: number; + version: string; // x.y.z + request_version: string; // x.y.z or blank + pkg: { + packs: { + url: string; + md5: string; + package_size: string; + }[]; + total_size: string; + file_path: string; + url: string; + md5: string; + package_size: string; + file_id: string; + sub_channel: string; + game_files_md5: string; + }; + patch: unknown; + state: number; + launcher_action: number; +}; + +type LauncherLatestGameResources = { + resources: { + name: string; + version: string; + path: string; + }[]; + configs: string; // json str + res_version: string; + patch_index_path: string; + domain: string; +}; + +type LauncherLatestLauncher = { + action: number; + version: string; // x.y.z + request_version: string; // x.y.z or blank + zip_package_url: string; + md5: string; + package_size: string; + total_size: string; + description: string; +}; + +type LauncherWebSidebar = { + data_version: string; + sidebars: { + display_type: 'DisplayType_RESERVE'; + media: string; + pic: { url: string; md5: string; description: string } | null; + sidebar_labels: { content: string; jump_url: string; need_token: boolean }[]; + grid_info: null; + jump_url: string; + need_token: boolean; + }[]; +}; + +type LauncherWebSingleEnt = { + single_ent: { + version_url: string; + version_md5: string; + jump_url: string; + button_url: string; + button_md5: string; + button_hover_url: string; + button_hover_md5: string; + need_token: boolean; + }; +}; + +type LauncherWebMainBgImage = { + data_version: string; + main_bg_image: { + url: string; + md5: string; + video_url: string; + }; +}; + +type LauncherWebBanner = { + data_version: string; + banners: { + url: string; + md5: string; + jump_url: string; + id: string; + need_token: boolean; + }[]; +}; + +type LauncherWebAnnouncement = { + data_version: string; + tabs: { + tabName: string; + announcements: { + content: string; + jump_url: string; + start_ts: string; // example: 1768969800000 + id: string; + need_token: boolean; + }[]; + tab_id: string; + }[]; +}; + +export type { + LauncherLatestGame, + LauncherLatestGameResources, + LauncherLatestLauncher, + LauncherWebSidebar, + LauncherWebSingleEnt, + LauncherWebMainBgImage, + LauncherWebBanner, + LauncherWebAnnouncement, +}; diff --git a/src/utils/api.ts b/src/utils/api.ts new file mode 100644 index 0000000..9a9312c --- /dev/null +++ b/src/utils/api.ts @@ -0,0 +1,252 @@ +import ky from 'ky'; +import semver from 'semver'; +import * as TypesApiAkEndfield from '../types/api/akEndfield/api.js'; +import appConfig from './config.js'; + +const defaultKySettings = { + headers: { + 'User-Agent': appConfig.network.userAgent.minimum, + }, + timeout: appConfig.network.timeout, + retry: { limit: appConfig.network.retryCount }, +}; + +const launcherWebLang = [ + 'de-de', + 'en-us', + 'es-mx', + 'fr-fr', + 'id-id', + 'it-it', + 'ja-jp', + 'ko-kr', + 'pt-br', + 'ru-ru', + 'th-th', + 'vi-vn', + 'zh-cn', + 'zh-tw', +] as const; + +export default { + defaultKySettings, + apiAkEndfield: { + launcher: { + latestGame: async ( + appCode: string, + launcherAppCode: string, + channel: number, + subChannel: number, + launcherSubChannel: number, + version: string | null, + ): Promise => { + if (version !== null && !semver.valid(version)) throw new Error(`Invalid version string (${version})`); + const rsp = await ky + .get(`https://${appConfig.network.api.akEndfield.base.launcher}/game/get_latest`, { + ...defaultKySettings, + searchParams: { + appcode: appCode, + launcher_appcode: launcherAppCode, + channel, + sub_channel: subChannel, + launcher_sub_channel: launcherSubChannel, + version: version ?? undefined, + }, + }) + .json(); + return rsp as TypesApiAkEndfield.LauncherLatestGame; + }, + latestGameResources: async ( + appCode: string, + gameVersion: string, // example: 1.0 + version: string, + randStr: string, + platform: 'Windows' = 'Windows', + ): Promise => { + if (!semver.valid(version)) throw new Error(`Invalid version string (${version})`); + const rsp = await ky + .get(`https://${appConfig.network.api.akEndfield.base.launcher}/game/get_latest_resources`, { + ...defaultKySettings, + searchParams: { + appcode: appCode, + game_version: gameVersion, + version: version, + platform, + rand_str: randStr, + }, + }) + .json(); + return rsp as TypesApiAkEndfield.LauncherLatestGameResources; + }, + latestLauncher: async ( + appCode: string, + channel: number, + subChannel: number, + version: string | null, + targetApp: 'EndField' | null, + ): Promise => { + if (version !== null && !semver.valid(version)) throw new Error(`Invalid version string (${version})`); + const rsp = await ky + .get(`https://${appConfig.network.api.akEndfield.base.launcher}/launcher/get_latest`, { + ...defaultKySettings, + searchParams: { + appcode: appCode, + channel, + sub_channel: subChannel, + version: version ?? undefined, + targetApp: targetApp ?? undefined, + }, + }) + .json(); + return rsp as TypesApiAkEndfield.LauncherLatestLauncher; + }, + web: { + sidebar: async ( + appCode: string, + channel: number, + subChannel: number, + language: (typeof launcherWebLang)[number], + platform: 'Windows' = 'Windows', + ): Promise => { + const rsp = await ky + .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, { + ...defaultKySettings, + json: { + proxy_reqs: [ + { + kind: 'get_sidebar', + get_sidebar_req: { + appcode: appCode, + channel: String(channel), + sub_channel: String(subChannel), + language, + platform, + source: 'launcher', + }, + }, + ], + }, + }) + .json(); + return (rsp as any).proxy_rsps[0].get_sidebar_rsp as TypesApiAkEndfield.LauncherWebSidebar; + }, + singleEnt: async ( + appCode: string, + channel: number, + subChannel: number, + language: (typeof launcherWebLang)[number], + platform: 'Windows' = 'Windows', + ): Promise => { + const rsp = await ky + .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, { + ...defaultKySettings, + json: { + proxy_reqs: [ + { + kind: 'get_single_ent', + get_single_ent_req: { + appcode: appCode, + channel: String(channel), + sub_channel: String(subChannel), + language, + platform, + source: 'launcher', + }, + }, + ], + }, + }) + .json(); + return (rsp as any).proxy_rsps[0].get_single_ent_rsp as TypesApiAkEndfield.LauncherWebSingleEnt; + }, + mainBgImage: async ( + appCode: string, + channel: number, + subChannel: number, + language: (typeof launcherWebLang)[number], + platform: 'Windows' = 'Windows', + ): Promise => { + const rsp = await ky + .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, { + ...defaultKySettings, + json: { + proxy_reqs: [ + { + kind: 'get_main_bg_image', + get_main_bg_image_req: { + appcode: appCode, + channel: String(channel), + sub_channel: String(subChannel), + language, + platform, + source: 'launcher', + }, + }, + ], + }, + }) + .json(); + return (rsp as any).proxy_rsps[0].get_main_bg_image_rsp as TypesApiAkEndfield.LauncherWebMainBgImage; + }, + banner: async ( + appCode: string, + channel: number, + subChannel: number, + language: (typeof launcherWebLang)[number], + platform: 'Windows' = 'Windows', + ): Promise => { + const rsp = await ky + .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, { + ...defaultKySettings, + json: { + proxy_reqs: [ + { + kind: 'get_banner', + get_banner_req: { + appcode: appCode, + channel: String(channel), + sub_channel: String(subChannel), + language, + platform, + source: 'launcher', + }, + }, + ], + }, + }) + .json(); + return (rsp as any).proxy_rsps[0].get_banner_rsp as TypesApiAkEndfield.LauncherWebBanner; + }, + announcement: async ( + appCode: string, + channel: number, + subChannel: number, + language: (typeof launcherWebLang)[number], + platform: 'Windows' = 'Windows', + ): Promise => { + const rsp = await ky + .post(`https://${appConfig.network.api.akEndfield.base.launcher}/proxy/web/batch_proxy`, { + ...defaultKySettings, + json: { + proxy_reqs: [ + { + kind: 'get_announcement', + get_announcement_req: { + appcode: appCode, + channel: String(channel), + sub_channel: String(subChannel), + language, + platform, + source: 'launcher', + }, + }, + ], + }, + }) + .json(); + return (rsp as any).proxy_rsps[0].get_announcement_rsp as TypesApiAkEndfield.LauncherWebAnnouncement; + }, + }, + }, + }, +}; diff --git a/src/utils/argv.ts b/src/utils/argv.ts new file mode 100644 index 0000000..4fb0cfc --- /dev/null +++ b/src/utils/argv.ts @@ -0,0 +1,13 @@ +type argvType = { + [prop: string]: any; +}; +let argv: argvType | null = null; +export default { + setArgv: (argvIn: object) => { + argv = argvIn; + }, + getArgv: () => { + if (argv === null) throw new Error('argv is null'); + return argv; + }, +}; diff --git a/src/utils/config.ts b/src/utils/config.ts new file mode 100644 index 0000000..b5e1c4b --- /dev/null +++ b/src/utils/config.ts @@ -0,0 +1,120 @@ +import path from 'node:path'; +import deepmerge from 'deepmerge'; +import YAML from 'yaml'; +// import * as TypesGameEntry from '../types/GameEntry.js'; +import * as TypesLogLevels from '../types/LogLevels.js'; + +type Freeze = Readonly<{ + [P in keyof T]: T[P] extends object ? Freeze : T[P]; +}>; +type AllRequired = Required<{ + [P in keyof T]: T[P] extends object ? Freeze : T[P]; +}>; + +type ConfigType = AllRequired< + Freeze<{ + file: { + outputDirPath: string; + }; + network: { + api: { + akEndfield: { + appCode: { osWinRel: string }; + launcherAppCode: { osWinRel: string }; + channel: { osWinRel: number }; + base: { + accountService: string; + launcher: string; + u8: string; + }; + }; + }; + userAgent: { + // UA to hide the fact that the access is from this tool + minimum: string; + chromeWindows: string; + curl: string; + ios: string; + }; + timeout: number; // Network timeout + retryCount: number; // Number of retries for access failure + }; + threadCount: { + // Upper limit on the number of threads for parallel processing + network: number; // network access + }; + cli: { + autoExit: boolean; // Whether to exit the tool without waiting for key input when the exit code is 0 + }; + logger: { + // log4js-node logger settings + logLevel: TypesLogLevels.LogLevelNumber; + useCustomLayout: boolean; + customLayoutPattern: string; + }; + }> +>; + +const initialConfig: ConfigType = { + file: { + outputDirPath: path.resolve('output'), + }, + network: { + api: { + akEndfield: { + appCode: { osWinRel: 'YDUTE5gscDZ229CW' }, + launcherAppCode: { osWinRel: 'TiaytKBUIEdoEwRT' }, + channel: { osWinRel: 6 }, + base: { + accountService: 'YXMuZ3J5cGhsaW5lLmNvbQ==', + launcher: 'bGF1bmNoZXIuZ3J5cGhsaW5lLmNvbS9hcGk=', + u8: 'dTguZ3J5cGhsaW5lLmNvbQ==', + }, + }, + }, + userAgent: { + minimum: 'Mozilla/5.0', + chromeWindows: + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36', + curl: 'curl/8.4.0', + ios: 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1', + }, + timeout: 20000, + retryCount: 5, + }, + threadCount: { network: 16 }, + cli: { autoExit: false }, + logger: { + logLevel: 0, + useCustomLayout: true, + customLayoutPattern: '%[%d{hh:mm:ss.SSS} %-5.0p >%] %m', + }, +}; + +const deobfuscator = (input: ConfigType): ConfigType => { + const newConfig = JSON.parse(JSON.stringify(input)) as any; + const api = newConfig.network.api.akEndfield; + for (const key of Object.keys(api.base) as (keyof typeof api.base)[]) { + api.base[key] = atob(api.base[key]); + } + return newConfig as ConfigType; +}; + +const filePath = 'config/config.yaml'; + +if ((await Bun.file(filePath).exists()) === false) { + await Bun.write(filePath, YAML.stringify(initialConfig)); +} + +const config: ConfigType = await (async () => { + const rawFileData: ConfigType = YAML.parse(await Bun.file(filePath).text()) as ConfigType; + const mergedConfig = deepmerge(initialConfig, rawFileData, { + arrayMerge: (_destinationArray, sourceArray) => sourceArray, + }); + if (JSON.stringify(rawFileData) !== JSON.stringify(mergedConfig)) { + await Bun.write(filePath, YAML.stringify(mergedConfig)); + } + return deobfuscator(mergedConfig); +})(); + +export default config; diff --git a/src/utils/configEmbed.ts b/src/utils/configEmbed.ts new file mode 100644 index 0000000..56956cd --- /dev/null +++ b/src/utils/configEmbed.ts @@ -0,0 +1,6 @@ +import semver from 'semver'; + +export default { + APPLICATION_NAME: 'ak-endfield-api-archive', + VERSION_NUMBER: semver.valid('0.1.0'), +}; diff --git a/src/utils/exit.ts b/src/utils/exit.ts new file mode 100644 index 0000000..2c000c2 --- /dev/null +++ b/src/utils/exit.ts @@ -0,0 +1,50 @@ +import readline from 'node:readline'; +import appConfig from './config.js'; + +async function pressAnyKeyToExit(errorCode: number): Promise { + if (errorCode !== 0) console.error('An error occurred'); + if (!process.stdin.isTTY || (appConfig.cli.autoExit && errorCode === 0)) { + console.log(`Exiting with code ${errorCode} ...`); + process.exit(errorCode); + } + process.stdout.write('Press any key to exit ...'); + return new Promise((resolve) => { + readline.emitKeypressEvents(process.stdin); + process.stdin.setRawMode(true); + process.stdin.resume(); + process.stdin.once('data', () => { + process.stdin.setRawMode(false); + process.stdin.pause(); + process.stdout.write(` Exiting with code ${errorCode} ...\n`); + resolve(); // Promiseを解決 + process.exit(errorCode); // その後、プロセスを終了 + }); + }); +} + +async function exit(errorCode: number, str: string | null = null, printText: boolean = true): Promise { + if (errorCode !== 0 && printText) console.error('An error occurred' + (str ? ': ' + str : '')); + printText ? process.stdout.write(`Exiting with code ${errorCode} ...\n`) : null; + process.exit(errorCode); +} + +async function pressAnyKeyToContinue(printText: boolean = true): Promise { + printText ? process.stdout.write('Press any key to continue ...') : null; + return new Promise((resolve) => { + readline.emitKeypressEvents(process.stdin); + process.stdin.setRawMode(true); + process.stdin.resume(); + process.stdin.once('data', () => { + process.stdin.setRawMode(false); + process.stdin.pause(); + printText ? process.stdout.write(`\n`) : null; + resolve(); // Promiseを解決 + }); + }); +} + +export default { + pressAnyKeyToExit, + exit, + pressAnyKeyToContinue, +}; diff --git a/src/utils/file.ts b/src/utils/file.ts new file mode 100644 index 0000000..76480b0 --- /dev/null +++ b/src/utils/file.ts @@ -0,0 +1,117 @@ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import stream from 'node:stream'; +import { fileURLToPath } from 'node:url'; +import util from 'node:util'; +import configEmbed from './configEmbed.js'; + +function getAppDataDir(): string { + switch (process.platform) { + case 'win32': + return path.join( + process.env['APPDATA'] || path.join(os.homedir(), 'AppData', 'Roaming'), + configEmbed.APPLICATION_NAME, + ); + case 'darwin': + return path.join(os.homedir(), 'Library', 'Application Support', configEmbed.APPLICATION_NAME); + case 'linux': + return path.join( + process.env['XDG_CONFIG_HOME'] || path.join(os.homedir(), '.config'), + configEmbed.APPLICATION_NAME, + ); + default: + return path.resolve('config'); + } +} + +/** + * Detect app is standalone or not + */ +function isAppCompiledSA(): boolean { + return Boolean( + /^file:\/\/\/\$bunfs\/root\//g.test(import.meta.url) || /^file:\/\/\/B:\/%7EBUN\/root\//g.test(import.meta.url), + ); +} + +function getAppRootDir(): string { + const __filename = fileURLToPath(import.meta.url); + const __dirname = path.dirname(__filename); + if (isAppCompiledSA()) { + // app is standalone + return path.dirname(process.execPath); + } + // app is not standalone + let currentDir = __dirname; + + while (currentDir !== path.parse(currentDir).root) { + const basename = path.basename(currentDir); + if (basename === 'dist' || basename === 'src') { + return path.dirname(currentDir); + } + currentDir = path.dirname(currentDir); + } + + return __dirname; // fallback +} + +async function checkFolderExists(folderPath: string): Promise { + try { + const stats = await fs.promises.stat(folderPath); + return stats.isDirectory(); + } catch (error: any) { + return false; + } +} + +async function checkFileExists(filePath: string): Promise { + try { + const stats = await fs.promises.stat(filePath); + return stats.isFile(); + } catch (error: any) { + return false; + } +} + +async function getFileList(dirPath: string): Promise { + const absoluteDirPath = path.resolve(dirPath); + const filePaths: string[] = []; + async function walk(currentDir: string): Promise { + const entries = await fs.promises.readdir(currentDir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(currentDir, entry.name); + if (entry.isDirectory()) { + await walk(fullPath); + } else if (entry.isFile()) { + filePaths.push(fullPath); + } + } + } + await walk(absoluteDirPath); + return filePaths; +} + +async function readFileAsArrayBuffer(filePath: string): Promise { + const buffer = await fs.promises.readFile(filePath); + return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); +} + +async function copyFileWithStream(srcPath: string, destPath: string): Promise { + const pipelineAsync = util.promisify(stream.pipeline); + try { + await pipelineAsync(fs.createReadStream(srcPath), fs.createWriteStream(destPath)); + } catch (err) { + throw err; + } +} + +export default { + getAppDataDir, + isAppCompiledSA, + getAppRootDir, + checkFolderExists, + checkFileExists, + getFileList, + readFileAsArrayBuffer, + copyFileWithStream, +}; diff --git a/src/utils/logger.ts b/src/utils/logger.ts new file mode 100644 index 0000000..371e141 --- /dev/null +++ b/src/utils/logger.ts @@ -0,0 +1,25 @@ +import log4js from 'log4js'; +import * as TypesLogLevels from '../types/LogLevels.js'; +import appConfig from './config.js'; + +log4js.configure({ + appenders: { + System: { + type: 'stdout', + layout: { + type: appConfig.logger.useCustomLayout ? 'pattern' : 'colored', + pattern: appConfig.logger.useCustomLayout ? appConfig.logger.customLayoutPattern : '', + }, + }, + }, + categories: { + default: { + appenders: ['System'], + level: TypesLogLevels.LOG_LEVELS[appConfig.logger.logLevel], + }, + }, +}); + +const logger: log4js.Logger = log4js.getLogger('System'); + +export default logger; diff --git a/src/utils/math.ts b/src/utils/math.ts new file mode 100644 index 0000000..3cee9f2 --- /dev/null +++ b/src/utils/math.ts @@ -0,0 +1,90 @@ +export default { + arrayMax(array: Array) { + return array.reduce((a, b) => Math.max(a, b)); + }, + + arrayMin(array: Array) { + return array.reduce((a, b) => Math.min(a, b)); + }, + + arrayTotal(array: Array) { + return array.reduce((acc, f) => acc + f, 0); + }, + + arrayAvg(array: Array) { + return this.arrayTotal(array) / array.length; + }, + + rounder(method: 'floor' | 'ceil' | 'round', num: number, n: number) { + const pow = Math.pow(10, n); + let result: number; + switch (method) { + case 'floor': + result = Math.floor(num * pow) / pow; + break; + case 'ceil': + result = Math.ceil(num * pow) / pow; + break; + case 'round': + result = Math.round(num * pow) / pow; + break; + } + return { + orig: result, + padded: result.toFixed(n), + }; + }, + + formatFileSize( + bytes: number, + options: { + decimals: number; + decimalPadding: boolean; + useBinaryUnit: boolean; + useBitUnit: boolean; + unitVisible: boolean; + unit: 'B' | 'K' | 'M' | 'G' | 'T' | 'P' | 'E' | 'Z' | 'Y' | null; + }, + ) { + const k = options.useBinaryUnit ? 1024 : 1000; + const dm = options.decimals < 0 ? 0 : options.decimals; + + const baseUnits = ['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; + const binaryUnitSuffix = options.useBitUnit ? 'ib' : 'iB'; + const siUnitSuffix = options.useBitUnit ? 'b' : 'B'; + + const getUnitString = (i: number) => { + if (i === 0) return options.useBitUnit ? 'b' : 'B'; + return baseUnits[i] + (options.useBinaryUnit ? binaryUnitSuffix : siUnitSuffix); + }; + + let value = bytes < 0 ? 0 : Math.floor(bytes); + if (options.useBitUnit) { + value *= 8; + } + + let i: number; + if (options.unit !== null) { + i = baseUnits.indexOf(options.unit); + if (i === -1) throw new Error(`Invalid unit: ${options.unit}`); + } else { + if (value === 0) { + i = 0; + } else { + i = Math.floor(Math.log(value) / Math.log(k)); + i = Math.max(0, Math.min(baseUnits.length - 1, i)); // clamp + } + } + + const resultValue = value / Math.pow(k, i); + + let formattedValue: string; + if (options.decimalPadding) { + formattedValue = resultValue.toFixed(dm); + } else { + formattedValue = resultValue.toFixed(dm).replace(/\.?0+$/, ''); + } + + return formattedValue + (options.unitVisible ? ' ' + getUnitString(i) : ''); + }, +}; diff --git a/src/utils/omitDeep.ts b/src/utils/omitDeep.ts new file mode 100644 index 0000000..aa5b279 --- /dev/null +++ b/src/utils/omitDeep.ts @@ -0,0 +1,125 @@ +type Path = Array; +type Paths = Path | Path[]; + +/** + * Removes properties from an object at specified paths. + * @param obj The target object. + * @param paths The paths of the properties to remove. + * @returns A new object with the properties removed. + * + * @example + * const user = { + * id: 1, + * name: 'John', + * profile: { + * email: 'john@example.com', + * settings: { + * theme: 'dark', + * notifications: true + * } + * }, + * tags: ['user', 'premium', 'verified'] + * }; + * + * // Remove a single nested property + * const withoutEmail = omitDeep(user, ['profile', 'email']); + * + * // Remove multiple properties and array elements at once + * const cleanedUser = omitDeep(user, [ + * ['profile', 'email'], + * ['profile', 'settings', 'notifications'], + * ['tags', 1] // Remove the second element of the array + * ]); + */ +function omitDeep(obj: T, paths: Paths): T { + // Robust deep copy + const deepClone = (item: U): U => { + if (item === null || typeof item !== 'object') return item; + + if (item instanceof Date) return new Date(item) as unknown as U; + if (item instanceof RegExp) return new RegExp(item) as unknown as U; + + if (Array.isArray(item)) { + return item.map(deepClone) as unknown as U; + } + + const clone = {} as U; + for (const key in item) { + if (Object.prototype.hasOwnProperty.call(item, key)) { + clone[key] = deepClone(item[key]); + } + } + return clone; + }; + + const result = deepClone(obj); + + // Normalize paths + const pathArray: Path[] = + Array.isArray(paths) && paths.length > 0 && Array.isArray(paths[0]) ? (paths as Path[]) : [paths as Path]; + + // Perform deletion for each path + for (const path of pathArray) { + if (path.length === 0) continue; + + // Get the parent object/array of the target property + const parentInfo = getParentAndKey(result, path); + if (!parentInfo) continue; + + const { parent, lastKey } = parentInfo; + + // Delete the property or array element + if (Array.isArray(parent)) { + // If it's an array + const index = Number(lastKey); + if (!isNaN(index) && index >= 0 && index < parent.length) { + parent.splice(index, 1); + } + } else if (typeof parent === 'object' && parent !== null) { + // If it's an object + delete parent[lastKey as string]; + } + } + + return result; +} + +/** + * Gets the parent object/array and the final key for a given path. + */ +function getParentAndKey(obj: any, path: Path): { parent: any; lastKey: string | number } | null { + let current: any = obj; + + for (let i = 0; i < path.length - 1; i++) { + const key = path[i]; + + if (current === null || typeof current !== 'object') { + return null; + } + + // Handle arrays + if (Array.isArray(current)) { + const index = Number(key); + if (isNaN(index) || index < 0 || index >= current.length) { + return null; + } + current = current[index]; + } // Handle objects + else if (Object.prototype.hasOwnProperty.call(current, key!)) { + current = current[key!]; + } else { + return null; + } + } + + if (current === null || typeof current !== 'object') { + return null; + } + + return { + parent: current, + lastKey: path[path.length - 1]!, + }; +} + +export default omitDeep; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..deac618 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": [ + // "@tsconfig/bun", + "@tsconfig/recommended", + "@tsconfig/node24", + "@tsconfig/strictest" + ], + "compilerOptions": { + "outDir": "./dist", + "sourceMap": false, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] +}