alien-middleware 0.5.0 → 0.6.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-DQDr9Gkb.d.ts → index-CuxbHrbf.d.ts} +25 -11
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -10
- package/dist/router.d.ts +4 -3
- package/package.json +1 -1
- package/readme.md +16 -10
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import { AdapterRequestContext, HattipHandler } from '@hattip/core';
|
|
2
2
|
import { Any } from 'radashi';
|
|
3
3
|
|
|
4
|
-
type
|
|
4
|
+
type RequestEnvPlugin = {
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
define?: object;
|
|
9
|
-
/**
|
|
10
|
-
* Add type-safe environment variables.
|
|
6
|
+
* Add type-safe environment variables. These are accessed with the `env()`
|
|
7
|
+
* method on the request context.
|
|
11
8
|
*/
|
|
12
9
|
env?: object;
|
|
13
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* The object returned by a request middleware that is merged into the request
|
|
13
|
+
* context. The same context property cannot be defined by two different
|
|
14
|
+
* plugins, or an error will be thrown at runtime.
|
|
15
|
+
*
|
|
16
|
+
* May contain special properties:
|
|
17
|
+
* - `env`: Add type-safe environment variables.
|
|
18
|
+
*/
|
|
19
|
+
type RequestPlugin = Record<string, unknown> & RequestEnvPlugin;
|
|
14
20
|
type Inputs<T extends MiddlewareChain> = T['$']['input'];
|
|
15
21
|
type Platform<T extends MiddlewareChain> = T['$']['platform'];
|
|
16
22
|
type InputProperties<T extends MiddlewareChain> = Inputs<T>['properties'];
|
|
@@ -35,7 +41,14 @@ interface HattipContext<TPlatform, TEnv extends object> extends AdapterRequestCo
|
|
|
35
41
|
* Converts a type `T` to something that can be intersected with an object.
|
|
36
42
|
*/
|
|
37
43
|
type Intersectable<T extends object> = [T] extends [never] ? {} : [T] extends [Any] ? Record<PropertyKey, any> : T;
|
|
38
|
-
|
|
44
|
+
/**
|
|
45
|
+
* An extensible Hattip context object.
|
|
46
|
+
*
|
|
47
|
+
* NOTE: When using this type on the right side of an `extends` clause, you
|
|
48
|
+
* should prefer `RequestContext<any>` over `RequestContext` (no type
|
|
49
|
+
* parameters), as the default type is stricter.
|
|
50
|
+
*/
|
|
51
|
+
type RequestContext<TProperties extends object = never, TEnv extends object = any, TPlatform = any> = HattipContext<TPlatform, TEnv> & Intersectable<TProperties>;
|
|
39
52
|
/**
|
|
40
53
|
* Extract a `RequestContext` type from a `MiddlewareChain` type.
|
|
41
54
|
*
|
|
@@ -62,7 +75,7 @@ type Merge<TSource extends object, TOverrides extends object | undefined> = {} &
|
|
|
62
75
|
[K in keyof TSource | keyof TOverrides]: K extends keyof TOverrides ? TOverrides[K] : K extends keyof TSource ? TSource[K] : never;
|
|
63
76
|
} : TSource);
|
|
64
77
|
type ApplyRequestPlugin<TParent extends MiddlewareChain, TPlugin extends RequestPlugin> = {
|
|
65
|
-
properties: Merge<Properties<TParent>, TPlugin
|
|
78
|
+
properties: Merge<Properties<TParent>, Omit<TPlugin, keyof RequestEnvPlugin>>;
|
|
66
79
|
env: Merge<Env<TParent>, TPlugin['env']>;
|
|
67
80
|
};
|
|
68
81
|
/**
|
|
@@ -71,13 +84,14 @@ type ApplyRequestPlugin<TParent extends MiddlewareChain, TPlugin extends Request
|
|
|
71
84
|
* parent chain.
|
|
72
85
|
*/
|
|
73
86
|
type ApplyMiddleware<TParent extends MiddlewareChain, TMiddleware> = TMiddleware extends MiddlewareChain ? RequestHandler<Inputs<TParent>, Current<TParent>, Platform<TParent>> : TMiddleware extends () => Awaitable<infer TPlugin extends RequestPlugin> ? RequestHandler<Inputs<TParent>, ApplyRequestPlugin<TParent, TPlugin>, Platform<TParent>> : RequestHandler<Inputs<TParent>, Current<TParent>, Platform<TParent>>;
|
|
74
|
-
type
|
|
87
|
+
type EmptyMiddlewareChain = MiddlewareChain<{
|
|
75
88
|
properties: {};
|
|
76
89
|
env: {};
|
|
77
90
|
}, {
|
|
78
91
|
properties: {};
|
|
79
92
|
env: {};
|
|
80
|
-
}, unknown
|
|
93
|
+
}, unknown>;
|
|
94
|
+
type ApplyFirstMiddleware<T extends Middleware> = T extends MiddlewareChain ? T : ApplyMiddleware<EmptyMiddlewareChain, T>;
|
|
81
95
|
type MergeMiddleware<TFirst extends MiddlewareChain, TSecond extends Middleware<Properties<TFirst>, Env<TFirst>, Platform<TFirst>>> = RequestHandler<Inputs<TFirst>, TSecond extends MiddlewareChain ? {
|
|
82
96
|
properties: Merge<Properties<TFirst>, Properties<TSecond>>;
|
|
83
97
|
env: Merge<Env<TFirst>, Env<TSecond>>;
|
|
@@ -135,4 +149,4 @@ declare function chain<TProperties extends object = {}, TEnv extends object = {}
|
|
|
135
149
|
}, TPlatform>;
|
|
136
150
|
declare function chain<const T extends Middleware = Middleware>(middleware: T): ApplyFirstMiddleware<T>;
|
|
137
151
|
|
|
138
|
-
export { type ApplyMiddleware as A, type
|
|
152
|
+
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 MergeMiddleware as f, type Middleware as g, type RequestContext as h, type RequestHandler as i, type RequestMiddleware as j, type RequestPlugin as k, type ResponseMiddleware as l };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { A as ApplyMiddleware,
|
|
1
|
+
export { A as ApplyMiddleware, e as ExtractMiddleware, f as MergeMiddleware, g as Middleware, M as MiddlewareChain, a as MiddlewareContext, h as RequestContext, i as RequestHandler, j as RequestMiddleware, k as RequestPlugin, l as ResponseMiddleware, d as chain } from './index-CuxbHrbf.js';
|
|
2
2
|
import '@hattip/core';
|
|
3
3
|
import 'radashi';
|
package/dist/index.js
CHANGED
|
@@ -73,18 +73,16 @@ function createHandler(requestChain, responseChain) {
|
|
|
73
73
|
response = result;
|
|
74
74
|
break;
|
|
75
75
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
for (const key in result) {
|
|
77
|
+
const descriptor = Object.getOwnPropertyDescriptor(result, key);
|
|
78
|
+
if (key === "env") {
|
|
79
|
+
env ||= createExtendedEnv(context);
|
|
80
|
+
Object.defineProperty(env, key, descriptor);
|
|
81
|
+
} else {
|
|
82
|
+
descriptor.configurable = false;
|
|
83
|
+
Object.defineProperty(context, key, descriptor);
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
|
-
if (result.env) {
|
|
85
|
-
env ||= createExtendedEnv(context);
|
|
86
|
-
Object.assign(env, result.env);
|
|
87
|
-
}
|
|
88
86
|
}
|
|
89
87
|
}
|
|
90
88
|
if (!response) {
|
package/dist/router.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { InferParams } from 'pathic';
|
|
2
|
-
import { M as MiddlewareChain, a as MiddlewareContext, R as RouteHandler, b as RouteMethod } from './index-
|
|
2
|
+
import { M as MiddlewareChain, E as EmptyMiddlewareChain, a as MiddlewareContext, R as RouteHandler, b as RouteMethod } from './index-CuxbHrbf.js';
|
|
3
|
+
export { c as RouterContext } from './index-CuxbHrbf.js';
|
|
3
4
|
import '@hattip/core';
|
|
4
5
|
import 'radashi';
|
|
5
6
|
|
|
6
7
|
type OneOrMany<T> = T | readonly T[];
|
|
7
8
|
type Router<T extends MiddlewareChain = any> = ReturnType<typeof routes<T>>;
|
|
8
|
-
declare function routes<T extends MiddlewareChain>(middlewares?: T): {
|
|
9
|
+
declare function routes<T extends MiddlewareChain = EmptyMiddlewareChain>(middlewares?: T): {
|
|
9
10
|
(context: MiddlewareContext<T>): void | Response | Promise<void | Response> | undefined;
|
|
10
11
|
use: {
|
|
11
12
|
<TPath extends string>(path: TPath, handler: RouteHandler<T, InferParams<TPath>>): /*elided*/ any;
|
|
@@ -13,4 +14,4 @@ declare function routes<T extends MiddlewareChain>(middlewares?: T): {
|
|
|
13
14
|
};
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
export { type Router, routes };
|
|
17
|
+
export { RouteHandler, type Router, routes };
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -97,6 +97,8 @@ Request middleware runs sequentially before a `Response` is generated.
|
|
|
97
97
|
- **Terminating the Chain:** Return a `Response` object to stop processing subsequent request middleware.
|
|
98
98
|
|
|
99
99
|
```typescript
|
|
100
|
+
import type { RequestContext } from 'alien-middleware'
|
|
101
|
+
|
|
100
102
|
const earlyResponder = (context: RequestContext) => {
|
|
101
103
|
if (context.request.url.endsWith('/forbidden')) {
|
|
102
104
|
return new Response('Forbidden', { status: 403 })
|
|
@@ -105,19 +107,21 @@ Request middleware runs sequentially before a `Response` is generated.
|
|
|
105
107
|
}
|
|
106
108
|
```
|
|
107
109
|
|
|
108
|
-
- **Extending Context:** Return an object
|
|
110
|
+
- **Extending Context:** Return an object (known as a "request plugin") to add its properties to the context for _downstream_ middleware. Getter syntax is supported.
|
|
109
111
|
|
|
110
112
|
```typescript
|
|
113
|
+
import type { RequestContext } from 'alien-middleware'
|
|
114
|
+
|
|
115
|
+
type User = { id: number; name: string }
|
|
116
|
+
|
|
111
117
|
const addUser = (context: RequestContext) => {
|
|
112
118
|
// In a real app, you might look up a user based on a token
|
|
113
|
-
const user = { id: 1, name: 'Alice' }
|
|
119
|
+
const user: User = { id: 1, name: 'Alice' }
|
|
114
120
|
|
|
115
|
-
return {
|
|
121
|
+
return { user }
|
|
116
122
|
}
|
|
117
123
|
|
|
118
|
-
const greetUser = (
|
|
119
|
-
context: RequestContext<{ user: { id: number; name: string } }>
|
|
120
|
-
) => {
|
|
124
|
+
const greetUser = (context: RequestContext<{ user: User }>) => {
|
|
121
125
|
// The `user` property is now available thanks to `addUser`
|
|
122
126
|
return new Response(`Hello, ${context.user.name}!`)
|
|
123
127
|
}
|
|
@@ -125,14 +129,16 @@ Request middleware runs sequentially before a `Response` is generated.
|
|
|
125
129
|
const app = chain().use(addUser).use(greetUser)
|
|
126
130
|
```
|
|
127
131
|
|
|
128
|
-
- **Extending Environment:**
|
|
132
|
+
- **Extending Environment:** Request plugins may have an `env` property to add environment variables accessible via `context.env()`.
|
|
129
133
|
|
|
130
134
|
```typescript
|
|
135
|
+
import type { RequestContext } from 'alien-middleware'
|
|
136
|
+
|
|
131
137
|
const addApiKey = (context: RequestContext) => {
|
|
132
138
|
return { env: { API_KEY: 'secret123' } }
|
|
133
139
|
}
|
|
134
140
|
|
|
135
|
-
const useApiKey = (context: RequestContext<
|
|
141
|
+
const useApiKey = (context: RequestContext<never, { API_KEY: string }>) => {
|
|
136
142
|
const key = context.env('API_KEY')
|
|
137
143
|
console.log('API Key:', key) // Output: API Key: secret123
|
|
138
144
|
}
|
|
@@ -141,7 +147,7 @@ Request middleware runs sequentially before a `Response` is generated.
|
|
|
141
147
|
```
|
|
142
148
|
|
|
143
149
|
> [!NOTE]
|
|
144
|
-
> If you're wondering why you need to return
|
|
150
|
+
> If you're wondering why you need to return an object to define properties
|
|
145
151
|
> (rather than simply assigning to the context object), it's because TypeScript
|
|
146
152
|
> is unable to infer the type of the context object downstream if you don't do
|
|
147
153
|
> it like this.
|
|
@@ -182,7 +188,7 @@ another chain, since the outer chain will still have a chance to return a
|
|
|
182
188
|
|
|
183
189
|
### Nesting Chains
|
|
184
190
|
|
|
185
|
-
You can compose middleware by nesting chains using `.use()`.
|
|
191
|
+
You can compose middleware by nesting chains using `.use()`. _Request plugins_ within a nested chain are scoped to that chain and do not affect middleware outside of it.
|
|
186
192
|
|
|
187
193
|
```typescript
|
|
188
194
|
const innerChain = chain((context: RequestContext) => {
|