diff --git a/api-monorepo/apps/backend/package.json b/api-monorepo/apps/backend/package.json
index fbae901..8099a23 100644
--- a/api-monorepo/apps/backend/package.json
+++ b/api-monorepo/apps/backend/package.json
@@ -46,18 +46,18 @@
"@japa/plugin-adonisjs": "^5.2.0",
"@japa/runner": "^5.3.0",
"@poppinss/ts-exec": "^1.4.4",
- "@types/luxon": "^3.7.1",
- "@types/node": "~25.9.1",
- "eslint": "^10.4.0",
+ "@types/luxon": "^3.7.4",
+ "@types/node": "~26.2.0",
+ "eslint": "^10.8.1",
"hot-hook": "^1.0.0",
"pino-pretty": "^13.1.3",
- "prettier": "^3.8.3",
+ "prettier": "^3.9.6",
"typescript": "~6.0.3",
"youch": "^4.1.1"
},
"dependencies": {
"@adonisjs/auth": "^10.1.0",
- "@adonisjs/core": "^7.3.3",
+ "@adonisjs/core": "^7.4.0",
"@adonisjs/cors": "^3.0.0",
"@adonisjs/lucid": "^22.4.2",
"@adonisjs/session": "^8.1.0",
@@ -65,7 +65,7 @@
"@japa/api-client": "^3.2.1",
"@tuyau/core": "^1.2.2",
"@vinejs/vine": "^4.4.0",
- "better-sqlite3": "^12.10.0",
+ "better-sqlite3": "^13.0.3",
"luxon": "^3.7.2",
"reflect-metadata": "^0.2.2"
},
diff --git a/api-monorepo/package.json b/api-monorepo/package.json
index 709afbb..26a78b1 100644
--- a/api-monorepo/package.json
+++ b/api-monorepo/package.json
@@ -21,8 +21,8 @@
},
"devDependencies": {
"@adonisjs/prettier-config": "^1.5.0",
- "prettier": "^3.8.3",
- "turbo": "^2.9.16"
+ "prettier": "^3.9.6",
+ "turbo": "^2.10.9"
},
"allowScripts": {
"@swc/core": true,
diff --git a/api/package.json b/api/package.json
index 77cd854..708fa55 100644
--- a/api/package.json
+++ b/api/package.json
@@ -46,18 +46,18 @@
"@japa/plugin-adonisjs": "^5.2.0",
"@japa/runner": "^5.3.0",
"@poppinss/ts-exec": "^1.4.4",
- "@types/luxon": "^3.7.1",
- "@types/node": "~25.9.1",
- "eslint": "^10.4.0",
+ "@types/luxon": "^3.7.4",
+ "@types/node": "~26.2.0",
+ "eslint": "^10.8.1",
"hot-hook": "^1.0.0",
"pino-pretty": "^13.1.3",
- "prettier": "^3.8.3",
+ "prettier": "^3.9.6",
"typescript": "~6.0.3",
"youch": "^4.1.1"
},
"dependencies": {
"@adonisjs/auth": "^10.1.0",
- "@adonisjs/core": "^7.3.3",
+ "@adonisjs/core": "^7.4.0",
"@adonisjs/cors": "^3.0.0",
"@adonisjs/lucid": "^22.4.2",
"@adonisjs/session": "^8.1.0",
@@ -65,7 +65,7 @@
"@japa/api-client": "^3.2.1",
"@tuyau/core": "^1.2.2",
"@vinejs/vine": "^4.4.0",
- "better-sqlite3": "^12.10.0",
+ "better-sqlite3": "^13.0.3",
"luxon": "^3.7.2",
"reflect-metadata": "^0.2.2"
},
diff --git a/hypermedia/package.json b/hypermedia/package.json
index 1c18ef4..e05d8a7 100644
--- a/hypermedia/package.json
+++ b/hypermedia/package.json
@@ -46,27 +46,27 @@
"@japa/runner": "^5.3.0",
"@poppinss/ts-exec": "^1.4.4",
"@types/alpinejs": "^3.13.11",
- "@types/luxon": "^3.7.1",
- "@types/node": "~25.9.1",
+ "@types/luxon": "^3.7.4",
+ "@types/node": "~26.2.0",
"alpinejs": "^3.15.12",
- "eslint": "^10.4.0",
+ "eslint": "^10.8.1",
"hot-hook": "^1.0.0",
"pino-pretty": "^13.1.3",
- "prettier": "^3.8.3",
+ "prettier": "^3.9.6",
"typescript": "~6.0.3",
- "vite": "^7.3.3",
+ "vite": "^8.2.1",
"youch": "^4.1.1"
},
"dependencies": {
"@adonisjs/auth": "^10.1.0",
- "@adonisjs/core": "^7.3.3",
+ "@adonisjs/core": "^7.4.0",
"@adonisjs/lucid": "^22.4.2",
"@adonisjs/session": "^8.1.0",
"@adonisjs/shield": "^9.0.0",
"@adonisjs/static": "^2.0.1",
- "@adonisjs/vite": "^5.1.1",
+ "@adonisjs/vite": "^6.0.0",
"@vinejs/vine": "^4.4.0",
- "better-sqlite3": "^12.10.0",
+ "better-sqlite3": "^13.0.3",
"edge.js": "^6.5.1",
"luxon": "^3.7.2",
"reflect-metadata": "^0.2.2"
diff --git a/hypermedia/vite.config.ts b/hypermedia/vite.config.ts
index 671111c..bd5d6b3 100644
--- a/hypermedia/vite.config.ts
+++ b/hypermedia/vite.config.ts
@@ -8,7 +8,7 @@ export default defineConfig({
* Entrypoints of your application. Each entrypoint will
* result in a separate bundle.
*/
- entrypoints: ['resources/css/app.css', 'resources/js/app.js'],
+ entryPoints: ['resources/css/app.css', 'resources/js/app.js'],
/**
* Paths to watch and reload the browser on file change
diff --git a/inertia-react/.adonisjs/client/data.d.ts b/inertia-react/.adonisjs/client/data.d.ts
index 3b8c719..9998cde 100644
--- a/inertia-react/.adonisjs/client/data.d.ts
+++ b/inertia-react/.adonisjs/client/data.d.ts
@@ -5,7 +5,7 @@
///
import type { InferData, InferVariants } from '@adonisjs/core/types/transformers'
-import type { InferSharedProps } from '@adonisjs/inertia/types'
+import type { InferSharedProps, InferFlashData } from '@adonisjs/inertia/types'
import type UserTransformer from '#transformers/user_transformer'
import type InertiaMiddleware from '#middleware/inertia_middleware'
@@ -15,4 +15,5 @@ export namespace Data {
export type Variants = InferVariants
}
export type SharedProps = InferSharedProps
+ export type FlashMessages = InferFlashData
}
diff --git a/inertia-react/.adonisjs/client/registry/schema.d.ts b/inertia-react/.adonisjs/client/registry/schema.d.ts
index 1f3d623..bfeb118 100644
--- a/inertia-react/.adonisjs/client/registry/schema.d.ts
+++ b/inertia-react/.adonisjs/client/registry/schema.d.ts
@@ -59,12 +59,12 @@ export interface Registry {
methods: ["POST"]
pattern: '/login'
types: {
- body: {}
+ body: ExtractBody>
paramsTuple: []
params: {}
- query: {}
+ query: ExtractQuery>
response: ExtractResponse>>
- errorResponse: ExtractErrorResponse>>
+ errorResponse: ExtractErrorResponse>> | { status: 422; response: { errors: SimpleError[] } }
}
}
'session.destroy': {
diff --git a/inertia-react/app/controllers/new_account_controller.ts b/inertia-react/app/controllers/new_account_controller.ts
index 36b53fe..5e4f5d7 100644
--- a/inertia-react/app/controllers/new_account_controller.ts
+++ b/inertia-react/app/controllers/new_account_controller.ts
@@ -8,7 +8,7 @@ export default class NewAccountController {
}
async store({ request, response, auth }: HttpContext) {
- const payload = await request.validateUsing(signupValidator)
+ const { passwordConfirmation, ...payload } = await request.validateUsing(signupValidator)
const user = await User.create({ ...payload })
await auth.use('web').login(user)
diff --git a/inertia-react/app/controllers/session_controller.ts b/inertia-react/app/controllers/session_controller.ts
index 07b8569..838b6d8 100644
--- a/inertia-react/app/controllers/session_controller.ts
+++ b/inertia-react/app/controllers/session_controller.ts
@@ -1,4 +1,5 @@
import User from '#models/user'
+import { loginValidator } from '#validators/user'
import type { HttpContext } from '@adonisjs/core/http'
export default class SessionController {
@@ -7,7 +8,7 @@ export default class SessionController {
}
async store({ request, auth, response }: HttpContext) {
- const { email, password } = request.all()
+ const { email, password } = await request.validateUsing(loginValidator)
const user = await User.verifyCredentials(email, password)
await auth.use('web').login(user)
diff --git a/inertia-react/app/middleware/inertia_middleware.ts b/inertia-react/app/middleware/inertia_middleware.ts
index 5ed6d82..6c9cdab 100644
--- a/inertia-react/app/middleware/inertia_middleware.ts
+++ b/inertia-react/app/middleware/inertia_middleware.ts
@@ -13,13 +13,7 @@ export default class InertiaMiddleware extends BaseInertiaMiddleware {
* In that case, we must always assume that HttpContext is not fully hydrated
* with all the properties
*/
- const { session, auth } = ctx as Partial
-
- /**
- * Fetching the first error from the flash messages
- */
- const error = session?.flashMessages.get('error') as string
- const success = session?.flashMessages.get('success') as string
+ const { auth } = ctx as Partial
/**
* Data shared with all Inertia pages. Make sure you are using
@@ -27,14 +21,29 @@ export default class InertiaMiddleware extends BaseInertiaMiddleware {
*/
return {
errors: ctx.inertia.always(this.getValidationErrors(ctx)),
- flash: ctx.inertia.always({
- error,
- success,
- }),
user: ctx.inertia.always(auth?.user ? UserTransformer.transform(auth.user) : undefined),
}
}
+ /**
+ * The flash bag is sent to every Inertia page as a top-level "flash" field
+ * (a sibling of "props") and is read on the client using "usePage().flash".
+ *
+ * Just like the share method, the flash method may run before the session
+ * middleware, so HttpContext must be treated as partially hydrated.
+ */
+ flash(ctx: HttpContext) {
+ const { session } = ctx as Partial
+
+ /**
+ * Fetching the first error from the flash messages
+ */
+ return {
+ error: session?.flashMessages.get('error') as string | undefined,
+ success: session?.flashMessages.get('success') as string | undefined,
+ }
+ }
+
async handle(ctx: HttpContext, next: NextFn) {
await this.init(ctx)
diff --git a/inertia-react/app/validators/user.ts b/inertia-react/app/validators/user.ts
index 67548d8..45c2bd1 100644
--- a/inertia-react/app/validators/user.ts
+++ b/inertia-react/app/validators/user.ts
@@ -7,7 +7,11 @@ const email = () => vine.string().email().maxLength(254)
const password = () => vine.string().minLength(8).maxLength(32)
/**
- * Validator to use when performing self-signup
+ * Validator to use when performing self-signup.
+ *
+ * The "passwordConfirmation" field is declared explicitly, so that it is part
+ * of the request body type shared with the frontend. Otherwise the signup form
+ * has no way to know about the errors reported for this field.
*/
export const signupValidator = vine.create({
fullName: vine.string().nullable(),
@@ -15,4 +19,13 @@ export const signupValidator = vine.create({
password: password().confirmed({
confirmationField: 'passwordConfirmation',
}),
+ passwordConfirmation: vine.string(),
+})
+
+/**
+ * Validator to use when logging in an existing user
+ */
+export const loginValidator = vine.create({
+ email: email(),
+ password: vine.string(),
})
diff --git a/inertia-react/inertia/app.tsx b/inertia-react/inertia/app.tsx
index 15593dd..027021c 100644
--- a/inertia-react/inertia/app.tsx
+++ b/inertia-react/inertia/app.tsx
@@ -4,7 +4,7 @@ import { client } from './client'
import Layout from '~/layouts/default'
import { type Data } from '@generated/data'
import { createRoot } from 'react-dom/client'
-import { createInertiaApp } from '@inertiajs/react'
+import { createInertiaApp, type ResolvedComponent } from '@inertiajs/react'
import { TuyauProvider } from '@adonisjs/inertia/react'
import { resolvePageComponent } from '@adonisjs/inertia/helpers'
@@ -13,9 +13,9 @@ const appName = import.meta.env.VITE_APP_NAME || 'AdonisJS'
createInertiaApp({
title: (title) => (title ? `${title} - ${appName}` : appName),
resolve: (name) => {
- return resolvePageComponent(
+ return resolvePageComponent(
`./pages/${name}.tsx`,
- import.meta.glob('./pages/**/*.tsx'),
+ import.meta.glob('./pages/**/*.tsx'),
(page: ReactElement) =>
)
},
diff --git a/inertia-react/inertia/layouts/default.tsx b/inertia-react/inertia/layouts/default.tsx
index 4de27e5..15efc90 100644
--- a/inertia-react/inertia/layouts/default.tsx
+++ b/inertia-react/inertia/layouts/default.tsx
@@ -5,17 +5,17 @@ import { type ReactElement, useEffect } from 'react'
import { Form, Link } from '@adonisjs/inertia/react'
export default function Layout({ children }: { children: ReactElement }) {
- const { url } = usePage()
+ const { url, flash } = usePage()
useEffect(() => {
toast.dismiss()
}, [url])
useEffect(() => {
- if (children.props.flash.error) {
- toast.error(children.props.flash.error)
+ if (flash.error) {
+ toast.error(flash.error)
}
- if (children.props.flash.success) {
- toast.success(children.props.flash.success)
+ if (flash.success) {
+ toast.success(flash.success)
}
})
diff --git a/inertia-react/inertia/ssr.tsx b/inertia-react/inertia/ssr.tsx
index 3e97872..77631c9 100644
--- a/inertia-react/inertia/ssr.tsx
+++ b/inertia-react/inertia/ssr.tsx
@@ -3,7 +3,7 @@ import { type ReactElement } from 'react'
import Layout from '~/layouts/default'
import { type Data } from '@generated/data'
import ReactDOMServer from 'react-dom/server'
-import { createInertiaApp } from '@inertiajs/react'
+import { createInertiaApp, type ResolvedComponent } from '@inertiajs/react'
import { TuyauProvider } from '@adonisjs/inertia/react'
import { resolvePageComponent } from '@adonisjs/inertia/helpers'
@@ -12,9 +12,9 @@ export default function render(page: any) {
page,
render: ReactDOMServer.renderToString,
resolve: (name) => {
- return resolvePageComponent(
+ return resolvePageComponent(
`./pages/${name}.tsx`,
- import.meta.glob('./pages/**/*.tsx', { eager: true }),
+ import.meta.glob('./pages/**/*.tsx', { eager: true }),
(resolvedPage: ReactElement) =>
)
},
diff --git a/inertia-react/inertia/types.ts b/inertia-react/inertia/types.ts
index ff40d8d..7653c0f 100644
--- a/inertia-react/inertia/types.ts
+++ b/inertia-react/inertia/types.ts
@@ -3,3 +3,15 @@ import { type PropsWithChildren } from 'react'
import { type JSONDataTypes } from '@adonisjs/core/types/transformers'
export type InertiaProps = PropsWithChildren
+
+/**
+ * Bridges the server side types into the Inertia client. "usePage().props" is
+ * typed from the Inertia middleware share method and "usePage().flash" from
+ * its flash method.
+ */
+declare module '@inertiajs/core' {
+ interface InertiaConfig {
+ sharedPageProps: Data.SharedProps
+ flashDataType: Data.FlashMessages
+ }
+}
diff --git a/inertia-react/package.json b/inertia-react/package.json
index f7548ed..cdf4402 100644
--- a/inertia-react/package.json
+++ b/inertia-react/package.json
@@ -46,41 +46,42 @@
"@japa/plugin-adonisjs": "^5.2.0",
"@japa/runner": "^5.3.0",
"@poppinss/ts-exec": "^1.4.4",
- "@types/luxon": "^3.7.1",
- "@types/node": "~25.9.1",
- "@types/react": "^19.2.15",
- "@types/react-dom": "^19.2.3",
- "@vitejs/plugin-react": "^5.2.0",
- "eslint": "^10.4.0",
+ "@types/luxon": "^3.7.4",
+ "@types/node": "~26.2.0",
+ "@types/react": "^19.2.18",
+ "@types/react-dom": "^19.2.4",
+ "@vitejs/plugin-react": "^6.0.5",
+ "eslint": "^10.8.1",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.1.1",
"hot-hook": "^1.0.0",
"pino-pretty": "^13.1.3",
- "prettier": "^3.8.3",
+ "prettier": "^3.9.6",
"typescript": "~6.0.3",
- "vite": "^7.3.3",
+ "vite": "^8.2.1",
"youch": "^4.1.1"
},
"dependencies": {
"@adonisjs/auth": "^10.1.0",
- "@adonisjs/core": "^7.3.3",
+ "@adonisjs/core": "^7.4.0",
"@adonisjs/cors": "^3.0.0",
- "@adonisjs/inertia": "^4.2.0",
+ "@adonisjs/inertia": "^5.0.0",
"@adonisjs/lucid": "^22.4.2",
"@adonisjs/session": "^8.1.0",
"@adonisjs/shield": "^9.0.0",
"@adonisjs/static": "^2.0.1",
- "@adonisjs/vite": "^5.1.1",
- "@inertiajs/react": "^2.3.24",
+ "@adonisjs/vite": "^6.0.0",
+ "@inertiajs/react": "^3.6.1",
"@tuyau/core": "^1.2.2",
"@vinejs/vine": "^4.4.0",
- "better-sqlite3": "^12.10.0",
+ "axios": "^1.19.0",
+ "better-sqlite3": "^13.0.3",
"edge.js": "^6.5.1",
"luxon": "^3.7.2",
- "react": "^19.2.6",
- "react-dom": "^19.2.6",
+ "react": "^19.2.8",
+ "react-dom": "^19.2.8",
"reflect-metadata": "^0.2.2",
- "sonner": "^2.0.7"
+ "sonner": "^2.0.8"
},
"hotHook": {
"boundaries": [
diff --git a/inertia-react/resources/views/inertia_layout.edge b/inertia-react/resources/views/inertia_layout.edge
index 0b34b79..7f16a3f 100644
--- a/inertia-react/resources/views/inertia_layout.edge
+++ b/inertia-react/resources/views/inertia_layout.edge
@@ -3,7 +3,7 @@
-
+
AdonisJS
diff --git a/inertia-react/vite.config.ts b/inertia-react/vite.config.ts
index 522a656..11e85cc 100644
--- a/inertia-react/vite.config.ts
+++ b/inertia-react/vite.config.ts
@@ -1,13 +1,11 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import adonisjs from '@adonisjs/vite/client'
-import inertia from '@adonisjs/inertia/vite'
export default defineConfig({
plugins: [
react(),
- inertia({ ssr: { enabled: false, entrypoint: 'inertia/ssr.tsx' } }),
- adonisjs({ entrypoints: ['inertia/app.tsx'], reload: ['resources/views/**/*.edge'] }),
+ adonisjs({ entryPoints: ['inertia/app.tsx'], reload: ['resources/views/**/*.edge'] }),
],
/**
diff --git a/inertia-vue/.adonisjs/client/data.d.ts b/inertia-vue/.adonisjs/client/data.d.ts
index 3b8c719..9998cde 100644
--- a/inertia-vue/.adonisjs/client/data.d.ts
+++ b/inertia-vue/.adonisjs/client/data.d.ts
@@ -5,7 +5,7 @@
///
import type { InferData, InferVariants } from '@adonisjs/core/types/transformers'
-import type { InferSharedProps } from '@adonisjs/inertia/types'
+import type { InferSharedProps, InferFlashData } from '@adonisjs/inertia/types'
import type UserTransformer from '#transformers/user_transformer'
import type InertiaMiddleware from '#middleware/inertia_middleware'
@@ -15,4 +15,5 @@ export namespace Data {
export type Variants = InferVariants
}
export type SharedProps = InferSharedProps
+ export type FlashMessages = InferFlashData
}
diff --git a/inertia-vue/.adonisjs/client/registry/schema.d.ts b/inertia-vue/.adonisjs/client/registry/schema.d.ts
index 1f3d623..bfeb118 100644
--- a/inertia-vue/.adonisjs/client/registry/schema.d.ts
+++ b/inertia-vue/.adonisjs/client/registry/schema.d.ts
@@ -59,12 +59,12 @@ export interface Registry {
methods: ["POST"]
pattern: '/login'
types: {
- body: {}
+ body: ExtractBody>
paramsTuple: []
params: {}
- query: {}
+ query: ExtractQuery>
response: ExtractResponse>>
- errorResponse: ExtractErrorResponse>>
+ errorResponse: ExtractErrorResponse>> | { status: 422; response: { errors: SimpleError[] } }
}
}
'session.destroy': {
diff --git a/inertia-vue/app/controllers/new_account_controller.ts b/inertia-vue/app/controllers/new_account_controller.ts
index 36b53fe..5e4f5d7 100644
--- a/inertia-vue/app/controllers/new_account_controller.ts
+++ b/inertia-vue/app/controllers/new_account_controller.ts
@@ -8,7 +8,7 @@ export default class NewAccountController {
}
async store({ request, response, auth }: HttpContext) {
- const payload = await request.validateUsing(signupValidator)
+ const { passwordConfirmation, ...payload } = await request.validateUsing(signupValidator)
const user = await User.create({ ...payload })
await auth.use('web').login(user)
diff --git a/inertia-vue/app/controllers/session_controller.ts b/inertia-vue/app/controllers/session_controller.ts
index 07b8569..838b6d8 100644
--- a/inertia-vue/app/controllers/session_controller.ts
+++ b/inertia-vue/app/controllers/session_controller.ts
@@ -1,4 +1,5 @@
import User from '#models/user'
+import { loginValidator } from '#validators/user'
import type { HttpContext } from '@adonisjs/core/http'
export default class SessionController {
@@ -7,7 +8,7 @@ export default class SessionController {
}
async store({ request, auth, response }: HttpContext) {
- const { email, password } = request.all()
+ const { email, password } = await request.validateUsing(loginValidator)
const user = await User.verifyCredentials(email, password)
await auth.use('web').login(user)
diff --git a/inertia-vue/app/middleware/inertia_middleware.ts b/inertia-vue/app/middleware/inertia_middleware.ts
index 5ed6d82..6c9cdab 100644
--- a/inertia-vue/app/middleware/inertia_middleware.ts
+++ b/inertia-vue/app/middleware/inertia_middleware.ts
@@ -13,13 +13,7 @@ export default class InertiaMiddleware extends BaseInertiaMiddleware {
* In that case, we must always assume that HttpContext is not fully hydrated
* with all the properties
*/
- const { session, auth } = ctx as Partial
-
- /**
- * Fetching the first error from the flash messages
- */
- const error = session?.flashMessages.get('error') as string
- const success = session?.flashMessages.get('success') as string
+ const { auth } = ctx as Partial
/**
* Data shared with all Inertia pages. Make sure you are using
@@ -27,14 +21,29 @@ export default class InertiaMiddleware extends BaseInertiaMiddleware {
*/
return {
errors: ctx.inertia.always(this.getValidationErrors(ctx)),
- flash: ctx.inertia.always({
- error,
- success,
- }),
user: ctx.inertia.always(auth?.user ? UserTransformer.transform(auth.user) : undefined),
}
}
+ /**
+ * The flash bag is sent to every Inertia page as a top-level "flash" field
+ * (a sibling of "props") and is read on the client using "usePage().flash".
+ *
+ * Just like the share method, the flash method may run before the session
+ * middleware, so HttpContext must be treated as partially hydrated.
+ */
+ flash(ctx: HttpContext) {
+ const { session } = ctx as Partial
+
+ /**
+ * Fetching the first error from the flash messages
+ */
+ return {
+ error: session?.flashMessages.get('error') as string | undefined,
+ success: session?.flashMessages.get('success') as string | undefined,
+ }
+ }
+
async handle(ctx: HttpContext, next: NextFn) {
await this.init(ctx)
diff --git a/inertia-vue/app/validators/user.ts b/inertia-vue/app/validators/user.ts
index 7225d2a..de7595d 100644
--- a/inertia-vue/app/validators/user.ts
+++ b/inertia-vue/app/validators/user.ts
@@ -3,10 +3,21 @@ import vine from '@vinejs/vine'
const email = () => vine.string().email().maxLength(254)
const password = () => vine.string().minLength(8).maxLength(32)
+/**
+ * "passwordConfirmation" is declared explicitly, so that it is part of the
+ * request body type shared with the frontend. Otherwise the signup form has
+ * no way to know about the errors reported for this field.
+ */
export const signupValidator = vine.create({
fullName: vine.string().nullable(),
email: email().unique({ table: 'users', column: 'email' }),
password: password().confirmed({
confirmationField: 'passwordConfirmation',
}),
+ passwordConfirmation: vine.string(),
+})
+
+export const loginValidator = vine.create({
+ email: email(),
+ password: vine.string(),
})
diff --git a/inertia-vue/inertia/layouts/default.vue b/inertia-vue/inertia/layouts/default.vue
index b0749b1..7d6c783 100644
--- a/inertia-vue/inertia/layouts/default.vue
+++ b/inertia-vue/inertia/layouts/default.vue
@@ -13,7 +13,7 @@ watch(
)
watch(
- () => page.props.flash,
+ () => page.flash,
(flashMessages) => {
if (flashMessages.error) {
toast.error(flashMessages.error)
diff --git a/inertia-vue/inertia/types.ts b/inertia-vue/inertia/types.ts
new file mode 100644
index 0000000..66c7bfb
--- /dev/null
+++ b/inertia-vue/inertia/types.ts
@@ -0,0 +1,13 @@
+import { type Data } from '@generated/data'
+
+/**
+ * Bridges the server side types into the Inertia client. "usePage().props" is
+ * typed from the Inertia middleware share method and "usePage().flash" from
+ * its flash method.
+ */
+declare module '@inertiajs/core' {
+ interface InertiaConfig {
+ sharedPageProps: Data.SharedProps
+ flashDataType: Data.FlashMessages
+ }
+}
diff --git a/inertia-vue/package.json b/inertia-vue/package.json
index 87ad25d..df1d85f 100644
--- a/inertia-vue/package.json
+++ b/inertia-vue/package.json
@@ -46,38 +46,39 @@
"@japa/plugin-adonisjs": "^5.2.0",
"@japa/runner": "^5.3.0",
"@poppinss/ts-exec": "^1.4.4",
- "@types/luxon": "^3.7.1",
- "@types/node": "~25.9.1",
- "@vitejs/plugin-vue": "^6.0.7",
- "eslint": "^10.4.0",
- "eslint-plugin-vue": "^10.9.1",
+ "@types/luxon": "^3.7.4",
+ "@types/node": "~26.2.0",
+ "@vitejs/plugin-vue": "^6.0.8",
+ "eslint": "^10.8.1",
+ "eslint-plugin-vue": "^10.10.0",
"hot-hook": "^1.0.0",
"pino-pretty": "^13.1.3",
- "prettier": "^3.8.3",
+ "prettier": "^3.9.6",
"typescript": "~6.0.3",
- "vite": "^7.3.3",
- "vue-tsc": "^3.3.2",
+ "vite": "^8.2.1",
+ "vue-tsc": "^3.3.9",
"youch": "^4.1.1"
},
"dependencies": {
"@adonisjs/auth": "^10.1.0",
- "@adonisjs/core": "^7.3.3",
+ "@adonisjs/core": "^7.4.0",
"@adonisjs/cors": "^3.0.0",
- "@adonisjs/inertia": "^4.2.0",
+ "@adonisjs/inertia": "^5.0.0",
"@adonisjs/lucid": "^22.4.2",
"@adonisjs/session": "^8.1.0",
"@adonisjs/shield": "^9.0.0",
"@adonisjs/static": "^2.0.1",
- "@adonisjs/vite": "^5.1.1",
- "@inertiajs/vue3": "^2.3.24",
+ "@adonisjs/vite": "^6.0.0",
+ "@inertiajs/vue3": "^3.6.1",
"@tuyau/core": "^1.2.2",
"@vinejs/vine": "^4.4.0",
- "@vue/server-renderer": "^3.5.35",
- "better-sqlite3": "^12.10.0",
+ "@vue/server-renderer": "^3.5.41",
+ "axios": "^1.19.0",
+ "better-sqlite3": "^13.0.3",
"edge.js": "^6.5.1",
"luxon": "^3.7.2",
"reflect-metadata": "^0.2.2",
- "vue": "^3.5.35",
+ "vue": "^3.5.41",
"vue-sonner": "^2.0.9"
},
"hotHook": {
diff --git a/inertia-vue/resources/views/inertia_layout.edge b/inertia-vue/resources/views/inertia_layout.edge
index d13fc9a..df5cbf6 100644
--- a/inertia-vue/resources/views/inertia_layout.edge
+++ b/inertia-vue/resources/views/inertia_layout.edge
@@ -3,7 +3,7 @@
-
+
AdonisJS
diff --git a/inertia-vue/vite.config.ts b/inertia-vue/vite.config.ts
index 09f43f0..0c9148a 100644
--- a/inertia-vue/vite.config.ts
+++ b/inertia-vue/vite.config.ts
@@ -1,13 +1,11 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import adonisjs from '@adonisjs/vite/client'
-import inertia from '@adonisjs/inertia/vite'
export default defineConfig({
plugins: [
vue(),
- inertia({ ssr: { enabled: false, entrypoint: 'inertia/ssr.ts' } }),
- adonisjs({ entrypoints: ['inertia/app.ts'], reload: ['resources/views/**/*.edge'] }),
+ adonisjs({ entryPoints: ['inertia/app.ts'], reload: ['resources/views/**/*.edge'] }),
],
resolve: {