chore: improve type safety Tuyau
This commit is contained in:
parent
4add77856e
commit
20ab889cf8
3
TODO.md
3
TODO.md
@ -40,8 +40,7 @@
|
||||
- [ ] Share VineJS validators between `website` and `api`
|
||||
- [ ] Implement Wikipedia Game Solver (`website`)
|
||||
- [x] Init Next.js project
|
||||
- [ ] Try to use <https://www.npmjs.com/package/@tuyau/client> for API calls
|
||||
- [ ] Hard code 2 pages to test if it works with `console.log` in the browser
|
||||
- [x] Try to use <https://www.npmjs.com/package/@tuyau/client> for API calls
|
||||
- [ ] Implement a form with inputs, button to submit, and list all pages to go from one to another, or none if it is not possible
|
||||
- [ ] Add images, links to the pages + good UI/UX
|
||||
- [ ] Autocompletion page titles
|
||||
|
@ -11,9 +11,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["app/controllers/**/*.ts", "app/middleware/**/*.ts"],
|
||||
"files": ["app/controllers/**/*.ts"],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/naming-convention": "off"
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,31 @@ import { healthChecks } from "#start/health.ts"
|
||||
import { middleware } from "#start/kernel.ts"
|
||||
import type { HttpContext } from "@adonisjs/core/http"
|
||||
import router from "@adonisjs/core/services/router"
|
||||
import type { HealthCheckReport } from "@adonisjs/core/types/health"
|
||||
|
||||
export default class get_health_controller {
|
||||
public async handle(context: HttpContext) {
|
||||
public async handle(context: HttpContext): Promise<
|
||||
| {
|
||||
__response: HealthCheckReport
|
||||
__status: 200
|
||||
}
|
||||
| {
|
||||
__response: HealthCheckReport
|
||||
__status: 503
|
||||
}
|
||||
> {
|
||||
const report = await healthChecks.run()
|
||||
if (report.isHealthy) {
|
||||
return context.response.ok(report)
|
||||
if (!report.isHealthy) {
|
||||
return context.response.serviceUnavailable(report)
|
||||
}
|
||||
return context.response.serviceUnavailable(report)
|
||||
return context.response.ok(report)
|
||||
}
|
||||
}
|
||||
|
||||
router.get("/health", [get_health_controller]).use(middleware.appKeySecurity())
|
||||
router
|
||||
.get("/health", [get_health_controller])
|
||||
.use(middleware.appKeySecurity())
|
||||
.openapi({
|
||||
description: "Ensure that the application is in a healthy state.",
|
||||
tags: ["health"],
|
||||
})
|
||||
|
@ -1,3 +1,4 @@
|
||||
import type { ExceptionMessage } from "#app/exceptions/handler.ts"
|
||||
import Page, { type PageWithInternalLinksRaw } from "#app/models/page.ts"
|
||||
import { throttle } from "#start/limiter.ts"
|
||||
import type { HttpContext } from "@adonisjs/core/http"
|
||||
@ -13,13 +14,22 @@ export const get_wikipedia_page_by_id_validator = vine.compile(
|
||||
)
|
||||
|
||||
export default class get_wikipedia_page_by_id {
|
||||
public async handle(context: HttpContext): Promise<PageWithInternalLinksRaw> {
|
||||
public async handle(context: HttpContext): Promise<
|
||||
| {
|
||||
__response: ExceptionMessage
|
||||
__status: 404
|
||||
}
|
||||
| {
|
||||
__response: PageWithInternalLinksRaw
|
||||
__status: 200
|
||||
}
|
||||
> {
|
||||
const payload = await context.request.validateUsing(
|
||||
get_wikipedia_page_by_id_validator,
|
||||
)
|
||||
const page = await Page.findOrFail(payload.params.id)
|
||||
await page.load("internalLinks")
|
||||
return page
|
||||
return context.response.ok(page)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,14 +25,17 @@ export const get_wikipedia_pages_validator = vine.compile(
|
||||
)
|
||||
|
||||
export default class get_wikipedia_pages {
|
||||
public async handle(context: HttpContext): Promise<PageRaw[]> {
|
||||
public async handle(context: HttpContext): Promise<{
|
||||
__response: PageRaw[]
|
||||
__status: 200
|
||||
}> {
|
||||
const payload = await context.request.validateUsing(
|
||||
get_wikipedia_pages_validator,
|
||||
)
|
||||
const pages = await Page.query()
|
||||
.whereLike("title", `${payload.title}%`)
|
||||
.limit(payload.limit)
|
||||
return pages
|
||||
return context.response.ok(pages)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,10 @@ import type { HttpContext } from "@adonisjs/core/http"
|
||||
import { ExceptionHandler } from "@adonisjs/core/http"
|
||||
import app from "@adonisjs/core/services/app"
|
||||
|
||||
export interface ExceptionMessage {
|
||||
message: string
|
||||
}
|
||||
|
||||
export default class HttpExceptionHandler extends ExceptionHandler {
|
||||
/**
|
||||
* In debug mode, the exception handler will display verbose errors with pretty printed stack traces.
|
||||
|
@ -1,9 +1,13 @@
|
||||
import type { ExceptionMessage } from "#app/exceptions/handler.ts"
|
||||
import { APP_KEY, APP_KEY_HEADER_NAME } from "#config/app.ts"
|
||||
import type { HttpContext } from "@adonisjs/core/http"
|
||||
import type { NextFn } from "@adonisjs/core/types/http"
|
||||
|
||||
export default class AppKeySecurityMiddleware {
|
||||
public async handle(context: HttpContext, next: NextFn) {
|
||||
public async handle(
|
||||
context: HttpContext,
|
||||
next: NextFn,
|
||||
): Promise<unknown | ExceptionMessage> {
|
||||
if (context.request.header(APP_KEY_HEADER_NAME) === APP_KEY) {
|
||||
return next()
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ export default class AuthMiddleware {
|
||||
options: {
|
||||
guards?: Array<keyof Authenticators>
|
||||
} = {},
|
||||
) {
|
||||
): Promise<void> {
|
||||
await context.auth.authenticateUsing(options.guards, {
|
||||
loginRoute: this.redirectTo,
|
||||
})
|
||||
|
@ -9,7 +9,7 @@ import type { NextFn } from "@adonisjs/core/types/http"
|
||||
* - And bind "Logger" class to the "context.logger" object.
|
||||
*/
|
||||
export default class ContainerBindingsMiddleware {
|
||||
public async handle(context: HttpContext, next: NextFn) {
|
||||
public async handle(context: HttpContext, next: NextFn): Promise<void> {
|
||||
context.containerResolver.bindValue(HttpContext, context)
|
||||
context.containerResolver.bindValue(Logger, context.logger)
|
||||
|
||||
|
@ -5,7 +5,7 @@ import type { NextFn } from "@adonisjs/core/types/http"
|
||||
* Updating the "Accept" header to always accept "application/json" response from the server. This will force the internals of the framework like validator errors or auth errors to return a JSON response.
|
||||
*/
|
||||
export default class ForceJsonResponseMiddleware {
|
||||
public async handle({ request }: HttpContext, next: NextFn) {
|
||||
public async handle({ request }: HttpContext, next: NextFn): Promise<void> {
|
||||
const headers = request.headers()
|
||||
headers.accept = "application/json"
|
||||
|
||||
|
@ -12,7 +12,7 @@ const tuyauConfig = defineConfig({
|
||||
title: "Wikipedia Game Solver API",
|
||||
version: VERSION,
|
||||
},
|
||||
tags: [{ name: "users" }, { name: "wikipedia" }],
|
||||
tags: [{ name: "health" }, { name: "users" }, { name: "wikipedia" }],
|
||||
servers: [{ url: env.get("API_URL") }],
|
||||
},
|
||||
},
|
||||
|
@ -34,7 +34,9 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"@tuyau/core@0.1.4": "patches/@tuyau__core@0.1.4.patch"
|
||||
"@tuyau/core@0.1.4": "patches/@tuyau__core@0.1.4.patch",
|
||||
"@tuyau/openapi@0.2.0": "patches/@tuyau__openapi@0.2.0.patch",
|
||||
"@tuyau/client@0.1.2": "patches/@tuyau__client@0.1.2.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,10 +39,20 @@ export const WikipediaClient: React.FC = () => {
|
||||
|
||||
const data = await api.wikipedia
|
||||
.pages({ id: fromPageWikipediaLinks.pageId })
|
||||
// TODO: any
|
||||
.$get({} as any)
|
||||
.$get({})
|
||||
.unwrap()
|
||||
console.log(data)
|
||||
|
||||
const data2 = await api.wikipedia.pages
|
||||
.$get({
|
||||
query: {
|
||||
title: "Node.j",
|
||||
limit: 5,
|
||||
},
|
||||
})
|
||||
.unwrap()
|
||||
console.log(data2)
|
||||
|
||||
// const deepInternalLinks = await getDeepWikipediaPageInternalLinks({
|
||||
// locale: localeWikipedia,
|
||||
// data: {
|
||||
|
19
patches/@tuyau__client@0.1.2.patch
Normal file
19
patches/@tuyau__client@0.1.2.patch
Normal file
@ -0,0 +1,19 @@
|
||||
diff --git a/build/index.d.ts b/build/index.d.ts
|
||||
index fd28b2fd3f91f0312e933189df5b635eeb692281..445d47f6f18a981bba7c0e784a03972bdf99c880 100644
|
||||
--- a/build/index.d.ts
|
||||
+++ b/build/index.d.ts
|
||||
@@ -83,11 +83,11 @@ type TuyauRpcClient<in out Route extends Record<string, any>> = {
|
||||
response: infer Res extends Record<number, unknown>;
|
||||
request: infer Request;
|
||||
} ? K extends '$get' | '$head' ? unknown extends Request ? (options?: TuyauQueryOptions & {
|
||||
- query?: Request;
|
||||
+ query?: Omit<Request, 'cookies' | 'headers' | 'params'>;
|
||||
}) => ResponseOrUnwrap<Res> : {} extends Request ? (options?: TuyauQueryOptions & {
|
||||
- query?: Request;
|
||||
+ query?: Omit<Request, 'cookies' | 'headers' | 'params'>;
|
||||
}) => ResponseOrUnwrap<Res> : (options: TuyauQueryOptions & {
|
||||
- query: Request;
|
||||
+ query?: Omit<Request, 'cookies' | 'headers' | 'params'>;
|
||||
}) => ResponseOrUnwrap<Res> : {} extends Request ? (body?: Request | null, options?: TuyauQueryOptions) => ResponseOrUnwrap<Res> : (body: Request, options?: TuyauQueryOptions) => ResponseOrUnwrap<Res> : K extends '$url' ? () => string : CreateParams<Route[K]>;
|
||||
};
|
||||
type CreateParams<Route extends Record<string, any>> = Extract<keyof Route, `:${string}`> extends infer Path extends string ? IsNever<Path> extends true ? Prettify<TuyauRpcClient<Route>> : ((params: {
|
13
patches/@tuyau__openapi@0.2.0.patch
Normal file
13
patches/@tuyau__openapi@0.2.0.patch
Normal file
@ -0,0 +1,13 @@
|
||||
diff --git a/build/chunk-DFECKFQT.js b/build/chunk-DFECKFQT.js
|
||||
index 0740bf03f8c9de643f09fdcf02c43e40eb5efa55..ff348509b0e77b0b98e6e6db57c3355e3e0914f7 100644
|
||||
--- a/build/chunk-DFECKFQT.js
|
||||
+++ b/build/chunk-DFECKFQT.js
|
||||
@@ -266,7 +266,7 @@ var OpenApiGenerator = class {
|
||||
for (const prop of type.getProperties()) {
|
||||
const propName = prop.getName();
|
||||
const type2 = prop.getValueDeclaration()?.getType();
|
||||
- if (!type2)
|
||||
+ if (!type2 || (mode === 'request' && ['cookies', 'headers', 'params'].includes(propName)))
|
||||
continue;
|
||||
if (type2.isArray()) {
|
||||
properties2[propName] = {
|
@ -245,9 +245,15 @@ catalogs:
|
||||
version: 2.0.5
|
||||
|
||||
patchedDependencies:
|
||||
'@tuyau/client@0.1.2':
|
||||
hash: fb6mal6i73tvzidaazfbwsp5ya
|
||||
path: patches/@tuyau__client@0.1.2.patch
|
||||
'@tuyau/core@0.1.4':
|
||||
hash: zzabo2h6qjt52qr7ntgx4dwdpa
|
||||
path: patches/@tuyau__core@0.1.4.patch
|
||||
'@tuyau/openapi@0.2.0':
|
||||
hash: i6nyw7jxy3i3iokbuvzj62ysse
|
||||
path: patches/@tuyau__openapi@0.2.0.patch
|
||||
|
||||
importers:
|
||||
|
||||
@ -315,7 +321,7 @@ importers:
|
||||
version: 0.1.4(patch_hash=zzabo2h6qjt52qr7ntgx4dwdpa)(@adonisjs/core@6.12.1(@adonisjs/assembler@7.7.0(typescript@5.5.4))(@vinejs/vine@2.1.0))
|
||||
'@tuyau/openapi':
|
||||
specifier: 'catalog:'
|
||||
version: 0.2.0(@tuyau/core@0.1.4(patch_hash=zzabo2h6qjt52qr7ntgx4dwdpa)(@adonisjs/core@6.12.1(@adonisjs/assembler@7.7.0(typescript@5.5.4))(@vinejs/vine@2.1.0)))
|
||||
version: 0.2.0(patch_hash=i6nyw7jxy3i3iokbuvzj62ysse)(@tuyau/core@0.1.4(patch_hash=zzabo2h6qjt52qr7ntgx4dwdpa)(@adonisjs/core@6.12.1(@adonisjs/assembler@7.7.0(typescript@5.5.4))(@vinejs/vine@2.1.0)))
|
||||
'@tuyau/utils':
|
||||
specifier: 'catalog:'
|
||||
version: 0.0.4
|
||||
@ -598,7 +604,7 @@ importers:
|
||||
dependencies:
|
||||
'@tuyau/client':
|
||||
specifier: 'catalog:'
|
||||
version: 0.1.2
|
||||
version: 0.1.2(patch_hash=fb6mal6i73tvzidaazfbwsp5ya)
|
||||
devDependencies:
|
||||
'@repo/api':
|
||||
specifier: 'workspace:'
|
||||
@ -12578,7 +12584,7 @@ snapshots:
|
||||
mkdirp: 3.0.1
|
||||
path-browserify: 1.0.1
|
||||
|
||||
'@tuyau/client@0.1.2':
|
||||
'@tuyau/client@0.1.2(patch_hash=fb6mal6i73tvzidaazfbwsp5ya)':
|
||||
dependencies:
|
||||
'@poppinss/matchit': 3.1.2
|
||||
ky: 1.6.0
|
||||
@ -12589,7 +12595,7 @@ snapshots:
|
||||
'@adonisjs/core': 6.12.1(@adonisjs/assembler@7.7.0(typescript@5.5.4))(@vinejs/vine@2.1.0)
|
||||
ts-morph: 22.0.0
|
||||
|
||||
'@tuyau/openapi@0.2.0(@tuyau/core@0.1.4(patch_hash=zzabo2h6qjt52qr7ntgx4dwdpa)(@adonisjs/core@6.12.1(@adonisjs/assembler@7.7.0(typescript@5.5.4))(@vinejs/vine@2.1.0)))':
|
||||
'@tuyau/openapi@0.2.0(patch_hash=i6nyw7jxy3i3iokbuvzj62ysse)(@tuyau/core@0.1.4(patch_hash=zzabo2h6qjt52qr7ntgx4dwdpa)(@adonisjs/core@6.12.1(@adonisjs/assembler@7.7.0(typescript@5.5.4))(@vinejs/vine@2.1.0)))':
|
||||
dependencies:
|
||||
'@tuyau/core': 0.1.4(patch_hash=zzabo2h6qjt52qr7ntgx4dwdpa)(@adonisjs/core@6.12.1(@adonisjs/assembler@7.7.0(typescript@5.5.4))(@vinejs/vine@2.1.0))
|
||||
defu: 6.1.4
|
||||
|
Reference in New Issue
Block a user