UNPKG

27.9 kBJavaScriptView Raw
1"use strict";
2// Copyright IBM Corp. and LoopBack contributors 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
6Object.defineProperty(exports, "__esModule", { value: true });
7exports.Binding = exports.isDynamicValueProviderClass = exports.BindingType = exports.BindingScope = void 0;
8const tslib_1 = require("tslib");
9const debug_1 = tslib_1.__importDefault(require("debug"));
10const events_1 = require("events");
11const binding_inspector_1 = require("./binding-inspector");
12const binding_key_1 = require("./binding-key");
13const inject_1 = require("./inject");
14const interception_proxy_1 = require("./interception-proxy");
15const invocation_1 = require("./invocation");
16const keys_1 = require("./keys");
17const resolution_session_1 = require("./resolution-session");
18const resolver_1 = require("./resolver");
19const value_promise_1 = require("./value-promise");
20const debug = (0, debug_1.default)('loopback:context:binding');
21/**
22 * Scope for binding values
23 */
24var 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 */
152var 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 */
179function 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 */
189function 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}
197exports.isDynamicValueProviderClass = isDynamicValueProviderClass;
198/**
199 * Binding represents an entry in the `Context`. Each binding has a key and a
200 * corresponding value getter.
201 */
202class 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}
778exports.Binding = Binding;
779function 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
\No newline at end of file