@loopback/context 4.0.0-alpha.9 → 4.0.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/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/{lib/src/provider.js → dist/json-types.js} +3 -3
- 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/{lib6/src → dist}/provider.js +2 -2
- 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 -34
- 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/index.d.ts +0 -1
- package/lib/index.js +0 -12
- package/lib/index.js.map +0 -1
- package/lib/src/binding.d.ts +0 -98
- package/lib/src/binding.js +0 -169
- package/lib/src/binding.js.map +0 -1
- package/lib/src/context.d.ts +0 -14
- package/lib/src/context.js +0 -122
- package/lib/src/context.js.map +0 -1
- package/lib/src/index.d.ts +0 -10
- package/lib/src/index.js +0 -25
- package/lib/src/index.js.map +0 -1
- package/lib/src/inject.d.ts +0 -60
- package/lib/src/inject.js +0 -112
- package/lib/src/inject.js.map +0 -1
- package/lib/src/is-promise.d.ts +0 -1
- package/lib/src/is-promise.js +0 -15
- package/lib/src/is-promise.js.map +0 -1
- package/lib/src/provider.d.ts +0 -31
- package/lib/src/provider.js.map +0 -1
- package/lib/src/reflect.d.ts +0 -38
- package/lib/src/reflect.js +0 -143
- package/lib/src/reflect.js.map +0 -1
- package/lib/src/resolver.d.ts +0 -30
- package/lib/src/resolver.js +0 -141
- package/lib/src/resolver.js.map +0 -1
- package/lib6/index.d.ts +0 -1
- package/lib6/index.js +0 -12
- package/lib6/index.js.map +0 -1
- package/lib6/src/binding.d.ts +0 -98
- package/lib6/src/binding.js +0 -169
- package/lib6/src/binding.js.map +0 -1
- package/lib6/src/context.d.ts +0 -14
- package/lib6/src/context.js +0 -122
- package/lib6/src/context.js.map +0 -1
- package/lib6/src/index.d.ts +0 -10
- package/lib6/src/index.js +0 -25
- package/lib6/src/index.js.map +0 -1
- package/lib6/src/inject.d.ts +0 -60
- package/lib6/src/inject.js +0 -112
- package/lib6/src/inject.js.map +0 -1
- package/lib6/src/is-promise.d.ts +0 -1
- package/lib6/src/is-promise.js +0 -15
- package/lib6/src/is-promise.js.map +0 -1
- package/lib6/src/provider.d.ts +0 -31
- package/lib6/src/provider.js.map +0 -1
- package/lib6/src/reflect.d.ts +0 -38
- package/lib6/src/reflect.js +0 -143
- package/lib6/src/reflect.js.map +0 -1
- package/lib6/src/resolver.d.ts +0 -30
- package/lib6/src/resolver.js +0 -141
- package/lib6/src/resolver.js.map +0 -1
package/dist/binding.js
ADDED
|
@@ -0,0 +1,788 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright IBM Corp. 2017,2020. All Rights Reserved.
|
|
3
|
+
// Node module: @loopback/context
|
|
4
|
+
// This file is licensed under the MIT License.
|
|
5
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.Binding = exports.isDynamicValueProviderClass = exports.BindingType = exports.BindingScope = void 0;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
9
|
+
const debug_1 = (0, tslib_1.__importDefault)(require("debug"));
|
|
10
|
+
const events_1 = require("events");
|
|
11
|
+
const binding_inspector_1 = require("./binding-inspector");
|
|
12
|
+
const binding_key_1 = require("./binding-key");
|
|
13
|
+
const inject_1 = require("./inject");
|
|
14
|
+
const interception_proxy_1 = require("./interception-proxy");
|
|
15
|
+
const invocation_1 = require("./invocation");
|
|
16
|
+
const keys_1 = require("./keys");
|
|
17
|
+
const resolution_session_1 = require("./resolution-session");
|
|
18
|
+
const resolver_1 = require("./resolver");
|
|
19
|
+
const value_promise_1 = require("./value-promise");
|
|
20
|
+
const debug = (0, debug_1.default)('loopback:context:binding');
|
|
21
|
+
/**
|
|
22
|
+
* Scope for binding values
|
|
23
|
+
*/
|
|
24
|
+
var BindingScope;
|
|
25
|
+
(function (BindingScope) {
|
|
26
|
+
/**
|
|
27
|
+
* The binding provides a value that is calculated each time. This will be
|
|
28
|
+
* the default scope if not set.
|
|
29
|
+
*
|
|
30
|
+
* For example, with the following context hierarchy:
|
|
31
|
+
*
|
|
32
|
+
* - `app` (with a binding `'b1'` that produces sequential values 0, 1, ...)
|
|
33
|
+
* - req1
|
|
34
|
+
* - req2
|
|
35
|
+
*
|
|
36
|
+
* Now `'b1'` is resolved to a new value each time for `app` and its
|
|
37
|
+
* descendants `req1` and `req2`:
|
|
38
|
+
* - app.get('b1') ==> 0
|
|
39
|
+
* - req1.get('b1') ==> 1
|
|
40
|
+
* - req2.get('b1') ==> 2
|
|
41
|
+
* - req2.get('b1') ==> 3
|
|
42
|
+
* - app.get('b1') ==> 4
|
|
43
|
+
*/
|
|
44
|
+
BindingScope["TRANSIENT"] = "Transient";
|
|
45
|
+
/**
|
|
46
|
+
* @deprecated Finer-grained scopes such as `APPLICATION`, `SERVER`, or
|
|
47
|
+
* `REQUEST` should be used instead to ensure the scope of sharing of resolved
|
|
48
|
+
* binding values.
|
|
49
|
+
*
|
|
50
|
+
* The binding provides a value as a singleton within each local context. The
|
|
51
|
+
* value is calculated only once per context and cached for subsequential
|
|
52
|
+
* uses. Child contexts have their own value and do not share with their
|
|
53
|
+
* ancestors.
|
|
54
|
+
*
|
|
55
|
+
* For example, with the following context hierarchy:
|
|
56
|
+
*
|
|
57
|
+
* - `app` (with a binding `'b1'` that produces sequential values 0, 1, ...)
|
|
58
|
+
* - req1
|
|
59
|
+
* - req2
|
|
60
|
+
*
|
|
61
|
+
* 1. `0` is the resolved value for `'b1'` within the `app` afterward
|
|
62
|
+
* - app.get('b1') ==> 0 (always)
|
|
63
|
+
*
|
|
64
|
+
* 2. `'b1'` is resolved in `app` but not in `req1`, a new value `1` is
|
|
65
|
+
* calculated and used for `req1` afterward
|
|
66
|
+
* - req1.get('b1') ==> 1 (always)
|
|
67
|
+
*
|
|
68
|
+
* 3. `'b1'` is resolved in `app` but not in `req2`, a new value `2` is
|
|
69
|
+
* calculated and used for `req2` afterward
|
|
70
|
+
* - req2.get('b1') ==> 2 (always)
|
|
71
|
+
*
|
|
72
|
+
*/
|
|
73
|
+
BindingScope["CONTEXT"] = "Context";
|
|
74
|
+
/**
|
|
75
|
+
* The binding provides a value as a singleton within the context hierarchy
|
|
76
|
+
* (the owning context and its descendants). The value is calculated only
|
|
77
|
+
* once for the owning context and cached for subsequential uses. Child
|
|
78
|
+
* contexts share the same value as their ancestors.
|
|
79
|
+
*
|
|
80
|
+
* For example, with the following context hierarchy:
|
|
81
|
+
*
|
|
82
|
+
* - `app` (with a binding `'b1'` that produces sequential values 0, 1, ...)
|
|
83
|
+
* - req1
|
|
84
|
+
* - req2
|
|
85
|
+
*
|
|
86
|
+
* 1. `0` is the singleton for `app` afterward
|
|
87
|
+
* - app.get('b1') ==> 0 (always)
|
|
88
|
+
*
|
|
89
|
+
* 2. `'b1'` is resolved in `app`, reuse it for `req1`
|
|
90
|
+
* - req1.get('b1') ==> 0 (always)
|
|
91
|
+
*
|
|
92
|
+
* 3. `'b1'` is resolved in `app`, reuse it for `req2`
|
|
93
|
+
* - req2.get('b1') ==> 0 (always)
|
|
94
|
+
*/
|
|
95
|
+
BindingScope["SINGLETON"] = "Singleton";
|
|
96
|
+
/*
|
|
97
|
+
* The following scopes are checked against the context hierarchy to find
|
|
98
|
+
* the first matching context for a given scope in the chain. Resolved binding
|
|
99
|
+
* values will be cached and shared on the scoped context. This ensures a
|
|
100
|
+
* binding to have the same value for the scoped context.
|
|
101
|
+
*/
|
|
102
|
+
/**
|
|
103
|
+
* Application scope
|
|
104
|
+
*
|
|
105
|
+
* @remarks
|
|
106
|
+
* The binding provides an application-scoped value within the context
|
|
107
|
+
* hierarchy. Resolved value for this binding will be cached and shared for
|
|
108
|
+
* the same application context (denoted by its scope property set to
|
|
109
|
+
* `BindingScope.APPLICATION`).
|
|
110
|
+
*
|
|
111
|
+
*/
|
|
112
|
+
BindingScope["APPLICATION"] = "Application";
|
|
113
|
+
/**
|
|
114
|
+
* Server scope
|
|
115
|
+
*
|
|
116
|
+
* @remarks
|
|
117
|
+
* The binding provides an server-scoped value within the context hierarchy.
|
|
118
|
+
* Resolved value for this binding will be cached and shared for the same
|
|
119
|
+
* server context (denoted by its scope property set to
|
|
120
|
+
* `BindingScope.SERVER`).
|
|
121
|
+
*
|
|
122
|
+
* It's possible that an application has more than one servers configured,
|
|
123
|
+
* such as a `RestServer` and a `GrpcServer`. Both server contexts are created
|
|
124
|
+
* with `scope` set to `BindingScope.SERVER`. Depending on where a binding
|
|
125
|
+
* is resolved:
|
|
126
|
+
* - If the binding is resolved from the RestServer or below, it will be
|
|
127
|
+
* cached using the RestServer context as the key.
|
|
128
|
+
* - If the binding is resolved from the GrpcServer or below, it will be
|
|
129
|
+
* cached using the GrpcServer context as the key.
|
|
130
|
+
*
|
|
131
|
+
* The same binding can resolved/shared/cached for all servers, each of which
|
|
132
|
+
* has its own value for the binding.
|
|
133
|
+
*/
|
|
134
|
+
BindingScope["SERVER"] = "Server";
|
|
135
|
+
/**
|
|
136
|
+
* Request scope
|
|
137
|
+
*
|
|
138
|
+
* @remarks
|
|
139
|
+
* The binding provides an request-scoped value within the context hierarchy.
|
|
140
|
+
* Resolved value for this binding will be cached and shared for the same
|
|
141
|
+
* request context (denoted by its scope property set to
|
|
142
|
+
* `BindingScope.REQUEST`).
|
|
143
|
+
*
|
|
144
|
+
* The `REQUEST` scope is very useful for controllers, services and artifacts
|
|
145
|
+
* that want to have a single instance/value for a given request.
|
|
146
|
+
*/
|
|
147
|
+
BindingScope["REQUEST"] = "Request";
|
|
148
|
+
})(BindingScope = exports.BindingScope || (exports.BindingScope = {}));
|
|
149
|
+
/**
|
|
150
|
+
* Type of the binding source
|
|
151
|
+
*/
|
|
152
|
+
var BindingType;
|
|
153
|
+
(function (BindingType) {
|
|
154
|
+
/**
|
|
155
|
+
* A fixed value
|
|
156
|
+
*/
|
|
157
|
+
BindingType["CONSTANT"] = "Constant";
|
|
158
|
+
/**
|
|
159
|
+
* A function to get the value
|
|
160
|
+
*/
|
|
161
|
+
BindingType["DYNAMIC_VALUE"] = "DynamicValue";
|
|
162
|
+
/**
|
|
163
|
+
* A class to be instantiated as the value
|
|
164
|
+
*/
|
|
165
|
+
BindingType["CLASS"] = "Class";
|
|
166
|
+
/**
|
|
167
|
+
* A provider class with `value()` function to get the value
|
|
168
|
+
*/
|
|
169
|
+
BindingType["PROVIDER"] = "Provider";
|
|
170
|
+
/**
|
|
171
|
+
* A alias to another binding key with optional path
|
|
172
|
+
*/
|
|
173
|
+
BindingType["ALIAS"] = "Alias";
|
|
174
|
+
})(BindingType = exports.BindingType || (exports.BindingType = {}));
|
|
175
|
+
/**
|
|
176
|
+
* Adapt the ValueFactoryProvider class to be a value factory
|
|
177
|
+
* @param provider - ValueFactoryProvider class
|
|
178
|
+
*/
|
|
179
|
+
function toValueFactory(provider) {
|
|
180
|
+
return resolutionCtx => (0, invocation_1.invokeMethod)(provider, 'value', resolutionCtx.context, [], {
|
|
181
|
+
skipInterceptors: true,
|
|
182
|
+
session: resolutionCtx.options.session,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Check if the factory is a value factory provider class
|
|
187
|
+
* @param factory - A factory function or a dynamic value provider class
|
|
188
|
+
*/
|
|
189
|
+
function isDynamicValueProviderClass(factory) {
|
|
190
|
+
// Not a class
|
|
191
|
+
if (typeof factory !== 'function' || !String(factory).startsWith('class ')) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
const valueMethod = factory.value;
|
|
195
|
+
return typeof valueMethod === 'function';
|
|
196
|
+
}
|
|
197
|
+
exports.isDynamicValueProviderClass = isDynamicValueProviderClass;
|
|
198
|
+
/**
|
|
199
|
+
* Binding represents an entry in the `Context`. Each binding has a key and a
|
|
200
|
+
* corresponding value getter.
|
|
201
|
+
*/
|
|
202
|
+
class Binding extends events_1.EventEmitter {
|
|
203
|
+
constructor(key, isLocked = false) {
|
|
204
|
+
super();
|
|
205
|
+
this.isLocked = isLocked;
|
|
206
|
+
/**
|
|
207
|
+
* Map for tag name/value pairs
|
|
208
|
+
*/
|
|
209
|
+
this.tagMap = {};
|
|
210
|
+
binding_key_1.BindingKey.validate(key);
|
|
211
|
+
this.key = key.toString();
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Scope of the binding to control how the value is cached/shared
|
|
215
|
+
*/
|
|
216
|
+
get scope() {
|
|
217
|
+
var _a;
|
|
218
|
+
// Default to TRANSIENT if not set
|
|
219
|
+
return (_a = this._scope) !== null && _a !== void 0 ? _a : BindingScope.TRANSIENT;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Type of the binding value getter
|
|
223
|
+
*/
|
|
224
|
+
get type() {
|
|
225
|
+
var _a;
|
|
226
|
+
return (_a = this._source) === null || _a === void 0 ? void 0 : _a.type;
|
|
227
|
+
}
|
|
228
|
+
get source() {
|
|
229
|
+
return this._source;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* For bindings bound via `toClass()`, this property contains the constructor
|
|
233
|
+
* function of the class
|
|
234
|
+
*/
|
|
235
|
+
get valueConstructor() {
|
|
236
|
+
var _a, _b;
|
|
237
|
+
return ((_a = this._source) === null || _a === void 0 ? void 0 : _a.type) === BindingType.CLASS
|
|
238
|
+
? (_b = this._source) === null || _b === void 0 ? void 0 : _b.value
|
|
239
|
+
: undefined;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* For bindings bound via `toProvider()`, this property contains the
|
|
243
|
+
* constructor function of the provider class
|
|
244
|
+
*/
|
|
245
|
+
get providerConstructor() {
|
|
246
|
+
var _a, _b;
|
|
247
|
+
return ((_a = this._source) === null || _a === void 0 ? void 0 : _a.type) === BindingType.PROVIDER
|
|
248
|
+
? (_b = this._source) === null || _b === void 0 ? void 0 : _b.value
|
|
249
|
+
: undefined;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Cache the resolved value by the binding scope
|
|
253
|
+
* @param resolutionCtx - The resolution context
|
|
254
|
+
* @param result - The calculated value for the binding
|
|
255
|
+
*/
|
|
256
|
+
_cacheValue(resolutionCtx, result) {
|
|
257
|
+
// Initialize the cache as a weakmap keyed by context
|
|
258
|
+
if (!this._cache)
|
|
259
|
+
this._cache = new WeakMap();
|
|
260
|
+
if (this.scope !== BindingScope.TRANSIENT) {
|
|
261
|
+
this._cache.set(resolutionCtx, result);
|
|
262
|
+
}
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Clear the cache
|
|
267
|
+
*/
|
|
268
|
+
_clearCache() {
|
|
269
|
+
if (!this._cache)
|
|
270
|
+
return;
|
|
271
|
+
// WeakMap does not have a `clear` method
|
|
272
|
+
this._cache = new WeakMap();
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Invalidate the binding cache so that its value will be reloaded next time.
|
|
276
|
+
* This is useful to force reloading a cached value when its configuration or
|
|
277
|
+
* dependencies are changed.
|
|
278
|
+
* **WARNING**: The state held in the cached value will be gone.
|
|
279
|
+
*
|
|
280
|
+
* @param ctx - Context object
|
|
281
|
+
*/
|
|
282
|
+
refresh(ctx) {
|
|
283
|
+
if (!this._cache)
|
|
284
|
+
return;
|
|
285
|
+
if (this.scope !== BindingScope.TRANSIENT) {
|
|
286
|
+
const resolutionCtx = ctx.getResolutionContext(this);
|
|
287
|
+
if (resolutionCtx != null) {
|
|
288
|
+
this._cache.delete(resolutionCtx);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
// Implementation
|
|
293
|
+
getValue(ctx, optionsOrSession) {
|
|
294
|
+
var _a;
|
|
295
|
+
/* istanbul ignore if */
|
|
296
|
+
if (debug.enabled) {
|
|
297
|
+
debug('Get value for binding %s', this.key);
|
|
298
|
+
}
|
|
299
|
+
const options = (0, resolution_session_1.asResolutionOptions)(optionsOrSession);
|
|
300
|
+
const resolutionCtx = this.getResolutionContext(ctx, options);
|
|
301
|
+
if (resolutionCtx == null)
|
|
302
|
+
return undefined;
|
|
303
|
+
// Keep a snapshot for proxy
|
|
304
|
+
const savedSession = (_a = resolution_session_1.ResolutionSession.fork(options.session)) !== null && _a !== void 0 ? _a : new resolution_session_1.ResolutionSession();
|
|
305
|
+
// First check cached value for non-transient
|
|
306
|
+
if (this._cache) {
|
|
307
|
+
if (this.scope !== BindingScope.TRANSIENT) {
|
|
308
|
+
if (resolutionCtx && this._cache.has(resolutionCtx)) {
|
|
309
|
+
const value = this._cache.get(resolutionCtx);
|
|
310
|
+
return this.getValueOrProxy(resolutionCtx, { ...options, session: savedSession }, value);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
const resolutionMetadata = {
|
|
315
|
+
context: resolutionCtx,
|
|
316
|
+
binding: this,
|
|
317
|
+
options,
|
|
318
|
+
};
|
|
319
|
+
if (typeof this._getValue === 'function') {
|
|
320
|
+
const result = resolution_session_1.ResolutionSession.runWithBinding(s => {
|
|
321
|
+
const optionsWithSession = {
|
|
322
|
+
...options,
|
|
323
|
+
session: s,
|
|
324
|
+
// Force to be the non-proxy version
|
|
325
|
+
asProxyWithInterceptors: false,
|
|
326
|
+
};
|
|
327
|
+
// We already test `this._getValue` is a function. It's safe to assert
|
|
328
|
+
// that `this._getValue` is not undefined.
|
|
329
|
+
return this._getValue({
|
|
330
|
+
...resolutionMetadata,
|
|
331
|
+
options: optionsWithSession,
|
|
332
|
+
});
|
|
333
|
+
}, this, options.session);
|
|
334
|
+
const value = this._cacheValue(resolutionCtx, result);
|
|
335
|
+
return this.getValueOrProxy(resolutionCtx, { ...options, session: savedSession }, value);
|
|
336
|
+
}
|
|
337
|
+
// `@inject.binding` adds a binding without _getValue
|
|
338
|
+
if (options.optional)
|
|
339
|
+
return undefined;
|
|
340
|
+
return Promise.reject(new resolution_session_1.ResolutionError(`No value was configured for binding ${this.key}.`, resolutionMetadata));
|
|
341
|
+
}
|
|
342
|
+
getValueOrProxy(resolutionCtx, options, value) {
|
|
343
|
+
const session = options.session;
|
|
344
|
+
session.pushBinding(this);
|
|
345
|
+
return Binding.valueOrProxy({
|
|
346
|
+
context: resolutionCtx,
|
|
347
|
+
binding: this,
|
|
348
|
+
options,
|
|
349
|
+
}, value);
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Locate and validate the resolution context
|
|
353
|
+
* @param ctx - Current context
|
|
354
|
+
* @param options - Resolution options
|
|
355
|
+
*/
|
|
356
|
+
getResolutionContext(ctx, options) {
|
|
357
|
+
const resolutionCtx = ctx.getResolutionContext(this);
|
|
358
|
+
switch (this.scope) {
|
|
359
|
+
case BindingScope.APPLICATION:
|
|
360
|
+
case BindingScope.SERVER:
|
|
361
|
+
case BindingScope.REQUEST:
|
|
362
|
+
if (resolutionCtx == null) {
|
|
363
|
+
const msg = `Binding "${this.key}" in context "${ctx.name}" cannot` +
|
|
364
|
+
` be resolved in scope "${this.scope}"`;
|
|
365
|
+
if (options.optional) {
|
|
366
|
+
debug(msg);
|
|
367
|
+
return undefined;
|
|
368
|
+
}
|
|
369
|
+
throw new Error(msg);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const ownerCtx = ctx.getOwnerContext(this.key);
|
|
373
|
+
if (ownerCtx != null && !ownerCtx.isVisibleTo(resolutionCtx)) {
|
|
374
|
+
const msg = `Resolution context "${resolutionCtx === null || resolutionCtx === void 0 ? void 0 : resolutionCtx.name}" does not have ` +
|
|
375
|
+
`visibility to binding "${this.key} (scope:${this.scope})" in context "${ownerCtx.name}"`;
|
|
376
|
+
if (options.optional) {
|
|
377
|
+
debug(msg);
|
|
378
|
+
return undefined;
|
|
379
|
+
}
|
|
380
|
+
throw new Error(msg);
|
|
381
|
+
}
|
|
382
|
+
return resolutionCtx;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Lock the binding so that it cannot be rebound
|
|
386
|
+
*/
|
|
387
|
+
lock() {
|
|
388
|
+
this.isLocked = true;
|
|
389
|
+
return this;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Emit a `changed` event
|
|
393
|
+
* @param operation - Operation that makes changes
|
|
394
|
+
*/
|
|
395
|
+
emitChangedEvent(operation) {
|
|
396
|
+
const event = { binding: this, operation, type: 'changed' };
|
|
397
|
+
this.emit('changed', event);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Tag the binding with names or name/value objects. A tag has a name and
|
|
401
|
+
* an optional value. If not supplied, the tag name is used as the value.
|
|
402
|
+
*
|
|
403
|
+
* @param tags - A list of names or name/value objects. Each
|
|
404
|
+
* parameter can be in one of the following forms:
|
|
405
|
+
* - string: A tag name without value
|
|
406
|
+
* - string[]: An array of tag names
|
|
407
|
+
* - TagMap: A map of tag name/value pairs
|
|
408
|
+
*
|
|
409
|
+
* @example
|
|
410
|
+
* ```ts
|
|
411
|
+
* // Add a named tag `controller`
|
|
412
|
+
* binding.tag('controller');
|
|
413
|
+
*
|
|
414
|
+
* // Add two named tags: `controller` and `rest`
|
|
415
|
+
* binding.tag('controller', 'rest');
|
|
416
|
+
*
|
|
417
|
+
* // Add two tags
|
|
418
|
+
* // - `controller` (name = 'controller')
|
|
419
|
+
* // `{name: 'my-controller'}` (name = 'name', value = 'my-controller')
|
|
420
|
+
* binding.tag('controller', {name: 'my-controller'});
|
|
421
|
+
*
|
|
422
|
+
* ```
|
|
423
|
+
*/
|
|
424
|
+
tag(...tags) {
|
|
425
|
+
for (const t of tags) {
|
|
426
|
+
if (typeof t === 'string') {
|
|
427
|
+
this.tagMap[t] = t;
|
|
428
|
+
}
|
|
429
|
+
else if (Array.isArray(t)) {
|
|
430
|
+
// Throw an error as TypeScript cannot exclude array from TagMap
|
|
431
|
+
throw new Error('Tag must be a string or an object (but not array): ' + t);
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
Object.assign(this.tagMap, t);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
this.emitChangedEvent('tag');
|
|
438
|
+
return this;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Get an array of tag names
|
|
442
|
+
*/
|
|
443
|
+
get tagNames() {
|
|
444
|
+
return Object.keys(this.tagMap);
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Set the binding scope
|
|
448
|
+
* @param scope - Binding scope
|
|
449
|
+
*/
|
|
450
|
+
inScope(scope) {
|
|
451
|
+
if (this._scope !== scope)
|
|
452
|
+
this._clearCache();
|
|
453
|
+
this._scope = scope;
|
|
454
|
+
this.emitChangedEvent('scope');
|
|
455
|
+
return this;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Apply default scope to the binding. It only changes the scope if it's not
|
|
459
|
+
* set yet
|
|
460
|
+
* @param scope - Default binding scope
|
|
461
|
+
*/
|
|
462
|
+
applyDefaultScope(scope) {
|
|
463
|
+
if (!this._scope) {
|
|
464
|
+
this.inScope(scope);
|
|
465
|
+
}
|
|
466
|
+
return this;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Set the `_getValue` function
|
|
470
|
+
* @param getValue - getValue function
|
|
471
|
+
*/
|
|
472
|
+
_setValueGetter(getValue) {
|
|
473
|
+
// Clear the cache
|
|
474
|
+
this._clearCache();
|
|
475
|
+
this._getValue = resolutionCtx => {
|
|
476
|
+
return getValue(resolutionCtx);
|
|
477
|
+
};
|
|
478
|
+
this.emitChangedEvent('value');
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Bind the key to a constant value. The value must be already available
|
|
482
|
+
* at binding time, it is not allowed to pass a Promise instance.
|
|
483
|
+
*
|
|
484
|
+
* @param value - The bound value.
|
|
485
|
+
*
|
|
486
|
+
* @example
|
|
487
|
+
*
|
|
488
|
+
* ```ts
|
|
489
|
+
* ctx.bind('appName').to('CodeHub');
|
|
490
|
+
* ```
|
|
491
|
+
*/
|
|
492
|
+
to(value) {
|
|
493
|
+
if ((0, value_promise_1.isPromiseLike)(value)) {
|
|
494
|
+
// Promises are a construct primarily intended for flow control:
|
|
495
|
+
// In an algorithm with steps 1 and 2, we want to wait for the outcome
|
|
496
|
+
// of step 1 before starting step 2.
|
|
497
|
+
//
|
|
498
|
+
// Promises are NOT a tool for storing values that may become available
|
|
499
|
+
// in the future, depending on the success or a failure of a background
|
|
500
|
+
// async task.
|
|
501
|
+
//
|
|
502
|
+
// Values stored in bindings are typically accessed only later,
|
|
503
|
+
// in a different turn of the event loop or the Promise micro-queue.
|
|
504
|
+
// As a result, when a promise is stored via `.to()` and is rejected
|
|
505
|
+
// later, then more likely than not, there will be no error (catch)
|
|
506
|
+
// handler registered yet, and Node.js will print
|
|
507
|
+
// "Unhandled Rejection Warning".
|
|
508
|
+
throw new Error('Promise instances are not allowed for constant values ' +
|
|
509
|
+
'bound via ".to()". Register an async getter function ' +
|
|
510
|
+
'via ".toDynamicValue()" instead.');
|
|
511
|
+
}
|
|
512
|
+
/* istanbul ignore if */
|
|
513
|
+
if (debug.enabled) {
|
|
514
|
+
debug('Bind %s to constant:', this.key, value);
|
|
515
|
+
}
|
|
516
|
+
this._source = {
|
|
517
|
+
type: BindingType.CONSTANT,
|
|
518
|
+
value,
|
|
519
|
+
};
|
|
520
|
+
this._setValueGetter(resolutionCtx => {
|
|
521
|
+
return Binding.valueOrProxy(resolutionCtx, value);
|
|
522
|
+
});
|
|
523
|
+
return this;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Bind the key to a computed (dynamic) value.
|
|
527
|
+
*
|
|
528
|
+
* @param factoryFn - The factory function creating the value.
|
|
529
|
+
* Both sync and async functions are supported.
|
|
530
|
+
*
|
|
531
|
+
* @example
|
|
532
|
+
*
|
|
533
|
+
* ```ts
|
|
534
|
+
* // synchronous
|
|
535
|
+
* ctx.bind('now').toDynamicValue(() => Date.now());
|
|
536
|
+
*
|
|
537
|
+
* // asynchronous
|
|
538
|
+
* ctx.bind('something').toDynamicValue(
|
|
539
|
+
* async () => Promise.delay(10).then(doSomething)
|
|
540
|
+
* );
|
|
541
|
+
* ```
|
|
542
|
+
*/
|
|
543
|
+
toDynamicValue(factory) {
|
|
544
|
+
/* istanbul ignore if */
|
|
545
|
+
if (debug.enabled) {
|
|
546
|
+
debug('Bind %s to dynamic value:', this.key, factory);
|
|
547
|
+
}
|
|
548
|
+
this._source = {
|
|
549
|
+
type: BindingType.DYNAMIC_VALUE,
|
|
550
|
+
value: factory,
|
|
551
|
+
};
|
|
552
|
+
let factoryFn;
|
|
553
|
+
if (isDynamicValueProviderClass(factory)) {
|
|
554
|
+
factoryFn = toValueFactory(factory);
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
factoryFn = factory;
|
|
558
|
+
}
|
|
559
|
+
this._setValueGetter(resolutionCtx => {
|
|
560
|
+
const value = factoryFn(resolutionCtx);
|
|
561
|
+
return Binding.valueOrProxy(resolutionCtx, value);
|
|
562
|
+
});
|
|
563
|
+
return this;
|
|
564
|
+
}
|
|
565
|
+
static valueOrProxy(resolutionCtx, value) {
|
|
566
|
+
if (!resolutionCtx.options.asProxyWithInterceptors)
|
|
567
|
+
return value;
|
|
568
|
+
return createInterceptionProxyFromInstance(value, resolutionCtx.context, resolutionCtx.options.session);
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Bind the key to a value computed by a Provider.
|
|
572
|
+
*
|
|
573
|
+
* * @example
|
|
574
|
+
*
|
|
575
|
+
* ```ts
|
|
576
|
+
* export class DateProvider implements Provider<Date> {
|
|
577
|
+
* constructor(@inject('stringDate') private param: String){}
|
|
578
|
+
* value(): Date {
|
|
579
|
+
* return new Date(param);
|
|
580
|
+
* }
|
|
581
|
+
* }
|
|
582
|
+
* ```
|
|
583
|
+
*
|
|
584
|
+
* @param provider - The value provider to use.
|
|
585
|
+
*/
|
|
586
|
+
toProvider(providerClass) {
|
|
587
|
+
/* istanbul ignore if */
|
|
588
|
+
if (debug.enabled) {
|
|
589
|
+
debug('Bind %s to provider %s', this.key, providerClass.name);
|
|
590
|
+
}
|
|
591
|
+
this._source = {
|
|
592
|
+
type: BindingType.PROVIDER,
|
|
593
|
+
value: providerClass,
|
|
594
|
+
};
|
|
595
|
+
this._setValueGetter(resolutionCtx => {
|
|
596
|
+
const providerOrPromise = (0, resolver_1.instantiateClass)(providerClass, resolutionCtx.context, resolutionCtx.options.session);
|
|
597
|
+
const value = (0, value_promise_1.transformValueOrPromise)(providerOrPromise, p => p.value());
|
|
598
|
+
return Binding.valueOrProxy(resolutionCtx, value);
|
|
599
|
+
});
|
|
600
|
+
return this;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Bind the key to an instance of the given class.
|
|
604
|
+
*
|
|
605
|
+
* @param ctor - The class constructor to call. Any constructor
|
|
606
|
+
* arguments must be annotated with `@inject` so that
|
|
607
|
+
* we can resolve them from the context.
|
|
608
|
+
*/
|
|
609
|
+
toClass(ctor) {
|
|
610
|
+
/* istanbul ignore if */
|
|
611
|
+
if (debug.enabled) {
|
|
612
|
+
debug('Bind %s to class %s', this.key, ctor.name);
|
|
613
|
+
}
|
|
614
|
+
this._source = {
|
|
615
|
+
type: BindingType.CLASS,
|
|
616
|
+
value: ctor,
|
|
617
|
+
};
|
|
618
|
+
this._setValueGetter(resolutionCtx => {
|
|
619
|
+
const value = (0, resolver_1.instantiateClass)(ctor, resolutionCtx.context, resolutionCtx.options.session);
|
|
620
|
+
return Binding.valueOrProxy(resolutionCtx, value);
|
|
621
|
+
});
|
|
622
|
+
return this;
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Bind to a class optionally decorated with `@injectable`. Based on the
|
|
626
|
+
* introspection of the class, it calls `toClass/toProvider/toDynamicValue`
|
|
627
|
+
* internally. The current binding key will be preserved (not being overridden
|
|
628
|
+
* by the key inferred from the class or options).
|
|
629
|
+
*
|
|
630
|
+
* This is similar to {@link createBindingFromClass} but applies to an
|
|
631
|
+
* existing binding.
|
|
632
|
+
*
|
|
633
|
+
* @example
|
|
634
|
+
*
|
|
635
|
+
* ```ts
|
|
636
|
+
* @injectable({scope: BindingScope.SINGLETON, tags: {service: 'MyService}})
|
|
637
|
+
* class MyService {
|
|
638
|
+
* // ...
|
|
639
|
+
* }
|
|
640
|
+
*
|
|
641
|
+
* const ctx = new Context();
|
|
642
|
+
* ctx.bind('services.MyService').toInjectable(MyService);
|
|
643
|
+
* ```
|
|
644
|
+
*
|
|
645
|
+
* @param ctor - A class decorated with `@injectable`.
|
|
646
|
+
*/
|
|
647
|
+
toInjectable(ctor) {
|
|
648
|
+
this.apply((0, binding_inspector_1.bindingTemplateFor)(ctor));
|
|
649
|
+
return this;
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Bind the key to an alias of another binding
|
|
653
|
+
* @param keyWithPath - Target binding key with optional path,
|
|
654
|
+
* such as `servers.RestServer.options#apiExplorer`
|
|
655
|
+
*/
|
|
656
|
+
toAlias(keyWithPath) {
|
|
657
|
+
/* istanbul ignore if */
|
|
658
|
+
if (debug.enabled) {
|
|
659
|
+
debug('Bind %s to alias %s', this.key, keyWithPath);
|
|
660
|
+
}
|
|
661
|
+
this._source = {
|
|
662
|
+
type: BindingType.ALIAS,
|
|
663
|
+
value: keyWithPath,
|
|
664
|
+
};
|
|
665
|
+
this._setValueGetter(({ context, options }) => {
|
|
666
|
+
return context.getValueOrPromise(keyWithPath, options);
|
|
667
|
+
});
|
|
668
|
+
return this;
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Unlock the binding
|
|
672
|
+
*/
|
|
673
|
+
unlock() {
|
|
674
|
+
this.isLocked = false;
|
|
675
|
+
return this;
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Apply one or more template functions to set up the binding with scope,
|
|
679
|
+
* tags, and other attributes as a group.
|
|
680
|
+
*
|
|
681
|
+
* @example
|
|
682
|
+
* ```ts
|
|
683
|
+
* const serverTemplate = (binding: Binding) =>
|
|
684
|
+
* binding.inScope(BindingScope.SINGLETON).tag('server');
|
|
685
|
+
*
|
|
686
|
+
* const serverBinding = new Binding<RestServer>('servers.RestServer1');
|
|
687
|
+
* serverBinding.apply(serverTemplate);
|
|
688
|
+
* ```
|
|
689
|
+
* @param templateFns - One or more functions to configure the binding
|
|
690
|
+
*/
|
|
691
|
+
apply(...templateFns) {
|
|
692
|
+
for (const fn of templateFns) {
|
|
693
|
+
fn(this);
|
|
694
|
+
}
|
|
695
|
+
return this;
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Convert to a plain JSON object
|
|
699
|
+
*/
|
|
700
|
+
toJSON() {
|
|
701
|
+
var _a, _b, _c, _d;
|
|
702
|
+
const json = {
|
|
703
|
+
key: this.key,
|
|
704
|
+
scope: this.scope,
|
|
705
|
+
tags: this.tagMap,
|
|
706
|
+
isLocked: this.isLocked,
|
|
707
|
+
};
|
|
708
|
+
if (this.type != null) {
|
|
709
|
+
json.type = this.type;
|
|
710
|
+
}
|
|
711
|
+
switch ((_a = this._source) === null || _a === void 0 ? void 0 : _a.type) {
|
|
712
|
+
case BindingType.CLASS:
|
|
713
|
+
json.valueConstructor = (_b = this._source) === null || _b === void 0 ? void 0 : _b.value.name;
|
|
714
|
+
break;
|
|
715
|
+
case BindingType.PROVIDER:
|
|
716
|
+
json.providerConstructor = (_c = this._source) === null || _c === void 0 ? void 0 : _c.value.name;
|
|
717
|
+
break;
|
|
718
|
+
case BindingType.ALIAS:
|
|
719
|
+
json.alias = (_d = this._source) === null || _d === void 0 ? void 0 : _d.value.toString();
|
|
720
|
+
break;
|
|
721
|
+
}
|
|
722
|
+
return json;
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Inspect the binding to return a json representation of the binding information
|
|
726
|
+
* @param options - Options to control what information should be included
|
|
727
|
+
*/
|
|
728
|
+
inspect(options = {}) {
|
|
729
|
+
options = {
|
|
730
|
+
includeInjections: false,
|
|
731
|
+
...options,
|
|
732
|
+
};
|
|
733
|
+
const json = this.toJSON();
|
|
734
|
+
if (options.includeInjections) {
|
|
735
|
+
const injections = (0, inject_1.inspectInjections)(this);
|
|
736
|
+
if (Object.keys(injections).length)
|
|
737
|
+
json.injections = injections;
|
|
738
|
+
}
|
|
739
|
+
return json;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* A static method to create a binding so that we can do
|
|
743
|
+
* `Binding.bind('foo').to('bar');` as `new Binding('foo').to('bar')` is not
|
|
744
|
+
* easy to read.
|
|
745
|
+
* @param key - Binding key
|
|
746
|
+
*/
|
|
747
|
+
static bind(key) {
|
|
748
|
+
return new Binding(key);
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* Create a configuration binding for the given key
|
|
752
|
+
*
|
|
753
|
+
* @example
|
|
754
|
+
* ```ts
|
|
755
|
+
* const configBinding = Binding.configure('servers.RestServer.server1')
|
|
756
|
+
* .to({port: 3000});
|
|
757
|
+
* ```
|
|
758
|
+
*
|
|
759
|
+
* @typeParam V Generic type for the configuration value (not the binding to
|
|
760
|
+
* be configured)
|
|
761
|
+
*
|
|
762
|
+
* @param key - Key for the binding to be configured
|
|
763
|
+
*/
|
|
764
|
+
static configure(key) {
|
|
765
|
+
return new Binding(binding_key_1.BindingKey.buildKeyForConfig(key)).tag({
|
|
766
|
+
[keys_1.ContextTags.CONFIGURATION_FOR]: key.toString(),
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
770
|
+
on(event, listener) {
|
|
771
|
+
return super.on(event, listener);
|
|
772
|
+
}
|
|
773
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
774
|
+
once(event, listener) {
|
|
775
|
+
return super.once(event, listener);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
exports.Binding = Binding;
|
|
779
|
+
function createInterceptionProxyFromInstance(instOrPromise, context, session) {
|
|
780
|
+
return (0, value_promise_1.transformValueOrPromise)(instOrPromise, inst => {
|
|
781
|
+
if (typeof inst !== 'object' || inst == null)
|
|
782
|
+
return inst;
|
|
783
|
+
return (0, interception_proxy_1.createProxyWithInterceptors)(
|
|
784
|
+
// Cast inst from `T` to `object`
|
|
785
|
+
inst, context, session);
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
//# sourceMappingURL=binding.js.map
|