From 573afbaeca3a1605164eebef9063548d068e2454 Mon Sep 17 00:00:00 2001 From: Jackson <30759238+HoloPanio@users.noreply.github.com> Date: Sat, 24 Jan 2026 10:54:03 -0600 Subject: [PATCH 01/73] Initial commit --- .gitignore | 139 +++++++++++ LICENSE | 674 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 + 3 files changed, 815 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9a5aced --- /dev/null +++ b/.gitignore @@ -0,0 +1,139 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.* +!.env.example + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Sveltekit cache directory +.svelte-kit/ + +# vitepress build output +**/.vitepress/dist + +# vitepress cache directory +**/.vitepress/cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# Firebase cache directory +.firebase/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v3 +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Vite logs files +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 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 General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is 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. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + 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. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + 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 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. Use with the GNU Affero General Public License. + + 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 Affero 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 special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 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 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 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 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + 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 GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..66c9d9f --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# ttsci-api +The Api for the TTS Credentials Manager From 916e5a7ada5835c3d46b0c95903962f686ece1f4 Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Sat, 24 Jan 2026 11:00:35 -0600 Subject: [PATCH 02/73] bun init --- bun.lock | 26 ++++++++++++++++++++++++++ package.json | 12 ++++++++++++ src/index.ts | 1 + tsconfig.json | 29 +++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 bun.lock create mode 100644 package.json create mode 100644 src/index.ts create mode 100644 tsconfig.json diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..8b6b24b --- /dev/null +++ b/bun.lock @@ -0,0 +1,26 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "ttscm-api", + "devDependencies": { + "@types/bun": "latest", + }, + "peerDependencies": { + "typescript": "^5", + }, + }, + }, + "packages": { + "@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="], + + "@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="], + + "bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..bac1b98 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "ttscm-api", + "module": "src/index.ts", + "type": "module", + "private": true, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5" + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..f67b2c6 --- /dev/null +++ b/src/index.ts @@ -0,0 +1 @@ +console.log("Hello via Bun!"); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..bfa0fea --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + // Environment setup & latest features + "lib": ["ESNext"], + "target": "ESNext", + "module": "Preserve", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} From 935c7296f6ce3ec281be9a61e805363c9c4853a5 Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Sat, 24 Jan 2026 13:47:52 -0600 Subject: [PATCH 03/73] Update gitIgnore --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index 9a5aced..be0d1ce 100644 --- a/.gitignore +++ b/.gitignore @@ -137,3 +137,10 @@ dist # Vite logs files vite.config.js.timestamp-* vite.config.ts.timestamp-* + +.permissions.key +.refreshToken.key +.apiKeyToken.key +.accessToken.key + +microsoft-oauth.json From 4be36e6ca0647675e1429b851bbc0182b2c3cd4b Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Sat, 24 Jan 2026 16:59:50 -0600 Subject: [PATCH 04/73] untested WIP --- .docker/docker-compose.yml | 48 + bruno/ttscm/Teapot.bru | 15 + bruno/ttscm/bruno.json | 9 + bun.lock | 286 +++ generated/prisma/browser.ts | 34 + generated/prisma/client.ts | 56 + generated/prisma/commonInputTypes.ts | 352 ++++ generated/prisma/enums.ts | 15 + generated/prisma/internal/class.ts | 212 ++ generated/prisma/internal/prismaNamespace.ts | 964 +++++++++ .../prisma/internal/prismaNamespaceBrowser.ts | 139 ++ generated/prisma/models.ts | 14 + generated/prisma/models/Role.ts | 1409 +++++++++++++ generated/prisma/models/Session.ts | 1426 +++++++++++++ generated/prisma/models/User.ts | 1778 +++++++++++++++++ package.json | 29 +- prisma.config.ts | 12 + prisma/schema.prisma | 56 + src/Errors/AuthenticationError.ts | 8 + src/Errors/AuthorizationError.ts | 11 + src/Errors/BodyError.ts | 8 + src/Errors/ExpiredAccessTokenError.ts | 8 + src/Errors/ExpiredRefreshTokenError.ts | 8 + src/Errors/GenericError.ts | 16 + src/Errors/InsufficientPermission.ts | 11 + src/Errors/MissingBodyValue.ts | 9 + src/Errors/PermissionsVerificationError.ts | 8 + src/Errors/RoleError.ts | 8 + src/Errors/SessionError.ts | 8 + src/Errors/SessionTokenError.ts | 8 + src/Errors/UserError.ts | 8 + src/api/.gitignore | 5 + src/api/prisma.config.ts | 12 + src/api/server.ts | 53 + src/api/teapot.ts | 12 + src/constants.ts | 34 + src/controllers/RoleController.ts | 338 ++++ src/controllers/SessionController.ts | 228 +++ src/controllers/UserController.ts | 200 ++ src/index.ts | 8 +- src/managers/roles.ts | 171 ++ src/managers/sessions.ts | 159 ++ src/managers/users.ts | 118 ++ src/modules/api-utils/apiResponse.ts | 56 + src/modules/api-utils/createRoute.ts | 40 + src/modules/globalEvents.ts | 64 + .../permission-utils/checkImplicitPerm.ts | 0 .../permission-utils/genImplicitPerm.ts | 9 + .../permission-utils/permissionValidator.ts | 53 + .../permission-utils/signPermissions.ts | 24 + src/modules/tools/Password.ts | 34 + src/modules/tools/mergeArrays.ts | 8 + src/types/HonoTypes.ts | 3 + src/types/PermissionTypes.ts | 7 + tsconfig.json | 2 +- utils/genPrivateKeys.ts | 37 + 56 files changed, 8645 insertions(+), 3 deletions(-) create mode 100644 .docker/docker-compose.yml create mode 100644 bruno/ttscm/Teapot.bru create mode 100644 bruno/ttscm/bruno.json create mode 100644 generated/prisma/browser.ts create mode 100644 generated/prisma/client.ts create mode 100644 generated/prisma/commonInputTypes.ts create mode 100644 generated/prisma/enums.ts create mode 100644 generated/prisma/internal/class.ts create mode 100644 generated/prisma/internal/prismaNamespace.ts create mode 100644 generated/prisma/internal/prismaNamespaceBrowser.ts create mode 100644 generated/prisma/models.ts create mode 100644 generated/prisma/models/Role.ts create mode 100644 generated/prisma/models/Session.ts create mode 100644 generated/prisma/models/User.ts create mode 100644 prisma.config.ts create mode 100644 prisma/schema.prisma create mode 100644 src/Errors/AuthenticationError.ts create mode 100644 src/Errors/AuthorizationError.ts create mode 100644 src/Errors/BodyError.ts create mode 100644 src/Errors/ExpiredAccessTokenError.ts create mode 100644 src/Errors/ExpiredRefreshTokenError.ts create mode 100644 src/Errors/GenericError.ts create mode 100644 src/Errors/InsufficientPermission.ts create mode 100644 src/Errors/MissingBodyValue.ts create mode 100644 src/Errors/PermissionsVerificationError.ts create mode 100644 src/Errors/RoleError.ts create mode 100644 src/Errors/SessionError.ts create mode 100644 src/Errors/SessionTokenError.ts create mode 100644 src/Errors/UserError.ts create mode 100644 src/api/.gitignore create mode 100644 src/api/prisma.config.ts create mode 100644 src/api/server.ts create mode 100644 src/api/teapot.ts create mode 100644 src/constants.ts create mode 100644 src/controllers/RoleController.ts create mode 100644 src/controllers/SessionController.ts create mode 100644 src/controllers/UserController.ts create mode 100644 src/managers/roles.ts create mode 100644 src/managers/sessions.ts create mode 100644 src/managers/users.ts create mode 100644 src/modules/api-utils/apiResponse.ts create mode 100644 src/modules/api-utils/createRoute.ts create mode 100644 src/modules/globalEvents.ts create mode 100644 src/modules/permission-utils/checkImplicitPerm.ts create mode 100644 src/modules/permission-utils/genImplicitPerm.ts create mode 100644 src/modules/permission-utils/permissionValidator.ts create mode 100644 src/modules/permission-utils/signPermissions.ts create mode 100644 src/modules/tools/Password.ts create mode 100644 src/modules/tools/mergeArrays.ts create mode 100644 src/types/HonoTypes.ts create mode 100644 src/types/PermissionTypes.ts create mode 100644 utils/genPrivateKeys.ts diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml new file mode 100644 index 0000000..1ac86aa --- /dev/null +++ b/.docker/docker-compose.yml @@ -0,0 +1,48 @@ +version: "3" + +services: + pgsql: + image: postgres + restart: unless-stopped + environment: + POSTGRES_USER: duxcore + POSTGRES_PASSWORD: 123web123 + POSTGRES_DB: duxcore + volumes: + - ./postgres:/var/lib/postgresql/data + ports: + - 5432:5432 + pgsql-boss: + image: postgres + restart: unless-stopped + environment: + POSTGRES_USER: pg-boss + POSTGRES_PASSWORD: 123web123 + POSTGRES_DB: pg-boss + volumes: + - ./postgres-pgb:/var/lib/postgresql/data + ports: + - 2345:5432 + + redis: + image: redis:6.2-alpine + restart: always + ports: + - "6379:6379" + command: redis-server --save 20 1 --loglevel warning --requirepass iamatotallysecurepassworddonttestmebrox + volumes: + - ./redis:/data + + adminer: + image: adminer + restart: unless-stopped + ports: + - 8080:8080 + depends_on: + - pgsql + redisinsight: + image: redis/redisinsight:latest + container_name: redisinsight + ports: + - "5540:5540" + restart: unless-stopped \ No newline at end of file diff --git a/bruno/ttscm/Teapot.bru b/bruno/ttscm/Teapot.bru new file mode 100644 index 0000000..bc2e493 --- /dev/null +++ b/bruno/ttscm/Teapot.bru @@ -0,0 +1,15 @@ +meta { + name: Teapot + type: http + seq: 1 +} + +get { + url: http://localhost:3000/v1/teapot + body: none + auth: inherit +} + +settings { + encodeUrl: true +} diff --git a/bruno/ttscm/bruno.json b/bruno/ttscm/bruno.json new file mode 100644 index 0000000..b6108ee --- /dev/null +++ b/bruno/ttscm/bruno.json @@ -0,0 +1,9 @@ +{ + "version": "1", + "name": "ttscm", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ] +} \ No newline at end of file diff --git a/bun.lock b/bun.lock index 8b6b24b..064769a 100644 --- a/bun.lock +++ b/bun.lock @@ -4,8 +4,22 @@ "workspaces": { "": { "name": "ttscm-api", + "dependencies": { + "@discordjs/collection": "^2.1.1", + "@duxcore/eventra": "^1.1.0", + "@prisma/adapter-pg": "^7.3.0", + "cors": "^2.8.6", + "cuid": "^3.0.0", + "hono": "^4.11.5", + "jsonwebtoken": "^9.0.3", + "keypair": "^1.0.4", + "prisma": "^7.3.0", + "zod": "^4.3.6", + "zon": "^1.0.3", + }, "devDependencies": { "@types/bun": "latest", + "@types/jsonwebtoken": "^9.0.10", }, "peerDependencies": { "typescript": "^5", @@ -13,14 +27,286 @@ }, }, "packages": { + "@chevrotain/cst-dts-gen": ["@chevrotain/cst-dts-gen@10.5.0", "", { "dependencies": { "@chevrotain/gast": "10.5.0", "@chevrotain/types": "10.5.0", "lodash": "4.17.21" } }, "sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw=="], + + "@chevrotain/gast": ["@chevrotain/gast@10.5.0", "", { "dependencies": { "@chevrotain/types": "10.5.0", "lodash": "4.17.21" } }, "sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A=="], + + "@chevrotain/types": ["@chevrotain/types@10.5.0", "", {}, "sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A=="], + + "@chevrotain/utils": ["@chevrotain/utils@10.5.0", "", {}, "sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ=="], + + "@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="], + + "@duxcore/eventra": ["@duxcore/eventra@1.1.0", "", {}, "sha512-XYLksXvOjr3uGw9oh0wgKVF0POiz1Gjk/Ety8chEQdEwzDAiyydztB8TtjF/Pfr+vdM/ceMV/OOQliBZLnfONA=="], + + "@electric-sql/pglite": ["@electric-sql/pglite@0.3.15", "", {}, "sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ=="], + + "@electric-sql/pglite-socket": ["@electric-sql/pglite-socket@0.0.20", "", { "peerDependencies": { "@electric-sql/pglite": "0.3.15" }, "bin": { "pglite-server": "dist/scripts/server.js" } }, "sha512-J5nLGsicnD9wJHnno9r+DGxfcZWh+YJMCe0q/aCgtG6XOm9Z7fKeite8IZSNXgZeGltSigM9U/vAWZQWdgcSFg=="], + + "@electric-sql/pglite-tools": ["@electric-sql/pglite-tools@0.2.20", "", { "peerDependencies": { "@electric-sql/pglite": "0.3.15" } }, "sha512-BK50ZnYa3IG7ztXhtgYf0Q7zijV32Iw1cYS8C+ThdQlwx12V5VZ9KRJ42y82Hyb4PkTxZQklVQA9JHyUlex33A=="], + + "@hono/node-server": ["@hono/node-server@1.19.9", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw=="], + + "@mrleebo/prisma-ast": ["@mrleebo/prisma-ast@0.13.1", "", { "dependencies": { "chevrotain": "^10.5.0", "lilconfig": "^2.1.0" } }, "sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw=="], + + "@prisma/adapter-pg": ["@prisma/adapter-pg@7.3.0", "", { "dependencies": { "@prisma/driver-adapter-utils": "7.3.0", "pg": "^8.16.3", "postgres-array": "3.0.4" } }, "sha512-iuYQMbIPO6i9O45Fv8TB7vWu00BXhCaNAShenqF7gLExGDbnGp5BfFB4yz1K59zQ59jF6tQ9YHrg0P6/J3OoLg=="], + + "@prisma/config": ["@prisma/config@7.3.0", "", { "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", "effect": "3.18.4", "empathic": "2.0.0" } }, "sha512-QyMV67+eXF7uMtKxTEeQqNu/Be7iH+3iDZOQZW5ttfbSwBamCSdwPszA0dum+Wx27I7anYTPLmRmMORKViSW1A=="], + + "@prisma/debug": ["@prisma/debug@7.3.0", "", {}, "sha512-yh/tHhraCzYkffsI1/3a7SHX8tpgbJu1NPnuxS4rEpJdWAUDHUH25F1EDo6PPzirpyLNkgPPZdhojQK804BGtg=="], + + "@prisma/dev": ["@prisma/dev@0.20.0", "", { "dependencies": { "@electric-sql/pglite": "0.3.15", "@electric-sql/pglite-socket": "0.0.20", "@electric-sql/pglite-tools": "0.2.20", "@hono/node-server": "1.19.9", "@mrleebo/prisma-ast": "0.13.1", "@prisma/get-platform": "7.2.0", "@prisma/query-plan-executor": "7.2.0", "foreground-child": "3.3.1", "get-port-please": "3.2.0", "hono": "4.11.4", "http-status-codes": "2.3.0", "pathe": "2.0.3", "proper-lockfile": "4.1.2", "remeda": "2.33.4", "std-env": "3.10.0", "valibot": "1.2.0", "zeptomatch": "2.1.0" } }, "sha512-ovlBYwWor0OzG+yH4J3Ot+AneD818BttLA+Ii7wjbcLHUrnC4tbUPVGyNd3c/+71KETPKZfjhkTSpdS15dmXNQ=="], + + "@prisma/driver-adapter-utils": ["@prisma/driver-adapter-utils@7.3.0", "", { "dependencies": { "@prisma/debug": "7.3.0" } }, "sha512-Wdlezh1ck0Rq2dDINkfSkwbR53q53//Eo1vVqVLwtiZ0I6fuWDGNPxwq+SNAIHnsU+FD/m3aIJKevH3vF13U3w=="], + + "@prisma/engines": ["@prisma/engines@7.3.0", "", { "dependencies": { "@prisma/debug": "7.3.0", "@prisma/engines-version": "7.3.0-16.9d6ad21cbbceab97458517b147a6a09ff43aa735", "@prisma/fetch-engine": "7.3.0", "@prisma/get-platform": "7.3.0" } }, "sha512-cWRQoPDXPtR6stOWuWFZf9pHdQ/o8/QNWn0m0zByxf5Kd946Q875XdEJ52pEsX88vOiXUmjuPG3euw82mwQNMg=="], + + "@prisma/engines-version": ["@prisma/engines-version@7.3.0-16.9d6ad21cbbceab97458517b147a6a09ff43aa735", "", {}, "sha512-IH2va2ouUHihyiTTRW889LjKAl1CusZOvFfZxCDNpjSENt7g2ndFsK0vdIw/72v7+jCN6YgkHmdAP/BI7SDgyg=="], + + "@prisma/fetch-engine": ["@prisma/fetch-engine@7.3.0", "", { "dependencies": { "@prisma/debug": "7.3.0", "@prisma/engines-version": "7.3.0-16.9d6ad21cbbceab97458517b147a6a09ff43aa735", "@prisma/get-platform": "7.3.0" } }, "sha512-Mm0F84JMqM9Vxk70pzfNpGJ1lE4hYjOeLMu7nOOD1i83nvp8MSAcFYBnHqLvEZiA6onUR+m8iYogtOY4oPO5lQ=="], + + "@prisma/get-platform": ["@prisma/get-platform@7.2.0", "", { "dependencies": { "@prisma/debug": "7.2.0" } }, "sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA=="], + + "@prisma/query-plan-executor": ["@prisma/query-plan-executor@7.2.0", "", {}, "sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ=="], + + "@prisma/studio-core": ["@prisma/studio-core@0.13.1", "", { "peerDependencies": { "@types/react": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-agdqaPEePRHcQ7CexEfkX1RvSH9uWDb6pXrZnhCRykhDFAV0/0P3d07WtfiY8hZWb7oRU4v+NkT4cGFHkQJIPg=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="], + "@types/jsonwebtoken": ["@types/jsonwebtoken@9.0.10", "", { "dependencies": { "@types/ms": "*", "@types/node": "*" } }, "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA=="], + + "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], + "@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="], + "@types/react": ["@types/react@19.2.9", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA=="], + + "aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="], + + "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], + "bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="], + "c12": ["c12@3.1.0", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^16.6.1", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.4.2", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw=="], + + "chevrotain": ["chevrotain@10.5.0", "", { "dependencies": { "@chevrotain/cst-dts-gen": "10.5.0", "@chevrotain/gast": "10.5.0", "@chevrotain/types": "10.5.0", "@chevrotain/utils": "10.5.0", "lodash": "4.17.21", "regexp-to-ast": "0.5.0" } }, "sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A=="], + + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + + "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], + + "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], + + "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], + + "cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + + "cuid": ["cuid@3.0.0", "", {}, "sha512-WZYYkHdIDnaxdeP8Misq3Lah5vFjJwGuItJuV+tvMafosMzw0nF297T7mrm8IOWiPJkV6gc7sa8pzx27+w25Zg=="], + + "deepmerge-ts": ["deepmerge-ts@7.1.5", "", {}, "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw=="], + + "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + + "denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="], + + "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], + + "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + + "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], + + "effect": ["effect@3.18.4", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA=="], + + "empathic": ["empathic@2.0.0", "", {}, "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA=="], + + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], + + "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="], + + "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "generate-function": ["generate-function@2.3.1", "", { "dependencies": { "is-property": "^1.0.2" } }, "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ=="], + + "get-port-please": ["get-port-please@3.2.0", "", {}, "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A=="], + + "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "grammex": ["grammex@3.1.12", "", {}, "sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ=="], + + "graphmatch": ["graphmatch@1.1.0", "", {}, "sha512-0E62MaTW5rPZVRLyIJZG/YejmdA/Xr1QydHEw3Vt+qOKkMIOE8WDLc9ZX2bmAjtJFZcId4lEdrdmASsEy7D1QA=="], + + "hono": ["hono@4.11.5", "", {}, "sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g=="], + + "http-status-codes": ["http-status-codes@2.3.0", "", {}, "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA=="], + + "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], + + "is-property": ["is-property@1.0.2", "", {}, "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + + "jsonwebtoken": ["jsonwebtoken@9.0.3", "", { "dependencies": { "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g=="], + + "jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="], + + "jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="], + + "keypair": ["keypair@1.0.4", "", {}, "sha512-zwhgOhhniaL7oxMgUMKKw5219PWWABMO+dgMnzJOQ2/5L3XJtTJGhW2PEXlxXj9zaccdReZJZ83+4NPhVfNVDg=="], + + "lilconfig": ["lilconfig@2.1.0", "", {}, "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="], + + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + + "lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="], + + "lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="], + + "lodash.isinteger": ["lodash.isinteger@4.0.4", "", {}, "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="], + + "lodash.isnumber": ["lodash.isnumber@3.0.3", "", {}, "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="], + + "lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="], + + "lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="], + + "lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="], + + "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], + + "lru.min": ["lru.min@1.1.3", "", {}, "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "mysql2": ["mysql2@3.15.3", "", { "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.7.0", "long": "^5.2.1", "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg=="], + + "named-placeholders": ["named-placeholders@1.1.6", "", { "dependencies": { "lru.min": "^1.1.0" } }, "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w=="], + + "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], + + "nypm": ["nypm@0.6.4", "", { "dependencies": { "citty": "^0.2.0", "pathe": "^2.0.3", "tinyexec": "^1.0.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-1TvCKjZyyklN+JJj2TS3P4uSQEInrM/HkkuSXsEzm1ApPgBffOn8gFguNnZf07r/1X6vlryfIqMUkJKQMzlZiw=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="], + + "pg": ["pg@8.17.2", "", { "dependencies": { "pg-connection-string": "^2.10.1", "pg-pool": "^3.11.0", "pg-protocol": "^1.11.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.3.0" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-vjbKdiBJRqzcYw1fNU5KuHyYvdJ1qpcQg1CeBrHFqV1pWgHeVR6j/+kX0E1AAXfyuLUGY1ICrN2ELKA/z2HWzw=="], + + "pg-cloudflare": ["pg-cloudflare@1.3.0", "", {}, "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ=="], + + "pg-connection-string": ["pg-connection-string@2.10.1", "", {}, "sha512-iNzslsoeSH2/gmDDKiyMqF64DATUCWj3YJ0wP14kqcsf2TUklwimd+66yYojKwZCA7h2yRNLGug71hCBA2a4sw=="], + + "pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="], + + "pg-pool": ["pg-pool@3.11.0", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w=="], + + "pg-protocol": ["pg-protocol@1.11.0", "", {}, "sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g=="], + + "pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="], + + "pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="], + + "pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], + + "postgres": ["postgres@3.4.7", "", {}, "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw=="], + + "postgres-array": ["postgres-array@3.0.4", "", {}, "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ=="], + + "postgres-bytea": ["postgres-bytea@1.0.1", "", {}, "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ=="], + + "postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="], + + "postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="], + + "prisma": ["prisma@7.3.0", "", { "dependencies": { "@prisma/config": "7.3.0", "@prisma/dev": "0.20.0", "@prisma/engines": "7.3.0", "@prisma/studio-core": "0.13.1", "mysql2": "3.15.3", "postgres": "3.4.7" }, "peerDependencies": { "better-sqlite3": ">=9.0.0", "typescript": ">=5.4.0" }, "optionalPeers": ["better-sqlite3", "typescript"], "bin": { "prisma": "build/index.js" } }, "sha512-ApYSOLHfMN8WftJA+vL6XwAPOh/aZ0BgUyyKPwUFgjARmG6EBI9LzDPf6SWULQMSAxydV9qn5gLj037nPNlg2w=="], + + "proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="], + + "pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="], + + "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], + + "react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="], + + "react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="], + + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + + "regexp-to-ast": ["regexp-to-ast@0.5.0", "", {}, "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw=="], + + "remeda": ["remeda@2.33.4", "", {}, "sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ=="], + + "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], + + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "seq-queue": ["seq-queue@0.0.5", "", {}, "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + + "sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="], + + "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], + + "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "valibot": ["valibot@1.2.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg=="], + + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], + + "zeptomatch": ["zeptomatch@2.1.0", "", { "dependencies": { "grammex": "^3.1.11", "graphmatch": "^1.1.0" } }, "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA=="], + + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + + "zon": ["zon@1.0.3", "", {}, "sha512-FKLlkaI8bU0ORFgZIzbqgvT7ei7aHob2jvhDPLgkwxccDurBRviDlD2eC2px6kEox0VlW0rK3VBwjsvtGV6g0w=="], + + "@prisma/dev/hono": ["hono@4.11.4", "", {}, "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA=="], + + "@prisma/engines/@prisma/get-platform": ["@prisma/get-platform@7.3.0", "", { "dependencies": { "@prisma/debug": "7.3.0" } }, "sha512-N7c6m4/I0Q6JYmWKP2RCD/sM9eWiyCPY98g5c0uEktObNSZnugW2U/PO+pwL0UaqzxqTXt7gTsYsb0FnMnJNbg=="], + + "@prisma/fetch-engine/@prisma/get-platform": ["@prisma/get-platform@7.3.0", "", { "dependencies": { "@prisma/debug": "7.3.0" } }, "sha512-N7c6m4/I0Q6JYmWKP2RCD/sM9eWiyCPY98g5c0uEktObNSZnugW2U/PO+pwL0UaqzxqTXt7gTsYsb0FnMnJNbg=="], + + "@prisma/get-platform/@prisma/debug": ["@prisma/debug@7.2.0", "", {}, "sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw=="], + + "nypm/citty": ["citty@0.2.0", "", {}, "sha512-8csy5IBFI2ex2hTVpaHN2j+LNE199AgiI7y4dMintrr8i0lQiFn+0AWMZrWdHKIgMOer65f8IThysYhoReqjWA=="], + + "pg-types/postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="], + + "proper-lockfile/signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], } } diff --git a/generated/prisma/browser.ts b/generated/prisma/browser.ts new file mode 100644 index 0000000..cde1741 --- /dev/null +++ b/generated/prisma/browser.ts @@ -0,0 +1,34 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file should be your main import to use Prisma-related types and utilities in a browser. + * Use it to get access to models, enums, and input types. + * + * This file does not contain a `PrismaClient` class, nor several other helpers that are intended as server-side only. + * See `client.ts` for the standard, server-side entry point. + * + * 🟢 You can import this file directly. + */ + +import * as Prisma from './internal/prismaNamespaceBrowser.ts' +export { Prisma } +export * as $Enums from './enums.ts' +export * from './enums.ts'; +/** + * Model Session + * + */ +export type Session = Prisma.SessionModel +/** + * Model User + * + */ +export type User = Prisma.UserModel +/** + * Model Role + * + */ +export type Role = Prisma.RoleModel diff --git a/generated/prisma/client.ts b/generated/prisma/client.ts new file mode 100644 index 0000000..d181956 --- /dev/null +++ b/generated/prisma/client.ts @@ -0,0 +1,56 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file should be your main import to use Prisma. Through it you get access to all the models, enums, and input types. + * If you're looking for something you can import in the client-side of your application, please refer to the `browser.ts` file instead. + * + * 🟢 You can import this file directly. + */ + +import * as process from 'node:process' +import * as path from 'node:path' +import { fileURLToPath } from 'node:url' +globalThis['__dirname'] = path.dirname(fileURLToPath(import.meta.url)) + +import * as runtime from "@prisma/client/runtime/client" +import * as $Enums from "./enums.ts" +import * as $Class from "./internal/class.ts" +import * as Prisma from "./internal/prismaNamespace.ts" + +export * as $Enums from './enums.ts' +export * from "./enums.ts" +/** + * ## Prisma Client + * + * Type-safe database client for TypeScript + * @example + * ``` + * const prisma = new PrismaClient() + * // Fetch zero or more Sessions + * const sessions = await prisma.session.findMany() + * ``` + * + * Read more in our [docs](https://pris.ly/d/client). + */ +export const PrismaClient = $Class.getPrismaClientClass() +export type PrismaClient = $Class.PrismaClient +export { Prisma } + +/** + * Model Session + * + */ +export type Session = Prisma.SessionModel +/** + * Model User + * + */ +export type User = Prisma.UserModel +/** + * Model Role + * + */ +export type Role = Prisma.RoleModel diff --git a/generated/prisma/commonInputTypes.ts b/generated/prisma/commonInputTypes.ts new file mode 100644 index 0000000..2da8eda --- /dev/null +++ b/generated/prisma/commonInputTypes.ts @@ -0,0 +1,352 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports various common sort, input & filter types that are not directly linked to a particular model. + * + * 🟢 You can import this file directly. + */ + +import type * as runtime from "@prisma/client/runtime/client" +import * as $Enums from "./enums.ts" +import type * as Prisma from "./internal/prismaNamespace.ts" + + +export type StringFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + mode?: Prisma.QueryMode + not?: Prisma.NestedStringFilter<$PrismaModel> | string +} + +export type DateTimeFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeFilter<$PrismaModel> | Date | string +} + +export type BoolFilter<$PrismaModel = never> = { + equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> + not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean +} + +export type DateTimeNullableFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null +} + +export type SortOrderInput = { + sort: Prisma.SortOrder + nulls?: Prisma.NullsOrder +} + +export type StringWithAggregatesFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + mode?: Prisma.QueryMode + not?: Prisma.NestedStringWithAggregatesFilter<$PrismaModel> | string + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedStringFilter<$PrismaModel> + _max?: Prisma.NestedStringFilter<$PrismaModel> +} + +export type DateTimeWithAggregatesFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedDateTimeFilter<$PrismaModel> + _max?: Prisma.NestedDateTimeFilter<$PrismaModel> +} + +export type BoolWithAggregatesFilter<$PrismaModel = never> = { + equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> + not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedBoolFilter<$PrismaModel> + _max?: Prisma.NestedBoolFilter<$PrismaModel> +} + +export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null + _count?: Prisma.NestedIntNullableFilter<$PrismaModel> + _min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> + _max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> +} + +export type StringNullableFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + mode?: Prisma.QueryMode + not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null +} + +export type IntFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntFilter<$PrismaModel> | number +} + +export type StringNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + mode?: Prisma.QueryMode + not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null + _count?: Prisma.NestedIntNullableFilter<$PrismaModel> + _min?: Prisma.NestedStringNullableFilter<$PrismaModel> + _max?: Prisma.NestedStringNullableFilter<$PrismaModel> +} + +export type IntWithAggregatesFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntWithAggregatesFilter<$PrismaModel> | number + _count?: Prisma.NestedIntFilter<$PrismaModel> + _avg?: Prisma.NestedFloatFilter<$PrismaModel> + _sum?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedIntFilter<$PrismaModel> + _max?: Prisma.NestedIntFilter<$PrismaModel> +} + +export type NestedStringFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + not?: Prisma.NestedStringFilter<$PrismaModel> | string +} + +export type NestedDateTimeFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeFilter<$PrismaModel> | Date | string +} + +export type NestedBoolFilter<$PrismaModel = never> = { + equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> + not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean +} + +export type NestedDateTimeNullableFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null +} + +export type NestedStringWithAggregatesFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + not?: Prisma.NestedStringWithAggregatesFilter<$PrismaModel> | string + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedStringFilter<$PrismaModel> + _max?: Prisma.NestedStringFilter<$PrismaModel> +} + +export type NestedIntFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntFilter<$PrismaModel> | number +} + +export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedDateTimeFilter<$PrismaModel> + _max?: Prisma.NestedDateTimeFilter<$PrismaModel> +} + +export type NestedBoolWithAggregatesFilter<$PrismaModel = never> = { + equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> + not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean + _count?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedBoolFilter<$PrismaModel> + _max?: Prisma.NestedBoolFilter<$PrismaModel> +} + +export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null + in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null + lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> + not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null + _count?: Prisma.NestedIntNullableFilter<$PrismaModel> + _min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> + _max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> +} + +export type NestedIntNullableFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null +} + +export type NestedStringNullableFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null +} + +export type NestedStringNullableWithAggregatesFilter<$PrismaModel = never> = { + equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null + in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null + lt?: string | Prisma.StringFieldRefInput<$PrismaModel> + lte?: string | Prisma.StringFieldRefInput<$PrismaModel> + gt?: string | Prisma.StringFieldRefInput<$PrismaModel> + gte?: string | Prisma.StringFieldRefInput<$PrismaModel> + contains?: string | Prisma.StringFieldRefInput<$PrismaModel> + startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel> + not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null + _count?: Prisma.NestedIntNullableFilter<$PrismaModel> + _min?: Prisma.NestedStringNullableFilter<$PrismaModel> + _max?: Prisma.NestedStringNullableFilter<$PrismaModel> +} + +export type NestedIntWithAggregatesFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntWithAggregatesFilter<$PrismaModel> | number + _count?: Prisma.NestedIntFilter<$PrismaModel> + _avg?: Prisma.NestedFloatFilter<$PrismaModel> + _sum?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedIntFilter<$PrismaModel> + _max?: Prisma.NestedIntFilter<$PrismaModel> +} + +export type NestedFloatFilter<$PrismaModel = never> = { + equals?: number | Prisma.FloatFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> + lt?: number | Prisma.FloatFieldRefInput<$PrismaModel> + lte?: number | Prisma.FloatFieldRefInput<$PrismaModel> + gt?: number | Prisma.FloatFieldRefInput<$PrismaModel> + gte?: number | Prisma.FloatFieldRefInput<$PrismaModel> + not?: Prisma.NestedFloatFilter<$PrismaModel> | number +} + + diff --git a/generated/prisma/enums.ts b/generated/prisma/enums.ts new file mode 100644 index 0000000..043572d --- /dev/null +++ b/generated/prisma/enums.ts @@ -0,0 +1,15 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* +* This file exports all enum related types from the schema. +* +* 🟢 You can import this file directly. +*/ + + + +// This file is empty because there are no enums in the schema. +export {} diff --git a/generated/prisma/internal/class.ts b/generated/prisma/internal/class.ts new file mode 100644 index 0000000..f9cf156 --- /dev/null +++ b/generated/prisma/internal/class.ts @@ -0,0 +1,212 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * WARNING: This is an internal file that is subject to change! + * + * 🛑 Under no circumstances should you import this file directly! 🛑 + * + * Please import the `PrismaClient` class from the `client.ts` file instead. + */ + +import * as runtime from "@prisma/client/runtime/client" +import type * as Prisma from "./prismaNamespace.ts" + + +const config: runtime.GetPrismaClientConfig = { + "previewFeatures": [], + "clientVersion": "7.3.0", + "engineVersion": "9d6ad21cbbceab97458517b147a6a09ff43aa735", + "activeProvider": "postgresql", + "inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel Session {\n id String @id @default(uuid())\n sessionKey String @unique @default(cuid())\n userId String\n expires DateTime\n refreshTokenGenerated Boolean @default(false)\n refreshedAt DateTime?\n invalidatedAt DateTime?\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n}\n\nmodel User {\n id String @id @default(cuid())\n roles Role[]\n permissions String?\n login String @unique\n name String?\n email String @unique\n emailVerified DateTime?\n image String?\n\n userId Int @unique\n token String?\n\n sessions Session[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel Role {\n id String @id @default(uuid())\n title String\n moniker String @unique // e.g. admin, super_admin, moderator\n\n permissions String\n users User[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n", + "runtimeDataModel": { + "models": {}, + "enums": {}, + "types": {} + } +} + +config.runtimeDataModel = JSON.parse("{\"models\":{\"Session\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessionKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"expires\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"refreshTokenGenerated\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"refreshedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"invalidatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"SessionToUser\"}],\"dbName\":null},\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"roles\",\"kind\":\"object\",\"type\":\"Role\",\"relationName\":\"RoleToUser\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"login\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"emailVerified\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"image\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"token\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessions\",\"kind\":\"object\",\"type\":\"Session\",\"relationName\":\"SessionToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Role\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"moniker\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"users\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"RoleToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") + +async function decodeBase64AsWasm(wasmBase64: string): Promise { + const { Buffer } = await import('node:buffer') + const wasmArray = Buffer.from(wasmBase64, 'base64') + return new WebAssembly.Module(wasmArray) +} + +config.compilerWasm = { + getRuntime: async () => await import("@prisma/client/runtime/query_compiler_fast_bg.postgresql.mjs"), + + getQueryCompilerWasmModule: async () => { + const { wasm } = await import("@prisma/client/runtime/query_compiler_fast_bg.postgresql.wasm-base64.mjs") + return await decodeBase64AsWasm(wasm) + }, + + importName: "./query_compiler_fast_bg.js" +} + + + +export type LogOptions = + 'log' extends keyof ClientOptions ? ClientOptions['log'] extends Array ? Prisma.GetEvents : never : never + +export interface PrismaClientConstructor { + /** + * ## Prisma Client + * + * Type-safe database client for TypeScript + * @example + * ``` + * const prisma = new PrismaClient() + * // Fetch zero or more Sessions + * const sessions = await prisma.session.findMany() + * ``` + * + * Read more in our [docs](https://pris.ly/d/client). + */ + + new < + Options extends Prisma.PrismaClientOptions = Prisma.PrismaClientOptions, + LogOpts extends LogOptions = LogOptions, + OmitOpts extends Prisma.PrismaClientOptions['omit'] = Options extends { omit: infer U } ? U : Prisma.PrismaClientOptions['omit'], + ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs + >(options: Prisma.Subset ): PrismaClient +} + +/** + * ## Prisma Client + * + * Type-safe database client for TypeScript + * @example + * ``` + * const prisma = new PrismaClient() + * // Fetch zero or more Sessions + * const sessions = await prisma.session.findMany() + * ``` + * + * Read more in our [docs](https://pris.ly/d/client). + */ + +export interface PrismaClient< + in LogOpts extends Prisma.LogLevel = never, + in out OmitOpts extends Prisma.PrismaClientOptions['omit'] = undefined, + in out ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs +> { + [K: symbol]: { types: Prisma.TypeMap['other'] } + + $on(eventType: V, callback: (event: V extends 'query' ? Prisma.QueryEvent : Prisma.LogEvent) => void): PrismaClient; + + /** + * Connect with the database + */ + $connect(): runtime.Types.Utils.JsPromise; + + /** + * Disconnect from the database + */ + $disconnect(): runtime.Types.Utils.JsPromise; + +/** + * Executes a prepared raw query and returns the number of affected rows. + * @example + * ``` + * const result = await prisma.$executeRaw`UPDATE User SET cool = ${true} WHERE email = ${'user@email.com'};` + * ``` + * + * Read more in our [docs](https://pris.ly/d/raw-queries). + */ + $executeRaw(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise; + + /** + * Executes a raw query and returns the number of affected rows. + * Susceptible to SQL injections, see documentation. + * @example + * ``` + * const result = await prisma.$executeRawUnsafe('UPDATE User SET cool = $1 WHERE email = $2 ;', true, 'user@email.com') + * ``` + * + * Read more in our [docs](https://pris.ly/d/raw-queries). + */ + $executeRawUnsafe(query: string, ...values: any[]): Prisma.PrismaPromise; + + /** + * Performs a prepared raw query and returns the `SELECT` data. + * @example + * ``` + * const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${1} OR email = ${'user@email.com'};` + * ``` + * + * Read more in our [docs](https://pris.ly/d/raw-queries). + */ + $queryRaw(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise; + + /** + * Performs a raw query and returns the `SELECT` data. + * Susceptible to SQL injections, see documentation. + * @example + * ``` + * const result = await prisma.$queryRawUnsafe('SELECT * FROM User WHERE id = $1 OR email = $2;', 1, 'user@email.com') + * ``` + * + * Read more in our [docs](https://pris.ly/d/raw-queries). + */ + $queryRawUnsafe(query: string, ...values: any[]): Prisma.PrismaPromise; + + + /** + * Allows the running of a sequence of read/write operations that are guaranteed to either succeed or fail as a whole. + * @example + * ``` + * const [george, bob, alice] = await prisma.$transaction([ + * prisma.user.create({ data: { name: 'George' } }), + * prisma.user.create({ data: { name: 'Bob' } }), + * prisma.user.create({ data: { name: 'Alice' } }), + * ]) + * ``` + * + * Read more in our [docs](https://www.prisma.io/docs/concepts/components/prisma-client/transactions). + */ + $transaction

[]>(arg: [...P], options?: { isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise> + + $transaction(fn: (prisma: Omit) => runtime.Types.Utils.JsPromise, options?: { maxWait?: number, timeout?: number, isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise + + $extends: runtime.Types.Extensions.ExtendsHook<"extends", Prisma.TypeMapCb, ExtArgs, runtime.Types.Utils.Call, { + extArgs: ExtArgs + }>> + + /** + * `prisma.session`: Exposes CRUD operations for the **Session** model. + * Example usage: + * ```ts + * // Fetch zero or more Sessions + * const sessions = await prisma.session.findMany() + * ``` + */ + get session(): Prisma.SessionDelegate; + + /** + * `prisma.user`: Exposes CRUD operations for the **User** model. + * Example usage: + * ```ts + * // Fetch zero or more Users + * const users = await prisma.user.findMany() + * ``` + */ + get user(): Prisma.UserDelegate; + + /** + * `prisma.role`: Exposes CRUD operations for the **Role** model. + * Example usage: + * ```ts + * // Fetch zero or more Roles + * const roles = await prisma.role.findMany() + * ``` + */ + get role(): Prisma.RoleDelegate; +} + +export function getPrismaClientClass(): PrismaClientConstructor { + return runtime.getPrismaClient(config) as unknown as PrismaClientConstructor +} diff --git a/generated/prisma/internal/prismaNamespace.ts b/generated/prisma/internal/prismaNamespace.ts new file mode 100644 index 0000000..9bf4a22 --- /dev/null +++ b/generated/prisma/internal/prismaNamespace.ts @@ -0,0 +1,964 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * WARNING: This is an internal file that is subject to change! + * + * 🛑 Under no circumstances should you import this file directly! 🛑 + * + * All exports from this file are wrapped under a `Prisma` namespace object in the client.ts file. + * While this enables partial backward compatibility, it is not part of the stable public API. + * + * If you are looking for your Models, Enums, and Input Types, please import them from the respective + * model files in the `model` directory! + */ + +import * as runtime from "@prisma/client/runtime/client" +import type * as Prisma from "../models.ts" +import { type PrismaClient } from "./class.ts" + +export type * from '../models.ts' + +export type DMMF = typeof runtime.DMMF + +export type PrismaPromise = runtime.Types.Public.PrismaPromise + +/** + * Prisma Errors + */ + +export const PrismaClientKnownRequestError = runtime.PrismaClientKnownRequestError +export type PrismaClientKnownRequestError = runtime.PrismaClientKnownRequestError + +export const PrismaClientUnknownRequestError = runtime.PrismaClientUnknownRequestError +export type PrismaClientUnknownRequestError = runtime.PrismaClientUnknownRequestError + +export const PrismaClientRustPanicError = runtime.PrismaClientRustPanicError +export type PrismaClientRustPanicError = runtime.PrismaClientRustPanicError + +export const PrismaClientInitializationError = runtime.PrismaClientInitializationError +export type PrismaClientInitializationError = runtime.PrismaClientInitializationError + +export const PrismaClientValidationError = runtime.PrismaClientValidationError +export type PrismaClientValidationError = runtime.PrismaClientValidationError + +/** + * Re-export of sql-template-tag + */ +export const sql = runtime.sqltag +export const empty = runtime.empty +export const join = runtime.join +export const raw = runtime.raw +export const Sql = runtime.Sql +export type Sql = runtime.Sql + + + +/** + * Decimal.js + */ +export const Decimal = runtime.Decimal +export type Decimal = runtime.Decimal + +export type DecimalJsLike = runtime.DecimalJsLike + +/** +* Extensions +*/ +export type Extension = runtime.Types.Extensions.UserArgs +export const getExtensionContext = runtime.Extensions.getExtensionContext +export type Args = runtime.Types.Public.Args +export type Payload = runtime.Types.Public.Payload +export type Result = runtime.Types.Public.Result +export type Exact = runtime.Types.Public.Exact + +export type PrismaVersion = { + client: string + engine: string +} + +/** + * Prisma Client JS version: 7.3.0 + * Query Engine version: 9d6ad21cbbceab97458517b147a6a09ff43aa735 + */ +export const prismaVersion: PrismaVersion = { + client: "7.3.0", + engine: "9d6ad21cbbceab97458517b147a6a09ff43aa735" +} + +/** + * Utility Types + */ + +export type Bytes = runtime.Bytes +export type JsonObject = runtime.JsonObject +export type JsonArray = runtime.JsonArray +export type JsonValue = runtime.JsonValue +export type InputJsonObject = runtime.InputJsonObject +export type InputJsonArray = runtime.InputJsonArray +export type InputJsonValue = runtime.InputJsonValue + + +export const NullTypes = { + DbNull: runtime.NullTypes.DbNull as (new (secret: never) => typeof runtime.DbNull), + JsonNull: runtime.NullTypes.JsonNull as (new (secret: never) => typeof runtime.JsonNull), + AnyNull: runtime.NullTypes.AnyNull as (new (secret: never) => typeof runtime.AnyNull), +} +/** + * Helper for filtering JSON entries that have `null` on the database (empty on the db) + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ +export const DbNull = runtime.DbNull + +/** + * Helper for filtering JSON entries that have JSON `null` values (not empty on the db) + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ +export const JsonNull = runtime.JsonNull + +/** + * Helper for filtering JSON entries that are `Prisma.DbNull` or `Prisma.JsonNull` + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ +export const AnyNull = runtime.AnyNull + + +type SelectAndInclude = { + select: any + include: any +} + +type SelectAndOmit = { + select: any + omit: any +} + +/** + * From T, pick a set of properties whose keys are in the union K + */ +type Prisma__Pick = { + [P in K]: T[P]; +}; + +export type Enumerable = T | Array; + +/** + * Subset + * @desc From `T` pick properties that exist in `U`. Simple version of Intersection + */ +export type Subset = { + [key in keyof T]: key extends keyof U ? T[key] : never; +}; + +/** + * SelectSubset + * @desc From `T` pick properties that exist in `U`. Simple version of Intersection. + * Additionally, it validates, if both select and include are present. If the case, it errors. + */ +export type SelectSubset = { + [key in keyof T]: key extends keyof U ? T[key] : never +} & + (T extends SelectAndInclude + ? 'Please either choose `select` or `include`.' + : T extends SelectAndOmit + ? 'Please either choose `select` or `omit`.' + : {}) + +/** + * Subset + Intersection + * @desc From `T` pick properties that exist in `U` and intersect `K` + */ +export type SubsetIntersection = { + [key in keyof T]: key extends keyof U ? T[key] : never +} & + K + +type Without = { [P in Exclude]?: never }; + +/** + * XOR is needed to have a real mutually exclusive union type + * https://stackoverflow.com/questions/42123407/does-typescript-support-mutually-exclusive-types + */ +export type XOR = + T extends object ? + U extends object ? + (Without & U) | (Without & T) + : U : T + + +/** + * Is T a Record? + */ +type IsObject = T extends Array +? False +: T extends Date +? False +: T extends Uint8Array +? False +: T extends BigInt +? False +: T extends object +? True +: False + + +/** + * If it's T[], return T + */ +export type UnEnumerate = T extends Array ? U : T + +/** + * From ts-toolbelt + */ + +type __Either = Omit & + { + // Merge all but K + [P in K]: Prisma__Pick // With K possibilities + }[K] + +type EitherStrict = Strict<__Either> + +type EitherLoose = ComputeRaw<__Either> + +type _Either< + O extends object, + K extends Key, + strict extends Boolean +> = { + 1: EitherStrict + 0: EitherLoose +}[strict] + +export type Either< + O extends object, + K extends Key, + strict extends Boolean = 1 +> = O extends unknown ? _Either : never + +export type Union = any + +export type PatchUndefined = { + [K in keyof O]: O[K] extends undefined ? At : O[K] +} & {} + +/** Helper Types for "Merge" **/ +export type IntersectOf = ( + U extends unknown ? (k: U) => void : never +) extends (k: infer I) => void + ? I + : never + +export type Overwrite = { + [K in keyof O]: K extends keyof O1 ? O1[K] : O[K]; +} & {}; + +type _Merge = IntersectOf; +}>>; + +type Key = string | number | symbol; +type AtStrict = O[K & keyof O]; +type AtLoose = O extends unknown ? AtStrict : never; +export type At = { + 1: AtStrict; + 0: AtLoose; +}[strict]; + +export type ComputeRaw = A extends Function ? A : { + [K in keyof A]: A[K]; +} & {}; + +export type OptionalFlat = { + [K in keyof O]?: O[K]; +} & {}; + +type _Record = { + [P in K]: T; +}; + +// cause typescript not to expand types and preserve names +type NoExpand = T extends unknown ? T : never; + +// this type assumes the passed object is entirely optional +export type AtLeast = NoExpand< + O extends unknown + ? | (K extends keyof O ? { [P in K]: O[P] } & O : O) + | {[P in keyof O as P extends K ? P : never]-?: O[P]} & O + : never>; + +type _Strict = U extends unknown ? U & OptionalFlat<_Record, keyof U>, never>> : never; + +export type Strict = ComputeRaw<_Strict>; +/** End Helper Types for "Merge" **/ + +export type Merge = ComputeRaw<_Merge>>; + +export type Boolean = True | False + +export type True = 1 + +export type False = 0 + +export type Not = { + 0: 1 + 1: 0 +}[B] + +export type Extends = [A1] extends [never] + ? 0 // anything `never` is false + : A1 extends A2 + ? 1 + : 0 + +export type Has = Not< + Extends, U1> +> + +export type Or = { + 0: { + 0: 0 + 1: 1 + } + 1: { + 0: 1 + 1: 1 + } +}[B1][B2] + +export type Keys = U extends unknown ? keyof U : never + +export type GetScalarType = O extends object ? { + [P in keyof T]: P extends keyof O + ? O[P] + : never +} : never + +type FieldPaths< + T, + U = Omit +> = IsObject extends True ? U : T + +export type GetHavingFields = { + [K in keyof T]: Or< + Or, Extends<'AND', K>>, + Extends<'NOT', K> + > extends True + ? // infer is only needed to not hit TS limit + // based on the brilliant idea of Pierre-Antoine Mills + // https://github.com/microsoft/TypeScript/issues/30188#issuecomment-478938437 + T[K] extends infer TK + ? GetHavingFields extends object ? Merge> : never> + : never + : {} extends FieldPaths + ? never + : K +}[keyof T] + +/** + * Convert tuple to union + */ +type _TupleToUnion = T extends (infer E)[] ? E : never +type TupleToUnion = _TupleToUnion +export type MaybeTupleToUnion = T extends any[] ? TupleToUnion : T + +/** + * Like `Pick`, but additionally can also accept an array of keys + */ +export type PickEnumerable | keyof T> = Prisma__Pick> + +/** + * Exclude all keys with underscores + */ +export type ExcludeUnderscoreKeys = T extends `_${string}` ? never : T + + +export type FieldRef = runtime.FieldRef + +type FieldRefInputType = Model extends never ? never : FieldRef + + +export const ModelName = { + Session: 'Session', + User: 'User', + Role: 'Role' +} as const + +export type ModelName = (typeof ModelName)[keyof typeof ModelName] + + + +export interface TypeMapCb extends runtime.Types.Utils.Fn<{extArgs: runtime.Types.Extensions.InternalArgs }, runtime.Types.Utils.Record> { + returns: TypeMap +} + +export type TypeMap = { + globalOmitOptions: { + omit: GlobalOmitOptions + } + meta: { + modelProps: "session" | "user" | "role" + txIsolationLevel: TransactionIsolationLevel + } + model: { + Session: { + payload: Prisma.$SessionPayload + fields: Prisma.SessionFieldRefs + operations: { + findUnique: { + args: Prisma.SessionFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.SessionFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.SessionFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.SessionFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.SessionFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.SessionCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.SessionCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.SessionCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.SessionDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.SessionUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.SessionDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.SessionUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.SessionUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.SessionUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.SessionAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.SessionGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.SessionCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + User: { + payload: Prisma.$UserPayload + fields: Prisma.UserFieldRefs + operations: { + findUnique: { + args: Prisma.UserFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.UserFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.UserFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.UserFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.UserFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.UserCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.UserCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.UserCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.UserDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.UserUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.UserDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.UserUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.UserUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.UserUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.UserAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.UserGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.UserCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + Role: { + payload: Prisma.$RolePayload + fields: Prisma.RoleFieldRefs + operations: { + findUnique: { + args: Prisma.RoleFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.RoleFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.RoleFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.RoleFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.RoleFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.RoleCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.RoleCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.RoleCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.RoleDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.RoleUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.RoleDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.RoleUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.RoleUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.RoleUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.RoleAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.RoleGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.RoleCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } + } +} & { + other: { + payload: any + operations: { + $executeRaw: { + args: [query: TemplateStringsArray | Sql, ...values: any[]], + result: any + } + $executeRawUnsafe: { + args: [query: string, ...values: any[]], + result: any + } + $queryRaw: { + args: [query: TemplateStringsArray | Sql, ...values: any[]], + result: any + } + $queryRawUnsafe: { + args: [query: string, ...values: any[]], + result: any + } + } + } +} + +/** + * Enums + */ + +export const TransactionIsolationLevel = runtime.makeStrictEnum({ + ReadUncommitted: 'ReadUncommitted', + ReadCommitted: 'ReadCommitted', + RepeatableRead: 'RepeatableRead', + Serializable: 'Serializable' +} as const) + +export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel] + + +export const SessionScalarFieldEnum = { + id: 'id', + sessionKey: 'sessionKey', + userId: 'userId', + expires: 'expires', + refreshTokenGenerated: 'refreshTokenGenerated', + refreshedAt: 'refreshedAt', + invalidatedAt: 'invalidatedAt' +} as const + +export type SessionScalarFieldEnum = (typeof SessionScalarFieldEnum)[keyof typeof SessionScalarFieldEnum] + + +export const UserScalarFieldEnum = { + id: 'id', + permissions: 'permissions', + login: 'login', + name: 'name', + email: 'email', + emailVerified: 'emailVerified', + image: 'image', + userId: 'userId', + token: 'token', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum] + + +export const RoleScalarFieldEnum = { + id: 'id', + title: 'title', + moniker: 'moniker', + permissions: 'permissions', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type RoleScalarFieldEnum = (typeof RoleScalarFieldEnum)[keyof typeof RoleScalarFieldEnum] + + +export const SortOrder = { + asc: 'asc', + desc: 'desc' +} as const + +export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder] + + +export const QueryMode = { + default: 'default', + insensitive: 'insensitive' +} as const + +export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode] + + +export const NullsOrder = { + first: 'first', + last: 'last' +} as const + +export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder] + + + +/** + * Field references + */ + + +/** + * Reference to a field of type 'String' + */ +export type StringFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'String'> + + + +/** + * Reference to a field of type 'String[]' + */ +export type ListStringFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'String[]'> + + + +/** + * Reference to a field of type 'DateTime' + */ +export type DateTimeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'DateTime'> + + + +/** + * Reference to a field of type 'DateTime[]' + */ +export type ListDateTimeFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'DateTime[]'> + + + +/** + * Reference to a field of type 'Boolean' + */ +export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Boolean'> + + + +/** + * Reference to a field of type 'Int' + */ +export type IntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Int'> + + + +/** + * Reference to a field of type 'Int[]' + */ +export type ListIntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Int[]'> + + + +/** + * Reference to a field of type 'Float' + */ +export type FloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float'> + + + +/** + * Reference to a field of type 'Float[]' + */ +export type ListFloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float[]'> + + +/** + * Batch Payload for updateMany & deleteMany & createMany + */ +export type BatchPayload = { + count: number +} + +export const defineExtension = runtime.Extensions.defineExtension as unknown as runtime.Types.Extensions.ExtendsHook<"define", TypeMapCb, runtime.Types.Extensions.DefaultArgs> +export type DefaultPrismaClient = PrismaClient +export type ErrorFormat = 'pretty' | 'colorless' | 'minimal' +export type PrismaClientOptions = ({ + /** + * Instance of a Driver Adapter, e.g., like one provided by `@prisma/adapter-pg`. + */ + adapter: runtime.SqlDriverAdapterFactory + accelerateUrl?: never +} | { + /** + * Prisma Accelerate URL allowing the client to connect through Accelerate instead of a direct database. + */ + accelerateUrl: string + adapter?: never +}) & { + /** + * @default "colorless" + */ + errorFormat?: ErrorFormat + /** + * @example + * ``` + * // Shorthand for `emit: 'stdout'` + * log: ['query', 'info', 'warn', 'error'] + * + * // Emit as events only + * log: [ + * { emit: 'event', level: 'query' }, + * { emit: 'event', level: 'info' }, + * { emit: 'event', level: 'warn' } + * { emit: 'event', level: 'error' } + * ] + * + * / Emit as events and log to stdout + * og: [ + * { emit: 'stdout', level: 'query' }, + * { emit: 'stdout', level: 'info' }, + * { emit: 'stdout', level: 'warn' } + * { emit: 'stdout', level: 'error' } + * + * ``` + * Read more in our [docs](https://pris.ly/d/logging). + */ + log?: (LogLevel | LogDefinition)[] + /** + * The default values for transactionOptions + * maxWait ?= 2000 + * timeout ?= 5000 + */ + transactionOptions?: { + maxWait?: number + timeout?: number + isolationLevel?: TransactionIsolationLevel + } + /** + * Global configuration for omitting model fields by default. + * + * @example + * ``` + * const prisma = new PrismaClient({ + * omit: { + * user: { + * password: true + * } + * } + * }) + * ``` + */ + omit?: GlobalOmitConfig + /** + * SQL commenter plugins that add metadata to SQL queries as comments. + * Comments follow the sqlcommenter format: https://google.github.io/sqlcommenter/ + * + * @example + * ``` + * const prisma = new PrismaClient({ + * adapter, + * comments: [ + * traceContext(), + * queryInsights(), + * ], + * }) + * ``` + */ + comments?: runtime.SqlCommenterPlugin[] +} +export type GlobalOmitConfig = { + session?: Prisma.SessionOmit + user?: Prisma.UserOmit + role?: Prisma.RoleOmit +} + +/* Types for Logging */ +export type LogLevel = 'info' | 'query' | 'warn' | 'error' +export type LogDefinition = { + level: LogLevel + emit: 'stdout' | 'event' +} + +export type CheckIsLogLevel = T extends LogLevel ? T : never; + +export type GetLogType = CheckIsLogLevel< + T extends LogDefinition ? T['level'] : T +>; + +export type GetEvents = T extends Array + ? GetLogType + : never; + +export type QueryEvent = { + timestamp: Date + query: string + params: string + duration: number + target: string +} + +export type LogEvent = { + timestamp: Date + message: string + target: string +} +/* End Types for Logging */ + + +export type PrismaAction = + | 'findUnique' + | 'findUniqueOrThrow' + | 'findMany' + | 'findFirst' + | 'findFirstOrThrow' + | 'create' + | 'createMany' + | 'createManyAndReturn' + | 'update' + | 'updateMany' + | 'updateManyAndReturn' + | 'upsert' + | 'delete' + | 'deleteMany' + | 'executeRaw' + | 'queryRaw' + | 'aggregate' + | 'count' + | 'runCommandRaw' + | 'findRaw' + | 'groupBy' + +/** + * `PrismaClient` proxy available in interactive transactions. + */ +export type TransactionClient = Omit + diff --git a/generated/prisma/internal/prismaNamespaceBrowser.ts b/generated/prisma/internal/prismaNamespaceBrowser.ts new file mode 100644 index 0000000..4be0826 --- /dev/null +++ b/generated/prisma/internal/prismaNamespaceBrowser.ts @@ -0,0 +1,139 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * WARNING: This is an internal file that is subject to change! + * + * 🛑 Under no circumstances should you import this file directly! 🛑 + * + * All exports from this file are wrapped under a `Prisma` namespace object in the browser.ts file. + * While this enables partial backward compatibility, it is not part of the stable public API. + * + * If you are looking for your Models, Enums, and Input Types, please import them from the respective + * model files in the `model` directory! + */ + +import * as runtime from "@prisma/client/runtime/index-browser" + +export type * from '../models.ts' +export type * from './prismaNamespace.ts' + +export const Decimal = runtime.Decimal + + +export const NullTypes = { + DbNull: runtime.NullTypes.DbNull as (new (secret: never) => typeof runtime.DbNull), + JsonNull: runtime.NullTypes.JsonNull as (new (secret: never) => typeof runtime.JsonNull), + AnyNull: runtime.NullTypes.AnyNull as (new (secret: never) => typeof runtime.AnyNull), +} +/** + * Helper for filtering JSON entries that have `null` on the database (empty on the db) + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ +export const DbNull = runtime.DbNull + +/** + * Helper for filtering JSON entries that have JSON `null` values (not empty on the db) + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ +export const JsonNull = runtime.JsonNull + +/** + * Helper for filtering JSON entries that are `Prisma.DbNull` or `Prisma.JsonNull` + * + * @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field + */ +export const AnyNull = runtime.AnyNull + + +export const ModelName = { + Session: 'Session', + User: 'User', + Role: 'Role' +} as const + +export type ModelName = (typeof ModelName)[keyof typeof ModelName] + +/* + * Enums + */ + +export const TransactionIsolationLevel = runtime.makeStrictEnum({ + ReadUncommitted: 'ReadUncommitted', + ReadCommitted: 'ReadCommitted', + RepeatableRead: 'RepeatableRead', + Serializable: 'Serializable' +} as const) + +export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel] + + +export const SessionScalarFieldEnum = { + id: 'id', + sessionKey: 'sessionKey', + userId: 'userId', + expires: 'expires', + refreshTokenGenerated: 'refreshTokenGenerated', + refreshedAt: 'refreshedAt', + invalidatedAt: 'invalidatedAt' +} as const + +export type SessionScalarFieldEnum = (typeof SessionScalarFieldEnum)[keyof typeof SessionScalarFieldEnum] + + +export const UserScalarFieldEnum = { + id: 'id', + permissions: 'permissions', + login: 'login', + name: 'name', + email: 'email', + emailVerified: 'emailVerified', + image: 'image', + userId: 'userId', + token: 'token', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum] + + +export const RoleScalarFieldEnum = { + id: 'id', + title: 'title', + moniker: 'moniker', + permissions: 'permissions', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type RoleScalarFieldEnum = (typeof RoleScalarFieldEnum)[keyof typeof RoleScalarFieldEnum] + + +export const SortOrder = { + asc: 'asc', + desc: 'desc' +} as const + +export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder] + + +export const QueryMode = { + default: 'default', + insensitive: 'insensitive' +} as const + +export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode] + + +export const NullsOrder = { + first: 'first', + last: 'last' +} as const + +export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder] + diff --git a/generated/prisma/models.ts b/generated/prisma/models.ts new file mode 100644 index 0000000..5076f8f --- /dev/null +++ b/generated/prisma/models.ts @@ -0,0 +1,14 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This is a barrel export file for all models and their related types. + * + * 🟢 You can import this file directly. + */ +export type * from './models/Session.ts' +export type * from './models/User.ts' +export type * from './models/Role.ts' +export type * from './commonInputTypes.ts' \ No newline at end of file diff --git a/generated/prisma/models/Role.ts b/generated/prisma/models/Role.ts new file mode 100644 index 0000000..6b592f1 --- /dev/null +++ b/generated/prisma/models/Role.ts @@ -0,0 +1,1409 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `Role` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.ts" +import type * as Prisma from "../internal/prismaNamespace.ts" + +/** + * Model Role + * + */ +export type RoleModel = runtime.Types.Result.DefaultSelection + +export type AggregateRole = { + _count: RoleCountAggregateOutputType | null + _min: RoleMinAggregateOutputType | null + _max: RoleMaxAggregateOutputType | null +} + +export type RoleMinAggregateOutputType = { + id: string | null + title: string | null + moniker: string | null + permissions: string | null + createdAt: Date | null + updatedAt: Date | null +} + +export type RoleMaxAggregateOutputType = { + id: string | null + title: string | null + moniker: string | null + permissions: string | null + createdAt: Date | null + updatedAt: Date | null +} + +export type RoleCountAggregateOutputType = { + id: number + title: number + moniker: number + permissions: number + createdAt: number + updatedAt: number + _all: number +} + + +export type RoleMinAggregateInputType = { + id?: true + title?: true + moniker?: true + permissions?: true + createdAt?: true + updatedAt?: true +} + +export type RoleMaxAggregateInputType = { + id?: true + title?: true + moniker?: true + permissions?: true + createdAt?: true + updatedAt?: true +} + +export type RoleCountAggregateInputType = { + id?: true + title?: true + moniker?: true + permissions?: true + createdAt?: true + updatedAt?: true + _all?: true +} + +export type RoleAggregateArgs = { + /** + * Filter which Role to aggregate. + */ + where?: Prisma.RoleWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Roles to fetch. + */ + orderBy?: Prisma.RoleOrderByWithRelationInput | Prisma.RoleOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.RoleWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Roles from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Roles. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Roles + **/ + _count?: true | RoleCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: RoleMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: RoleMaxAggregateInputType +} + +export type GetRoleAggregateType = { + [P in keyof T & keyof AggregateRole]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type RoleGroupByArgs = { + where?: Prisma.RoleWhereInput + orderBy?: Prisma.RoleOrderByWithAggregationInput | Prisma.RoleOrderByWithAggregationInput[] + by: Prisma.RoleScalarFieldEnum[] | Prisma.RoleScalarFieldEnum + having?: Prisma.RoleScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: RoleCountAggregateInputType | true + _min?: RoleMinAggregateInputType + _max?: RoleMaxAggregateInputType +} + +export type RoleGroupByOutputType = { + id: string + title: string + moniker: string + permissions: string + createdAt: Date + updatedAt: Date + _count: RoleCountAggregateOutputType | null + _min: RoleMinAggregateOutputType | null + _max: RoleMaxAggregateOutputType | null +} + +type GetRoleGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof RoleGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type RoleWhereInput = { + AND?: Prisma.RoleWhereInput | Prisma.RoleWhereInput[] + OR?: Prisma.RoleWhereInput[] + NOT?: Prisma.RoleWhereInput | Prisma.RoleWhereInput[] + id?: Prisma.StringFilter<"Role"> | string + title?: Prisma.StringFilter<"Role"> | string + moniker?: Prisma.StringFilter<"Role"> | string + permissions?: Prisma.StringFilter<"Role"> | string + createdAt?: Prisma.DateTimeFilter<"Role"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"Role"> | Date | string + users?: Prisma.UserListRelationFilter +} + +export type RoleOrderByWithRelationInput = { + id?: Prisma.SortOrder + title?: Prisma.SortOrder + moniker?: Prisma.SortOrder + permissions?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + users?: Prisma.UserOrderByRelationAggregateInput +} + +export type RoleWhereUniqueInput = Prisma.AtLeast<{ + id?: string + moniker?: string + AND?: Prisma.RoleWhereInput | Prisma.RoleWhereInput[] + OR?: Prisma.RoleWhereInput[] + NOT?: Prisma.RoleWhereInput | Prisma.RoleWhereInput[] + title?: Prisma.StringFilter<"Role"> | string + permissions?: Prisma.StringFilter<"Role"> | string + createdAt?: Prisma.DateTimeFilter<"Role"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"Role"> | Date | string + users?: Prisma.UserListRelationFilter +}, "id" | "moniker"> + +export type RoleOrderByWithAggregationInput = { + id?: Prisma.SortOrder + title?: Prisma.SortOrder + moniker?: Prisma.SortOrder + permissions?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + _count?: Prisma.RoleCountOrderByAggregateInput + _max?: Prisma.RoleMaxOrderByAggregateInput + _min?: Prisma.RoleMinOrderByAggregateInput +} + +export type RoleScalarWhereWithAggregatesInput = { + AND?: Prisma.RoleScalarWhereWithAggregatesInput | Prisma.RoleScalarWhereWithAggregatesInput[] + OR?: Prisma.RoleScalarWhereWithAggregatesInput[] + NOT?: Prisma.RoleScalarWhereWithAggregatesInput | Prisma.RoleScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"Role"> | string + title?: Prisma.StringWithAggregatesFilter<"Role"> | string + moniker?: Prisma.StringWithAggregatesFilter<"Role"> | string + permissions?: Prisma.StringWithAggregatesFilter<"Role"> | string + createdAt?: Prisma.DateTimeWithAggregatesFilter<"Role"> | Date | string + updatedAt?: Prisma.DateTimeWithAggregatesFilter<"Role"> | Date | string +} + +export type RoleCreateInput = { + id?: string + title: string + moniker: string + permissions: string + createdAt?: Date | string + updatedAt?: Date | string + users?: Prisma.UserCreateNestedManyWithoutRolesInput +} + +export type RoleUncheckedCreateInput = { + id?: string + title: string + moniker: string + permissions: string + createdAt?: Date | string + updatedAt?: Date | string + users?: Prisma.UserUncheckedCreateNestedManyWithoutRolesInput +} + +export type RoleUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + moniker?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + users?: Prisma.UserUpdateManyWithoutRolesNestedInput +} + +export type RoleUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + moniker?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + users?: Prisma.UserUncheckedUpdateManyWithoutRolesNestedInput +} + +export type RoleCreateManyInput = { + id?: string + title: string + moniker: string + permissions: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type RoleUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + moniker?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type RoleUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + moniker?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type RoleListRelationFilter = { + every?: Prisma.RoleWhereInput + some?: Prisma.RoleWhereInput + none?: Prisma.RoleWhereInput +} + +export type RoleOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type RoleCountOrderByAggregateInput = { + id?: Prisma.SortOrder + title?: Prisma.SortOrder + moniker?: Prisma.SortOrder + permissions?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type RoleMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + title?: Prisma.SortOrder + moniker?: Prisma.SortOrder + permissions?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type RoleMinOrderByAggregateInput = { + id?: Prisma.SortOrder + title?: Prisma.SortOrder + moniker?: Prisma.SortOrder + permissions?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type RoleCreateNestedManyWithoutUsersInput = { + create?: Prisma.XOR | Prisma.RoleCreateWithoutUsersInput[] | Prisma.RoleUncheckedCreateWithoutUsersInput[] + connectOrCreate?: Prisma.RoleCreateOrConnectWithoutUsersInput | Prisma.RoleCreateOrConnectWithoutUsersInput[] + connect?: Prisma.RoleWhereUniqueInput | Prisma.RoleWhereUniqueInput[] +} + +export type RoleUncheckedCreateNestedManyWithoutUsersInput = { + create?: Prisma.XOR | Prisma.RoleCreateWithoutUsersInput[] | Prisma.RoleUncheckedCreateWithoutUsersInput[] + connectOrCreate?: Prisma.RoleCreateOrConnectWithoutUsersInput | Prisma.RoleCreateOrConnectWithoutUsersInput[] + connect?: Prisma.RoleWhereUniqueInput | Prisma.RoleWhereUniqueInput[] +} + +export type RoleUpdateManyWithoutUsersNestedInput = { + create?: Prisma.XOR | Prisma.RoleCreateWithoutUsersInput[] | Prisma.RoleUncheckedCreateWithoutUsersInput[] + connectOrCreate?: Prisma.RoleCreateOrConnectWithoutUsersInput | Prisma.RoleCreateOrConnectWithoutUsersInput[] + upsert?: Prisma.RoleUpsertWithWhereUniqueWithoutUsersInput | Prisma.RoleUpsertWithWhereUniqueWithoutUsersInput[] + set?: Prisma.RoleWhereUniqueInput | Prisma.RoleWhereUniqueInput[] + disconnect?: Prisma.RoleWhereUniqueInput | Prisma.RoleWhereUniqueInput[] + delete?: Prisma.RoleWhereUniqueInput | Prisma.RoleWhereUniqueInput[] + connect?: Prisma.RoleWhereUniqueInput | Prisma.RoleWhereUniqueInput[] + update?: Prisma.RoleUpdateWithWhereUniqueWithoutUsersInput | Prisma.RoleUpdateWithWhereUniqueWithoutUsersInput[] + updateMany?: Prisma.RoleUpdateManyWithWhereWithoutUsersInput | Prisma.RoleUpdateManyWithWhereWithoutUsersInput[] + deleteMany?: Prisma.RoleScalarWhereInput | Prisma.RoleScalarWhereInput[] +} + +export type RoleUncheckedUpdateManyWithoutUsersNestedInput = { + create?: Prisma.XOR | Prisma.RoleCreateWithoutUsersInput[] | Prisma.RoleUncheckedCreateWithoutUsersInput[] + connectOrCreate?: Prisma.RoleCreateOrConnectWithoutUsersInput | Prisma.RoleCreateOrConnectWithoutUsersInput[] + upsert?: Prisma.RoleUpsertWithWhereUniqueWithoutUsersInput | Prisma.RoleUpsertWithWhereUniqueWithoutUsersInput[] + set?: Prisma.RoleWhereUniqueInput | Prisma.RoleWhereUniqueInput[] + disconnect?: Prisma.RoleWhereUniqueInput | Prisma.RoleWhereUniqueInput[] + delete?: Prisma.RoleWhereUniqueInput | Prisma.RoleWhereUniqueInput[] + connect?: Prisma.RoleWhereUniqueInput | Prisma.RoleWhereUniqueInput[] + update?: Prisma.RoleUpdateWithWhereUniqueWithoutUsersInput | Prisma.RoleUpdateWithWhereUniqueWithoutUsersInput[] + updateMany?: Prisma.RoleUpdateManyWithWhereWithoutUsersInput | Prisma.RoleUpdateManyWithWhereWithoutUsersInput[] + deleteMany?: Prisma.RoleScalarWhereInput | Prisma.RoleScalarWhereInput[] +} + +export type RoleCreateWithoutUsersInput = { + id?: string + title: string + moniker: string + permissions: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type RoleUncheckedCreateWithoutUsersInput = { + id?: string + title: string + moniker: string + permissions: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type RoleCreateOrConnectWithoutUsersInput = { + where: Prisma.RoleWhereUniqueInput + create: Prisma.XOR +} + +export type RoleUpsertWithWhereUniqueWithoutUsersInput = { + where: Prisma.RoleWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type RoleUpdateWithWhereUniqueWithoutUsersInput = { + where: Prisma.RoleWhereUniqueInput + data: Prisma.XOR +} + +export type RoleUpdateManyWithWhereWithoutUsersInput = { + where: Prisma.RoleScalarWhereInput + data: Prisma.XOR +} + +export type RoleScalarWhereInput = { + AND?: Prisma.RoleScalarWhereInput | Prisma.RoleScalarWhereInput[] + OR?: Prisma.RoleScalarWhereInput[] + NOT?: Prisma.RoleScalarWhereInput | Prisma.RoleScalarWhereInput[] + id?: Prisma.StringFilter<"Role"> | string + title?: Prisma.StringFilter<"Role"> | string + moniker?: Prisma.StringFilter<"Role"> | string + permissions?: Prisma.StringFilter<"Role"> | string + createdAt?: Prisma.DateTimeFilter<"Role"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"Role"> | Date | string +} + +export type RoleUpdateWithoutUsersInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + moniker?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type RoleUncheckedUpdateWithoutUsersInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + moniker?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type RoleUncheckedUpdateManyWithoutUsersInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + title?: Prisma.StringFieldUpdateOperationsInput | string + moniker?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + +/** + * Count Type RoleCountOutputType + */ + +export type RoleCountOutputType = { + users: number +} + +export type RoleCountOutputTypeSelect = { + users?: boolean | RoleCountOutputTypeCountUsersArgs +} + +/** + * RoleCountOutputType without action + */ +export type RoleCountOutputTypeDefaultArgs = { + /** + * Select specific fields to fetch from the RoleCountOutputType + */ + select?: Prisma.RoleCountOutputTypeSelect | null +} + +/** + * RoleCountOutputType without action + */ +export type RoleCountOutputTypeCountUsersArgs = { + where?: Prisma.UserWhereInput +} + + +export type RoleSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + title?: boolean + moniker?: boolean + permissions?: boolean + createdAt?: boolean + updatedAt?: boolean + users?: boolean | Prisma.Role$usersArgs + _count?: boolean | Prisma.RoleCountOutputTypeDefaultArgs +}, ExtArgs["result"]["role"]> + +export type RoleSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + title?: boolean + moniker?: boolean + permissions?: boolean + createdAt?: boolean + updatedAt?: boolean +}, ExtArgs["result"]["role"]> + +export type RoleSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + title?: boolean + moniker?: boolean + permissions?: boolean + createdAt?: boolean + updatedAt?: boolean +}, ExtArgs["result"]["role"]> + +export type RoleSelectScalar = { + id?: boolean + title?: boolean + moniker?: boolean + permissions?: boolean + createdAt?: boolean + updatedAt?: boolean +} + +export type RoleOmit = runtime.Types.Extensions.GetOmit<"id" | "title" | "moniker" | "permissions" | "createdAt" | "updatedAt", ExtArgs["result"]["role"]> +export type RoleInclude = { + users?: boolean | Prisma.Role$usersArgs + _count?: boolean | Prisma.RoleCountOutputTypeDefaultArgs +} +export type RoleIncludeCreateManyAndReturn = {} +export type RoleIncludeUpdateManyAndReturn = {} + +export type $RolePayload = { + name: "Role" + objects: { + users: Prisma.$UserPayload[] + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + title: string + moniker: string + permissions: string + createdAt: Date + updatedAt: Date + }, ExtArgs["result"]["role"]> + composites: {} +} + +export type RoleGetPayload = runtime.Types.Result.GetResult + +export type RoleCountArgs = + Omit & { + select?: RoleCountAggregateInputType | true + } + +export interface RoleDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['Role'], meta: { name: 'Role' } } + /** + * Find zero or one Role that matches the filter. + * @param {RoleFindUniqueArgs} args - Arguments to find a Role + * @example + * // Get one Role + * const role = await prisma.role.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__RoleClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one Role that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {RoleFindUniqueOrThrowArgs} args - Arguments to find a Role + * @example + * // Get one Role + * const role = await prisma.role.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__RoleClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Role that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {RoleFindFirstArgs} args - Arguments to find a Role + * @example + * // Get one Role + * const role = await prisma.role.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__RoleClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Role that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {RoleFindFirstOrThrowArgs} args - Arguments to find a Role + * @example + * // Get one Role + * const role = await prisma.role.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__RoleClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more Roles that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {RoleFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all Roles + * const roles = await prisma.role.findMany() + * + * // Get first 10 Roles + * const roles = await prisma.role.findMany({ take: 10 }) + * + * // Only select the `id` + * const roleWithIdOnly = await prisma.role.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a Role. + * @param {RoleCreateArgs} args - Arguments to create a Role. + * @example + * // Create one Role + * const Role = await prisma.role.create({ + * data: { + * // ... data to create a Role + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__RoleClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many Roles. + * @param {RoleCreateManyArgs} args - Arguments to create many Roles. + * @example + * // Create many Roles + * const role = await prisma.role.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many Roles and returns the data saved in the database. + * @param {RoleCreateManyAndReturnArgs} args - Arguments to create many Roles. + * @example + * // Create many Roles + * const role = await prisma.role.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many Roles and only return the `id` + * const roleWithIdOnly = await prisma.role.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a Role. + * @param {RoleDeleteArgs} args - Arguments to delete one Role. + * @example + * // Delete one Role + * const Role = await prisma.role.delete({ + * where: { + * // ... filter to delete one Role + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__RoleClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one Role. + * @param {RoleUpdateArgs} args - Arguments to update one Role. + * @example + * // Update one Role + * const role = await prisma.role.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__RoleClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more Roles. + * @param {RoleDeleteManyArgs} args - Arguments to filter Roles to delete. + * @example + * // Delete a few Roles + * const { count } = await prisma.role.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Roles. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {RoleUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Roles + * const role = await prisma.role.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Roles and returns the data updated in the database. + * @param {RoleUpdateManyAndReturnArgs} args - Arguments to update many Roles. + * @example + * // Update many Roles + * const role = await prisma.role.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more Roles and only return the `id` + * const roleWithIdOnly = await prisma.role.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one Role. + * @param {RoleUpsertArgs} args - Arguments to update or create a Role. + * @example + * // Update or create a Role + * const role = await prisma.role.upsert({ + * create: { + * // ... data to create a Role + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the Role we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__RoleClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of Roles. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {RoleCountArgs} args - Arguments to filter Roles to count. + * @example + * // Count the number of Roles + * const count = await prisma.role.count({ + * where: { + * // ... the filter for the Roles we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a Role. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {RoleAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by Role. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {RoleGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends RoleGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: RoleGroupByArgs['orderBy'] } + : { orderBy?: RoleGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetRoleGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the Role model + */ +readonly fields: RoleFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for Role. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__RoleClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + users = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the Role model + */ +export interface RoleFieldRefs { + readonly id: Prisma.FieldRef<"Role", 'String'> + readonly title: Prisma.FieldRef<"Role", 'String'> + readonly moniker: Prisma.FieldRef<"Role", 'String'> + readonly permissions: Prisma.FieldRef<"Role", 'String'> + readonly createdAt: Prisma.FieldRef<"Role", 'DateTime'> + readonly updatedAt: Prisma.FieldRef<"Role", 'DateTime'> +} + + +// Custom InputTypes +/** + * Role findUnique + */ +export type RoleFindUniqueArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelect | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.RoleInclude | null + /** + * Filter, which Role to fetch. + */ + where: Prisma.RoleWhereUniqueInput +} + +/** + * Role findUniqueOrThrow + */ +export type RoleFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelect | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.RoleInclude | null + /** + * Filter, which Role to fetch. + */ + where: Prisma.RoleWhereUniqueInput +} + +/** + * Role findFirst + */ +export type RoleFindFirstArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelect | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.RoleInclude | null + /** + * Filter, which Role to fetch. + */ + where?: Prisma.RoleWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Roles to fetch. + */ + orderBy?: Prisma.RoleOrderByWithRelationInput | Prisma.RoleOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Roles. + */ + cursor?: Prisma.RoleWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Roles from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Roles. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Roles. + */ + distinct?: Prisma.RoleScalarFieldEnum | Prisma.RoleScalarFieldEnum[] +} + +/** + * Role findFirstOrThrow + */ +export type RoleFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelect | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.RoleInclude | null + /** + * Filter, which Role to fetch. + */ + where?: Prisma.RoleWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Roles to fetch. + */ + orderBy?: Prisma.RoleOrderByWithRelationInput | Prisma.RoleOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Roles. + */ + cursor?: Prisma.RoleWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Roles from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Roles. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Roles. + */ + distinct?: Prisma.RoleScalarFieldEnum | Prisma.RoleScalarFieldEnum[] +} + +/** + * Role findMany + */ +export type RoleFindManyArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelect | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.RoleInclude | null + /** + * Filter, which Roles to fetch. + */ + where?: Prisma.RoleWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Roles to fetch. + */ + orderBy?: Prisma.RoleOrderByWithRelationInput | Prisma.RoleOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Roles. + */ + cursor?: Prisma.RoleWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Roles from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Roles. + */ + skip?: number + distinct?: Prisma.RoleScalarFieldEnum | Prisma.RoleScalarFieldEnum[] +} + +/** + * Role create + */ +export type RoleCreateArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelect | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.RoleInclude | null + /** + * The data needed to create a Role. + */ + data: Prisma.XOR +} + +/** + * Role createMany + */ +export type RoleCreateManyArgs = { + /** + * The data used to create many Roles. + */ + data: Prisma.RoleCreateManyInput | Prisma.RoleCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * Role createManyAndReturn + */ +export type RoleCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelectCreateManyAndReturn | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * The data used to create many Roles. + */ + data: Prisma.RoleCreateManyInput | Prisma.RoleCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * Role update + */ +export type RoleUpdateArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelect | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.RoleInclude | null + /** + * The data needed to update a Role. + */ + data: Prisma.XOR + /** + * Choose, which Role to update. + */ + where: Prisma.RoleWhereUniqueInput +} + +/** + * Role updateMany + */ +export type RoleUpdateManyArgs = { + /** + * The data used to update Roles. + */ + data: Prisma.XOR + /** + * Filter which Roles to update + */ + where?: Prisma.RoleWhereInput + /** + * Limit how many Roles to update. + */ + limit?: number +} + +/** + * Role updateManyAndReturn + */ +export type RoleUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * The data used to update Roles. + */ + data: Prisma.XOR + /** + * Filter which Roles to update + */ + where?: Prisma.RoleWhereInput + /** + * Limit how many Roles to update. + */ + limit?: number +} + +/** + * Role upsert + */ +export type RoleUpsertArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelect | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.RoleInclude | null + /** + * The filter to search for the Role to update in case it exists. + */ + where: Prisma.RoleWhereUniqueInput + /** + * In case the Role found by the `where` argument doesn't exist, create a new Role with this data. + */ + create: Prisma.XOR + /** + * In case the Role was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * Role delete + */ +export type RoleDeleteArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelect | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.RoleInclude | null + /** + * Filter which Role to delete. + */ + where: Prisma.RoleWhereUniqueInput +} + +/** + * Role deleteMany + */ +export type RoleDeleteManyArgs = { + /** + * Filter which Roles to delete + */ + where?: Prisma.RoleWhereInput + /** + * Limit how many Roles to delete. + */ + limit?: number +} + +/** + * Role.users + */ +export type Role$usersArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + where?: Prisma.UserWhereInput + orderBy?: Prisma.UserOrderByWithRelationInput | Prisma.UserOrderByWithRelationInput[] + cursor?: Prisma.UserWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.UserScalarFieldEnum | Prisma.UserScalarFieldEnum[] +} + +/** + * Role without action + */ +export type RoleDefaultArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelect | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.RoleInclude | null +} diff --git a/generated/prisma/models/Session.ts b/generated/prisma/models/Session.ts new file mode 100644 index 0000000..3fc12fa --- /dev/null +++ b/generated/prisma/models/Session.ts @@ -0,0 +1,1426 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `Session` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.ts" +import type * as Prisma from "../internal/prismaNamespace.ts" + +/** + * Model Session + * + */ +export type SessionModel = runtime.Types.Result.DefaultSelection + +export type AggregateSession = { + _count: SessionCountAggregateOutputType | null + _min: SessionMinAggregateOutputType | null + _max: SessionMaxAggregateOutputType | null +} + +export type SessionMinAggregateOutputType = { + id: string | null + sessionKey: string | null + userId: string | null + expires: Date | null + refreshTokenGenerated: boolean | null + refreshedAt: Date | null + invalidatedAt: Date | null +} + +export type SessionMaxAggregateOutputType = { + id: string | null + sessionKey: string | null + userId: string | null + expires: Date | null + refreshTokenGenerated: boolean | null + refreshedAt: Date | null + invalidatedAt: Date | null +} + +export type SessionCountAggregateOutputType = { + id: number + sessionKey: number + userId: number + expires: number + refreshTokenGenerated: number + refreshedAt: number + invalidatedAt: number + _all: number +} + + +export type SessionMinAggregateInputType = { + id?: true + sessionKey?: true + userId?: true + expires?: true + refreshTokenGenerated?: true + refreshedAt?: true + invalidatedAt?: true +} + +export type SessionMaxAggregateInputType = { + id?: true + sessionKey?: true + userId?: true + expires?: true + refreshTokenGenerated?: true + refreshedAt?: true + invalidatedAt?: true +} + +export type SessionCountAggregateInputType = { + id?: true + sessionKey?: true + userId?: true + expires?: true + refreshTokenGenerated?: true + refreshedAt?: true + invalidatedAt?: true + _all?: true +} + +export type SessionAggregateArgs = { + /** + * Filter which Session to aggregate. + */ + where?: Prisma.SessionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Sessions to fetch. + */ + orderBy?: Prisma.SessionOrderByWithRelationInput | Prisma.SessionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.SessionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Sessions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Sessions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Sessions + **/ + _count?: true | SessionCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: SessionMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: SessionMaxAggregateInputType +} + +export type GetSessionAggregateType = { + [P in keyof T & keyof AggregateSession]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type SessionGroupByArgs = { + where?: Prisma.SessionWhereInput + orderBy?: Prisma.SessionOrderByWithAggregationInput | Prisma.SessionOrderByWithAggregationInput[] + by: Prisma.SessionScalarFieldEnum[] | Prisma.SessionScalarFieldEnum + having?: Prisma.SessionScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: SessionCountAggregateInputType | true + _min?: SessionMinAggregateInputType + _max?: SessionMaxAggregateInputType +} + +export type SessionGroupByOutputType = { + id: string + sessionKey: string + userId: string + expires: Date + refreshTokenGenerated: boolean + refreshedAt: Date | null + invalidatedAt: Date | null + _count: SessionCountAggregateOutputType | null + _min: SessionMinAggregateOutputType | null + _max: SessionMaxAggregateOutputType | null +} + +type GetSessionGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof SessionGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type SessionWhereInput = { + AND?: Prisma.SessionWhereInput | Prisma.SessionWhereInput[] + OR?: Prisma.SessionWhereInput[] + NOT?: Prisma.SessionWhereInput | Prisma.SessionWhereInput[] + id?: Prisma.StringFilter<"Session"> | string + sessionKey?: Prisma.StringFilter<"Session"> | string + userId?: Prisma.StringFilter<"Session"> | string + expires?: Prisma.DateTimeFilter<"Session"> | Date | string + refreshTokenGenerated?: Prisma.BoolFilter<"Session"> | boolean + refreshedAt?: Prisma.DateTimeNullableFilter<"Session"> | Date | string | null + invalidatedAt?: Prisma.DateTimeNullableFilter<"Session"> | Date | string | null + user?: Prisma.XOR +} + +export type SessionOrderByWithRelationInput = { + id?: Prisma.SortOrder + sessionKey?: Prisma.SortOrder + userId?: Prisma.SortOrder + expires?: Prisma.SortOrder + refreshTokenGenerated?: Prisma.SortOrder + refreshedAt?: Prisma.SortOrderInput | Prisma.SortOrder + invalidatedAt?: Prisma.SortOrderInput | Prisma.SortOrder + user?: Prisma.UserOrderByWithRelationInput +} + +export type SessionWhereUniqueInput = Prisma.AtLeast<{ + id?: string + sessionKey?: string + AND?: Prisma.SessionWhereInput | Prisma.SessionWhereInput[] + OR?: Prisma.SessionWhereInput[] + NOT?: Prisma.SessionWhereInput | Prisma.SessionWhereInput[] + userId?: Prisma.StringFilter<"Session"> | string + expires?: Prisma.DateTimeFilter<"Session"> | Date | string + refreshTokenGenerated?: Prisma.BoolFilter<"Session"> | boolean + refreshedAt?: Prisma.DateTimeNullableFilter<"Session"> | Date | string | null + invalidatedAt?: Prisma.DateTimeNullableFilter<"Session"> | Date | string | null + user?: Prisma.XOR +}, "id" | "sessionKey"> + +export type SessionOrderByWithAggregationInput = { + id?: Prisma.SortOrder + sessionKey?: Prisma.SortOrder + userId?: Prisma.SortOrder + expires?: Prisma.SortOrder + refreshTokenGenerated?: Prisma.SortOrder + refreshedAt?: Prisma.SortOrderInput | Prisma.SortOrder + invalidatedAt?: Prisma.SortOrderInput | Prisma.SortOrder + _count?: Prisma.SessionCountOrderByAggregateInput + _max?: Prisma.SessionMaxOrderByAggregateInput + _min?: Prisma.SessionMinOrderByAggregateInput +} + +export type SessionScalarWhereWithAggregatesInput = { + AND?: Prisma.SessionScalarWhereWithAggregatesInput | Prisma.SessionScalarWhereWithAggregatesInput[] + OR?: Prisma.SessionScalarWhereWithAggregatesInput[] + NOT?: Prisma.SessionScalarWhereWithAggregatesInput | Prisma.SessionScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"Session"> | string + sessionKey?: Prisma.StringWithAggregatesFilter<"Session"> | string + userId?: Prisma.StringWithAggregatesFilter<"Session"> | string + expires?: Prisma.DateTimeWithAggregatesFilter<"Session"> | Date | string + refreshTokenGenerated?: Prisma.BoolWithAggregatesFilter<"Session"> | boolean + refreshedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"Session"> | Date | string | null + invalidatedAt?: Prisma.DateTimeNullableWithAggregatesFilter<"Session"> | Date | string | null +} + +export type SessionCreateInput = { + id?: string + sessionKey?: string + expires: Date | string + refreshTokenGenerated?: boolean + refreshedAt?: Date | string | null + invalidatedAt?: Date | string | null + user: Prisma.UserCreateNestedOneWithoutSessionsInput +} + +export type SessionUncheckedCreateInput = { + id?: string + sessionKey?: string + userId: string + expires: Date | string + refreshTokenGenerated?: boolean + refreshedAt?: Date | string | null + invalidatedAt?: Date | string | null +} + +export type SessionUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + sessionKey?: Prisma.StringFieldUpdateOperationsInput | string + expires?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + refreshTokenGenerated?: Prisma.BoolFieldUpdateOperationsInput | boolean + refreshedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + invalidatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + user?: Prisma.UserUpdateOneRequiredWithoutSessionsNestedInput +} + +export type SessionUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + sessionKey?: Prisma.StringFieldUpdateOperationsInput | string + userId?: Prisma.StringFieldUpdateOperationsInput | string + expires?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + refreshTokenGenerated?: Prisma.BoolFieldUpdateOperationsInput | boolean + refreshedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + invalidatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null +} + +export type SessionCreateManyInput = { + id?: string + sessionKey?: string + userId: string + expires: Date | string + refreshTokenGenerated?: boolean + refreshedAt?: Date | string | null + invalidatedAt?: Date | string | null +} + +export type SessionUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + sessionKey?: Prisma.StringFieldUpdateOperationsInput | string + expires?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + refreshTokenGenerated?: Prisma.BoolFieldUpdateOperationsInput | boolean + refreshedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + invalidatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null +} + +export type SessionUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + sessionKey?: Prisma.StringFieldUpdateOperationsInput | string + userId?: Prisma.StringFieldUpdateOperationsInput | string + expires?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + refreshTokenGenerated?: Prisma.BoolFieldUpdateOperationsInput | boolean + refreshedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + invalidatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null +} + +export type SessionCountOrderByAggregateInput = { + id?: Prisma.SortOrder + sessionKey?: Prisma.SortOrder + userId?: Prisma.SortOrder + expires?: Prisma.SortOrder + refreshTokenGenerated?: Prisma.SortOrder + refreshedAt?: Prisma.SortOrder + invalidatedAt?: Prisma.SortOrder +} + +export type SessionMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + sessionKey?: Prisma.SortOrder + userId?: Prisma.SortOrder + expires?: Prisma.SortOrder + refreshTokenGenerated?: Prisma.SortOrder + refreshedAt?: Prisma.SortOrder + invalidatedAt?: Prisma.SortOrder +} + +export type SessionMinOrderByAggregateInput = { + id?: Prisma.SortOrder + sessionKey?: Prisma.SortOrder + userId?: Prisma.SortOrder + expires?: Prisma.SortOrder + refreshTokenGenerated?: Prisma.SortOrder + refreshedAt?: Prisma.SortOrder + invalidatedAt?: Prisma.SortOrder +} + +export type SessionListRelationFilter = { + every?: Prisma.SessionWhereInput + some?: Prisma.SessionWhereInput + none?: Prisma.SessionWhereInput +} + +export type SessionOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type StringFieldUpdateOperationsInput = { + set?: string +} + +export type DateTimeFieldUpdateOperationsInput = { + set?: Date | string +} + +export type BoolFieldUpdateOperationsInput = { + set?: boolean +} + +export type NullableDateTimeFieldUpdateOperationsInput = { + set?: Date | string | null +} + +export type SessionCreateNestedManyWithoutUserInput = { + create?: Prisma.XOR | Prisma.SessionCreateWithoutUserInput[] | Prisma.SessionUncheckedCreateWithoutUserInput[] + connectOrCreate?: Prisma.SessionCreateOrConnectWithoutUserInput | Prisma.SessionCreateOrConnectWithoutUserInput[] + createMany?: Prisma.SessionCreateManyUserInputEnvelope + connect?: Prisma.SessionWhereUniqueInput | Prisma.SessionWhereUniqueInput[] +} + +export type SessionUncheckedCreateNestedManyWithoutUserInput = { + create?: Prisma.XOR | Prisma.SessionCreateWithoutUserInput[] | Prisma.SessionUncheckedCreateWithoutUserInput[] + connectOrCreate?: Prisma.SessionCreateOrConnectWithoutUserInput | Prisma.SessionCreateOrConnectWithoutUserInput[] + createMany?: Prisma.SessionCreateManyUserInputEnvelope + connect?: Prisma.SessionWhereUniqueInput | Prisma.SessionWhereUniqueInput[] +} + +export type SessionUpdateManyWithoutUserNestedInput = { + create?: Prisma.XOR | Prisma.SessionCreateWithoutUserInput[] | Prisma.SessionUncheckedCreateWithoutUserInput[] + connectOrCreate?: Prisma.SessionCreateOrConnectWithoutUserInput | Prisma.SessionCreateOrConnectWithoutUserInput[] + upsert?: Prisma.SessionUpsertWithWhereUniqueWithoutUserInput | Prisma.SessionUpsertWithWhereUniqueWithoutUserInput[] + createMany?: Prisma.SessionCreateManyUserInputEnvelope + set?: Prisma.SessionWhereUniqueInput | Prisma.SessionWhereUniqueInput[] + disconnect?: Prisma.SessionWhereUniqueInput | Prisma.SessionWhereUniqueInput[] + delete?: Prisma.SessionWhereUniqueInput | Prisma.SessionWhereUniqueInput[] + connect?: Prisma.SessionWhereUniqueInput | Prisma.SessionWhereUniqueInput[] + update?: Prisma.SessionUpdateWithWhereUniqueWithoutUserInput | Prisma.SessionUpdateWithWhereUniqueWithoutUserInput[] + updateMany?: Prisma.SessionUpdateManyWithWhereWithoutUserInput | Prisma.SessionUpdateManyWithWhereWithoutUserInput[] + deleteMany?: Prisma.SessionScalarWhereInput | Prisma.SessionScalarWhereInput[] +} + +export type SessionUncheckedUpdateManyWithoutUserNestedInput = { + create?: Prisma.XOR | Prisma.SessionCreateWithoutUserInput[] | Prisma.SessionUncheckedCreateWithoutUserInput[] + connectOrCreate?: Prisma.SessionCreateOrConnectWithoutUserInput | Prisma.SessionCreateOrConnectWithoutUserInput[] + upsert?: Prisma.SessionUpsertWithWhereUniqueWithoutUserInput | Prisma.SessionUpsertWithWhereUniqueWithoutUserInput[] + createMany?: Prisma.SessionCreateManyUserInputEnvelope + set?: Prisma.SessionWhereUniqueInput | Prisma.SessionWhereUniqueInput[] + disconnect?: Prisma.SessionWhereUniqueInput | Prisma.SessionWhereUniqueInput[] + delete?: Prisma.SessionWhereUniqueInput | Prisma.SessionWhereUniqueInput[] + connect?: Prisma.SessionWhereUniqueInput | Prisma.SessionWhereUniqueInput[] + update?: Prisma.SessionUpdateWithWhereUniqueWithoutUserInput | Prisma.SessionUpdateWithWhereUniqueWithoutUserInput[] + updateMany?: Prisma.SessionUpdateManyWithWhereWithoutUserInput | Prisma.SessionUpdateManyWithWhereWithoutUserInput[] + deleteMany?: Prisma.SessionScalarWhereInput | Prisma.SessionScalarWhereInput[] +} + +export type SessionCreateWithoutUserInput = { + id?: string + sessionKey?: string + expires: Date | string + refreshTokenGenerated?: boolean + refreshedAt?: Date | string | null + invalidatedAt?: Date | string | null +} + +export type SessionUncheckedCreateWithoutUserInput = { + id?: string + sessionKey?: string + expires: Date | string + refreshTokenGenerated?: boolean + refreshedAt?: Date | string | null + invalidatedAt?: Date | string | null +} + +export type SessionCreateOrConnectWithoutUserInput = { + where: Prisma.SessionWhereUniqueInput + create: Prisma.XOR +} + +export type SessionCreateManyUserInputEnvelope = { + data: Prisma.SessionCreateManyUserInput | Prisma.SessionCreateManyUserInput[] + skipDuplicates?: boolean +} + +export type SessionUpsertWithWhereUniqueWithoutUserInput = { + where: Prisma.SessionWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type SessionUpdateWithWhereUniqueWithoutUserInput = { + where: Prisma.SessionWhereUniqueInput + data: Prisma.XOR +} + +export type SessionUpdateManyWithWhereWithoutUserInput = { + where: Prisma.SessionScalarWhereInput + data: Prisma.XOR +} + +export type SessionScalarWhereInput = { + AND?: Prisma.SessionScalarWhereInput | Prisma.SessionScalarWhereInput[] + OR?: Prisma.SessionScalarWhereInput[] + NOT?: Prisma.SessionScalarWhereInput | Prisma.SessionScalarWhereInput[] + id?: Prisma.StringFilter<"Session"> | string + sessionKey?: Prisma.StringFilter<"Session"> | string + userId?: Prisma.StringFilter<"Session"> | string + expires?: Prisma.DateTimeFilter<"Session"> | Date | string + refreshTokenGenerated?: Prisma.BoolFilter<"Session"> | boolean + refreshedAt?: Prisma.DateTimeNullableFilter<"Session"> | Date | string | null + invalidatedAt?: Prisma.DateTimeNullableFilter<"Session"> | Date | string | null +} + +export type SessionCreateManyUserInput = { + id?: string + sessionKey?: string + expires: Date | string + refreshTokenGenerated?: boolean + refreshedAt?: Date | string | null + invalidatedAt?: Date | string | null +} + +export type SessionUpdateWithoutUserInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + sessionKey?: Prisma.StringFieldUpdateOperationsInput | string + expires?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + refreshTokenGenerated?: Prisma.BoolFieldUpdateOperationsInput | boolean + refreshedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + invalidatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null +} + +export type SessionUncheckedUpdateWithoutUserInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + sessionKey?: Prisma.StringFieldUpdateOperationsInput | string + expires?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + refreshTokenGenerated?: Prisma.BoolFieldUpdateOperationsInput | boolean + refreshedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + invalidatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null +} + +export type SessionUncheckedUpdateManyWithoutUserInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + sessionKey?: Prisma.StringFieldUpdateOperationsInput | string + expires?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + refreshTokenGenerated?: Prisma.BoolFieldUpdateOperationsInput | boolean + refreshedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + invalidatedAt?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null +} + + + +export type SessionSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + sessionKey?: boolean + userId?: boolean + expires?: boolean + refreshTokenGenerated?: boolean + refreshedAt?: boolean + invalidatedAt?: boolean + user?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["session"]> + +export type SessionSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + sessionKey?: boolean + userId?: boolean + expires?: boolean + refreshTokenGenerated?: boolean + refreshedAt?: boolean + invalidatedAt?: boolean + user?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["session"]> + +export type SessionSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + sessionKey?: boolean + userId?: boolean + expires?: boolean + refreshTokenGenerated?: boolean + refreshedAt?: boolean + invalidatedAt?: boolean + user?: boolean | Prisma.UserDefaultArgs +}, ExtArgs["result"]["session"]> + +export type SessionSelectScalar = { + id?: boolean + sessionKey?: boolean + userId?: boolean + expires?: boolean + refreshTokenGenerated?: boolean + refreshedAt?: boolean + invalidatedAt?: boolean +} + +export type SessionOmit = runtime.Types.Extensions.GetOmit<"id" | "sessionKey" | "userId" | "expires" | "refreshTokenGenerated" | "refreshedAt" | "invalidatedAt", ExtArgs["result"]["session"]> +export type SessionInclude = { + user?: boolean | Prisma.UserDefaultArgs +} +export type SessionIncludeCreateManyAndReturn = { + user?: boolean | Prisma.UserDefaultArgs +} +export type SessionIncludeUpdateManyAndReturn = { + user?: boolean | Prisma.UserDefaultArgs +} + +export type $SessionPayload = { + name: "Session" + objects: { + user: Prisma.$UserPayload + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + sessionKey: string + userId: string + expires: Date + refreshTokenGenerated: boolean + refreshedAt: Date | null + invalidatedAt: Date | null + }, ExtArgs["result"]["session"]> + composites: {} +} + +export type SessionGetPayload = runtime.Types.Result.GetResult + +export type SessionCountArgs = + Omit & { + select?: SessionCountAggregateInputType | true + } + +export interface SessionDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['Session'], meta: { name: 'Session' } } + /** + * Find zero or one Session that matches the filter. + * @param {SessionFindUniqueArgs} args - Arguments to find a Session + * @example + * // Get one Session + * const session = await prisma.session.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__SessionClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one Session that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {SessionFindUniqueOrThrowArgs} args - Arguments to find a Session + * @example + * // Get one Session + * const session = await prisma.session.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__SessionClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Session that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {SessionFindFirstArgs} args - Arguments to find a Session + * @example + * // Get one Session + * const session = await prisma.session.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__SessionClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Session that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {SessionFindFirstOrThrowArgs} args - Arguments to find a Session + * @example + * // Get one Session + * const session = await prisma.session.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__SessionClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more Sessions that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {SessionFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all Sessions + * const sessions = await prisma.session.findMany() + * + * // Get first 10 Sessions + * const sessions = await prisma.session.findMany({ take: 10 }) + * + * // Only select the `id` + * const sessionWithIdOnly = await prisma.session.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a Session. + * @param {SessionCreateArgs} args - Arguments to create a Session. + * @example + * // Create one Session + * const Session = await prisma.session.create({ + * data: { + * // ... data to create a Session + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__SessionClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many Sessions. + * @param {SessionCreateManyArgs} args - Arguments to create many Sessions. + * @example + * // Create many Sessions + * const session = await prisma.session.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many Sessions and returns the data saved in the database. + * @param {SessionCreateManyAndReturnArgs} args - Arguments to create many Sessions. + * @example + * // Create many Sessions + * const session = await prisma.session.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many Sessions and only return the `id` + * const sessionWithIdOnly = await prisma.session.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a Session. + * @param {SessionDeleteArgs} args - Arguments to delete one Session. + * @example + * // Delete one Session + * const Session = await prisma.session.delete({ + * where: { + * // ... filter to delete one Session + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__SessionClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one Session. + * @param {SessionUpdateArgs} args - Arguments to update one Session. + * @example + * // Update one Session + * const session = await prisma.session.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__SessionClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more Sessions. + * @param {SessionDeleteManyArgs} args - Arguments to filter Sessions to delete. + * @example + * // Delete a few Sessions + * const { count } = await prisma.session.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Sessions. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {SessionUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Sessions + * const session = await prisma.session.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Sessions and returns the data updated in the database. + * @param {SessionUpdateManyAndReturnArgs} args - Arguments to update many Sessions. + * @example + * // Update many Sessions + * const session = await prisma.session.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more Sessions and only return the `id` + * const sessionWithIdOnly = await prisma.session.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one Session. + * @param {SessionUpsertArgs} args - Arguments to update or create a Session. + * @example + * // Update or create a Session + * const session = await prisma.session.upsert({ + * create: { + * // ... data to create a Session + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the Session we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__SessionClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of Sessions. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {SessionCountArgs} args - Arguments to filter Sessions to count. + * @example + * // Count the number of Sessions + * const count = await prisma.session.count({ + * where: { + * // ... the filter for the Sessions we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a Session. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {SessionAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by Session. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {SessionGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends SessionGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: SessionGroupByArgs['orderBy'] } + : { orderBy?: SessionGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetSessionGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the Session model + */ +readonly fields: SessionFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for Session. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__SessionClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + user = {}>(args?: Prisma.Subset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions> | Null, Null, ExtArgs, GlobalOmitOptions> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the Session model + */ +export interface SessionFieldRefs { + readonly id: Prisma.FieldRef<"Session", 'String'> + readonly sessionKey: Prisma.FieldRef<"Session", 'String'> + readonly userId: Prisma.FieldRef<"Session", 'String'> + readonly expires: Prisma.FieldRef<"Session", 'DateTime'> + readonly refreshTokenGenerated: Prisma.FieldRef<"Session", 'Boolean'> + readonly refreshedAt: Prisma.FieldRef<"Session", 'DateTime'> + readonly invalidatedAt: Prisma.FieldRef<"Session", 'DateTime'> +} + + +// Custom InputTypes +/** + * Session findUnique + */ +export type SessionFindUniqueArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelect | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionInclude | null + /** + * Filter, which Session to fetch. + */ + where: Prisma.SessionWhereUniqueInput +} + +/** + * Session findUniqueOrThrow + */ +export type SessionFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelect | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionInclude | null + /** + * Filter, which Session to fetch. + */ + where: Prisma.SessionWhereUniqueInput +} + +/** + * Session findFirst + */ +export type SessionFindFirstArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelect | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionInclude | null + /** + * Filter, which Session to fetch. + */ + where?: Prisma.SessionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Sessions to fetch. + */ + orderBy?: Prisma.SessionOrderByWithRelationInput | Prisma.SessionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Sessions. + */ + cursor?: Prisma.SessionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Sessions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Sessions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Sessions. + */ + distinct?: Prisma.SessionScalarFieldEnum | Prisma.SessionScalarFieldEnum[] +} + +/** + * Session findFirstOrThrow + */ +export type SessionFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelect | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionInclude | null + /** + * Filter, which Session to fetch. + */ + where?: Prisma.SessionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Sessions to fetch. + */ + orderBy?: Prisma.SessionOrderByWithRelationInput | Prisma.SessionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Sessions. + */ + cursor?: Prisma.SessionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Sessions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Sessions. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Sessions. + */ + distinct?: Prisma.SessionScalarFieldEnum | Prisma.SessionScalarFieldEnum[] +} + +/** + * Session findMany + */ +export type SessionFindManyArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelect | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionInclude | null + /** + * Filter, which Sessions to fetch. + */ + where?: Prisma.SessionWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Sessions to fetch. + */ + orderBy?: Prisma.SessionOrderByWithRelationInput | Prisma.SessionOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Sessions. + */ + cursor?: Prisma.SessionWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Sessions from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Sessions. + */ + skip?: number + distinct?: Prisma.SessionScalarFieldEnum | Prisma.SessionScalarFieldEnum[] +} + +/** + * Session create + */ +export type SessionCreateArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelect | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionInclude | null + /** + * The data needed to create a Session. + */ + data: Prisma.XOR +} + +/** + * Session createMany + */ +export type SessionCreateManyArgs = { + /** + * The data used to create many Sessions. + */ + data: Prisma.SessionCreateManyInput | Prisma.SessionCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * Session createManyAndReturn + */ +export type SessionCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelectCreateManyAndReturn | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * The data used to create many Sessions. + */ + data: Prisma.SessionCreateManyInput | Prisma.SessionCreateManyInput[] + skipDuplicates?: boolean + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionIncludeCreateManyAndReturn | null +} + +/** + * Session update + */ +export type SessionUpdateArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelect | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionInclude | null + /** + * The data needed to update a Session. + */ + data: Prisma.XOR + /** + * Choose, which Session to update. + */ + where: Prisma.SessionWhereUniqueInput +} + +/** + * Session updateMany + */ +export type SessionUpdateManyArgs = { + /** + * The data used to update Sessions. + */ + data: Prisma.XOR + /** + * Filter which Sessions to update + */ + where?: Prisma.SessionWhereInput + /** + * Limit how many Sessions to update. + */ + limit?: number +} + +/** + * Session updateManyAndReturn + */ +export type SessionUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * The data used to update Sessions. + */ + data: Prisma.XOR + /** + * Filter which Sessions to update + */ + where?: Prisma.SessionWhereInput + /** + * Limit how many Sessions to update. + */ + limit?: number + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionIncludeUpdateManyAndReturn | null +} + +/** + * Session upsert + */ +export type SessionUpsertArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelect | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionInclude | null + /** + * The filter to search for the Session to update in case it exists. + */ + where: Prisma.SessionWhereUniqueInput + /** + * In case the Session found by the `where` argument doesn't exist, create a new Session with this data. + */ + create: Prisma.XOR + /** + * In case the Session was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * Session delete + */ +export type SessionDeleteArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelect | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionInclude | null + /** + * Filter which Session to delete. + */ + where: Prisma.SessionWhereUniqueInput +} + +/** + * Session deleteMany + */ +export type SessionDeleteManyArgs = { + /** + * Filter which Sessions to delete + */ + where?: Prisma.SessionWhereInput + /** + * Limit how many Sessions to delete. + */ + limit?: number +} + +/** + * Session without action + */ +export type SessionDefaultArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelect | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionInclude | null +} diff --git a/generated/prisma/models/User.ts b/generated/prisma/models/User.ts new file mode 100644 index 0000000..e3a66e2 --- /dev/null +++ b/generated/prisma/models/User.ts @@ -0,0 +1,1778 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `User` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.ts" +import type * as Prisma from "../internal/prismaNamespace.ts" + +/** + * Model User + * + */ +export type UserModel = runtime.Types.Result.DefaultSelection + +export type AggregateUser = { + _count: UserCountAggregateOutputType | null + _avg: UserAvgAggregateOutputType | null + _sum: UserSumAggregateOutputType | null + _min: UserMinAggregateOutputType | null + _max: UserMaxAggregateOutputType | null +} + +export type UserAvgAggregateOutputType = { + userId: number | null +} + +export type UserSumAggregateOutputType = { + userId: number | null +} + +export type UserMinAggregateOutputType = { + id: string | null + permissions: string | null + login: string | null + name: string | null + email: string | null + emailVerified: Date | null + image: string | null + userId: number | null + token: string | null + createdAt: Date | null + updatedAt: Date | null +} + +export type UserMaxAggregateOutputType = { + id: string | null + permissions: string | null + login: string | null + name: string | null + email: string | null + emailVerified: Date | null + image: string | null + userId: number | null + token: string | null + createdAt: Date | null + updatedAt: Date | null +} + +export type UserCountAggregateOutputType = { + id: number + permissions: number + login: number + name: number + email: number + emailVerified: number + image: number + userId: number + token: number + createdAt: number + updatedAt: number + _all: number +} + + +export type UserAvgAggregateInputType = { + userId?: true +} + +export type UserSumAggregateInputType = { + userId?: true +} + +export type UserMinAggregateInputType = { + id?: true + permissions?: true + login?: true + name?: true + email?: true + emailVerified?: true + image?: true + userId?: true + token?: true + createdAt?: true + updatedAt?: true +} + +export type UserMaxAggregateInputType = { + id?: true + permissions?: true + login?: true + name?: true + email?: true + emailVerified?: true + image?: true + userId?: true + token?: true + createdAt?: true + updatedAt?: true +} + +export type UserCountAggregateInputType = { + id?: true + permissions?: true + login?: true + name?: true + email?: true + emailVerified?: true + image?: true + userId?: true + token?: true + createdAt?: true + updatedAt?: true + _all?: true +} + +export type UserAggregateArgs = { + /** + * Filter which User to aggregate. + */ + where?: Prisma.UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + */ + orderBy?: Prisma.UserOrderByWithRelationInput | Prisma.UserOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Users from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Users. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Users + **/ + _count?: true | UserCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: UserAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: UserSumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: UserMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: UserMaxAggregateInputType +} + +export type GetUserAggregateType = { + [P in keyof T & keyof AggregateUser]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type UserGroupByArgs = { + where?: Prisma.UserWhereInput + orderBy?: Prisma.UserOrderByWithAggregationInput | Prisma.UserOrderByWithAggregationInput[] + by: Prisma.UserScalarFieldEnum[] | Prisma.UserScalarFieldEnum + having?: Prisma.UserScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: UserCountAggregateInputType | true + _avg?: UserAvgAggregateInputType + _sum?: UserSumAggregateInputType + _min?: UserMinAggregateInputType + _max?: UserMaxAggregateInputType +} + +export type UserGroupByOutputType = { + id: string + permissions: string | null + login: string + name: string | null + email: string + emailVerified: Date | null + image: string | null + userId: number + token: string | null + createdAt: Date + updatedAt: Date + _count: UserCountAggregateOutputType | null + _avg: UserAvgAggregateOutputType | null + _sum: UserSumAggregateOutputType | null + _min: UserMinAggregateOutputType | null + _max: UserMaxAggregateOutputType | null +} + +type GetUserGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof UserGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type UserWhereInput = { + AND?: Prisma.UserWhereInput | Prisma.UserWhereInput[] + OR?: Prisma.UserWhereInput[] + NOT?: Prisma.UserWhereInput | Prisma.UserWhereInput[] + id?: Prisma.StringFilter<"User"> | string + permissions?: Prisma.StringNullableFilter<"User"> | string | null + login?: Prisma.StringFilter<"User"> | string + name?: Prisma.StringNullableFilter<"User"> | string | null + email?: Prisma.StringFilter<"User"> | string + emailVerified?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null + image?: Prisma.StringNullableFilter<"User"> | string | null + userId?: Prisma.IntFilter<"User"> | number + token?: Prisma.StringNullableFilter<"User"> | string | null + createdAt?: Prisma.DateTimeFilter<"User"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string + roles?: Prisma.RoleListRelationFilter + sessions?: Prisma.SessionListRelationFilter +} + +export type UserOrderByWithRelationInput = { + id?: Prisma.SortOrder + permissions?: Prisma.SortOrderInput | Prisma.SortOrder + login?: Prisma.SortOrder + name?: Prisma.SortOrderInput | Prisma.SortOrder + email?: Prisma.SortOrder + emailVerified?: Prisma.SortOrderInput | Prisma.SortOrder + image?: Prisma.SortOrderInput | Prisma.SortOrder + userId?: Prisma.SortOrder + token?: Prisma.SortOrderInput | Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + roles?: Prisma.RoleOrderByRelationAggregateInput + sessions?: Prisma.SessionOrderByRelationAggregateInput +} + +export type UserWhereUniqueInput = Prisma.AtLeast<{ + id?: string + login?: string + email?: string + userId?: number + AND?: Prisma.UserWhereInput | Prisma.UserWhereInput[] + OR?: Prisma.UserWhereInput[] + NOT?: Prisma.UserWhereInput | Prisma.UserWhereInput[] + permissions?: Prisma.StringNullableFilter<"User"> | string | null + name?: Prisma.StringNullableFilter<"User"> | string | null + emailVerified?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null + image?: Prisma.StringNullableFilter<"User"> | string | null + token?: Prisma.StringNullableFilter<"User"> | string | null + createdAt?: Prisma.DateTimeFilter<"User"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string + roles?: Prisma.RoleListRelationFilter + sessions?: Prisma.SessionListRelationFilter +}, "id" | "login" | "email" | "userId"> + +export type UserOrderByWithAggregationInput = { + id?: Prisma.SortOrder + permissions?: Prisma.SortOrderInput | Prisma.SortOrder + login?: Prisma.SortOrder + name?: Prisma.SortOrderInput | Prisma.SortOrder + email?: Prisma.SortOrder + emailVerified?: Prisma.SortOrderInput | Prisma.SortOrder + image?: Prisma.SortOrderInput | Prisma.SortOrder + userId?: Prisma.SortOrder + token?: Prisma.SortOrderInput | Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + _count?: Prisma.UserCountOrderByAggregateInput + _avg?: Prisma.UserAvgOrderByAggregateInput + _max?: Prisma.UserMaxOrderByAggregateInput + _min?: Prisma.UserMinOrderByAggregateInput + _sum?: Prisma.UserSumOrderByAggregateInput +} + +export type UserScalarWhereWithAggregatesInput = { + AND?: Prisma.UserScalarWhereWithAggregatesInput | Prisma.UserScalarWhereWithAggregatesInput[] + OR?: Prisma.UserScalarWhereWithAggregatesInput[] + NOT?: Prisma.UserScalarWhereWithAggregatesInput | Prisma.UserScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"User"> | string + permissions?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null + login?: Prisma.StringWithAggregatesFilter<"User"> | string + name?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null + email?: Prisma.StringWithAggregatesFilter<"User"> | string + emailVerified?: Prisma.DateTimeNullableWithAggregatesFilter<"User"> | Date | string | null + image?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null + userId?: Prisma.IntWithAggregatesFilter<"User"> | number + token?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null + createdAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string + updatedAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string +} + +export type UserCreateInput = { + id?: string + permissions?: string | null + login: string + name?: string | null + email: string + emailVerified?: Date | string | null + image?: string | null + userId: number + token?: string | null + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.RoleCreateNestedManyWithoutUsersInput + sessions?: Prisma.SessionCreateNestedManyWithoutUserInput +} + +export type UserUncheckedCreateInput = { + id?: string + permissions?: string | null + login: string + name?: string | null + email: string + emailVerified?: Date | string | null + image?: string | null + userId: number + token?: string | null + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.RoleUncheckedCreateNestedManyWithoutUsersInput + sessions?: Prisma.SessionUncheckedCreateNestedManyWithoutUserInput +} + +export type UserUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + login?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + email?: Prisma.StringFieldUpdateOperationsInput | string + emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + userId?: Prisma.IntFieldUpdateOperationsInput | number + token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.RoleUpdateManyWithoutUsersNestedInput + sessions?: Prisma.SessionUpdateManyWithoutUserNestedInput +} + +export type UserUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + login?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + email?: Prisma.StringFieldUpdateOperationsInput | string + emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + userId?: Prisma.IntFieldUpdateOperationsInput | number + token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.RoleUncheckedUpdateManyWithoutUsersNestedInput + sessions?: Prisma.SessionUncheckedUpdateManyWithoutUserNestedInput +} + +export type UserCreateManyInput = { + id?: string + permissions?: string | null + login: string + name?: string | null + email: string + emailVerified?: Date | string | null + image?: string | null + userId: number + token?: string | null + createdAt?: Date | string + updatedAt?: Date | string +} + +export type UserUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + login?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + email?: Prisma.StringFieldUpdateOperationsInput | string + emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + userId?: Prisma.IntFieldUpdateOperationsInput | number + token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type UserUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + login?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + email?: Prisma.StringFieldUpdateOperationsInput | string + emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + userId?: Prisma.IntFieldUpdateOperationsInput | number + token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type UserScalarRelationFilter = { + is?: Prisma.UserWhereInput + isNot?: Prisma.UserWhereInput +} + +export type UserCountOrderByAggregateInput = { + id?: Prisma.SortOrder + permissions?: Prisma.SortOrder + login?: Prisma.SortOrder + name?: Prisma.SortOrder + email?: Prisma.SortOrder + emailVerified?: Prisma.SortOrder + image?: Prisma.SortOrder + userId?: Prisma.SortOrder + token?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type UserAvgOrderByAggregateInput = { + userId?: Prisma.SortOrder +} + +export type UserMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + permissions?: Prisma.SortOrder + login?: Prisma.SortOrder + name?: Prisma.SortOrder + email?: Prisma.SortOrder + emailVerified?: Prisma.SortOrder + image?: Prisma.SortOrder + userId?: Prisma.SortOrder + token?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type UserMinOrderByAggregateInput = { + id?: Prisma.SortOrder + permissions?: Prisma.SortOrder + login?: Prisma.SortOrder + name?: Prisma.SortOrder + email?: Prisma.SortOrder + emailVerified?: Prisma.SortOrder + image?: Prisma.SortOrder + userId?: Prisma.SortOrder + token?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type UserSumOrderByAggregateInput = { + userId?: Prisma.SortOrder +} + +export type UserListRelationFilter = { + every?: Prisma.UserWhereInput + some?: Prisma.UserWhereInput + none?: Prisma.UserWhereInput +} + +export type UserOrderByRelationAggregateInput = { + _count?: Prisma.SortOrder +} + +export type UserCreateNestedOneWithoutSessionsInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutSessionsInput + connect?: Prisma.UserWhereUniqueInput +} + +export type UserUpdateOneRequiredWithoutSessionsNestedInput = { + create?: Prisma.XOR + connectOrCreate?: Prisma.UserCreateOrConnectWithoutSessionsInput + upsert?: Prisma.UserUpsertWithoutSessionsInput + connect?: Prisma.UserWhereUniqueInput + update?: Prisma.XOR, Prisma.UserUncheckedUpdateWithoutSessionsInput> +} + +export type NullableStringFieldUpdateOperationsInput = { + set?: string | null +} + +export type IntFieldUpdateOperationsInput = { + set?: number + increment?: number + decrement?: number + multiply?: number + divide?: number +} + +export type UserCreateNestedManyWithoutRolesInput = { + create?: Prisma.XOR | Prisma.UserCreateWithoutRolesInput[] | Prisma.UserUncheckedCreateWithoutRolesInput[] + connectOrCreate?: Prisma.UserCreateOrConnectWithoutRolesInput | Prisma.UserCreateOrConnectWithoutRolesInput[] + connect?: Prisma.UserWhereUniqueInput | Prisma.UserWhereUniqueInput[] +} + +export type UserUncheckedCreateNestedManyWithoutRolesInput = { + create?: Prisma.XOR | Prisma.UserCreateWithoutRolesInput[] | Prisma.UserUncheckedCreateWithoutRolesInput[] + connectOrCreate?: Prisma.UserCreateOrConnectWithoutRolesInput | Prisma.UserCreateOrConnectWithoutRolesInput[] + connect?: Prisma.UserWhereUniqueInput | Prisma.UserWhereUniqueInput[] +} + +export type UserUpdateManyWithoutRolesNestedInput = { + create?: Prisma.XOR | Prisma.UserCreateWithoutRolesInput[] | Prisma.UserUncheckedCreateWithoutRolesInput[] + connectOrCreate?: Prisma.UserCreateOrConnectWithoutRolesInput | Prisma.UserCreateOrConnectWithoutRolesInput[] + upsert?: Prisma.UserUpsertWithWhereUniqueWithoutRolesInput | Prisma.UserUpsertWithWhereUniqueWithoutRolesInput[] + set?: Prisma.UserWhereUniqueInput | Prisma.UserWhereUniqueInput[] + disconnect?: Prisma.UserWhereUniqueInput | Prisma.UserWhereUniqueInput[] + delete?: Prisma.UserWhereUniqueInput | Prisma.UserWhereUniqueInput[] + connect?: Prisma.UserWhereUniqueInput | Prisma.UserWhereUniqueInput[] + update?: Prisma.UserUpdateWithWhereUniqueWithoutRolesInput | Prisma.UserUpdateWithWhereUniqueWithoutRolesInput[] + updateMany?: Prisma.UserUpdateManyWithWhereWithoutRolesInput | Prisma.UserUpdateManyWithWhereWithoutRolesInput[] + deleteMany?: Prisma.UserScalarWhereInput | Prisma.UserScalarWhereInput[] +} + +export type UserUncheckedUpdateManyWithoutRolesNestedInput = { + create?: Prisma.XOR | Prisma.UserCreateWithoutRolesInput[] | Prisma.UserUncheckedCreateWithoutRolesInput[] + connectOrCreate?: Prisma.UserCreateOrConnectWithoutRolesInput | Prisma.UserCreateOrConnectWithoutRolesInput[] + upsert?: Prisma.UserUpsertWithWhereUniqueWithoutRolesInput | Prisma.UserUpsertWithWhereUniqueWithoutRolesInput[] + set?: Prisma.UserWhereUniqueInput | Prisma.UserWhereUniqueInput[] + disconnect?: Prisma.UserWhereUniqueInput | Prisma.UserWhereUniqueInput[] + delete?: Prisma.UserWhereUniqueInput | Prisma.UserWhereUniqueInput[] + connect?: Prisma.UserWhereUniqueInput | Prisma.UserWhereUniqueInput[] + update?: Prisma.UserUpdateWithWhereUniqueWithoutRolesInput | Prisma.UserUpdateWithWhereUniqueWithoutRolesInput[] + updateMany?: Prisma.UserUpdateManyWithWhereWithoutRolesInput | Prisma.UserUpdateManyWithWhereWithoutRolesInput[] + deleteMany?: Prisma.UserScalarWhereInput | Prisma.UserScalarWhereInput[] +} + +export type UserCreateWithoutSessionsInput = { + id?: string + permissions?: string | null + login: string + name?: string | null + email: string + emailVerified?: Date | string | null + image?: string | null + userId: number + token?: string | null + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.RoleCreateNestedManyWithoutUsersInput +} + +export type UserUncheckedCreateWithoutSessionsInput = { + id?: string + permissions?: string | null + login: string + name?: string | null + email: string + emailVerified?: Date | string | null + image?: string | null + userId: number + token?: string | null + createdAt?: Date | string + updatedAt?: Date | string + roles?: Prisma.RoleUncheckedCreateNestedManyWithoutUsersInput +} + +export type UserCreateOrConnectWithoutSessionsInput = { + where: Prisma.UserWhereUniqueInput + create: Prisma.XOR +} + +export type UserUpsertWithoutSessionsInput = { + update: Prisma.XOR + create: Prisma.XOR + where?: Prisma.UserWhereInput +} + +export type UserUpdateToOneWithWhereWithoutSessionsInput = { + where?: Prisma.UserWhereInput + data: Prisma.XOR +} + +export type UserUpdateWithoutSessionsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + login?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + email?: Prisma.StringFieldUpdateOperationsInput | string + emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + userId?: Prisma.IntFieldUpdateOperationsInput | number + token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.RoleUpdateManyWithoutUsersNestedInput +} + +export type UserUncheckedUpdateWithoutSessionsInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + login?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + email?: Prisma.StringFieldUpdateOperationsInput | string + emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + userId?: Prisma.IntFieldUpdateOperationsInput | number + token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + roles?: Prisma.RoleUncheckedUpdateManyWithoutUsersNestedInput +} + +export type UserCreateWithoutRolesInput = { + id?: string + permissions?: string | null + login: string + name?: string | null + email: string + emailVerified?: Date | string | null + image?: string | null + userId: number + token?: string | null + createdAt?: Date | string + updatedAt?: Date | string + sessions?: Prisma.SessionCreateNestedManyWithoutUserInput +} + +export type UserUncheckedCreateWithoutRolesInput = { + id?: string + permissions?: string | null + login: string + name?: string | null + email: string + emailVerified?: Date | string | null + image?: string | null + userId: number + token?: string | null + createdAt?: Date | string + updatedAt?: Date | string + sessions?: Prisma.SessionUncheckedCreateNestedManyWithoutUserInput +} + +export type UserCreateOrConnectWithoutRolesInput = { + where: Prisma.UserWhereUniqueInput + create: Prisma.XOR +} + +export type UserUpsertWithWhereUniqueWithoutRolesInput = { + where: Prisma.UserWhereUniqueInput + update: Prisma.XOR + create: Prisma.XOR +} + +export type UserUpdateWithWhereUniqueWithoutRolesInput = { + where: Prisma.UserWhereUniqueInput + data: Prisma.XOR +} + +export type UserUpdateManyWithWhereWithoutRolesInput = { + where: Prisma.UserScalarWhereInput + data: Prisma.XOR +} + +export type UserScalarWhereInput = { + AND?: Prisma.UserScalarWhereInput | Prisma.UserScalarWhereInput[] + OR?: Prisma.UserScalarWhereInput[] + NOT?: Prisma.UserScalarWhereInput | Prisma.UserScalarWhereInput[] + id?: Prisma.StringFilter<"User"> | string + permissions?: Prisma.StringNullableFilter<"User"> | string | null + login?: Prisma.StringFilter<"User"> | string + name?: Prisma.StringNullableFilter<"User"> | string | null + email?: Prisma.StringFilter<"User"> | string + emailVerified?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null + image?: Prisma.StringNullableFilter<"User"> | string | null + userId?: Prisma.IntFilter<"User"> | number + token?: Prisma.StringNullableFilter<"User"> | string | null + createdAt?: Prisma.DateTimeFilter<"User"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string +} + +export type UserUpdateWithoutRolesInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + login?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + email?: Prisma.StringFieldUpdateOperationsInput | string + emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + userId?: Prisma.IntFieldUpdateOperationsInput | number + token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + sessions?: Prisma.SessionUpdateManyWithoutUserNestedInput +} + +export type UserUncheckedUpdateWithoutRolesInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + login?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + email?: Prisma.StringFieldUpdateOperationsInput | string + emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + userId?: Prisma.IntFieldUpdateOperationsInput | number + token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + sessions?: Prisma.SessionUncheckedUpdateManyWithoutUserNestedInput +} + +export type UserUncheckedUpdateManyWithoutRolesInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + permissions?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + login?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + email?: Prisma.StringFieldUpdateOperationsInput | string + emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null + image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + userId?: Prisma.IntFieldUpdateOperationsInput | number + token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + + +/** + * Count Type UserCountOutputType + */ + +export type UserCountOutputType = { + roles: number + sessions: number +} + +export type UserCountOutputTypeSelect = { + roles?: boolean | UserCountOutputTypeCountRolesArgs + sessions?: boolean | UserCountOutputTypeCountSessionsArgs +} + +/** + * UserCountOutputType without action + */ +export type UserCountOutputTypeDefaultArgs = { + /** + * Select specific fields to fetch from the UserCountOutputType + */ + select?: Prisma.UserCountOutputTypeSelect | null +} + +/** + * UserCountOutputType without action + */ +export type UserCountOutputTypeCountRolesArgs = { + where?: Prisma.RoleWhereInput +} + +/** + * UserCountOutputType without action + */ +export type UserCountOutputTypeCountSessionsArgs = { + where?: Prisma.SessionWhereInput +} + + +export type UserSelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + permissions?: boolean + login?: boolean + name?: boolean + email?: boolean + emailVerified?: boolean + image?: boolean + userId?: boolean + token?: boolean + createdAt?: boolean + updatedAt?: boolean + roles?: boolean | Prisma.User$rolesArgs + sessions?: boolean | Prisma.User$sessionsArgs + _count?: boolean | Prisma.UserCountOutputTypeDefaultArgs +}, ExtArgs["result"]["user"]> + +export type UserSelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + permissions?: boolean + login?: boolean + name?: boolean + email?: boolean + emailVerified?: boolean + image?: boolean + userId?: boolean + token?: boolean + createdAt?: boolean + updatedAt?: boolean +}, ExtArgs["result"]["user"]> + +export type UserSelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + permissions?: boolean + login?: boolean + name?: boolean + email?: boolean + emailVerified?: boolean + image?: boolean + userId?: boolean + token?: boolean + createdAt?: boolean + updatedAt?: boolean +}, ExtArgs["result"]["user"]> + +export type UserSelectScalar = { + id?: boolean + permissions?: boolean + login?: boolean + name?: boolean + email?: boolean + emailVerified?: boolean + image?: boolean + userId?: boolean + token?: boolean + createdAt?: boolean + updatedAt?: boolean +} + +export type UserOmit = runtime.Types.Extensions.GetOmit<"id" | "permissions" | "login" | "name" | "email" | "emailVerified" | "image" | "userId" | "token" | "createdAt" | "updatedAt", ExtArgs["result"]["user"]> +export type UserInclude = { + roles?: boolean | Prisma.User$rolesArgs + sessions?: boolean | Prisma.User$sessionsArgs + _count?: boolean | Prisma.UserCountOutputTypeDefaultArgs +} +export type UserIncludeCreateManyAndReturn = {} +export type UserIncludeUpdateManyAndReturn = {} + +export type $UserPayload = { + name: "User" + objects: { + roles: Prisma.$RolePayload[] + sessions: Prisma.$SessionPayload[] + } + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + permissions: string | null + login: string + name: string | null + email: string + emailVerified: Date | null + image: string | null + userId: number + token: string | null + createdAt: Date + updatedAt: Date + }, ExtArgs["result"]["user"]> + composites: {} +} + +export type UserGetPayload = runtime.Types.Result.GetResult + +export type UserCountArgs = + Omit & { + select?: UserCountAggregateInputType | true + } + +export interface UserDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['User'], meta: { name: 'User' } } + /** + * Find zero or one User that matches the filter. + * @param {UserFindUniqueArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one User that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {UserFindUniqueOrThrowArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first User that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserFindFirstArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first User that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserFindFirstOrThrowArgs} args - Arguments to find a User + * @example + * // Get one User + * const user = await prisma.user.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more Users that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all Users + * const users = await prisma.user.findMany() + * + * // Get first 10 Users + * const users = await prisma.user.findMany({ take: 10 }) + * + * // Only select the `id` + * const userWithIdOnly = await prisma.user.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a User. + * @param {UserCreateArgs} args - Arguments to create a User. + * @example + * // Create one User + * const User = await prisma.user.create({ + * data: { + * // ... data to create a User + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many Users. + * @param {UserCreateManyArgs} args - Arguments to create many Users. + * @example + * // Create many Users + * const user = await prisma.user.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many Users and returns the data saved in the database. + * @param {UserCreateManyAndReturnArgs} args - Arguments to create many Users. + * @example + * // Create many Users + * const user = await prisma.user.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many Users and only return the `id` + * const userWithIdOnly = await prisma.user.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a User. + * @param {UserDeleteArgs} args - Arguments to delete one User. + * @example + * // Delete one User + * const User = await prisma.user.delete({ + * where: { + * // ... filter to delete one User + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one User. + * @param {UserUpdateArgs} args - Arguments to update one User. + * @example + * // Update one User + * const user = await prisma.user.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more Users. + * @param {UserDeleteManyArgs} args - Arguments to filter Users to delete. + * @example + * // Delete a few Users + * const { count } = await prisma.user.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Users. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Users + * const user = await prisma.user.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Users and returns the data updated in the database. + * @param {UserUpdateManyAndReturnArgs} args - Arguments to update many Users. + * @example + * // Update many Users + * const user = await prisma.user.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more Users and only return the `id` + * const userWithIdOnly = await prisma.user.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one User. + * @param {UserUpsertArgs} args - Arguments to update or create a User. + * @example + * // Update or create a User + * const user = await prisma.user.upsert({ + * create: { + * // ... data to create a User + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the User we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__UserClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of Users. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserCountArgs} args - Arguments to filter Users to count. + * @example + * // Count the number of Users + * const count = await prisma.user.count({ + * where: { + * // ... the filter for the Users we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a User. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by User. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {UserGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends UserGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: UserGroupByArgs['orderBy'] } + : { orderBy?: UserGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetUserGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the User model + */ +readonly fields: UserFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for User. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__UserClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + roles = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + sessions = {}>(args?: Prisma.Subset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions> | Null> + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the User model + */ +export interface UserFieldRefs { + readonly id: Prisma.FieldRef<"User", 'String'> + readonly permissions: Prisma.FieldRef<"User", 'String'> + readonly login: Prisma.FieldRef<"User", 'String'> + readonly name: Prisma.FieldRef<"User", 'String'> + readonly email: Prisma.FieldRef<"User", 'String'> + readonly emailVerified: Prisma.FieldRef<"User", 'DateTime'> + readonly image: Prisma.FieldRef<"User", 'String'> + readonly userId: Prisma.FieldRef<"User", 'Int'> + readonly token: Prisma.FieldRef<"User", 'String'> + readonly createdAt: Prisma.FieldRef<"User", 'DateTime'> + readonly updatedAt: Prisma.FieldRef<"User", 'DateTime'> +} + + +// Custom InputTypes +/** + * User findUnique + */ +export type UserFindUniqueArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * Filter, which User to fetch. + */ + where: Prisma.UserWhereUniqueInput +} + +/** + * User findUniqueOrThrow + */ +export type UserFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * Filter, which User to fetch. + */ + where: Prisma.UserWhereUniqueInput +} + +/** + * User findFirst + */ +export type UserFindFirstArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * Filter, which User to fetch. + */ + where?: Prisma.UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + */ + orderBy?: Prisma.UserOrderByWithRelationInput | Prisma.UserOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Users. + */ + cursor?: Prisma.UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Users from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Users. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Users. + */ + distinct?: Prisma.UserScalarFieldEnum | Prisma.UserScalarFieldEnum[] +} + +/** + * User findFirstOrThrow + */ +export type UserFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * Filter, which User to fetch. + */ + where?: Prisma.UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + */ + orderBy?: Prisma.UserOrderByWithRelationInput | Prisma.UserOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Users. + */ + cursor?: Prisma.UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Users from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Users. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Users. + */ + distinct?: Prisma.UserScalarFieldEnum | Prisma.UserScalarFieldEnum[] +} + +/** + * User findMany + */ +export type UserFindManyArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * Filter, which Users to fetch. + */ + where?: Prisma.UserWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Users to fetch. + */ + orderBy?: Prisma.UserOrderByWithRelationInput | Prisma.UserOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Users. + */ + cursor?: Prisma.UserWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Users from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Users. + */ + skip?: number + distinct?: Prisma.UserScalarFieldEnum | Prisma.UserScalarFieldEnum[] +} + +/** + * User create + */ +export type UserCreateArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * The data needed to create a User. + */ + data: Prisma.XOR +} + +/** + * User createMany + */ +export type UserCreateManyArgs = { + /** + * The data used to create many Users. + */ + data: Prisma.UserCreateManyInput | Prisma.UserCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * User createManyAndReturn + */ +export type UserCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelectCreateManyAndReturn | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * The data used to create many Users. + */ + data: Prisma.UserCreateManyInput | Prisma.UserCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * User update + */ +export type UserUpdateArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * The data needed to update a User. + */ + data: Prisma.XOR + /** + * Choose, which User to update. + */ + where: Prisma.UserWhereUniqueInput +} + +/** + * User updateMany + */ +export type UserUpdateManyArgs = { + /** + * The data used to update Users. + */ + data: Prisma.XOR + /** + * Filter which Users to update + */ + where?: Prisma.UserWhereInput + /** + * Limit how many Users to update. + */ + limit?: number +} + +/** + * User updateManyAndReturn + */ +export type UserUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelectUpdateManyAndReturn | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * The data used to update Users. + */ + data: Prisma.XOR + /** + * Filter which Users to update + */ + where?: Prisma.UserWhereInput + /** + * Limit how many Users to update. + */ + limit?: number +} + +/** + * User upsert + */ +export type UserUpsertArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * The filter to search for the User to update in case it exists. + */ + where: Prisma.UserWhereUniqueInput + /** + * In case the User found by the `where` argument doesn't exist, create a new User with this data. + */ + create: Prisma.XOR + /** + * In case the User was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * User delete + */ +export type UserDeleteArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null + /** + * Filter which User to delete. + */ + where: Prisma.UserWhereUniqueInput +} + +/** + * User deleteMany + */ +export type UserDeleteManyArgs = { + /** + * Filter which Users to delete + */ + where?: Prisma.UserWhereInput + /** + * Limit how many Users to delete. + */ + limit?: number +} + +/** + * User.roles + */ +export type User$rolesArgs = { + /** + * Select specific fields to fetch from the Role + */ + select?: Prisma.RoleSelect | null + /** + * Omit specific fields from the Role + */ + omit?: Prisma.RoleOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.RoleInclude | null + where?: Prisma.RoleWhereInput + orderBy?: Prisma.RoleOrderByWithRelationInput | Prisma.RoleOrderByWithRelationInput[] + cursor?: Prisma.RoleWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.RoleScalarFieldEnum | Prisma.RoleScalarFieldEnum[] +} + +/** + * User.sessions + */ +export type User$sessionsArgs = { + /** + * Select specific fields to fetch from the Session + */ + select?: Prisma.SessionSelect | null + /** + * Omit specific fields from the Session + */ + omit?: Prisma.SessionOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.SessionInclude | null + where?: Prisma.SessionWhereInput + orderBy?: Prisma.SessionOrderByWithRelationInput | Prisma.SessionOrderByWithRelationInput[] + cursor?: Prisma.SessionWhereUniqueInput + take?: number + skip?: number + distinct?: Prisma.SessionScalarFieldEnum | Prisma.SessionScalarFieldEnum[] +} + +/** + * User without action + */ +export type UserDefaultArgs = { + /** + * Select specific fields to fetch from the User + */ + select?: Prisma.UserSelect | null + /** + * Omit specific fields from the User + */ + omit?: Prisma.UserOmit | null + /** + * Choose, which related nodes to fetch as well + */ + include?: Prisma.UserInclude | null +} diff --git a/package.json b/package.json index bac1b98..595cc18 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,39 @@ { "name": "ttscm-api", + "homepage": "https://totaltech.net", + "author": { + "name": "Jackson Roberts", + "email": "jackson.roberts@totaltech.net", + "url": "https://totaltech.net" + }, "module": "src/index.ts", "type": "module", "private": true, "devDependencies": { - "@types/bun": "latest" + "@types/bun": "latest", + "@types/jsonwebtoken": "^9.0.10" }, "peerDependencies": { "typescript": "^5" + }, + "scripts": { + "dev": "NODE_ENV=development bun --watch src/index.ts", + "db:gen": "prisma generate", + "db:push": "prisma migrate dev --skip-generate", + "utils:dev": "docker compose -f .docker/docker-compose.yml up --build", + "utils:gen_private_keys": "bun ./utils/genPrivateKeys" + }, + "dependencies": { + "@discordjs/collection": "^2.1.1", + "@duxcore/eventra": "^1.1.0", + "@prisma/adapter-pg": "^7.3.0", + "cors": "^2.8.6", + "cuid": "^3.0.0", + "hono": "^4.11.5", + "jsonwebtoken": "^9.0.3", + "keypair": "^1.0.4", + "prisma": "^7.3.0", + "zod": "^4.3.6", + "zon": "^1.0.3" } } diff --git a/prisma.config.ts b/prisma.config.ts new file mode 100644 index 0000000..4ddab3a --- /dev/null +++ b/prisma.config.ts @@ -0,0 +1,12 @@ +import 'dotenv/config' +import { defineConfig, env } from 'prisma/config' + +export default defineConfig({ + schema: 'prisma/schema.prisma', + migrations: { + path: 'prisma/migrations', + }, + datasource: { + url: env('DATABASE_URL'), + }, +}) \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..092ebc4 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,56 @@ +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + +// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? +// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init + +generator client { + provider = "prisma-client" + output = "../generated/prisma" +} + +datasource db { + provider = "postgresql" +} + +model Session { + id String @id @default(uuid()) + sessionKey String @unique @default(cuid()) + userId String + expires DateTime + refreshTokenGenerated Boolean @default(false) + refreshedAt DateTime? + invalidatedAt DateTime? + user User @relation(fields: [userId], references: [id], onDelete: Cascade) +} + +model User { + id String @id @default(cuid()) + roles Role[] + permissions String? + login String @unique + name String? + email String @unique + emailVerified DateTime? + image String? + + userId Int @unique + token String? + + sessions Session[] + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model Role { + id String @id @default(uuid()) + title String + moniker String @unique // e.g. admin, super_admin, moderator + + permissions String + users User[] + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} \ No newline at end of file diff --git a/src/Errors/AuthenticationError.ts b/src/Errors/AuthenticationError.ts new file mode 100644 index 0000000..4018912 --- /dev/null +++ b/src/Errors/AuthenticationError.ts @@ -0,0 +1,8 @@ +export default class AuthenticationError extends Error { + constructor(message: string, cause?: string) { + super(); + this.name = "AuthenticationError"; + this.message = message; + this.cause = cause; + } +} diff --git a/src/Errors/AuthorizationError.ts b/src/Errors/AuthorizationError.ts new file mode 100644 index 0000000..f0f8d6a --- /dev/null +++ b/src/Errors/AuthorizationError.ts @@ -0,0 +1,11 @@ +export default class AuthorizationError extends Error { + public status: number; + + constructor(message: string, cause?: string, status?: number) { + super(); + this.name = "AuthorizationError"; + this.status = status ?? 401; + this.message = message; + this.cause = cause; + } +} diff --git a/src/Errors/BodyError.ts b/src/Errors/BodyError.ts new file mode 100644 index 0000000..84fcb04 --- /dev/null +++ b/src/Errors/BodyError.ts @@ -0,0 +1,8 @@ +export default class BodyError extends Error { + constructor(message: string, cause?: string) { + super(); + this.name = "BodyError"; + this.message = message; + this.cause = cause; + } +} diff --git a/src/Errors/ExpiredAccessTokenError.ts b/src/Errors/ExpiredAccessTokenError.ts new file mode 100644 index 0000000..fa2b3e8 --- /dev/null +++ b/src/Errors/ExpiredAccessTokenError.ts @@ -0,0 +1,8 @@ +export default class ExpiredAccessTokenError extends Error { + constructor(cause?: string) { + super(); + this.name = "ExpiredAccessTokenError"; + this.message = "The provided access token has expired."; + this.cause = cause; + } +} diff --git a/src/Errors/ExpiredRefreshTokenError.ts b/src/Errors/ExpiredRefreshTokenError.ts new file mode 100644 index 0000000..fc444ad --- /dev/null +++ b/src/Errors/ExpiredRefreshTokenError.ts @@ -0,0 +1,8 @@ +export default class ExpiredRefreshTokenError extends Error { + constructor(cause?: string) { + super(); + this.name = "ExpiredRefreshTokenError"; + this.message = "The provided refresh token has expired."; + this.cause = cause; + } +} diff --git a/src/Errors/GenericError.ts b/src/Errors/GenericError.ts new file mode 100644 index 0000000..631b188 --- /dev/null +++ b/src/Errors/GenericError.ts @@ -0,0 +1,16 @@ +export default class GenericError extends Error { + public status: number; + + constructor(info: { + name: string; + message: string; + cause?: string; + status?: number; + }) { + super(); + this.name = info.name; + this.status = info.status ?? 400; + this.message = info.message; + this.cause = info.cause; + } +} diff --git a/src/Errors/InsufficientPermission.ts b/src/Errors/InsufficientPermission.ts new file mode 100644 index 0000000..bf104f2 --- /dev/null +++ b/src/Errors/InsufficientPermission.ts @@ -0,0 +1,11 @@ +export default class InsufficientPermission extends Error { + public status: number; + + constructor(message: string, cause?: string) { + super(); + this.name = "InsufficientPermission"; + this.status = 403; + this.message = message; + this.cause = cause; + } +} diff --git a/src/Errors/MissingBodyValue.ts b/src/Errors/MissingBodyValue.ts new file mode 100644 index 0000000..ed8995b --- /dev/null +++ b/src/Errors/MissingBodyValue.ts @@ -0,0 +1,9 @@ +export default class MissingBodyValue extends Error { + constructor(valueName: string) { + super(); + this.name = "MissingBodyValue"; + this.message = `Value '${valueName}' is missing from the body.`; + this.cause = + "A value that was required by the body of this request is missing."; + } +} diff --git a/src/Errors/PermissionsVerificationError.ts b/src/Errors/PermissionsVerificationError.ts new file mode 100644 index 0000000..250b7a6 --- /dev/null +++ b/src/Errors/PermissionsVerificationError.ts @@ -0,0 +1,8 @@ +export default class PermissionsVerificationError extends Error { + constructor(message: string, cause?: string) { + super(); + this.name = "PermissionsVerificationError"; + this.message = message; + this.cause = cause; + } +} diff --git a/src/Errors/RoleError.ts b/src/Errors/RoleError.ts new file mode 100644 index 0000000..aceb0ad --- /dev/null +++ b/src/Errors/RoleError.ts @@ -0,0 +1,8 @@ +export default class RoleError extends Error { + constructor(message: string, cause?: string) { + super(); + this.name = "RoleError"; + this.message = message; + this.cause = cause; + } +} diff --git a/src/Errors/SessionError.ts b/src/Errors/SessionError.ts new file mode 100644 index 0000000..1601de7 --- /dev/null +++ b/src/Errors/SessionError.ts @@ -0,0 +1,8 @@ +export default class SessionError extends Error { + constructor(message: string, cause?: string) { + super(); + this.name = "SessionError"; + this.message = message; + this.cause = cause; + } +} diff --git a/src/Errors/SessionTokenError.ts b/src/Errors/SessionTokenError.ts new file mode 100644 index 0000000..1f8ed7a --- /dev/null +++ b/src/Errors/SessionTokenError.ts @@ -0,0 +1,8 @@ +export default class SessionTokenError extends Error { + constructor(message: string, cause?: string) { + super(); + this.name = "SessionTokenError"; + this.message = message; + this.cause = cause; + } +} diff --git a/src/Errors/UserError.ts b/src/Errors/UserError.ts new file mode 100644 index 0000000..6273153 --- /dev/null +++ b/src/Errors/UserError.ts @@ -0,0 +1,8 @@ +export default class UserError extends Error { + constructor(message: string, cause?: string) { + super(); + this.name = "UserError"; + this.message = message; + this.cause = cause; + } +} diff --git a/src/api/.gitignore b/src/api/.gitignore new file mode 100644 index 0000000..9f62ec0 --- /dev/null +++ b/src/api/.gitignore @@ -0,0 +1,5 @@ +node_modules +# Keep environment variables out of version control +.env + +/generated/prisma diff --git a/src/api/prisma.config.ts b/src/api/prisma.config.ts new file mode 100644 index 0000000..d5ecde5 --- /dev/null +++ b/src/api/prisma.config.ts @@ -0,0 +1,12 @@ +// This file was generated by Prisma, and assumes you run Prisma commands using `bun --bun run prisma [command]`. +import { defineConfig, env } from "prisma/config"; + +export default defineConfig({ + schema: "prisma/schema.prisma", + migrations: { + path: "prisma/migrations", + }, + datasource: { + url: env("DATABASE_URL"), + }, +}); diff --git a/src/api/server.ts b/src/api/server.ts new file mode 100644 index 0000000..015e506 --- /dev/null +++ b/src/api/server.ts @@ -0,0 +1,53 @@ +import { Hono } from "hono"; +import { apiResponse } from "../modules/api-utils/apiResponse"; +import { ZodError } from "zod"; +import { cors } from "hono/cors"; +import GenericError from "../Errors/GenericError"; +import teapot from "./teapot"; + +const app = new Hono(); +const v1 = new Hono(); + +app.onError((err, ctx) => { + const errClassName = err.constructor.name; + + if ( + errClassName.toLowerCase().includes("prisma") || + err.message.toLowerCase().includes("prisma") || + err.name.toLowerCase().includes("prisma") + ) { + console.trace(err); + return ctx.json(apiResponse.internalError(), 500); + } + + if (err instanceof ZodError) { + return ctx.json( + apiResponse.zodError(err), + //@ts-ignore + apiResponse.zodError(err).status + ); + } + + const response = apiResponse.error(err); + return ctx.json(response, response.status); +}); + +app.use("*", cors()); + +app.notFound((c) => { + const response = apiResponse.error( + new GenericError({ + name: "NotFound", + message: `Cannot ${c.req.method.toUpperCase()} ${c.req.path}`, + status: 404, + cause: "Unknown", + }) + ); + return c.json(response, response.status); +}); + +v1.route("/teapot", teapot); + +app.route("/v1", v1); + +export default app; \ No newline at end of file diff --git a/src/api/teapot.ts b/src/api/teapot.ts new file mode 100644 index 0000000..0e91a1f --- /dev/null +++ b/src/api/teapot.ts @@ -0,0 +1,12 @@ +import { Hono } from "hono/tiny"; +import { createRoute } from "../modules/api-utils/createRoute"; + +/* /v1/teapot */ +export default createRoute("get", ["/"], (c) => { + c.status(418); + return c.json({ + status: 418, + message: "I'm not a teapot", + successful: true, + }); +}); diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..78c8670 --- /dev/null +++ b/src/constants.ts @@ -0,0 +1,34 @@ +import { readFileSync } from "fs"; +import { PrismaPg } from '@prisma/adapter-pg' +import { PrismaClient } from '../generated/prisma/client' + +const connectionString = `${process.env.DATABASE_URL}` +const adapter = new PrismaPg({ connectionString }) + + +interface EnvKey { + PORT: number; +}; + +// ENV CONSTANTS + +export const PORT = process.env.PORT; + +export const prisma = new PrismaClient({ adapter }) + +export const sessionDuration = 30 * 24 * 60 * 60000; +export const accessTokenDuration = "10min"; +export const refreshTokenDuration = "30d"; + +export const accessTokenPrivateKey = readFileSync( + `${import.meta.dir}/../.accessToken.key` +).toString(); +export const refreshTokenPrivateKey = readFileSync( + `${import.meta.dir}/../.refreshToken.key` +).toString(); +export const permissionsPrivateKey = readFileSync( + `${import.meta.dir}/../.permissions.key` +); +export const apiKeyTokenPrivateKey = readFileSync( + `${import.meta.dir}/../.apiKeyToken.key` +); \ No newline at end of file diff --git a/src/controllers/RoleController.ts b/src/controllers/RoleController.ts new file mode 100644 index 0000000..f52c1c0 --- /dev/null +++ b/src/controllers/RoleController.ts @@ -0,0 +1,338 @@ +import UserController from "./UserController"; +import { Collection } from "@discordjs/collection"; +import jwt, { JsonWebTokenError } from "jsonwebtoken"; +import { permissionsPrivateKey, prisma } from "../constants"; +import PermissionsVerificationError from "../Errors/PermissionsVerificationError"; +import { mergeArrays } from "../modules/tools/mergeArrays"; +import { signPermissions } from "../modules/permission-utils/signPermissions"; +import { DecodedPermissionsBlock } from "../types/PermissionTypes"; +import { permissionValidator } from "../modules/permission-utils/permissionValidator"; +import { z } from "zod"; +import { roles } from "../managers/roles"; +import GenericError from "../Errors/GenericError"; +import RoleError from "../Errors/RoleError"; +import { Role, User } from "../../generated/prisma/client"; +import { events } from "../modules/globalEvents"; + +/** + * Roles + * + * Roles are for adding onto a users permissions. They are not for defining a default users permissions. + * + * Roles have two forms of identifiers, titles and monikers. The title is something that can be capitalized and publicly displayed, + * so if you make modifications, and you need to be able to see how they were able to do that without having explicit permission to + * make the modifications, the title is what would be shown to you. The moniker is the human readable identifier. So in an api + * response where you need to get the roles of a user, instead of being given a bunch of id's, you will be given a bunch of monikers + * which are easy to read and easy to identify. + */ +export class RoleController { + public readonly id: string; + public title: string; + public moniker: string; // e.g. admin, super_admin, moderator + + private _permissionsToken: string; + private _users: (User & { roles: Role[] })[]; + + public readonly createdAt: Date; + public updatedAt: Date; + + public deleted: boolean = false; + + constructor(roledata: Role & { users: (User & { roles: Role[] })[] }) { + this.id = roledata.id; + this.title = roledata.title; + this.moniker = roledata.moniker; + + this._permissionsToken = roledata.permissions; + this._users = roledata.users; + + this.createdAt = roledata.createdAt; + this.updatedAt = roledata.updatedAt; + } + + private _signPermissions = signPermissions; + + /** + * Verify Permissions + * + * This method is vital to maintining the security of this system. This method is here to ensure + * that the permissions object is authentic and signed by our system. + * + * @param permissionsToken - Signed permissions JWT + * @returns - Verified object with permissions in it. + */ + private _verifyPermissions(permissionsToken: string) { + let perms: DecodedPermissionsBlock; + try { + perms = jwt.verify(permissionsToken, permissionsPrivateKey, { + algorithms: ["RS256"], + issuer: "roles", + subject: this.id, + }) as DecodedPermissionsBlock; + } catch (err) { + events.emit("role:permissions:verification_error", { + currentSigned: this._permissionsToken, + attemptedVerification: permissionsToken, + err: err as Error, + role: this, + }); + throw new PermissionsVerificationError( + `Unable to verify permissions for role '${this.title}, it is recommended that you override and rewrite these permissions immediately.`, + (err as Error).message + ); + } + + return perms as { permissions: string[] }; + } + + /** + * Get Users + * + * This will get all the users that have this role and return it as a collection dictionary where the key is + * the `id` of the user and the value is the users `UserController`. + * + * @returns {Collection} - A collection of all the users that are assigned to this role + */ + public getUsers() { + const collection = new Collection(); + this._users.map((v) => collection.set(v.id, new UserController(v))); + return collection; + } + + /** + * Check Permission + * + * Check to see if a role has a specified set of permissions. + * + * @param permission - The permission to check for + * @returns {boolean} Does this role have the specified permission + */ + public checkPermission(permission: string): boolean { + const permissions = this._verifyPermissions(this._permissionsToken); + return permissionValidator(permission, permissions.permissions); + } + + /** + * Set permissions + * + * This will remove all existing permissions and replate them with the permissions defined in the params + * of this method. + * + * @param permissions - Array of all Permissions + * @returns {void} + */ + public async setPermissions(...permissions: string[]) { + /* + Make sure the current permissions are verified before updating them again. Basically speaking if the permissions + are tampered with in any way, this bricks the further modification of the permissions + */ + const previous = this._verifyPermissions(this._permissionsToken); + + const newPermissionsToken = this._signPermissions({ + issuer: "roles", + subject: this.id, + permissions, + }); + const newRaw = await prisma.role.update({ + where: { id: this.id }, + data: { permissions: newPermissionsToken }, + }); + + events.emit("role:permissions:updated", { + current: permissions, + currentSigned: newPermissionsToken, + previous: previous.permissions, + previousSigned: this._permissionsToken, + action: "set", + role: this, + }); + + this._permissionsToken = newPermissionsToken; + this.updatedAt = newRaw.updatedAt; + return; + } + + /** + * Add Permissions + * + * This will take the permissions provided in the params of the method and combine them into the pre-existing + * permissions of this role. + * + * @param permissions - Array of added Permissions + * @returns {void} + */ + public async addPermissions(...permissions: string[]) { + /* + Make sure the current permissions are verified before updating them again. Basically speaking if the permissions + are tampered with in any way, this bricks the further modification of the permissions + */ + const previous = this._verifyPermissions(this._permissionsToken); + + const newPermissionsToken = this._signPermissions({ + issuer: "roles", + subject: this.id, + permissions: mergeArrays(previous.permissions, permissions), + }); + const newRaw = await prisma.role.update({ + where: { id: this.id }, + data: { permissions: newPermissionsToken }, + }); + + events.emit("role:permissions:updated", { + current: permissions, + currentSigned: newPermissionsToken, + previous: previous.permissions, + previousSigned: this._permissionsToken, + action: "added", + role: this, + }); + + this._permissionsToken = newPermissionsToken; + this.updatedAt = newRaw.updatedAt; + return; + } + + /** + * Remove Permissions + * + * This will take the permissions provided in the params of the method and remove them from the exisitng + * permissions object for this role. + * + * @param permissions - Array of removed Permissions + * @returns {void} + */ + public async removePermissions(...permissions: string[]) { + /* + Make sure the current permissions are verified before updating them again. Basically speaking if the permissions + are tampered with in any way, this bricks the further modification of the permissions + */ + const previous = this._verifyPermissions(this._permissionsToken); + + const newPermissionsToken = this._signPermissions({ + issuer: "roles", + subject: this.id, + permissions: previous.permissions.filter((v) => !permissions.includes(v)), + }); + const newRaw = await prisma.role.update({ + where: { id: this.id }, + data: { permissions: newPermissionsToken }, + }); + + events.emit("role:permissions:updated", { + current: permissions, + currentSigned: newPermissionsToken, + previous: previous.permissions, + previousSigned: this._permissionsToken, + action: "removed", + role: this, + }); + + this._permissionsToken = newPermissionsToken; + this.updatedAt = newRaw.updatedAt; + return; + } + + /** + * Get Current Permissions + * + * Get all of the permissions for this role. + * @returns {string[]} - Existing permissions in an array + */ + public getPermissions() { + const permissions = this._verifyPermissions(this._permissionsToken!); + return permissions; + } + + public async update( + data: Partial<{ + title: string; + moniker: string; + permissions: string[]; + }> + ) { + const schema = z + .object({ + title: z.string().min(1, "Title cannot be empty."), + moniker: z.string().min(1, "Moniker cannot be empty."), + permissions: z.array( + z.string().min(1, "Permission node cannot be empty") + ), + }) + .partial() + .strict(); + + data = schema.parse(data); + + if (data.moniker) { + const checkMoniker = await prisma.role.findFirst({ + where: { moniker: data.moniker }, + }); + + if (checkMoniker) + throw new RoleError( + "Moniker is already taken.", + "Another role with this moniker already exists in the databse." + ); + } + + const updatedRole = await prisma.role.update({ + where: { id: this.id }, + data: { + ...data, + permissions: undefined, + }, + }); + + if (data.permissions) await this.setPermissions(...data.permissions); + + events.emit("role:updated", { role: this, updateData: data }); + this.title = data.title ?? this.title; + this.moniker = data.moniker ?? this.moniker; + + return this; + } + + /** + * Delete Role + * + * @returns {Promise} The Remains of a deleted role. + */ + public async delete() { + const deletedData = await prisma.role.delete({ where: { id: this.id } }); + + this.deleted = true; + events.emit("role:deleted", this); + return this; + } + + /** + * To JSON + * + * Create a JSON object that can be used in things like API responses. + * + * @param opts - Optional values to include in the response. + * @returns - JSON-Friendly object. + */ + public toJson(opts?: { viewUsers?: boolean; viewPermissions?: boolean }) { + let object = { + id: this.id, + title: this.title, + moniker: this.moniker, + permissions: opts?.viewPermissions + ? this._verifyPermissions(this._permissionsToken).permissions + : undefined, + users: opts?.viewUsers + ? this._users.map((v) => ({ + id: v.id, + name: v.name, + login: v.login, + roles: v.roles.map((r:any) => r.id), + })) + : undefined, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + }; + + return object; + } +} diff --git a/src/controllers/SessionController.ts b/src/controllers/SessionController.ts new file mode 100644 index 0000000..813bbf1 --- /dev/null +++ b/src/controllers/SessionController.ts @@ -0,0 +1,228 @@ +import jwt from "jsonwebtoken"; +import { + prisma, + refreshTokenDuration, + accessTokenDuration, + accessTokenPrivateKey, + refreshTokenPrivateKey, +} from "../constants"; +import SessionTokenError from "../Errors/SessionTokenError"; +import { events } from "../modules/globalEvents"; +import UserController from "./UserController"; +import { users } from "../managers/users"; +import { Session } from "../../generated/prisma/client"; + +export interface SessionPayloadObject { + userID: string; + sessionKey: string; +} + +export interface SessionTokensObject { + accessToken: string; + refreshToken: string; +} + +export type DecodedSession = SessionPayloadObject & { + iat: number; + exp: number; +}; + +/** + * Session Controller + * + * This class is for create a controller that can manage, generate and refresh tokens, self terminate and self delete + * all sessions. This also allows you to access all data about a session. + */ +export class SessionController { + public readonly id: string; + public readonly sessionKey: string; + public readonly userId: string; + public readonly expires: Date; + public refreshedAt: Date | null; + public invalidatedAt: Date | null; + + public terminated: boolean = false; + + private _refreshTokenGenrated: boolean; + + constructor(sessionData: Session) { + this.id = sessionData.id; + this.sessionKey = sessionData.sessionKey; + this.userId = sessionData.userId; + this.expires = sessionData.expires; + this.refreshedAt = sessionData.refreshedAt; + this.invalidatedAt = sessionData.invalidatedAt; + + this._refreshTokenGenrated = sessionData.refreshTokenGenerated; + } + + /** @ignore */ + private _generateAccessToken() { + const payload: SessionPayloadObject = { + sessionKey: this.sessionKey, + userID: this.userId, + }; + + return jwt.sign(payload, accessTokenPrivateKey, { + algorithm: "RS256", + expiresIn: accessTokenDuration, + }); + } + + /** @ignore */ + private _generateRefreshToken() { + const payload: SessionPayloadObject = { + sessionKey: this.sessionKey, + userID: this.userId, + }; + + return jwt.sign(payload, refreshTokenPrivateKey, { + algorithm: "RS256", + expiresIn: refreshTokenDuration, + }); + } + + /** + * Invalidate the Session + * + * The purpose for this function is if you wanted to be able to listen for somebody using an invalid session, + * you just have to invalidate it with this function and go from there. + * + * @returns {Promise} - nothing + */ + public async invalidate() { + const invalidationDate = new Date(); + + if (this.invalidatedAt) + throw new Error("Session has already been invalidated."); + + await prisma.session.update({ + data: { invalidatedAt: invalidationDate }, + where: { id: this.id }, + }); + this.invalidatedAt = invalidationDate; + + events.emit("session:invalidated", this); + return; + } + + /** + * Terminate the session + * + * Terminating the session will immediately delete the session making it impossible for it to be referenced again. + * + * @returns {Promise} - nothing + */ + public async terminate() { + await prisma.session.delete({ where: { id: this.id } }); + events.emit("session:terminated", this); + this.terminated = true; + return; + } + + /** + * Generate Tokens + * + * **NOTE**: This method can only be ran once per session. + * + * Running this function will allow you to generate an accessToken and a refreshToken. Each token + * will be generated with their own respective private keys. + * + * + * @returns {Promise} An object containing the `accessToken` and `refreshToken` + */ + public async generateTokens(): Promise { + if (this._refreshTokenGenrated) + throw new Error("Tokens have alredy been generated for this session."); + + const accessToken = this._generateAccessToken(); + const refreshToken = this._generateRefreshToken(); + + const newRefreshDate = new Date(); + await prisma.session.update({ + data: { refreshTokenGenerated: true, refreshedAt: newRefreshDate }, + where: { id: this.id }, + }); + this._refreshTokenGenrated = true; + this.refreshedAt = newRefreshDate; + + let tokens = { accessToken, refreshToken }; + + events.emit("session:tokens_generated", { session: this, tokens }); + + return tokens; + } + + /** + * Refresh the session + * + * Refreshing the session will generate a new accessToken for the user to authenticate their requests with. + * + * **NOTE**: Best practice when implementing token refreshing into the UI is that if for any reason this method + * throws an error, imediately purge the existing tokens and have the user login again. This way you don't hold + * them up any longer than necessary. + * + * @param refreshToken - The refresh token provided at session generation + * @returns {Promise} The new access token. + */ + public refresh(refreshToken: string): Promise { + return new Promise(async (res, rej) => { + if (this.expires.getTime() <= Date.now()) { + await this.terminate(); + throw new SessionTokenError("Session has Expired."); + } + jwt.verify( + refreshToken, + refreshTokenPrivateKey, + { + algorithms: ["RS256"], + }, + async (err, decode) => { + if (err) { + if ( + err.name == "TokenExpiredError" || + err.message == "invalid signature" + ) + this.terminate(); + rej(err); + } + const data: DecodedSession = decode as DecodedSession; + + if ( + data.sessionKey !== this.sessionKey || + data.userID !== this.userId + ) + rej( + new SessionTokenError( + "Refresh token does not match this session." + ) + ); + + await prisma.session.update({ + data: { refreshedAt: new Date() }, + where: { id: this.id }, + }); + + const newToken = this._generateAccessToken(); + events.emit("session:token_refresh", { + session: this, + tokens: { accessToken: newToken, refreshToken }, + }); + + return res(newToken); + } + ); + }); + } + + /** + * Fetch Session User + * + * Fetch the user controller of the user that created the session. + * + * @returns {Promise} The user that created this session. + */ + public async fetchUser(): Promise { + return (await users.fetchUser({ id: this.userId }))!; + } +} diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts new file mode 100644 index 0000000..d4d4276 --- /dev/null +++ b/src/controllers/UserController.ts @@ -0,0 +1,200 @@ +import { Collection } from "@discordjs/collection"; +import { z } from "zod"; +import { Role } from "../../generated/prisma/client"; +import { User } from "../../generated/prisma/browser"; +import { SessionTokensObject } from "./SessionController"; +import { sessions } from "../managers/sessions"; +import BodyError from "../Errors/BodyError"; +import { prisma } from "../constants"; +import { events } from "../modules/globalEvents"; +import { RoleController } from "./RoleController"; +import { roles } from "../managers/roles"; + + + +export default class UserController { + public id: string; + public name: string | null; + public login: string; + public email: string; + public image: string | null; + + private _roles: Collection; + + public createdAt: Date; + public updatedAt: Date; + constructor(userdata: User & { roles: Role[] }) { + this.id = userdata.id; + this.name = userdata.name; + this.login = userdata.login; + this.email = userdata.email; + this.image = userdata.image; + this.updatedAt = userdata.updatedAt; + this.createdAt = userdata.createdAt; + + this._roles = (() => { + let collection = new Collection(); + userdata.roles.map((v: any) => collection.set(v.id, v)); + + return collection; + })(); + } + + /** + * Update the internal values + * + * This is an internal method used to update all the internal values when we query the database. This way + * everything stays upto date even when we pass around the user controller. + * + * @param userdata - User object from Prisma + */ + private _updateInternalValues(userdata: User) { + this.id = userdata.id; + this.name = userdata.name; + this.login = userdata.login; + this.email = userdata.email; + this.image = userdata.image; + this.updatedAt = userdata.updatedAt; + this.createdAt = userdata.createdAt; + } + + /** + * Create Session + * + * This will create a session in the database that is linked to the user and will then create a pair of access and refresh + * tokens to provide to the user such that they can authorized their api requests. + * + * @returns {Promise} - Object with an access token and a refresh token. + */ + public async createSession(): Promise { + return sessions.create({ user: this }); + } + + /** + * Update the user + * + * Take in a partial of the user data and validate it then updated it if it passes validation and return + * the updated `UserController` object. + * + * @param data - A partial of the user data + * @returns {Promise} - The updated user controller + */ + public async update(data: Partial) { + // Parsed Data With Schema + const pData = z + .object({ + name: z.string().optional(), + image: z.string().optional(), + }) + .strict() + .parse(data); + + if (Object.keys(data).length == 0) + throw new BodyError("Body cannot be empty."); + + const updatedUser = await prisma.user.update({ + where: { id: this.id }, + data: pData, + }); + + this._updateInternalValues(updatedUser); + events.emit("user:updated", { user: this, updatedValues: data }); + + return this; + } + + /** + * Fetch Roles + * + * This method will fetch all of the roles that a user belongs to and will return each of their controllers in a collection + * of role id's and RoleControllers. + * + * @returns {Promise>} A collection of all the roles a user has + */ + public async fetchRoles(): Promise> { + const collection = new Collection(); + + await Promise.all( + this._roles.map(async (v) => + collection.set(v.id, await roles.fetch(v.id)) + ) + ); + + return collection; + } + + /** + * Check Permission + * + * Check if this user has this specific permission. This method will not only check explicit permissions defined in + * the database under users and roles, but will also generate implicit permissions for resources that the user has + * access to but doesn't specifically have defined under any given permissions object. + * + * @param permission - The permission to check for + * @returns {boolean} Does this user have the specified permission + */ + public async hasPermission(permission: string) { + let resources = await prisma.user.findFirst({ + where: { id: this.id }, + select: { + sessions: { + select: { id: true }, + }, + apiKeys: { + select: { id: true }, + }, + projects: { + select: { id: true }, + }, + services: { + select: { id: true }, + }, + }, + }); + + const implicitPermissions = Object.keys(resources ?? {}) + .filter((v) => resources![v].length > 0) + .map( + (v) => + `resource.${v}.[${(resources![v] as { id: string }[]) + .map((o) => o.id) + .join(",")}].user.${this.id}.implicit` + ); + + console.log(implicitPermissions); + + let checks = [ + (await this.fetchRoles()).map((v) => v.checkPermission(permission)), + ].flatMap((v) => v); + + return checks.includes(true); + } + + /** + * To JSON + * + * Create an object that can be safely returned to the user of an api request such that when you + * need to return data to the end user, you don't accidently return data that could be harmful + * if leaked. + * + * Options: + * - Safe return is to return only data that is considered "safe", and not detrimental to pass around + * + * @param opts - Options to change the output + * @returns - An object that is JSON friendly + */ + public toJson(opts?: { safeReturn: boolean }) { + return { + id: this.id, + name: this.name, + roles: opts?.safeReturn + ? undefined + : this._roles.size > 0 + ? this._roles.map((v) => v.moniker) + : undefined, + login: opts?.safeReturn ? undefined : this.login, + email: opts?.safeReturn ? undefined : this.email, + image: this.image, + }; + } +} diff --git a/src/index.ts b/src/index.ts index f67b2c6..d40f9ae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,7 @@ -console.log("Hello via Bun!"); \ No newline at end of file +import app from "./api/server"; +import { PORT } from "./constants"; + +Bun.serve({ + port: PORT, + fetch: app.fetch +}); \ No newline at end of file diff --git a/src/managers/roles.ts b/src/managers/roles.ts new file mode 100644 index 0000000..8dd3c72 --- /dev/null +++ b/src/managers/roles.ts @@ -0,0 +1,171 @@ +import { Collection } from "@discordjs/collection"; +import GenericError from "../Errors/GenericError"; +import RoleError from "../Errors/RoleError"; +import { prisma } from "../constants"; +import { RoleController } from "../controllers/RoleController"; +import { signPermissions } from "../modules/permission-utils/signPermissions"; +import cuid from "cuid"; +import UserController from "../controllers/UserController"; +import InsufficientPermission from "../Errors/InsufficientPermission"; +import { z } from "zod"; + +export const roles = { + /** + * Create a role + * + * @param data - Data required to make a role + * @returns {RoleController} - The new role + */ + async create(data: { + title: string; + moniker: string; + permissions?: string[]; + }) { + const schema = z.object({ + title: z.string().min(1, "Title cannot be empty"), + moniker: z.string().min(1, "Moniker cannot be empty"), + permissions: z + .array(z.string().min(1, "Cannot have a blank permission node.")) + .optional(), + }); + + data = await schema.parseAsync(data); + + const checkMoniker = await prisma.role.findFirst({ + where: { moniker: data.moniker }, + }); + + if (checkMoniker) + throw new RoleError( + "Moniker is already taken.", + "Another role with this moniker already exists in the databse." + ); + + const id = cuid(); + const newRole = await prisma.role.create({ + data: { + id, + title: data.title, + moniker: data.moniker, + permissions: signPermissions({ + issuer: "roles", + subject: id, + permissions: data.permissions ?? [], + }), + }, + include: { + users: { + include: { + roles: true, + }, + }, + }, + }); + + const controller = new RoleController(newRole); + + return controller; + }, + + /** + * Fetch a role + * + * Fetch a role using either it's id or it's moniker. + * + * @param identifier - Role `id` or `moniker` + * @param identifier - Options for fetching a role. + * @returns {RoleController} - Role Controller + */ + async fetch(identifier:string, opt?: { requestingUser?: UserController }) { + const roleData = await prisma.role.findFirst({ + where: { OR: [{ id: identifier }, { moniker: identifier }] }, + include: { + users: { + include: { + roles: true, + }, + }, + }, + }); + + if (!roleData) + throw new GenericError({ + name: "UnknownRole", + message: "Unknown role...", + status: 404, + }); + + if ( + opt?.requestingUser && + !(await opt.requestingUser.hasPermission( + this._buildPermissionNode(roleData.id, "read") + )) + ) + throw new InsufficientPermission( + "You do not have permission to access this role." + ); + const controller = new RoleController(roleData); + + return controller; + }, + + /** + * Fetch all roles + * + * This will give you all of the roles and their respective controllers + * + * @param opt - Options for fetching all roles. + * @returns {Collection} A collection of all the roles and their id's + */ + async fetchAllRoles(opt?: { requestingUser?: UserController }) { + let collection = new Collection(); + const roles = await prisma.role.findMany({ + include: { users: { include: { roles: true } } }, + }); + + roles. map((v:any) => collection.set(v.id, new RoleController(v))); + + if (opt?.requestingUser) { + const permittedRoles = await Promise.all( + collection.map(async (v) => + (await opt.requestingUser?.hasPermission( + this._buildPermissionNode(v.id, "read") + )) + ? v.id + : null + ) + ); + collection = collection.filter((v) => + permittedRoles.filter((x) => x !== null).includes(v.id) + ); + } + + return collection; + }, + + /** + * Build Permissino Node + * + * Build a role centric permission node with a role id and permission scope. + * + * **FORMAT**: `roles.{id}.{scope} + * + * @param id - Role ID + * @param scope - Scope of the permission node + * @returns {string} Constructed Permission Node + */ + _buildPermissionNode(id: string, scope: "read" | "write") { + return ["roles", id, scope].join("."); + }, +}; + +/** + * @TODO automatic string transformation for monikers to be all lower case with no spaces and only underscores. + * + * @TODO create and inheritance and ordering system @see https://www.prisma.io/docs/concepts/components/prisma-schema/relations/self-relations + * + * @TODO go through and make sure all the zod schemas have mins, maxes, etc. + * + * @TODO Limit those who can give out the `*` permission to those with the `*` permission. + * - Maybe also limit the use of `*` all together? + */ diff --git a/src/managers/sessions.ts b/src/managers/sessions.ts new file mode 100644 index 0000000..9817554 --- /dev/null +++ b/src/managers/sessions.ts @@ -0,0 +1,159 @@ +import { + prisma, + refreshTokenDuration, + sessionDuration, + accessTokenDuration, + accessTokenPrivateKey, + refreshTokenPrivateKey, +} from "../constants"; +import UserController from "../controllers/UserController"; +import { + SessionController, + DecodedSession, + SessionPayloadObject, + SessionTokensObject, +} from "../controllers/SessionController"; +import jwt from "jsonwebtoken"; +import SessionError from "../Errors/SessionError"; +import SessionTokenError from "../Errors/SessionTokenError"; +import ExpiredAccessTokenError from "../Errors/ExpiredAccessTokenError"; +import ExpiredRefreshTokenError from "../Errors/ExpiredRefreshTokenError"; +import { events } from "../modules/globalEvents"; + +export interface SessionCreationData { + user: UserController; +} + +export const sessions = { + /** + * Create a session + * + * This will create a session instance in the databse that will be linked to both the session token + * and the refresh token. + * + * @param data - The params needed to create the session tokens + * @returns {Promise} Session Token and the Refresh Token + */ + async create(data: SessionCreationData): Promise { + const session = await prisma.session.create({ + data: { + expires: new Date(Date.now() + sessionDuration), + userId: data.user.id, + }, + }); + + const controller = new SessionController(session); + + // Trigger Global Event + events.emit("session:created", { + user: data.user, + session: controller, + }); + + let tokens: SessionTokensObject = await controller.generateTokens(); + + return tokens; + }, + + /** + * Fetch a session + * + * This method is designed to be as versitile as possible, if you are looking for a session, use this method with + * your choice of `accessToken`, `refreshToken`, `id`, or `sessionKey`. The identifier value is a partial type. + * + * @param identifier - An object allowing you to put either session token, sessionKey, or id in to fetch the desired session. + * @returns {Promise} The controller for the desired session. + */ + async fetch( + identifier: Partial<{ + refreshToken: string; + accessToken: string; + id: string; + sessionKey: string; + }> + ) { + if (identifier.refreshToken || identifier.accessToken) { + const decodedJWT = identifier.refreshToken + ? ((await new Promise((res, rej) => + jwt.verify( + identifier.refreshToken!, + refreshTokenPrivateKey, + { + algorithms: ["RS256"], + }, + async (err, decode) => { + if ( + err && + (err.name == "TokenExpiredError" || + err.message == "invalid signature") + ) { + let sessionDat = await prisma.session.findFirst({ + where: { + sessionKey: ( + jwt.decode(identifier.refreshToken!) as DecodedSession + ).sessionKey, + }, + }); + + if (!sessionDat) + return rej(new SessionError("Invalid session.")); + let session = new SessionController(sessionDat); + + await session.terminate(); + if (err.message == "invalid signature") + return rej(new SessionError("Invalid session.")); + + return rej(new ExpiredRefreshTokenError("It epired.")); + } + if (err) return rej(err); + + return res(decode as DecodedSession); + } + ) + )) as DecodedSession) + : ((await new Promise((res, rej) => + jwt.verify( + identifier.accessToken!, + accessTokenPrivateKey, + { + algorithms: ["RS256"], + }, + (err, decode) => { + if (err && err.name == "TokenExpiredError") + return rej(new ExpiredAccessTokenError()); + if (err) return rej(err); + return res(decode as DecodedSession); + } + ) + )) as DecodedSession); + + const sessionData = await prisma.session.findFirst({ + where: { sessionKey: decodedJWT.sessionKey }, + }); + + if (!sessionData) throw new SessionError("Invalid Session"); + if (identifier.accessToken && decodedJWT.exp > Date.now()) + throw new ExpiredAccessTokenError(); + + if (identifier.refreshToken && decodedJWT.exp > Date.now()) { + let sess = new SessionController(sessionData); + await sess.terminate(); + throw new SessionError("Invalid Session...", "Expired Refresh Token"); + } + + return new SessionController(sessionData); + } + + const sessionData = await prisma.session.findFirst({ + where: { OR: [{ sessionKey: identifier.sessionKey, id: identifier.id }] }, + }); + + if (!sessionData) throw new SessionError("Invalid Session"); + + return new SessionController(sessionData); + }, +}; + +/** + * @TODO As a consequence of the above, need to setup pgBoss for cron and event loop. + */ diff --git a/src/managers/users.ts b/src/managers/users.ts new file mode 100644 index 0000000..53617ef --- /dev/null +++ b/src/managers/users.ts @@ -0,0 +1,118 @@ +import { User } from "../../generated/prisma/client"; +import { prisma } from "../constants"; +import { SessionTokensObject } from "../controllers/SessionController"; +import UserController from "../controllers/UserController"; + +export const users = { + /** + * Authenticate The User + * + * If the user has already been registered, this function will supply them with a session id, otherwise + * this method will create an account, then create a session id. + * + * @summary It creates a user if one doesn't exist and will supply a session id + * + * @async + * @param ghCode - The code supplied in the callback url of a GitHub oAuth transaction + */ +/* async authenticate(ghCode: string): Promise { + const token = await ghApp.oauth.createToken({ code: ghCode }).catch((e) => { + throw new AuthenticationError("Invalid OAuth code..."); + }); + const userOK = await ghApp.oauth.getUserOctokit({ + token: token.authentication.token, + }); + const ghUser = await userOK.request("GET /user"); + let user = + (await this.fetchUser({ userId: ghUser.data.id })) ?? + (await this.createUser(token.authentication.token)); + + const tokens = await sessions.create({ user }); + events.emit("user:authenticated", { user, tokens }); + + return tokens; + }, */ + + /** + * Check to see if the user exists + * + * @param partial - A partial object that you can feed any value from the database into. + * @returns {Promise} Does the user exist? + */ + async userExists(partial: Partial): Promise { + const match = await prisma.user.findFirst({ where: partial }); + return !!match; + }, + + /** + * Fetch a user + * + * This method takes in a unique identifier for the user you are trying to fetch, and returns + * the controller for the user if the user exists. If the user doesn't exist, or no identifier + * was provided, this will reutrn `null`. + * + * @param identifier - A partial identifier for a user (e.g. id, email, userID, etc.) + * @returns {Promise} The controller for the user + */ + async fetchUser( + identifier: Partial<{ + id: string; + email: string; + login: string; + userId: number; + }> + ) { + if (Object.keys(identifier).length == 0) return null; + const userData = await prisma.user.findFirst({ + where: { + //@ts-ignore + OR: Object.keys(identifier).map((v) => ({ [v]: identifier[v] })), + }, + include: { roles: true }, + }); + + if (!userData) return null; + + return new UserController(userData); + }, + + /** + * Create a new user + * + * This method will poll GitHub and get all the information on the user to then create the + * record in our database. On top of that it also pushes it into the user cache. + * + * @param token - The Github token provided by the auth method + * @returns {Promise} The new user controller for the user + */ + async createUser(token: string): Promise { + const ghUser = await ( + await ghApp.oauth.getUserOctokit({ token }) + ).request("GET /user"); + + const emails = await ( + await ghApp.oauth.getUserOctokit({ token }) + ).request("GET /user/emails"); + + const newUser = await prisma.user.create({ + data: { + userId: ghUser.data.id, + email: emails.data[0].email, + image: ghUser.data.avatar_url, + name: ghUser.data.name, + login: ghUser.data.login, + token, + }, + include: { roles: true }, + }); + + let controller = new UserController(newUser); + events.emit("user:created", controller); + + return controller; + }, +}; + +/** + * @TODO Figure out default permissions + */ diff --git a/src/modules/api-utils/apiResponse.ts b/src/modules/api-utils/apiResponse.ts new file mode 100644 index 0000000..47072c2 --- /dev/null +++ b/src/modules/api-utils/apiResponse.ts @@ -0,0 +1,56 @@ +import { ZodError } from "zod"; + +/** + * @ignore + */ +export const apiResponse = { + successful: (message: string, data?: any) => ({ + status: 200, + message, + data, + successful: true, + meta: { + timestamp: Date.now(), + }, + }), + created: (message: string, data?: any) => ({ + status: 201, + message, + data, + successful: true, + meta: { + timestamp: Date.now(), + }, + }), + error: (err: Error) => ({ + // @ts-ignore + status: err["status"] ?? 400, + message: err.message, + error: err.name, + successful: false, + meta: { + timestamp: Date.now(), + }, + }), + internalError: () => ({ + status: 500, + message: "An Internal Server Error has occured...", + error: "InternalServerError", + successful: false, + meta: { + timestamp: Date.now(), + }, + }), + zodError: (err: ZodError) => { + const data = JSON.parse(err.message); + return { + status: 400, + message: "TypeError", + error: data, + successful: false, + meta: { + timestamp: Date.now(), + }, + }; + }, +}; diff --git a/src/modules/api-utils/createRoute.ts b/src/modules/api-utils/createRoute.ts new file mode 100644 index 0000000..0a80dc5 --- /dev/null +++ b/src/modules/api-utils/createRoute.ts @@ -0,0 +1,40 @@ +import { Handler, Hono, MiddlewareHandler } from "hono"; +import { Variables } from "../../types/HonoTypes"; + +/** + * Create a route. + * + * This method exists to serve the purpose of allowing us to split all of our api routes into different files and + * easily and quickly be able to rope them back into the main api server instance. + * + * One of the sortfallings of this method is that I was not able to figure out how to integrate the middleware to come + * before the handler, so if somebody feels upto it please figure out a way to have the middleware come before the handler + * method naturally as you would if you using a plain hono method. + * + * @TODO Move middleware handlers to come before primary handler naturally. + * + * @param method - HTTP Method + * @param path - URL Path + * @param handler - Handler function for Hono + * @param middleware - Array of Middleware Handlers for Hono + * @returns {Hono} - A new Hono instance containing the newly created route. + */ +export function createRoute( + method: string | string[], + path: string[], + handler: Handler<{ + Variables: Variables; + }>, + ...middleware: MiddlewareHandler<{ + Variables: Variables; + }>[] +): Hono<{ Variables: Variables }> { + if (middleware) + return new Hono<{ Variables: Variables }>().on( + method as any, + path, + ...middleware, + handler + ); + return new Hono<{ Variables: Variables }>().on(method as any, path, handler); +} diff --git a/src/modules/globalEvents.ts b/src/modules/globalEvents.ts new file mode 100644 index 0000000..cb6a695 --- /dev/null +++ b/src/modules/globalEvents.ts @@ -0,0 +1,64 @@ +import { Eventra } from "@duxcore/eventra"; +import UserController from "../controllers/UserController"; +import { + SessionController, + SessionTokensObject, +} from "../controllers/SessionController"; +import { RoleController } from "../controllers/RoleController"; +import { JsonWebTokenError } from "jsonwebtoken"; +import { User } from "../../generated/prisma/client"; + +interface EventTypes { + "api:started": () => void; + "user:created": (user: UserController) => void; + "user:updated": (data: { + user: UserController; + updatedValues: Partial; + }) => void; + "user:authenticated": (data: { + user: UserController; + tokens: SessionTokensObject; + }) => void; + "session:created": (data: { + user: UserController; + session: SessionController; + }) => void; + "session:tokens_generated": (data: { + session: SessionController; + tokens: SessionTokensObject; + }) => void; + "session:token_refresh": (data: { + session: SessionController; + tokens: SessionTokensObject; + }) => void; + "session:invalidated": (session: SessionController) => void; + "session:terminated": (session: SessionController) => void; + "role:created": (role: RoleController) => void; + "role:deleted": (role: RoleController) => void; + "role:updated": (data: { + role: RoleController; + updateData: Parameters["0"]; + }) => void; + "role:permissions:updated": (data: { + previous: string[]; + previousSigned: string; + current: string[]; + currentSigned: string; + action: "set" | "added" | "removed"; + role: RoleController; + }) => void; + "role:permissions:verification_error": (data: { + currentSigned: string; + attemptedVerification: string; + err: Error; + role: RoleController; + }) => void; +} + +export const events = new Eventra(); + +export function setupEventDebugger() { + events.any((eventName, ...args) => { + console.log(`[ Event Debugger ] (${eventName})`); + }); +} \ No newline at end of file diff --git a/src/modules/permission-utils/checkImplicitPerm.ts b/src/modules/permission-utils/checkImplicitPerm.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/permission-utils/genImplicitPerm.ts b/src/modules/permission-utils/genImplicitPerm.ts new file mode 100644 index 0000000..14b8efd --- /dev/null +++ b/src/modules/permission-utils/genImplicitPerm.ts @@ -0,0 +1,9 @@ +export function genImplicitPerm( + resource: string, + resourceId: string, + userId: string +) { + return ["resource", resource, resourceId, "user", userId, "implicit"].join( + "." + ); +} diff --git a/src/modules/permission-utils/permissionValidator.ts b/src/modules/permission-utils/permissionValidator.ts new file mode 100644 index 0000000..9855d34 --- /dev/null +++ b/src/modules/permission-utils/permissionValidator.ts @@ -0,0 +1,53 @@ +/** + * Permission Validator + * + * This method is used for validaing user and role permissions. This method is given a single or and array + * of permission nodes that the user has and it is also given the permission node that is required for whatever + * query they are trying to execute, and this will determine if any of the permission nodes match or will + * verify the given permission node. + * + * Special token types: + * - Asterisk (*): verifies it's token and all following tokens. + * - Question Mark (?): verifies it's token and only it's token. + * - Inclusive List ([a,b,c]): verifies only the tokens in the list. + * - Exclusive List (): verifies all tokens except for the ones in the list. + * + * @param permission - The required permission + * @param permissionExpressions - The owned permission(s) + * @returns {boolean} Does the user have the permission? + */ +export function permissionValidator( + permission: string, + permissionExpressions: string | string[] +): boolean { + if (typeof permissionExpressions === "string") { + // If the second parameter is a string, treat it as a single expression + permissionExpressions = [permissionExpressions]; + } + + // Iterate over each expression in the array and check if any of them match the permission + for (const expression of permissionExpressions) { + const rx = expression + .replace(/\./g, "\\.") + .replace(/\*/g, ".*") + .replace(/\?/g, ".") + .replace(/\[([^\]\[]*)\]/g, "($1)") + .replace(/<([^<>]+)>/g, "(?:(?!$1)[^.])*") + .replace(/,/g, "|"); + + if (new RegExp(`^${rx}$`).test(permission)) { + return true; + } + } + + return false; +} + +/** + * @TODO It's okay, you can't always get everything done and that is fine. + * Just take a breath and move on, come back if you feel upto it. + * What you make is good and whilst you can always do more, + * you can't do everything. Nothing will ever be perfect, + * so stop trying to be perfect and allow your self to move on + * even if you know there is more you can do. + */ diff --git a/src/modules/permission-utils/signPermissions.ts b/src/modules/permission-utils/signPermissions.ts new file mode 100644 index 0000000..4e813d6 --- /dev/null +++ b/src/modules/permission-utils/signPermissions.ts @@ -0,0 +1,24 @@ +import jwt from "jsonwebtoken"; +import { permissionsPrivateKey } from "../../constants"; +import { PermissionIssuers } from "../../types/PermissionTypes"; + +/** + * Sign Permissions + * + * This will sign the array of permissions with the private key for permissions, and then return + * a JWT which will be stored in the databse. + * + * @param permissions - All the permissions to be signed + * @returns {string} - The signed permissions object + */ +export function signPermissions(data: { + issuer: PermissionIssuers; + subject: string; + permissions: string[]; +}) { + return jwt.sign({ permissions: data.permissions }, permissionsPrivateKey, { + algorithm: "RS256", + issuer: data.issuer, + subject: data.subject, + }); +} diff --git a/src/modules/tools/Password.ts b/src/modules/tools/Password.ts new file mode 100644 index 0000000..50e91d0 --- /dev/null +++ b/src/modules/tools/Password.ts @@ -0,0 +1,34 @@ +import { blake2sHex } from "blakets"; +import crypto from "crypto"; + +export default class Password { + public static generateSalt(options?: GenerateSaltOptions): string { + const length = options?.length ?? 12; + const randomBytes = crypto.randomBytes(Math.ceil(length / 2)); + return randomBytes.toString("hex").slice(0, length); + } + + public static hash(password: string, options?: HashPasswordOptions): string { + const salt = + options?.overrideSalt ?? Password.generateSalt(options?.saltOpts); + const hash = blake2sHex(`$BLAKE2s$${password}$${salt}`); + return `BLAKE2s$${hash}$${salt}`; + } + + public static validate(newPass: string, hashed: string): boolean { + const [algo, oldHash, salt] = hashed.split(/\$/g); + return crypto.timingSafeEqual( + Buffer.from(hashed), + Buffer.from(Password.hash(newPass, { overrideSalt: salt })) + ); + } +} + +export interface HashPasswordOptions { + overrideSalt?: string; + saltOpts?: GenerateSaltOptions; +} + +export interface GenerateSaltOptions { + length?: number; // default 12 +} diff --git a/src/modules/tools/mergeArrays.ts b/src/modules/tools/mergeArrays.ts new file mode 100644 index 0000000..89e667e --- /dev/null +++ b/src/modules/tools/mergeArrays.ts @@ -0,0 +1,8 @@ +export const mergeArrays = (a, b, predicate = (a, b) => a === b) => { + const c = [...a]; // copy to avoid side effects + // add all items from B to copy C if they're not already present + b.forEach((bItem) => + c.some((cItem) => predicate(bItem, cItem)) ? null : c.push(bItem) + ); + return c; +}; diff --git a/src/types/HonoTypes.ts b/src/types/HonoTypes.ts new file mode 100644 index 0000000..8cc1ec4 --- /dev/null +++ b/src/types/HonoTypes.ts @@ -0,0 +1,3 @@ +export type Variables = { + foo: "bar" +}; diff --git a/src/types/PermissionTypes.ts b/src/types/PermissionTypes.ts new file mode 100644 index 0000000..6f0191d --- /dev/null +++ b/src/types/PermissionTypes.ts @@ -0,0 +1,7 @@ +export type PermissionIssuers = "roles" | "user" | "api_key"; +export interface DecodedPermissionsBlock { + permissions: string[]; + iat: number; // Issued at + iss: PermissionIssuers; // Issuer + sub: string; // Subject +} diff --git a/tsconfig.json b/tsconfig.json index bfa0fea..d23842c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,7 @@ // Bundler mode "moduleResolution": "bundler", "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, + "verbatimModuleSyntax": false, "noEmit": true, // Best practices diff --git a/utils/genPrivateKeys.ts b/utils/genPrivateKeys.ts new file mode 100644 index 0000000..aa1b559 --- /dev/null +++ b/utils/genPrivateKeys.ts @@ -0,0 +1,37 @@ +import keypair from "keypair"; + +console.log(` +Generating Private Keys +----------------- +This script will go through and genrate all the keys necessary for running the Credential Manager API locally. +This process might take several minutes. +-----------------`); + +await Promise.all( + [ + ".accessToken.key", + ".refreshToken.key", + ".permissions.key", + ".apiKeyToken.key", + ].map(async (v) => { + if ( + await Bun.file(v) + .exists() + .then((bool) => { + if (bool) { + console.log(`'${v}' already exists`); + return false; + } + return true; + }) + ) { + console.log(`Generating '${v}'...`); + const keys = keypair({ bits: 4096 }); + + await Bun.write(v, keys.private); + } + return; + }) +); + +console.log("\nGenerated All Keys Successfully!"); From 1bf0acdf3909159b950c98b93d486be4fdcfe426 Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Sun, 25 Jan 2026 15:01:13 -0600 Subject: [PATCH 05/73] Do not include dev pgsql nor redis data. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index be0d1ce..56fe0a6 100644 --- a/.gitignore +++ b/.gitignore @@ -144,3 +144,6 @@ vite.config.ts.timestamp-* .accessToken.key microsoft-oauth.json + +.docker/postgres +.docker/redis From e76caa68f15078e244f90edb49dfc57760c7cdf0 Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Sun, 25 Jan 2026 15:03:17 -0600 Subject: [PATCH 06/73] User Authentication Flow Works --- .docker/docker-compose.yml | 17 +-- bun.lock | 12 +++ generated/prisma/commonInputTypes.ts | 54 ---------- generated/prisma/internal/class.ts | 4 +- generated/prisma/internal/prismaNamespace.ts | 14 --- generated/prisma/models/User.ts | 102 +++++------------- package.json | 2 + .../migrations/20260125205653/migration.sql | 76 +++++++++++++ prisma/migrations/migration_lock.toml | 3 + prisma/schema.prisma | 2 +- src/api/.gitignore | 5 - src/api/auth/redirect.ts | 36 +++++++ src/api/prisma.config.ts | 12 --- src/api/server.ts | 1 + src/constants.ts | 38 ++++--- src/controllers/UserController.ts | 21 +--- src/managers/roles.ts | 18 ++-- src/managers/sessions.ts | 2 - src/managers/users.ts | 51 ++++----- src/modules/fetchMicrosoftUser.ts | 33 ++++++ src/types/MSAuthTypes.ts | 14 +++ tsconfig.json | 6 +- 22 files changed, 275 insertions(+), 248 deletions(-) create mode 100644 prisma/migrations/20260125205653/migration.sql create mode 100644 prisma/migrations/migration_lock.toml delete mode 100644 src/api/.gitignore create mode 100644 src/api/auth/redirect.ts delete mode 100644 src/api/prisma.config.ts create mode 100644 src/modules/fetchMicrosoftUser.ts create mode 100644 src/types/MSAuthTypes.ts diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml index 1ac86aa..541011b 100644 --- a/.docker/docker-compose.yml +++ b/.docker/docker-compose.yml @@ -2,27 +2,16 @@ version: "3" services: pgsql: - image: postgres + image: postgres:17 restart: unless-stopped environment: - POSTGRES_USER: duxcore + POSTGRES_USER: ttscm POSTGRES_PASSWORD: 123web123 - POSTGRES_DB: duxcore + POSTGRES_DB: ttscm volumes: - ./postgres:/var/lib/postgresql/data ports: - 5432:5432 - pgsql-boss: - image: postgres - restart: unless-stopped - environment: - POSTGRES_USER: pg-boss - POSTGRES_PASSWORD: 123web123 - POSTGRES_DB: pg-boss - volumes: - - ./postgres-pgb:/var/lib/postgresql/data - ports: - - 2345:5432 redis: image: redis:6.2-alpine diff --git a/bun.lock b/bun.lock index 064769a..473143e 100644 --- a/bun.lock +++ b/bun.lock @@ -5,9 +5,11 @@ "": { "name": "ttscm-api", "dependencies": { + "@azure/msal-node": "^5.0.2", "@discordjs/collection": "^2.1.1", "@duxcore/eventra": "^1.1.0", "@prisma/adapter-pg": "^7.3.0", + "@prisma/client": "^7.3.0", "cors": "^2.8.6", "cuid": "^3.0.0", "hono": "^4.11.5", @@ -27,6 +29,10 @@ }, }, "packages": { + "@azure/msal-common": ["@azure/msal-common@16.0.2", "", {}, "sha512-ZJ/UR7lyqIntURrIJCyvScwJFanM9QhJYcJCheB21jZofGKpP9QxWgvADANo7UkresHKzV+6YwoeZYP7P7HvUg=="], + + "@azure/msal-node": ["@azure/msal-node@5.0.2", "", { "dependencies": { "@azure/msal-common": "16.0.2", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" } }, "sha512-3tHeJghckgpTX98TowJoXOjKGuds0L+FKfeHJtoZFl2xvwE6RF65shZJzMQ5EQZWXzh3sE1i9gE+m3aRMachjA=="], + "@chevrotain/cst-dts-gen": ["@chevrotain/cst-dts-gen@10.5.0", "", { "dependencies": { "@chevrotain/gast": "10.5.0", "@chevrotain/types": "10.5.0", "lodash": "4.17.21" } }, "sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw=="], "@chevrotain/gast": ["@chevrotain/gast@10.5.0", "", { "dependencies": { "@chevrotain/types": "10.5.0", "lodash": "4.17.21" } }, "sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A=="], @@ -51,6 +57,10 @@ "@prisma/adapter-pg": ["@prisma/adapter-pg@7.3.0", "", { "dependencies": { "@prisma/driver-adapter-utils": "7.3.0", "pg": "^8.16.3", "postgres-array": "3.0.4" } }, "sha512-iuYQMbIPO6i9O45Fv8TB7vWu00BXhCaNAShenqF7gLExGDbnGp5BfFB4yz1K59zQ59jF6tQ9YHrg0P6/J3OoLg=="], + "@prisma/client": ["@prisma/client@7.3.0", "", { "dependencies": { "@prisma/client-runtime-utils": "7.3.0" }, "peerDependencies": { "prisma": "*", "typescript": ">=5.4.0" }, "optionalPeers": ["prisma", "typescript"] }, "sha512-FXBIxirqQfdC6b6HnNgxGmU7ydCPEPk7maHMOduJJfnTP+MuOGa15X4omjR/zpPUUpm8ef/mEFQjJudOGkXFcQ=="], + + "@prisma/client-runtime-utils": ["@prisma/client-runtime-utils@7.3.0", "", {}, "sha512-dG/ceD9c+tnXATPk8G+USxxYM9E6UdMTnQeQ+1SZUDxTz7SgQcfxEqafqIQHcjdlcNK/pvmmLfSwAs3s2gYwUw=="], + "@prisma/config": ["@prisma/config@7.3.0", "", { "dependencies": { "c12": "3.1.0", "deepmerge-ts": "7.1.5", "effect": "3.18.4", "empathic": "2.0.0" } }, "sha512-QyMV67+eXF7uMtKxTEeQqNu/Be7iH+3iDZOQZW5ttfbSwBamCSdwPszA0dum+Wx27I7anYTPLmRmMORKViSW1A=="], "@prisma/debug": ["@prisma/debug@7.3.0", "", {}, "sha512-yh/tHhraCzYkffsI1/3a7SHX8tpgbJu1NPnuxS4rEpJdWAUDHUH25F1EDo6PPzirpyLNkgPPZdhojQK804BGtg=="], @@ -281,6 +291,8 @@ "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + "valibot": ["valibot@1.2.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg=="], "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], diff --git a/generated/prisma/commonInputTypes.ts b/generated/prisma/commonInputTypes.ts index 2da8eda..feb939f 100644 --- a/generated/prisma/commonInputTypes.ts +++ b/generated/prisma/commonInputTypes.ts @@ -130,17 +130,6 @@ export type StringNullableFilter<$PrismaModel = never> = { not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null } -export type IntFilter<$PrismaModel = never> = { - equals?: number | Prisma.IntFieldRefInput<$PrismaModel> - in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> - notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> - lt?: number | Prisma.IntFieldRefInput<$PrismaModel> - lte?: number | Prisma.IntFieldRefInput<$PrismaModel> - gt?: number | Prisma.IntFieldRefInput<$PrismaModel> - gte?: number | Prisma.IntFieldRefInput<$PrismaModel> - not?: Prisma.NestedIntFilter<$PrismaModel> | number -} - export type StringNullableWithAggregatesFilter<$PrismaModel = never> = { equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null @@ -159,22 +148,6 @@ export type StringNullableWithAggregatesFilter<$PrismaModel = never> = { _max?: Prisma.NestedStringNullableFilter<$PrismaModel> } -export type IntWithAggregatesFilter<$PrismaModel = never> = { - equals?: number | Prisma.IntFieldRefInput<$PrismaModel> - in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> - notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> - lt?: number | Prisma.IntFieldRefInput<$PrismaModel> - lte?: number | Prisma.IntFieldRefInput<$PrismaModel> - gt?: number | Prisma.IntFieldRefInput<$PrismaModel> - gte?: number | Prisma.IntFieldRefInput<$PrismaModel> - not?: Prisma.NestedIntWithAggregatesFilter<$PrismaModel> | number - _count?: Prisma.NestedIntFilter<$PrismaModel> - _avg?: Prisma.NestedFloatFilter<$PrismaModel> - _sum?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedIntFilter<$PrismaModel> - _max?: Prisma.NestedIntFilter<$PrismaModel> -} - export type NestedStringFilter<$PrismaModel = never> = { equals?: string | Prisma.StringFieldRefInput<$PrismaModel> in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> @@ -322,31 +295,4 @@ export type NestedStringNullableWithAggregatesFilter<$PrismaModel = never> = { _max?: Prisma.NestedStringNullableFilter<$PrismaModel> } -export type NestedIntWithAggregatesFilter<$PrismaModel = never> = { - equals?: number | Prisma.IntFieldRefInput<$PrismaModel> - in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> - notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> - lt?: number | Prisma.IntFieldRefInput<$PrismaModel> - lte?: number | Prisma.IntFieldRefInput<$PrismaModel> - gt?: number | Prisma.IntFieldRefInput<$PrismaModel> - gte?: number | Prisma.IntFieldRefInput<$PrismaModel> - not?: Prisma.NestedIntWithAggregatesFilter<$PrismaModel> | number - _count?: Prisma.NestedIntFilter<$PrismaModel> - _avg?: Prisma.NestedFloatFilter<$PrismaModel> - _sum?: Prisma.NestedIntFilter<$PrismaModel> - _min?: Prisma.NestedIntFilter<$PrismaModel> - _max?: Prisma.NestedIntFilter<$PrismaModel> -} - -export type NestedFloatFilter<$PrismaModel = never> = { - equals?: number | Prisma.FloatFieldRefInput<$PrismaModel> - in?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> - notIn?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> - lt?: number | Prisma.FloatFieldRefInput<$PrismaModel> - lte?: number | Prisma.FloatFieldRefInput<$PrismaModel> - gt?: number | Prisma.FloatFieldRefInput<$PrismaModel> - gte?: number | Prisma.FloatFieldRefInput<$PrismaModel> - not?: Prisma.NestedFloatFilter<$PrismaModel> | number -} - diff --git a/generated/prisma/internal/class.ts b/generated/prisma/internal/class.ts index f9cf156..9cce4d3 100644 --- a/generated/prisma/internal/class.ts +++ b/generated/prisma/internal/class.ts @@ -20,7 +20,7 @@ const config: runtime.GetPrismaClientConfig = { "clientVersion": "7.3.0", "engineVersion": "9d6ad21cbbceab97458517b147a6a09ff43aa735", "activeProvider": "postgresql", - "inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel Session {\n id String @id @default(uuid())\n sessionKey String @unique @default(cuid())\n userId String\n expires DateTime\n refreshTokenGenerated Boolean @default(false)\n refreshedAt DateTime?\n invalidatedAt DateTime?\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n}\n\nmodel User {\n id String @id @default(cuid())\n roles Role[]\n permissions String?\n login String @unique\n name String?\n email String @unique\n emailVerified DateTime?\n image String?\n\n userId Int @unique\n token String?\n\n sessions Session[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel Role {\n id String @id @default(uuid())\n title String\n moniker String @unique // e.g. admin, super_admin, moderator\n\n permissions String\n users User[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n", + "inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel Session {\n id String @id @default(uuid())\n sessionKey String @unique @default(cuid())\n userId String\n expires DateTime\n refreshTokenGenerated Boolean @default(false)\n refreshedAt DateTime?\n invalidatedAt DateTime?\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n}\n\nmodel User {\n id String @id @default(cuid())\n roles Role[]\n permissions String?\n login String @unique\n name String?\n email String @unique\n emailVerified DateTime?\n image String?\n\n userId String @unique\n token String?\n\n sessions Session[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel Role {\n id String @id @default(uuid())\n title String\n moniker String @unique // e.g. admin, super_admin, moderator\n\n permissions String\n users User[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n", "runtimeDataModel": { "models": {}, "enums": {}, @@ -28,7 +28,7 @@ const config: runtime.GetPrismaClientConfig = { } } -config.runtimeDataModel = JSON.parse("{\"models\":{\"Session\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessionKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"expires\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"refreshTokenGenerated\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"refreshedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"invalidatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"SessionToUser\"}],\"dbName\":null},\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"roles\",\"kind\":\"object\",\"type\":\"Role\",\"relationName\":\"RoleToUser\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"login\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"emailVerified\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"image\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"token\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessions\",\"kind\":\"object\",\"type\":\"Session\",\"relationName\":\"SessionToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Role\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"moniker\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"users\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"RoleToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") +config.runtimeDataModel = JSON.parse("{\"models\":{\"Session\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessionKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"expires\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"refreshTokenGenerated\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"refreshedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"invalidatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"SessionToUser\"}],\"dbName\":null},\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"roles\",\"kind\":\"object\",\"type\":\"Role\",\"relationName\":\"RoleToUser\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"login\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"emailVerified\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"image\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"token\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessions\",\"kind\":\"object\",\"type\":\"Session\",\"relationName\":\"SessionToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Role\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"moniker\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"users\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"RoleToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") async function decodeBase64AsWasm(wasmBase64: string): Promise { const { Buffer } = await import('node:buffer') diff --git a/generated/prisma/internal/prismaNamespace.ts b/generated/prisma/internal/prismaNamespace.ts index 9bf4a22..6fdc93d 100644 --- a/generated/prisma/internal/prismaNamespace.ts +++ b/generated/prisma/internal/prismaNamespace.ts @@ -787,20 +787,6 @@ export type IntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'In export type ListIntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Int[]'> - -/** - * Reference to a field of type 'Float' - */ -export type FloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float'> - - - -/** - * Reference to a field of type 'Float[]' - */ -export type ListFloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float[]'> - - /** * Batch Payload for updateMany & deleteMany & createMany */ diff --git a/generated/prisma/models/User.ts b/generated/prisma/models/User.ts index e3a66e2..7f38da9 100644 --- a/generated/prisma/models/User.ts +++ b/generated/prisma/models/User.ts @@ -20,20 +20,10 @@ export type UserModel = runtime.Types.Result.DefaultSelection | string emailVerified?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null image?: Prisma.StringNullableFilter<"User"> | string | null - userId?: Prisma.IntFilter<"User"> | number + userId?: Prisma.StringFilter<"User"> | string token?: Prisma.StringNullableFilter<"User"> | string | null createdAt?: Prisma.DateTimeFilter<"User"> | Date | string updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string @@ -288,7 +254,7 @@ export type UserWhereUniqueInput = Prisma.AtLeast<{ id?: string login?: string email?: string - userId?: number + userId?: string AND?: Prisma.UserWhereInput | Prisma.UserWhereInput[] OR?: Prisma.UserWhereInput[] NOT?: Prisma.UserWhereInput | Prisma.UserWhereInput[] @@ -316,10 +282,8 @@ export type UserOrderByWithAggregationInput = { createdAt?: Prisma.SortOrder updatedAt?: Prisma.SortOrder _count?: Prisma.UserCountOrderByAggregateInput - _avg?: Prisma.UserAvgOrderByAggregateInput _max?: Prisma.UserMaxOrderByAggregateInput _min?: Prisma.UserMinOrderByAggregateInput - _sum?: Prisma.UserSumOrderByAggregateInput } export type UserScalarWhereWithAggregatesInput = { @@ -333,7 +297,7 @@ export type UserScalarWhereWithAggregatesInput = { email?: Prisma.StringWithAggregatesFilter<"User"> | string emailVerified?: Prisma.DateTimeNullableWithAggregatesFilter<"User"> | Date | string | null image?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null - userId?: Prisma.IntWithAggregatesFilter<"User"> | number + userId?: Prisma.StringWithAggregatesFilter<"User"> | string token?: Prisma.StringNullableWithAggregatesFilter<"User"> | string | null createdAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string updatedAt?: Prisma.DateTimeWithAggregatesFilter<"User"> | Date | string @@ -347,7 +311,7 @@ export type UserCreateInput = { email: string emailVerified?: Date | string | null image?: string | null - userId: number + userId: string token?: string | null createdAt?: Date | string updatedAt?: Date | string @@ -363,7 +327,7 @@ export type UserUncheckedCreateInput = { email: string emailVerified?: Date | string | null image?: string | null - userId: number + userId: string token?: string | null createdAt?: Date | string updatedAt?: Date | string @@ -379,7 +343,7 @@ export type UserUpdateInput = { email?: Prisma.StringFieldUpdateOperationsInput | string emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - userId?: Prisma.IntFieldUpdateOperationsInput | number + userId?: Prisma.StringFieldUpdateOperationsInput | string token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string @@ -395,7 +359,7 @@ export type UserUncheckedUpdateInput = { email?: Prisma.StringFieldUpdateOperationsInput | string emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - userId?: Prisma.IntFieldUpdateOperationsInput | number + userId?: Prisma.StringFieldUpdateOperationsInput | string token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string @@ -411,7 +375,7 @@ export type UserCreateManyInput = { email: string emailVerified?: Date | string | null image?: string | null - userId: number + userId: string token?: string | null createdAt?: Date | string updatedAt?: Date | string @@ -425,7 +389,7 @@ export type UserUpdateManyMutationInput = { email?: Prisma.StringFieldUpdateOperationsInput | string emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - userId?: Prisma.IntFieldUpdateOperationsInput | number + userId?: Prisma.StringFieldUpdateOperationsInput | string token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string @@ -439,7 +403,7 @@ export type UserUncheckedUpdateManyInput = { email?: Prisma.StringFieldUpdateOperationsInput | string emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - userId?: Prisma.IntFieldUpdateOperationsInput | number + userId?: Prisma.StringFieldUpdateOperationsInput | string token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string @@ -464,10 +428,6 @@ export type UserCountOrderByAggregateInput = { updatedAt?: Prisma.SortOrder } -export type UserAvgOrderByAggregateInput = { - userId?: Prisma.SortOrder -} - export type UserMaxOrderByAggregateInput = { id?: Prisma.SortOrder permissions?: Prisma.SortOrder @@ -496,10 +456,6 @@ export type UserMinOrderByAggregateInput = { updatedAt?: Prisma.SortOrder } -export type UserSumOrderByAggregateInput = { - userId?: Prisma.SortOrder -} - export type UserListRelationFilter = { every?: Prisma.UserWhereInput some?: Prisma.UserWhereInput @@ -528,14 +484,6 @@ export type NullableStringFieldUpdateOperationsInput = { set?: string | null } -export type IntFieldUpdateOperationsInput = { - set?: number - increment?: number - decrement?: number - multiply?: number - divide?: number -} - export type UserCreateNestedManyWithoutRolesInput = { create?: Prisma.XOR | Prisma.UserCreateWithoutRolesInput[] | Prisma.UserUncheckedCreateWithoutRolesInput[] connectOrCreate?: Prisma.UserCreateOrConnectWithoutRolesInput | Prisma.UserCreateOrConnectWithoutRolesInput[] @@ -582,7 +530,7 @@ export type UserCreateWithoutSessionsInput = { email: string emailVerified?: Date | string | null image?: string | null - userId: number + userId: string token?: string | null createdAt?: Date | string updatedAt?: Date | string @@ -597,7 +545,7 @@ export type UserUncheckedCreateWithoutSessionsInput = { email: string emailVerified?: Date | string | null image?: string | null - userId: number + userId: string token?: string | null createdAt?: Date | string updatedAt?: Date | string @@ -628,7 +576,7 @@ export type UserUpdateWithoutSessionsInput = { email?: Prisma.StringFieldUpdateOperationsInput | string emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - userId?: Prisma.IntFieldUpdateOperationsInput | number + userId?: Prisma.StringFieldUpdateOperationsInput | string token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string @@ -643,7 +591,7 @@ export type UserUncheckedUpdateWithoutSessionsInput = { email?: Prisma.StringFieldUpdateOperationsInput | string emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - userId?: Prisma.IntFieldUpdateOperationsInput | number + userId?: Prisma.StringFieldUpdateOperationsInput | string token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string @@ -658,7 +606,7 @@ export type UserCreateWithoutRolesInput = { email: string emailVerified?: Date | string | null image?: string | null - userId: number + userId: string token?: string | null createdAt?: Date | string updatedAt?: Date | string @@ -673,7 +621,7 @@ export type UserUncheckedCreateWithoutRolesInput = { email: string emailVerified?: Date | string | null image?: string | null - userId: number + userId: string token?: string | null createdAt?: Date | string updatedAt?: Date | string @@ -712,7 +660,7 @@ export type UserScalarWhereInput = { email?: Prisma.StringFilter<"User"> | string emailVerified?: Prisma.DateTimeNullableFilter<"User"> | Date | string | null image?: Prisma.StringNullableFilter<"User"> | string | null - userId?: Prisma.IntFilter<"User"> | number + userId?: Prisma.StringFilter<"User"> | string token?: Prisma.StringNullableFilter<"User"> | string | null createdAt?: Prisma.DateTimeFilter<"User"> | Date | string updatedAt?: Prisma.DateTimeFilter<"User"> | Date | string @@ -726,7 +674,7 @@ export type UserUpdateWithoutRolesInput = { email?: Prisma.StringFieldUpdateOperationsInput | string emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - userId?: Prisma.IntFieldUpdateOperationsInput | number + userId?: Prisma.StringFieldUpdateOperationsInput | string token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string @@ -741,7 +689,7 @@ export type UserUncheckedUpdateWithoutRolesInput = { email?: Prisma.StringFieldUpdateOperationsInput | string emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - userId?: Prisma.IntFieldUpdateOperationsInput | number + userId?: Prisma.StringFieldUpdateOperationsInput | string token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string @@ -756,7 +704,7 @@ export type UserUncheckedUpdateManyWithoutRolesInput = { email?: Prisma.StringFieldUpdateOperationsInput | string emailVerified?: Prisma.NullableDateTimeFieldUpdateOperationsInput | Date | string | null image?: Prisma.NullableStringFieldUpdateOperationsInput | string | null - userId?: Prisma.IntFieldUpdateOperationsInput | number + userId?: Prisma.StringFieldUpdateOperationsInput | string token?: Prisma.NullableStringFieldUpdateOperationsInput | string | null createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string @@ -884,7 +832,7 @@ export type $UserPayload readonly emailVerified: Prisma.FieldRef<"User", 'DateTime'> readonly image: Prisma.FieldRef<"User", 'String'> - readonly userId: Prisma.FieldRef<"User", 'Int'> + readonly userId: Prisma.FieldRef<"User", 'String'> readonly token: Prisma.FieldRef<"User", 'String'> readonly createdAt: Prisma.FieldRef<"User", 'DateTime'> readonly updatedAt: Prisma.FieldRef<"User", 'DateTime'> diff --git a/package.json b/package.json index 595cc18..7e727de 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,11 @@ "utils:gen_private_keys": "bun ./utils/genPrivateKeys" }, "dependencies": { + "@azure/msal-node": "^5.0.2", "@discordjs/collection": "^2.1.1", "@duxcore/eventra": "^1.1.0", "@prisma/adapter-pg": "^7.3.0", + "@prisma/client": "^7.3.0", "cors": "^2.8.6", "cuid": "^3.0.0", "hono": "^4.11.5", diff --git a/prisma/migrations/20260125205653/migration.sql b/prisma/migrations/20260125205653/migration.sql new file mode 100644 index 0000000..87b80bd --- /dev/null +++ b/prisma/migrations/20260125205653/migration.sql @@ -0,0 +1,76 @@ +-- CreateTable +CREATE TABLE "Session" ( + "id" TEXT NOT NULL, + "sessionKey" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "expires" TIMESTAMP(3) NOT NULL, + "refreshTokenGenerated" BOOLEAN NOT NULL DEFAULT false, + "refreshedAt" TIMESTAMP(3), + "invalidatedAt" TIMESTAMP(3), + + CONSTRAINT "Session_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "User" ( + "id" TEXT NOT NULL, + "permissions" TEXT, + "login" TEXT NOT NULL, + "name" TEXT, + "email" TEXT NOT NULL, + "emailVerified" TIMESTAMP(3), + "image" TEXT, + "userId" TEXT NOT NULL, + "token" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Role" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "moniker" TEXT NOT NULL, + "permissions" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Role_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "_RoleToUser" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL, + + CONSTRAINT "_RoleToUser_AB_pkey" PRIMARY KEY ("A","B") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Session_sessionKey_key" ON "Session"("sessionKey"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_login_key" ON "User"("login"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_userId_key" ON "User"("userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Role_moniker_key" ON "Role"("moniker"); + +-- CreateIndex +CREATE INDEX "_RoleToUser_B_index" ON "_RoleToUser"("B"); + +-- AddForeignKey +ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_RoleToUser" ADD CONSTRAINT "_RoleToUser_A_fkey" FOREIGN KEY ("A") REFERENCES "Role"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_RoleToUser" ADD CONSTRAINT "_RoleToUser_B_fkey" FOREIGN KEY ("B") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..044d57c --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (e.g., Git) +provider = "postgresql" diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 092ebc4..37a11be 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -34,7 +34,7 @@ model User { emailVerified DateTime? image String? - userId Int @unique + userId String @unique token String? sessions Session[] diff --git a/src/api/.gitignore b/src/api/.gitignore deleted file mode 100644 index 9f62ec0..0000000 --- a/src/api/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -# Keep environment variables out of version control -.env - -/generated/prisma diff --git a/src/api/auth/redirect.ts b/src/api/auth/redirect.ts new file mode 100644 index 0000000..bebac0b --- /dev/null +++ b/src/api/auth/redirect.ts @@ -0,0 +1,36 @@ +import { Hono } from "hono/tiny"; +import { createRoute } from "../../modules/api-utils/createRoute"; +import * as msal from "@azure/msal-node"; +import { msalClient } from "../../constants"; +import { users } from "../../managers/users"; + +/* /v1/authRedirect */ +export default createRoute("get", ["/"], async (c) => { + c.status(200); + + console.log("Query", c.req.query()); + + const tokenRequest: msal.AuthorizationCodeRequest = { + code: c.req.query().code as string, + scopes: ["user.read"], + redirectUri: "http://localhost:3000/v1/auth/redirect", + }; + + const authResult = await msalClient.acquireTokenByCode(tokenRequest); + + await users.authenticate(authResult); + + // This closes the window because duh + return c.html(` + + `); + + /* return c.json({ + status: 200, + message: "Auth Redirect Endpoint", + data: authResult, + successful: true, + }); */ +}); diff --git a/src/api/prisma.config.ts b/src/api/prisma.config.ts deleted file mode 100644 index d5ecde5..0000000 --- a/src/api/prisma.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -// This file was generated by Prisma, and assumes you run Prisma commands using `bun --bun run prisma [command]`. -import { defineConfig, env } from "prisma/config"; - -export default defineConfig({ - schema: "prisma/schema.prisma", - migrations: { - path: "prisma/migrations", - }, - datasource: { - url: env("DATABASE_URL"), - }, -}); diff --git a/src/api/server.ts b/src/api/server.ts index 015e506..48f69e8 100644 --- a/src/api/server.ts +++ b/src/api/server.ts @@ -47,6 +47,7 @@ app.notFound((c) => { }); v1.route("/teapot", teapot); +v1.route("/auth/redirect", await import("./auth/redirect").then(m => m.default)); app.route("/v1", v1); diff --git a/src/constants.ts b/src/constants.ts index 78c8670..73149c4 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,34 +1,46 @@ import { readFileSync } from "fs"; -import { PrismaPg } from '@prisma/adapter-pg' -import { PrismaClient } from '../generated/prisma/client' - -const connectionString = `${process.env.DATABASE_URL}` -const adapter = new PrismaPg({ connectionString }) +import { PrismaPg } from "@prisma/adapter-pg"; +import { Prisma, PrismaClient } from "../generated/prisma/client"; +import * as msal from "@azure/msal-node"; +const connectionString = `${process.env.DATABASE_URL}`; +const adapter = new PrismaPg({ connectionString }); interface EnvKey { - PORT: number; -}; + PORT: number; +} // ENV CONSTANTS export const PORT = process.env.PORT; -export const prisma = new PrismaClient({ adapter }) +export const prisma = new PrismaClient({ adapter }); export const sessionDuration = 30 * 24 * 60 * 60000; export const accessTokenDuration = "10min"; export const refreshTokenDuration = "30d"; export const accessTokenPrivateKey = readFileSync( - `${import.meta.dir}/../.accessToken.key` + `${import.meta.dir}/../.accessToken.key`, ).toString(); export const refreshTokenPrivateKey = readFileSync( - `${import.meta.dir}/../.refreshToken.key` + `${import.meta.dir}/../.refreshToken.key`, ).toString(); export const permissionsPrivateKey = readFileSync( - `${import.meta.dir}/../.permissions.key` + `${import.meta.dir}/../.permissions.key`, ); export const apiKeyTokenPrivateKey = readFileSync( - `${import.meta.dir}/../.apiKeyToken.key` -); \ No newline at end of file + `${import.meta.dir}/../.apiKeyToken.key`, +); + +// Microsoft Auth Constants +const msalConfig: msal.Configuration = { + auth: { + clientId: process.env.MICROSOFT_CLIENT_ID!, + authority: `https://login.microsoftonline.com/${process.env.MICROSOFT_TENANT_ID!}`, + clientSecret: process.env.MICROSOFT_CLIENT_SECRET!, + }, +}; + +// MSAL Client Instance +export const msalClient = new msal.ConfidentialClientApplication(msalConfig); diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index d4d4276..93a9a12 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -10,8 +10,6 @@ import { events } from "../modules/globalEvents"; import { RoleController } from "./RoleController"; import { roles } from "../managers/roles"; - - export default class UserController { public id: string; public name: string | null; @@ -116,8 +114,8 @@ export default class UserController { await Promise.all( this._roles.map(async (v) => - collection.set(v.id, await roles.fetch(v.id)) - ) + collection.set(v.id, await roles.fetch(v.id)), + ), ); return collection; @@ -140,15 +138,6 @@ export default class UserController { sessions: { select: { id: true }, }, - apiKeys: { - select: { id: true }, - }, - projects: { - select: { id: true }, - }, - services: { - select: { id: true }, - }, }, }); @@ -158,7 +147,7 @@ export default class UserController { (v) => `resource.${v}.[${(resources![v] as { id: string }[]) .map((o) => o.id) - .join(",")}].user.${this.id}.implicit` + .join(",")}].user.${this.id}.implicit`, ); console.log(implicitPermissions); @@ -190,8 +179,8 @@ export default class UserController { roles: opts?.safeReturn ? undefined : this._roles.size > 0 - ? this._roles.map((v) => v.moniker) - : undefined, + ? this._roles.map((v) => v.moniker) + : undefined, login: opts?.safeReturn ? undefined : this.login, email: opts?.safeReturn ? undefined : this.email, image: this.image, diff --git a/src/managers/roles.ts b/src/managers/roles.ts index 8dd3c72..d1d609f 100644 --- a/src/managers/roles.ts +++ b/src/managers/roles.ts @@ -38,7 +38,7 @@ export const roles = { if (checkMoniker) throw new RoleError( "Moniker is already taken.", - "Another role with this moniker already exists in the databse." + "Another role with this moniker already exists in the databse.", ); const id = cuid(); @@ -76,7 +76,7 @@ export const roles = { * @param identifier - Options for fetching a role. * @returns {RoleController} - Role Controller */ - async fetch(identifier:string, opt?: { requestingUser?: UserController }) { + async fetch(identifier: string, opt?: { requestingUser?: UserController }) { const roleData = await prisma.role.findFirst({ where: { OR: [{ id: identifier }, { moniker: identifier }] }, include: { @@ -98,11 +98,11 @@ export const roles = { if ( opt?.requestingUser && !(await opt.requestingUser.hasPermission( - this._buildPermissionNode(roleData.id, "read") + this._buildPermissionNode(roleData.id, "read"), )) ) throw new InsufficientPermission( - "You do not have permission to access this role." + "You do not have permission to access this role.", ); const controller = new RoleController(roleData); @@ -123,20 +123,20 @@ export const roles = { include: { users: { include: { roles: true } } }, }); - roles. map((v:any) => collection.set(v.id, new RoleController(v))); + roles.map((v: any) => collection.set(v.id, new RoleController(v))); if (opt?.requestingUser) { const permittedRoles = await Promise.all( collection.map(async (v) => (await opt.requestingUser?.hasPermission( - this._buildPermissionNode(v.id, "read") + this._buildPermissionNode(v.id, "read"), )) ? v.id - : null - ) + : null, + ), ); collection = collection.filter((v) => - permittedRoles.filter((x) => x !== null).includes(v.id) + permittedRoles.filter((x) => x !== null).includes(v.id), ); } diff --git a/src/managers/sessions.ts b/src/managers/sessions.ts index 9817554..d4808cb 100644 --- a/src/managers/sessions.ts +++ b/src/managers/sessions.ts @@ -1,8 +1,6 @@ import { prisma, - refreshTokenDuration, sessionDuration, - accessTokenDuration, accessTokenPrivateKey, refreshTokenPrivateKey, } from "../constants"; diff --git a/src/managers/users.ts b/src/managers/users.ts index 53617ef..1928d9a 100644 --- a/src/managers/users.ts +++ b/src/managers/users.ts @@ -1,7 +1,12 @@ +import { ms } from "zod/locales"; import { User } from "../../generated/prisma/client"; import { prisma } from "../constants"; import { SessionTokensObject } from "../controllers/SessionController"; import UserController from "../controllers/UserController"; +import { fetchMicrosoftUser } from "../modules/fetchMicrosoftUser"; +import { events } from "../modules/globalEvents"; +import { sessions } from "./sessions"; +import * as msal from "@azure/msal-node"; export const users = { /** @@ -13,25 +18,22 @@ export const users = { * @summary It creates a user if one doesn't exist and will supply a session id * * @async - * @param ghCode - The code supplied in the callback url of a GitHub oAuth transaction + * @param authRequest - The code supplied in the callback url of the Microsoft oAuth transaction */ -/* async authenticate(ghCode: string): Promise { - const token = await ghApp.oauth.createToken({ code: ghCode }).catch((e) => { - throw new AuthenticationError("Invalid OAuth code..."); - }); - const userOK = await ghApp.oauth.getUserOctokit({ - token: token.authentication.token, - }); - const ghUser = await userOK.request("GET /user"); + async authenticate( + authRequest: msal.AuthenticationResult, + ): Promise { + let id = authRequest.uniqueId as string; + let user = - (await this.fetchUser({ userId: ghUser.data.id })) ?? - (await this.createUser(token.authentication.token)); + (await this.fetchUser({ userId: id })) ?? + (await this.createUser(authRequest.accessToken)); const tokens = await sessions.create({ user }); events.emit("user:authenticated", { user, tokens }); return tokens; - }, */ + }, /** * Check to see if the user exists @@ -59,8 +61,8 @@ export const users = { id: string; email: string; login: string; - userId: number; - }> + userId: string; + }>, ) { if (Object.keys(identifier).length == 0) return null; const userData = await prisma.user.findFirst({ @@ -79,28 +81,21 @@ export const users = { /** * Create a new user * - * This method will poll GitHub and get all the information on the user to then create the + * This method will poll Microsoft and get all the information on the user to then create the * record in our database. On top of that it also pushes it into the user cache. * - * @param token - The Github token provided by the auth method + * @param token - The Microsoft token provided by the auth method * @returns {Promise} The new user controller for the user */ async createUser(token: string): Promise { - const ghUser = await ( - await ghApp.oauth.getUserOctokit({ token }) - ).request("GET /user"); - - const emails = await ( - await ghApp.oauth.getUserOctokit({ token }) - ).request("GET /user/emails"); + const msData = await fetchMicrosoftUser(token); const newUser = await prisma.user.create({ data: { - userId: ghUser.data.id, - email: emails.data[0].email, - image: ghUser.data.avatar_url, - name: ghUser.data.name, - login: ghUser.data.login, + userId: msData.id, + email: msData.mail, + name: `${msData.givenName} ${msData.surname}`, + login: msData.userPrincipalName, token, }, include: { roles: true }, diff --git a/src/modules/fetchMicrosoftUser.ts b/src/modules/fetchMicrosoftUser.ts new file mode 100644 index 0000000..24181db --- /dev/null +++ b/src/modules/fetchMicrosoftUser.ts @@ -0,0 +1,33 @@ +import { MicrosoftGraphUser } from "../types/MSAuthTypes"; + +/** + * Fetch Microsoft User + * + * This function fetches user data from Microsoft Graph API using the provided access token. + * It makes a GET request to the `/me` endpoint and returns the user data in JSON format. + * + * @param accessToken - This is the access token provided by Microsoft. + * @returns - Raw API Data from Microsoft. + */ +export const fetchMicrosoftUser = async ( + accessToken: string, +): Promise => { + const graphEndpoint = "https://graph.microsoft.com/v1.0/me"; + + const response = await fetch(graphEndpoint, { + method: "GET", + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }); + + if (!response.ok) { + throw new Error( + `Graph request failed: ${response.status} ${response.statusText}`, + ); + } + + const data = (await response.json()) as MicrosoftGraphUser; + + return data; +}; diff --git a/src/types/MSAuthTypes.ts b/src/types/MSAuthTypes.ts new file mode 100644 index 0000000..4d8671d --- /dev/null +++ b/src/types/MSAuthTypes.ts @@ -0,0 +1,14 @@ +export interface MicrosoftGraphUser { + "@odata.context": string; + businessPhones: string[]; + displayName: string; + givenName: string; + jobTitle: string | null; + mail: string; + mobilePhone: string | null; + officeLocation: string | null; + preferredLanguage: string | null; + surname: string; + userPrincipalName: string; + id: string; +} diff --git a/tsconfig.json b/tsconfig.json index d23842c..eff676a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,6 +24,10 @@ // Some stricter flags (disabled by default) "noUnusedLocals": false, "noUnusedParameters": false, - "noPropertyAccessFromIndexSignature": false + "noPropertyAccessFromIndexSignature": false, + + "paths": { + "@prisma/client": ["./generated/prisma"] + } } } From d96f18e6cf97df2ce6f55cce7138cdfd8cd13ce3 Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Sun, 25 Jan 2026 15:09:55 -0600 Subject: [PATCH 07/73] Fixed UserController errors --- src/controllers/RoleController.ts | 10 +++++----- src/controllers/UserController.ts | 24 +++++++++++++++--------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/controllers/RoleController.ts b/src/controllers/RoleController.ts index f52c1c0..8d20752 100644 --- a/src/controllers/RoleController.ts +++ b/src/controllers/RoleController.ts @@ -78,7 +78,7 @@ export class RoleController { }); throw new PermissionsVerificationError( `Unable to verify permissions for role '${this.title}, it is recommended that you override and rewrite these permissions immediately.`, - (err as Error).message + (err as Error).message, ); } @@ -248,14 +248,14 @@ export class RoleController { title: string; moniker: string; permissions: string[]; - }> + }>, ) { const schema = z .object({ title: z.string().min(1, "Title cannot be empty."), moniker: z.string().min(1, "Moniker cannot be empty."), permissions: z.array( - z.string().min(1, "Permission node cannot be empty") + z.string().min(1, "Permission node cannot be empty"), ), }) .partial() @@ -271,7 +271,7 @@ export class RoleController { if (checkMoniker) throw new RoleError( "Moniker is already taken.", - "Another role with this moniker already exists in the databse." + "Another role with this moniker already exists in the databse.", ); } @@ -326,7 +326,7 @@ export class RoleController { id: v.id, name: v.name, login: v.login, - roles: v.roles.map((r:any) => r.id), + roles: v.roles.map((r: any) => r.id), })) : undefined, createdAt: this.createdAt, diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 93a9a12..683c79c 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -141,16 +141,22 @@ export default class UserController { }, }); - const implicitPermissions = Object.keys(resources ?? {}) - .filter((v) => resources![v].length > 0) - .map( - (v) => - `resource.${v}.[${(resources![v] as { id: string }[]) - .map((o) => o.id) - .join(",")}].user.${this.id}.implicit`, - ); + const resourceKeys: string[] = Object.keys(resources ?? {}) as string[]; - console.log(implicitPermissions); + const implicitPermissions = resources + ? resourceKeys + // @ts-ignore + .filter((v) => resources[v].length > 0) + .map( + (v) => + //@ts-ignore + `resource.${v}.[${(resources![v] as { id: string }[]) + .map((o) => o.id) + .join(",")}].user.${this.id}.implicit`, + ) + : []; + + // console.log(implicitPermissions); let checks = [ (await this.fetchRoles()).map((v) => v.checkPermission(permission)), From 8ee7dc15e572347e3c459997b72350d2e217a578 Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Sun, 25 Jan 2026 16:53:18 -0600 Subject: [PATCH 08/73] Got Authorization flow working (Untested) --- bun.lock | 34 ++++++++++++ package.json | 2 + src/api/auth/redirect.ts | 23 +++------ src/api/auth/refresh.ts | 26 ++++++++++ src/api/middleware/authorization.ts | 80 +++++++++++++++++++++++++++++ src/constants.ts | 10 ++++ src/index.ts | 16 ++++-- src/types/HonoTypes.ts | 4 +- 8 files changed, 174 insertions(+), 21 deletions(-) create mode 100644 src/api/auth/refresh.ts create mode 100644 src/api/middleware/authorization.ts diff --git a/bun.lock b/bun.lock index 473143e..6500d50 100644 --- a/bun.lock +++ b/bun.lock @@ -10,12 +10,14 @@ "@duxcore/eventra": "^1.1.0", "@prisma/adapter-pg": "^7.3.0", "@prisma/client": "^7.3.0", + "@socket.io/bun-engine": "^0.1.0", "cors": "^2.8.6", "cuid": "^3.0.0", "hono": "^4.11.5", "jsonwebtoken": "^9.0.3", "keypair": "^1.0.4", "prisma": "^7.3.0", + "socket.io": "^4.8.3", "zod": "^4.3.6", "zon": "^1.0.3", }, @@ -81,10 +83,16 @@ "@prisma/studio-core": ["@prisma/studio-core@0.13.1", "", { "peerDependencies": { "@types/react": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" } }, "sha512-agdqaPEePRHcQ7CexEfkX1RvSH9uWDb6pXrZnhCRykhDFAV0/0P3d07WtfiY8hZWb7oRU4v+NkT4cGFHkQJIPg=="], + "@socket.io/bun-engine": ["@socket.io/bun-engine@0.1.0", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-B1z6GuAxZlfvjgaa3BHZBOfqHJNfnpebTw15p+Un1HuBL4YM7wUxO9sJa7K4NDTe7XbUBeqLIwTDA5tOOjffog=="], + + "@socket.io/component-emitter": ["@socket.io/component-emitter@3.1.2", "", {}, "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="], + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], "@types/bun": ["@types/bun@1.3.6", "", { "dependencies": { "bun-types": "1.3.6" } }, "sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA=="], + "@types/cors": ["@types/cors@2.8.19", "", { "dependencies": { "@types/node": "*" } }, "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg=="], + "@types/jsonwebtoken": ["@types/jsonwebtoken@9.0.10", "", { "dependencies": { "@types/ms": "*", "@types/node": "*" } }, "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA=="], "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], @@ -93,8 +101,12 @@ "@types/react": ["@types/react@19.2.9", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-Lpo8kgb/igvMIPeNV2rsYKTgaORYdO1XGVZ4Qz3akwOj0ySGYMPlQWa8BaLn0G63D1aSaAQ5ldR06wCpChQCjA=="], + "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], + "aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="], + "base64id": ["base64id@2.0.0", "", {}, "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="], + "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], "bun-types": ["bun-types@1.3.6", "", { "dependencies": { "@types/node": "*" } }, "sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ=="], @@ -111,6 +123,8 @@ "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + "cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="], "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], @@ -119,6 +133,8 @@ "cuid": ["cuid@3.0.0", "", {}, "sha512-WZYYkHdIDnaxdeP8Misq3Lah5vFjJwGuItJuV+tvMafosMzw0nF297T7mrm8IOWiPJkV6gc7sa8pzx27+w25Zg=="], + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "deepmerge-ts": ["deepmerge-ts@7.1.5", "", {}, "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw=="], "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], @@ -135,6 +151,10 @@ "empathic": ["empathic@2.0.0", "", {}, "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA=="], + "engine.io": ["engine.io@6.6.5", "", { "dependencies": { "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", "cookie": "~0.7.2", "cors": "~2.8.5", "debug": "~4.4.1", "engine.io-parser": "~5.2.1", "ws": "~8.18.3" } }, "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A=="], + + "engine.io-parser": ["engine.io-parser@5.2.3", "", {}, "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="], + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="], @@ -195,12 +215,18 @@ "lru.min": ["lru.min@1.1.3", "", {}, "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q=="], + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "mysql2": ["mysql2@3.15.3", "", { "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.7.0", "long": "^5.2.1", "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg=="], "named-placeholders": ["named-placeholders@1.1.6", "", { "dependencies": { "lru.min": "^1.1.0" } }, "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w=="], + "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], + "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], "nypm": ["nypm@0.6.4", "", { "dependencies": { "citty": "^0.2.0", "pathe": "^2.0.3", "tinyexec": "^1.0.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-1TvCKjZyyklN+JJj2TS3P4uSQEInrM/HkkuSXsEzm1ApPgBffOn8gFguNnZf07r/1X6vlryfIqMUkJKQMzlZiw=="], @@ -279,6 +305,12 @@ "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "socket.io": ["socket.io@4.8.3", "", { "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.4.1", "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" } }, "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A=="], + + "socket.io-adapter": ["socket.io-adapter@2.5.6", "", { "dependencies": { "debug": "~4.4.1", "ws": "~8.18.3" } }, "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ=="], + + "socket.io-parser": ["socket.io-parser@4.2.5", "", { "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" } }, "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ=="], + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], "sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="], @@ -299,6 +331,8 @@ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], "zeptomatch": ["zeptomatch@2.1.0", "", { "dependencies": { "grammex": "^3.1.11", "graphmatch": "^1.1.0" } }, "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA=="], diff --git a/package.json b/package.json index 7e727de..dfb0424 100644 --- a/package.json +++ b/package.json @@ -29,12 +29,14 @@ "@duxcore/eventra": "^1.1.0", "@prisma/adapter-pg": "^7.3.0", "@prisma/client": "^7.3.0", + "@socket.io/bun-engine": "^0.1.0", "cors": "^2.8.6", "cuid": "^3.0.0", "hono": "^4.11.5", "jsonwebtoken": "^9.0.3", "keypair": "^1.0.4", "prisma": "^7.3.0", + "socket.io": "^4.8.3", "zod": "^4.3.6", "zon": "^1.0.3" } diff --git a/src/api/auth/redirect.ts b/src/api/auth/redirect.ts index bebac0b..0dd539b 100644 --- a/src/api/auth/redirect.ts +++ b/src/api/auth/redirect.ts @@ -4,12 +4,10 @@ import * as msal from "@azure/msal-node"; import { msalClient } from "../../constants"; import { users } from "../../managers/users"; -/* /v1/authRedirect */ +/* /v1/auth/redirect */ export default createRoute("get", ["/"], async (c) => { c.status(200); - console.log("Query", c.req.query()); - const tokenRequest: msal.AuthorizationCodeRequest = { code: c.req.query().code as string, scopes: ["user.read"], @@ -20,17 +18,10 @@ export default createRoute("get", ["/"], async (c) => { await users.authenticate(authResult); - // This closes the window because duh - return c.html(` - - `); - - /* return c.json({ - status: 200, - message: "Auth Redirect Endpoint", - data: authResult, - successful: true, - }); */ + return c.json({ + status: 200, + message: "Auth Redirect Endpoint", + data: authResult, + successful: true, + }); }); diff --git a/src/api/auth/refresh.ts b/src/api/auth/refresh.ts new file mode 100644 index 0000000..6a32f1a --- /dev/null +++ b/src/api/auth/refresh.ts @@ -0,0 +1,26 @@ +import { Hono } from "hono/tiny"; +import { createRoute } from "../../modules/api-utils/createRoute"; +import { sessions } from "../../managers/sessions"; + +/* /v1/auth/refresh */ +export default createRoute("post", ["/"], async (c) => { + c.status(201); + + const refreshToken = c.req.header("x-refresh-token") || ""; + + const session = await sessions.fetch({ + refreshToken: refreshToken, + }); + + const newAccessToken = await session.refresh(refreshToken); + + return c.json({ + status: 201, + message: "Token refreshed successfully!", + data: { + accessToken: newAccessToken, + refreshToken, + }, + successful: true, + }); +}); diff --git a/src/api/middleware/authorization.ts b/src/api/middleware/authorization.ts new file mode 100644 index 0000000..22a9153 --- /dev/null +++ b/src/api/middleware/authorization.ts @@ -0,0 +1,80 @@ +import { Context, Env, MiddlewareHandler } from "hono"; +import AuthorizationError from "../../Errors/AuthorizationError"; +import { sessions } from "../../managers/sessions"; +import { Variables } from "../../types/HonoTypes"; +import GenericError from "../../Errors/GenericError"; +import { events } from "../../modules/globalEvents"; + +/** + * Authorization Middleware + * + * This middleware will do all of the authorization for all the routes that may need authorization. + * It will check which auth type is being used and pull the correct credentials from said auth type and + * supply them as a variable to the route. If there is an error thrown at any point in this middleware, it + * will hault and will not proceed to the route handler. + * + * Eventually this method will analyze roles and permissions and supply those as objects to the route handler. + * + * ## Auth Types + * - Bearer: Access Token for user authentication + * - Key: API Key + * + * @param ctx - Hono Context Object + * @param next - Move onto the handler + */ +export const authMiddleware = (permParams?: { + permissions?: string[]; + scopes?: string[]; + forbiddenAuthTypes?: string[]; +}): MiddlewareHandler<{ + Variables: Variables; +}> => { + return async (ctx, next) => { + const authorization = ctx.req.header()["authorization"]; + if (!authorization) + throw new AuthorizationError("Missing 'authorization' header."); + + const components = authorization.match( + /^(Bearer|Key)\s([a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+)$/, + ); + if (!components) + throw new AuthorizationError( + "Invalid or malformed authorization header...", + ); + + const authType: string = components[1] ?? ""; + const authValue: string = components[2] ?? ""; + + if (permParams?.forbiddenAuthTypes?.includes(authType)) + throw new GenericError({ + name: "NonpermittedAuthType", + message: + "The authorization method you are using is not permitted for this API request.", + cause: `Type '${authType}' is not permitted.`, + status: 403, + }); + + if (authType) { + const session = await sessions.fetch({ accessToken: authValue }); + const user = await session.fetchUser(); + ctx.set("user", user); + + if ( + permParams?.permissions && + permParams?.permissions.length > 0 && + ( + await Promise.all( + permParams?.permissions.map((p) => user.hasPermission(p)), + ) + ).includes(false) + ) + throw new GenericError({ + name: "InsufficentPermission", + message: "You do not have sufficent permissions to do this.", + status: 403, + }); + } + + await next(); + }; +}; diff --git a/src/constants.ts b/src/constants.ts index 73149c4..cd8a3f0 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -2,6 +2,8 @@ import { readFileSync } from "fs"; import { PrismaPg } from "@prisma/adapter-pg"; import { Prisma, PrismaClient } from "../generated/prisma/client"; import * as msal from "@azure/msal-node"; +import { Server } from "socket.io"; +import { Server as Engine } from "@socket.io/bun-engine"; const connectionString = `${process.env.DATABASE_URL}`; const adapter = new PrismaPg({ connectionString }); @@ -44,3 +46,11 @@ const msalConfig: msal.Configuration = { // MSAL Client Instance export const msalClient = new msal.ConfidentialClientApplication(msalConfig); + +// Socket.io + +const io = new Server(); +const engine = new Engine(); + +io.bind(engine); +export { io, engine }; diff --git a/src/index.ts b/src/index.ts index d40f9ae..e05c0f5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,15 @@ import app from "./api/server"; -import { PORT } from "./constants"; +import { engine, PORT } from "./constants"; Bun.serve({ - port: PORT, - fetch: app.fetch -}); \ No newline at end of file + port: PORT, + fetch: (req, server) => { + const url = new URL(req.url); + + if (url.pathname.startsWith("/socket.io/")) { + return engine.handleRequest(req, server as any); + } + + return app.fetch(req, server); + }, +}); diff --git a/src/types/HonoTypes.ts b/src/types/HonoTypes.ts index 8cc1ec4..57c865c 100644 --- a/src/types/HonoTypes.ts +++ b/src/types/HonoTypes.ts @@ -1,3 +1,5 @@ +import UserController from "../controllers/UserController"; + export type Variables = { - foo: "bar" + user: UserController; }; From 4524c0258a1b4f2b21ebac9a55b1353911e11b6b Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Mon, 26 Jan 2026 15:56:10 -0600 Subject: [PATCH 09/73] Working User Authorization Flow --- src/api/auth/index.ts | 3 +++ src/api/auth/redirect.ts | 20 +++++++++++++++++--- src/api/auth/refresh.ts | 4 +++- src/api/auth/uri.ts | 21 +++++++++++++++++++++ src/api/routers/authRouter.ts | 7 +++++++ src/api/server.ts | 9 ++++----- src/constants.ts | 1 + src/index.ts | 1 + 8 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 src/api/auth/index.ts create mode 100644 src/api/auth/uri.ts create mode 100644 src/api/routers/authRouter.ts diff --git a/src/api/auth/index.ts b/src/api/auth/index.ts new file mode 100644 index 0000000..613953a --- /dev/null +++ b/src/api/auth/index.ts @@ -0,0 +1,3 @@ +export { default as redirect } from "./redirect"; +export { default as refresh } from "./refresh"; +export { default as uri } from "./uri"; diff --git a/src/api/auth/redirect.ts b/src/api/auth/redirect.ts index 0dd539b..0906382 100644 --- a/src/api/auth/redirect.ts +++ b/src/api/auth/redirect.ts @@ -1,11 +1,11 @@ import { Hono } from "hono/tiny"; import { createRoute } from "../../modules/api-utils/createRoute"; import * as msal from "@azure/msal-node"; -import { msalClient } from "../../constants"; +import { io, msalClient } from "../../constants"; import { users } from "../../managers/users"; /* /v1/auth/redirect */ -export default createRoute("get", ["/"], async (c) => { +export default createRoute("get", ["/redirect"], async (c) => { c.status(200); const tokenRequest: msal.AuthorizationCodeRequest = { @@ -15,8 +15,22 @@ export default createRoute("get", ["/"], async (c) => { }; const authResult = await msalClient.acquireTokenByCode(tokenRequest); + const callbackKey = c.req.query().state as string; + const tokens = await users.authenticate(authResult); - await users.authenticate(authResult); + io.of(`/auth_callback`).emit(`auth:login:callback:${callbackKey}`, { + accessToken: tokens.accessToken, + refreshToken: tokens.refreshToken, + }); + + console.log("Emitted auth callback for key:", callbackKey); + + // Close the window because duh + return c.html( + ``, + ); return c.json({ status: 200, diff --git a/src/api/auth/refresh.ts b/src/api/auth/refresh.ts index 6a32f1a..b2a5fde 100644 --- a/src/api/auth/refresh.ts +++ b/src/api/auth/refresh.ts @@ -3,11 +3,13 @@ import { createRoute } from "../../modules/api-utils/createRoute"; import { sessions } from "../../managers/sessions"; /* /v1/auth/refresh */ -export default createRoute("post", ["/"], async (c) => { +export default createRoute("post", ["/refresh"], async (c) => { c.status(201); const refreshToken = c.req.header("x-refresh-token") || ""; + console.log("Received refresh token:", refreshToken); + const session = await sessions.fetch({ refreshToken: refreshToken, }); diff --git a/src/api/auth/uri.ts b/src/api/auth/uri.ts new file mode 100644 index 0000000..ea55cf8 --- /dev/null +++ b/src/api/auth/uri.ts @@ -0,0 +1,21 @@ +import { Hono } from "hono/tiny"; +import { createRoute } from "../../modules/api-utils/createRoute"; +import cuid from "cuid"; + +/* /v1/auth/uri */ +export default createRoute("get", ["/uri"], (c) => { + c.status(200); + + const callbackKey = cuid(); + const msUri = `https://login.microsoftonline.com/${process.env.MICROSOFT_TENANT_ID}/oauth2/v2.0/authorize?client_id=${process.env.MICROSOFT_CLIENT_ID}&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fv1%2Fauth%2Fredirect&scope=openid+User.Read&state=${callbackKey}&prompt=login`; + + return c.json({ + status: 200, + message: "Successfully fetch Auth URI", + data: { + uri: msUri, + callbackKey: callbackKey, + }, + successful: true, + }); +}); diff --git a/src/api/routers/authRouter.ts b/src/api/routers/authRouter.ts new file mode 100644 index 0000000..735008e --- /dev/null +++ b/src/api/routers/authRouter.ts @@ -0,0 +1,7 @@ +import { Hono } from "hono"; +import * as authRoles from "../auth"; + +const authRouter = new Hono(); +Object.values(authRoles).map((r) => authRouter.route("/", r)); + +export default authRouter; diff --git a/src/api/server.ts b/src/api/server.ts index 48f69e8..95d6982 100644 --- a/src/api/server.ts +++ b/src/api/server.ts @@ -24,7 +24,7 @@ app.onError((err, ctx) => { return ctx.json( apiResponse.zodError(err), //@ts-ignore - apiResponse.zodError(err).status + apiResponse.zodError(err).status, ); } @@ -41,14 +41,13 @@ app.notFound((c) => { message: `Cannot ${c.req.method.toUpperCase()} ${c.req.path}`, status: 404, cause: "Unknown", - }) + }), ); return c.json(response, response.status); }); v1.route("/teapot", teapot); -v1.route("/auth/redirect", await import("./auth/redirect").then(m => m.default)); - +v1.route("/auth", require("./routers/authRouter").default); app.route("/v1", v1); -export default app; \ No newline at end of file +export default app; diff --git a/src/constants.ts b/src/constants.ts index cd8a3f0..0c7e775 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -50,6 +50,7 @@ export const msalClient = new msal.ConfidentialClientApplication(msalConfig); // Socket.io const io = new Server(); +const authIO = io.of("/auth_callback"); const engine = new Engine(); io.bind(engine); diff --git a/src/index.ts b/src/index.ts index e05c0f5..01d7f15 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,6 +3,7 @@ import { engine, PORT } from "./constants"; Bun.serve({ port: PORT, + websocket: engine.handler().websocket, fetch: (req, server) => { const url = new URL(req.url); From 7748e6171b0cf3d4cee4bb619f25e62eecb37fba Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Mon, 26 Jan 2026 17:09:18 -0600 Subject: [PATCH 10/73] Added Connectwise Compnay Syncing --- bun.lock | 43 + generated/prisma/browser.ts | 5 + generated/prisma/client.ts | 5 + generated/prisma/commonInputTypes.ts | 54 + generated/prisma/internal/class.ts | 14 +- generated/prisma/internal/prismaNamespace.ts | 106 +- .../prisma/internal/prismaNamespaceBrowser.ts | 15 +- generated/prisma/models.ts | 1 + generated/prisma/models/Company.ts | 1224 +++++++++++++++++ package.json | 5 +- prisma/schema.prisma | 15 +- src/constants.ts | 14 + src/index.ts | 10 + src/modules/cw-utils/fetchAllCompanies.ts | 27 + src/modules/cw-utils/refreshCompanies.ts | 40 + src/modules/globalEvents.ts | 7 +- src/types/ConnectWiseTypes.ts | 139 ++ utils/assignUserRole.ts | 41 + utils/createAdminRole.ts | 27 + 19 files changed, 1783 insertions(+), 9 deletions(-) create mode 100644 generated/prisma/models/Company.ts create mode 100644 src/modules/cw-utils/fetchAllCompanies.ts create mode 100644 src/modules/cw-utils/refreshCompanies.ts create mode 100644 src/types/ConnectWiseTypes.ts create mode 100644 utils/assignUserRole.ts create mode 100644 utils/createAdminRole.ts diff --git a/bun.lock b/bun.lock index 6500d50..b57b2f7 100644 --- a/bun.lock +++ b/bun.lock @@ -11,6 +11,7 @@ "@prisma/adapter-pg": "^7.3.0", "@prisma/client": "^7.3.0", "@socket.io/bun-engine": "^0.1.0", + "axios": "^1.13.3", "cors": "^2.8.6", "cuid": "^3.0.0", "hono": "^4.11.5", @@ -103,8 +104,12 @@ "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + "aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="], + "axios": ["axios@1.13.3", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-ERT8kdX7DZjtUm7IitEyV7InTHAF42iJuMArIiDIV5YtPanJkgw4hw5Dyg9fh0mihdWNn1GKaeIWErfe56UQ1g=="], + "base64id": ["base64id@2.0.0", "", {}, "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="], "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], @@ -113,12 +118,16 @@ "c12": ["c12@3.1.0", "", { "dependencies": { "chokidar": "^4.0.3", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^16.6.1", "exsolve": "^1.0.7", "giget": "^2.0.0", "jiti": "^2.4.2", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^1.0.0", "pkg-types": "^2.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.5" }, "optionalPeers": ["magicast"] }, "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw=="], + "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=="], + "chevrotain": ["chevrotain@10.5.0", "", { "dependencies": { "@chevrotain/cst-dts-gen": "10.5.0", "@chevrotain/gast": "10.5.0", "@chevrotain/types": "10.5.0", "@chevrotain/utils": "10.5.0", "lodash": "4.17.21", "regexp-to-ast": "0.5.0" } }, "sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A=="], "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], + "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], + "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], @@ -139,12 +148,16 @@ "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + "denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="], "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + "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=="], + "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], "effect": ["effect@3.18.4", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA=="], @@ -155,24 +168,50 @@ "engine.io-parser": ["engine.io-parser@5.2.3", "", {}, "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="], + "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=="], + + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="], + "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], + "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + "form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + "generate-function": ["generate-function@2.3.1", "", { "dependencies": { "is-property": "^1.0.2" } }, "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ=="], + "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-port-please": ["get-port-please@3.2.0", "", {}, "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A=="], + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + "giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], + "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=="], "grammex": ["grammex@3.1.12", "", {}, "sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ=="], "graphmatch": ["graphmatch@1.1.0", "", {}, "sha512-0E62MaTW5rPZVRLyIJZG/YejmdA/Xr1QydHEw3Vt+qOKkMIOE8WDLc9ZX2bmAjtJFZcId4lEdrdmASsEy7D1QA=="], + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "hono": ["hono@4.11.5", "", {}, "sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g=="], "http-status-codes": ["http-status-codes@2.3.0", "", {}, "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA=="], @@ -215,6 +254,8 @@ "lru.min": ["lru.min@1.1.3", "", {}, "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], @@ -273,6 +314,8 @@ "proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="], + "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], + "pure-rand": ["pure-rand@6.1.0", "", {}, "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA=="], "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], diff --git a/generated/prisma/browser.ts b/generated/prisma/browser.ts index cde1741..8c56a70 100644 --- a/generated/prisma/browser.ts +++ b/generated/prisma/browser.ts @@ -32,3 +32,8 @@ export type User = Prisma.UserModel * */ export type Role = Prisma.RoleModel +/** + * Model Company + * + */ +export type Company = Prisma.CompanyModel diff --git a/generated/prisma/client.ts b/generated/prisma/client.ts index d181956..140ed38 100644 --- a/generated/prisma/client.ts +++ b/generated/prisma/client.ts @@ -54,3 +54,8 @@ export type User = Prisma.UserModel * */ export type Role = Prisma.RoleModel +/** + * Model Company + * + */ +export type Company = Prisma.CompanyModel diff --git a/generated/prisma/commonInputTypes.ts b/generated/prisma/commonInputTypes.ts index feb939f..219894b 100644 --- a/generated/prisma/commonInputTypes.ts +++ b/generated/prisma/commonInputTypes.ts @@ -148,6 +148,33 @@ export type StringNullableWithAggregatesFilter<$PrismaModel = never> = { _max?: Prisma.NestedStringNullableFilter<$PrismaModel> } +export type IntFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntFilter<$PrismaModel> | number +} + +export type IntWithAggregatesFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntWithAggregatesFilter<$PrismaModel> | number + _count?: Prisma.NestedIntFilter<$PrismaModel> + _avg?: Prisma.NestedFloatFilter<$PrismaModel> + _sum?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedIntFilter<$PrismaModel> + _max?: Prisma.NestedIntFilter<$PrismaModel> +} + export type NestedStringFilter<$PrismaModel = never> = { equals?: string | Prisma.StringFieldRefInput<$PrismaModel> in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> @@ -295,4 +322,31 @@ export type NestedStringNullableWithAggregatesFilter<$PrismaModel = never> = { _max?: Prisma.NestedStringNullableFilter<$PrismaModel> } +export type NestedIntWithAggregatesFilter<$PrismaModel = never> = { + equals?: number | Prisma.IntFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> + lt?: number | Prisma.IntFieldRefInput<$PrismaModel> + lte?: number | Prisma.IntFieldRefInput<$PrismaModel> + gt?: number | Prisma.IntFieldRefInput<$PrismaModel> + gte?: number | Prisma.IntFieldRefInput<$PrismaModel> + not?: Prisma.NestedIntWithAggregatesFilter<$PrismaModel> | number + _count?: Prisma.NestedIntFilter<$PrismaModel> + _avg?: Prisma.NestedFloatFilter<$PrismaModel> + _sum?: Prisma.NestedIntFilter<$PrismaModel> + _min?: Prisma.NestedIntFilter<$PrismaModel> + _max?: Prisma.NestedIntFilter<$PrismaModel> +} + +export type NestedFloatFilter<$PrismaModel = never> = { + equals?: number | Prisma.FloatFieldRefInput<$PrismaModel> + in?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> + notIn?: number[] | Prisma.ListFloatFieldRefInput<$PrismaModel> + lt?: number | Prisma.FloatFieldRefInput<$PrismaModel> + lte?: number | Prisma.FloatFieldRefInput<$PrismaModel> + gt?: number | Prisma.FloatFieldRefInput<$PrismaModel> + gte?: number | Prisma.FloatFieldRefInput<$PrismaModel> + not?: Prisma.NestedFloatFilter<$PrismaModel> | number +} + diff --git a/generated/prisma/internal/class.ts b/generated/prisma/internal/class.ts index 9cce4d3..2f5176c 100644 --- a/generated/prisma/internal/class.ts +++ b/generated/prisma/internal/class.ts @@ -20,7 +20,7 @@ const config: runtime.GetPrismaClientConfig = { "clientVersion": "7.3.0", "engineVersion": "9d6ad21cbbceab97458517b147a6a09ff43aa735", "activeProvider": "postgresql", - "inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel Session {\n id String @id @default(uuid())\n sessionKey String @unique @default(cuid())\n userId String\n expires DateTime\n refreshTokenGenerated Boolean @default(false)\n refreshedAt DateTime?\n invalidatedAt DateTime?\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n}\n\nmodel User {\n id String @id @default(cuid())\n roles Role[]\n permissions String?\n login String @unique\n name String?\n email String @unique\n emailVerified DateTime?\n image String?\n\n userId String @unique\n token String?\n\n sessions Session[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel Role {\n id String @id @default(uuid())\n title String\n moniker String @unique // e.g. admin, super_admin, moderator\n\n permissions String\n users User[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n", + "inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel Session {\n id String @id @default(uuid())\n sessionKey String @unique @default(cuid())\n userId String\n expires DateTime\n refreshTokenGenerated Boolean @default(false)\n refreshedAt DateTime?\n invalidatedAt DateTime?\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n}\n\nmodel User {\n id String @id @default(cuid())\n roles Role[]\n permissions String?\n login String @unique\n name String?\n email String @unique\n emailVerified DateTime?\n image String?\n\n userId String @unique\n token String?\n\n sessions Session[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel Role {\n id String @id @default(uuid())\n title String\n moniker String @unique // e.g. admin, super_admin, moderator\n\n permissions String\n users User[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel Company {\n id String @id @default(cuid())\n name String\n\n cw_CompanyId Int @unique\n cw_Identifier String @unique\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n", "runtimeDataModel": { "models": {}, "enums": {}, @@ -28,7 +28,7 @@ const config: runtime.GetPrismaClientConfig = { } } -config.runtimeDataModel = JSON.parse("{\"models\":{\"Session\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessionKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"expires\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"refreshTokenGenerated\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"refreshedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"invalidatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"SessionToUser\"}],\"dbName\":null},\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"roles\",\"kind\":\"object\",\"type\":\"Role\",\"relationName\":\"RoleToUser\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"login\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"emailVerified\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"image\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"token\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessions\",\"kind\":\"object\",\"type\":\"Session\",\"relationName\":\"SessionToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Role\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"moniker\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"users\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"RoleToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") +config.runtimeDataModel = JSON.parse("{\"models\":{\"Session\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessionKey\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"expires\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"refreshTokenGenerated\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"refreshedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"invalidatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"SessionToUser\"}],\"dbName\":null},\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"roles\",\"kind\":\"object\",\"type\":\"Role\",\"relationName\":\"RoleToUser\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"login\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"emailVerified\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"image\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"token\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"sessions\",\"kind\":\"object\",\"type\":\"Session\",\"relationName\":\"SessionToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Role\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"title\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"moniker\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"permissions\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"users\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"RoleToUser\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null},\"Company\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"cw_CompanyId\",\"kind\":\"scalar\",\"type\":\"Int\"},{\"name\":\"cw_Identifier\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}") async function decodeBase64AsWasm(wasmBase64: string): Promise { const { Buffer } = await import('node:buffer') @@ -205,6 +205,16 @@ export interface PrismaClient< * ``` */ get role(): Prisma.RoleDelegate; + + /** + * `prisma.company`: Exposes CRUD operations for the **Company** model. + * Example usage: + * ```ts + * // Fetch zero or more Companies + * const companies = await prisma.company.findMany() + * ``` + */ + get company(): Prisma.CompanyDelegate; } export function getPrismaClientClass(): PrismaClientConstructor { diff --git a/generated/prisma/internal/prismaNamespace.ts b/generated/prisma/internal/prismaNamespace.ts index 6fdc93d..e55030e 100644 --- a/generated/prisma/internal/prismaNamespace.ts +++ b/generated/prisma/internal/prismaNamespace.ts @@ -386,7 +386,8 @@ type FieldRefInputType = Model extends never ? never : FieldRe export const ModelName = { Session: 'Session', User: 'User', - Role: 'Role' + Role: 'Role', + Company: 'Company' } as const export type ModelName = (typeof ModelName)[keyof typeof ModelName] @@ -402,7 +403,7 @@ export type TypeMap + fields: Prisma.CompanyFieldRefs + operations: { + findUnique: { + args: Prisma.CompanyFindUniqueArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findUniqueOrThrow: { + args: Prisma.CompanyFindUniqueOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findFirst: { + args: Prisma.CompanyFindFirstArgs + result: runtime.Types.Utils.PayloadToResult | null + } + findFirstOrThrow: { + args: Prisma.CompanyFindFirstOrThrowArgs + result: runtime.Types.Utils.PayloadToResult + } + findMany: { + args: Prisma.CompanyFindManyArgs + result: runtime.Types.Utils.PayloadToResult[] + } + create: { + args: Prisma.CompanyCreateArgs + result: runtime.Types.Utils.PayloadToResult + } + createMany: { + args: Prisma.CompanyCreateManyArgs + result: BatchPayload + } + createManyAndReturn: { + args: Prisma.CompanyCreateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + delete: { + args: Prisma.CompanyDeleteArgs + result: runtime.Types.Utils.PayloadToResult + } + update: { + args: Prisma.CompanyUpdateArgs + result: runtime.Types.Utils.PayloadToResult + } + deleteMany: { + args: Prisma.CompanyDeleteManyArgs + result: BatchPayload + } + updateMany: { + args: Prisma.CompanyUpdateManyArgs + result: BatchPayload + } + updateManyAndReturn: { + args: Prisma.CompanyUpdateManyAndReturnArgs + result: runtime.Types.Utils.PayloadToResult[] + } + upsert: { + args: Prisma.CompanyUpsertArgs + result: runtime.Types.Utils.PayloadToResult + } + aggregate: { + args: Prisma.CompanyAggregateArgs + result: runtime.Types.Utils.Optional + } + groupBy: { + args: Prisma.CompanyGroupByArgs + result: runtime.Types.Utils.Optional[] + } + count: { + args: Prisma.CompanyCountArgs + result: runtime.Types.Utils.Optional | number + } + } + } } } & { other: { @@ -709,6 +784,18 @@ export const RoleScalarFieldEnum = { export type RoleScalarFieldEnum = (typeof RoleScalarFieldEnum)[keyof typeof RoleScalarFieldEnum] +export const CompanyScalarFieldEnum = { + id: 'id', + name: 'name', + cw_CompanyId: 'cw_CompanyId', + cw_Identifier: 'cw_Identifier', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type CompanyScalarFieldEnum = (typeof CompanyScalarFieldEnum)[keyof typeof CompanyScalarFieldEnum] + + export const SortOrder = { asc: 'asc', desc: 'desc' @@ -787,6 +874,20 @@ export type IntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'In export type ListIntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Int[]'> + +/** + * Reference to a field of type 'Float' + */ +export type FloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float'> + + + +/** + * Reference to a field of type 'Float[]' + */ +export type ListFloatFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Float[]'> + + /** * Batch Payload for updateMany & deleteMany & createMany */ @@ -885,6 +986,7 @@ export type GlobalOmitConfig = { session?: Prisma.SessionOmit user?: Prisma.UserOmit role?: Prisma.RoleOmit + company?: Prisma.CompanyOmit } /* Types for Logging */ diff --git a/generated/prisma/internal/prismaNamespaceBrowser.ts b/generated/prisma/internal/prismaNamespaceBrowser.ts index 4be0826..b6b9521 100644 --- a/generated/prisma/internal/prismaNamespaceBrowser.ts +++ b/generated/prisma/internal/prismaNamespaceBrowser.ts @@ -53,7 +53,8 @@ export const AnyNull = runtime.AnyNull export const ModelName = { Session: 'Session', User: 'User', - Role: 'Role' + Role: 'Role', + Company: 'Company' } as const export type ModelName = (typeof ModelName)[keyof typeof ModelName] @@ -114,6 +115,18 @@ export const RoleScalarFieldEnum = { export type RoleScalarFieldEnum = (typeof RoleScalarFieldEnum)[keyof typeof RoleScalarFieldEnum] +export const CompanyScalarFieldEnum = { + id: 'id', + name: 'name', + cw_CompanyId: 'cw_CompanyId', + cw_Identifier: 'cw_Identifier', + createdAt: 'createdAt', + updatedAt: 'updatedAt' +} as const + +export type CompanyScalarFieldEnum = (typeof CompanyScalarFieldEnum)[keyof typeof CompanyScalarFieldEnum] + + export const SortOrder = { asc: 'asc', desc: 'desc' diff --git a/generated/prisma/models.ts b/generated/prisma/models.ts index 5076f8f..99e7913 100644 --- a/generated/prisma/models.ts +++ b/generated/prisma/models.ts @@ -11,4 +11,5 @@ export type * from './models/Session.ts' export type * from './models/User.ts' export type * from './models/Role.ts' +export type * from './models/Company.ts' export type * from './commonInputTypes.ts' \ No newline at end of file diff --git a/generated/prisma/models/Company.ts b/generated/prisma/models/Company.ts new file mode 100644 index 0000000..74664f9 --- /dev/null +++ b/generated/prisma/models/Company.ts @@ -0,0 +1,1224 @@ + +/* !!! This is code generated by Prisma. Do not edit directly. !!! */ +/* eslint-disable */ +// biome-ignore-all lint: generated file +// @ts-nocheck +/* + * This file exports the `Company` model and its related types. + * + * 🟢 You can import this file directly. + */ +import type * as runtime from "@prisma/client/runtime/client" +import type * as $Enums from "../enums.ts" +import type * as Prisma from "../internal/prismaNamespace.ts" + +/** + * Model Company + * + */ +export type CompanyModel = runtime.Types.Result.DefaultSelection + +export type AggregateCompany = { + _count: CompanyCountAggregateOutputType | null + _avg: CompanyAvgAggregateOutputType | null + _sum: CompanySumAggregateOutputType | null + _min: CompanyMinAggregateOutputType | null + _max: CompanyMaxAggregateOutputType | null +} + +export type CompanyAvgAggregateOutputType = { + cw_CompanyId: number | null +} + +export type CompanySumAggregateOutputType = { + cw_CompanyId: number | null +} + +export type CompanyMinAggregateOutputType = { + id: string | null + name: string | null + cw_CompanyId: number | null + cw_Identifier: string | null + createdAt: Date | null + updatedAt: Date | null +} + +export type CompanyMaxAggregateOutputType = { + id: string | null + name: string | null + cw_CompanyId: number | null + cw_Identifier: string | null + createdAt: Date | null + updatedAt: Date | null +} + +export type CompanyCountAggregateOutputType = { + id: number + name: number + cw_CompanyId: number + cw_Identifier: number + createdAt: number + updatedAt: number + _all: number +} + + +export type CompanyAvgAggregateInputType = { + cw_CompanyId?: true +} + +export type CompanySumAggregateInputType = { + cw_CompanyId?: true +} + +export type CompanyMinAggregateInputType = { + id?: true + name?: true + cw_CompanyId?: true + cw_Identifier?: true + createdAt?: true + updatedAt?: true +} + +export type CompanyMaxAggregateInputType = { + id?: true + name?: true + cw_CompanyId?: true + cw_Identifier?: true + createdAt?: true + updatedAt?: true +} + +export type CompanyCountAggregateInputType = { + id?: true + name?: true + cw_CompanyId?: true + cw_Identifier?: true + createdAt?: true + updatedAt?: true + _all?: true +} + +export type CompanyAggregateArgs = { + /** + * Filter which Company to aggregate. + */ + where?: Prisma.CompanyWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Companies to fetch. + */ + orderBy?: Prisma.CompanyOrderByWithRelationInput | Prisma.CompanyOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the start position + */ + cursor?: Prisma.CompanyWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Companies from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Companies. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Count returned Companies + **/ + _count?: true | CompanyCountAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to average + **/ + _avg?: CompanyAvgAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to sum + **/ + _sum?: CompanySumAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the minimum value + **/ + _min?: CompanyMinAggregateInputType + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/aggregations Aggregation Docs} + * + * Select which fields to find the maximum value + **/ + _max?: CompanyMaxAggregateInputType +} + +export type GetCompanyAggregateType = { + [P in keyof T & keyof AggregateCompany]: P extends '_count' | 'count' + ? T[P] extends true + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType +} + + + + +export type CompanyGroupByArgs = { + where?: Prisma.CompanyWhereInput + orderBy?: Prisma.CompanyOrderByWithAggregationInput | Prisma.CompanyOrderByWithAggregationInput[] + by: Prisma.CompanyScalarFieldEnum[] | Prisma.CompanyScalarFieldEnum + having?: Prisma.CompanyScalarWhereWithAggregatesInput + take?: number + skip?: number + _count?: CompanyCountAggregateInputType | true + _avg?: CompanyAvgAggregateInputType + _sum?: CompanySumAggregateInputType + _min?: CompanyMinAggregateInputType + _max?: CompanyMaxAggregateInputType +} + +export type CompanyGroupByOutputType = { + id: string + name: string + cw_CompanyId: number + cw_Identifier: string + createdAt: Date + updatedAt: Date + _count: CompanyCountAggregateOutputType | null + _avg: CompanyAvgAggregateOutputType | null + _sum: CompanySumAggregateOutputType | null + _min: CompanyMinAggregateOutputType | null + _max: CompanyMaxAggregateOutputType | null +} + +type GetCompanyGroupByPayload = Prisma.PrismaPromise< + Array< + Prisma.PickEnumerable & + { + [P in ((keyof T) & (keyof CompanyGroupByOutputType))]: P extends '_count' + ? T[P] extends boolean + ? number + : Prisma.GetScalarType + : Prisma.GetScalarType + } + > + > + + + +export type CompanyWhereInput = { + AND?: Prisma.CompanyWhereInput | Prisma.CompanyWhereInput[] + OR?: Prisma.CompanyWhereInput[] + NOT?: Prisma.CompanyWhereInput | Prisma.CompanyWhereInput[] + id?: Prisma.StringFilter<"Company"> | string + name?: Prisma.StringFilter<"Company"> | string + cw_CompanyId?: Prisma.IntFilter<"Company"> | number + cw_Identifier?: Prisma.StringFilter<"Company"> | string + createdAt?: Prisma.DateTimeFilter<"Company"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"Company"> | Date | string +} + +export type CompanyOrderByWithRelationInput = { + id?: Prisma.SortOrder + name?: Prisma.SortOrder + cw_CompanyId?: Prisma.SortOrder + cw_Identifier?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type CompanyWhereUniqueInput = Prisma.AtLeast<{ + id?: string + cw_CompanyId?: number + cw_Identifier?: string + AND?: Prisma.CompanyWhereInput | Prisma.CompanyWhereInput[] + OR?: Prisma.CompanyWhereInput[] + NOT?: Prisma.CompanyWhereInput | Prisma.CompanyWhereInput[] + name?: Prisma.StringFilter<"Company"> | string + createdAt?: Prisma.DateTimeFilter<"Company"> | Date | string + updatedAt?: Prisma.DateTimeFilter<"Company"> | Date | string +}, "id" | "cw_CompanyId" | "cw_Identifier"> + +export type CompanyOrderByWithAggregationInput = { + id?: Prisma.SortOrder + name?: Prisma.SortOrder + cw_CompanyId?: Prisma.SortOrder + cw_Identifier?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder + _count?: Prisma.CompanyCountOrderByAggregateInput + _avg?: Prisma.CompanyAvgOrderByAggregateInput + _max?: Prisma.CompanyMaxOrderByAggregateInput + _min?: Prisma.CompanyMinOrderByAggregateInput + _sum?: Prisma.CompanySumOrderByAggregateInput +} + +export type CompanyScalarWhereWithAggregatesInput = { + AND?: Prisma.CompanyScalarWhereWithAggregatesInput | Prisma.CompanyScalarWhereWithAggregatesInput[] + OR?: Prisma.CompanyScalarWhereWithAggregatesInput[] + NOT?: Prisma.CompanyScalarWhereWithAggregatesInput | Prisma.CompanyScalarWhereWithAggregatesInput[] + id?: Prisma.StringWithAggregatesFilter<"Company"> | string + name?: Prisma.StringWithAggregatesFilter<"Company"> | string + cw_CompanyId?: Prisma.IntWithAggregatesFilter<"Company"> | number + cw_Identifier?: Prisma.StringWithAggregatesFilter<"Company"> | string + createdAt?: Prisma.DateTimeWithAggregatesFilter<"Company"> | Date | string + updatedAt?: Prisma.DateTimeWithAggregatesFilter<"Company"> | Date | string +} + +export type CompanyCreateInput = { + id?: string + name: string + cw_CompanyId: number + cw_Identifier: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type CompanyUncheckedCreateInput = { + id?: string + name: string + cw_CompanyId: number + cw_Identifier: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type CompanyUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.StringFieldUpdateOperationsInput | string + cw_CompanyId?: Prisma.IntFieldUpdateOperationsInput | number + cw_Identifier?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type CompanyUncheckedUpdateInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.StringFieldUpdateOperationsInput | string + cw_CompanyId?: Prisma.IntFieldUpdateOperationsInput | number + cw_Identifier?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type CompanyCreateManyInput = { + id?: string + name: string + cw_CompanyId: number + cw_Identifier: string + createdAt?: Date | string + updatedAt?: Date | string +} + +export type CompanyUpdateManyMutationInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.StringFieldUpdateOperationsInput | string + cw_CompanyId?: Prisma.IntFieldUpdateOperationsInput | number + cw_Identifier?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type CompanyUncheckedUpdateManyInput = { + id?: Prisma.StringFieldUpdateOperationsInput | string + name?: Prisma.StringFieldUpdateOperationsInput | string + cw_CompanyId?: Prisma.IntFieldUpdateOperationsInput | number + cw_Identifier?: Prisma.StringFieldUpdateOperationsInput | string + createdAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string + updatedAt?: Prisma.DateTimeFieldUpdateOperationsInput | Date | string +} + +export type CompanyCountOrderByAggregateInput = { + id?: Prisma.SortOrder + name?: Prisma.SortOrder + cw_CompanyId?: Prisma.SortOrder + cw_Identifier?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type CompanyAvgOrderByAggregateInput = { + cw_CompanyId?: Prisma.SortOrder +} + +export type CompanyMaxOrderByAggregateInput = { + id?: Prisma.SortOrder + name?: Prisma.SortOrder + cw_CompanyId?: Prisma.SortOrder + cw_Identifier?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type CompanyMinOrderByAggregateInput = { + id?: Prisma.SortOrder + name?: Prisma.SortOrder + cw_CompanyId?: Prisma.SortOrder + cw_Identifier?: Prisma.SortOrder + createdAt?: Prisma.SortOrder + updatedAt?: Prisma.SortOrder +} + +export type CompanySumOrderByAggregateInput = { + cw_CompanyId?: Prisma.SortOrder +} + +export type IntFieldUpdateOperationsInput = { + set?: number + increment?: number + decrement?: number + multiply?: number + divide?: number +} + + + +export type CompanySelect = runtime.Types.Extensions.GetSelect<{ + id?: boolean + name?: boolean + cw_CompanyId?: boolean + cw_Identifier?: boolean + createdAt?: boolean + updatedAt?: boolean +}, ExtArgs["result"]["company"]> + +export type CompanySelectCreateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + name?: boolean + cw_CompanyId?: boolean + cw_Identifier?: boolean + createdAt?: boolean + updatedAt?: boolean +}, ExtArgs["result"]["company"]> + +export type CompanySelectUpdateManyAndReturn = runtime.Types.Extensions.GetSelect<{ + id?: boolean + name?: boolean + cw_CompanyId?: boolean + cw_Identifier?: boolean + createdAt?: boolean + updatedAt?: boolean +}, ExtArgs["result"]["company"]> + +export type CompanySelectScalar = { + id?: boolean + name?: boolean + cw_CompanyId?: boolean + cw_Identifier?: boolean + createdAt?: boolean + updatedAt?: boolean +} + +export type CompanyOmit = runtime.Types.Extensions.GetOmit<"id" | "name" | "cw_CompanyId" | "cw_Identifier" | "createdAt" | "updatedAt", ExtArgs["result"]["company"]> + +export type $CompanyPayload = { + name: "Company" + objects: {} + scalars: runtime.Types.Extensions.GetPayloadResult<{ + id: string + name: string + cw_CompanyId: number + cw_Identifier: string + createdAt: Date + updatedAt: Date + }, ExtArgs["result"]["company"]> + composites: {} +} + +export type CompanyGetPayload = runtime.Types.Result.GetResult + +export type CompanyCountArgs = + Omit & { + select?: CompanyCountAggregateInputType | true + } + +export interface CompanyDelegate { + [K: symbol]: { types: Prisma.TypeMap['model']['Company'], meta: { name: 'Company' } } + /** + * Find zero or one Company that matches the filter. + * @param {CompanyFindUniqueArgs} args - Arguments to find a Company + * @example + * // Get one Company + * const company = await prisma.company.findUnique({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUnique(args: Prisma.SelectSubset>): Prisma.Prisma__CompanyClient, T, "findUnique", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find one Company that matches the filter or throw an error with `error.code='P2025'` + * if no matches were found. + * @param {CompanyFindUniqueOrThrowArgs} args - Arguments to find a Company + * @example + * // Get one Company + * const company = await prisma.company.findUniqueOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findUniqueOrThrow(args: Prisma.SelectSubset>): Prisma.Prisma__CompanyClient, T, "findUniqueOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Company that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CompanyFindFirstArgs} args - Arguments to find a Company + * @example + * // Get one Company + * const company = await prisma.company.findFirst({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirst(args?: Prisma.SelectSubset>): Prisma.Prisma__CompanyClient, T, "findFirst", GlobalOmitOptions> | null, null, ExtArgs, GlobalOmitOptions> + + /** + * Find the first Company that matches the filter or + * throw `PrismaKnownClientError` with `P2025` code if no matches were found. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CompanyFindFirstOrThrowArgs} args - Arguments to find a Company + * @example + * // Get one Company + * const company = await prisma.company.findFirstOrThrow({ + * where: { + * // ... provide filter here + * } + * }) + */ + findFirstOrThrow(args?: Prisma.SelectSubset>): Prisma.Prisma__CompanyClient, T, "findFirstOrThrow", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Find zero or more Companies that matches the filter. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CompanyFindManyArgs} args - Arguments to filter and select certain fields only. + * @example + * // Get all Companies + * const companies = await prisma.company.findMany() + * + * // Get first 10 Companies + * const companies = await prisma.company.findMany({ take: 10 }) + * + * // Only select the `id` + * const companyWithIdOnly = await prisma.company.findMany({ select: { id: true } }) + * + */ + findMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "findMany", GlobalOmitOptions>> + + /** + * Create a Company. + * @param {CompanyCreateArgs} args - Arguments to create a Company. + * @example + * // Create one Company + * const Company = await prisma.company.create({ + * data: { + * // ... data to create a Company + * } + * }) + * + */ + create(args: Prisma.SelectSubset>): Prisma.Prisma__CompanyClient, T, "create", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Create many Companies. + * @param {CompanyCreateManyArgs} args - Arguments to create many Companies. + * @example + * // Create many Companies + * const company = await prisma.company.createMany({ + * data: [ + * // ... provide data here + * ] + * }) + * + */ + createMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Create many Companies and returns the data saved in the database. + * @param {CompanyCreateManyAndReturnArgs} args - Arguments to create many Companies. + * @example + * // Create many Companies + * const company = await prisma.company.createManyAndReturn({ + * data: [ + * // ... provide data here + * ] + * }) + * + * // Create many Companies and only return the `id` + * const companyWithIdOnly = await prisma.company.createManyAndReturn({ + * select: { id: true }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + createManyAndReturn(args?: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "createManyAndReturn", GlobalOmitOptions>> + + /** + * Delete a Company. + * @param {CompanyDeleteArgs} args - Arguments to delete one Company. + * @example + * // Delete one Company + * const Company = await prisma.company.delete({ + * where: { + * // ... filter to delete one Company + * } + * }) + * + */ + delete(args: Prisma.SelectSubset>): Prisma.Prisma__CompanyClient, T, "delete", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Update one Company. + * @param {CompanyUpdateArgs} args - Arguments to update one Company. + * @example + * // Update one Company + * const company = await prisma.company.update({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + update(args: Prisma.SelectSubset>): Prisma.Prisma__CompanyClient, T, "update", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + /** + * Delete zero or more Companies. + * @param {CompanyDeleteManyArgs} args - Arguments to filter Companies to delete. + * @example + * // Delete a few Companies + * const { count } = await prisma.company.deleteMany({ + * where: { + * // ... provide filter here + * } + * }) + * + */ + deleteMany(args?: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Companies. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CompanyUpdateManyArgs} args - Arguments to update one or more rows. + * @example + * // Update many Companies + * const company = await prisma.company.updateMany({ + * where: { + * // ... provide filter here + * }, + * data: { + * // ... provide data here + * } + * }) + * + */ + updateMany(args: Prisma.SelectSubset>): Prisma.PrismaPromise + + /** + * Update zero or more Companies and returns the data updated in the database. + * @param {CompanyUpdateManyAndReturnArgs} args - Arguments to update many Companies. + * @example + * // Update many Companies + * const company = await prisma.company.updateManyAndReturn({ + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * + * // Update zero or more Companies and only return the `id` + * const companyWithIdOnly = await prisma.company.updateManyAndReturn({ + * select: { id: true }, + * where: { + * // ... provide filter here + * }, + * data: [ + * // ... provide data here + * ] + * }) + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * + */ + updateManyAndReturn(args: Prisma.SelectSubset>): Prisma.PrismaPromise, T, "updateManyAndReturn", GlobalOmitOptions>> + + /** + * Create or update one Company. + * @param {CompanyUpsertArgs} args - Arguments to update or create a Company. + * @example + * // Update or create a Company + * const company = await prisma.company.upsert({ + * create: { + * // ... data to create a Company + * }, + * update: { + * // ... in case it already exists, update + * }, + * where: { + * // ... the filter for the Company we want to update + * } + * }) + */ + upsert(args: Prisma.SelectSubset>): Prisma.Prisma__CompanyClient, T, "upsert", GlobalOmitOptions>, never, ExtArgs, GlobalOmitOptions> + + + /** + * Count the number of Companies. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CompanyCountArgs} args - Arguments to filter Companies to count. + * @example + * // Count the number of Companies + * const count = await prisma.company.count({ + * where: { + * // ... the filter for the Companies we want to count + * } + * }) + **/ + count( + args?: Prisma.Subset, + ): Prisma.PrismaPromise< + T extends runtime.Types.Utils.Record<'select', any> + ? T['select'] extends true + ? number + : Prisma.GetScalarType + : number + > + + /** + * Allows you to perform aggregations operations on a Company. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CompanyAggregateArgs} args - Select which aggregations you would like to apply and on what fields. + * @example + * // Ordered by age ascending + * // Where email contains prisma.io + * // Limited to the 10 users + * const aggregations = await prisma.user.aggregate({ + * _avg: { + * age: true, + * }, + * where: { + * email: { + * contains: "prisma.io", + * }, + * }, + * orderBy: { + * age: "asc", + * }, + * take: 10, + * }) + **/ + aggregate(args: Prisma.Subset): Prisma.PrismaPromise> + + /** + * Group by Company. + * Note, that providing `undefined` is treated as the value not being there. + * Read more here: https://pris.ly/d/null-undefined + * @param {CompanyGroupByArgs} args - Group by arguments. + * @example + * // Group by city, order by createdAt, get count + * const result = await prisma.user.groupBy({ + * by: ['city', 'createdAt'], + * orderBy: { + * createdAt: true + * }, + * _count: { + * _all: true + * }, + * }) + * + **/ + groupBy< + T extends CompanyGroupByArgs, + HasSelectOrTake extends Prisma.Or< + Prisma.Extends<'skip', Prisma.Keys>, + Prisma.Extends<'take', Prisma.Keys> + >, + OrderByArg extends Prisma.True extends HasSelectOrTake + ? { orderBy: CompanyGroupByArgs['orderBy'] } + : { orderBy?: CompanyGroupByArgs['orderBy'] }, + OrderFields extends Prisma.ExcludeUnderscoreKeys>>, + ByFields extends Prisma.MaybeTupleToUnion, + ByValid extends Prisma.Has, + HavingFields extends Prisma.GetHavingFields, + HavingValid extends Prisma.Has, + ByEmpty extends T['by'] extends never[] ? Prisma.True : Prisma.False, + InputErrors extends ByEmpty extends Prisma.True + ? `Error: "by" must not be empty.` + : HavingValid extends Prisma.False + ? { + [P in HavingFields]: P extends ByFields + ? never + : P extends string + ? `Error: Field "${P}" used in "having" needs to be provided in "by".` + : [ + Error, + 'Field ', + P, + ` in "having" needs to be provided in "by"`, + ] + }[HavingFields] + : 'take' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "take", you also need to provide "orderBy"' + : 'skip' extends Prisma.Keys + ? 'orderBy' extends Prisma.Keys + ? ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + : 'Error: If you provide "skip", you also need to provide "orderBy"' + : ByValid extends Prisma.True + ? {} + : { + [P in OrderFields]: P extends ByFields + ? never + : `Error: Field "${P}" in "orderBy" needs to be provided in "by"` + }[OrderFields] + >(args: Prisma.SubsetIntersection & InputErrors): {} extends InputErrors ? GetCompanyGroupByPayload : Prisma.PrismaPromise +/** + * Fields of the Company model + */ +readonly fields: CompanyFieldRefs; +} + +/** + * The delegate class that acts as a "Promise-like" for Company. + * Why is this prefixed with `Prisma__`? + * Because we want to prevent naming conflicts as mentioned in + * https://github.com/prisma/prisma-client-js/issues/707 + */ +export interface Prisma__CompanyClient extends Prisma.PrismaPromise { + readonly [Symbol.toStringTag]: "PrismaPromise" + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback for only the rejection of the Promise. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of the callback. + */ + catch(onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null): runtime.Types.Utils.JsPromise + /** + * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The + * resolved value cannot be modified from the callback. + * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected). + * @returns A Promise for the completion of the callback. + */ + finally(onfinally?: (() => void) | undefined | null): runtime.Types.Utils.JsPromise +} + + + + +/** + * Fields of the Company model + */ +export interface CompanyFieldRefs { + readonly id: Prisma.FieldRef<"Company", 'String'> + readonly name: Prisma.FieldRef<"Company", 'String'> + readonly cw_CompanyId: Prisma.FieldRef<"Company", 'Int'> + readonly cw_Identifier: Prisma.FieldRef<"Company", 'String'> + readonly createdAt: Prisma.FieldRef<"Company", 'DateTime'> + readonly updatedAt: Prisma.FieldRef<"Company", 'DateTime'> +} + + +// Custom InputTypes +/** + * Company findUnique + */ +export type CompanyFindUniqueArgs = { + /** + * Select specific fields to fetch from the Company + */ + select?: Prisma.CompanySelect | null + /** + * Omit specific fields from the Company + */ + omit?: Prisma.CompanyOmit | null + /** + * Filter, which Company to fetch. + */ + where: Prisma.CompanyWhereUniqueInput +} + +/** + * Company findUniqueOrThrow + */ +export type CompanyFindUniqueOrThrowArgs = { + /** + * Select specific fields to fetch from the Company + */ + select?: Prisma.CompanySelect | null + /** + * Omit specific fields from the Company + */ + omit?: Prisma.CompanyOmit | null + /** + * Filter, which Company to fetch. + */ + where: Prisma.CompanyWhereUniqueInput +} + +/** + * Company findFirst + */ +export type CompanyFindFirstArgs = { + /** + * Select specific fields to fetch from the Company + */ + select?: Prisma.CompanySelect | null + /** + * Omit specific fields from the Company + */ + omit?: Prisma.CompanyOmit | null + /** + * Filter, which Company to fetch. + */ + where?: Prisma.CompanyWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Companies to fetch. + */ + orderBy?: Prisma.CompanyOrderByWithRelationInput | Prisma.CompanyOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Companies. + */ + cursor?: Prisma.CompanyWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Companies from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Companies. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Companies. + */ + distinct?: Prisma.CompanyScalarFieldEnum | Prisma.CompanyScalarFieldEnum[] +} + +/** + * Company findFirstOrThrow + */ +export type CompanyFindFirstOrThrowArgs = { + /** + * Select specific fields to fetch from the Company + */ + select?: Prisma.CompanySelect | null + /** + * Omit specific fields from the Company + */ + omit?: Prisma.CompanyOmit | null + /** + * Filter, which Company to fetch. + */ + where?: Prisma.CompanyWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Companies to fetch. + */ + orderBy?: Prisma.CompanyOrderByWithRelationInput | Prisma.CompanyOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for searching for Companies. + */ + cursor?: Prisma.CompanyWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Companies from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Companies. + */ + skip?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/distinct Distinct Docs} + * + * Filter by unique combinations of Companies. + */ + distinct?: Prisma.CompanyScalarFieldEnum | Prisma.CompanyScalarFieldEnum[] +} + +/** + * Company findMany + */ +export type CompanyFindManyArgs = { + /** + * Select specific fields to fetch from the Company + */ + select?: Prisma.CompanySelect | null + /** + * Omit specific fields from the Company + */ + omit?: Prisma.CompanyOmit | null + /** + * Filter, which Companies to fetch. + */ + where?: Prisma.CompanyWhereInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/sorting Sorting Docs} + * + * Determine the order of Companies to fetch. + */ + orderBy?: Prisma.CompanyOrderByWithRelationInput | Prisma.CompanyOrderByWithRelationInput[] + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination#cursor-based-pagination Cursor Docs} + * + * Sets the position for listing Companies. + */ + cursor?: Prisma.CompanyWhereUniqueInput + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Take `±n` Companies from the position of the cursor. + */ + take?: number + /** + * {@link https://www.prisma.io/docs/concepts/components/prisma-client/pagination Pagination Docs} + * + * Skip the first `n` Companies. + */ + skip?: number + distinct?: Prisma.CompanyScalarFieldEnum | Prisma.CompanyScalarFieldEnum[] +} + +/** + * Company create + */ +export type CompanyCreateArgs = { + /** + * Select specific fields to fetch from the Company + */ + select?: Prisma.CompanySelect | null + /** + * Omit specific fields from the Company + */ + omit?: Prisma.CompanyOmit | null + /** + * The data needed to create a Company. + */ + data: Prisma.XOR +} + +/** + * Company createMany + */ +export type CompanyCreateManyArgs = { + /** + * The data used to create many Companies. + */ + data: Prisma.CompanyCreateManyInput | Prisma.CompanyCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * Company createManyAndReturn + */ +export type CompanyCreateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Company + */ + select?: Prisma.CompanySelectCreateManyAndReturn | null + /** + * Omit specific fields from the Company + */ + omit?: Prisma.CompanyOmit | null + /** + * The data used to create many Companies. + */ + data: Prisma.CompanyCreateManyInput | Prisma.CompanyCreateManyInput[] + skipDuplicates?: boolean +} + +/** + * Company update + */ +export type CompanyUpdateArgs = { + /** + * Select specific fields to fetch from the Company + */ + select?: Prisma.CompanySelect | null + /** + * Omit specific fields from the Company + */ + omit?: Prisma.CompanyOmit | null + /** + * The data needed to update a Company. + */ + data: Prisma.XOR + /** + * Choose, which Company to update. + */ + where: Prisma.CompanyWhereUniqueInput +} + +/** + * Company updateMany + */ +export type CompanyUpdateManyArgs = { + /** + * The data used to update Companies. + */ + data: Prisma.XOR + /** + * Filter which Companies to update + */ + where?: Prisma.CompanyWhereInput + /** + * Limit how many Companies to update. + */ + limit?: number +} + +/** + * Company updateManyAndReturn + */ +export type CompanyUpdateManyAndReturnArgs = { + /** + * Select specific fields to fetch from the Company + */ + select?: Prisma.CompanySelectUpdateManyAndReturn | null + /** + * Omit specific fields from the Company + */ + omit?: Prisma.CompanyOmit | null + /** + * The data used to update Companies. + */ + data: Prisma.XOR + /** + * Filter which Companies to update + */ + where?: Prisma.CompanyWhereInput + /** + * Limit how many Companies to update. + */ + limit?: number +} + +/** + * Company upsert + */ +export type CompanyUpsertArgs = { + /** + * Select specific fields to fetch from the Company + */ + select?: Prisma.CompanySelect | null + /** + * Omit specific fields from the Company + */ + omit?: Prisma.CompanyOmit | null + /** + * The filter to search for the Company to update in case it exists. + */ + where: Prisma.CompanyWhereUniqueInput + /** + * In case the Company found by the `where` argument doesn't exist, create a new Company with this data. + */ + create: Prisma.XOR + /** + * In case the Company was found with the provided `where` argument, update it with this data. + */ + update: Prisma.XOR +} + +/** + * Company delete + */ +export type CompanyDeleteArgs = { + /** + * Select specific fields to fetch from the Company + */ + select?: Prisma.CompanySelect | null + /** + * Omit specific fields from the Company + */ + omit?: Prisma.CompanyOmit | null + /** + * Filter which Company to delete. + */ + where: Prisma.CompanyWhereUniqueInput +} + +/** + * Company deleteMany + */ +export type CompanyDeleteManyArgs = { + /** + * Filter which Companies to delete + */ + where?: Prisma.CompanyWhereInput + /** + * Limit how many Companies to delete. + */ + limit?: number +} + +/** + * Company without action + */ +export type CompanyDefaultArgs = { + /** + * Select specific fields to fetch from the Company + */ + select?: Prisma.CompanySelect | null + /** + * Omit specific fields from the Company + */ + omit?: Prisma.CompanyOmit | null +} diff --git a/package.json b/package.json index dfb0424..19c5acb 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,9 @@ "db:gen": "prisma generate", "db:push": "prisma migrate dev --skip-generate", "utils:dev": "docker compose -f .docker/docker-compose.yml up --build", - "utils:gen_private_keys": "bun ./utils/genPrivateKeys" + "utils:gen_private_keys": "bun ./utils/genPrivateKeys", + "utils:create_admin_role": "bun ./utils/createAdminRole", + "utils:assign_user_role": "bun ./utils/assignUserRole" }, "dependencies": { "@azure/msal-node": "^5.0.2", @@ -30,6 +32,7 @@ "@prisma/adapter-pg": "^7.3.0", "@prisma/client": "^7.3.0", "@socket.io/bun-engine": "^0.1.0", + "axios": "^1.13.3", "cors": "^2.8.6", "cuid": "^3.0.0", "hono": "^4.11.5", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 37a11be..38460c5 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -34,7 +34,7 @@ model User { emailVerified DateTime? image String? - userId String @unique + userId String @unique token String? sessions Session[] @@ -53,4 +53,15 @@ model Role { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt -} \ No newline at end of file +} + +model Company { + id String @id @default(cuid()) + name String + + cw_CompanyId Int @unique + cw_Identifier String @unique + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} diff --git a/src/constants.ts b/src/constants.ts index 0c7e775..7613d58 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -4,6 +4,7 @@ import { Prisma, PrismaClient } from "../generated/prisma/client"; import * as msal from "@azure/msal-node"; import { Server } from "socket.io"; import { Server as Engine } from "@socket.io/bun-engine"; +import axios from "axios"; const connectionString = `${process.env.DATABASE_URL}`; const adapter = new PrismaPg({ connectionString }); @@ -55,3 +56,16 @@ const engine = new Engine(); io.bind(engine); export { io, engine }; + +// Connectwise API Client + +const connectWiseApi = axios.create({ + baseURL: `https://ttscw.totaltech.net/v4_6_release/apis/3.0/`, + headers: { + Authorization: `Basic ${process.env.CW_BASIC_TOKEN}`, + clientId: `${process.env.CW_CLIENT_ID}`, + "Content-Type": "application/json", + }, +}); + +export { connectWiseApi }; diff --git a/src/index.ts b/src/index.ts index 01d7f15..c0e35a1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,15 @@ +import { refresh } from "./api/auth"; import app from "./api/server"; import { engine, PORT } from "./constants"; +import { refreshCompanies } from "./modules/cw-utils/refreshCompanies"; +import { events, setupEventDebugger } from "./modules/globalEvents"; + +// Setup global event debugger in non-production environments +if (Bun.env.NODE_ENV == "development") setupEventDebugger(); + +// Refresh the internal list of companies every minute +await refreshCompanies(); +setInterval(() => refreshCompanies, 60 * 1000); Bun.serve({ port: PORT, diff --git a/src/modules/cw-utils/fetchAllCompanies.ts b/src/modules/cw-utils/fetchAllCompanies.ts new file mode 100644 index 0000000..dfa0d6b --- /dev/null +++ b/src/modules/cw-utils/fetchAllCompanies.ts @@ -0,0 +1,27 @@ +import { Collection } from "@discordjs/collection"; +import { connectWiseApi } from "../../constants"; +import { Company } from "../../types/ConnectWiseTypes"; + +export const fetchAllCwCompanies = async (): Promise< + Collection +> => { + let allCompanies = new Collection(); + const pageCount = 1000; + + const count = (await connectWiseApi.get("/company/companies/count")).data + .count; + const totalPages = Math.ceil(count / pageCount); + + for (let page = 0; page < totalPages; page++) { + const response = await connectWiseApi.get( + `/company/companies?page=${page + 1}&pageSize=${pageCount}`, + ); + const companies = response.data; + + for (const company of companies) { + allCompanies.set(company.id, company); + } + } + + return allCompanies; +}; diff --git a/src/modules/cw-utils/refreshCompanies.ts b/src/modules/cw-utils/refreshCompanies.ts new file mode 100644 index 0000000..9b9e7bd --- /dev/null +++ b/src/modules/cw-utils/refreshCompanies.ts @@ -0,0 +1,40 @@ +import { connectWiseApi, prisma } from "../../constants"; +import { events } from "../globalEvents"; +import { fetchAllCwCompanies } from "./fetchAllCompanies"; + +export const refreshCompanies = async () => { + events.emit("cw:companies:refreshed:check"); + + // Dynamically import to avoid circular dependency + const internalCompanyCount = await prisma.company.count(); + const externalCompanyCount = + (await connectWiseApi.get("/company/companies/count")).data.count - 1; + + if (internalCompanyCount !== externalCompanyCount) { + console.log( + `Company count mismatch detected. Internal: ${internalCompanyCount}, External: ${externalCompanyCount}. Refreshing...`, + ); + + const allCompanies = await fetchAllCwCompanies(); + + await Promise.all( + allCompanies.map(async (company) => { + return await prisma.company.upsert({ + where: { cw_CompanyId: company.id }, + create: { + cw_CompanyId: company.id, + cw_Identifier: company.identifier, + name: company.name, + }, + update: { + name: company.name, + }, + }); + }), + ); + events.emit("cw:companies:refreshed", { + internalCompaniesCount: internalCompanyCount, + externalCompaniesCount: externalCompanyCount, + }); + } +}; diff --git a/src/modules/globalEvents.ts b/src/modules/globalEvents.ts index cb6a695..91962c8 100644 --- a/src/modules/globalEvents.ts +++ b/src/modules/globalEvents.ts @@ -53,6 +53,11 @@ interface EventTypes { err: Error; role: RoleController; }) => void; + "cw:companies:refreshed:check": () => void; + "cw:companies:refreshed": (data: { + internalCompaniesCount: number; + externalCompaniesCount: number; + }) => void; } export const events = new Eventra(); @@ -61,4 +66,4 @@ export function setupEventDebugger() { events.any((eventName, ...args) => { console.log(`[ Event Debugger ] (${eventName})`); }); -} \ No newline at end of file +} diff --git a/src/types/ConnectWiseTypes.ts b/src/types/ConnectWiseTypes.ts new file mode 100644 index 0000000..a0da7e2 --- /dev/null +++ b/src/types/ConnectWiseTypes.ts @@ -0,0 +1,139 @@ +export interface Company { + id: number; + identifier: string; + name: string; + status: CompanyStatus; + addressLine1: string; + city: string; + state: string; + zip: string; + phoneNumber: string; + faxNumber: string; + website: string; + territory: Territory; + market: Market; + accountNumber: string; + defaultContact: Contact; + dateAcquired: string; + annualRevenue: number; + numberOfEmployees: number; + leadFlag: boolean; + unsubscribeFlag: boolean; + vendorIdentifier: string; + taxIdentifier: string; + taxCode: TaxCode; + billingTerms: BasicEntity; + billToCompany: LinkedCompany; + billingSite: LinkedSite; + billingContact: Contact; + invoiceDeliveryMethod: BasicEntity; + invoiceToEmailAddress: string; + deletedFlag: boolean; + dateDeleted: string; + mobileGuid: string; + resellerIdentifier: string; + isVendorFlag: boolean; + types: TypeItem[]; + site: LinkedSite; + _info: CompanyInfo; + customFields: CustomField[]; +} + +export interface CompanyStatus { + id: number; + name: string; + _info: { + status_href: string; + }; +} + +export interface Territory { + id: number; + name: string; + _info: { + location_href: string; + }; +} + +export interface Market { + id: number; + name: string; + _info: { + Market_href: string; + }; +} + +export interface TaxCode { + id: number; + name: string; + _info: { + taxCode_href: string; + }; +} + +export interface BasicEntity { + id: number; + name: string; +} + +export interface LinkedCompany extends BasicEntity { + identifier: string; + _info: { + company_href: string; + }; +} + +export interface LinkedSite extends BasicEntity { + _info: { + site_href: string; + }; +} + +export interface Contact { + id: number; + name: string; + _info: { + contact_href: string; + }; +} + +export interface TypeItem { + id: number; + name: string; + _info: { + type_href: string; + }; +} + +export interface CompanyInfo { + lastUpdated: string; + updatedBy: string; + dateEntered: string; + enteredBy: string; + contacts_href: string; + agreements_href: string; + tickets_href: string; + opportunities_href: string; + activities_href: string; + projects_href: string; + configurations_href: string; + orders_href: string; + documents_href: string; + sites_href: string; + teams_href: string; + reports_href: string; + notes_href: string; +} + +export interface CustomField { + id: number; + caption: string; + type: string; + entryMethod: string; + numberOfDecimals: number; + value: string | null; + connectWiseId: string; + rowNum: number; + userDefinedFieldRecId: number; + podId: string; +} diff --git a/utils/assignUserRole.ts b/utils/assignUserRole.ts new file mode 100644 index 0000000..ec4cc79 --- /dev/null +++ b/utils/assignUserRole.ts @@ -0,0 +1,41 @@ +import { prisma } from "../src/constants"; +await (async () => { + const userIdentifier = Bun.argv[2]; + const roleIdentifier = Bun.argv[3]; + + if (Bun.argv.length !== 4) + console.error( + "2 arguments expected. \n Format: bun utils:assign_user_role {user} {role}" + ); + + const user = await prisma.user.findFirst({ + where: { OR: [{ id: userIdentifier }, { login: userIdentifier }] }, + }); + + if (!user) + return console.error( + `User with identifier '${userIdentifier}' doesn't exist` + ); + + const role = await prisma.role.findFirst({ + where: { OR: [{ id: roleIdentifier }, { moniker: roleIdentifier }] }, + include: { users: true }, + }); + + if (!role) + return console.error( + `Role with identifier '${roleIdentifier}' doesn't exist` + ); + + if (role.users.map((v) => v.id).includes(user.id)) + return console.log("User already has role!"); + + await prisma.user.update({ + where: { id: user.id }, + data: { roles: { set: { id: role.id } } }, + }); + + return console.log( + `User '${user.login}' has been given role '${role.title}'!` + ); +})(); diff --git a/utils/createAdminRole.ts b/utils/createAdminRole.ts new file mode 100644 index 0000000..054c00c --- /dev/null +++ b/utils/createAdminRole.ts @@ -0,0 +1,27 @@ +import cuid from "cuid"; +import { prisma } from "../src/constants"; +import { signPermissions } from "../src/modules/permission-utils/signPermissions"; + +let newRole; +let id = cuid(); +const admin = await prisma.role.findFirst({ + where: { moniker: "administrator" }, +}); + +if (admin) console.log("Admin already exists", admin); + +if (!admin) + newRole = await prisma.role.create({ + data: { + id, + moniker: "administrator", + title: "Admin", + permissions: signPermissions({ + issuer: "roles", + subject: id, + permissions: ["*"], + }), + }, + }); + +console.log("Admin Role Created!", newRole); From 24d0c066fd89448ca9763446febcd41d83358890 Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Mon, 26 Jan 2026 18:14:28 -0600 Subject: [PATCH 11/73] Setup fetch and wip fetchall route for getting companies. --- src/api/companies/fetch.ts | 22 +++++++++++++ src/api/companies/fetchAll.ts | 31 ++++++++++++++++++ src/controllers/CompanyController.ts | 47 +++++++++++++++++++++++++++ src/managers/companies.ts | 20 ++++++++++++ src/modules/cw-utils/fetchCompany.ts | 19 +++++++++++ src/modules/cw-utils/updateCompany.ts | 24 ++++++++++++++ 6 files changed, 163 insertions(+) create mode 100644 src/api/companies/fetch.ts create mode 100644 src/api/companies/fetchAll.ts create mode 100644 src/controllers/CompanyController.ts create mode 100644 src/managers/companies.ts create mode 100644 src/modules/cw-utils/fetchCompany.ts create mode 100644 src/modules/cw-utils/updateCompany.ts diff --git a/src/api/companies/fetch.ts b/src/api/companies/fetch.ts new file mode 100644 index 0000000..d7345b3 --- /dev/null +++ b/src/api/companies/fetch.ts @@ -0,0 +1,22 @@ +import { Hono } from "hono/tiny"; +import { createRoute } from "../../modules/api-utils/createRoute"; +import { companies } from "../../managers/companies"; +import { apiResponse } from "../../modules/api-utils/apiResponse"; +import { ContentfulStatusCode } from "hono/utils/http-status"; +import { authMiddleware } from "../middleware/authorization"; + +/* /v1/company/[id] */ +export default createRoute( + "get", + ["/:identifier"], + async (c) => { + const company = await companies.fetch(c.req.param("identifier")); + + const response = apiResponse.successful( + "Company Fetched Successfully!", + company, + ); + return c.json(response, response.status as ContentfulStatusCode); + }, + authMiddleware({ permissions: ["company.fetch"] }), +); diff --git a/src/api/companies/fetchAll.ts b/src/api/companies/fetchAll.ts new file mode 100644 index 0000000..0eaa44b --- /dev/null +++ b/src/api/companies/fetchAll.ts @@ -0,0 +1,31 @@ +import { Hono } from "hono/tiny"; +import { createRoute } from "../../modules/api-utils/createRoute"; +import { companies } from "../../managers/companies"; +import { apiResponse } from "../../modules/api-utils/apiResponse"; +import { ContentfulStatusCode } from "hono/utils/http-status"; +import { authMiddleware } from "../middleware/authorization"; + +/* /v1/company/companies */ +export default createRoute( + "get", + ["/companies"], + async (c) => { + /** + * + * + * @TODO MAKE THIS WORK + * + * + * + */ + + const company = await companies.fetch(c.req.param("identifier")); + + const response = apiResponse.successful( + "Company Fetched Successfully!", + company, + ); + return c.json(response, response.status as ContentfulStatusCode); + }, + authMiddleware({ permissions: ["company.fetch"] }), +); diff --git a/src/controllers/CompanyController.ts b/src/controllers/CompanyController.ts new file mode 100644 index 0000000..a96e967 --- /dev/null +++ b/src/controllers/CompanyController.ts @@ -0,0 +1,47 @@ +import { Company } from "../../generated/prisma/client"; +import { updateCwInternalCompany } from "../modules/cw-utils/updateCompany"; + +/** + * Company Controller + * + * This class is for creating a controller that can manage company data, + * synchronize with external systems, and provide methods for accessing + * and updating company information within our internal system. + */ +export class CompanyController { + public readonly id: string; + public name: string; + public readonly cw_Identifier: string; + public readonly cw_CompanyId: number; + + constructor(companyData: Company) { + this.id = companyData.id; + this.name = companyData.name; + this.cw_Identifier = companyData.cw_Identifier; + this.cw_CompanyId = companyData.cw_CompanyId; + } + + /** + * Refresh Internal Company Data from ConnectWise + * + * This method fetches the latest company data from ConnectWise and updates + * the internal company information accordingly. + * + * @returns {ThisType} - Updated Controller + */ + public async refreshFromCW() { + const data = await updateCwInternalCompany(this.cw_CompanyId); + + this.name = data?.name || this.name; + return this; + } + + public toJson() { + return { + id: this.id, + name: this.name, + cw_Identifier: this.cw_Identifier, + cw_CompanyId: this.cw_CompanyId, + }; + } +} diff --git a/src/managers/companies.ts b/src/managers/companies.ts new file mode 100644 index 0000000..434aae8 --- /dev/null +++ b/src/managers/companies.ts @@ -0,0 +1,20 @@ +import { prisma } from "../constants"; +import { CompanyController } from "../controllers/CompanyController"; + +export const companies = { + async fetch(identifier: string | number): Promise { + const search = await prisma.company.findFirst({ + where: { + OR: [ + { id: identifier as string }, + { cw_CompanyId: identifier as number }, + { cw_Identifier: identifier as string }, + ], + }, + }); + + if (!search) throw new Error("Unknown company."); + + return new CompanyController(search); + }, +}; diff --git a/src/modules/cw-utils/fetchCompany.ts b/src/modules/cw-utils/fetchCompany.ts new file mode 100644 index 0000000..b965c26 --- /dev/null +++ b/src/modules/cw-utils/fetchCompany.ts @@ -0,0 +1,19 @@ +import { connectWiseApi } from "../../constants"; +import { Company } from "../../types/ConnectWiseTypes"; + +export const fetchCwCompanyById = async ( + companyId: number, +): Promise => { + try { + const response = await connectWiseApi.get( + `/company/companies/${companyId}`, + ); + return response.data; + } catch (error) { + console.error( + `Error fetching company with ID ${companyId}:`, + (error as any).response?.data || error, + ); + return null; + } +}; diff --git a/src/modules/cw-utils/updateCompany.ts b/src/modules/cw-utils/updateCompany.ts new file mode 100644 index 0000000..17fd699 --- /dev/null +++ b/src/modules/cw-utils/updateCompany.ts @@ -0,0 +1,24 @@ +import { Company } from "../../../generated/prisma/client"; +import { prisma } from "../../constants"; +import { fetchCwCompanyById } from "./fetchCompany"; + +export const updateCwInternalCompany = async ( + companyId: number, +): Promise => { + const cwCompany = await fetchCwCompanyById(companyId); + if (!cwCompany) return null; + + const updatedCompany = await prisma.company.upsert({ + where: { cw_CompanyId: cwCompany.id }, + create: { + cw_CompanyId: cwCompany.id, + cw_Identifier: cwCompany.identifier, + name: cwCompany.name, + }, + update: { + name: cwCompany.name, + }, + }); + + return updatedCompany; +}; From 628dc35deaf7249e69df917dd3d379d2e33309f6 Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Fri, 13 Feb 2026 17:02:03 -0600 Subject: [PATCH 12/73] Companies are now listing properly --- bruno/ttscm/Fetch Company Pages.bru | 15 +++++++++++++ src/.DS_Store | Bin 0 -> 6148 bytes src/api/companies/fetchAll.ts | 32 ++++++++++++++++----------- src/api/companies/index.ts | 2 ++ src/api/routers/companyRouter.ts | 7 ++++++ src/api/routers/user.ts | 7 ++++++ src/api/server.ts | 2 ++ src/api/user/@me/fetch.ts | 18 +++++++++++++++ src/api/user/@me/index.ts | 2 ++ src/api/user/@me/update.ts | 19 ++++++++++++++++ src/index.ts | 4 +++- src/managers/companies.ts | 27 ++++++++++++++++++++++ src/modules/api-utils/apiResponse.ts | 3 ++- 13 files changed, 123 insertions(+), 15 deletions(-) create mode 100644 bruno/ttscm/Fetch Company Pages.bru create mode 100644 src/.DS_Store create mode 100644 src/api/companies/index.ts create mode 100644 src/api/routers/companyRouter.ts create mode 100644 src/api/routers/user.ts create mode 100644 src/api/user/@me/fetch.ts create mode 100644 src/api/user/@me/index.ts create mode 100644 src/api/user/@me/update.ts diff --git a/bruno/ttscm/Fetch Company Pages.bru b/bruno/ttscm/Fetch Company Pages.bru new file mode 100644 index 0000000..3fea809 --- /dev/null +++ b/bruno/ttscm/Fetch Company Pages.bru @@ -0,0 +1,15 @@ +meta { + name: Fetch Company Pages. + type: http + seq: 2 +} + +get { + url: + body: none + auth: inherit +} + +settings { + encodeUrl: true +} diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..941feefd24bf5da2c753d1819aa501371792b4ad GIT binary patch literal 6148 zcmeH~O=`nH427SXECStlndNMHfZkvT$q90S1_~h%(o$&GbM!v_Y~prZOnCz7jWiav zzlFyFV7t%PXJ7)bp}XSA!_18N3Mahd@^$>UUEgkJR=f&4M9hqp3A6p$mWY4|h=2%) zfCwyzK%U~*JTB;&^e7@A0?Q!a--kwb?WH3%J{=4(0#Mg1hjAUV1hsjA+Dk_&D>SR= z!K&3_4DoujQ(IlvOGj$9!)o}jy0iHdL$hp$H6}FcAqpZO0y6@u%qKtp5A@&W|5=Mt z5fFiYM!?ql<9^4Nsv{d9s=gj{YFy56_Y=UxkK!#ojQhk literal 0 HcmV?d00001 diff --git a/src/api/companies/fetchAll.ts b/src/api/companies/fetchAll.ts index 0eaa44b..7920844 100644 --- a/src/api/companies/fetchAll.ts +++ b/src/api/companies/fetchAll.ts @@ -10,22 +10,28 @@ export default createRoute( "get", ["/companies"], async (c) => { - /** - * - * - * @TODO MAKE THIS WORK - * - * - * - */ + const page = new Number(c.req.query("page") ?? 1) as number; + const rpp = new Number(c.req.query("rpp") ?? 30) as number; // Records Per Page + const companyQty = await companies.count(); - const company = await companies.fetch(c.req.param("identifier")); + const data = await companies.fetchPages(page, rpp); - const response = apiResponse.successful( - "Company Fetched Successfully!", - company, + let response = apiResponse.successful( + "Companies Fetched Successfully!", + data, + { + pagination: { + previousPage: page == 1 ? null : page - 1, // Previous Page + currentPage: page, // Current Page + nextPage: page >= companyQty / rpp ? null : page + 1, // Next Page + totalPages: Math.ceil(companyQty / rpp), // Total Number of Pages + totalRecords: companyQty, // Total Number of Records + listedRecords: rpp, // Total Number of Records being recieved at time of request. + }, + }, ); + return c.json(response, response.status as ContentfulStatusCode); }, - authMiddleware({ permissions: ["company.fetch"] }), + authMiddleware({ permissions: ["company.fetch.many"] }), ); diff --git a/src/api/companies/index.ts b/src/api/companies/index.ts new file mode 100644 index 0000000..2e25161 --- /dev/null +++ b/src/api/companies/index.ts @@ -0,0 +1,2 @@ +export { default as fetchAll } from "./fetchAll"; +//export { default as fetch } from "./fetch"; diff --git a/src/api/routers/companyRouter.ts b/src/api/routers/companyRouter.ts new file mode 100644 index 0000000..273764c --- /dev/null +++ b/src/api/routers/companyRouter.ts @@ -0,0 +1,7 @@ +import { Hono } from "hono"; +import * as companyRoutes from "../companies"; + +const companyRouter = new Hono(); +Object.values(companyRoutes).map((r) => companyRouter.route("/", r)); + +export default companyRouter; diff --git a/src/api/routers/user.ts b/src/api/routers/user.ts new file mode 100644 index 0000000..1e5f3b3 --- /dev/null +++ b/src/api/routers/user.ts @@ -0,0 +1,7 @@ +import { Hono } from "hono"; +import * as userRoutes from "../user/@me"; + +const authRouter = new Hono(); +Object.values(userRoutes).map((r) => authRouter.route("/", r)); + +export default authRouter; diff --git a/src/api/server.ts b/src/api/server.ts index 95d6982..c236d34 100644 --- a/src/api/server.ts +++ b/src/api/server.ts @@ -48,6 +48,8 @@ app.notFound((c) => { v1.route("/teapot", teapot); v1.route("/auth", require("./routers/authRouter").default); +v1.route("/user", require("./routers/user").default); +v1.route("/company", require("./routers/companyRouter").default); app.route("/v1", v1); export default app; diff --git a/src/api/user/@me/fetch.ts b/src/api/user/@me/fetch.ts new file mode 100644 index 0000000..68b872f --- /dev/null +++ b/src/api/user/@me/fetch.ts @@ -0,0 +1,18 @@ +import { ContentfulStatusCode } from "hono/utils/http-status"; +import { apiResponse } from "../../../modules/api-utils/apiResponse"; +import { createRoute } from "../../../modules/api-utils/createRoute"; +import { authMiddleware } from "../../middleware/authorization"; + +// /v1/user/@me +export default createRoute( + "get", + ["/@me"], + (c) => { + const response = apiResponse.successful( + "Fetched user.", + c.get("user")?.toJson(), + ); + return c.json(response, response.status as ContentfulStatusCode); + }, + authMiddleware({ scopes: ["user.read"] }), +); diff --git a/src/api/user/@me/index.ts b/src/api/user/@me/index.ts new file mode 100644 index 0000000..492e227 --- /dev/null +++ b/src/api/user/@me/index.ts @@ -0,0 +1,2 @@ +export { default as fetch } from "./fetch"; +export { default as update } from "./update"; diff --git a/src/api/user/@me/update.ts b/src/api/user/@me/update.ts new file mode 100644 index 0000000..8c698c0 --- /dev/null +++ b/src/api/user/@me/update.ts @@ -0,0 +1,19 @@ +import { ContentfulStatusCode } from "hono/utils/http-status"; +import { apiResponse } from "../../../modules/api-utils/apiResponse"; +import { createRoute } from "../../../modules/api-utils/createRoute"; +import { authMiddleware } from "../../middleware/authorization"; + +export default createRoute( + "patch", + ["/@me"], + async (c) => { + const updatedUser = await c.get("user")?.update(await c.req.json()); + const response = apiResponse.successful( + "Successfully updated user.", + updatedUser?.toJson(), + ); + + return c.json(response, response.status as ContentfulStatusCode); + }, + authMiddleware({ scopes: ["user.write"] }), +); diff --git a/src/index.ts b/src/index.ts index c0e35a1..ed19a55 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,9 @@ if (Bun.env.NODE_ENV == "development") setupEventDebugger(); // Refresh the internal list of companies every minute await refreshCompanies(); -setInterval(() => refreshCompanies, 60 * 1000); +setInterval(() => { + return refreshCompanies(); +}, 60 * 1000); Bun.serve({ port: PORT, diff --git a/src/managers/companies.ts b/src/managers/companies.ts index 434aae8..a6055d7 100644 --- a/src/managers/companies.ts +++ b/src/managers/companies.ts @@ -17,4 +17,31 @@ export const companies = { return new CompanyController(search); }, + + async count() { + return await prisma.company.count(); + }, + + /** + * Fetch Company Pages + * + * This is a method to be used to fetch pages of companies used for pagination. + * + * @param page - Page number + * @param rpp - Records Per Page + */ + async fetchPages(page: number, rpp: number) { + page = page.valueOf(); + rpp = rpp.valueOf(); + + const skip = (page > 1 ? page : 0) * rpp; + const take = rpp ?? 30; + + const data = prisma.company.findMany({ + skip, + take, + }); + + return data; + }, }; diff --git a/src/modules/api-utils/apiResponse.ts b/src/modules/api-utils/apiResponse.ts index 47072c2..5a3859d 100644 --- a/src/modules/api-utils/apiResponse.ts +++ b/src/modules/api-utils/apiResponse.ts @@ -4,13 +4,14 @@ import { ZodError } from "zod"; * @ignore */ export const apiResponse = { - successful: (message: string, data?: any) => ({ + successful: (message: string, data?: any, meta?: {}) => ({ status: 200, message, data, successful: true, meta: { timestamp: Date.now(), + ...meta, }, }), created: (message: string, data?: any) => ({ From 7466bbdeac71cac05a3f6c96bb014124e775d8bb Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Fri, 13 Feb 2026 18:02:52 -0600 Subject: [PATCH 13/73] Something changed idk --- src/api/companies/fetch.ts | 2 +- src/api/companies/index.ts | 6 ++++-- src/api/server.ts | 2 +- src/managers/companies.ts | 6 +----- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/api/companies/fetch.ts b/src/api/companies/fetch.ts index d7345b3..aed035a 100644 --- a/src/api/companies/fetch.ts +++ b/src/api/companies/fetch.ts @@ -8,7 +8,7 @@ import { authMiddleware } from "../middleware/authorization"; /* /v1/company/[id] */ export default createRoute( "get", - ["/:identifier"], + ["/company/:identifier"], async (c) => { const company = await companies.fetch(c.req.param("identifier")); diff --git a/src/api/companies/index.ts b/src/api/companies/index.ts index 2e25161..011fed2 100644 --- a/src/api/companies/index.ts +++ b/src/api/companies/index.ts @@ -1,2 +1,4 @@ -export { default as fetchAll } from "./fetchAll"; -//export { default as fetch } from "./fetch"; +import { default as fetchAll } from "./fetchAll"; +import { default as fetch } from "./fetch"; + +export { fetch, fetchAll }; diff --git a/src/api/server.ts b/src/api/server.ts index c236d34..99a36f0 100644 --- a/src/api/server.ts +++ b/src/api/server.ts @@ -49,7 +49,7 @@ app.notFound((c) => { v1.route("/teapot", teapot); v1.route("/auth", require("./routers/authRouter").default); v1.route("/user", require("./routers/user").default); -v1.route("/company", require("./routers/companyRouter").default); +v1.route("/", require("./routers/companyRouter").default); app.route("/v1", v1); export default app; diff --git a/src/managers/companies.ts b/src/managers/companies.ts index a6055d7..8892ce9 100644 --- a/src/managers/companies.ts +++ b/src/managers/companies.ts @@ -5,11 +5,7 @@ export const companies = { async fetch(identifier: string | number): Promise { const search = await prisma.company.findFirst({ where: { - OR: [ - { id: identifier as string }, - { cw_CompanyId: identifier as number }, - { cw_Identifier: identifier as string }, - ], + OR: [{ id: identifier as string }], }, }); From 3ab443790c664a4be04de7ac64eba361be15dec8 Mon Sep 17 00:00:00 2001 From: Jackson Roberts Date: Sat, 14 Feb 2026 12:08:23 -0600 Subject: [PATCH 14/73] Lots of updates and cleaning up. --- .github/copilot-instructions.md | 73 ++++++++ src/api/auth/redirect.ts | 2 - src/api/auth/refresh.ts | 2 - src/api/companies/[id]/configurations.ts | 26 +++ src/api/companies/{ => [id]}/fetch.ts | 13 +- src/api/companies/fetchAll.ts | 10 +- src/api/companies/index.ts | 5 +- src/api/server.ts | 2 +- src/controllers/CompanyController.ts | 29 +++ src/controllers/RoleController.ts | 17 +- src/controllers/UserController.ts | 2 - src/managers/companies.ts | 31 ++++ .../cw-utils/fetchCompanyConfigurations.ts | 30 ++++ .../cw-utils/processConfigurationResponse.ts | 22 +++ src/modules/cw-utils/refreshCompanies.ts | 47 ++--- src/modules/globalEvents.ts | 59 ++++++- src/types/ConnectWiseTypes.ts | 166 ++++++++++++++++++ 17 files changed, 484 insertions(+), 52 deletions(-) create mode 100644 .github/copilot-instructions.md create mode 100644 src/api/companies/[id]/configurations.ts rename src/api/companies/{ => [id]}/fetch.ts (58%) create mode 100644 src/modules/cw-utils/fetchCompanyConfigurations.ts create mode 100644 src/modules/cw-utils/processConfigurationResponse.ts diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..451e0d3 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,73 @@ +# Copilot / AI Agent Instructions for ttscm-api + +Purpose: make AI coding agents immediately productive in this repository by describing architecture, conventions, workflows, and helpful code pointers. + +-- **Big picture**: This is a TypeScript API service (runs on Bun) using the Hono framework. The HTTP surface is implemented in `src/api` where small router files are mounted on a versioned router in `src/api/server.ts` (see the `/v1` mount). Typical request flow is: + +- `router` (in `src/api/routers/*`) → `controller` (in `src/controllers/*`) → `manager` (in `src/managers/*`) → `module` / `generated/prisma` for persistence and external integrations. +- Keep each layer focused: routers handle routing & middleware, controllers handle request validation and high-level orchestration, managers encapsulate domain/persistence logic, modules provide shared utilities (external API clients, helpers). + +- **Runtime / tooling**: The project runs on Bun. Dev command: `npm run dev` (runs `bun --watch src/index.ts`). DB tooling uses Prisma; generated client lives under `generated/prisma` (do NOT edit generated files). Key scripts in `package.json`: + - `dev` — start the server with Bun in watch mode + - `db:gen` — `prisma generate` + - `db:push` — `prisma migrate dev --skip-generate` + +- **Data layer**: Prisma schema is at `prisma/schema.prisma`. The app imports the generated Prisma client from `generated/prisma/client.ts` (or `generated/prisma/browser.ts` in browser contexts). Always run the `db:gen` script after updating `schema.prisma`. + +- **Routing & controllers**: Example flow: a request hits a `router` in `src/api/routers/*` → router delegates to a `controller` in `src/controllers/*` → controller calls a `manager` in `src/managers/*` for domain/persistence logic. Important concrete patterns: + - `src/api/server.ts` mounts `v1` and uses `v1.route("/auth", require("./routers/authRouter").default)` style requires; preserve this shape when adding routes. + - Router files export a default Hono router object (CommonJS `module.exports`/`export default` mixture is used across the codebase). + - Controllers are single-export modules named like `CompanyController.ts` with named methods per action (e.g., `fetch`, `update`). Prefer small methods that call into `managers/*`. + - Managers are thin domain layers (e.g., `managers/companies.ts`) that wrap `generated/prisma` calls and other I/O. Keep side effects here, keep controllers pure orchestration. + - Use `src/modules/api-utils/apiResponse.ts` for every HTTP response shape (successful/created/error/internalError/zodError). + - Use Zod schemas in controllers for request validation; server-level `app.onError` maps `ZodError` to `apiResponse.zodError`. + +**API layout & conventions (how to add a new endpoint)** + +- **Add router**: create `src/api/routers/Router.ts` exporting a Hono router and mount it in `src/api/server.ts` under the `v1` router. +- **Add controller**: create `src/controllers/Controller.ts` exporting functions for each action. Controllers should validate input with Zod, call managers, and return `apiResponse.*` results. +- **Add manager**: create `src/managers/.ts` for persistence/domain logic. Use the generated Prisma client (`generated/prisma/client.ts`) here; do not import Prisma directly in controllers. +- **Add modules/types**: if needed, add helpers to `src/modules/*` and runtime types to `src/types/*`. +- **Middleware & auth**: use `src/api/middleware/authorization.ts` for protecting routes; follow existing token/session patterns from `src/controllers/SessionController.ts` and `src/Errors/*`. +- **Error handling**: throw repository-specific errors from `src/Errors/*` (include `status`, `name`, `message`, optional `cause`) and let `src/api/server.ts` map them via `apiResponse.error`. +- **Naming**: prefer plural manager filenames (`companies.ts`) and singular controller names (`CompanyController.ts`) — follow existing files. + +**Examples & notable files** + +- `src/api/server.ts` — mounts `v1`, registers `cors`, central `onError` handler and `notFound` response. +- `src/api/routers/companyRouter.ts` and `src/controllers/CompanyController.ts` — canonical example for adding company endpoints. +- `src/api/user/@me/*` — nested route example (use Hono sub-routers for subpaths). +- `src/modules/cw-utils/*` — external API integrations; keep interfaces stable and return domain objects consumed by managers. + +- **Validation & errors**: Zod is used for input validation; Zod errors are handled centrally in `src/api/server.ts` via `apiResponse.zodError`. Application errors use custom error classes in `src/Errors/*` (e.g., `AuthenticationError.ts`, `GenericError.ts`). When creating errors, follow the shape used in existing errors (include `status`, `name`, `message`, and optional `cause`). + +- **Response pattern**: Use the `apiResponse` helpers in `src/modules/api-utils/apiResponse.ts` for formatting responses and status codes (successful, created, error, internalError, zodError). + +- **Auth & external integrations**: Microsoft OAuth flow is under `src/api/auth/*` and `src/modules/fetchMicrosoftUser.ts`. If touching authentication, follow existing redirect/refresh patterns in `src/api/auth` and preserve token-refresh semantics. + +- **ConnectWise integration**: Utilities for ConnectWise interactions live in `src/modules/cw-utils/*` (e.g., `fetchCompanyConfigurations.ts`). These modules often call external APIs and return domain data; preserve the module contracts (input types and returned shapes) when refactoring. + +- **Generated files and CI**: `generated/` is a build artifact. Do not modify. When updating Prisma models, run `npm run db:gen` and commit changes to `generated/prisma` only if that's the established workflow. + +- **Files to inspect for context / examples**: + - `src/api/server.ts` — central error handling, router mounting, CORS and not-found handling. + - `src/modules/api-utils/apiResponse.ts` — response shaping used across controllers. + - `src/controllers/CompanyController.ts` — example controller calling managers. + - `src/modules/cw-utils/fetchCompanyConfigurations.ts` — example external integration utility. + - `generated/prisma/client.ts` — generated Prisma client imports; avoid editing. + +- **Coding conventions & patterns specific to this repo**: + - Prefer the existing layered architecture: routers → controllers → managers → modules. + - Use the `apiResponse` helpers for all HTTP responses. + - Throw or propagate repository-specific custom errors (from `src/Errors/*`) rather than returning bare objects. + - Keep TypeScript types in `src/types/*` and use Zod for runtime checks. + - **Avoid `else` statements** — prefer ternary operators, early returns, or other control flow patterns. Only use `else` if there is absolutely no other way. + +- **Local dev / quick checks**: + - Start dev server: `npm run dev` + - Regenerate Prisma client: `npm run db:gen` + - Apply DB migrations locally: `npm run db:push` + +- **When editing generated or infra files**: if you need to change `generated/prisma/*` (rare), explain why in the PR and show commands used to regenerate. + +If anything here is unclear or you'd like more examples (e.g., a walk-through editing a controller + manager + test run), tell me which area to expand and I'll iterate. diff --git a/src/api/auth/redirect.ts b/src/api/auth/redirect.ts index 0906382..6bb9cb3 100644 --- a/src/api/auth/redirect.ts +++ b/src/api/auth/redirect.ts @@ -23,8 +23,6 @@ export default createRoute("get", ["/redirect"], async (c) => { refreshToken: tokens.refreshToken, }); - console.log("Emitted auth callback for key:", callbackKey); - // Close the window because duh return c.html( `