-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: starting documentation website * docs: progress * docs: .gitignore * docs: progress * docs: prepare for wip release * fix: tests
- Loading branch information
Showing
30 changed files
with
2,027 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Sample workflow for building and deploying a VitePress site to GitHub Pages | ||
# | ||
name: Deploy VitePress site to Pages | ||
|
||
on: | ||
# Runs on pushes targeting the `main` branch. Change this to `master` if you're | ||
# using the `master` branch as the default branch. | ||
push: | ||
branches: [main] | ||
|
||
# Allows you to run this workflow manually from the Actions tab | ||
workflow_dispatch: | ||
|
||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages | ||
permissions: | ||
contents: read | ||
pages: write | ||
id-token: write | ||
|
||
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. | ||
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. | ||
concurrency: | ||
group: pages | ||
cancel-in-progress: false | ||
|
||
jobs: | ||
# Build job | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 # Not needed if lastUpdated is not enabled | ||
- uses: pnpm/action-setup@v4 | ||
- name: Setup Node | ||
uses: actions/setup-node@v4 | ||
with: | ||
node-version: 20 | ||
cache: pnpm | ||
- name: Setup Pages | ||
uses: actions/configure-pages@v5 | ||
- name: Install dependencies | ||
run: pnpm i | ||
- name: Build with VitePress | ||
run: pnpm run build-doc | ||
with: | ||
path: docs | ||
- name: Upload artifact | ||
uses: actions/upload-pages-artifact@v3 | ||
with: | ||
path: docs/.vitepress/dist | ||
|
||
# Deployment job | ||
deploy: | ||
environment: | ||
name: github-pages | ||
url: ${{ steps.deployment.outputs.page_url }} | ||
needs: build | ||
runs-on: ubuntu-latest | ||
name: Deploy | ||
steps: | ||
- name: Deploy to GitHub Pages | ||
id: deployment | ||
uses: actions/deploy-pages@v4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { defineConfig } from "vitepress"; | ||
import { transformerTwoslash } from "@shikijs/vitepress-twoslash"; | ||
import type { ModuleResolutionKind } from "typescript"; | ||
|
||
// https://vitepress.dev/reference/site-config | ||
export default defineConfig({ | ||
cleanUrls: true, | ||
markdown: { | ||
codeTransformers: [ | ||
transformerTwoslash({ | ||
twoslashOptions: { | ||
compilerOptions: { | ||
verbatimModuleSyntax: true, | ||
moduleResolution: 100 satisfies ModuleResolutionKind.Bundler, | ||
}, | ||
}, | ||
}), | ||
], | ||
}, | ||
title: "universal-middleware", | ||
description: | ||
"Write universal middlewares and handlers once, target all supported servers", | ||
themeConfig: { | ||
// https://vitepress.dev/reference/default-theme-config | ||
nav: [ | ||
{ text: "Guide", link: "/guide/what-is-universal-middleware" }, | ||
{ text: "Examples", link: "/examples/context-middleware" }, | ||
], | ||
|
||
sidebar: [ | ||
{ | ||
text: "Middlewares", | ||
items: [ | ||
{ | ||
text: "Updating the context", | ||
link: "/examples/context-middleware", | ||
}, | ||
{ | ||
text: "Updating the headers", | ||
link: "/examples/headers-middleware", | ||
}, | ||
{ | ||
text: "Return an early response", | ||
link: "/examples/guard-middleware", | ||
}, | ||
], | ||
}, | ||
], | ||
|
||
socialLinks: [ | ||
{ icon: "github", link: "https://github.com/vuejs/vitepress" }, | ||
], | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import DefaultTheme from "vitepress/theme"; | ||
import TwoslashFloatingVue from "@shikijs/vitepress-twoslash/client"; | ||
import "@shikijs/vitepress-twoslash/style.css"; | ||
import type { EnhanceAppContext } from "vitepress"; | ||
|
||
export default { | ||
extends: DefaultTheme, | ||
enhanceApp({ app }: EnhanceAppContext) { | ||
app.use(TwoslashFloatingVue); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# Definitions | ||
|
||
## Handler | ||
A function that returns a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response). | ||
|
||
```ts twoslash | ||
export interface UniversalHandler<Context> { | ||
(request: Request, context: Context): Response | Promise<Response>; | ||
} | ||
``` | ||
|
||
> [!NOTE] | ||
> In some frameworks, a Response can be anything from a web Response, a string, an object, a ServerResponse, etc. | ||
> Only web Response are supported by `universal-middleware`, as this is part of the [WinterCG standard](https://fetch.spec.wintercg.org/#responses). | ||
## Middleware | ||
A function that alters the [Context](#context) or Response. | ||
Check the [examples](/examples/context-middleware) for details. | ||
|
||
```ts twoslash | ||
export interface UniversalMiddleware<InContext, OutContext> { | ||
(request: Request, context: InContext): | ||
| Response | Promise<Response> // Can return an early Response | ||
| void | Promise<void> // Can return nothing | ||
| OutContext | Promise<OutContext> // Can return a new context. Ensures type-safe context representation | ||
| ((response: Response) => Response | Promise<Response>); // Can return a function that manipulates the Response | ||
} | ||
``` | ||
|
||
## Context | ||
Some data, usually added by a middleware, with the same lifespan as a Request. | ||
|
||
For instance, a `{ user?: User }` context can be set by a middleware, then accessed by others. | ||
|
||
> [!NOTE] | ||
> Each framework as its own way to attach data related to the request, | ||
> either by attaching values to their internal request representation (like Express), | ||
> or by having their own context encapsulating the request (like Hono). | ||
> | ||
> _On the other hand, a universal context is just an object, detached from the request, | ||
> but with the same lifespan._ | ||
> [!TIP] | ||
> Each adapter provides a `getContext` helper to retrieve the universal context | ||
> from any non-universal middleware or handler. | ||
> [!NOTE] | ||
> TODO `Universal.Context` | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
# Updating the Context | ||
|
||
In this example, we're creating a middleware that adds a `hello` property to the context. | ||
This property will then be accessible to any subsequent middleware or handler. | ||
|
||
<<< @/../examples/tool/src/middlewares/context.middleware.ts | ||
|
||
After bundling and publishing this middleware, one can then use this middleware as follows: | ||
|
||
::: code-group | ||
|
||
```ts twoslash [hono-entry.ts] | ||
import { Hono } from "hono"; | ||
import contextMiddleware from "@universal-middleware-examples/tool/middlewares/context-middleware-hono"; | ||
import { getContext } from "@universal-middleware/hono"; | ||
|
||
const app = new Hono(); | ||
|
||
// Now the universal context contains `{ hello: "world" }` | ||
app.use(contextMiddleware("world")); | ||
|
||
app.get("/", (honoCtx) => { | ||
// The universal context can be retrieved through `getContext` helper | ||
// outside of universal middlewares and handlers | ||
const universalCtx = getContext<{ hello: string }>(honoCtx)!; | ||
return new Response(`Hello ${universalCtx.hello}`); | ||
}); | ||
|
||
export default app; | ||
``` | ||
|
||
```ts twoslash [h3-entry.ts] | ||
import { createApp, createRouter, defineEventHandler } from "h3"; | ||
import contextMiddleware from "@universal-middleware-examples/tool/middlewares/context-middleware-h3"; | ||
import { getContext, universalOnBeforeResponse } from "@universal-middleware/h3"; | ||
|
||
const app = createApp({ | ||
// /!\ This is required for universal-middleware to operate properly | ||
onBeforeResponse: universalOnBeforeResponse, | ||
}); | ||
|
||
// Now the universal context contains `{ hello: "world" }`. | ||
app.use(contextMiddleware("world")); | ||
|
||
const router = createRouter(); | ||
|
||
router.get("/", defineEventHandler((event) => { | ||
// The universal context can be retrieved through `getContext` helper | ||
// outside of universal middlewares and handlers | ||
const universalCtx = getContext<{ hello: string }>(event)!; | ||
|
||
return `Hello ${universalCtx.hello}`; | ||
})); | ||
|
||
app.use(router); | ||
|
||
export default app; | ||
``` | ||
|
||
```ts twoslash [hattip-entry.ts] | ||
import { createRouter } from "@hattip/router"; | ||
import contextMiddleware from "@universal-middleware-examples/tool/middlewares/context-middleware-hattip"; | ||
import { getContext } from "@universal-middleware/hattip"; | ||
|
||
const app = createRouter(); | ||
|
||
// Now the universal context contains `{ hello: "world" }`. | ||
app.use(contextMiddleware("world")); | ||
|
||
app.get("/", (honoCtx) => { | ||
// The universal context can be retrieved through `getContext` helper | ||
// outside of universal middlewares and handlers | ||
const universalCtx = getContext<{ hello: string }>(honoCtx)!; | ||
return new Response(`Hello ${universalCtx.hello}`); | ||
}); | ||
|
||
const hattipHandler = app.buildHandler(); | ||
|
||
export default hattipHandler; | ||
``` | ||
|
||
```ts twoslash [express-entry.ts] | ||
import contextMiddleware from "@universal-middleware-examples/tool/middlewares/context-middleware-express"; | ||
import express from "express"; | ||
import { getContext } from "@universal-middleware/express"; | ||
|
||
const app = express(); | ||
|
||
// Now the universal context contains `{ hello: "world" }`. | ||
app.use(contextMiddleware("world")); | ||
|
||
app.get("/", (req, res) => { | ||
// The universal context can be retrieved through `getContext` helper | ||
// outside of universal middlewares and handlers | ||
const universalCtx = getContext<{ hello: string }>(req)!; | ||
res.send(`Hello ${universalCtx.hello}`); | ||
}); | ||
|
||
export default app; | ||
``` | ||
|
||
```ts twoslash [fastify-entry.ts] | ||
import contextMiddleware from "@universal-middleware-examples/tool/middlewares/context-middleware-fastify"; | ||
import fastify from "fastify"; | ||
import { getContext } from "@universal-middleware/fastify"; | ||
|
||
const app = fastify(); | ||
|
||
// Now the universal context contains `{ hello: "world" }`. | ||
app.register(contextMiddleware("world")); | ||
|
||
app.get("/", (req, reply) => { | ||
// The universal context can be retrieved through `getContext` helper | ||
// outside of universal middlewares and handlers | ||
const universalCtx = getContext<{ hello: string }>(req)!; | ||
reply.send(`Hello ${universalCtx.hello}`); | ||
}); | ||
|
||
export default app; | ||
``` | ||
|
||
::: |
Oops, something went wrong.