├── .editorconfig ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CONTRIBUTING.pt_BR.md ├── README.md └── README.pt_BR.md ├── .gitignore ├── LICENSE ├── lib ├── .gitignore ├── LICENSE ├── README.md ├── index.d.ts ├── package-lock.json ├── package.json ├── rollup.config.mjs └── src │ ├── index.js │ └── useInertia.js ├── package-lock.json ├── package.json ├── server ├── .adonisrc.json ├── .env.example ├── .gitignore ├── .prettierignore ├── ace ├── ace-manifest.json ├── app │ ├── Controllers │ │ └── Http │ │ │ └── UsersController.ts │ ├── Exceptions │ │ └── Handler.ts │ └── Validators │ │ └── UserCreateValidator.ts ├── commands │ └── index.ts ├── config │ ├── app.ts │ ├── bodyparser.ts │ ├── cors.ts │ ├── drive.ts │ ├── hash.ts │ ├── inertia.ts │ ├── session.ts │ ├── shield.ts │ └── static.ts ├── contracts │ ├── drive.ts │ ├── env.ts │ ├── events.ts │ ├── hash.ts │ └── tests.ts ├── env.ts ├── package.json ├── providers │ └── AppProvider.ts ├── public │ ├── assets │ │ ├── entrypoints.json │ │ └── manifest.json │ └── favicon.ico ├── resources │ ├── css │ │ └── app.css │ ├── js │ │ ├── Pages │ │ │ └── User.vue │ │ ├── app.js │ │ └── vue.d.ts │ └── views │ │ └── app.edge ├── server.ts ├── start │ ├── inertia.ts │ ├── kernel.ts │ └── routes.ts ├── test.ts ├── tests │ ├── bootstrap.ts │ └── functional │ │ └── hello_world.spec.ts ├── tsconfig.json └── webpack.config.js └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = space 3 | indent_size = 2 4 | charset = utf-8 5 | end_of_line = crlf 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | 9 | [*.json] 10 | insert_final_newline = ignore 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | gustavofenilli@gmail.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | If you wish to make a pull request, you can test out your feature by following these steps. 4 | 5 | 1. Clone this [repository](https://github.com/GustavoFenilli/formkit-addon-inertia) 6 | 2. Create a branch 7 | 3. Run `npm run lib:dev` 8 | 4. Run `npm run server:dev` 9 | 5. Make your changes inside `lib/src` 10 | 6. Test it out inside `server/resources/js/Pages/User.vue` 11 | 12 | And that is it! quite simple right? now you can make your changes and send a PR. 13 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.pt_BR.md: -------------------------------------------------------------------------------- 1 | # Configuração 2 | 3 | Se você deseja fazer um pull request, você pode começar testando sua funcionalidade seguindo esses passos. 4 | 5 | 1. Clone este [repositorio](https://github.com/GustavoFenilli/formkit-addon-inertia) 6 | 2. Crie uma branch 7 | 3. Rode o comando `npm run lib:dev` 8 | 4. Rode o comando `npm run server:dev` 9 | 5. Faça suas mudanças dentro de `lib/src` 10 | 6. Teste elas dentro de `server/resources/js/Pages/User.vue` 11 | 12 | E é so isso! bem simples certo? agora você pode fazer suas mudanças e enviar um PR. 13 | -------------------------------------------------------------------------------- /.github/README.md: -------------------------------------------------------------------------------- 1 | > This package has been moved to [@formkit/inertia](https://github.com/formkit/inertia) to maintain a first party integration with Inertia and FormKit, it comes with breaking changes, a better composable and an easier way to extend event callbacks. 2 | 3 | # FormKit Addon Inertia 4 | 5 | Addon for integrating [InertiaJS](https://inertiajs.com/) with [FormKit](https://formkit.com/) 6 | 7 | - 🇺🇸 [English](./README.md) 8 | - 🇧🇷 [Português](./README.pt_BR.md) 9 | 10 | ## Table of contents 11 | 12 | - 🚀 [Getting Started](#getting-started) 13 | - 🛠 [Options](#options) 14 | - 👏 [Contributing](#contributing) 15 | - 📝 [License](#license) 16 | 17 | ## Getting Started 18 | 19 | There are two ways to use this addon, firstly there is the composition way, and there is also a formkit plugin. 20 | 21 | > In the end, the plugin uses the composable inside of it with the correct form node for easy of use. 22 | 23 | ```bash 24 | npm i formkit-addon-inertia 25 | ``` 26 | 27 | ### 1. Composition 28 | 29 | The `useInertia` is a function that receives a `FormKit` node and returns all Inertia HTTP methods. 30 | Those are `visit`, `get`, `post`, `put`, `patch`, `delete` and `reload`. 31 | 32 | ```html 33 | 36 | 37 | 46 | ``` 47 | 48 | ### 2. Plugin 49 | 50 | The `inertia` context property has all Inertia HTTP methods. 51 | Those are `visit`, `get`, `post`, `put`, `patch`, `delete` and `reload`. 52 | 53 | ```html 54 | 57 | 58 | 68 | ``` 69 | 70 | > You can add this plugin as a global formkit plugin so every form has it, instead of defining manually like the example above 71 | > 72 | > ```js 73 | > import { createApp } from "vue"; 74 | > import App from "App.vue"; 75 | > import { plugin, defaultConfig } from "@formkit/vue"; 76 | > import { plugin as inertiaPlugin } from "formkit-addon-inertia"; 77 | > 78 | > createApp(App) 79 | > .use(plugin, defaultConfig({ plugins: [inertiaPlugin] })) 80 | > .mount("#app"); 81 | > ``` 82 | 83 | ## Options 84 | 85 | You can use all of InertiaJS [callbacks](https://inertiajs.com/manual-visits#event-callbacks), and we add the FormKit node as the last argument for easy integration of your features. 86 | 87 | > We by default add some features inside Inertia callbacks to make the use smoother. 88 | > 89 | > There are four features, loading message, disabled prop, progress data attribute and automatic field errors. 90 | > You can disable any of these by passing any of these properties to the options. 91 | > 92 | > { disableLoading: true, disableDisabled: true, disableProgress: true, disableErrors: true } 93 | 94 | ```html 95 | 107 | 108 | 114 | ``` 115 | 116 | ## Contributing 117 | 118 | All contributions are welcomed and appreciated! 119 | 120 | - You can always star it! 121 | - Any bug you found can be reported by opening an [issue](https://github.com/GustavoFenilli/formkit-addon-inertia/issues/new?assignees=GustavoFenilli&labels=bug) 122 | - If you have any cool ideas or features you want to be added just open a [discussion](https://github.com/GustavoFenilli/formkit-addon-inertia/discussions/new?category=ideas) about it 123 | - You can make pull request with fixes or features, read out the [contributing guide](./CONTRIBUTING.md) to get started 124 | 125 | ## License 126 | 127 | [MIT](https://github.com/GustavoFenilli/formkit-addon-inertia/blob/main/LICENSE) 128 | -------------------------------------------------------------------------------- /.github/README.pt_BR.md: -------------------------------------------------------------------------------- 1 | # FormKit Addon Inertia 2 | 3 | Addon para integrar [InertiaJS](https://inertiajs.com/) com [FormKit](https://formkit.com/) 4 | 5 | - 🇺🇸 [English](./README.md) 6 | - 🇧🇷 [Português](./README.pt_BR.md) 7 | 8 | ## Sumário 9 | 10 | - 🚀 [Primeiros Passos](#primeiros-passos) 11 | - 🛠 [Opções](#opções) 12 | - 👏 [Contribuindo](#contribuindo) 13 | - 📝 [Licença](#licença) 14 | 15 | ## Primeiros Passos 16 | 17 | Existem duas maneiras de usar este addon, primeiramente existe a composition, e também existe um plugin para o formkit. 18 | 19 | > No final das contas, o plugin usa a função da composition com o node correto para facilitar o uso. 20 | 21 | ```bash 22 | npm i formkit-addon-inertia 23 | ``` 24 | 25 | ### 1. Composition 26 | 27 | A função `useInertia` recebe um `FormKit` node e retorna todos metodos HTTP disponíveis pelo Inertia. 28 | Estes sendo `visit`, `get`, `post`, `put`, `patch`, `delete` e `reload`. 29 | 30 | ```html 31 | 34 | 35 | 44 | ``` 45 | 46 | ### 2. Plugin 47 | 48 | A propriedade `inertia` dentro do contexto conta tom todos os metodos HTTP disponíveis pelo Inertia. 49 | Estes sendo `visit`, `get`, `post`, `put`, `patch`, `delete` e `reload`. 50 | 51 | ```html 52 | 55 | 56 | 66 | ``` 67 | 68 | > Você pode adicionar o plugin de forma global para que todos os forms do FormKit tenham acesso as propriedades do Inertia, em vez de manualmente usar como no example acima. 69 | > 70 | > ```js 71 | > import { createApp } from "vue"; 72 | > import App from "App.vue"; 73 | > import { plugin, defaultConfig } from "@formkit/vue"; 74 | > import inertiaPlugin from "formkit-addon-inertia"; 75 | > 76 | > createApp(App) 77 | > .use(plugin, defaultConfig({ plugins: [inertiaPlugin] })) 78 | > .mount("#app"); 79 | > ``` 80 | 81 | ## Opções 82 | 83 | Você pode usar todos os [callbacks](https://inertiajs.com/manual-visits#event-callbacks) do InertiaJS, e nós adicionamos o node do FormKit para facil integração com suas funcionalidades. 84 | 85 | > Por padrão nos adicionamos algumas funcionalidades dentro dos callbacks do Inertia para que o uso seja mais simples. 86 | > 87 | > Existem 4 funcionalidades, carregamento, prop disabled automatico, data attribute com progresso e automaticamento mostrar erros nos campos. 88 | > Você pode disabilitar qualquer um deles passando qualquer uma dessas propriedades nas opções. 89 | > 90 | > { disableLoading: true, disableDisabled: true, disableProgress: true, disableErrors: true } 91 | 92 | ```html 93 | 105 | 106 | 112 | ``` 113 | 114 | ## Contribuindo 115 | 116 | Todas contribuições são bem vindas e apreciadas! 117 | 118 | - Você sempre pode clicar na estrelinha! 119 | - Qualquer bug que você encontrar pode ser reportado abrindo um [chamado](https://github.com/GustavoFenilli/formkit-addon-inertia/issues/new?assignees=GustavoFenilli&labels=bug) 120 | - Se você tem uma ideia legal ou funcionalidade que você quer adicionado, abra uma [discussão](https://github.com/GustavoFenilli/formkit-addon-inertia/discussions/new?category=ideas) sobre ela 121 | - Você pode abrir um pull request com soluçoes ou funcionalidades, leia nosso [guia de contribuição](./CONTRIBUTING.pt_BR.md) para começar 122 | 123 | ## Licença 124 | 125 | [MIT](https://github.com/GustavoFenilli/formkit-addon-inertia/blob/main/LICENSE) 126 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode 3 | .DS_STORE 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Gustavo Fenilli 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | .rollup.cache 2 | tsconfig.tsbuildinfo 3 | node_modules 4 | dist 5 | -------------------------------------------------------------------------------- /lib/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Gustavo Fenilli 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/README.md: -------------------------------------------------------------------------------- 1 | # FormKit Addon Inertia 2 | 3 | Plugin for integrating InertiaJS with FormKit 4 | 5 | You can check out the full documentation [here](https://github.com/GustavoFenilli/formkit-addon-inertia) 6 | 7 | ## Getting Started 8 | 9 | There are two ways to use this addon, firstly there is the composable way, and there is also a formkit plugin. 10 | 11 | > In the end, the plugin uses the composable inside of it with the correct form node for easy of use. 12 | 13 | ```bash 14 | npm i formkit-addon-inertia 15 | ``` 16 | 17 | ### 1. Composable 18 | 19 | The `useInertia` is a function that receives a `FormKit` node and returns all Inertia HTTP methods. 20 | Those are `visit`, `get`, `post`, `put`, `patch`, `delete` and `reload`. 21 | 22 | ```html 23 | 26 | 27 | 36 | ``` 37 | 38 | ### 2. Plugin 39 | 40 | The `inertia` context property has all Inertia HTTP methods. 41 | Those are `visit`, `get`, `post`, `put`, `patch`, `delete` and `reload`. 42 | 43 | ```html 44 | 47 | 48 | 58 | ``` 59 | 60 | > You can add this plugin as a global formkit plugin so every form has it, instead of defining manually like the example above 61 | > 62 | > ```js 63 | > import { createApp } from "vue"; 64 | > import App from "App.vue"; 65 | > import { plugin, defaultConfig } from "@formkit/vue"; 66 | > import { plugin as inertiaPlugin } from "formkit-addon-inertia"; 67 | > 68 | > createApp(App) 69 | > .use(plugin, defaultConfig({ plugins: [inertiaPlugin] })) 70 | > .mount("#app"); 71 | > ``` 72 | 73 | ## License 74 | 75 | [MIT](https://github.com/GustavoFenilli/formkit-addon-inertia/blob/main/LICENSE) 76 | -------------------------------------------------------------------------------- /lib/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | Visit, 3 | Progress, 4 | Page, 5 | Errors, 6 | VisitOptions, 7 | PendingVisit, 8 | ActiveVisit, 9 | RequestPayload, 10 | } from "@inertiajs/vue3"; 11 | import type { FormKitNode } from "@formkit/core"; 12 | 13 | export interface FormKitAddonInertiaDisableOptions { 14 | disableLoading: boolean; 15 | disableDisabled: boolean; 16 | disableProgress: boolean; 17 | disableErrors: boolean; 18 | } 19 | 20 | export declare type FormKitAddonInertiaOptions = Partial< 21 | Visit & { 22 | onCancelToken: (cancelToken: VoidFunction, node: FormKitNode) => void; 23 | onBefore: (visit: PendingVisit, node: FormKitNode) => void; 24 | onStart: (visit: PendingVisit, node: FormKitNode) => void; 25 | onProgress: (progress: Progress | undefined, node: FormKitNode) => void; 26 | onFinish: (visit: ActiveVisit, node: FormKitNode) => void; 27 | onCancel: (node: FormKitNode) => void; 28 | onSuccess: (page: Page, node: FormKitNode) => void; 29 | onError: (errors: Errors, node: FormKitNode) => void; 30 | } & FormKitAddonInertiaDisableOptions 31 | >; 32 | 33 | export interface FormKitAddonInertiaVisits { 34 | visit: (url: URL, options?: FormKitAddonInertiaOptions) => void; 35 | get: ( 36 | url: URL | string, 37 | data?: RequestPayload, 38 | options?: Exclude 39 | ) => void; 40 | post: ( 41 | url: URL | string, 42 | data?: RequestPayload, 43 | options?: Exclude 44 | ) => void; 45 | put: ( 46 | url: URL | string, 47 | data?: RequestPayload, 48 | options?: Exclude 49 | ) => void; 50 | patch: ( 51 | url: URL | string, 52 | data?: RequestPayload, 53 | options?: Exclude 54 | ) => void; 55 | delete: ( 56 | url: URL | string, 57 | options?: Exclude 58 | ) => void; 59 | reload: ( 60 | options?: Exclude< 61 | FormKitAddonInertiaOptions, 62 | "preserveScroll" | "preserveState" 63 | > 64 | ) => void; 65 | } 66 | 67 | export declare const useInertia: (formNode: FormKitNode) => { 68 | visit: ( 69 | url: URL, 70 | options?: 71 | | Partial< 72 | Visit & { 73 | onCancelToken: ( 74 | cancelToken: VoidFunction, 75 | node: FormKitNode 76 | ) => void; 77 | onBefore: (visit: PendingVisit, node: FormKitNode) => void; 78 | onStart: (visit: PendingVisit, node: FormKitNode) => void; 79 | onProgress: ( 80 | progress: Progress | undefined, 81 | node: FormKitNode 82 | ) => void; 83 | onFinish: (visit: ActiveVisit, node: FormKitNode) => void; 84 | onCancel: (node: FormKitNode) => void; 85 | onSuccess: (page: Page, node: FormKitNode) => void; 86 | onError: (errors: Errors, node: FormKitNode) => void; 87 | } & FormKitAddonInertiaDisableOptions 88 | > 89 | | undefined 90 | ) => void; 91 | get: ( 92 | url: URL | string, 93 | data?: RequestPayload | undefined, 94 | options?: 95 | | Partial< 96 | Visit & { 97 | onCancelToken: ( 98 | cancelToken: VoidFunction, 99 | node: FormKitNode 100 | ) => void; 101 | onBefore: (visit: PendingVisit, node: FormKitNode) => void; 102 | onStart: (visit: PendingVisit, node: FormKitNode) => void; 103 | onProgress: ( 104 | progress: Progress | undefined, 105 | node: FormKitNode 106 | ) => void; 107 | onFinish: (visit: ActiveVisit, node: FormKitNode) => void; 108 | onCancel: (node: FormKitNode) => void; 109 | onSuccess: (page: Page, node: FormKitNode) => void; 110 | onError: (errors: Errors, node: FormKitNode) => void; 111 | } & FormKitAddonInertiaDisableOptions 112 | > 113 | | undefined 114 | ) => void; 115 | post: ( 116 | url: URL | string, 117 | data?: RequestPayload | undefined, 118 | options?: 119 | | Partial< 120 | Visit & { 121 | onCancelToken: ( 122 | cancelToken: VoidFunction, 123 | node: FormKitNode 124 | ) => void; 125 | onBefore: (visit: PendingVisit, node: FormKitNode) => void; 126 | onStart: (visit: PendingVisit, node: FormKitNode) => void; 127 | onProgress: ( 128 | progress: Progress | undefined, 129 | node: FormKitNode 130 | ) => void; 131 | onFinish: (visit: ActiveVisit, node: FormKitNode) => void; 132 | onCancel: (node: FormKitNode) => void; 133 | onSuccess: (page: Page, node: FormKitNode) => void; 134 | onError: (errors: Errors, node: FormKitNode) => void; 135 | } & FormKitAddonInertiaDisableOptions 136 | > 137 | | undefined 138 | ) => void; 139 | put: ( 140 | url: URL | string, 141 | data?: RequestPayload | undefined, 142 | options?: 143 | | Partial< 144 | Visit & { 145 | onCancelToken: ( 146 | cancelToken: VoidFunction, 147 | node: FormKitNode 148 | ) => void; 149 | onBefore: (visit: PendingVisit, node: FormKitNode) => void; 150 | onStart: (visit: PendingVisit, node: FormKitNode) => void; 151 | onProgress: ( 152 | progress: Progress | undefined, 153 | node: FormKitNode 154 | ) => void; 155 | onFinish: (visit: ActiveVisit, node: FormKitNode) => void; 156 | onCancel: (node: FormKitNode) => void; 157 | onSuccess: (page: Page, node: FormKitNode) => void; 158 | onError: (errors: Errors, node: FormKitNode) => void; 159 | } & FormKitAddonInertiaDisableOptions 160 | > 161 | | undefined 162 | ) => void; 163 | patch: ( 164 | url: URL | string, 165 | data?: RequestPayload | undefined, 166 | options?: 167 | | Partial< 168 | Visit & { 169 | onCancelToken: ( 170 | cancelToken: VoidFunction, 171 | node: FormKitNode 172 | ) => void; 173 | onBefore: (visit: PendingVisit, node: FormKitNode) => void; 174 | onStart: (visit: PendingVisit, node: FormKitNode) => void; 175 | onProgress: ( 176 | progress: Progress | undefined, 177 | node: FormKitNode 178 | ) => void; 179 | onFinish: (visit: ActiveVisit, node: FormKitNode) => void; 180 | onCancel: (node: FormKitNode) => void; 181 | onSuccess: (page: Page, node: FormKitNode) => void; 182 | onError: (errors: Errors, node: FormKitNode) => void; 183 | } & FormKitAddonInertiaDisableOptions 184 | > 185 | | undefined 186 | ) => void; 187 | delete: ( 188 | url: URL | string, 189 | options?: 190 | | Partial< 191 | Visit & { 192 | onCancelToken: ( 193 | cancelToken: VoidFunction, 194 | node: FormKitNode 195 | ) => void; 196 | onBefore: (visit: PendingVisit, node: FormKitNode) => void; 197 | onStart: (visit: PendingVisit, node: FormKitNode) => void; 198 | onProgress: ( 199 | progress: Progress | undefined, 200 | node: FormKitNode 201 | ) => void; 202 | onFinish: (visit: ActiveVisit, node: FormKitNode) => void; 203 | onCancel: (node: FormKitNode) => void; 204 | onSuccess: (page: Page, node: FormKitNode) => void; 205 | onError: (errors: Errors, node: FormKitNode) => void; 206 | } & FormKitAddonInertiaDisableOptions 207 | > 208 | | undefined 209 | ) => void; 210 | reload: ( 211 | options?: 212 | | Partial< 213 | Visit & { 214 | onCancelToken: ( 215 | cancelToken: VoidFunction, 216 | node: FormKitNode 217 | ) => void; 218 | onBefore: (visit: PendingVisit, node: FormKitNode) => void; 219 | onStart: (visit: PendingVisit, node: FormKitNode) => void; 220 | onProgress: ( 221 | progress: Progress | undefined, 222 | node: FormKitNode 223 | ) => void; 224 | onFinish: (visit: ActiveVisit, node: FormKitNode) => void; 225 | onCancel: (node: FormKitNode) => void; 226 | onSuccess: (page: Page, node: FormKitNode) => void; 227 | onError: (errors: Errors, node: FormKitNode) => void; 228 | } & FormKitAddonInertiaDisableOptions 229 | > 230 | | undefined 231 | ) => void; 232 | }; 233 | 234 | export declare const plugin: (node: FormKitNode) => false | undefined; 235 | 236 | declare module "@formkit/core" { 237 | export interface FormKitFrameworkContext { 238 | inertia: FormKitAddonInertiaVisits; 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "formkit-addon-inertia", 3 | "version": "1.0.0-beta.4", 4 | "description": "A plugin for integrating InertiaJS with FormKit.", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.esm.js", 7 | "types": "index.d.ts", 8 | "scripts": { 9 | "build": "npx rimraf ./dist && rollup -c", 10 | "dev": "npx rimraf ./dist && rollup -c -w" 11 | }, 12 | "files": [ 13 | "dist", 14 | "index.d.ts" 15 | ], 16 | "keywords": [ 17 | "inertiajs", 18 | "formkit", 19 | "addon" 20 | ], 21 | "author": "Gustavo Fenilli (https://github.com/gustavofenilli)", 22 | "license": "MIT", 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/GustavoFenilli/formkit-addon-inertia.git" 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/GustavoFenilli/formkit-addon-inertia/issues" 29 | }, 30 | "homepage": "https://github.com/GustavoFenilli/formkit-addon-inertia#readme", 31 | "peerDependencies": { 32 | "@formkit/core": "^0.16.0", 33 | "@inertiajs/vue3": "^1.0.0" 34 | }, 35 | "devDependencies": { 36 | "rollup": "^3.2.3", 37 | "rollup-plugin-peer-deps-external": "^2.2.4" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import peerDepsExternal from "rollup-plugin-peer-deps-external"; 2 | import pkg from "./package.json" assert { type: "json" }; 3 | 4 | export default [ 5 | { 6 | input: "src/index.js", 7 | plugins: [peerDepsExternal()], 8 | output: [ 9 | { file: pkg.main, format: "cjs", sourcemap: true }, 10 | { file: pkg.module, format: "es", sourcemap: true }, 11 | ], 12 | }, 13 | ]; 14 | 15 | -------------------------------------------------------------------------------- /lib/src/index.js: -------------------------------------------------------------------------------- 1 | import { useInertia } from "./useInertia"; 2 | 3 | export const plugin = (node) => { 4 | if (node.props.type !== "form" || !node.context) return false; 5 | 6 | if (node.context) node.context.inertia = useInertia(node); 7 | }; 8 | 9 | export { useInertia }; 10 | 11 | -------------------------------------------------------------------------------- /lib/src/useInertia.js: -------------------------------------------------------------------------------- 1 | import { router } from "@inertiajs/vue3"; 2 | import { createMessage } from "@formkit/core"; 3 | 4 | const loadingMessage = createMessage({ 5 | key: "loading", 6 | visible: false, 7 | value: true, 8 | }); 9 | 10 | const injectNode = (node, options) => { 11 | const mergedOptions = { ...options }; 12 | 13 | if (mergedOptions?.onCancelToken) { 14 | mergedOptions.onCancelToken = ({ cancel }) => options?.onCancelToken?.(cancel, node); 15 | } 16 | 17 | if (mergedOptions?.onCancel) { 18 | mergedOptions.onCancel = () => options?.onCancel?.(node); 19 | } 20 | 21 | if (mergedOptions?.onSuccess) { 22 | mergedOptions.onSuccess = (page) => options?.onSuccess?.(page, node); 23 | } 24 | 25 | if (mergedOptions?.onBefore) { 26 | mergedOptions.onBefore = (visit) => options?.onBefore?.(visit, node); 27 | } 28 | 29 | mergedOptions.onStart = (visit) => { 30 | if (!options?.disableLoading) node.store.set(loadingMessage); 31 | if (!options?.disableDisabled) node.props.disabled = true; 32 | 33 | if (options?.onStart) return options.onStart(visit, node); 34 | }; 35 | 36 | mergedOptions.onProgress = (progress) => { 37 | if (!options?.disableProgress && node.context) node.context.attrs = { 'data-progress': progress?.total }; 38 | 39 | if (options?.onProgress) return options.onProgress(progress, node); 40 | }; 41 | 42 | mergedOptions.onFinish = (visit) => { 43 | if (!options?.disableLoading) node.store.remove('loading'); 44 | if (!options?.disableDisabled) node.props.disabled = false; 45 | if (!options?.disableProgress && node.context && node.context.attrs['data-progress']) delete node.context.attrs['data-progress']; 46 | 47 | if (options?.onFinish) return options.onFinish(visit, node); 48 | }; 49 | 50 | mergedOptions.onError = (errors) => { 51 | if (!options?.disableErrors) node.setErrors([], errors); 52 | 53 | if (options?.onError) return options.onError(errors, node); 54 | }; 55 | 56 | return mergedOptions; 57 | }; 58 | 59 | export const useInertia = (formNode) => { 60 | return { 61 | visit: (url, options) => router.visit(url, injectNode(formNode, options)), 62 | get: (url, data, options) => 63 | router.get(url, data, injectNode(formNode, options)), 64 | post: (url, data, options) => 65 | router.post(url, data, injectNode(formNode, options)), 66 | put: (url, data, options) => 67 | router.put(url, data, injectNode(formNode, options)), 68 | patch: (url, data, options) => 69 | router.patch(url, data, injectNode(formNode, options)), 70 | delete: (url, options) => router.delete(url, injectNode(formNode, options)), 71 | reload: (options) => router.reload(injectNode(formNode, options)), 72 | }; 73 | }; 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": "true", 3 | "workspaces": [ 4 | "lib", 5 | "server" 6 | ], 7 | "scripts": { 8 | "server:dev": "npm run dev --workspace=server", 9 | "server:ace": "npm run ace --workspace=server", 10 | "lib:dev": "npm run dev --workspace=lib", 11 | "lib:build": "npm run build --workspace=lib" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /server/.adonisrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript": true, 3 | "commands": [ 4 | "./commands", 5 | "@adonisjs/core/build/commands/index.js", 6 | "@adonisjs/repl/build/commands", 7 | "@eidellev/inertia-adonisjs/build/commands" 8 | ], 9 | "exceptionHandlerNamespace": "App/Exceptions/Handler", 10 | "aliases": { 11 | "App": "app", 12 | "Config": "config", 13 | "Database": "database", 14 | "Contracts": "contracts" 15 | }, 16 | "preloads": [ 17 | "./start/routes", 18 | "./start/kernel", 19 | { 20 | "file": "./start/inertia", 21 | "environment": [ 22 | "web" 23 | ] 24 | } 25 | ], 26 | "providers": [ 27 | "./providers/AppProvider", 28 | "@adonisjs/core", 29 | "@adonisjs/session", 30 | "@adonisjs/view", 31 | "@adonisjs/shield", 32 | "@eidellev/inertia-adonisjs" 33 | ], 34 | "metaFiles": [ 35 | { 36 | "pattern": "public/**", 37 | "reloadServer": false 38 | }, 39 | { 40 | "pattern": "resources/views/**/*.edge", 41 | "reloadServer": false 42 | } 43 | ], 44 | "aceProviders": [ 45 | "@adonisjs/repl" 46 | ], 47 | "tests": { 48 | "suites": [ 49 | { 50 | "name": "functional", 51 | "files": [ 52 | "tests/functional/**/*.spec(.ts|.js)" 53 | ], 54 | "timeout": 60000 55 | } 56 | ] 57 | }, 58 | "testProviders": [ 59 | "@japa/preset-adonis/TestsProvider" 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /server/.env.example: -------------------------------------------------------------------------------- 1 | PORT=3333 2 | HOST=0.0.0.0 3 | NODE_ENV=development 4 | APP_KEY=HVIOVZCtIc0RriD22WsCMhuoCZ-HhUU9 5 | DRIVE_DISK=local 6 | SESSION_DRIVER=cookie 7 | CACHE_VIEWS=false 8 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | coverage 4 | .vscode 5 | .DS_STORE 6 | .env 7 | tmp 8 | -------------------------------------------------------------------------------- /server/.prettierignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /server/ace: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Ace Commands 4 | |-------------------------------------------------------------------------- 5 | | 6 | | This file is the entry point for running ace commands. 7 | | 8 | */ 9 | 10 | require('reflect-metadata') 11 | require('source-map-support').install({ handleUncaughtExceptions: false }) 12 | 13 | const { Ignitor } = require('@adonisjs/core/build/standalone') 14 | new Ignitor(__dirname) 15 | .ace() 16 | .handle(process.argv.slice(2)) 17 | -------------------------------------------------------------------------------- /server/ace-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "commands": { 3 | "dump:rcfile": { 4 | "settings": {}, 5 | "commandPath": "@adonisjs/core/build/commands/DumpRc", 6 | "commandName": "dump:rcfile", 7 | "description": "Dump contents of .adonisrc.json file along with defaults", 8 | "args": [], 9 | "aliases": [], 10 | "flags": [] 11 | }, 12 | "list:routes": { 13 | "settings": { 14 | "loadApp": true, 15 | "stayAlive": true 16 | }, 17 | "commandPath": "@adonisjs/core/build/commands/ListRoutes/index", 18 | "commandName": "list:routes", 19 | "description": "List application routes", 20 | "args": [], 21 | "aliases": [], 22 | "flags": [ 23 | { 24 | "name": "verbose", 25 | "propertyName": "verbose", 26 | "type": "boolean", 27 | "description": "Display more information" 28 | }, 29 | { 30 | "name": "reverse", 31 | "propertyName": "reverse", 32 | "type": "boolean", 33 | "alias": "r", 34 | "description": "Reverse routes display" 35 | }, 36 | { 37 | "name": "methods", 38 | "propertyName": "methodsFilter", 39 | "type": "array", 40 | "alias": "m", 41 | "description": "Filter routes by method" 42 | }, 43 | { 44 | "name": "patterns", 45 | "propertyName": "patternsFilter", 46 | "type": "array", 47 | "alias": "p", 48 | "description": "Filter routes by the route pattern" 49 | }, 50 | { 51 | "name": "names", 52 | "propertyName": "namesFilter", 53 | "type": "array", 54 | "alias": "n", 55 | "description": "Filter routes by route name" 56 | }, 57 | { 58 | "name": "json", 59 | "propertyName": "json", 60 | "type": "boolean", 61 | "description": "Output as JSON" 62 | }, 63 | { 64 | "name": "table", 65 | "propertyName": "table", 66 | "type": "boolean", 67 | "description": "Output as Table" 68 | }, 69 | { 70 | "name": "max-width", 71 | "propertyName": "maxWidth", 72 | "type": "number", 73 | "description": "Specify maximum rendering width. Ignored for JSON Output" 74 | } 75 | ] 76 | }, 77 | "generate:key": { 78 | "settings": {}, 79 | "commandPath": "@adonisjs/core/build/commands/GenerateKey", 80 | "commandName": "generate:key", 81 | "description": "Generate a new APP_KEY secret", 82 | "args": [], 83 | "aliases": [], 84 | "flags": [] 85 | }, 86 | "repl": { 87 | "settings": { 88 | "loadApp": true, 89 | "environment": "repl", 90 | "stayAlive": true 91 | }, 92 | "commandPath": "@adonisjs/repl/build/commands/AdonisRepl", 93 | "commandName": "repl", 94 | "description": "Start a new REPL session", 95 | "args": [], 96 | "aliases": [], 97 | "flags": [] 98 | }, 99 | "ssr:build": { 100 | "settings": { 101 | "stayAlive": true 102 | }, 103 | "commandPath": "@eidellev/inertia-adonisjs/build/commands/Build", 104 | "commandName": "ssr:build", 105 | "description": "Build and watch files for changes", 106 | "args": [], 107 | "aliases": [], 108 | "flags": [] 109 | }, 110 | "ssr:watch": { 111 | "settings": { 112 | "stayAlive": true 113 | }, 114 | "commandPath": "@eidellev/inertia-adonisjs/build/commands/Watch", 115 | "commandName": "ssr:watch", 116 | "description": "Build and watch files for changes", 117 | "args": [], 118 | "aliases": [], 119 | "flags": [] 120 | } 121 | }, 122 | "aliases": {} 123 | } 124 | -------------------------------------------------------------------------------- /server/app/Controllers/Http/UsersController.ts: -------------------------------------------------------------------------------- 1 | import UserCreateValidator from 'App/Validators/UserCreateValidator' 2 | import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext' 3 | 4 | export default class UsersController { 5 | public async index({ inertia }: HttpContextContract) { 6 | return inertia.render('User') 7 | } 8 | 9 | public async store({ request, inertia }: HttpContextContract) { 10 | await request.validate(UserCreateValidator) 11 | 12 | await new Promise((resolve) => setTimeout(resolve, 3000)) 13 | 14 | return inertia.render('User', { success: 'Test did not fail validations.' }) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /server/app/Exceptions/Handler.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Http Exception Handler 4 | |-------------------------------------------------------------------------- 5 | | 6 | | AdonisJs will forward all exceptions occurred during an HTTP request to 7 | | the following class. You can learn more about exception handling by 8 | | reading docs. 9 | | 10 | | The exception handler extends a base `HttpExceptionHandler` which is not 11 | | mandatory, however it can do lot of heavy lifting to handle the errors 12 | | properly. 13 | | 14 | */ 15 | 16 | import Logger from '@ioc:Adonis/Core/Logger' 17 | import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler' 18 | 19 | export default class ExceptionHandler extends HttpExceptionHandler { 20 | protected statusPages = { 21 | '403': 'errors/unauthorized', 22 | '404': 'errors/not-found', 23 | '500..599': 'errors/server-error', 24 | } 25 | 26 | constructor() { 27 | super(Logger) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /server/app/Validators/UserCreateValidator.ts: -------------------------------------------------------------------------------- 1 | import { schema, rules, CustomMessages } from '@ioc:Adonis/Core/Validator' 2 | import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext' 3 | 4 | export default class UserCreateValidator { 5 | constructor(protected ctx: HttpContextContract) {} 6 | 7 | public schema = schema.create({ 8 | name: schema.string([ 9 | rules.notIn(['admin']), 10 | rules.alpha({ 11 | allow: ['space'], 12 | }), 13 | rules.minLength(4), 14 | rules.maxLength(30), 15 | rules.trim(), 16 | ]), 17 | email: schema.string([rules.email(), rules.notIn(['admin@formkit.com'])]), 18 | }) 19 | 20 | public messages: CustomMessages = {} 21 | } 22 | -------------------------------------------------------------------------------- /server/commands/index.ts: -------------------------------------------------------------------------------- 1 | import { listDirectoryFiles } from '@adonisjs/core/build/standalone' 2 | import Application from '@ioc:Adonis/Core/Application' 3 | 4 | /* 5 | |-------------------------------------------------------------------------- 6 | | Exporting an array of commands 7 | |-------------------------------------------------------------------------- 8 | | 9 | | Instead of manually exporting each file from this directory, we use the 10 | | helper `listDirectoryFiles` to recursively collect and export an array 11 | | of filenames. 12 | | 13 | | Couple of things to note: 14 | | 15 | | 1. The file path must be relative from the project root and not this directory. 16 | | 2. We must ignore this file to avoid getting into an infinite loop 17 | | 18 | */ 19 | export default listDirectoryFiles(__dirname, Application.appRoot, ['./commands/index']) 20 | -------------------------------------------------------------------------------- /server/config/app.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Config source: https://git.io/JfefZ 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this config 5 | * file. 6 | */ 7 | 8 | import proxyAddr from 'proxy-addr' 9 | import Env from '@ioc:Adonis/Core/Env' 10 | import Application from '@ioc:Adonis/Core/Application' 11 | import { ServerConfig } from '@ioc:Adonis/Core/Server' 12 | import { LoggerConfig } from '@ioc:Adonis/Core/Logger' 13 | import { ProfilerConfig } from '@ioc:Adonis/Core/Profiler' 14 | import { ValidatorConfig } from '@ioc:Adonis/Core/Validator' 15 | import { AssetsManagerConfig } from '@ioc:Adonis/Core/AssetsManager' 16 | 17 | /* 18 | |-------------------------------------------------------------------------- 19 | | Application secret key 20 | |-------------------------------------------------------------------------- 21 | | 22 | | The secret to encrypt and sign different values in your application. 23 | | Make sure to keep the `APP_KEY` as an environment variable and secure. 24 | | 25 | | Note: Changing the application key for an existing app will make all 26 | | the cookies invalid and also the existing encrypted data will not 27 | | be decrypted. 28 | | 29 | */ 30 | export const appKey: string = Env.get('APP_KEY') 31 | 32 | /* 33 | |-------------------------------------------------------------------------- 34 | | Http server configuration 35 | |-------------------------------------------------------------------------- 36 | | 37 | | The configuration for the HTTP(s) server. Make sure to go through all 38 | | the config properties to make keep server secure. 39 | | 40 | */ 41 | export const http: ServerConfig = { 42 | /* 43 | |-------------------------------------------------------------------------- 44 | | Allow method spoofing 45 | |-------------------------------------------------------------------------- 46 | | 47 | | Method spoofing enables defining custom HTTP methods using a query string 48 | | `_method`. This is usually required when you are making traditional 49 | | form requests and wants to use HTTP verbs like `PUT`, `DELETE` and 50 | | so on. 51 | | 52 | */ 53 | allowMethodSpoofing: false, 54 | 55 | /* 56 | |-------------------------------------------------------------------------- 57 | | Subdomain offset 58 | |-------------------------------------------------------------------------- 59 | */ 60 | subdomainOffset: 2, 61 | 62 | /* 63 | |-------------------------------------------------------------------------- 64 | | Request Ids 65 | |-------------------------------------------------------------------------- 66 | | 67 | | Setting this value to `true` will generate a unique request id for each 68 | | HTTP request and set it as `x-request-id` header. 69 | | 70 | */ 71 | generateRequestId: false, 72 | 73 | /* 74 | |-------------------------------------------------------------------------- 75 | | Trusting proxy servers 76 | |-------------------------------------------------------------------------- 77 | | 78 | | Define the proxy servers that AdonisJs must trust for reading `X-Forwarded` 79 | | headers. 80 | | 81 | */ 82 | trustProxy: proxyAddr.compile('loopback'), 83 | 84 | /* 85 | |-------------------------------------------------------------------------- 86 | | Generating Etag 87 | |-------------------------------------------------------------------------- 88 | | 89 | | Whether or not to generate an etag for every response. 90 | | 91 | */ 92 | etag: false, 93 | 94 | /* 95 | |-------------------------------------------------------------------------- 96 | | JSONP Callback 97 | |-------------------------------------------------------------------------- 98 | */ 99 | jsonpCallbackName: 'callback', 100 | 101 | /* 102 | |-------------------------------------------------------------------------- 103 | | Cookie settings 104 | |-------------------------------------------------------------------------- 105 | */ 106 | cookie: { 107 | domain: '', 108 | path: '/', 109 | maxAge: '2h', 110 | httpOnly: true, 111 | secure: false, 112 | sameSite: false, 113 | }, 114 | } 115 | 116 | /* 117 | |-------------------------------------------------------------------------- 118 | | Logger 119 | |-------------------------------------------------------------------------- 120 | */ 121 | export const logger: LoggerConfig = { 122 | /* 123 | |-------------------------------------------------------------------------- 124 | | Application name 125 | |-------------------------------------------------------------------------- 126 | | 127 | | The name of the application you want to add to the log. It is recommended 128 | | to always have app name in every log line. 129 | | 130 | | The `APP_NAME` environment variable is automatically set by AdonisJS by 131 | | reading the `name` property from the `package.json` file. 132 | | 133 | */ 134 | name: Env.get('APP_NAME'), 135 | 136 | /* 137 | |-------------------------------------------------------------------------- 138 | | Toggle logger 139 | |-------------------------------------------------------------------------- 140 | | 141 | | Enable or disable logger application wide 142 | | 143 | */ 144 | enabled: true, 145 | 146 | /* 147 | |-------------------------------------------------------------------------- 148 | | Logging level 149 | |-------------------------------------------------------------------------- 150 | | 151 | | The level from which you want the logger to flush logs. It is recommended 152 | | to make use of the environment variable, so that you can define log levels 153 | | at deployment level and not code level. 154 | | 155 | */ 156 | level: Env.get('LOG_LEVEL', 'info'), 157 | 158 | /* 159 | |-------------------------------------------------------------------------- 160 | | Pretty print 161 | |-------------------------------------------------------------------------- 162 | | 163 | | It is highly advised NOT to use `prettyPrint` in production, since it 164 | | can have huge impact on performance. 165 | | 166 | */ 167 | prettyPrint: Env.get('NODE_ENV') === 'development', 168 | } 169 | 170 | /* 171 | |-------------------------------------------------------------------------- 172 | | Profiler 173 | |-------------------------------------------------------------------------- 174 | */ 175 | export const profiler: ProfilerConfig = { 176 | /* 177 | |-------------------------------------------------------------------------- 178 | | Toggle profiler 179 | |-------------------------------------------------------------------------- 180 | | 181 | | Enable or disable profiler 182 | | 183 | */ 184 | enabled: true, 185 | 186 | /* 187 | |-------------------------------------------------------------------------- 188 | | Blacklist actions/row labels 189 | |-------------------------------------------------------------------------- 190 | | 191 | | Define an array of actions or row labels that you want to disable from 192 | | getting profiled. 193 | | 194 | */ 195 | blacklist: [], 196 | 197 | /* 198 | |-------------------------------------------------------------------------- 199 | | Whitelist actions/row labels 200 | |-------------------------------------------------------------------------- 201 | | 202 | | Define an array of actions or row labels that you want to whitelist for 203 | | the profiler. When whitelist is defined, then `blacklist` is ignored. 204 | | 205 | */ 206 | whitelist: [], 207 | } 208 | 209 | /* 210 | |-------------------------------------------------------------------------- 211 | | Validator 212 | |-------------------------------------------------------------------------- 213 | | 214 | | Configure the global configuration for the validator. Here's the reference 215 | | to the default config https://git.io/JT0WE 216 | | 217 | */ 218 | export const validator: ValidatorConfig = {} 219 | 220 | /* 221 | |-------------------------------------------------------------------------- 222 | | Assets 223 | |-------------------------------------------------------------------------- 224 | | 225 | | Configure the asset manager you are using to compile the frontend assets 226 | | 227 | */ 228 | export const assets: AssetsManagerConfig = { 229 | /* 230 | |-------------------------------------------------------------------------- 231 | | Driver 232 | |-------------------------------------------------------------------------- 233 | | 234 | | Currently we only support webpack encore and may introduce more drivers 235 | | in the future 236 | | 237 | */ 238 | driver: Env.get('ASSETS_DRIVER'), 239 | 240 | /* 241 | |-------------------------------------------------------------------------- 242 | | Public path 243 | |-------------------------------------------------------------------------- 244 | | 245 | | Directory to search for the "manifest.json" and the "entrypoints.json" 246 | | files 247 | | 248 | */ 249 | publicPath: Application.publicPath('assets'), 250 | 251 | /* 252 | |-------------------------------------------------------------------------- 253 | | Script tag 254 | |-------------------------------------------------------------------------- 255 | | 256 | | Define attributes for the entryPointScripts tags 257 | | 258 | */ 259 | script: { 260 | attributes: { 261 | defer: true, 262 | }, 263 | }, 264 | 265 | /* 266 | |-------------------------------------------------------------------------- 267 | | Style tag 268 | |-------------------------------------------------------------------------- 269 | | 270 | | Define attributes for the entryPointStyles tags 271 | | 272 | */ 273 | style: { 274 | attributes: {}, 275 | }, 276 | } 277 | -------------------------------------------------------------------------------- /server/config/bodyparser.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Config source: https://git.io/Jfefn 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this config 5 | * file. 6 | */ 7 | 8 | import { BodyParserConfig } from '@ioc:Adonis/Core/BodyParser' 9 | 10 | const bodyParserConfig: BodyParserConfig = { 11 | /* 12 | |-------------------------------------------------------------------------- 13 | | White listed methods 14 | |-------------------------------------------------------------------------- 15 | | 16 | | HTTP methods for which body parsing must be performed. It is a good practice 17 | | to avoid body parsing for `GET` requests. 18 | | 19 | */ 20 | whitelistedMethods: ['POST', 'PUT', 'PATCH', 'DELETE'], 21 | 22 | /* 23 | |-------------------------------------------------------------------------- 24 | | JSON parser settings 25 | |-------------------------------------------------------------------------- 26 | | 27 | | The settings for the JSON parser. The types defines the request content 28 | | types which gets processed by the JSON parser. 29 | | 30 | */ 31 | json: { 32 | encoding: 'utf-8', 33 | limit: '1mb', 34 | strict: true, 35 | types: [ 36 | 'application/json', 37 | 'application/json-patch+json', 38 | 'application/vnd.api+json', 39 | 'application/csp-report', 40 | ], 41 | }, 42 | 43 | /* 44 | |-------------------------------------------------------------------------- 45 | | Form parser settings 46 | |-------------------------------------------------------------------------- 47 | | 48 | | The settings for the `application/x-www-form-urlencoded` parser. The types 49 | | defines the request content types which gets processed by the form parser. 50 | | 51 | */ 52 | form: { 53 | encoding: 'utf-8', 54 | limit: '1mb', 55 | queryString: {}, 56 | 57 | /* 58 | |-------------------------------------------------------------------------- 59 | | Convert empty strings to null 60 | |-------------------------------------------------------------------------- 61 | | 62 | | Convert empty form fields to null. HTML forms results in field string 63 | | value when the field is left blank. This option normalizes all the blank 64 | | field values to "null" 65 | | 66 | */ 67 | convertEmptyStringsToNull: true, 68 | 69 | types: ['application/x-www-form-urlencoded'], 70 | }, 71 | 72 | /* 73 | |-------------------------------------------------------------------------- 74 | | Raw body parser settings 75 | |-------------------------------------------------------------------------- 76 | | 77 | | Raw body just reads the request body stream as a plain text, which you 78 | | can process by hand. This must be used when request body type is not 79 | | supported by the body parser. 80 | | 81 | */ 82 | raw: { 83 | encoding: 'utf-8', 84 | limit: '1mb', 85 | queryString: {}, 86 | types: ['text/*'], 87 | }, 88 | 89 | /* 90 | |-------------------------------------------------------------------------- 91 | | Multipart parser settings 92 | |-------------------------------------------------------------------------- 93 | | 94 | | The settings for the `multipart/form-data` parser. The types defines the 95 | | request content types which gets processed by the form parser. 96 | | 97 | */ 98 | multipart: { 99 | /* 100 | |-------------------------------------------------------------------------- 101 | | Auto process 102 | |-------------------------------------------------------------------------- 103 | | 104 | | The auto process option will process uploaded files and writes them to 105 | | the `tmp` folder. You can turn it off and then manually use the stream 106 | | to pipe stream to a different destination. 107 | | 108 | | It is recommended to keep `autoProcess=true`. Unless you are processing bigger 109 | | file sizes. 110 | | 111 | */ 112 | autoProcess: true, 113 | 114 | /* 115 | |-------------------------------------------------------------------------- 116 | | Files to be processed manually 117 | |-------------------------------------------------------------------------- 118 | | 119 | | You can turn off `autoProcess` for certain routes by defining 120 | | routes inside the following array. 121 | | 122 | | NOTE: Make sure the route pattern starts with a leading slash. 123 | | 124 | | Correct 125 | | ```js 126 | | /projects/:id/file 127 | | ``` 128 | | 129 | | Incorrect 130 | | ```js 131 | | projects/:id/file 132 | | ``` 133 | */ 134 | processManually: [], 135 | 136 | /* 137 | |-------------------------------------------------------------------------- 138 | | Temporary file name 139 | |-------------------------------------------------------------------------- 140 | | 141 | | When auto processing is on. We will use this method to compute the temporary 142 | | file name. AdonisJs will compute a unique `tmpPath` for you automatically, 143 | | However, you can also define your own custom method. 144 | | 145 | */ 146 | // tmpFileName () { 147 | // }, 148 | 149 | /* 150 | |-------------------------------------------------------------------------- 151 | | Encoding 152 | |-------------------------------------------------------------------------- 153 | | 154 | | Request body encoding 155 | | 156 | */ 157 | encoding: 'utf-8', 158 | 159 | /* 160 | |-------------------------------------------------------------------------- 161 | | Convert empty strings to null 162 | |-------------------------------------------------------------------------- 163 | | 164 | | Convert empty form fields to null. HTML forms results in field string 165 | | value when the field is left blank. This option normalizes all the blank 166 | | field values to "null" 167 | | 168 | */ 169 | convertEmptyStringsToNull: true, 170 | 171 | /* 172 | |-------------------------------------------------------------------------- 173 | | Max Fields 174 | |-------------------------------------------------------------------------- 175 | | 176 | | The maximum number of fields allowed in the request body. The field includes 177 | | text inputs and files both. 178 | | 179 | */ 180 | maxFields: 1000, 181 | 182 | /* 183 | |-------------------------------------------------------------------------- 184 | | Request body limit 185 | |-------------------------------------------------------------------------- 186 | | 187 | | The total limit to the multipart body. This includes all request files 188 | | and fields data. 189 | | 190 | */ 191 | limit: '20mb', 192 | 193 | /* 194 | |-------------------------------------------------------------------------- 195 | | Types 196 | |-------------------------------------------------------------------------- 197 | | 198 | | The types that will be considered and parsed as multipart body. 199 | | 200 | */ 201 | types: ['multipart/form-data'], 202 | }, 203 | } 204 | 205 | export default bodyParserConfig 206 | -------------------------------------------------------------------------------- /server/config/cors.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Config source: https://git.io/JfefC 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this config 5 | * file. 6 | */ 7 | 8 | import { CorsConfig } from '@ioc:Adonis/Core/Cors' 9 | 10 | const corsConfig: CorsConfig = { 11 | /* 12 | |-------------------------------------------------------------------------- 13 | | Enabled 14 | |-------------------------------------------------------------------------- 15 | | 16 | | A boolean to enable or disable CORS integration from your AdonisJs 17 | | application. 18 | | 19 | | Setting the value to `true` will enable the CORS for all HTTP request. However, 20 | | you can define a function to enable/disable it on per request basis as well. 21 | | 22 | */ 23 | enabled: false, 24 | 25 | // You can also use a function that return true or false. 26 | // enabled: (request) => request.url().startsWith('/api') 27 | 28 | /* 29 | |-------------------------------------------------------------------------- 30 | | Origin 31 | |-------------------------------------------------------------------------- 32 | | 33 | | Set a list of origins to be allowed for `Access-Control-Allow-Origin`. 34 | | The value can be one of the following: 35 | | 36 | | https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin 37 | | 38 | | Boolean (true) - Allow current request origin. 39 | | Boolean (false) - Disallow all. 40 | | String - Comma separated list of allowed origins. 41 | | Array - An array of allowed origins. 42 | | String (*) - A wildcard (*) to allow all request origins. 43 | | Function - Receives the current origin string and should return 44 | | one of the above values. 45 | | 46 | */ 47 | origin: true, 48 | 49 | /* 50 | |-------------------------------------------------------------------------- 51 | | Methods 52 | |-------------------------------------------------------------------------- 53 | | 54 | | An array of allowed HTTP methods for CORS. The `Access-Control-Request-Method` 55 | | is checked against the following list. 56 | | 57 | | Following is the list of default methods. Feel free to add more. 58 | */ 59 | methods: ['GET', 'HEAD', 'POST', 'PUT', 'DELETE'], 60 | 61 | /* 62 | |-------------------------------------------------------------------------- 63 | | Headers 64 | |-------------------------------------------------------------------------- 65 | | 66 | | List of headers to be allowed for `Access-Control-Allow-Headers` header. 67 | | The value can be one of the following: 68 | | 69 | | https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Headers 70 | | 71 | | Boolean(true) - Allow all headers mentioned in `Access-Control-Request-Headers`. 72 | | Boolean(false) - Disallow all headers. 73 | | String - Comma separated list of allowed headers. 74 | | Array - An array of allowed headers. 75 | | Function - Receives the current header and should return one of the above values. 76 | | 77 | */ 78 | headers: true, 79 | 80 | /* 81 | |-------------------------------------------------------------------------- 82 | | Expose Headers 83 | |-------------------------------------------------------------------------- 84 | | 85 | | A list of headers to be exposed by setting `Access-Control-Expose-Headers`. 86 | | header. By default following 6 simple response headers are exposed. 87 | | 88 | | Cache-Control 89 | | Content-Language 90 | | Content-Type 91 | | Expires 92 | | Last-Modified 93 | | Pragma 94 | | 95 | | In order to add more headers, simply define them inside the following array. 96 | | 97 | | https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers 98 | | 99 | */ 100 | exposeHeaders: [ 101 | 'cache-control', 102 | 'content-language', 103 | 'content-type', 104 | 'expires', 105 | 'last-modified', 106 | 'pragma', 107 | ], 108 | 109 | /* 110 | |-------------------------------------------------------------------------- 111 | | Credentials 112 | |-------------------------------------------------------------------------- 113 | | 114 | | Toggle `Access-Control-Allow-Credentials` header. If value is set to `true`, 115 | | then header will be set, otherwise not. 116 | | 117 | | https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials 118 | | 119 | */ 120 | credentials: true, 121 | 122 | /* 123 | |-------------------------------------------------------------------------- 124 | | MaxAge 125 | |-------------------------------------------------------------------------- 126 | | 127 | | Define `Access-Control-Max-Age` header in seconds. 128 | | https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age 129 | | 130 | */ 131 | maxAge: 90, 132 | } 133 | 134 | export default corsConfig 135 | -------------------------------------------------------------------------------- /server/config/drive.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Config source: https://git.io/JBt3o 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this config 5 | * file. 6 | */ 7 | 8 | import Env from '@ioc:Adonis/Core/Env' 9 | import { driveConfig } from '@adonisjs/core/build/config' 10 | import Application from '@ioc:Adonis/Core/Application' 11 | 12 | /* 13 | |-------------------------------------------------------------------------- 14 | | Drive Config 15 | |-------------------------------------------------------------------------- 16 | | 17 | | The `DriveConfig` relies on the `DisksList` interface which is 18 | | defined inside the `contracts` directory. 19 | | 20 | */ 21 | export default driveConfig({ 22 | /* 23 | |-------------------------------------------------------------------------- 24 | | Default disk 25 | |-------------------------------------------------------------------------- 26 | | 27 | | The default disk to use for managing file uploads. The value is driven by 28 | | the `DRIVE_DISK` environment variable. 29 | | 30 | */ 31 | disk: Env.get('DRIVE_DISK'), 32 | 33 | disks: { 34 | /* 35 | |-------------------------------------------------------------------------- 36 | | Local 37 | |-------------------------------------------------------------------------- 38 | | 39 | | Uses the local file system to manage files. Make sure to turn off serving 40 | | files when not using this disk. 41 | | 42 | */ 43 | local: { 44 | driver: 'local', 45 | visibility: 'public', 46 | 47 | /* 48 | |-------------------------------------------------------------------------- 49 | | Storage root - Local driver only 50 | |-------------------------------------------------------------------------- 51 | | 52 | | Define an absolute path to the storage directory from where to read the 53 | | files. 54 | | 55 | */ 56 | root: Application.tmpPath('uploads'), 57 | 58 | /* 59 | |-------------------------------------------------------------------------- 60 | | Serve files - Local driver only 61 | |-------------------------------------------------------------------------- 62 | | 63 | | When this is set to true, AdonisJS will configure a files server to serve 64 | | files from the disk root. This is done to mimic the behavior of cloud 65 | | storage services that has inbuilt capabilities to serve files. 66 | | 67 | */ 68 | serveFiles: true, 69 | 70 | /* 71 | |-------------------------------------------------------------------------- 72 | | Base path - Local driver only 73 | |-------------------------------------------------------------------------- 74 | | 75 | | Base path is always required when "serveFiles = true". Also make sure 76 | | the `basePath` is unique across all the disks using "local" driver and 77 | | you are not registering routes with this prefix. 78 | | 79 | */ 80 | basePath: '/uploads', 81 | }, 82 | 83 | /* 84 | |-------------------------------------------------------------------------- 85 | | S3 Driver 86 | |-------------------------------------------------------------------------- 87 | | 88 | | Uses the S3 cloud storage to manage files. Make sure to install the s3 89 | | drive separately when using it. 90 | | 91 | |************************************************************************** 92 | | npm i @adonisjs/drive-s3 93 | |************************************************************************** 94 | | 95 | */ 96 | // s3: { 97 | // driver: 's3', 98 | // visibility: 'public', 99 | // key: Env.get('S3_KEY'), 100 | // secret: Env.get('S3_SECRET'), 101 | // region: Env.get('S3_REGION'), 102 | // bucket: Env.get('S3_BUCKET'), 103 | // endpoint: Env.get('S3_ENDPOINT'), 104 | // 105 | // // For minio to work 106 | // // forcePathStyle: true, 107 | // }, 108 | 109 | /* 110 | |-------------------------------------------------------------------------- 111 | | GCS Driver 112 | |-------------------------------------------------------------------------- 113 | | 114 | | Uses the Google cloud storage to manage files. Make sure to install the GCS 115 | | drive separately when using it. 116 | | 117 | |************************************************************************** 118 | | npm i @adonisjs/drive-gcs 119 | |************************************************************************** 120 | | 121 | */ 122 | // gcs: { 123 | // driver: 'gcs', 124 | // visibility: 'public', 125 | // keyFilename: Env.get('GCS_KEY_FILENAME'), 126 | // bucket: Env.get('GCS_BUCKET'), 127 | 128 | /* 129 | |-------------------------------------------------------------------------- 130 | | Uniform ACL - Google cloud storage only 131 | |-------------------------------------------------------------------------- 132 | | 133 | | When using the Uniform ACL on the bucket, the "visibility" option is 134 | | ignored. Since, the files ACL is managed by the google bucket policies 135 | | directly. 136 | | 137 | |************************************************************************** 138 | | Learn more: https://cloud.google.com/storage/docs/uniform-bucket-level-access 139 | |************************************************************************** 140 | | 141 | | The following option just informs drive whether your bucket is using uniform 142 | | ACL or not. The actual setting needs to be toggled within the Google cloud 143 | | console. 144 | | 145 | */ 146 | // usingUniformAcl: false, 147 | // }, 148 | }, 149 | }) 150 | -------------------------------------------------------------------------------- /server/config/hash.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Config source: https://git.io/JfefW 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this config 5 | * file. 6 | */ 7 | 8 | import Env from '@ioc:Adonis/Core/Env' 9 | import { hashConfig } from '@adonisjs/core/build/config' 10 | 11 | /* 12 | |-------------------------------------------------------------------------- 13 | | Hash Config 14 | |-------------------------------------------------------------------------- 15 | | 16 | | The `HashConfig` relies on the `HashList` interface which is 17 | | defined inside `contracts` directory. 18 | | 19 | */ 20 | export default hashConfig({ 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Default hasher 24 | |-------------------------------------------------------------------------- 25 | | 26 | | By default we make use of the argon hasher to hash values. However, feel 27 | | free to change the default value 28 | | 29 | */ 30 | default: Env.get('HASH_DRIVER', 'argon'), 31 | 32 | list: { 33 | /* 34 | |-------------------------------------------------------------------------- 35 | | Argon 36 | |-------------------------------------------------------------------------- 37 | | 38 | | Argon mapping uses the `argon2` driver to hash values. 39 | | 40 | | Make sure you install the underlying dependency for this driver to work. 41 | | https://www.npmjs.com/package/phc-argon2. 42 | | 43 | | npm install phc-argon2 44 | | 45 | */ 46 | argon: { 47 | driver: 'argon2', 48 | variant: 'id', 49 | iterations: 3, 50 | memory: 4096, 51 | parallelism: 1, 52 | saltSize: 16, 53 | }, 54 | 55 | /* 56 | |-------------------------------------------------------------------------- 57 | | Bcrypt 58 | |-------------------------------------------------------------------------- 59 | | 60 | | Bcrypt mapping uses the `bcrypt` driver to hash values. 61 | | 62 | | Make sure you install the underlying dependency for this driver to work. 63 | | https://www.npmjs.com/package/phc-bcrypt. 64 | | 65 | | npm install phc-bcrypt 66 | | 67 | */ 68 | bcrypt: { 69 | driver: 'bcrypt', 70 | rounds: 10, 71 | }, 72 | }, 73 | }) 74 | -------------------------------------------------------------------------------- /server/config/inertia.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Feel free to let me know via PR, 3 | * if you find something broken in this config file. 4 | */ 5 | 6 | import { InertiaConfig } from '@ioc:EidelLev/Inertia' 7 | 8 | /* 9 | |-------------------------------------------------------------------------- 10 | | Inertia-AdonisJS config 11 | |-------------------------------------------------------------------------- 12 | | 13 | */ 14 | 15 | export const inertia: InertiaConfig = { 16 | view: 'app', 17 | } 18 | -------------------------------------------------------------------------------- /server/config/session.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Config source: https://git.io/JeYHp 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this config 5 | * file. 6 | */ 7 | 8 | import Env from '@ioc:Adonis/Core/Env' 9 | import Application from '@ioc:Adonis/Core/Application' 10 | import { sessionConfig } from '@adonisjs/session/build/config' 11 | 12 | export default sessionConfig({ 13 | /* 14 | |-------------------------------------------------------------------------- 15 | | Enable/Disable sessions 16 | |-------------------------------------------------------------------------- 17 | | 18 | | Setting the following property to "false" will disable the session for the 19 | | entire application 20 | | 21 | */ 22 | enabled: true, 23 | 24 | /* 25 | |-------------------------------------------------------------------------- 26 | | Driver 27 | |-------------------------------------------------------------------------- 28 | | 29 | | The session driver to use. You can choose between one of the following 30 | | drivers. 31 | | 32 | | - cookie (Uses signed cookies to store session values) 33 | | - file (Uses filesystem to store session values) 34 | | - redis (Uses redis. Make sure to install "@adonisjs/redis" as well) 35 | | 36 | | Note: Switching drivers will make existing sessions invalid. 37 | | 38 | */ 39 | driver: Env.get('SESSION_DRIVER'), 40 | 41 | /* 42 | |-------------------------------------------------------------------------- 43 | | Cookie name 44 | |-------------------------------------------------------------------------- 45 | | 46 | | The name of the cookie that will hold the session id. 47 | | 48 | */ 49 | cookieName: 'adonis-session', 50 | 51 | /* 52 | |-------------------------------------------------------------------------- 53 | | Clear session when browser closes 54 | |-------------------------------------------------------------------------- 55 | | 56 | | Whether or not you want to destroy the session when browser closes. Setting 57 | | this value to `true` will ignore the `age`. 58 | | 59 | */ 60 | clearWithBrowser: false, 61 | 62 | /* 63 | |-------------------------------------------------------------------------- 64 | | Session age 65 | |-------------------------------------------------------------------------- 66 | | 67 | | The duration for which session stays active after no activity. A new HTTP 68 | | request to the server is considered as activity. 69 | | 70 | | The value can be a number in milliseconds or a string that must be valid 71 | | as per https://npmjs.org/package/ms package. 72 | | 73 | | Example: `2 days`, `2.5 hrs`, `1y`, `5s` and so on. 74 | | 75 | */ 76 | age: '2h', 77 | 78 | /* 79 | |-------------------------------------------------------------------------- 80 | | Cookie values 81 | |-------------------------------------------------------------------------- 82 | | 83 | | The cookie settings are used to setup the session id cookie and also the 84 | | driver will use the same values. 85 | | 86 | */ 87 | cookie: { 88 | path: '/', 89 | httpOnly: true, 90 | sameSite: false, 91 | }, 92 | 93 | /* 94 | |-------------------------------------------------------------------------- 95 | | Configuration for the file driver 96 | |-------------------------------------------------------------------------- 97 | | 98 | | The file driver needs absolute path to the directory in which sessions 99 | | must be stored. 100 | | 101 | */ 102 | file: { 103 | location: Application.tmpPath('sessions'), 104 | }, 105 | 106 | /* 107 | |-------------------------------------------------------------------------- 108 | | Redis driver 109 | |-------------------------------------------------------------------------- 110 | | 111 | | The redis connection you want session driver to use. The same connection 112 | | must be defined inside `config/redis.ts` file as well. 113 | | 114 | */ 115 | redisConnection: 'local', 116 | }) 117 | -------------------------------------------------------------------------------- /server/config/shield.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Config source: https://git.io/Jvwvt 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this config 5 | * file. 6 | */ 7 | 8 | import Env from '@ioc:Adonis/Core/Env' 9 | import { ShieldConfig } from '@ioc:Adonis/Addons/Shield' 10 | 11 | /* 12 | |-------------------------------------------------------------------------- 13 | | Content Security Policy 14 | |-------------------------------------------------------------------------- 15 | | 16 | | Content security policy filters out the origins not allowed to execute 17 | | and load resources like scripts, styles and fonts. There are wide 18 | | variety of options to choose from. 19 | */ 20 | export const csp: ShieldConfig['csp'] = { 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Enable/disable CSP 24 | |-------------------------------------------------------------------------- 25 | | 26 | | The CSP rules are disabled by default for seamless onboarding. 27 | | 28 | */ 29 | enabled: false, 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Directives 34 | |-------------------------------------------------------------------------- 35 | | 36 | | All directives are defined in camelCase and here is the list of 37 | | available directives and their possible values. 38 | | 39 | | https://content-security-policy.com 40 | | 41 | | @example 42 | | directives: { 43 | | defaultSrc: ["'self'", '@nonce', 'cdnjs.cloudflare.com'] 44 | | } 45 | | 46 | */ 47 | directives: {}, 48 | 49 | /* 50 | |-------------------------------------------------------------------------- 51 | | Report only 52 | |-------------------------------------------------------------------------- 53 | | 54 | | Setting `reportOnly=true` will not block the scripts from running and 55 | | instead report them to a URL. 56 | | 57 | */ 58 | reportOnly: false, 59 | } 60 | 61 | /* 62 | |-------------------------------------------------------------------------- 63 | | CSRF Protection 64 | |-------------------------------------------------------------------------- 65 | | 66 | | CSRF Protection adds another layer of security by making sure, actionable 67 | | routes does have a valid token to execute an action. 68 | | 69 | */ 70 | export const csrf: ShieldConfig['csrf'] = { 71 | /* 72 | |-------------------------------------------------------------------------- 73 | | Enable/Disable CSRF 74 | |-------------------------------------------------------------------------- 75 | */ 76 | enabled: true, 77 | 78 | /* 79 | |-------------------------------------------------------------------------- 80 | | Routes to Ignore 81 | |-------------------------------------------------------------------------- 82 | | 83 | | Define an array of route patterns that you want to ignore from CSRF 84 | | validation. Make sure the route patterns are started with a leading 85 | | slash. Example: 86 | | 87 | | `/foo/bar` 88 | | 89 | | Also you can define a function that is evaluated on every HTTP Request. 90 | | ``` 91 | | exceptRoutes: ({ request }) => request.url().includes('/api') 92 | | ``` 93 | | 94 | */ 95 | exceptRoutes: [], 96 | 97 | /* 98 | |-------------------------------------------------------------------------- 99 | | Enable Sharing Token Via Cookie 100 | |-------------------------------------------------------------------------- 101 | | 102 | | When the following flag is enabled, AdonisJS will drop `XSRF-TOKEN` 103 | | cookie that frontend frameworks can read and return back as a 104 | | `X-XSRF-TOKEN` header. 105 | | 106 | | The cookie has `httpOnly` flag set to false, so it is little insecure and 107 | | can be turned off when you are not using a frontend framework making 108 | | AJAX requests. 109 | | 110 | */ 111 | enableXsrfCookie: true, 112 | 113 | /* 114 | |-------------------------------------------------------------------------- 115 | | Methods to Validate 116 | |-------------------------------------------------------------------------- 117 | | 118 | | Define an array of HTTP methods to be validated for a valid CSRF token. 119 | | 120 | */ 121 | methods: ['POST', 'PUT', 'PATCH', 'DELETE'], 122 | } 123 | 124 | /* 125 | |-------------------------------------------------------------------------- 126 | | DNS Prefetching 127 | |-------------------------------------------------------------------------- 128 | | 129 | | DNS prefetching allows browsers to proactively perform domain name 130 | | resolution in background. 131 | | 132 | | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control 133 | | 134 | */ 135 | export const dnsPrefetch: ShieldConfig['dnsPrefetch'] = { 136 | /* 137 | |-------------------------------------------------------------------------- 138 | | Enable/disable this feature 139 | |-------------------------------------------------------------------------- 140 | */ 141 | enabled: true, 142 | 143 | /* 144 | |-------------------------------------------------------------------------- 145 | | Allow or Dis-Allow Explicitly 146 | |-------------------------------------------------------------------------- 147 | | 148 | | The `enabled` boolean does not set `X-DNS-Prefetch-Control` header. However 149 | | the `allow` boolean controls the value of `X-DNS-Prefetch-Control` header. 150 | | 151 | | - When `allow = true`, then `X-DNS-Prefetch-Control = 'on'` 152 | | - When `allow = false`, then `X-DNS-Prefetch-Control = 'off'` 153 | | 154 | */ 155 | allow: true, 156 | } 157 | 158 | /* 159 | |-------------------------------------------------------------------------- 160 | | Iframe Options 161 | |-------------------------------------------------------------------------- 162 | | 163 | | xFrame defines whether or not your website can be embedded inside an 164 | | iframe. Choose from one of the following options. 165 | | 166 | | - DENY 167 | | - SAMEORIGIN 168 | | - ALLOW-FROM http://example.com 169 | | 170 | | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options 171 | */ 172 | export const xFrame: ShieldConfig['xFrame'] = { 173 | enabled: true, 174 | action: 'DENY', 175 | } 176 | 177 | /* 178 | |-------------------------------------------------------------------------- 179 | | Http Strict Transport Security 180 | |-------------------------------------------------------------------------- 181 | | 182 | | A security to ensure that a browser always makes a connection over 183 | | HTTPS. 184 | | 185 | | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security 186 | | 187 | */ 188 | export const hsts: ShieldConfig['hsts'] = { 189 | enabled: true, 190 | /* 191 | |-------------------------------------------------------------------------- 192 | | Max Age 193 | |-------------------------------------------------------------------------- 194 | | 195 | | Control, how long the browser should remember that a site is only to be 196 | | accessed using HTTPS. 197 | | 198 | */ 199 | maxAge: '180 days', 200 | 201 | /* 202 | |-------------------------------------------------------------------------- 203 | | Include Subdomains 204 | |-------------------------------------------------------------------------- 205 | | 206 | | Apply rules on the subdomains as well. 207 | | 208 | */ 209 | includeSubDomains: true, 210 | 211 | /* 212 | |-------------------------------------------------------------------------- 213 | | Preloading 214 | |-------------------------------------------------------------------------- 215 | | 216 | | Google maintains a service to register your domain and it will preload 217 | | the HSTS policy. Learn more https://hstspreload.org/ 218 | | 219 | */ 220 | preload: false, 221 | } 222 | 223 | /* 224 | |-------------------------------------------------------------------------- 225 | | No Sniff 226 | |-------------------------------------------------------------------------- 227 | | 228 | | Browsers have a habit of sniffing content-type of a response. Which means 229 | | files with .txt extension containing Javascript code will be executed as 230 | | Javascript. You can disable this behavior by setting nosniff to false. 231 | | 232 | | Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options 233 | | 234 | */ 235 | export const contentTypeSniffing: ShieldConfig['contentTypeSniffing'] = { 236 | enabled: true, 237 | } 238 | -------------------------------------------------------------------------------- /server/config/static.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Config source: https://git.io/Jfefl 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this config 5 | * file. 6 | */ 7 | 8 | import { AssetsConfig } from '@ioc:Adonis/Core/Static' 9 | 10 | const staticConfig: AssetsConfig = { 11 | /* 12 | |-------------------------------------------------------------------------- 13 | | Enabled 14 | |-------------------------------------------------------------------------- 15 | | 16 | | A boolean to enable or disable serving static files. The static files 17 | | are served from the `public` directory inside the application root. 18 | | However, you can override the default path inside `.adonisrc.json` 19 | | file. 20 | | 21 | | 22 | */ 23 | enabled: true, 24 | 25 | /* 26 | |-------------------------------------------------------------------------- 27 | | Handling Dot Files 28 | |-------------------------------------------------------------------------- 29 | | 30 | | Decide how you want the static assets server to handle the `dotfiles`. 31 | | By default, we ignore them as if they don't exists. However, you 32 | | can choose between one of the following options. 33 | | 34 | | - ignore: Behave as if the file doesn't exists. Results in 404. 35 | | - deny: Deny access to the file. Results in 403. 36 | | - allow: Serve the file contents 37 | | 38 | */ 39 | dotFiles: 'ignore', 40 | 41 | /* 42 | |-------------------------------------------------------------------------- 43 | | Generating Etag 44 | |-------------------------------------------------------------------------- 45 | | 46 | | Handle whether or not to generate etags for the files. Etag allows browser 47 | | to utilize the cache when file hasn't been changed. 48 | | 49 | */ 50 | etag: true, 51 | 52 | /* 53 | |-------------------------------------------------------------------------- 54 | | Set Last Modified 55 | |-------------------------------------------------------------------------- 56 | | 57 | | Whether or not to set the `Last-Modified` header in the response. Uses 58 | | the file system's last modified value. 59 | | 60 | */ 61 | lastModified: true, 62 | 63 | /* 64 | |-------------------------------------------------------------------------- 65 | | Max age 66 | |-------------------------------------------------------------------------- 67 | | 68 | | Set the value for the max-age directive. Set a higher value in production 69 | | if you fingerprint your assets. 70 | | 71 | | Learn more: https://docs.adonisjs.com/guides/deployment#serving-static-assets 72 | | 73 | */ 74 | maxAge: 0, 75 | 76 | /* 77 | |-------------------------------------------------------------------------- 78 | | Immutable 79 | |-------------------------------------------------------------------------- 80 | | 81 | | Set the immutable directive. Set it to `true` if the assets are generated 82 | | with a fingerprint. In others words the file name changes when the file 83 | | contents change. 84 | | 85 | */ 86 | immutable: false, 87 | } 88 | 89 | export default staticConfig 90 | -------------------------------------------------------------------------------- /server/contracts/drive.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Contract source: https://git.io/JBt3I 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this contract 5 | * file. 6 | */ 7 | 8 | import { InferDisksFromConfig } from '@adonisjs/core/build/config' 9 | import driveConfig from '../config/drive' 10 | 11 | declare module '@ioc:Adonis/Core/Drive' { 12 | interface DisksList extends InferDisksFromConfig {} 13 | } 14 | -------------------------------------------------------------------------------- /server/contracts/env.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Contract source: https://git.io/JTm6U 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this contract 5 | * file. 6 | */ 7 | 8 | declare module '@ioc:Adonis/Core/Env' { 9 | /* 10 | |-------------------------------------------------------------------------- 11 | | Getting types for validated environment variables 12 | |-------------------------------------------------------------------------- 13 | | 14 | | The `default` export from the "../env.ts" file exports types for the 15 | | validated environment variables. Here we merge them with the `EnvTypes` 16 | | interface so that you can enjoy intellisense when using the "Env" 17 | | module. 18 | | 19 | */ 20 | 21 | type CustomTypes = typeof import('../env').default 22 | interface EnvTypes extends CustomTypes {} 23 | } 24 | -------------------------------------------------------------------------------- /server/contracts/events.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Contract source: https://git.io/JfefG 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this contract 5 | * file. 6 | */ 7 | 8 | declare module '@ioc:Adonis/Core/Event' { 9 | /* 10 | |-------------------------------------------------------------------------- 11 | | Define typed events 12 | |-------------------------------------------------------------------------- 13 | | 14 | | You can define types for events inside the following interface and 15 | | AdonisJS will make sure that all listeners and emit calls adheres 16 | | to the defined types. 17 | | 18 | | For example: 19 | | 20 | | interface EventsList { 21 | | 'new:user': UserModel 22 | | } 23 | | 24 | | Now calling `Event.emit('new:user')` will statically ensure that passed value is 25 | | an instance of the the UserModel only. 26 | | 27 | */ 28 | interface EventsList {} 29 | } 30 | -------------------------------------------------------------------------------- /server/contracts/hash.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Contract source: https://git.io/Jfefs 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this contract 5 | * file. 6 | */ 7 | 8 | import { InferListFromConfig } from '@adonisjs/core/build/config' 9 | import hashConfig from '../config/hash' 10 | 11 | declare module '@ioc:Adonis/Core/Hash' { 12 | interface HashersList extends InferListFromConfig {} 13 | } 14 | -------------------------------------------------------------------------------- /server/contracts/tests.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Contract source: https://bit.ly/3DP1ypf 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this contract 5 | * file. 6 | */ 7 | 8 | import '@japa/runner' 9 | 10 | declare module '@japa/runner' { 11 | interface TestContext { 12 | // Extend context 13 | } 14 | 15 | interface Test { 16 | // Extend test 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /server/env.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Validating Environment Variables 4 | |-------------------------------------------------------------------------- 5 | | 6 | | In this file we define the rules for validating environment variables. 7 | | By performing validation we ensure that your application is running in 8 | | a stable environment with correct configuration values. 9 | | 10 | | This file is read automatically by the framework during the boot lifecycle 11 | | and hence do not rename or move this file to a different location. 12 | | 13 | */ 14 | 15 | import Env from '@ioc:Adonis/Core/Env' 16 | 17 | export default Env.rules({ 18 | HOST: Env.schema.string({ format: 'host' }), 19 | PORT: Env.schema.number(), 20 | APP_KEY: Env.schema.string(), 21 | APP_NAME: Env.schema.string(), 22 | CACHE_VIEWS: Env.schema.boolean(), 23 | SESSION_DRIVER: Env.schema.string(), 24 | DRIVE_DISK: Env.schema.enum(['local'] as const), 25 | NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const), 26 | }) 27 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "ace": "node ace", 5 | "dev": "node ace serve --watch", 6 | "build": "node ace build --production", 7 | "start": "node server.js", 8 | "lint": "eslint . --ext=.ts", 9 | "format": "prettier --write ." 10 | }, 11 | "eslintConfig": { 12 | "extends": [ 13 | "plugin:adonis/typescriptApp", 14 | "prettier" 15 | ], 16 | "plugins": [ 17 | "prettier" 18 | ], 19 | "rules": { 20 | "prettier/prettier": [ 21 | "error" 22 | ] 23 | } 24 | }, 25 | "eslintIgnore": [ 26 | "build" 27 | ], 28 | "prettier": { 29 | "trailingComma": "es5", 30 | "semi": false, 31 | "singleQuote": true, 32 | "useTabs": false, 33 | "quoteProps": "consistent", 34 | "bracketSpacing": true, 35 | "arrowParens": "always", 36 | "printWidth": 100 37 | }, 38 | "devDependencies": { 39 | "@adonisjs/assembler": "^5.9.3", 40 | "@babel/core": "^7.19.6", 41 | "@babel/preset-env": "^7.19.4", 42 | "@japa/preset-adonis": "^1.2.0", 43 | "@japa/runner": "^2.2.2", 44 | "@symfony/webpack-encore": "^4.1.1", 45 | "@types/node": "^18.11.3", 46 | "adonis-preset-ts": "^2.1.0", 47 | "eslint": "^8.26.0", 48 | "eslint-config-prettier": "^8.5.0", 49 | "eslint-plugin-adonis": "^2.1.1", 50 | "eslint-plugin-prettier": "^4.2.1", 51 | "pino-pretty": "^9.1.1", 52 | "prettier": "^2.7.1", 53 | "typescript": "~4.6", 54 | "webpack": "^5.74.0", 55 | "webpack-cli": "^4.10.0", 56 | "webpack-node-externals": "^3.0.0", 57 | "youch": "^3.2.2", 58 | "youch-terminal": "^2.1.5" 59 | }, 60 | "dependencies": { 61 | "@adonisjs/core": "^5.8.8", 62 | "@adonisjs/repl": "^3.1.11", 63 | "@adonisjs/session": "^6.4.0", 64 | "@adonisjs/shield": "^7.1.0", 65 | "@adonisjs/view": "^6.2.0", 66 | "@eidellev/inertia-adonisjs": "^7.2.0", 67 | "@formkit/themes": "^1.0.0-beta.12", 68 | "@formkit/vue": "^1.0.0-beta.12", 69 | "@inertiajs/vue3": "^1.0.0-beta.2", 70 | "@vue/compiler-sfc": "^3.2.41", 71 | "@vue/server-renderer": "^3.2.41", 72 | "@vue/tsconfig": "^0.1.3", 73 | "proxy-addr": "^2.0.7", 74 | "reflect-metadata": "^0.1.13", 75 | "source-map-support": "^0.5.21", 76 | "ts-loader": "^9.4.1", 77 | "vue": "^3.2.41", 78 | "vue-loader": "^17.0.0", 79 | "vue-toastification": "^2.0.0-rc.5" 80 | } 81 | } 82 | 83 | -------------------------------------------------------------------------------- /server/providers/AppProvider.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationContract } from '@ioc:Adonis/Core/Application' 2 | 3 | export default class AppProvider { 4 | constructor(protected app: ApplicationContract) {} 5 | 6 | public register() { 7 | // Register your own bindings 8 | } 9 | 10 | public async boot() { 11 | // IoC container is ready 12 | } 13 | 14 | public async ready() { 15 | // App is ready 16 | } 17 | 18 | public async shutdown() { 19 | // Cleanup, since app is going down 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /server/public/assets/entrypoints.json: -------------------------------------------------------------------------------- 1 | { 2 | "entrypoints": { 3 | "app": { 4 | "css": [ 5 | "http://localhost:8080/assets/app.css" 6 | ], 7 | "js": [ 8 | "http://localhost:8080/assets/app.js" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /server/public/assets/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "assets/app.css": "http://localhost:8080/assets/app.css", 3 | "assets/app.js": "http://localhost:8080/assets/app.js" 4 | } -------------------------------------------------------------------------------- /server/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fenilli/formkit-addon-inertia/56873d95ce1e6dac5c362a07d3b98274d6bd4bbf/server/public/favicon.ico -------------------------------------------------------------------------------- /server/resources/css/app.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap'); 2 | 3 | html, body { 4 | background-color: #F7F8FA; 5 | font-family: 'Poppins', sans-serif; 6 | height: 100vh; 7 | color: #46444c; 8 | position: relative; 9 | } 10 | 11 | body:before { 12 | content: ''; 13 | background: #5A45FF; 14 | top: 0; 15 | left: 0; 16 | right: 0; 17 | height: 6px; 18 | position: absolute; 19 | } 20 | 21 | * { 22 | margin: 0; 23 | padding: 0; 24 | } 25 | 26 | a { 27 | color: #5A45FF; 28 | text-decoration: none; 29 | } 30 | 31 | main { 32 | max-width: 620px; 33 | margin: auto; 34 | height: 100vh; 35 | padding: 0 30px; 36 | align-items: center; 37 | display: flex; 38 | justify-content: center; 39 | } 40 | 41 | .title { 42 | font-size: 50px; 43 | line-height: 50px; 44 | margin-bottom: 10px; 45 | color: #17161A; 46 | } 47 | 48 | .subtitle { 49 | font-size: 26px; 50 | margin-bottom: 40px; 51 | } 52 | 53 | p { 54 | margin-bottom: 20px; 55 | } 56 | 57 | main ul { 58 | list-style: none; 59 | } 60 | 61 | main li { 62 | margin-bottom: 5px; 63 | position: relative; 64 | padding-left: 25px; 65 | } 66 | 67 | main li:before { 68 | content: '—'; 69 | position: absolute; 70 | left: 0; 71 | } 72 | 73 | main code { 74 | font-size: 16px; 75 | background: #e6e2ff; 76 | } 77 | -------------------------------------------------------------------------------- /server/resources/js/Pages/User.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 41 | 42 | 49 | -------------------------------------------------------------------------------- /server/resources/js/app.js: -------------------------------------------------------------------------------- 1 | import '../css/app.css' 2 | import 'vue-toastification/dist/index.css' 3 | import '@formkit/themes/genesis' 4 | 5 | import { createApp, h } from 'vue' 6 | import { createInertiaApp } from '@inertiajs/vue3' 7 | import { plugin as formkitPlugin, defaultConfig } from '@formkit/vue' 8 | import { plugin as inertiaPlugin } from 'formkit-addon-inertia' 9 | import Toast from 'vue-toastification' 10 | 11 | createInertiaApp({ 12 | resolve: (name) => require(`./Pages/${name}`), 13 | setup({ el, App, props, plugin }) { 14 | createApp({ render: () => h(App, props) }) 15 | .use(plugin) 16 | .use( 17 | formkitPlugin, 18 | defaultConfig({ 19 | plugins: [inertiaPlugin], 20 | }) 21 | ) 22 | .use(Toast) 23 | .mount(el) 24 | }, 25 | }) 26 | -------------------------------------------------------------------------------- /server/resources/js/vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import type { DefineComponent } from 'vue' 3 | const component: DefineComponent<{}, {}, any> 4 | export default component 5 | } 6 | -------------------------------------------------------------------------------- /server/resources/views/app.edge: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | @entryPointStyles('app') 9 | @entryPointScripts('app') 10 | 11 | server 12 | @inertiaHead 13 | 14 | 15 | @inertia 16 | 17 | 18 | -------------------------------------------------------------------------------- /server/server.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | AdonisJs Server 4 | |-------------------------------------------------------------------------- 5 | | 6 | | The contents in this file is meant to bootstrap the AdonisJs application 7 | | and start the HTTP server to accept incoming connections. You must avoid 8 | | making this file dirty and instead make use of `lifecycle hooks` provided 9 | | by AdonisJs service providers for custom code. 10 | | 11 | */ 12 | 13 | import 'reflect-metadata' 14 | import sourceMapSupport from 'source-map-support' 15 | import { Ignitor } from '@adonisjs/core/build/standalone' 16 | 17 | sourceMapSupport.install({ handleUncaughtExceptions: false }) 18 | 19 | new Ignitor(__dirname).httpServer().start() 20 | -------------------------------------------------------------------------------- /server/start/inertia.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Inertia Preloaded File 4 | |-------------------------------------------------------------------------- 5 | | 6 | | Any code written inside this file will be executed during the application 7 | | boot. 8 | | 9 | */ 10 | 11 | import Inertia from '@ioc:EidelLev/Inertia'; 12 | 13 | Inertia.share({ 14 | errors: (ctx) => { 15 | return ctx.session.flashMessages.get('errors'); 16 | }, 17 | }).version(() => Inertia.manifestFile('public/assets/manifest.json')); 18 | -------------------------------------------------------------------------------- /server/start/kernel.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Application middleware 4 | |-------------------------------------------------------------------------- 5 | | 6 | | This file is used to define middleware for HTTP requests. You can register 7 | | middleware as a `closure` or an IoC container binding. The bindings are 8 | | preferred, since they keep this file clean. 9 | | 10 | */ 11 | 12 | import Server from '@ioc:Adonis/Core/Server' 13 | 14 | /* 15 | |-------------------------------------------------------------------------- 16 | | Global middleware 17 | |-------------------------------------------------------------------------- 18 | | 19 | | An array of global middleware, that will be executed in the order they 20 | | are defined for every HTTP requests. 21 | | 22 | */ 23 | Server.middleware.register([ 24 | () => import('@ioc:Adonis/Core/BodyParser'), 25 | () => import('@ioc:EidelLev/Inertia/Middleware'), 26 | ]) 27 | 28 | /* 29 | |-------------------------------------------------------------------------- 30 | | Named middleware 31 | |-------------------------------------------------------------------------- 32 | | 33 | | Named middleware are defined as key-value pair. The value is the namespace 34 | | or middleware function and key is the alias. Later you can use these 35 | | alias on individual routes. For example: 36 | | 37 | | { auth: () => import('App/Middleware/Auth') } 38 | | 39 | | and then use it as follows 40 | | 41 | | Route.get('dashboard', 'UserController.dashboard').middleware('auth') 42 | | 43 | */ 44 | Server.middleware.registerNamed({}) 45 | -------------------------------------------------------------------------------- /server/start/routes.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Routes 4 | |-------------------------------------------------------------------------- 5 | | 6 | | This file is dedicated for defining HTTP routes. A single file is enough 7 | | for majority of projects, however you can define routes in different 8 | | files and just make sure to import them inside this file. For example 9 | | 10 | | Define routes in following two files 11 | | ├── start/routes/cart.ts 12 | | ├── start/routes/customer.ts 13 | | 14 | | and then import them inside `start/routes.ts` as follows 15 | | 16 | | import './routes/cart' 17 | | import './routes/customer'' 18 | | 19 | */ 20 | 21 | import Route from '@ioc:Adonis/Core/Route' 22 | 23 | Route.on('/').redirect('/users') 24 | Route.get('/users', 'UsersController.index') 25 | 26 | Route.post('/users', 'UsersController.store') 27 | -------------------------------------------------------------------------------- /server/test.ts: -------------------------------------------------------------------------------- 1 | /* 2 | |-------------------------------------------------------------------------- 3 | | Tests 4 | |-------------------------------------------------------------------------- 5 | | 6 | | The contents in this file boots the AdonisJS application and configures 7 | | the Japa tests runner. 8 | | 9 | | For the most part you will never edit this file. The configuration 10 | | for the tests can be controlled via ".adonisrc.json" and 11 | | "tests/bootstrap.ts" files. 12 | | 13 | */ 14 | 15 | process.env.NODE_ENV = 'test' 16 | 17 | import 'reflect-metadata' 18 | import sourceMapSupport from 'source-map-support' 19 | import { Ignitor } from '@adonisjs/core/build/standalone' 20 | import { configure, processCliArgs, run, RunnerHooksHandler } from '@japa/runner' 21 | 22 | sourceMapSupport.install({ handleUncaughtExceptions: false }) 23 | 24 | const kernel = new Ignitor(__dirname).kernel('test') 25 | 26 | kernel 27 | .boot() 28 | .then(() => import('./tests/bootstrap')) 29 | .then(({ runnerHooks, ...config }) => { 30 | const app: RunnerHooksHandler[] = [() => kernel.start()] 31 | 32 | configure({ 33 | ...kernel.application.rcFile.tests, 34 | ...processCliArgs(process.argv.slice(2)), 35 | ...config, 36 | ...{ 37 | importer: (filePath) => import(filePath), 38 | setup: app.concat(runnerHooks.setup), 39 | teardown: runnerHooks.teardown, 40 | }, 41 | cwd: kernel.application.appRoot, 42 | }) 43 | 44 | run() 45 | }) 46 | -------------------------------------------------------------------------------- /server/tests/bootstrap.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * File source: https://bit.ly/3ukaHTz 3 | * 4 | * Feel free to let us know via PR, if you find something broken in this contract 5 | * file. 6 | */ 7 | 8 | import type { Config } from '@japa/runner' 9 | import TestUtils from '@ioc:Adonis/Core/TestUtils' 10 | import { assert, runFailedTests, specReporter, apiClient } from '@japa/preset-adonis' 11 | 12 | /* 13 | |-------------------------------------------------------------------------- 14 | | Japa Plugins 15 | |-------------------------------------------------------------------------- 16 | | 17 | | Japa plugins allows you to add additional features to Japa. By default 18 | | we register the assertion plugin. 19 | | 20 | | Feel free to remove existing plugins or add more. 21 | | 22 | */ 23 | export const plugins: Config['plugins'] = [assert(), runFailedTests(), apiClient()] 24 | 25 | /* 26 | |-------------------------------------------------------------------------- 27 | | Japa Reporters 28 | |-------------------------------------------------------------------------- 29 | | 30 | | Japa reporters displays/saves the progress of tests as they are executed. 31 | | By default, we register the spec reporter to show a detailed report 32 | | of tests on the terminal. 33 | | 34 | */ 35 | export const reporters: Config['reporters'] = [specReporter()] 36 | 37 | /* 38 | |-------------------------------------------------------------------------- 39 | | Runner hooks 40 | |-------------------------------------------------------------------------- 41 | | 42 | | Runner hooks are executed after booting the AdonisJS app and 43 | | before the test files are imported. 44 | | 45 | | You can perform actions like starting the HTTP server or running migrations 46 | | within the runner hooks 47 | | 48 | */ 49 | export const runnerHooks: Required> = { 50 | setup: [() => TestUtils.ace().loadCommands()], 51 | teardown: [], 52 | } 53 | 54 | /* 55 | |-------------------------------------------------------------------------- 56 | | Configure individual suites 57 | |-------------------------------------------------------------------------- 58 | | 59 | | The configureSuite method gets called for every test suite registered 60 | | within ".adonisrc.json" file. 61 | | 62 | | You can use this method to configure suites. For example: Only start 63 | | the HTTP server when it is a functional suite. 64 | */ 65 | export const configureSuite: Config['configureSuite'] = (suite) => { 66 | if (suite.name === 'functional') { 67 | suite.setup(() => TestUtils.httpServer().start()) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /server/tests/functional/hello_world.spec.ts: -------------------------------------------------------------------------------- 1 | import { test } from '@japa/runner' 2 | 3 | test('display welcome page', async ({ client }) => { 4 | const response = await client.get('/') 5 | 6 | response.assertStatus(200) 7 | response.assertTextIncludes('

It Works!

') 8 | }) 9 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": ["**/*"], 4 | "compilerOptions": { 5 | "allowJs": true, 6 | "outDir": "build", 7 | "rootDir": "./", 8 | "sourceMap": true, 9 | "paths": { 10 | "App/*": [ 11 | "./app/*" 12 | ], 13 | "Config/*": [ 14 | "./config/*" 15 | ], 16 | "Contracts/*": [ 17 | "./contracts/*" 18 | ], 19 | "Database/*": [ 20 | "./database/*" 21 | ] 22 | }, 23 | "types": [ 24 | "@adonisjs/core", 25 | "@adonisjs/repl", 26 | "@adonisjs/session", 27 | "@adonisjs/view", 28 | "@adonisjs/shield", 29 | "@japa/preset-adonis/build/adonis-typings", 30 | "@eidellev/inertia-adonisjs" 31 | ] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { join } = require('path') 2 | const Encore = require('@symfony/webpack-encore') 3 | 4 | /* 5 | |-------------------------------------------------------------------------- 6 | | Encore runtime environment 7 | |-------------------------------------------------------------------------- 8 | */ 9 | if (!Encore.isRuntimeEnvironmentConfigured()) { 10 | Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev') 11 | } 12 | 13 | /* 14 | |-------------------------------------------------------------------------- 15 | | Output path 16 | |-------------------------------------------------------------------------- 17 | | 18 | | The output path for writing the compiled files. It should always 19 | | be inside the public directory, so that AdonisJS can serve it. 20 | | 21 | */ 22 | Encore.setOutputPath('./public/assets') 23 | 24 | /* 25 | |-------------------------------------------------------------------------- 26 | | Public URI 27 | |-------------------------------------------------------------------------- 28 | | 29 | | The public URI to access the static files. It should always be 30 | | relative from the "public" directory. 31 | | 32 | */ 33 | Encore.setPublicPath('/assets') 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Entrypoints 38 | |-------------------------------------------------------------------------- 39 | | 40 | | Entrypoints are script files that boots your frontend application. Ideally 41 | | a single entrypoint is used by majority of applications. However, feel 42 | | free to add more (if required). 43 | | 44 | | Also, make sure to read the docs on "Assets bundler" to learn more about 45 | | entrypoints. 46 | | 47 | */ 48 | Encore.addEntry('app', './resources/js/app.js') 49 | 50 | /* 51 | |-------------------------------------------------------------------------- 52 | | Copy assets 53 | |-------------------------------------------------------------------------- 54 | | 55 | | Since the edge templates are not part of the Webpack compile lifecycle, any 56 | | images referenced by it will not be processed by Webpack automatically. Hence 57 | | we must copy them manually. 58 | | 59 | */ 60 | // Encore.copyFiles({ 61 | // from: './resources/images', 62 | // to: 'images/[path][name].[hash:8].[ext]', 63 | // }) 64 | 65 | /* 66 | |-------------------------------------------------------------------------- 67 | | Split shared code 68 | |-------------------------------------------------------------------------- 69 | | 70 | | Instead of bundling duplicate code in all the bundles, generate a separate 71 | | bundle for the shared code. 72 | | 73 | | https://symfony.com/doc/current/frontend/encore/split-chunks.html 74 | | https://webpack.js.org/plugins/split-chunks-plugin/ 75 | | 76 | */ 77 | // Encore.splitEntryChunks() 78 | 79 | /* 80 | |-------------------------------------------------------------------------- 81 | | Isolated entrypoints 82 | |-------------------------------------------------------------------------- 83 | | 84 | | Treat each entry point and its dependencies as its own isolated module. 85 | | 86 | */ 87 | Encore.disableSingleRuntimeChunk() 88 | 89 | /* 90 | |-------------------------------------------------------------------------- 91 | | Cleanup output folder 92 | |-------------------------------------------------------------------------- 93 | | 94 | | It is always nice to cleanup the build output before creating a build. It 95 | | will ensure that all unused files from the previous build are removed. 96 | | 97 | */ 98 | Encore.cleanupOutputBeforeBuild() 99 | 100 | /* 101 | |-------------------------------------------------------------------------- 102 | | Source maps 103 | |-------------------------------------------------------------------------- 104 | | 105 | | Enable source maps in production 106 | | 107 | */ 108 | Encore.enableSourceMaps(!Encore.isProduction()) 109 | 110 | /* 111 | |-------------------------------------------------------------------------- 112 | | Assets versioning 113 | |-------------------------------------------------------------------------- 114 | | 115 | | Enable assets versioning to leverage lifetime browser and CDN cache 116 | | 117 | */ 118 | Encore.enableVersioning(Encore.isProduction()) 119 | 120 | /* 121 | |-------------------------------------------------------------------------- 122 | | Configure dev server 123 | |-------------------------------------------------------------------------- 124 | | 125 | | Here we configure the dev server to enable live reloading for edge templates. 126 | | Remember edge templates are not processed by Webpack and hence we need 127 | | to watch them explicitly and livereload the browser. 128 | | 129 | */ 130 | Encore.configureDevServerOptions((options) => { 131 | /** 132 | * Normalize "options.static" property to an array 133 | */ 134 | if (!options.static) { 135 | options.static = [] 136 | } else if (!Array.isArray(options.static)) { 137 | options.static = [options.static] 138 | } 139 | 140 | /** 141 | * Enable live reload and add views directory 142 | */ 143 | options.liveReload = true 144 | options.static.push({ 145 | directory: join(__dirname, './resources/views'), 146 | watch: true, 147 | }) 148 | }) 149 | 150 | /* 151 | |-------------------------------------------------------------------------- 152 | | CSS precompilers support 153 | |-------------------------------------------------------------------------- 154 | | 155 | | Uncomment one of the following lines of code to enable support for your 156 | | favorite CSS precompiler 157 | | 158 | */ 159 | // Encore.enableSassLoader() 160 | // Encore.enableLessLoader() 161 | // Encore.enableStylusLoader() 162 | 163 | /* 164 | |-------------------------------------------------------------------------- 165 | | CSS loaders 166 | |-------------------------------------------------------------------------- 167 | | 168 | | Uncomment one of the following line of code to enable support for 169 | | PostCSS or CSS. 170 | | 171 | */ 172 | // Encore.enablePostCssLoader() 173 | // Encore.configureCssLoader(() => {}) 174 | 175 | /* 176 | |-------------------------------------------------------------------------- 177 | | Enable Vue loader 178 | |-------------------------------------------------------------------------- 179 | | 180 | | Uncomment the following lines of code to enable support for vue. Also make 181 | | sure to install the required dependencies. 182 | | 183 | */ 184 | Encore.enableVueLoader(() => {}, { 185 | version: 3, 186 | runtimeCompilerBuild: false, 187 | useJsx: false, 188 | }) 189 | .addAliases({ 190 | '@': join(__dirname, 'resources/js'), 191 | }) 192 | .configureDefinePlugin((options) => { 193 | options['__VUE_OPTIONS_API__'] = true 194 | options['__VUE_PROD_DEVTOOLS__'] = false 195 | }) 196 | 197 | /* 198 | |-------------------------------------------------------------------------- 199 | | Configure logging 200 | |-------------------------------------------------------------------------- 201 | | 202 | | To keep the terminal clean from unnecessary info statements , we only 203 | | log warnings and errors. If you want all the logs, you can change 204 | | the level to "info". 205 | | 206 | */ 207 | const config = Encore.getWebpackConfig() 208 | config.infrastructureLogging = { 209 | level: 'warn', 210 | } 211 | config.stats = 'errors-warnings' 212 | 213 | /* 214 | |-------------------------------------------------------------------------- 215 | | Export config 216 | |-------------------------------------------------------------------------- 217 | | 218 | | Export config for webpack to do its job 219 | | 220 | */ 221 | module.exports = config 222 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "lib": [ 6 | "DOM", 7 | "ES2020" 8 | ], 9 | "noUnusedLocals": true, 10 | "skipLibCheck": true, 11 | "noUnusedParameters": true, 12 | "removeComments": true, 13 | "declaration": false, 14 | "moduleResolution": "node", 15 | "strictNullChecks": true, 16 | "allowSyntheticDefaultImports": true, 17 | "emitDecoratorMetadata": true, 18 | "experimentalDecorators": true, 19 | "esModuleInterop": true, 20 | }, 21 | "exclude": ["node_modules"] 22 | } 23 | --------------------------------------------------------------------------------