@loopback/context 4.0.0-alpha.8 → 4.1.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.
Files changed (201) hide show
  1. package/LICENSE +25 -0
  2. package/README.md +116 -0
  3. package/dist/binding-config.d.ts +40 -0
  4. package/dist/binding-config.js +33 -0
  5. package/dist/binding-config.js.map +1 -0
  6. package/dist/binding-decorator.d.ts +45 -0
  7. package/dist/binding-decorator.js +118 -0
  8. package/dist/binding-decorator.js.map +1 -0
  9. package/dist/binding-filter.d.ts +108 -0
  10. package/dist/binding-filter.js +162 -0
  11. package/dist/binding-filter.js.map +1 -0
  12. package/dist/binding-inspector.d.ts +150 -0
  13. package/dist/binding-inspector.js +249 -0
  14. package/dist/binding-inspector.js.map +1 -0
  15. package/dist/binding-key.d.ts +66 -0
  16. package/dist/binding-key.js +121 -0
  17. package/dist/binding-key.js.map +1 -0
  18. package/dist/binding-sorter.d.ts +71 -0
  19. package/dist/binding-sorter.js +89 -0
  20. package/dist/binding-sorter.js.map +1 -0
  21. package/dist/binding.d.ts +577 -0
  22. package/dist/binding.js +788 -0
  23. package/dist/binding.js.map +1 -0
  24. package/dist/context-event.d.ts +23 -0
  25. package/dist/context-event.js +7 -0
  26. package/dist/context-event.js.map +1 -0
  27. package/dist/context-observer.d.ts +36 -0
  28. package/dist/context-observer.js +7 -0
  29. package/dist/context-observer.js.map +1 -0
  30. package/dist/context-subscription.d.ts +147 -0
  31. package/dist/context-subscription.js +317 -0
  32. package/dist/context-subscription.js.map +1 -0
  33. package/dist/context-tag-indexer.d.ts +42 -0
  34. package/dist/context-tag-indexer.js +135 -0
  35. package/dist/context-tag-indexer.js.map +1 -0
  36. package/dist/context-view.d.ts +209 -0
  37. package/dist/context-view.js +240 -0
  38. package/dist/context-view.js.map +1 -0
  39. package/dist/context.d.ts +513 -0
  40. package/dist/context.js +717 -0
  41. package/dist/context.js.map +1 -0
  42. package/dist/index.d.ts +52 -0
  43. package/dist/index.js +60 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/inject-config.d.ts +67 -0
  46. package/dist/inject-config.js +181 -0
  47. package/dist/inject-config.js.map +1 -0
  48. package/dist/inject.d.ts +250 -0
  49. package/dist/inject.js +535 -0
  50. package/dist/inject.js.map +1 -0
  51. package/dist/interception-proxy.d.ts +76 -0
  52. package/dist/interception-proxy.js +67 -0
  53. package/dist/interception-proxy.js.map +1 -0
  54. package/dist/interceptor-chain.d.ts +121 -0
  55. package/dist/interceptor-chain.js +148 -0
  56. package/dist/interceptor-chain.js.map +1 -0
  57. package/dist/interceptor.d.ts +138 -0
  58. package/dist/interceptor.js +299 -0
  59. package/dist/interceptor.js.map +1 -0
  60. package/dist/invocation.d.ts +101 -0
  61. package/dist/invocation.js +163 -0
  62. package/dist/invocation.js.map +1 -0
  63. package/dist/json-types.d.ts +28 -0
  64. package/{lib/src/provider.js → dist/json-types.js} +3 -3
  65. package/dist/json-types.js.map +1 -0
  66. package/dist/keys.d.ts +65 -0
  67. package/dist/keys.js +74 -0
  68. package/dist/keys.js.map +1 -0
  69. package/dist/provider.d.ts +31 -0
  70. package/{lib6/src → dist}/provider.js +2 -2
  71. package/dist/provider.js.map +1 -0
  72. package/dist/resolution-session.d.ts +180 -0
  73. package/dist/resolution-session.js +274 -0
  74. package/dist/resolution-session.js.map +1 -0
  75. package/dist/resolver.d.ts +46 -0
  76. package/dist/resolver.js +203 -0
  77. package/dist/resolver.js.map +1 -0
  78. package/dist/unique-id.d.ts +14 -0
  79. package/dist/unique-id.js +26 -0
  80. package/dist/unique-id.js.map +1 -0
  81. package/dist/value-promise.d.ts +134 -0
  82. package/dist/value-promise.js +277 -0
  83. package/dist/value-promise.js.map +1 -0
  84. package/package.json +49 -34
  85. package/src/binding-config.ts +73 -0
  86. package/src/binding-decorator.ts +136 -0
  87. package/src/binding-filter.ts +250 -0
  88. package/src/binding-inspector.ts +371 -0
  89. package/src/binding-key.ts +136 -0
  90. package/src/binding-sorter.ts +124 -0
  91. package/src/binding.ts +1107 -0
  92. package/src/context-event.ts +30 -0
  93. package/src/context-observer.ts +50 -0
  94. package/src/context-subscription.ts +402 -0
  95. package/src/context-tag-indexer.ts +147 -0
  96. package/src/context-view.ts +440 -0
  97. package/src/context.ts +1079 -0
  98. package/src/index.ts +58 -0
  99. package/src/inject-config.ts +239 -0
  100. package/src/inject.ts +796 -0
  101. package/src/interception-proxy.ts +127 -0
  102. package/src/interceptor-chain.ts +268 -0
  103. package/src/interceptor.ts +430 -0
  104. package/src/invocation.ts +269 -0
  105. package/src/json-types.ts +35 -0
  106. package/src/keys.ts +85 -0
  107. package/src/provider.ts +37 -0
  108. package/src/resolution-session.ts +414 -0
  109. package/src/resolver.ts +282 -0
  110. package/src/unique-id.ts +24 -0
  111. package/src/value-promise.ts +318 -0
  112. package/index.d.ts +0 -6
  113. package/index.js +0 -9
  114. package/lib/binding.d.ts +0 -75
  115. package/lib/binding.js +0 -103
  116. package/lib/binding.js.map +0 -1
  117. package/lib/context.d.ts +0 -14
  118. package/lib/context.js +0 -97
  119. package/lib/context.js.map +0 -1
  120. package/lib/index.d.ts +0 -1
  121. package/lib/index.js +0 -12
  122. package/lib/index.js.map +0 -1
  123. package/lib/inject.d.ts +0 -46
  124. package/lib/inject.js +0 -74
  125. package/lib/inject.js.map +0 -1
  126. package/lib/isPromise.d.ts +0 -1
  127. package/lib/isPromise.js +0 -15
  128. package/lib/isPromise.js.map +0 -1
  129. package/lib/reflect.d.ts +0 -39
  130. package/lib/reflect.js +0 -20
  131. package/lib/reflect.js.map +0 -1
  132. package/lib/resolver.d.ts +0 -30
  133. package/lib/resolver.js +0 -129
  134. package/lib/resolver.js.map +0 -1
  135. package/lib/src/binding.d.ts +0 -85
  136. package/lib/src/binding.js +0 -123
  137. package/lib/src/binding.js.map +0 -1
  138. package/lib/src/context.d.ts +0 -14
  139. package/lib/src/context.js +0 -97
  140. package/lib/src/context.js.map +0 -1
  141. package/lib/src/index.d.ts +0 -10
  142. package/lib/src/index.js +0 -27
  143. package/lib/src/index.js.map +0 -1
  144. package/lib/src/inject.d.ts +0 -46
  145. package/lib/src/inject.js +0 -74
  146. package/lib/src/inject.js.map +0 -1
  147. package/lib/src/isPromise.d.ts +0 -1
  148. package/lib/src/isPromise.js +0 -15
  149. package/lib/src/isPromise.js.map +0 -1
  150. package/lib/src/provider.d.ts +0 -29
  151. package/lib/src/provider.js.map +0 -1
  152. package/lib/src/reflect.d.ts +0 -38
  153. package/lib/src/reflect.js +0 -143
  154. package/lib/src/reflect.js.map +0 -1
  155. package/lib/src/resolver.d.ts +0 -34
  156. package/lib/src/resolver.js +0 -144
  157. package/lib/src/resolver.js.map +0 -1
  158. package/lib6/binding.d.ts +0 -75
  159. package/lib6/binding.js +0 -103
  160. package/lib6/binding.js.map +0 -1
  161. package/lib6/context.d.ts +0 -14
  162. package/lib6/context.js +0 -97
  163. package/lib6/context.js.map +0 -1
  164. package/lib6/index.d.ts +0 -1
  165. package/lib6/index.js +0 -12
  166. package/lib6/index.js.map +0 -1
  167. package/lib6/inject.d.ts +0 -46
  168. package/lib6/inject.js +0 -74
  169. package/lib6/inject.js.map +0 -1
  170. package/lib6/isPromise.d.ts +0 -1
  171. package/lib6/isPromise.js +0 -15
  172. package/lib6/isPromise.js.map +0 -1
  173. package/lib6/reflect.d.ts +0 -39
  174. package/lib6/reflect.js +0 -20
  175. package/lib6/reflect.js.map +0 -1
  176. package/lib6/resolver.d.ts +0 -30
  177. package/lib6/resolver.js +0 -129
  178. package/lib6/resolver.js.map +0 -1
  179. package/lib6/src/binding.d.ts +0 -85
  180. package/lib6/src/binding.js +0 -133
  181. package/lib6/src/binding.js.map +0 -1
  182. package/lib6/src/context.d.ts +0 -14
  183. package/lib6/src/context.js +0 -97
  184. package/lib6/src/context.js.map +0 -1
  185. package/lib6/src/index.d.ts +0 -10
  186. package/lib6/src/index.js +0 -27
  187. package/lib6/src/index.js.map +0 -1
  188. package/lib6/src/inject.d.ts +0 -46
  189. package/lib6/src/inject.js +0 -74
  190. package/lib6/src/inject.js.map +0 -1
  191. package/lib6/src/isPromise.d.ts +0 -1
  192. package/lib6/src/isPromise.js +0 -15
  193. package/lib6/src/isPromise.js.map +0 -1
  194. package/lib6/src/provider.d.ts +0 -29
  195. package/lib6/src/provider.js.map +0 -1
  196. package/lib6/src/reflect.d.ts +0 -38
  197. package/lib6/src/reflect.js +0 -143
  198. package/lib6/src/reflect.js.map +0 -1
  199. package/lib6/src/resolver.d.ts +0 -34
  200. package/lib6/src/resolver.js +0 -154
  201. package/lib6/src/resolver.js.map +0 -1
@@ -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
+ }