From dde642f56e3d99ff092269b07ab537a0f021e3fe Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Sat, 8 Nov 2025 15:26:53 +0100 Subject: [PATCH 1/4] feat: add tuyau --- .adonisjs/client/registry.ts | 84 ++++++++++++++++++++++++++++++++++++ adonisrc.ts | 2 + inertia/client.ts | 9 ++++ package.json | 1 + vite.config.ts | 1 + 5 files changed, 97 insertions(+) create mode 100644 .adonisjs/client/registry.ts create mode 100644 inertia/client.ts diff --git a/.adonisjs/client/registry.ts b/.adonisjs/client/registry.ts new file mode 100644 index 0000000..5c44053 --- /dev/null +++ b/.adonisjs/client/registry.ts @@ -0,0 +1,84 @@ +/* eslint-disable prettier/prettier */ +import type { AdonisEndpoint } from '@tuyau/core/types' +import type { Infer } from '@vinejs/vine/types' + +const placeholder: any = {} +export const registry = { + 'home': { + methods: ["GET","HEAD"], + pattern: '/', + tokens: [{"old":"/","type":0,"val":"/","end":""}], + types: placeholder as { + body: {} + paramsTuple: [] + params: {} + query: {} + response: unknown + }, + }, + 'newAccount.create': { + methods: ["GET","HEAD"], + pattern: '/signup', + tokens: [{"old":"/signup","type":0,"val":"signup","end":""}], + types: placeholder as { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ReturnType + }, + }, + 'newAccount.store': { + methods: ["POST"], + pattern: '/signup', + tokens: [{"old":"/signup","type":0,"val":"signup","end":""}], + types: placeholder as { + body: Infer<(typeof import('#validators/user').signupValidator)> + paramsTuple: [] + params: {} + query: {} + response: ReturnType + }, + }, + 'session.create': { + methods: ["GET","HEAD"], + pattern: '/login', + tokens: [{"old":"/login","type":0,"val":"login","end":""}], + types: placeholder as { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ReturnType + }, + }, + 'session.store': { + methods: ["POST"], + pattern: '/login', + tokens: [{"old":"/login","type":0,"val":"login","end":""}], + types: placeholder as { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ReturnType + }, + }, + 'session.destroy': { + methods: ["POST"], + pattern: '/logout', + tokens: [{"old":"/logout","type":0,"val":"logout","end":""}], + types: placeholder as { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ReturnType + }, + } +} as const satisfies Record + +declare module '@tuyau/core/types' { + type Registry = typeof registry + export interface UserRegistry extends Registry {} +} diff --git a/adonisrc.ts b/adonisrc.ts index 7c5d55b..8c90dcd 100644 --- a/adonisrc.ts +++ b/adonisrc.ts @@ -1,6 +1,7 @@ import { indexPages } from '@adonisjs/inertia' import { indexEntities } from '@adonisjs/core' import { defineConfig } from '@adonisjs/core/app' +import { generateRegistry } from '@tuyau/core/hooks' export default defineConfig({ /* @@ -123,6 +124,7 @@ export default defineConfig({ framework: 'react', }), ], + routesScanned: [generateRegistry()], buildStarting: [() => import('@adonisjs/vite/build_hook')], }, }) diff --git a/inertia/client.ts b/inertia/client.ts new file mode 100644 index 0000000..76eaf4a --- /dev/null +++ b/inertia/client.ts @@ -0,0 +1,9 @@ +import { registry } from '~/generated/registry' +import { createTuyau } from '@tuyau/core/client' + +export const client = createTuyau({ + baseUrl: 'http://localhost:3333', + registry, +}) + +export const urlFor = client.urlFor diff --git a/package.json b/package.json index 3e892cd..382e59f 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "@adonisjs/static": "^2.0.0-next.1", "@adonisjs/vite": "^5.1.0-next.2", "@inertiajs/react": "^2.2.19", + "@tuyau/core": "1.0.0-beta.1", "@vinejs/vine": "^4.1.0", "better-sqlite3": "^12.5.0", "edge.js": "^6.3.0", diff --git a/vite.config.ts b/vite.config.ts index 6619e87..f5438ae 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -17,6 +17,7 @@ export default defineConfig({ resolve: { alias: { '~/': `${import.meta.dirname}/inertia/`, + '~/generated/registry': `${import.meta.dirname}/../.adonisjs/client/registry.js`, }, }, }) From 418a699575e7388b9b286d2158040963a38eaf76 Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Mon, 10 Nov 2025 18:58:51 +0100 Subject: [PATCH 2/4] feat: update tuyau --- .adonisjs/client/registry.schema.d.ts | 78 +++++++++++++++++++++++++++ .adonisjs/client/registry.ts | 63 ++++------------------ package.json | 2 +- 3 files changed, 90 insertions(+), 53 deletions(-) create mode 100644 .adonisjs/client/registry.schema.d.ts diff --git a/.adonisjs/client/registry.schema.d.ts b/.adonisjs/client/registry.schema.d.ts new file mode 100644 index 0000000..4c611f1 --- /dev/null +++ b/.adonisjs/client/registry.schema.d.ts @@ -0,0 +1,78 @@ +/* eslint-disable prettier/prettier */ +/// + +import type { AdonisEndpoint } from '@tuyau/core/types' +import type { Infer } from '@vinejs/vine/types' + +export interface Registry { + 'home': { + methods: ["GET","HEAD"] + pattern: '/' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: unknown + } + } + 'new_account.create': { + methods: ["GET","HEAD"] + pattern: '/signup' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ReturnType + } + } + 'new_account.store': { + methods: ["POST"] + pattern: '/signup' + types: { + body: Infer<(typeof import('#validators/user').signupValidator)> + paramsTuple: [] + params: {} + query: {} + response: ReturnType + } + } + 'session.create': { + methods: ["GET","HEAD"] + pattern: '/login' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ReturnType + } + } + 'session.store': { + methods: ["POST"] + pattern: '/login' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ReturnType + } + } + 'session.destroy': { + methods: ["POST"] + pattern: '/logout' + types: { + body: {} + paramsTuple: [] + params: {} + query: {} + response: ReturnType + } + } +} + +declare module '@tuyau/core/types' { + export interface UserRegistry extends Registry {} +} diff --git a/.adonisjs/client/registry.ts b/.adonisjs/client/registry.ts index 5c44053..b5205fc 100644 --- a/.adonisjs/client/registry.ts +++ b/.adonisjs/client/registry.ts @@ -1,84 +1,43 @@ /* eslint-disable prettier/prettier */ -import type { AdonisEndpoint } from '@tuyau/core/types' -import type { Infer } from '@vinejs/vine/types' - +import { type AdonisEndpoint } from '@tuyau/core/types' +import type { Registry } from './registry.schema' const placeholder: any = {} + export const registry = { 'home': { methods: ["GET","HEAD"], pattern: '/', tokens: [{"old":"/","type":0,"val":"/","end":""}], - types: placeholder as { - body: {} - paramsTuple: [] - params: {} - query: {} - response: unknown - }, + types: placeholder as Registry['home']['types'], }, - 'newAccount.create': { + 'new_account.create': { methods: ["GET","HEAD"], pattern: '/signup', tokens: [{"old":"/signup","type":0,"val":"signup","end":""}], - types: placeholder as { - body: {} - paramsTuple: [] - params: {} - query: {} - response: ReturnType - }, + types: placeholder as Registry['new_account.create']['types'], }, - 'newAccount.store': { + 'new_account.store': { methods: ["POST"], pattern: '/signup', tokens: [{"old":"/signup","type":0,"val":"signup","end":""}], - types: placeholder as { - body: Infer<(typeof import('#validators/user').signupValidator)> - paramsTuple: [] - params: {} - query: {} - response: ReturnType - }, + types: placeholder as Registry['new_account.store']['types'], }, 'session.create': { methods: ["GET","HEAD"], pattern: '/login', tokens: [{"old":"/login","type":0,"val":"login","end":""}], - types: placeholder as { - body: {} - paramsTuple: [] - params: {} - query: {} - response: ReturnType - }, + types: placeholder as Registry['session.create']['types'], }, 'session.store': { methods: ["POST"], pattern: '/login', tokens: [{"old":"/login","type":0,"val":"login","end":""}], - types: placeholder as { - body: {} - paramsTuple: [] - params: {} - query: {} - response: ReturnType - }, + types: placeholder as Registry['session.store']['types'], }, 'session.destroy': { methods: ["POST"], pattern: '/logout', tokens: [{"old":"/logout","type":0,"val":"logout","end":""}], - types: placeholder as { - body: {} - paramsTuple: [] - params: {} - query: {} - response: ReturnType - }, + types: placeholder as Registry['session.destroy']['types'], } } as const satisfies Record - -declare module '@tuyau/core/types' { - type Registry = typeof registry - export interface UserRegistry extends Registry {} -} diff --git a/package.json b/package.json index 382e59f..e76547e 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "@adonisjs/static": "^2.0.0-next.1", "@adonisjs/vite": "^5.1.0-next.2", "@inertiajs/react": "^2.2.19", - "@tuyau/core": "1.0.0-beta.1", + "@tuyau/core": "1.0.0-beta.2", "@vinejs/vine": "^4.1.0", "better-sqlite3": "^12.5.0", "edge.js": "^6.3.0", From 08e3edf63cf433f3064c4759400a8653b70bfb13 Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Mon, 10 Nov 2025 20:15:53 +0100 Subject: [PATCH 3/4] feat: add Tuyau x Inertia adapter --- inertia/app.tsx | 8 +++++++- inertia/client.ts | 2 +- inertia/layouts/default.tsx | 9 +++++---- inertia/tsconfig.json | 3 ++- vite.config.ts | 2 +- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/inertia/app.tsx b/inertia/app.tsx index e0d0aff..366e30e 100644 --- a/inertia/app.tsx +++ b/inertia/app.tsx @@ -1,9 +1,11 @@ import './css/app.css' +import { client } from './client' import { ReactElement } from 'react' import Layout from '~/layouts/default' import { Data } from '~/generated/data' import { createRoot } from 'react-dom/client' import { createInertiaApp } from '@inertiajs/react' +import { TuyauProvider } from '@adonisjs/inertia/react' import { resolvePageComponent } from '@adonisjs/inertia/helpers' const appName = import.meta.env.VITE_APP_NAME || 'AdonisJS' @@ -18,7 +20,11 @@ createInertiaApp({ ) }, setup({ el, App, props }) { - createRoot(el).render() + createRoot(el).render( + + + + ) }, progress: { color: '#4B5563', diff --git a/inertia/client.ts b/inertia/client.ts index 76eaf4a..9b8fc99 100644 --- a/inertia/client.ts +++ b/inertia/client.ts @@ -1,4 +1,4 @@ -import { registry } from '~/generated/registry' +import { registry } from '~registry' import { createTuyau } from '@tuyau/core/client' export const client = createTuyau({ diff --git a/inertia/layouts/default.tsx b/inertia/layouts/default.tsx index 4fe9e06..467f1e5 100644 --- a/inertia/layouts/default.tsx +++ b/inertia/layouts/default.tsx @@ -1,7 +1,8 @@ import { toast, Toaster } from 'sonner' import { ReactElement, useEffect } from 'react' import { Data } from '~/generated/data' -import { Form, Link, usePage } from '@inertiajs/react' +import { Form, usePage } from '@inertiajs/react' +import { Link } from '@adonisjs/inertia/react' export default function Layout({ children }: { children: ReactElement }) { useEffect(() => { @@ -17,7 +18,7 @@ export default function Layout({ children }: { children: ReactElement
- + ) : ( <> - Signup - Login + Signup + Login )} diff --git a/inertia/tsconfig.json b/inertia/tsconfig.json index 6020976..31edf4b 100644 --- a/inertia/tsconfig.json +++ b/inertia/tsconfig.json @@ -7,7 +7,8 @@ "composite": true, "paths": { "~/*": ["./*"], - "~/generated/*": ["../.adonisjs/client/*"] + "~/generated/*": ["../.adonisjs/client/*"], + "~registry": ["../.adonisjs/client/registry.ts"] } }, "include": ["./**/*.ts", "./**/*.tsx", "../.adonisjs/client/**/*.ts"] diff --git a/vite.config.ts b/vite.config.ts index f5438ae..d06605d 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -17,7 +17,7 @@ export default defineConfig({ resolve: { alias: { '~/': `${import.meta.dirname}/inertia/`, - '~/generated/registry': `${import.meta.dirname}/../.adonisjs/client/registry.js`, + '~registry': `${import.meta.dirname}/.adonisjs/client/registry.ts`, }, }, }) From adcbf7212fd9f93079292502a789921730aeb8c7 Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Sat, 6 Dec 2025 17:13:58 +0100 Subject: [PATCH 4/4] refactor: update tuyau --- .adonisjs/client/registry.schema.d.ts | 20 ++++++++---------- .adonisjs/client/registry.schema.tree.d.ts | 15 ++++++++++++++ .adonisjs/client/registry.ts | 24 ++++++++++++++++++---- inertia/layouts/default.tsx | 6 ++---- package.json | 4 ++-- 5 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 .adonisjs/client/registry.schema.tree.d.ts diff --git a/.adonisjs/client/registry.schema.d.ts b/.adonisjs/client/registry.schema.d.ts index 4c611f1..08dc399 100644 --- a/.adonisjs/client/registry.schema.d.ts +++ b/.adonisjs/client/registry.schema.d.ts @@ -1,7 +1,7 @@ /* eslint-disable prettier/prettier */ /// -import type { AdonisEndpoint } from '@tuyau/core/types' +import type { ExtractBody, ExtractQuery } from '@tuyau/core/types' import type { Infer } from '@vinejs/vine/types' export interface Registry { @@ -24,18 +24,18 @@ export interface Registry { paramsTuple: [] params: {} query: {} - response: ReturnType + response: Awaited> } } 'new_account.store': { methods: ["POST"] pattern: '/signup' types: { - body: Infer<(typeof import('#validators/user').signupValidator)> + body: ExtractBody> paramsTuple: [] params: {} - query: {} - response: ReturnType + query: ExtractQuery> + response: Awaited> } } 'session.create': { @@ -46,7 +46,7 @@ export interface Registry { paramsTuple: [] params: {} query: {} - response: ReturnType + response: Awaited> } } 'session.store': { @@ -57,7 +57,7 @@ export interface Registry { paramsTuple: [] params: {} query: {} - response: ReturnType + response: Awaited> } } 'session.destroy': { @@ -68,11 +68,7 @@ export interface Registry { paramsTuple: [] params: {} query: {} - response: ReturnType + response: Awaited> } } } - -declare module '@tuyau/core/types' { - export interface UserRegistry extends Registry {} -} diff --git a/.adonisjs/client/registry.schema.tree.d.ts b/.adonisjs/client/registry.schema.tree.d.ts new file mode 100644 index 0000000..1549851 --- /dev/null +++ b/.adonisjs/client/registry.schema.tree.d.ts @@ -0,0 +1,15 @@ +/* eslint-disable prettier/prettier */ +import type { routes } from './registry.ts' + +export interface ApiDefinition { + home: typeof routes['home'] + newAccount: { + create: typeof routes['new_account.create'] + store: typeof routes['new_account.store'] + } + session: { + create: typeof routes['session.create'] + store: typeof routes['session.store'] + destroy: typeof routes['session.destroy'] + } +} diff --git a/.adonisjs/client/registry.ts b/.adonisjs/client/registry.ts index b5205fc..aae525e 100644 --- a/.adonisjs/client/registry.ts +++ b/.adonisjs/client/registry.ts @@ -1,9 +1,11 @@ /* eslint-disable prettier/prettier */ -import { type AdonisEndpoint } from '@tuyau/core/types' -import type { Registry } from './registry.schema' +import type { AdonisEndpoint } from '@tuyau/core/types' +import type { Registry } from './registry.schema.d.ts' +import type { ApiDefinition } from './registry.schema.tree.d.ts' + const placeholder: any = {} -export const registry = { +const routes = { 'home': { methods: ["GET","HEAD"], pattern: '/', @@ -39,5 +41,19 @@ export const registry = { pattern: '/logout', tokens: [{"old":"/logout","type":0,"val":"logout","end":""}], types: placeholder as Registry['session.destroy']['types'], - } + }, } as const satisfies Record + +export { routes } + +export const registry = { + routes, + $tree: {} as ApiDefinition, +} + +declare module '@tuyau/core/types' { + export interface UserRegistry { + routes: typeof routes + $tree: ApiDefinition + } +} diff --git a/inertia/layouts/default.tsx b/inertia/layouts/default.tsx index 467f1e5..3e35d58 100644 --- a/inertia/layouts/default.tsx +++ b/inertia/layouts/default.tsx @@ -1,7 +1,7 @@ import { toast, Toaster } from 'sonner' import { ReactElement, useEffect } from 'react' import { Data } from '~/generated/data' -import { Form, usePage } from '@inertiajs/react' +import { usePage } from '@inertiajs/react' import { Link } from '@adonisjs/inertia/react' export default function Layout({ children }: { children: ReactElement }) { @@ -36,9 +36,7 @@ export default function Layout({ children }: { children: ReactElement