@loopback/context 4.0.0-alpha.7 → 4.0.1
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/LICENSE +25 -0
- package/README.md +116 -0
- package/dist/binding-config.d.ts +40 -0
- package/dist/binding-config.js +33 -0
- package/dist/binding-config.js.map +1 -0
- package/dist/binding-decorator.d.ts +45 -0
- package/dist/binding-decorator.js +118 -0
- package/dist/binding-decorator.js.map +1 -0
- package/dist/binding-filter.d.ts +108 -0
- package/dist/binding-filter.js +162 -0
- package/dist/binding-filter.js.map +1 -0
- package/dist/binding-inspector.d.ts +150 -0
- package/dist/binding-inspector.js +249 -0
- package/dist/binding-inspector.js.map +1 -0
- package/dist/binding-key.d.ts +66 -0
- package/dist/binding-key.js +121 -0
- package/dist/binding-key.js.map +1 -0
- package/dist/binding-sorter.d.ts +71 -0
- package/dist/binding-sorter.js +89 -0
- package/dist/binding-sorter.js.map +1 -0
- package/dist/binding.d.ts +577 -0
- package/dist/binding.js +788 -0
- package/dist/binding.js.map +1 -0
- package/dist/context-event.d.ts +23 -0
- package/dist/context-event.js +7 -0
- package/dist/context-event.js.map +1 -0
- package/dist/context-observer.d.ts +36 -0
- package/dist/context-observer.js +7 -0
- package/dist/context-observer.js.map +1 -0
- package/dist/context-subscription.d.ts +147 -0
- package/dist/context-subscription.js +317 -0
- package/dist/context-subscription.js.map +1 -0
- package/dist/context-tag-indexer.d.ts +42 -0
- package/dist/context-tag-indexer.js +135 -0
- package/dist/context-tag-indexer.js.map +1 -0
- package/dist/context-view.d.ts +209 -0
- package/dist/context-view.js +240 -0
- package/dist/context-view.js.map +1 -0
- package/dist/context.d.ts +513 -0
- package/dist/context.js +717 -0
- package/dist/context.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/inject-config.d.ts +67 -0
- package/dist/inject-config.js +181 -0
- package/dist/inject-config.js.map +1 -0
- package/dist/inject.d.ts +250 -0
- package/dist/inject.js +535 -0
- package/dist/inject.js.map +1 -0
- package/dist/interception-proxy.d.ts +76 -0
- package/dist/interception-proxy.js +67 -0
- package/dist/interception-proxy.js.map +1 -0
- package/dist/interceptor-chain.d.ts +121 -0
- package/dist/interceptor-chain.js +148 -0
- package/dist/interceptor-chain.js.map +1 -0
- package/dist/interceptor.d.ts +138 -0
- package/dist/interceptor.js +299 -0
- package/dist/interceptor.js.map +1 -0
- package/dist/invocation.d.ts +101 -0
- package/dist/invocation.js +163 -0
- package/dist/invocation.js.map +1 -0
- package/dist/json-types.d.ts +28 -0
- package/dist/json-types.js +7 -0
- package/dist/json-types.js.map +1 -0
- package/dist/keys.d.ts +65 -0
- package/dist/keys.js +74 -0
- package/dist/keys.js.map +1 -0
- package/dist/provider.d.ts +31 -0
- package/dist/provider.js +7 -0
- package/dist/provider.js.map +1 -0
- package/dist/resolution-session.d.ts +180 -0
- package/dist/resolution-session.js +274 -0
- package/dist/resolution-session.js.map +1 -0
- package/dist/resolver.d.ts +46 -0
- package/dist/resolver.js +203 -0
- package/dist/resolver.js.map +1 -0
- package/dist/unique-id.d.ts +14 -0
- package/dist/unique-id.js +26 -0
- package/dist/unique-id.js.map +1 -0
- package/dist/value-promise.d.ts +134 -0
- package/dist/value-promise.js +277 -0
- package/dist/value-promise.js.map +1 -0
- package/package.json +49 -35
- package/src/binding-config.ts +73 -0
- package/src/binding-decorator.ts +136 -0
- package/src/binding-filter.ts +250 -0
- package/src/binding-inspector.ts +371 -0
- package/src/binding-key.ts +136 -0
- package/src/binding-sorter.ts +124 -0
- package/src/binding.ts +1107 -0
- package/src/context-event.ts +30 -0
- package/src/context-observer.ts +50 -0
- package/src/context-subscription.ts +402 -0
- package/src/context-tag-indexer.ts +147 -0
- package/src/context-view.ts +440 -0
- package/src/context.ts +1079 -0
- package/src/index.ts +58 -0
- package/src/inject-config.ts +239 -0
- package/src/inject.ts +796 -0
- package/src/interception-proxy.ts +127 -0
- package/src/interceptor-chain.ts +268 -0
- package/src/interceptor.ts +430 -0
- package/src/invocation.ts +269 -0
- package/src/json-types.ts +35 -0
- package/src/keys.ts +85 -0
- package/src/provider.ts +37 -0
- package/src/resolution-session.ts +414 -0
- package/src/resolver.ts +282 -0
- package/src/unique-id.ts +24 -0
- package/src/value-promise.ts +318 -0
- package/index.d.ts +0 -6
- package/index.js +0 -9
- package/lib/binding.d.ts +0 -75
- package/lib/binding.js +0 -102
- package/lib/context.d.ts +0 -14
- package/lib/context.js +0 -96
- package/lib/index.d.ts +0 -5
- package/lib/index.js +0 -13
- package/lib/inject.d.ts +0 -47
- package/lib/inject.js +0 -73
- package/lib/isPromise.d.ts +0 -1
- package/lib/isPromise.js +0 -14
- package/lib/resolver.d.ts +0 -30
- package/lib/resolver.js +0 -128
- package/lib6/binding.d.ts +0 -75
- package/lib6/binding.js +0 -102
- package/lib6/context.d.ts +0 -14
- package/lib6/context.js +0 -96
- package/lib6/index.d.ts +0 -5
- package/lib6/index.js +0 -13
- package/lib6/inject.d.ts +0 -47
- package/lib6/inject.js +0 -73
- package/lib6/isPromise.d.ts +0 -1
- package/lib6/isPromise.js +0 -14
- package/lib6/resolver.d.ts +0 -30
- package/lib6/resolver.js +0 -128
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/context
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import {Context} from './context';
|
|
7
|
+
import {invokeMethodWithInterceptors} from './interceptor';
|
|
8
|
+
import {InvocationArgs, InvocationSource} from './invocation';
|
|
9
|
+
import {ResolutionSession} from './resolution-session';
|
|
10
|
+
import {ValueOrPromise} from './value-promise';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create the Promise type for `T`. If `T` extends `Promise`, the type is `T`,
|
|
14
|
+
* otherwise the type is `ValueOrPromise<T>`.
|
|
15
|
+
*/
|
|
16
|
+
export type AsValueOrPromise<T> = T extends Promise<unknown>
|
|
17
|
+
? T
|
|
18
|
+
: ValueOrPromise<T>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The intercepted variant of a function to return `ValueOrPromise<T>`.
|
|
22
|
+
* If `T` is not a function, the type is `T`.
|
|
23
|
+
*/
|
|
24
|
+
export type AsInterceptedFunction<T> = T extends (
|
|
25
|
+
...args: InvocationArgs
|
|
26
|
+
) => infer R
|
|
27
|
+
? (...args: Parameters<T>) => AsValueOrPromise<R>
|
|
28
|
+
: T;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The proxy type for `T`. The return type for any method of `T` with original
|
|
32
|
+
* return type `R` becomes `ValueOrPromise<R>` if `R` does not extend `Promise`.
|
|
33
|
+
* Property types stay untouched.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* class MyController {
|
|
38
|
+
* name: string;
|
|
39
|
+
*
|
|
40
|
+
* greet(name: string): string {
|
|
41
|
+
* return `Hello, ${name}`;
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* async hello(name: string) {
|
|
45
|
+
* return `Hello, ${name}`;
|
|
46
|
+
* }
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* `AsyncProxy<MyController>` will be:
|
|
51
|
+
* ```ts
|
|
52
|
+
* {
|
|
53
|
+
* name: string; // the same as MyController
|
|
54
|
+
* greet(name: string): ValueOrPromise<string>; // the return type becomes `ValueOrPromise<string>`
|
|
55
|
+
* hello(name: string): Promise<string>; // the same as MyController
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export type AsyncProxy<T> = {[P in keyof T]: AsInterceptedFunction<T[P]>};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Invocation source for injected proxies. It wraps a snapshot of the
|
|
63
|
+
* `ResolutionSession` that tracks the binding/injection stack.
|
|
64
|
+
*/
|
|
65
|
+
export class ProxySource implements InvocationSource<ResolutionSession> {
|
|
66
|
+
type = 'proxy';
|
|
67
|
+
constructor(readonly value: ResolutionSession) {}
|
|
68
|
+
|
|
69
|
+
toString() {
|
|
70
|
+
return this.value.getBindingPath();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* A proxy handler that applies interceptors
|
|
76
|
+
*
|
|
77
|
+
* See https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy
|
|
78
|
+
*/
|
|
79
|
+
export class InterceptionHandler<T extends object> implements ProxyHandler<T> {
|
|
80
|
+
constructor(
|
|
81
|
+
private context = new Context(),
|
|
82
|
+
private session?: ResolutionSession,
|
|
83
|
+
private source?: InvocationSource,
|
|
84
|
+
) {}
|
|
85
|
+
|
|
86
|
+
get(target: T, propertyName: PropertyKey, receiver: unknown) {
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
88
|
+
const targetObj = target as any;
|
|
89
|
+
if (typeof propertyName !== 'string') return targetObj[propertyName];
|
|
90
|
+
const propertyOrMethod = targetObj[propertyName];
|
|
91
|
+
if (typeof propertyOrMethod === 'function') {
|
|
92
|
+
return (...args: InvocationArgs) => {
|
|
93
|
+
return invokeMethodWithInterceptors(
|
|
94
|
+
this.context,
|
|
95
|
+
target,
|
|
96
|
+
propertyName,
|
|
97
|
+
args,
|
|
98
|
+
{
|
|
99
|
+
source:
|
|
100
|
+
this.source ?? (this.session && new ProxySource(this.session)),
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
};
|
|
104
|
+
} else {
|
|
105
|
+
return propertyOrMethod;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Create a proxy that applies interceptors for method invocations
|
|
112
|
+
* @param target - Target class or object
|
|
113
|
+
* @param context - Context object
|
|
114
|
+
* @param session - Resolution session
|
|
115
|
+
* @param source - Invocation source
|
|
116
|
+
*/
|
|
117
|
+
export function createProxyWithInterceptors<T extends object>(
|
|
118
|
+
target: T,
|
|
119
|
+
context?: Context,
|
|
120
|
+
session?: ResolutionSession,
|
|
121
|
+
source?: InvocationSource,
|
|
122
|
+
): AsyncProxy<T> {
|
|
123
|
+
return new Proxy(
|
|
124
|
+
target,
|
|
125
|
+
new InterceptionHandler(context, ResolutionSession.fork(session), source),
|
|
126
|
+
) as AsyncProxy<T>;
|
|
127
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/context
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import debugFactory from 'debug';
|
|
7
|
+
import {BindingFilter} from './binding-filter';
|
|
8
|
+
import {BindingAddress} from './binding-key';
|
|
9
|
+
import {BindingComparator} from './binding-sorter';
|
|
10
|
+
import {Context} from './context';
|
|
11
|
+
import {InvocationResult} from './invocation';
|
|
12
|
+
import {transformValueOrPromise, ValueOrPromise} from './value-promise';
|
|
13
|
+
const debug = debugFactory('loopback:context:interceptor-chain');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Any type except `void`. We use this type to enforce that interceptor functions
|
|
17
|
+
* always return a value (including undefined or null).
|
|
18
|
+
*/
|
|
19
|
+
export type NonVoid = string | number | boolean | null | undefined | object;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The `next` function that can be used to invoke next generic interceptor in
|
|
23
|
+
* the chain
|
|
24
|
+
*/
|
|
25
|
+
export type Next = () => ValueOrPromise<NonVoid>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* An interceptor function to be invoked in a chain for the given context.
|
|
29
|
+
* It serves as the base interface for various types of interceptors, such
|
|
30
|
+
* as method invocation interceptor or request/response processing interceptor.
|
|
31
|
+
*
|
|
32
|
+
* @remarks
|
|
33
|
+
* We choose `NonVoid` as the return type to avoid possible bugs that an
|
|
34
|
+
* interceptor forgets to return the value from `next()`. For example, the code
|
|
35
|
+
* below will fail to compile.
|
|
36
|
+
*
|
|
37
|
+
* ```ts
|
|
38
|
+
* const myInterceptor: Interceptor = async (ctx, next) {
|
|
39
|
+
* // preprocessing
|
|
40
|
+
* // ...
|
|
41
|
+
*
|
|
42
|
+
* // There is a subtle bug that the result from `next()` is not further
|
|
43
|
+
* // returned back to the upstream interceptors
|
|
44
|
+
* const result = await next();
|
|
45
|
+
*
|
|
46
|
+
* // postprocessing
|
|
47
|
+
* // ...
|
|
48
|
+
* // We must have `return ...` here
|
|
49
|
+
* // either return `result` or another value if the interceptor decides to
|
|
50
|
+
* // have its own response
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @typeParam C - `Context` class or a subclass of `Context`
|
|
55
|
+
* @param context - Context object
|
|
56
|
+
* @param next - A function to proceed with downstream interceptors or the
|
|
57
|
+
* target operation
|
|
58
|
+
*
|
|
59
|
+
* @returns The invocation result as a value (sync) or promise (async).
|
|
60
|
+
*/
|
|
61
|
+
export type GenericInterceptor<C extends Context = Context> = (
|
|
62
|
+
context: C,
|
|
63
|
+
next: Next,
|
|
64
|
+
) => ValueOrPromise<NonVoid>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Interceptor function or a binding key that resolves a generic interceptor
|
|
68
|
+
* function
|
|
69
|
+
* @typeParam C - `Context` class or a subclass of `Context`
|
|
70
|
+
* @typeParam T - Return type of `next()`
|
|
71
|
+
*/
|
|
72
|
+
export type GenericInterceptorOrKey<C extends Context = Context> =
|
|
73
|
+
| BindingAddress<GenericInterceptor<C>>
|
|
74
|
+
| GenericInterceptor<C>;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Invocation state of an interceptor chain
|
|
78
|
+
*/
|
|
79
|
+
class InterceptorChainState<C extends Context = Context> {
|
|
80
|
+
private _index = 0;
|
|
81
|
+
/**
|
|
82
|
+
* Create a state for the interceptor chain
|
|
83
|
+
* @param interceptors - Interceptor functions or binding keys
|
|
84
|
+
* @param finalHandler - An optional final handler
|
|
85
|
+
*/
|
|
86
|
+
constructor(
|
|
87
|
+
public readonly interceptors: GenericInterceptorOrKey<C>[],
|
|
88
|
+
public readonly finalHandler: Next = () => undefined,
|
|
89
|
+
) {}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get the index for the current interceptor
|
|
93
|
+
*/
|
|
94
|
+
get index() {
|
|
95
|
+
return this._index;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Check if the chain is done - all interceptors are invoked
|
|
100
|
+
*/
|
|
101
|
+
done() {
|
|
102
|
+
return this._index === this.interceptors.length;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get the next interceptor to be invoked
|
|
107
|
+
*/
|
|
108
|
+
next() {
|
|
109
|
+
if (this.done()) {
|
|
110
|
+
throw new Error('No more interceptor is in the chain');
|
|
111
|
+
}
|
|
112
|
+
return this.interceptors[this._index++];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* A chain of generic interceptors to be invoked for the given context
|
|
118
|
+
*
|
|
119
|
+
* @typeParam C - `Context` class or a subclass of `Context`
|
|
120
|
+
*/
|
|
121
|
+
export class GenericInterceptorChain<C extends Context = Context> {
|
|
122
|
+
/**
|
|
123
|
+
* A getter for an array of interceptor functions or binding keys
|
|
124
|
+
*/
|
|
125
|
+
protected getInterceptors: () => GenericInterceptorOrKey<C>[];
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Create an invocation chain with a list of interceptor functions or
|
|
129
|
+
* binding keys
|
|
130
|
+
* @param context - Context object
|
|
131
|
+
* @param interceptors - An array of interceptor functions or binding keys
|
|
132
|
+
*/
|
|
133
|
+
constructor(context: C, interceptors: GenericInterceptorOrKey<C>[]);
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Create an invocation interceptor chain with a binding filter and comparator.
|
|
137
|
+
* The interceptors are discovered from the context using the binding filter and
|
|
138
|
+
* sorted by the comparator (if provided).
|
|
139
|
+
*
|
|
140
|
+
* @param context - Context object
|
|
141
|
+
* @param filter - A binding filter function to select interceptors
|
|
142
|
+
* @param comparator - An optional comparator to sort matched interceptor bindings
|
|
143
|
+
*/
|
|
144
|
+
constructor(
|
|
145
|
+
context: C,
|
|
146
|
+
filter: BindingFilter,
|
|
147
|
+
comparator?: BindingComparator,
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
// Implementation
|
|
151
|
+
constructor(
|
|
152
|
+
private context: C,
|
|
153
|
+
interceptors: GenericInterceptorOrKey<C>[] | BindingFilter,
|
|
154
|
+
comparator?: BindingComparator,
|
|
155
|
+
) {
|
|
156
|
+
if (typeof interceptors === 'function') {
|
|
157
|
+
const interceptorsView = context.createView(interceptors, comparator);
|
|
158
|
+
this.getInterceptors = () => {
|
|
159
|
+
const bindings = interceptorsView.bindings;
|
|
160
|
+
if (comparator) {
|
|
161
|
+
bindings.sort(comparator);
|
|
162
|
+
}
|
|
163
|
+
return bindings.map(b => b.key);
|
|
164
|
+
};
|
|
165
|
+
} else if (Array.isArray(interceptors)) {
|
|
166
|
+
this.getInterceptors = () => interceptors;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Invoke the interceptor chain
|
|
172
|
+
*/
|
|
173
|
+
invokeInterceptors(finalHandler?: Next): ValueOrPromise<InvocationResult> {
|
|
174
|
+
// Create a state for each invocation to provide isolation
|
|
175
|
+
const state = new InterceptorChainState<C>(
|
|
176
|
+
this.getInterceptors(),
|
|
177
|
+
finalHandler,
|
|
178
|
+
);
|
|
179
|
+
return this.next(state);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Use the interceptor chain as an interceptor
|
|
184
|
+
*/
|
|
185
|
+
asInterceptor(): GenericInterceptor<C> {
|
|
186
|
+
return (ctx, next) => {
|
|
187
|
+
return this.invokeInterceptors(next);
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Invoke downstream interceptors or the target method
|
|
193
|
+
*/
|
|
194
|
+
private next(
|
|
195
|
+
state: InterceptorChainState<C>,
|
|
196
|
+
): ValueOrPromise<InvocationResult> {
|
|
197
|
+
if (state.done()) {
|
|
198
|
+
// No more interceptors
|
|
199
|
+
return state.finalHandler();
|
|
200
|
+
}
|
|
201
|
+
// Invoke the next interceptor in the chain
|
|
202
|
+
return this.invokeNextInterceptor(state);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Invoke downstream interceptors
|
|
207
|
+
*/
|
|
208
|
+
private invokeNextInterceptor(
|
|
209
|
+
state: InterceptorChainState<C>,
|
|
210
|
+
): ValueOrPromise<InvocationResult> {
|
|
211
|
+
const index = state.index;
|
|
212
|
+
const interceptor = state.next();
|
|
213
|
+
const interceptorFn = this.loadInterceptor(interceptor);
|
|
214
|
+
return transformValueOrPromise(interceptorFn, fn => {
|
|
215
|
+
/* istanbul ignore if */
|
|
216
|
+
if (debug.enabled) {
|
|
217
|
+
debug('Invoking interceptor %d (%s) on %s', index, fn.name);
|
|
218
|
+
}
|
|
219
|
+
return fn(this.context, () => this.next(state));
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Return the interceptor function or resolve the interceptor function as a binding
|
|
225
|
+
* from the context
|
|
226
|
+
*
|
|
227
|
+
* @param interceptor - Interceptor function or binding key
|
|
228
|
+
*/
|
|
229
|
+
private loadInterceptor(interceptor: GenericInterceptorOrKey<C>) {
|
|
230
|
+
if (typeof interceptor === 'function') return interceptor;
|
|
231
|
+
debug('Resolving interceptor binding %s', interceptor);
|
|
232
|
+
return this.context.getValueOrPromise(interceptor) as ValueOrPromise<
|
|
233
|
+
GenericInterceptor<C>
|
|
234
|
+
>;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Invoke a chain of interceptors with the context
|
|
240
|
+
* @param context - Context object
|
|
241
|
+
* @param interceptors - An array of interceptor functions or binding keys
|
|
242
|
+
*/
|
|
243
|
+
export function invokeInterceptors<
|
|
244
|
+
C extends Context = Context,
|
|
245
|
+
T = InvocationResult,
|
|
246
|
+
>(
|
|
247
|
+
context: C,
|
|
248
|
+
interceptors: GenericInterceptorOrKey<C>[],
|
|
249
|
+
): ValueOrPromise<T | undefined> {
|
|
250
|
+
const chain = new GenericInterceptorChain(context, interceptors);
|
|
251
|
+
return chain.invokeInterceptors();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Compose a list of interceptors as a single interceptor
|
|
256
|
+
* @param interceptors - A list of interceptor functions or binding keys
|
|
257
|
+
*/
|
|
258
|
+
export function composeInterceptors<C extends Context = Context>(
|
|
259
|
+
...interceptors: GenericInterceptorOrKey<C>[]
|
|
260
|
+
): GenericInterceptor<C> {
|
|
261
|
+
return (ctx, next) => {
|
|
262
|
+
const interceptor = new GenericInterceptorChain(
|
|
263
|
+
ctx,
|
|
264
|
+
interceptors,
|
|
265
|
+
).asInterceptor();
|
|
266
|
+
return interceptor(ctx, next);
|
|
267
|
+
};
|
|
268
|
+
}
|