@nmtjs/core 0.16.1 → 0.17.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +41 -1
  3. package/dist/container.d.ts +1 -1
  4. package/dist/container.js +3 -5
  5. package/dist/container.js.map +1 -1
  6. package/dist/execution-environment.d.ts +15 -0
  7. package/dist/execution-environment.js +30 -0
  8. package/dist/execution-environment.js.map +1 -0
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.js +1 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/injectables.d.ts +13 -5
  13. package/dist/injectables.js +16 -6
  14. package/dist/injectables.js.map +1 -1
  15. package/dist/logger.d.ts +2 -1
  16. package/dist/logger.js +15 -7
  17. package/dist/logger.js.map +1 -1
  18. package/dist/metadata.d.ts +4 -6
  19. package/dist/metadata.js +2 -3
  20. package/dist/metadata.js.map +1 -1
  21. package/package.json +6 -9
  22. package/src/container.ts +3 -7
  23. package/src/execution-environment.ts +50 -0
  24. package/src/index.ts +1 -1
  25. package/src/injectables.ts +60 -13
  26. package/src/logger.ts +24 -9
  27. package/src/metadata.ts +11 -32
  28. package/dist/utils/functions.d.ts +0 -7
  29. package/dist/utils/functions.js +0 -18
  30. package/dist/utils/functions.js.map +0 -1
  31. package/dist/utils/index.d.ts +0 -3
  32. package/dist/utils/index.js +0 -4
  33. package/dist/utils/index.js.map +0 -1
  34. package/dist/utils/pool.d.ts +0 -18
  35. package/dist/utils/pool.js +0 -106
  36. package/dist/utils/pool.js.map +0 -1
  37. package/dist/utils/semaphore.d.ts +0 -13
  38. package/dist/utils/semaphore.js +0 -56
  39. package/dist/utils/semaphore.js.map +0 -1
  40. package/src/utils/functions.ts +0 -31
  41. package/src/utils/index.ts +0 -3
  42. package/src/utils/pool.ts +0 -111
  43. package/src/utils/semaphore.ts +0 -63
package/src/container.ts CHANGED
@@ -122,7 +122,7 @@ export class Container {
122
122
  this.disposing = false
123
123
  }
124
124
 
