alien-middleware 0.3.0 → 0.4.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.d.ts +10 -1
- package/dist/index.js +70 -52
- package/package.json +1 -1
- package/readme.md +18 -0
package/dist/index.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ type RequestContext<TProperties extends object = any, TEnv extends object = any,
|
|
|
39
39
|
type Awaitable<T> = T | PromiseLike<T>;
|
|
40
40
|
type RequestMiddleware<T extends MiddlewareChain = MiddlewareChain> = (context: RequestContext<InputProperties<T>, InputEnv<T>, Platform<T>>) => Awaitable<Response | RequestPlugin | void>;
|
|
41
41
|
type ResponseMiddleware<T extends MiddlewareChain = MiddlewareChain> = (context: RequestContext<InputProperties<T>, InputEnv<T>, Platform<T>>, response: Response) => Awaitable<Response | void>;
|
|
42
|
-
type RequestHandler<TInputs extends MiddlewareTypes, TCurrent extends MiddlewareTypes, TPlatform> = HattipHandler<TPlatform> & MiddlewareChain<TInputs, TCurrent, TPlatform>;
|
|
42
|
+
type RequestHandler<TInputs extends MiddlewareTypes = any, TCurrent extends MiddlewareTypes = any, TPlatform = any> = HattipHandler<TPlatform> & MiddlewareChain<TInputs, TCurrent, TPlatform>;
|
|
43
43
|
/**
|
|
44
44
|
* Either a request middleware or a response middleware.
|
|
45
45
|
*
|
|
@@ -62,6 +62,10 @@ type ApplyFirstMiddleware<T extends Middleware> = ApplyMiddleware<MiddlewareChai
|
|
|
62
62
|
properties: {};
|
|
63
63
|
env: {};
|
|
64
64
|
}, unknown>, T>;
|
|
65
|
+
type MergeMiddlewareChains<TFirst extends MiddlewareChain, TSecond extends MiddlewareChain<Current<TFirst>, any, Platform<TFirst>>> = RequestHandler<Inputs<TFirst>, {
|
|
66
|
+
properties: Merge<Properties<TFirst>, Properties<TSecond>>;
|
|
67
|
+
env: Merge<Env<TFirst>, Env<TSecond>>;
|
|
68
|
+
}, Platform<TFirst>>;
|
|
65
69
|
|
|
66
70
|
declare const kRequestChain: unique symbol;
|
|
67
71
|
declare const kResponseChain: unique symbol;
|
|
@@ -90,6 +94,11 @@ TPlatform = any> {
|
|
|
90
94
|
* @returns a new `MiddlewareChain` instance
|
|
91
95
|
*/
|
|
92
96
|
use<const TMiddleware extends Middleware<TCurrent['properties'], TCurrent['env'], TPlatform>>(middleware: TMiddleware): ApplyMiddleware<this, TMiddleware>;
|
|
97
|
+
/**
|
|
98
|
+
* Merge two middleware chains. The middlewares from the second chain will be
|
|
99
|
+
* executed after the middlewares from the first chain.
|
|
100
|
+
*/
|
|
101
|
+
merge<TChain extends MiddlewareChain<TCurrent, any, TPlatform>>(chain: TChain): MergeMiddlewareChains<this, TChain>;
|
|
93
102
|
}
|
|
94
103
|
declare function chain<TProperties extends object = {}, TEnv extends object = {}, TPlatform = unknown>(): MiddlewareChain<{
|
|
95
104
|
env: TEnv;
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ var urlDescriptor = {
|
|
|
23
23
|
return url;
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
|
-
var MiddlewareChain = class
|
|
26
|
+
var MiddlewareChain = class {
|
|
27
27
|
[kRequestChain] = [];
|
|
28
28
|
[kResponseChain] = [];
|
|
29
29
|
/**
|
|
@@ -41,66 +41,84 @@ var MiddlewareChain = class _MiddlewareChain {
|
|
|
41
41
|
} else {
|
|
42
42
|
responseChain = [...responseChain, middleware];
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
return createHandler(requestChain, responseChain);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Merge two middleware chains. The middlewares from the second chain will be
|
|
48
|
+
* executed after the middlewares from the first chain.
|
|
49
|
+
*/
|
|
50
|
+
merge(chain2) {
|
|
51
|
+
return createHandler(
|
|
52
|
+
[...this[kRequestChain], ...chain2[kRequestChain]],
|
|
53
|
+
[...this[kResponseChain], ...chain2[kResponseChain]]
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
function createHandler(requestChain, responseChain) {
|
|
58
|
+
async function handler(parentContext) {
|
|
59
|
+
const context = Object.create(parentContext);
|
|
60
|
+
context[kIgnoreNotFound] = true;
|
|
61
|
+
if (!("url" in context)) {
|
|
62
|
+
Object.defineProperty(context, "url", urlDescriptor);
|
|
63
|
+
}
|
|
64
|
+
const cache = context[kMiddlewareCache] ||= /* @__PURE__ */ new Set();
|
|
65
|
+
let response;
|
|
66
|
+
let env;
|
|
67
|
+
for (const middleware of requestChain) {
|
|
68
|
+
if (cache.has(middleware)) {
|
|
69
|
+
continue;
|
|
49
70
|
}
|
|
50
|
-
|
|
51
|
-
let
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (isPromise(result)) {
|
|
60
|
-
result = await result;
|
|
71
|
+
cache.add(middleware);
|
|
72
|
+
let result = middleware(context);
|
|
73
|
+
if (isPromise(result)) {
|
|
74
|
+
result = await result;
|
|
75
|
+
}
|
|
76
|
+
if (result) {
|
|
77
|
+
if (result instanceof Response) {
|
|
78
|
+
response = result;
|
|
79
|
+
break;
|
|
61
80
|
}
|
|
62
|
-
if (result) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
Object.assign(context, result.define);
|
|
69
|
-
}
|
|
70
|
-
if (result.env) {
|
|
71
|
-
env ||= createExtendedEnv(context);
|
|
72
|
-
Object.assign(env, result.env);
|
|
81
|
+
if (result.define) {
|
|
82
|
+
for (const key in result.define) {
|
|
83
|
+
Object.defineProperty(context, key, {
|
|
84
|
+
...Object.getOwnPropertyDescriptor(result.define, key),
|
|
85
|
+
configurable: false
|
|
86
|
+
});
|
|
73
87
|
}
|
|
74
88
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return;
|
|
89
|
+
if (result.env) {
|
|
90
|
+
env ||= createExtendedEnv(context);
|
|
91
|
+
Object.assign(env, result.env);
|
|
79
92
|
}
|
|
80
|
-
response = new Response("Not Found", { status: 404 });
|
|
81
93
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
cache.add(middleware2);
|
|
87
|
-
let result = middleware2(context, response);
|
|
88
|
-
if (isPromise(result)) {
|
|
89
|
-
result = await result;
|
|
90
|
-
}
|
|
91
|
-
if (result && result instanceof Response) {
|
|
92
|
-
response = result;
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
94
|
+
}
|
|
95
|
+
if (!response) {
|
|
96
|
+
if (parentContext[kIgnoreNotFound]) {
|
|
97
|
+
return;
|
|
95
98
|
}
|
|
96
|
-
|
|
99
|
+
response = new Response("Not Found", { status: 404 });
|
|
97
100
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
for (const middleware of responseChain) {
|
|
102
|
+
if (cache.has(middleware)) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
cache.add(middleware);
|
|
106
|
+
let result = middleware(context, response);
|
|
107
|
+
if (isPromise(result)) {
|
|
108
|
+
result = await result;
|
|
109
|
+
}
|
|
110
|
+
if (result && result instanceof Response) {
|
|
111
|
+
response = result;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return response;
|
|
102
116
|
}
|
|
103
|
-
|
|
117
|
+
Object.setPrototypeOf(handler, MiddlewareChain.prototype);
|
|
118
|
+
handler[kRequestChain] = requestChain;
|
|
119
|
+
handler[kResponseChain] = responseChain;
|
|
120
|
+
return handler;
|
|
121
|
+
}
|
|
104
122
|
function createExtendedEnv(context) {
|
|
105
123
|
const env = /* @__PURE__ */ Object.create(null);
|
|
106
124
|
const superEnv = context.env;
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -82,6 +82,14 @@ server.listen(3000, () => {
|
|
|
82
82
|
> If no middleware in the chain returns a `Response`, a `404 Not Found` response
|
|
83
83
|
> is automatically returned.
|
|
84
84
|
|
|
85
|
+
#### Middlewares are deduplicated.
|
|
86
|
+
|
|
87
|
+
If you add the same middleware multiple times, it will only run once. This is a safety measure that allows you to use the same middleware in different places without worrying about it running multiple times.
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
const app = chain().use(myMiddleware).use(myMiddleware)
|
|
91
|
+
```
|
|
92
|
+
|
|
85
93
|
### Request Middleware
|
|
86
94
|
|
|
87
95
|
Request middleware runs sequentially before a `Response` is generated.
|
|
@@ -203,6 +211,16 @@ const finalApp = chain().use(innerChain).use(outerMiddleware)
|
|
|
203
211
|
|
|
204
212
|
If a nested chain does not return a `Response`, execution continues with the next middleware in the outer chain.
|
|
205
213
|
|
|
214
|
+
### Merging Chains
|
|
215
|
+
|
|
216
|
+
You can merge two middleware chains using the `merge` method. This is useful if you want to combine middleware from multiple files or modules.
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
const mergedApp = chain().use(middleware1).merge(chain().use(middleware2))
|
|
220
|
+
// …is equivalent to…
|
|
221
|
+
const mergedApp = chain().use(middleware1).use(middleware2)
|
|
222
|
+
```
|
|
223
|
+
|
|
206
224
|
### Safe Environment Variables
|
|
207
225
|
|
|
208
226
|
When writing a Hattip handler without this package, the `context.env()` method is inherently unsafe. Its return type is always `string | undefined`, which means you either need to write defensive checks or use type assertions. Neither is ideal.
|