@loopback/context 3.16.0 → 3.18.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/README.md +4 -4
- package/dist/binding-decorator.js +4 -4
- package/dist/binding-decorator.js.map +1 -1
- package/dist/binding-filter.js +1 -1
- package/dist/binding-inspector.js +3 -3
- package/dist/binding-inspector.js.map +1 -1
- package/dist/binding-key.js +1 -1
- package/dist/binding-key.js.map +1 -1
- package/dist/binding.js +12 -12
- package/dist/binding.js.map +1 -1
- package/dist/context-subscription.js +4 -4
- package/dist/context-subscription.js.map +1 -1
- package/dist/context-tag-indexer.js +1 -1
- package/dist/context-tag-indexer.js.map +1 -1
- package/dist/context-view.d.ts +8 -7
- package/dist/context-view.js +23 -14
- package/dist/context-view.js.map +1 -1
- package/dist/context.d.ts +2 -1
- package/dist/context.js +14 -13
- package/dist/context.js.map +1 -1
- package/dist/index.js +26 -26
- package/dist/index.js.map +1 -1
- package/dist/inject-config.js +6 -6
- package/dist/inject-config.js.map +1 -1
- package/dist/inject.d.ts +1 -1
- package/dist/inject.js +9 -9
- package/dist/inject.js.map +1 -1
- package/dist/interception-proxy.d.ts +1 -1
- package/dist/interception-proxy.js +1 -1
- package/dist/interception-proxy.js.map +1 -1
- package/dist/interceptor-chain.js +3 -3
- package/dist/interceptor-chain.js.map +1 -1
- package/dist/interceptor.js +11 -11
- package/dist/interceptor.js.map +1 -1
- package/dist/invocation.js +8 -8
- package/dist/invocation.js.map +1 -1
- package/dist/keys.js.map +1 -1
- package/dist/resolution-session.d.ts +0 -13
- package/dist/resolution-session.js +19 -38
- package/dist/resolution-session.js.map +1 -1
- package/dist/resolver.js +12 -12
- package/dist/resolver.js.map +1 -1
- package/dist/unique-id.js +2 -2
- package/dist/unique-id.js.map +1 -1
- package/dist/value-promise.js +1 -1
- package/dist/value-promise.js.map +1 -1
- package/package.json +14 -14
- package/src/binding-filter.ts +1 -1
- package/src/binding.ts +3 -3
- package/src/context-tag-indexer.ts +2 -4
- package/src/context-view.ts +39 -17
- package/src/context.ts +4 -2
- package/src/inject.ts +33 -31
- package/src/interception-proxy.ts +1 -1
- package/src/interceptor-chain.ts +1 -1
- package/src/interceptor.ts +1 -1
- package/src/keys.ts +4 -3
- package/src/resolution-session.ts +20 -50
- package/src/value-promise.ts +2 -1
- package/CHANGELOG.md +0 -1697
package/src/context-view.ts
CHANGED
|
@@ -14,7 +14,12 @@ import {ContextEvent} from './context-event';
|
|
|
14
14
|
import {ContextEventType, ContextObserver} from './context-observer';
|
|
15
15
|
import {Subscription} from './context-subscription';
|
|
16
16
|
import {Getter} from './inject';
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
asResolutionOptions,
|
|
19
|
+
ResolutionOptions,
|
|
20
|
+
ResolutionOptionsOrSession,
|
|
21
|
+
ResolutionSession,
|
|
22
|
+
} from './resolution-session';
|
|
18
23
|
import {isPromiseLike, resolveList, ValueOrPromise} from './value-promise';
|
|
19
24
|
const debug = debugFactory('loopback:context:view');
|
|
20
25
|
const nextTick = promisify(process.nextTick);
|
|
@@ -47,7 +52,8 @@ export interface ContextViewEvent<T> extends ContextEvent {
|
|
|
47
52
|
*/
|
|
48
53
|
export class ContextView<T = unknown>
|
|
49
54
|
extends EventEmitter
|
|
50
|
-
implements ContextObserver
|
|
55
|
+
implements ContextObserver
|
|
56
|
+
{
|
|
51
57
|
/**
|
|
52
58
|
* An array of cached bindings that matches the binding filter
|
|
53
59
|
*/
|
|
@@ -68,6 +74,7 @@ export class ContextView<T = unknown>
|
|
|
68
74
|
public readonly context: Context,
|
|
69
75
|
public readonly filter: BindingFilter,
|
|
70
76
|
public readonly comparator?: BindingComparator,
|
|
77
|
+
private resolutionOptions?: Omit<ResolutionOptions, 'session'>,
|
|
71
78
|
) {
|
|
72
79
|
super();
|
|
73
80
|
}
|
|
@@ -187,34 +194,41 @@ export class ContextView<T = unknown>
|
|
|
187
194
|
* Resolve values for the matching bindings
|
|
188
195
|
* @param session - Resolution session
|
|
189
196
|
*/
|
|
190
|
-
resolve(session?:
|
|
197
|
+
resolve(session?: ResolutionOptionsOrSession): ValueOrPromise<T[]> {
|
|
191
198
|
debug('Resolving values');
|
|
192
199
|
if (this._cachedValues != null) {
|
|
193
200
|
return this.getCachedValues();
|
|
194
201
|
}
|
|
195
202
|
const bindings = this.bindings;
|
|
196
203
|
let result = resolveList(bindings, b => {
|
|
197
|
-
|
|
204
|
+
const options = {
|
|
205
|
+
...this.resolutionOptions,
|
|
206
|
+
...asResolutionOptions(session),
|
|
207
|
+
};
|
|
208
|
+
options.session = ResolutionSession.fork(options.session);
|
|
209
|
+
return b.getValue(this.context, options);
|
|
198
210
|
});
|
|
199
211
|
if (isPromiseLike(result)) {
|
|
200
212
|
result = result.then(values => {
|
|
201
|
-
|
|
202
|
-
this.
|
|
203
|
-
|
|
213
|
+
const list = values.filter(v => v != null) as T[];
|
|
214
|
+
this.updateCachedValues(list);
|
|
215
|
+
this.emit('resolve', list);
|
|
216
|
+
return list;
|
|
204
217
|
});
|
|
205
218
|
} else {
|
|
206
219
|
// Clone the array so that the cached values won't be mutated
|
|
207
|
-
|
|
208
|
-
this.
|
|
220
|
+
const list = (result = result.filter(v => v != null) as T[]);
|
|
221
|
+
this.updateCachedValues(list);
|
|
222
|
+
this.emit('resolve', list);
|
|
209
223
|
}
|
|
210
|
-
return result
|
|
224
|
+
return result as ValueOrPromise<T[]>;
|
|
211
225
|
}
|
|
212
226
|
|
|
213
227
|
/**
|
|
214
228
|
* Get the list of resolved values. If they are not cached, it tries to find
|
|
215
229
|
* and resolve them.
|
|
216
230
|
*/
|
|
217
|
-
async values(session?:
|
|
231
|
+
async values(session?: ResolutionOptionsOrSession): Promise<T[]> {
|
|
218
232
|
debug('Reading values');
|
|
219
233
|
// Wait for the next tick so that context event notification can be emitted
|
|
220
234
|
await nextTick();
|
|
@@ -227,14 +241,16 @@ export class ContextView<T = unknown>
|
|
|
227
241
|
/**
|
|
228
242
|
* As a `Getter` function
|
|
229
243
|
*/
|
|
230
|
-
asGetter(session?:
|
|
244
|
+
asGetter(session?: ResolutionOptionsOrSession): Getter<T[]> {
|
|
231
245
|
return () => this.values(session);
|
|
232
246
|
}
|
|
233
247
|
|
|
234
248
|
/**
|
|
235
249
|
* Get the single value
|
|
236
250
|
*/
|
|
237
|
-
async singleValue(
|
|
251
|
+
async singleValue(
|
|
252
|
+
session?: ResolutionOptionsOrSession,
|
|
253
|
+
): Promise<T | undefined> {
|
|
238
254
|
const values = await this.values(session);
|
|
239
255
|
if (values.length === 0) return undefined;
|
|
240
256
|
if (values.length === 1) return values[0];
|
|
@@ -388,7 +404,7 @@ export function createViewGetter<T = unknown>(
|
|
|
388
404
|
ctx: Context,
|
|
389
405
|
bindingFilter: BindingFilter,
|
|
390
406
|
bindingComparator?: BindingComparator,
|
|
391
|
-
session?:
|
|
407
|
+
session?: ResolutionOptionsOrSession,
|
|
392
408
|
): Getter<T[]>;
|
|
393
409
|
|
|
394
410
|
/**
|
|
@@ -403,7 +419,7 @@ export function createViewGetter<T = unknown>(
|
|
|
403
419
|
ctx: Context,
|
|
404
420
|
bindingFilter: BindingFilter,
|
|
405
421
|
bindingComparatorOrSession?: BindingComparator | ResolutionSession,
|
|
406
|
-
session?:
|
|
422
|
+
session?: ResolutionOptionsOrSession,
|
|
407
423
|
): Getter<T[]> {
|
|
408
424
|
let bindingComparator: BindingComparator | undefined = undefined;
|
|
409
425
|
if (typeof bindingComparatorOrSession === 'function') {
|
|
@@ -412,7 +428,13 @@ export function createViewGetter<T = unknown>(
|
|
|
412
428
|
session = bindingComparatorOrSession;
|
|
413
429
|
}
|
|
414
430
|
|
|
415
|
-
const
|
|
431
|
+
const options = asResolutionOptions(session);
|
|
432
|
+
const view = new ContextView<T>(
|
|
433
|
+
ctx,
|
|
434
|
+
bindingFilter,
|
|
435
|
+
bindingComparator,
|
|
436
|
+
options,
|
|
437
|
+
);
|
|
416
438
|
view.open();
|
|
417
|
-
return view.asGetter(
|
|
439
|
+
return view.asGetter(options);
|
|
418
440
|
}
|
package/src/context.ts
CHANGED
|
@@ -128,7 +128,7 @@ export class Context extends EventEmitter {
|
|
|
128
128
|
// The number of listeners can grow with the number of child contexts
|
|
129
129
|
// For example, each request can add a listener to the RestServer and the
|
|
130
130
|
// listener is removed when the request processing is finished.
|
|
131
|
-
// See https://github.com/
|
|
131
|
+
// See https://github.com/loopbackio/loopback-next/issues/4363
|
|
132
132
|
this.setMaxListeners(Infinity);
|
|
133
133
|
if (typeof _parent === 'string') {
|
|
134
134
|
name = _parent;
|
|
@@ -441,12 +441,14 @@ export class Context extends EventEmitter {
|
|
|
441
441
|
* Create a view of the context chain with the given binding filter
|
|
442
442
|
* @param filter - A function to match bindings
|
|
443
443
|
* @param comparator - A function to sort matched bindings
|
|
444
|
+
* @param options - Resolution options
|
|
444
445
|
*/
|
|
445
446
|
createView<T = unknown>(
|
|
446
447
|
filter: BindingFilter,
|
|
447
448
|
comparator?: BindingComparator,
|
|
449
|
+
options?: Omit<ResolutionOptions, 'session'>,
|
|
448
450
|
) {
|
|
449
|
-
const view = new ContextView<T>(this, filter, comparator);
|
|
451
|
+
const view = new ContextView<T>(this, filter, comparator, options);
|
|
450
452
|
view.open();
|
|
451
453
|
return view;
|
|
452
454
|
}
|
package/src/inject.ts
CHANGED
|
@@ -67,7 +67,7 @@ export interface ResolverFunction {
|
|
|
67
67
|
/**
|
|
68
68
|
* An object to provide metadata for `@inject`
|
|
69
69
|
*/
|
|
70
|
-
export interface InjectionMetadata extends ResolutionOptions {
|
|
70
|
+
export interface InjectionMetadata extends Omit<ResolutionOptions, 'session'> {
|
|
71
71
|
/**
|
|
72
72
|
* Name of the decorator function, such as `@inject` or `@inject.setter`.
|
|
73
73
|
* It's usually set by the decorator implementation.
|
|
@@ -152,20 +152,21 @@ export function inject(
|
|
|
152
152
|
if (typeof methodDescriptorOrParameterIndex === 'number') {
|
|
153
153
|
// The decorator is applied to a method parameter
|
|
154
154
|
// Please note propertyKey is `undefined` for constructor
|
|
155
|
-
const paramDecorator: ParameterDecorator =
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
155
|
+
const paramDecorator: ParameterDecorator =
|
|
156
|
+
ParameterDecoratorFactory.createDecorator<Injection>(
|
|
157
|
+
INJECT_PARAMETERS_KEY,
|
|
158
|
+
{
|
|
159
|
+
target,
|
|
160
|
+
member,
|
|
161
|
+
methodDescriptorOrParameterIndex,
|
|
162
|
+
bindingSelector,
|
|
163
|
+
metadata: injectionMetadata,
|
|
164
|
+
resolve,
|
|
165
|
+
},
|
|
166
|
+
// Do not deep clone the spec as only metadata is mutable and it's
|
|
167
|
+
// shallowly cloned
|
|
168
|
+
{cloneInputSpec: false, decoratorName: injectionMetadata.decorator},
|
|
169
|
+
);
|
|
169
170
|
paramDecorator(target, member!, methodDescriptorOrParameterIndex);
|
|
170
171
|
} else if (member) {
|
|
171
172
|
// Property or method
|
|
@@ -186,20 +187,21 @@ export function inject(
|
|
|
186
187
|
),
|
|
187
188
|
);
|
|
188
189
|
}
|
|
189
|
-
const propDecorator: PropertyDecorator =
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
190
|
+
const propDecorator: PropertyDecorator =
|
|
191
|
+
PropertyDecoratorFactory.createDecorator<Injection>(
|
|
192
|
+
INJECT_PROPERTIES_KEY,
|
|
193
|
+
{
|
|
194
|
+
target,
|
|
195
|
+
member,
|
|
196
|
+
methodDescriptorOrParameterIndex,
|
|
197
|
+
bindingSelector,
|
|
198
|
+
metadata: injectionMetadata,
|
|
199
|
+
resolve,
|
|
200
|
+
},
|
|
201
|
+
// Do not deep clone the spec as only metadata is mutable and it's
|
|
202
|
+
// shallowly cloned
|
|
203
|
+
{cloneInputSpec: false, decoratorName: injectionMetadata.decorator},
|
|
204
|
+
);
|
|
203
205
|
propDecorator(target, member!);
|
|
204
206
|
} else {
|
|
205
207
|
// It won't happen here as `@inject` is not compatible with ClassDecorator
|
|
@@ -508,7 +510,7 @@ function shouldSkipBaseConstructorInjection(targetClass: Object) {
|
|
|
508
510
|
const classDef = targetClass.toString();
|
|
509
511
|
return (
|
|
510
512
|
/*
|
|
511
|
-
* See https://github.com/
|
|
513
|
+
* See https://github.com/loopbackio/loopback-next/issues/2946
|
|
512
514
|
* A class decorator can return a new constructor that mixes in
|
|
513
515
|
* additional properties/methods.
|
|
514
516
|
*
|
|
@@ -537,7 +539,7 @@ function shouldSkipBaseConstructorInjection(targetClass: Object) {
|
|
|
537
539
|
/\s+constructor\s*\(\s*\)\s*\{\s*super\(\.\.\.arguments\)/,
|
|
538
540
|
) &&
|
|
539
541
|
/*
|
|
540
|
-
* See https://github.com/
|
|
542
|
+
* See https://github.com/loopbackio/loopback-next/issues/1565
|
|
541
543
|
*
|
|
542
544
|
* @example
|
|
543
545
|
* ```ts
|
|
@@ -24,7 +24,7 @@ export type AsValueOrPromise<T> = T extends Promise<unknown>
|
|
|
24
24
|
export type AsInterceptedFunction<T> = T extends (
|
|
25
25
|
...args: InvocationArgs
|
|
26
26
|
) => infer R
|
|
27
|
-
? (...args:
|
|
27
|
+
? (...args: Parameters<T>) => AsValueOrPromise<R>
|
|
28
28
|
: T;
|
|
29
29
|
|
|
30
30
|
/**
|
package/src/interceptor-chain.ts
CHANGED
|
@@ -242,7 +242,7 @@ export class GenericInterceptorChain<C extends Context = Context> {
|
|
|
242
242
|
*/
|
|
243
243
|
export function invokeInterceptors<
|
|
244
244
|
C extends Context = Context,
|
|
245
|
-
T = InvocationResult
|
|
245
|
+
T = InvocationResult,
|
|
246
246
|
>(
|
|
247
247
|
context: C,
|
|
248
248
|
interceptors: GenericInterceptorOrKey<C>[],
|
package/src/interceptor.ts
CHANGED
|
@@ -287,7 +287,7 @@ export function intercept(...interceptorOrKeys: InterceptorOrKey[]) {
|
|
|
287
287
|
target: any,
|
|
288
288
|
method?: string,
|
|
289
289
|
// Use `any` to for `TypedPropertyDescriptor`
|
|
290
|
-
// See https://github.com/
|
|
290
|
+
// See https://github.com/loopbackio/loopback-next/pull/2704
|
|
291
291
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
292
292
|
methodDescriptor?: TypedPropertyDescriptor<any>,
|
|
293
293
|
) {
|
package/src/keys.ts
CHANGED
|
@@ -71,9 +71,10 @@ export namespace ContextBindings {
|
|
|
71
71
|
/**
|
|
72
72
|
* Binding key for ConfigurationResolver
|
|
73
73
|
*/
|
|
74
|
-
export const CONFIGURATION_RESOLVER =
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
export const CONFIGURATION_RESOLVER =
|
|
75
|
+
BindingKey.create<ConfigurationResolver>(
|
|
76
|
+
`${BindingKey.CONFIG_NAMESPACE}.resolver`,
|
|
77
|
+
);
|
|
77
78
|
|
|
78
79
|
/**
|
|
79
80
|
* Binding key for ordered groups of global interceptors
|
|
@@ -92,20 +92,6 @@ export class ResolutionSession {
|
|
|
92
92
|
return copy;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
/**
|
|
96
|
-
* Start to resolve a binding within the session
|
|
97
|
-
* @param binding - The current binding
|
|
98
|
-
* @param session - The current resolution session
|
|
99
|
-
*/
|
|
100
|
-
private static enterBinding(
|
|
101
|
-
binding: Readonly<Binding>,
|
|
102
|
-
session?: ResolutionSession,
|
|
103
|
-
): ResolutionSession {
|
|
104
|
-
session = session ?? new ResolutionSession();
|
|
105
|
-
session.pushBinding(binding);
|
|
106
|
-
return session;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
95
|
/**
|
|
110
96
|
* Run the given action with the given binding and session
|
|
111
97
|
* @param action - A function to do some work with the resolution session
|
|
@@ -115,29 +101,16 @@ export class ResolutionSession {
|
|
|
115
101
|
static runWithBinding(
|
|
116
102
|
action: ResolutionAction,
|
|
117
103
|
binding: Readonly<Binding>,
|
|
118
|
-
session
|
|
104
|
+
session = new ResolutionSession(),
|
|
119
105
|
) {
|
|
120
|
-
|
|
106
|
+
// Start to resolve a binding within the session
|
|
107
|
+
session.pushBinding(binding);
|
|
121
108
|
return tryWithFinally(
|
|
122
|
-
() => action(
|
|
123
|
-
() =>
|
|
109
|
+
() => action(session),
|
|
110
|
+
() => session.popBinding(),
|
|
124
111
|
);
|
|
125
112
|
}
|
|
126
113
|
|
|
127
|
-
/**
|
|
128
|
-
* Push an injection into the session
|
|
129
|
-
* @param injection - The current injection
|
|
130
|
-
* @param session - The current resolution session
|
|
131
|
-
*/
|
|
132
|
-
private static enterInjection(
|
|
133
|
-
injection: Readonly<Injection>,
|
|
134
|
-
session?: ResolutionSession,
|
|
135
|
-
): ResolutionSession {
|
|
136
|
-
session = session ?? new ResolutionSession();
|
|
137
|
-
session.pushInjection(injection);
|
|
138
|
-
return session;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
114
|
/**
|
|
142
115
|
* Run the given action with the given injection and session
|
|
143
116
|
* @param action - A function to do some work with the resolution session
|
|
@@ -147,15 +120,12 @@ export class ResolutionSession {
|
|
|
147
120
|
static runWithInjection(
|
|
148
121
|
action: ResolutionAction,
|
|
149
122
|
injection: Readonly<Injection>,
|
|
150
|
-
session
|
|
123
|
+
session = new ResolutionSession(),
|
|
151
124
|
) {
|
|
152
|
-
|
|
153
|
-
injection,
|
|
154
|
-
session,
|
|
155
|
-
);
|
|
125
|
+
session.pushInjection(injection);
|
|
156
126
|
return tryWithFinally(
|
|
157
|
-
() => action(
|
|
158
|
-
() =>
|
|
127
|
+
() => action(session),
|
|
128
|
+
() => session.popInjection(),
|
|
159
129
|
);
|
|
160
130
|
}
|
|
161
131
|
|
|
@@ -299,7 +269,7 @@ export class ResolutionSession {
|
|
|
299
269
|
* Get the binding path as `bindingA --> bindingB --> bindingC`.
|
|
300
270
|
*/
|
|
301
271
|
getBindingPath() {
|
|
302
|
-
return this.
|
|
272
|
+
return this.stack.filter(isBinding).map(describe).join(' --> ');
|
|
303
273
|
}
|
|
304
274
|
|
|
305
275
|
/**
|
|
@@ -311,22 +281,13 @@ export class ResolutionSession {
|
|
|
311
281
|
.join(' --> ');
|
|
312
282
|
}
|
|
313
283
|
|
|
314
|
-
private static describe(e: ResolutionElement) {
|
|
315
|
-
switch (e.type) {
|
|
316
|
-
case 'injection':
|
|
317
|
-
return '@' + ResolutionSession.describeInjection(e.value).targetName;
|
|
318
|
-
case 'binding':
|
|
319
|
-
return e.value.key;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
284
|
/**
|
|
324
285
|
* Get the resolution path including bindings and injections, for example:
|
|
325
286
|
* `bindingA --> @ClassA[0] --> bindingB --> @ClassB.prototype.prop1
|
|
326
287
|
* --> bindingC`.
|
|
327
288
|
*/
|
|
328
289
|
getResolutionPath() {
|
|
329
|
-
return this.stack.map(
|
|
290
|
+
return this.stack.map(describe).join(' --> ');
|
|
330
291
|
}
|
|
331
292
|
|
|
332
293
|
toString() {
|
|
@@ -334,6 +295,15 @@ export class ResolutionSession {
|
|
|
334
295
|
}
|
|
335
296
|
}
|
|
336
297
|
|
|
298
|
+
function describe(e: ResolutionElement) {
|
|
299
|
+
switch (e.type) {
|
|
300
|
+
case 'injection':
|
|
301
|
+
return '@' + ResolutionSession.describeInjection(e.value).targetName;
|
|
302
|
+
case 'binding':
|
|
303
|
+
return e.value.key;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
337
307
|
/**
|
|
338
308
|
* Options for binding/dependency resolution
|
|
339
309
|
*/
|
package/src/value-promise.ts
CHANGED
|
@@ -314,4 +314,5 @@ export function uuid() {
|
|
|
314
314
|
* @deprecated This pattern is an internal helper used by unit-tests, we are no
|
|
315
315
|
* longer using it.
|
|
316
316
|
*/
|
|
317
|
-
export const UUID_PATTERN =
|
|
317
|
+
export const UUID_PATTERN =
|
|
318
|
+
/[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}/i;
|