125
- containsWithinSelf(injectable: AnyInjectable) {
125
+ owns(injectable: AnyInjectable) {
126
126
  return (
127
127
  this.provisions.has(injectable) ||
128
128
  this.instances.has(injectable) ||
@@ -131,10 +131,7 @@ export class Container {
131
131
  }
132
132
 
133
133
  contains(injectable: AnyInjectable): boolean {
134
- return (
135
- this.containsWithinSelf(injectable) ||
136
- (this.parent?.contains(injectable) ?? false)
137
- )
134
+ return this.owns(injectable) || (this.parent?.contains(injectable) ?? false)
138
135
  }
139
136
 
140
137
  get<T extends AnyInjectable>(injectable: T): ResolveInjectableType<T> {
@@ -342,7 +339,6 @@ export class Container {
342
339
  ).finally(() => {
343
340
  this.resolvers.delete(injectable)
344
341
 
345
- // biome-ignore lint: false
346
342
  // @ts-ignore
347
343
  if (measurements && measure) measurements.push(measure)
348
344
  })
@@ -372,7 +368,7 @@ export class Container {
372
368
  }
373
369
  if (isFactoryInjectable(injectable)) {
374
370
  wrapper.private = await Promise.resolve(
375
- injectable.factory(wrapper.context),
371
+ injectable.create(wrapper.context),
376
372
  )
377
373
  wrapper.public = injectable.pick(wrapper.private)
378
374
  } else {
@@ -0,0 +1,50 @@
1
+ import type { Container } from './container.ts'
2
+ import type { AnyInjectable, Dependant } from './injectables.ts'
3
+ import type { Logger } from './logger.ts'
4
+ import { Container as CoreContainer } from './container.ts'
5
+ import { Scope } from './enums.ts'
6
+ import {
7
+ CoreInjectables,
8
+ getDepedencencyInjectable,
9
+ provision,
10
+ } from './injectables.ts'
11
+ import { forkLogger } from './logger.ts'
12
+
13
+ export type ExecutionEnvironmentOptions = {
14
+ logger: Logger
15
+ container?: Container
16
+ label?: string
17
+ }
18
+
19
+ export class ExecutionEnvironment {
20
+ readonly logger: Logger
21
+ readonly container: Container
22
+
23
+ constructor(options: ExecutionEnvironmentOptions) {
24
+ this.logger = options.label
25
+ ? forkLogger(options.logger, options.label)
26
+ : options.logger
27
+
28
+ this.container = options.container
29
+ ? options.container.fork(Scope.Global)
30
+ : new CoreContainer({ logger: this.logger })
31
+
32
+ this.container.provide([provision(CoreInjectables.logger, this.logger)])
33
+ }
34
+
35
+ async initialize(dependants: Iterable<Dependant> = []): Promise<void> {
36
+ const dependencies = new Set<AnyInjectable>()
37
+
38
+ for (const dependant of dependants) {
39
+ for (const dependency of Object.values(dependant.dependencies)) {
40
+ dependencies.add(getDepedencencyInjectable(dependency))
41
+ }
42
+ }
43
+
44
+ await this.container.initialize(dependencies)
45
+ }
46
+
47
+ async dispose(): Promise<void> {
48
+ await this.container.dispose()
49
+ }
50
+ }
package/src/index.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  export * from './constants.ts'
2
2
  export * from './container.ts'
3
3
  export * from './enums.ts'
4
+ export * from './execution-environment.ts'
4
5
  export * from './hooks.ts'
5
6
  export * from './injectables.ts'
6
7
  export * from './logger.ts'
7
8
  export * from './metadata.ts'
8
9
  export * from './plugin.ts'
9
10
  export * from './types.ts'
10
- export * from './utils/index.ts'
@@ -11,6 +11,7 @@ import {
11
11
  kValueInjectable,
12
12
  } from './constants.ts'
13
13
  import { Scope } from './enums.ts'
14
+ import { forkLogger } from './logger.ts'
14
15
 
15
16
  const ScopeStrictness = {
16
17
  [Scope.Transient]: Number.NaN, // this should make it always fail to compare with other scopes
@@ -57,6 +58,46 @@ export type DependencyContext<Deps extends Dependencies> = {
57
58
  : never
58
59
  }
59
60
 
61
+ export type HandlerFn<
62
+ Deps extends Dependencies,
63
+ Args extends readonly unknown[],
64
+ Return,
65
+ > = (context: DependencyContext<Deps>, ...args: Args) => MaybePromise<Return>
66
+
67
+ export interface Handler<
68
+ Deps extends Dependencies,
69
+ Args extends readonly unknown[],
70
+ Return,
71
+ > extends Dependant<Deps> {
72
+ handler: HandlerFn<Deps, Args, Return>
73
+ }
74
+
75
+ export type HandlerInput<
76
+ Deps extends Dependencies,
77
+ Args extends readonly unknown[],
78
+ Return,
79
+ > =
80
+ | HandlerFn<{}, Args, Return>
81
+ | {
82
+ dependencies?: Deps
83
+ handler: HandlerFn<Deps, Args, Return>
84
+ }
85
+
86
+ export function createHandler<
87
+ Args extends readonly unknown[],
88
+ Return,
89
+ Deps extends Dependencies = {},
90
+ >(
91
+ paramsOrHandler: HandlerInput<Deps, Args, Return>,
92
+ ): Handler<Deps, Args, Return> {
93
+ const { dependencies = {} as Deps, handler } =
94
+ typeof paramsOrHandler === 'function'
95
+ ? { handler: paramsOrHandler }
96
+ : paramsOrHandler
97
+
98
+ return Object.freeze({ dependencies, handler }) as Handler<Deps, Args, Return>
99
+ }
100
+
60
101
  export type InjectableFactoryType<
61
102
  InjectableType,
62
103
  InjectableDeps extends Dependencies,
@@ -72,11 +113,12 @@ export type InjectableDisposeType<
72
113
  context: DependencyContext<InjectableDeps>,
73
114
  ) => any
74
115
 
75
- export interface LazyInjectable<T, S extends Scope = Scope.Global>
76
- extends Dependant<{}> {
116
+ export interface LazyInjectable<
117
+ T,
118
+ S extends Scope = Scope.Global,
119
+ > extends Dependant<{}> {
77
120
  scope: S
78
121
  $withType<O extends T>(): LazyInjectable<O, S>
79
- optional(): DependencyOptional<LazyInjectable<T, S>>
80
122
  [kInjectable]: any
81
123
  [kLazyInjectable]: T
82
124
  }
@@ -95,10 +137,9 @@ export interface FactoryInjectable<
95
137
  P = T,
96
138
  > extends Dependant<D> {
97
139
  scope: S
98
- factory: InjectableFactoryType<P, D>
140
+ create: InjectableFactoryType<P, D>
99
141
  pick: InjectablePickType<P, T>
100
142
  dispose?: InjectableDisposeType<P, D>
101
- optional(): DependencyOptional<FactoryInjectable<T, D, S, P>>
102
143
  [kInjectable]: any
103
144
  [kFactoryInjectable]: any
104
145
  }
@@ -162,7 +203,7 @@ export function getDepedencencyInjectable(
162
203
  return dependency
163
204
  }
164
205
 
165
- export function createOptionalInjectable<T extends AnyInjectable>(
206
+ export function createOptionalInjectable<T extends LazyInjectable<any, any>>(
166
207
  injectable: T,
167
208
  ) {
168
209
  return Object.freeze({
@@ -171,6 +212,15 @@ export function createOptionalInjectable<T extends AnyInjectable>(
171
212
  }) as DependencyOptional<T>
172
213
  }
173
214
 
215
+ export function optional<T, S extends Scope>(
216
+ injectable: LazyInjectable<T, S>,
217
+ ): DependencyOptional<LazyInjectable<T, S>> {
218
+ if (!isLazyInjectable(injectable)) {
219
+ throw new TypeError('Optional dependencies can only wrap lazy injectables')
220
+ }
221
+ return createOptionalInjectable(injectable)
222
+ }
223
+
174
224
  export function createLazyInjectable<T, S extends Scope = Scope.Global>(
175
225
  scope = Scope.Global as S,
176
226
  label?: string,
@@ -181,7 +231,6 @@ export function createLazyInjectable<T, S extends Scope = Scope.Global>(
181
231
  dependencies: {},
182
232
  label,
183
233
  stack: tryCaptureStackTrace(stackTraceDepth),
184
- optional: () => createOptionalInjectable(injectable),
185
234
  $withType: () => injectable as any,
186
235
  [kInjectable]: true,
187
236
  [kLazyInjectable]: true as unknown as T,
@@ -216,7 +265,7 @@ export function createFactoryInjectable<
216
265
  dependencies?: D
217
266
  scope?: S
218
267
  pick?: InjectablePickType<P, T>
219
- factory: InjectableFactoryType<P, D>
268
+ create: InjectableFactoryType<P, D>
220
269
  dispose?: InjectableDisposeType<P, D>
221
270
  }
222
271
  | InjectableFactoryType<P, D>,
@@ -224,16 +273,15 @@ export function createFactoryInjectable<
224
273
  stackTraceDepth = 0,
225
274
  ): FactoryInjectable<null extends T ? P : T, D, S, P> {
226
275
  const isFactory = typeof paramsOrFactory === 'function'
227
- const params = isFactory ? { factory: paramsOrFactory } : paramsOrFactory
276
+ const params = isFactory ? { create: paramsOrFactory } : paramsOrFactory
228
277
  const injectable = {
229
278
  dependencies: (params.dependencies ?? {}) as D,
230
279
  scope: (params.scope ?? Scope.Global) as S,
231
- factory: params.factory,
280
+ create: params.create,
232
281
  dispose: params.dispose,
233
282
  pick: params.pick ?? ((instance: P) => instance as unknown as T),
234
283
  label,
235
284
  stack: tryCaptureStackTrace(stackTraceDepth),
236
- optional: () => createOptionalInjectable(injectable),
237
285
  [kInjectable]: true,
238
286
  [kFactoryInjectable]: true,
239
287
  }
@@ -308,11 +356,10 @@ export function compareScope(
308
356
 
309
357
  const loggerInjectable = Object.assign(
310
358
  (label: string | undefined, options?: ChildLoggerOptions) => {
311
- const bindings = label ? { $label: label } : {}
312
359
  return createFactoryInjectable({
313
360
  dependencies: { logger: loggerInjectable },
314
361
  scope: Scope.Global,
315
- factory: ({ logger }) => logger.child(bindings, options),
362
+ create: ({ logger }) => forkLogger(logger, label, options),
316
363
  })
317
364
  },
318
365
  createLazyInjectable<Logger>(Scope.Global, 'Logger'),
package/src/logger.ts CHANGED
@@ -2,6 +2,7 @@ import { AsyncLocalStorage } from 'node:async_hooks'
2
2
  import { threadId } from 'node:worker_threads'
3
3
 
4
4
  import type {
5
+ Bindings,
5
6
  ChildLoggerOptions,
6
7
  DestinationStream,
7
8
  Level,
@@ -52,13 +53,12 @@ export const loggerLocalStorage = new AsyncLocalStorage<object | undefined>({
52
53
  })
53
54
 
54
55
  export const createLogger = (options: LoggingOptions = {}, $label: string) => {
55
- let { destinations, pinoOptions } = options
56
+ let { destinations } = options
57
+ const { pinoOptions } = options
56
58
 
57
- if (!destinations || !destinations?.length) {
59
+ if (!destinations?.length) {
58
60
  destinations = [
59
- createConsolePrettyDestination(
60
- (options.pinoOptions?.level || 'info') as Level,
61
- ),
61
+ createConsolePrettyDestination((pinoOptions?.level || 'info') as Level),
62
62
  ]
63
63
  }
64
64
 
@@ -101,9 +101,21 @@ export const createLogger = (options: LoggingOptions = {}, $label: string) => {
101
101
  return object
102
102
  },
103
103
  },
104
+ base: { $label, $threadId: threadId },
104
105
  },
105
106
  multistream(destinations!),
106
- ).child({ $label, $threadId: threadId })
107
+ )
108
+ }
109
+
110
+ export const forkLogger = (
111
+ logger: Logger,
112
+ label: string | undefined,
113
+ options?: ChildLoggerOptions,
114
+ bindings?: Bindings,
115
+ ) => {
116
+ const _bindings = { ...bindings }
117
+ if (label !== undefined) _bindings.$label = label
118
+ return logger.child(_bindings, options)
107
119
  }
108
120
 
109
121
  export type CreateConsolePrettyDestination = (
@@ -121,9 +133,12 @@ export const createConsolePrettyDestination: CreateConsolePrettyDestination = (
121
133
  ignore: 'hostname,$label,$threadId',
122
134
  errorLikeObjectKeys: ['err', 'error', 'cause'],
123
135
  messageFormat: (log, messageKey) => {
124
- const group = fg(`[${log.$label}]`, 11)
125
- const msg = fg(log[messageKey], messageColors[log.level as number])
126
- const thread = fg(`(Thread-${log.$threadId})`, 89)
136
+ const group = fg(`[${String(log.$label)}]`, 11)
137
+ const msg = fg(
138
+ String(log[messageKey]),
139
+ messageColors[log.level as number],
140
+ )
141
+ const thread = fg(`(T-${String(log.$threadId)})`, 89)
127
142
  return `\x1b[0m${thread} ${group} ${msg}`
128
143
  },
129
144
  customPrettifiers: {
package/src/metadata.ts CHANGED
@@ -1,18 +1,14 @@
1
- import type { MaybePromise } from '@nmtjs/common'
2
-
3
1
  import type {
4
2
  Dependant,
5
3
  Dependencies,
6
- DependencyContext,
4
+ Handler,
5
+ HandlerFn,
7
6
  LazyInjectable,
8
7
  ResolveInjectableType,
9
8
  } from './injectables.ts'
10
9
  import { kMetaBinding, kMetadata } from './constants.ts'
11
10
  import { Scope } from './enums.ts'
12
- import {
13
- createLazyInjectable,
14
- createOptionalInjectable,
15
- } from './injectables.ts'
11
+ import { createLazyInjectable } from './injectables.ts'
16
12
 
17
13
  export enum MetadataKind {
18
14
  STATIC = 'STATIC',
@@ -55,8 +51,7 @@ type MetaBindingToken<T extends AnyMeta = AnyMeta> = {
55
51
  }
56
52
 
57
53
  export interface StaticMetaBinding<T extends AnyMeta = AnyMeta>
58
- extends Dependant<{}>,
59
- MetaBindingToken<T> {
54
+ extends Dependant<{}>, MetaBindingToken<T> {
60
55
  readonly kind: MetadataKind.STATIC
61
56
  readonly value: ResolveInjectableType<T>
62
57
  }
@@ -67,15 +62,12 @@ export interface MetaFactoryBinding<
67
62
  Phase extends MetaPhase = MetaPhase,
68
63
  Call = unknown,
69
64
  Input = unknown,
70
- > extends Dependant<Deps>,
65
+ >
66
+ extends
67
+ Handler<Deps, [call: Call, input: Input], ResolveInjectableType<T>>,
71
68
  MetaBindingToken<T> {
72
69
  readonly kind: MetadataKind.FACTORY
73
70
  readonly phase: Phase
74
- readonly resolve: (
75
- context: DependencyContext<Deps>,
76
- call: Call,
77
- input: Input,
78
- ) => MaybePromise<ResolveInjectableType<T>>
79
71
  }
80
72
 
81
73
  export type BeforeDecodeMetaBinding<
@@ -107,20 +99,12 @@ export type MetaFactoryMethod<Value, Call = unknown> = {
107
99
  <Deps extends Dependencies = {}>(params: {
108
100
  dependencies?: Deps
109
101
  phase?: 'beforeDecode'
110
- resolve: (
111
- context: DependencyContext<Deps>,
112
- call: Call,
113
- payload: unknown,
114
- ) => MaybePromise<Value>
102
+ handler: HandlerFn<Deps, [call: Call, payload: unknown], Value>
115
103
  }): BeforeDecodeMetaBinding<MetaToken<Value>, Deps, Call>
116
104
  <Deps extends Dependencies = {}, Input = unknown>(params: {
117
105
  dependencies?: Deps
118
106
  phase: 'afterDecode'
119
- resolve: (
120
- context: DependencyContext<Deps>,
121
- call: Call,
122
- input: Input,
123
- ) => MaybePromise<Value>
107
+ handler: HandlerFn<Deps, [call: Call, input: Input], Value>
124
108
  }): AfterDecodeMetaBinding<MetaToken<Value>, Deps, Call, Input>
125
109
  }
126
110
 
@@ -153,7 +137,6 @@ export function createMeta<
153
137
  ...injectable,
154
138
  [kMetadata]: true as const,
155
139
  $withType: () => meta as any,
156
- optional: () => createOptionalInjectable(meta),
157
140
  static: (value: Value) =>
158
141
  Object.freeze({
159
142
  dependencies: {},
@@ -164,17 +147,13 @@ export function createMeta<
164
147
  factory: ((params: {
165
148
  dependencies?: Dependencies
166
149
  phase?: MetaPhase
167
- resolve: (
168
- context: DependencyContext<any>,
169
- call: Call,
170
- input: unknown,
171
- ) => unknown
150
+ handler: HandlerFn<any, [call: Call, input: unknown], unknown>
172
151
  }) => {
173
152
  return Object.freeze({
174
153
  dependencies: params.dependencies ?? {},
154
+ handler: params.handler,
175
155
  kind: MetadataKind.FACTORY,
176
156
  phase: params.phase ?? 'beforeDecode',
177
- resolve: params.resolve,
178
157
  [kMetaBinding]: meta,
179
158
  })
180
159
  }) as MetaFactoryMethod<Value, Call>,
@@ -1,7 +0,0 @@
1
- export { match } from '@nmtjs/common';
2
- export declare function isJsFile(name: string): boolean;
3
- export declare function pick<T extends object, K extends {
4
- [KK in keyof T as T[KK] extends (...args: any[]) => any ? never : KK]?: true;
5
- }>(obj: T, keys: K): Pick<T, keyof {
6
- [KK in keyof K as K[KK] extends true ? KK : never]: K[KK];
7
- }>;
@@ -1,18 +0,0 @@
1
- export { match } from '@nmtjs/common';
2
- export function isJsFile(name) {
3
- if (name.endsWith('.d.ts'))
4
- return false;
5
- const leading = name.split('.').slice(1);
6
- const ext = leading.join('.');
7
- return ['js', 'mjs', 'cjs', 'ts', 'mts', 'cts'].includes(ext);
8
- }
9
- export function pick(obj, keys) {
10
- const result = {};
11
- for (const key in keys) {
12
- if (key in obj) {
13
- result[key] = obj[key];
14
- }
15
- }
16
- return result;
17
- }
18
- //# sourceMappingURL=functions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"functions.js","sourceRoot":"","sources":["../../src/utils/functions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAErC,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAA;IACxC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACxC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC7B,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;AAC/D,CAAC;AAED,MAAM,UAAU,IAAI,CAMlB,GAAM,EACN,IAAO;IAOP,MAAM,MAAM,GAAG,EAAS,CAAA;IACxB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;YACf,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAkC,CAAC,CAAA;QACvD,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -1,3 +0,0 @@
1
- export * from './functions.ts';
2
- export * from './pool.ts';
3
- export * from './semaphore.ts';
@@ -1,4 +0,0 @@
1
- export * from './functions.js';
2
- export * from './pool.js';
3
- export * from './semaphore.js';
4
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA"}
@@ -1,18 +0,0 @@
1
- interface PoolOptions {
2
- timeout?: number;
3
- }
4
- export declare class PoolError extends Error {
5
- }
6
- export declare class Pool<T = unknown> {
7
- #private;
8
- private readonly options;
9
- constructor(options?: PoolOptions);
10
- add(item: T): void;
11
- remove(item: T): void;
12
- capture(timeout?: number | undefined): Promise<T>;
13
- next(exclusive?: boolean, timeout?: number | undefined): Promise<T>;
14
- release(item: T): void;
15
- isFree(item: T): boolean;
16
- get items(): T[];
17
- }
18
- export {};
@@ -1,106 +0,0 @@
1
- export class PoolError extends Error {
2
- }
3
- // Fixed pool from https://github.com/metarhia/metautil
4
- export class Pool {
5
- options;
6
- #items = [];
7
- #free = [];
8
- #queue = [];
9
- #current = 0;
10
- #size = 0;
11
- #available = 0;
12
- constructor(options = {}) {
13
- this.options = options;
14
- }
15
- add(item) {
16
- if (this.#items.includes(item))
17
- throw new PoolError('Item already exists');
18
- this.#size++;
19
- this.#available++;
20
- this.#items.push(item);
21
- this.#free.push(true);
22
- }
23
- remove(item) {
24
- if (this.#size === 0)
25
- throw new PoolError('Pool is empty');
26
- const index = this.#items.indexOf(item);
27
- if (index < 0)
28
- throw new PoolError('Item is not in the pool');
29
- const isCaptured = this.isFree(item);
30
- if (isCaptured)
31
- this.#available--;
32
- this.#size--;
33
- this.#current--;
34
- this.#items.splice(index, 1);
35
- this.#free.splice(index, 1);
36
- }
37
- capture(timeout = this.options.timeout) {
38
- return this.next(true, timeout);
39
- }
40
- async next(exclusive = false, timeout = this.options.timeout) {
41
- if (this.#size === 0)
42
- throw new PoolError('Pool is empty');
43
- if (this.#available === 0) {
44
- return new Promise((resolve, reject) => {
45
- const waiting = {
46
- resolve: (item) => {
47
- if (exclusive)
48
- this.#capture(item);
49
- resolve(item);
50
- },
51
- timer: undefined,
52
- };
53
- if (timeout) {
54
- waiting.timer = setTimeout(() => {
55
- waiting.resolve = undefined;
56
- this.#queue.shift();
57
- reject(new PoolError('Next item timeout'));
58
- }, timeout);
59
- }
60
- this.#queue.push(waiting);
61
- });
62
- }
63
- let item;
64
- let free = false;
65
- do {
66
- item = this.#items[this.#current];
67
- free = this.#free[this.#current];
68
- this.#current++;
69
- if (this.#current >= this.#size)
70
- this.#current = 0;
71
- } while (typeof item === 'undefined' || !free);
72
- if (exclusive)
73
- this.#capture(item);
74
- return item;
75
- }
76
- release(item) {
77
- const index = this.#items.indexOf(item);
78
- if (index < 0)
79
- throw new PoolError('Unexpected item');
80
- if (this.#free[index])
81
- throw new PoolError('Unable to release not captured item');
82
- this.#free[index] = true;
83
- this.#available++;
84
- if (this.#queue.length > 0) {
85
- const { resolve, timer } = this.#queue.shift();
86
- clearTimeout(timer);
87
- if (resolve)
88
- setTimeout(resolve, 0, item);
89
- }
90
- }
91
- isFree(item) {
92
- const index = this.#items.indexOf(item);
93
- if (index < 0)
94
- return false;
95
- return this.#free[index];
96
- }
97
- get items() {
98
- return [...this.#items];
99
- }
100
- #capture(item) {
101
- const index = this.#items.indexOf(item);
102
- this.#free[index] = false;
103
- this.#available--;
104
- }
105
- }
106
- //# sourceMappingURL=pool.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/utils/pool.ts"],"names":[],"mappings":"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"}
@@ -1,13 +0,0 @@
1
- export declare class SemaphoreError extends Error {
2
- }
3
- export declare class Semaphore {
4
- private readonly size;
5
- private readonly timeout;
6
- private counter;
7
- private readonly queue;
8
- constructor(concurrency: number, size?: number, timeout?: number);
9
- enter(): Promise<void>;
10
- leave(): void;
11
- get isEmpty(): boolean;
12
- get queueLength(): number;
13
- }
@@ -1,56 +0,0 @@
1
- export class SemaphoreError extends Error {
2
- }
3
- // Semaphore from https://github.com/metarhia/metautil
4
- export class Semaphore {
5
- size;
6
- timeout;
7
- counter;
8
- queue = [];
9
- constructor(concurrency, size = 0, timeout = 0) {
10
- this.size = size;
11
- this.timeout = timeout;
12
- this.counter = concurrency;
13
- }
14
- enter() {
15
- if (this.counter > 0) {
16
- this.counter--;
17
- return Promise.resolve();
18
- }
19
- else if (this.queue.length >= this.size) {
20
- return Promise.reject(new SemaphoreError('Queue is full'));
21
- }
22
- else {
23
- return new Promise((resolve, reject) => {
24
- const waiting = { resolve };
25
- waiting.timer = setTimeout(() => {
26
- waiting.resolve = undefined;
27
- this.queue.shift();
28
- reject(new SemaphoreError('Timeout'));
29
- }, this.timeout);
30
- this.queue.push(waiting);
31
- });
32
- }
33
- }
34
- leave() {
35
- if (this.queue.length === 0) {
36
- this.counter++;
37
- }
38
- else {
39
- const item = this.queue.shift();
40
- if (item) {
41
- const { resolve, timer } = item;
42
- if (timer)
43
- clearTimeout(timer);
44
- if (resolve)
45
- setTimeout(resolve, 0);
46
- }
47
- }
48
- }
49
- get isEmpty() {
50
- return this.queue.length === 0;
51
- }
52
- get queueLength() {
53
- return this.queue.length;
54
- }
55
- }
56
- //# sourceMappingURL=semaphore.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"semaphore.js","sourceRoot":"","sources":["../../src/utils/semaphore.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,cAAe,SAAQ,KAAK;CAAG;AAE5C,sDAAsD;AACtD,MAAM,OAAO,SAAS;IAOD,IAAI;IACJ,OAAO;IAPlB,OAAO,CAAQ;IAEN,KAAK,GAAyB,EAAE,CAAA;IAEjD,YACE,WAAmB,EACF,IAAI,GAAW,CAAC,EAChB,OAAO,GAAW,CAAC;oBADnB,IAAI;uBACJ,OAAO;QAExB,IAAI,CAAC,OAAO,GAAG,WAAW,CAAA;IAC5B,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,OAAO,EAAE,CAAA;YACd,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;QAC1B,CAAC;aAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC1C,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,cAAc,CAAC,eAAe,CAAC,CAAC,CAAA;QAC5D,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACrC,MAAM,OAAO,GAAuB,EAAE,OAAO,EAAE,CAAA;gBAC/C,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;oBAC9B,OAAO,CAAC,OAAO,GAAG,SAAS,CAAA;oBAC3B,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;oBAClB,MAAM,CAAC,IAAI,cAAc,CAAC,SAAS,CAAC,CAAC,CAAA;gBACvC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;gBAChB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YAC1B,CAAC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO,EAAE,CAAA;QAChB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;YAC/B,IAAI,IAAI,EAAE,CAAC;gBACT,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;gBAC/B,IAAI,KAAK;oBAAE,YAAY,CAAC,KAAK,CAAC,CAAA;gBAC9B,IAAI,OAAO;oBAAE,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;YACrC,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAA;IAChC,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAA;IAC1B,CAAC;CACF"}