alien-middleware 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-DEMeaByn.d.ts → index-BP2sjKus.d.ts} +10 -28
- package/dist/index.d.ts +1 -1
- package/dist/router.d.ts +2 -2
- package/package.json +1 -1
- package/readme.md +54 -28
|
@@ -24,9 +24,9 @@ type InputEnv<T extends MiddlewareChain> = Inputs<T>['env'];
|
|
|
24
24
|
type Current<T extends MiddlewareChain> = T['$']['current'];
|
|
25
25
|
type Properties<T extends MiddlewareChain> = Current<T>['properties'];
|
|
26
26
|
type Env<T extends MiddlewareChain> = Current<T>['env'];
|
|
27
|
-
type MiddlewareTypes<
|
|
28
|
-
properties: TProperties;
|
|
27
|
+
type MiddlewareTypes<TEnv extends object = any, TProperties extends object = any> = {
|
|
29
28
|
env: TEnv;
|
|
29
|
+
properties: TProperties;
|
|
30
30
|
};
|
|
31
31
|
interface HattipContext<TPlatform, TEnv extends object> extends AdapterRequestContext<TPlatform> {
|
|
32
32
|
/**
|
|
@@ -48,13 +48,13 @@ type Intersectable<T extends object> = [T] extends [never] ? {} : [T] extends [A
|
|
|
48
48
|
* should prefer `RequestContext<any>` over `RequestContext` (no type
|
|
49
49
|
* parameters), as the default type is stricter.
|
|
50
50
|
*/
|
|
51
|
-
type RequestContext<
|
|
51
|
+
type RequestContext<TEnv extends object = any, TProperties extends object = never, TPlatform = any> = HattipContext<TPlatform, TEnv> & Intersectable<TProperties>;
|
|
52
52
|
/**
|
|
53
53
|
* Extract a `RequestContext` type from a `MiddlewareChain` type.
|
|
54
54
|
*
|
|
55
55
|
* When type `T` is `never`, a default context is returned.
|
|
56
56
|
*/
|
|
57
|
-
type MiddlewareContext<T extends MiddlewareChain> = [T] extends [never] ? RequestContext<{},
|
|
57
|
+
type MiddlewareContext<T extends MiddlewareChain> = [T] extends [never] ? RequestContext<{}, never, unknown> : RequestContext<Env<T>, Properties<T>, Platform<T>>;
|
|
58
58
|
type IsolatedContext<T extends MiddlewareChain> = RequestContext<InputProperties<T>, InputEnv<T>, Platform<T>>;
|
|
59
59
|
type Awaitable<T> = T | Promise<T>;
|
|
60
60
|
type RequestMiddleware<T extends MiddlewareChain = MiddlewareChain> = (context: RequestContext<InputProperties<T>, InputEnv<T>, Platform<T>>) => Awaitable<Response | RequestPlugin | void>;
|
|
@@ -67,34 +67,22 @@ type RequestHandler<TInputs extends MiddlewareTypes = any, TCurrent extends Midd
|
|
|
67
67
|
* response middleware. This means it will run *after* a `Response` is generated
|
|
68
68
|
* by a request middleware.
|
|
69
69
|
*/
|
|
70
|
-
type Middleware<
|
|
70
|
+
type Middleware<TEnv extends object = any, TProperties extends object = any, TPlatform = any> = (context: RequestContext<TEnv, TProperties, TPlatform>, response: Response) => Awaitable<Response | RequestPlugin | void>;
|
|
71
71
|
/**
|
|
72
72
|
* Extract a `Middleware` type from a `MiddlewareChain` type.
|
|
73
73
|
*/
|
|
74
|
-
type ExtractMiddleware<T extends MiddlewareChain> = Middleware<
|
|
74
|
+
type ExtractMiddleware<T extends MiddlewareChain> = Middleware<Env<T>, Properties<T>, Platform<T>>;
|
|
75
75
|
type Merge<TSource extends object, TOverrides extends object | undefined> = {} & (TOverrides extends object ? {
|
|
76
76
|
[K in keyof TSource | keyof TOverrides]: K extends keyof TOverrides ? TOverrides[K] : K extends keyof TSource ? TSource[K] : never;
|
|
77
77
|
} : TSource);
|
|
78
|
-
type ApplyRequestPlugin<TParent extends MiddlewareChain, TPlugin extends RequestPlugin> = {} &
|
|
79
|
-
properties: Merge<Properties<TParent>, Omit<TPlugin, keyof RequestEnvPlugin>>;
|
|
80
|
-
env: Merge<Env<TParent>, TPlugin['env']>;
|
|
81
|
-
};
|
|
78
|
+
type ApplyRequestPlugin<TParent extends MiddlewareChain, TPlugin extends RequestPlugin> = {} & MiddlewareTypes<Merge<Env<TParent>, TPlugin['env']>, Merge<Properties<TParent>, Omit<TPlugin, keyof RequestEnvPlugin>>>;
|
|
82
79
|
/**
|
|
83
80
|
* This applies a middleware to a chain. If the type `TMiddleware` is itself a
|
|
84
81
|
* chain, it's treated as a nested chain, which won't leak its plugins into the
|
|
85
82
|
* parent chain.
|
|
86
83
|
*/
|
|
87
|
-
type ApplyMiddleware<TFirst extends MiddlewareChain, TSecond extends Middleware<
|
|
88
|
-
|
|
89
|
-
env: Merge<Env<TFirst>, Env<TSecond>>;
|
|
90
|
-
} : TSecond extends () => Awaitable<infer TResult> ? TResult extends RequestPlugin ? ApplyRequestPlugin<TFirst, TResult> : Current<TFirst> : Current<TFirst>, Platform<TFirst>>;
|
|
91
|
-
type EmptyMiddlewareChain = MiddlewareChain<{
|
|
92
|
-
properties: {};
|
|
93
|
-
env: {};
|
|
94
|
-
}, {
|
|
95
|
-
properties: {};
|
|
96
|
-
env: {};
|
|
97
|
-
}, unknown>;
|
|
84
|
+
type ApplyMiddleware<TFirst extends MiddlewareChain, TSecond extends Middleware<Env<TFirst>, Properties<TFirst>, Platform<TFirst>>> = RequestHandler<Inputs<TFirst>, TSecond extends MiddlewareChain ? MiddlewareTypes<Merge<Env<TFirst>, Env<TSecond>>, Merge<Properties<TFirst>, Properties<TSecond>>> : TSecond extends () => Awaitable<infer TResult> ? TResult extends RequestPlugin ? ApplyRequestPlugin<TFirst, TResult> : Current<TFirst> : Current<TFirst>, Platform<TFirst>>;
|
|
85
|
+
type EmptyMiddlewareChain = MiddlewareChain<MiddlewareTypes<{}, {}>, MiddlewareTypes<{}, {}>, unknown>;
|
|
98
86
|
type ApplyFirstMiddleware<T extends Middleware> = T extends MiddlewareChain ? T : ApplyMiddleware<EmptyMiddlewareChain, T>;
|
|
99
87
|
type RouteMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD';
|
|
100
88
|
type RouterContext<T extends MiddlewareChain = any, TPathParams extends object = any, TMethod extends RouteMethod = RouteMethod> = MiddlewareContext<T> & {
|
|
@@ -139,13 +127,7 @@ TPlatform = any> {
|
|
|
139
127
|
*/
|
|
140
128
|
isolate(): ((ctx: IsolatedContext<this>) => Promise<Response | void>) | typeof noop;
|
|
141
129
|
}
|
|
142
|
-
declare function chain<
|
|
143
|
-
env: TEnv;
|
|
144
|
-
properties: TProperties;
|
|
145
|
-
}, {
|
|
146
|
-
env: TEnv;
|
|
147
|
-
properties: TProperties;
|
|
148
|
-
}, TPlatform>;
|
|
130
|
+
declare function chain<TEnv extends object = {}, TProperties extends object = {}, TPlatform = unknown>(): MiddlewareChain<MiddlewareTypes<TEnv, TProperties>, MiddlewareTypes<TEnv, TProperties>, TPlatform>;
|
|
149
131
|
declare function chain<const T extends Middleware = Middleware>(middleware: T): ApplyFirstMiddleware<T>;
|
|
150
132
|
|
|
151
133
|
export { type ApplyMiddleware as A, type EmptyMiddlewareChain as E, MiddlewareChain as M, type RouteHandler as R, type MiddlewareContext as a, type RouteMethod as b, type RouterContext as c, chain as d, type ExtractMiddleware as e, type Middleware as f, type RequestContext as g, type RequestHandler as h, type RequestMiddleware as i, type RequestPlugin as j, type ResponseMiddleware as k };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import 'radashi';
|
|
2
|
-
export { A as ApplyMiddleware, e as ExtractMiddleware, f as Middleware, M as MiddlewareChain, a as MiddlewareContext, g as RequestContext, h as RequestHandler, i as RequestMiddleware, j as RequestPlugin, k as ResponseMiddleware, d as chain } from './index-
|
|
2
|
+
export { A as ApplyMiddleware, e as ExtractMiddleware, f as Middleware, M as MiddlewareChain, a as MiddlewareContext, g as RequestContext, h as RequestHandler, i as RequestMiddleware, j as RequestPlugin, k as ResponseMiddleware, d as chain } from './index-BP2sjKus.js';
|
|
3
3
|
import '@hattip/core';
|
package/dist/router.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { InferParams } from 'pathic';
|
|
2
|
-
import { M as MiddlewareChain, E as EmptyMiddlewareChain, a as MiddlewareContext, R as RouteHandler, b as RouteMethod } from './index-
|
|
3
|
-
export { c as RouterContext } from './index-
|
|
2
|
+
import { M as MiddlewareChain, E as EmptyMiddlewareChain, a as MiddlewareContext, R as RouteHandler, b as RouteMethod } from './index-BP2sjKus.js';
|
|
3
|
+
export { c as RouterContext } from './index-BP2sjKus.js';
|
|
4
4
|
import 'radashi';
|
|
5
5
|
import '@hattip/core';
|
|
6
6
|
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -186,45 +186,71 @@ request middlewares, **except** when the middleware chain is nested inside
|
|
|
186
186
|
another chain, since the outer chain will still have a chance to return a
|
|
187
187
|
`Response`.
|
|
188
188
|
|
|
189
|
-
###
|
|
189
|
+
### Merging a Middleware Chain
|
|
190
190
|
|
|
191
|
-
|
|
191
|
+
By passing a middleware chain to `.use()`, you can merge it with the existing chain. Its middlewares will be executed _after_ any existing middlewares in this chain and _before_ any new middlewares you add later.
|
|
192
192
|
|
|
193
193
|
```typescript
|
|
194
194
|
const innerChain = chain((context: RequestContext) => {
|
|
195
|
-
|
|
196
|
-
return { define: { innerData: 'secret' } } // Only available inside innerChain
|
|
197
|
-
}).use((context: RequestContext<{ innerData: string }>) => {
|
|
198
|
-
console.log('Accessing inner data:', context.innerData)
|
|
195
|
+
return { helloFromInner: true }
|
|
199
196
|
})
|
|
200
197
|
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
return new Response('Finished')
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const finalApp = chain().use(innerChain).use(outerMiddleware)
|
|
211
|
-
// Output when executing the finalApp chain:
|
|
212
|
-
// Inner chain start
|
|
213
|
-
// Accessing inner data: secret
|
|
214
|
-
// Outer middleware after inner chain
|
|
215
|
-
// innerData is correctly scoped.
|
|
198
|
+
const app = chain()
|
|
199
|
+
.use(innerChain)
|
|
200
|
+
.use(context => {
|
|
201
|
+
context.helloFromInner // Output: true
|
|
202
|
+
})
|
|
216
203
|
```
|
|
217
204
|
|
|
218
|
-
|
|
205
|
+
### Isolating a Middleware Chain
|
|
219
206
|
|
|
220
|
-
|
|
207
|
+
When adding a middleware chain to another, you may use the `isolate()` method to isolate the nested chain from the outer chain.
|
|
221
208
|
|
|
222
|
-
|
|
209
|
+
```typescript
|
|
210
|
+
const isolatedChain = chain().isolate()
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
This prevents the nested chain from affecting middleware in the outer chain (e.g. through _request plugins_).
|
|
223
214
|
|
|
224
215
|
```typescript
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
216
|
+
const innerChain = chain()
|
|
217
|
+
.use(() => ({
|
|
218
|
+
foo: true,
|
|
219
|
+
}))
|
|
220
|
+
.use(context => {
|
|
221
|
+
context.foo // Output: true
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
const outerChain = chain()
|
|
225
|
+
.use(innerChain.isolate())
|
|
226
|
+
.use(context => {
|
|
227
|
+
context.foo // Output: undefined
|
|
228
|
+
})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
If an isolated chain does not return a `Response`, execution continues with the next middleware in the outer chain.
|
|
232
|
+
|
|
233
|
+
### Escaping a Middleware Chain
|
|
234
|
+
|
|
235
|
+
To stop processing a request (e.g. skip any remaining middlewares), use the `context.passThrough()` method. The Hattip adapter is responsible for deciding the appropriate action based on the request.
|
|
236
|
+
|
|
237
|
+
In the context of an isolated chain, `context.passThrough()` will skip remaining middlewares in the isolated chain, but the outer chain will continue execution with the next middleware.
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
const app = chain()
|
|
241
|
+
.use(context => {
|
|
242
|
+
if (!context.request.headers.has('Authorization')) {
|
|
243
|
+
// It's best practice to return immediately after
|
|
244
|
+
// calling passThrough()
|
|
245
|
+
return context.passThrough()
|
|
246
|
+
}
|
|
247
|
+
return new Response('Authorized', { status: 200 })
|
|
248
|
+
})
|
|
249
|
+
.use(context => {
|
|
250
|
+
// This will never run, since the previous middleware
|
|
251
|
+
// either returns a Response or calls passThrough()
|
|
252
|
+
throw new Error('This request middleware will never run')
|
|
253
|
+
})
|
|
228
254
|
```
|
|
229
255
|
|
|
230
256
|
### Safe Environment Variables
|
|
@@ -338,7 +364,7 @@ import { routes } from 'alien-middleware/router'
|
|
|
338
364
|
// Define a middleware that adds a user to the context
|
|
339
365
|
const addUserMiddleware = (context: RequestContext): RequestPlugin => {
|
|
340
366
|
const user = { id: 123, name: 'Alice' }
|
|
341
|
-
return {
|
|
367
|
+
return { user }
|
|
342
368
|
}
|
|
343
369
|
|
|
344
370
|
// Create a chain with the middleware
|