From d0a2f491ba2c7cfa6beeef6f026f84a0eb131e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Charles?= Date: Wed, 11 Dec 2024 14:08:38 +0100 Subject: [PATCH] doc: RuntimeAdapter (#87) --- docs/.vitepress/config.ts | 4 + docs/reference/runtime-adapter.md | 251 ++++++++++++++++++++++++++++++ packages/core/src/types.ts | 2 + 3 files changed, 257 insertions(+) create mode 100644 docs/reference/runtime-adapter.md diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 80d711b6..76716cc1 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -108,6 +108,10 @@ export default defineConfig({ text: "Definitions", link: "/definitions", }, + { + text: "RuntimeAdapter", + link: "/reference/runtime-adapter", + }, { text: "Supported adapters", link: "/reference/supported-adapters" }, ], diff --git a/docs/reference/runtime-adapter.md b/docs/reference/runtime-adapter.md new file mode 100644 index 00000000..2f7a4ea3 --- /dev/null +++ b/docs/reference/runtime-adapter.md @@ -0,0 +1,251 @@ +# Using `RuntimeAdapter` in userland + +Any package generated through `universal-middleware` exposes a `RuntimeAdapter` type. + +It can be used to type `runtime` when exposed to userland. + +### Adapter specific properties + +::: code-group + +```ts twoslash [hono] +// @noErrors +import type { Runtime, HonoAdapter } from "@universal-middleware/core"; + +export type Explain = + A extends Function + ? A + : {[K in keyof A]: A[K]} & unknown + +type RuntimeAdapter = Explain; + +// ---cut--- +import type { RuntimeAdapter } from "somelib/hono"; + +const runtime: RuntimeAdapter; + +// original Hono Context. See https://hono.dev/docs/api/context +runtime.hono; +// ^^^^ +``` + +```ts twoslash [h3] +// @noErrors +import type { Runtime, H3Adapter } from "@universal-middleware/core"; + +export type Explain = + A extends Function + ? A + : {[K in keyof A]: A[K]} & unknown + +type RuntimeAdapter = Explain; + +// ---cut--- +import type { RuntimeAdapter } from "somelib/h3"; + +const runtime: RuntimeAdapter; + +// original H3 Event. See https://h3.unjs.io/guide/event +runtime.h3; +// ^^ +``` + +```ts twoslash [hattip] +// @noErrors +import type { Runtime, HattipAdapter } from "@universal-middleware/core"; + +export type Explain = + A extends Function + ? A + : {[K in keyof A]: A[K]} & unknown + +type RuntimeAdapter = Explain; + +// ---cut--- +import type { RuntimeAdapter } from "somelib/hattip"; + +const runtime: RuntimeAdapter; + +// original Hattip context +runtime.hattip; +// ^^^^^^ +``` + +```ts twoslash [cloudflare-worker] +// @noErrors +import type { Runtime, CloudflareWorkerAdapter } from "@universal-middleware/core"; + +export type Explain = + A extends Function + ? A + : {[K in keyof A]: A[K]} & unknown + +type RuntimeAdapter = Explain; + +// ---cut--- +import type { RuntimeAdapter } from "somelib/cloudflare-worker"; + +const runtime: RuntimeAdapter; +const originalParameters = runtime["cloudflare-worker"]; + +// original Cloudflare Worker env. See https://developers.cloudflare.com/workers/runtime-apis/bindings/ +originalParameters.env; +// ^^^ +// original Cloudflare Worker ctx. See https://developers.cloudflare.com/workers/runtime-apis/context/ +originalParameters.ctx; +// ^^^ +``` + +```ts twoslash [cloudflare-pages] +// @noErrors +import type { Runtime, CloudflarePagesAdapter } from "@universal-middleware/core"; + +export type Explain = + A extends Function + ? A + : {[K in keyof A]: A[K]} & unknown + +type RuntimeAdapter = Explain; + +// ---cut--- +import type { RuntimeAdapter } from "somelib/cloudflare-pages"; + +const runtime: RuntimeAdapter; + +// original Cloudflare Worker context. See https://developers.cloudflare.com/pages/functions/api-reference/#eventcontext +const originalContext = runtime["cloudflare-pages"]; +// ^^^^^^^^^^^^^^^ +``` + +```ts twoslash [express] +// @noErrors +import type { Runtime, ExpressAdapter } from "@universal-middleware/core"; + +export type Explain = + A extends Function + ? A + : {[K in keyof A]: A[K]} & unknown + +type RuntimeAdapter = Explain; + +// ---cut--- +import type { RuntimeAdapter } from "somelib/express"; + +const runtime: RuntimeAdapter; + +// original express `req` and `res`. See https://expressjs.com/en/guide/using-middleware.html +runtime.express; +// ^^^^^^^ +``` + +```ts twoslash [fastify] +// @noErrors +import type { Runtime, FastifyAdapter } from "@universal-middleware/core"; + +export type Explain = + A extends Function + ? A + : {[K in keyof A]: A[K]} & unknown + +type RuntimeAdapter = Explain; + +// ---cut--- +import type { RuntimeAdapter } from "somelib/fastify"; + +const runtime: RuntimeAdapter; + +// original fastify `request` and `reply`. See https://fastify.dev/docs/latest/Guides/Getting-Started/ +runtime.fastify; +// ^^^^^^^ +``` + +```ts twoslash [elysia] +// @noErrors +import type { Runtime, ElysiaAdapter } from "@universal-middleware/core"; + +export type Explain = + A extends Function + ? A + : {[K in keyof A]: A[K]} & unknown + +type RuntimeAdapter = Explain; + +// ---cut--- +import type { RuntimeAdapter } from "somelib/elysia"; + +const runtime: RuntimeAdapter; + +// original elysia context. See https://elysiajs.com/essential/handler#context +runtime.elysia; +// ^^^^^^ +``` + +```ts twoslash [vercel-node] +// @noErrors +import type { Runtime, VercelNodeAdapter } from "@universal-middleware/core"; + +export type Explain = + A extends Function + ? A + : {[K in keyof A]: A[K]} & unknown + +type RuntimeAdapter = Explain; + +// ---cut--- +import type { RuntimeAdapter } from "somelib/vercel-node"; + +const runtime: RuntimeAdapter; + +// original node `req` and `res`. See https://expressjs.com/en/guide/using-middleware.html +const originalParameters = runtime["vercel-node"]; +// ^^^^^^^^^^^^^^^^^^ +``` + +::: + +### Common properties + +All `runtime` objects can also contain the following properties: + +```ts twoslash +// @noErrors +import type { Runtimes, Adapters } from "@universal-middleware/core"; +import type { IncomingMessage, ServerResponse } from "node:http"; + +export type Explain = + A extends Function + ? A + : { [K in keyof A]: A[K] } & unknown + +interface _RuntimeAdapter { + adapter: Adapters; + runtime: Runtimes; + params?: Record; + req?: IncomingMessage; + res?: ServerResponse; +} + +type RuntimeAdapter = Explain<_RuntimeAdapter>; + +// ---cut--- +const runtime: RuntimeAdapter; + +// identify which adapter is currently used +runtime.adapter; +// ^^^^^^^ +// runtime environment identifier. See https://runtime-keys.proposal.wintercg.org/ +runtime.runtime; +// ^^^^^^^ +// extracted route parameters. See http://localhost:5173/recipes/params-handler +runtime.params; +// ^^^^^^ +// original `req` if running inside node +runtime.req; +// ^^^ +// original `res` if running inside node +runtime.res; +// ^^^ +``` + +> [!NOTE] +> All runtime types are defined in [types.ts](https://github.com/magne4000/universal-middleware/blob/main/packages/core/src/types.ts) diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 95322a4d..20b7f99e 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -214,6 +214,8 @@ export type Adapter = | OtherAdapter; export type RuntimeAdapter = Runtime & Adapter; export type RuntimeAdapterTarget = T extends string ? Runtime & Extract : RuntimeAdapter; +export type Adapters = Adapter["adapter"]; +export type Runtimes = Runtime["runtime"]; export type UniversalMiddleware< InContext extends Universal.Context = Universal.Context,