@xyo-network/module-resolver 2.92.6 → 2.92.8

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 (42) hide show
  1. package/dist/browser/CompositeModuleResolver.d.cts +11 -4
  2. package/dist/browser/CompositeModuleResolver.d.cts.map +1 -1
  3. package/dist/browser/CompositeModuleResolver.d.mts +11 -4
  4. package/dist/browser/CompositeModuleResolver.d.mts.map +1 -1
  5. package/dist/browser/CompositeModuleResolver.d.ts +11 -4
  6. package/dist/browser/CompositeModuleResolver.d.ts.map +1 -1
  7. package/dist/browser/ResolverEventEmitter.d.cts.map +1 -1
  8. package/dist/browser/ResolverEventEmitter.d.mts.map +1 -1
  9. package/dist/browser/ResolverEventEmitter.d.ts.map +1 -1
  10. package/dist/browser/SimpleModuleResolver.d.cts +6 -3
  11. package/dist/browser/SimpleModuleResolver.d.cts.map +1 -1
  12. package/dist/browser/SimpleModuleResolver.d.mts +6 -3
  13. package/dist/browser/SimpleModuleResolver.d.mts.map +1 -1
  14. package/dist/browser/SimpleModuleResolver.d.ts +6 -3
  15. package/dist/browser/SimpleModuleResolver.d.ts.map +1 -1
  16. package/dist/browser/index.cjs +68 -25
  17. package/dist/browser/index.cjs.map +1 -1
  18. package/dist/browser/index.js +70 -27
  19. package/dist/browser/index.js.map +1 -1
  20. package/dist/node/CompositeModuleResolver.d.cts +11 -4
  21. package/dist/node/CompositeModuleResolver.d.cts.map +1 -1
  22. package/dist/node/CompositeModuleResolver.d.mts +11 -4
  23. package/dist/node/CompositeModuleResolver.d.mts.map +1 -1
  24. package/dist/node/CompositeModuleResolver.d.ts +11 -4
  25. package/dist/node/CompositeModuleResolver.d.ts.map +1 -1
  26. package/dist/node/ResolverEventEmitter.d.cts.map +1 -1
  27. package/dist/node/ResolverEventEmitter.d.mts.map +1 -1
  28. package/dist/node/ResolverEventEmitter.d.ts.map +1 -1
  29. package/dist/node/SimpleModuleResolver.d.cts +6 -3
  30. package/dist/node/SimpleModuleResolver.d.cts.map +1 -1
  31. package/dist/node/SimpleModuleResolver.d.mts +6 -3
  32. package/dist/node/SimpleModuleResolver.d.mts.map +1 -1
  33. package/dist/node/SimpleModuleResolver.d.ts +6 -3
  34. package/dist/node/SimpleModuleResolver.d.ts.map +1 -1
  35. package/dist/node/index.cjs +68 -28
  36. package/dist/node/index.cjs.map +1 -1
  37. package/dist/node/index.js +70 -30
  38. package/dist/node/index.js.map +1 -1
  39. package/package.json +9 -8
  40. package/src/CompositeModuleResolver.ts +49 -9
  41. package/src/ResolverEventEmitter.ts +1 -0
  42. package/src/SimpleModuleResolver.ts +53 -43
@@ -4,6 +4,7 @@ import { Address } from '@xylabs/hex'
4
4
  import { Base, BaseParams } from '@xylabs/object'
5
5
  import { Promisable } from '@xylabs/promise'
6
6
  import {
7
+ CacheConfig,
7
8
  duplicateModules,
8
9
  ModuleFilter,
9
10
  ModuleFilterOptions,
@@ -13,6 +14,7 @@ import {
13
14
  ModuleRepository,
14
15
  ModuleResolverInstance,
15
16
  } from '@xyo-network/module-model'
17
+ import { LRUCache } from 'lru-cache'
16
18
 
17
19
  import { SimpleModuleResolver } from './SimpleModuleResolver'
18
20
  import { ModuleIdentifierTransformer } from './transformers'
@@ -20,6 +22,7 @@ import { ModuleIdentifierTransformer } from './transformers'
20
22
  export type ModuleIdentifierTransformerFunc = (id: ModuleIdentifier) => Promisable<ModuleIdentifier>
21
23
 
22
24
  export interface ModuleResolverParams extends BaseParams {
25
+ cache?: CacheConfig
23
26
  moduleIdentifierTransformers?: ModuleIdentifierTransformer[]
24
27
  }
25
28
 
@@ -30,13 +33,16 @@ const moduleIdentifierParts = (moduleIdentifier: ModuleIdentifier): ModuleIdenti
30
33
  export class CompositeModuleResolver extends Base<ModuleResolverParams> implements ModuleRepository, ModuleResolverInstance {
31
34
  static defaultMaxDepth = 5
32
35
  protected resolvers: ModuleResolverInstance[] = []
33
- private localResolver: SimpleModuleResolver
36
+ private _cache: LRUCache<ModuleIdentifier, ModuleInstance>
37
+ private _localResolver: SimpleModuleResolver
34
38
 
35
- constructor(params: ModuleResolverParams = {}) {
39
+ constructor({ cache, ...params }: ModuleResolverParams = {}) {
36
40
  super(params)
37
41
  const localResolver = new SimpleModuleResolver()
38
42
  this.addResolver(localResolver)
39
- this.localResolver = localResolver
43
+ const { max = 100, ttl = 1000 * 5 /* five seconds */ } = cache ?? {}
44
+ this._cache = new LRUCache<ModuleIdentifier, ModuleInstance>({ max, ttl, ...cache })
45
+ this._localResolver = localResolver
40
46
  }
41
47
 
42
48
  private get moduleIdentifierTransformers() {
@@ -72,15 +78,37 @@ export class CompositeModuleResolver extends Base<ModuleResolverParams> implemen
72
78
  this.resolvers = this.resolvers.filter((item) => item !== resolver)
73
79
  return this
74
80
  }
75
-
76
- async resolve<T extends ModuleInstance = ModuleInstance>(filter?: ModuleFilter<T>, options?: ModuleFilterOptions<T>): Promise<T[]>
81
+ /** @deprecated do not pass undefined. If trying to get all, pass '*' */
82
+ async resolve(): Promise<ModuleInstance[]>
83
+ async resolve<T extends ModuleInstance = ModuleInstance>(all: '*', options?: ModuleFilterOptions<T>): Promise<T[]>
84
+ async resolve<T extends ModuleInstance = ModuleInstance>(filter: ModuleFilter<T>, options?: ModuleFilterOptions<T>): Promise<T[]>
77
85
  async resolve<T extends ModuleInstance = ModuleInstance>(id: ModuleIdentifier, options?: ModuleFilterOptions<T>): Promise<T | undefined>
86
+ /** @deprecated use '*' if trying to resolve all */
87
+ async resolve<T extends ModuleInstance = ModuleInstance>(filter?: ModuleFilter<T>, options?: ModuleFilterOptions<T>): Promise<T[]>
78
88
  async resolve<T extends ModuleInstance = ModuleInstance>(
79
- idOrFilter?: ModuleFilter<T> | ModuleIdentifier,
89
+ idOrFilter: ModuleFilter<T> | ModuleIdentifier = '*',
80
90
  options?: ModuleFilterOptions<T>,
81
91
  ): Promise<T | T[] | undefined> {
82
92
  const mutatedOptions = { ...options, maxDepth: (options?.maxDepth ?? CompositeModuleResolver.defaultMaxDepth) - 1 }
93
+
94
+ //resolve all
95
+ if (idOrFilter === '*') {
96
+ const all = idOrFilter
97
+ if (mutatedOptions.maxDepth < 0) {
98
+ return []
99
+ }
100
+ const result = await Promise.all(
101
+ this.resolvers.map(async (resolver) => {
102
+ const result: T[] = await resolver.resolve<T>(all, mutatedOptions)
103
+ return result
104
+ }),
105
+ )
106
+ const flatResult: T[] = result.flat().filter(exists)
107
+ return flatResult.filter(duplicateModules)
108
+ }
109
+
83
110
  if (typeof idOrFilter === 'string') {
111
+ //resolve ModuleIdentifier
84
112
  const idParts = moduleIdentifierParts(idOrFilter)
85
113
  if (idParts.length > 1) {
86
114
  return await this.resolveMultipartIdentifier<T>(idOrFilter)
@@ -89,6 +117,14 @@ export class CompositeModuleResolver extends Base<ModuleResolverParams> implemen
89
117
  if (mutatedOptions.maxDepth < 0) {
90
118
  return undefined
91
119
  }
120
+ const cachedResult = this._cache.get(id)
121
+ if (cachedResult) {
122
+ if (cachedResult.status === 'dead') {
123
+ this._cache.delete(id)
124
+ } else {
125
+ return cachedResult as T
126
+ }
127
+ }
92
128
  const results = await Promise.all(
93
129
  this.resolvers.map(async (resolver) => {
94
130
  const result: T | undefined = await resolver.resolve<T>(id, mutatedOptions)
@@ -96,8 +132,12 @@ export class CompositeModuleResolver extends Base<ModuleResolverParams> implemen
96
132
  }),
97
133
  )
98
134
  const result: T | undefined = results.filter(exists).filter(duplicateModules).pop()
135
+ if (result) {
136
+ this._cache.set(id, result)
137
+ }
99
138
  return result
100
139
  } else {
140
+ //resolve filter
101
141
  const filter = idOrFilter
102
142
  if (mutatedOptions.maxDepth < 0) {
103
143
  return []
@@ -115,16 +155,16 @@ export class CompositeModuleResolver extends Base<ModuleResolverParams> implemen
115
155
 
116
156
  private addSingleModule(module?: ModuleInstance) {
117
157
  if (module) {
118
- this.localResolver.add(module)
158
+ this._localResolver.add(module)
119
159
  }
120
160
  }
121
161
  private removeSingleModule(address: Address) {
122
- this.localResolver.remove(address)
162
+ this._localResolver.remove(address)
123
163
  }
124
164
 
125
165
  private async resolveMultipartIdentifier<T extends ModuleInstance = ModuleInstance>(moduleIdentifier: ModuleIdentifier): Promise<T | undefined> {
126
166
  const idParts = moduleIdentifierParts(moduleIdentifier)
127
- assertEx(idParts.length >= 2, 'Not a valid multipart identifier')
167
+ assertEx(idParts.length >= 2, () => 'Not a valid multipart identifier')
128
168
  const id = assertEx(idParts.shift())
129
169
  const module = await this.resolve(id)
130
170
  return await module?.resolve<T>(idParts.join(':'))
@@ -22,6 +22,7 @@ const getMixin = <T extends ModuleResolver = ModuleResolver>(resolver: T) => {
22
22
  const args = { filter, module }
23
23
  emit('moduleResolved', args)
24
24
  }
25
+ // eslint-disable-next-line deprecation/deprecation
25
26
  const { resolve } = resolver
26
27
  function originalResolve(filter?: ModuleFilter) {
27
28
  return resolve.bind(resolver)(filter)
@@ -1,22 +1,26 @@
1
- import { Address } from '@xylabs/hex'
2
- import { compact, flatten } from '@xylabs/lodash'
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { Address, isAddress } from '@xylabs/hex'
3
+ import { compact } from '@xylabs/lodash'
3
4
  import { Promisable } from '@xylabs/promise'
4
5
  import {
5
6
  isAddressModuleFilter,
7
+ isModuleName,
6
8
  isNameModuleFilter,
7
9
  isQueryModuleFilter,
8
10
  ModuleFilter,
9
11
  ModuleFilterOptions,
10
12
  ModuleIdentifier,
11
13
  ModuleInstance,
14
+ ModuleName,
12
15
  ModuleRepository,
16
+ ModuleResolver,
13
17
  ModuleResolverInstance,
14
18
  } from '@xyo-network/module-model'
15
19
 
16
20
  //This class is now package private (not exported from index.ts)
17
- export class SimpleModuleResolver implements ModuleRepository {
18
- private addressToName: Record<string, string> = {}
19
- private modules: Record<string, ModuleInstance> = {}
21
+ export class SimpleModuleResolver implements ModuleRepository, ModuleResolver {
22
+ private addressToName: Record<Address, ModuleName> = {}
23
+ private modules: Record<Address, ModuleInstance> = {}
20
24
 
21
25
  add(module: ModuleInstance): this
22
26
  add(module: ModuleInstance[]): this
@@ -46,21 +50,33 @@ export class SimpleModuleResolver implements ModuleRepository {
46
50
  throw 'Removing resolvers not supported'
47
51
  }
48
52
 
49
- resolve<T extends ModuleInstance = ModuleInstance>(filter?: ModuleFilter<T>, options?: ModuleFilterOptions<T>): Promisable<T[]>
53
+ resolve<T extends ModuleInstance = ModuleInstance>(all: '*', options?: ModuleFilterOptions<T>): Promisable<T[]>
54
+ resolve<T extends ModuleInstance = ModuleInstance>(filter: ModuleFilter<T>, options?: ModuleFilterOptions<T>): Promisable<T[]>
50
55
  resolve<T extends ModuleInstance = ModuleInstance>(id: ModuleIdentifier, options?: ModuleFilterOptions<T>): Promisable<T | undefined>
56
+ /** @deprecated use '*' if trying to resolve all */
57
+ resolve<T extends ModuleInstance = ModuleInstance>(filter?: ModuleFilter<T>, options?: ModuleFilterOptions<T>): Promisable<T[]>
51
58
  resolve<T extends ModuleInstance = ModuleInstance>(
52
- idOrFilter?: ModuleFilter<T> | string,
59
+ idOrFilter: ModuleFilter<T> | string = '*',
53
60
  options?: ModuleFilterOptions<T>,
54
61
  ): Promisable<T[] | T | undefined> {
55
62
  const unfiltered = (() => {
56
63
  if (idOrFilter) {
57
64
  if (typeof idOrFilter === 'string') {
58
- const id = idOrFilter
59
- return this.resolveByName<T>(Object.values(this.modules), [id]).pop() ?? this.resolveByAddress<T>(Object.values(this.modules), [id]).pop()
65
+ if (idOrFilter === '*') {
66
+ return Object.values(this.modules) as T[]
67
+ }
68
+ const id = idOrFilter as ModuleIdentifier
69
+ const name = isModuleName(id) ? id : undefined
70
+ const address = isAddress(id) ? id : undefined
71
+ assertEx(name || address, () => 'module identifier must be a ModuleName or Address')
72
+ return (
73
+ (name ? this.resolveByName<T>(Object.values(this.modules), [name]).pop() : undefined) ??
74
+ (address ? this.resolveByAddress<T>(this.modules, [address]).pop() : undefined)
75
+ )
60
76
  } else {
61
77
  const filter = idOrFilter
62
78
  if (isAddressModuleFilter(filter)) {
63
- return this.resolveByAddress<T>(Object.values(this.modules), filter.address)
79
+ return this.resolveByAddress<T>(this.modules, filter.address)
64
80
  } else if (isNameModuleFilter(filter)) {
65
81
  return this.resolveByName<T>(Object.values(this.modules), filter.name)
66
82
  } else if (isQueryModuleFilter(filter)) {
@@ -90,6 +106,7 @@ export class SimpleModuleResolver implements ModuleRepository {
90
106
  }
91
107
 
92
108
  private removeSingleModule(address: Address) {
109
+ assertEx(isAddress(address), () => 'Invalid address')
93
110
  if (address && this.modules[address]) {
94
111
  delete this.modules[address]
95
112
  const name = this.addressToName[address]
@@ -99,42 +116,35 @@ export class SimpleModuleResolver implements ModuleRepository {
99
116
  }
100
117
  }
101
118
 
102
- private resolveByAddress<T extends ModuleInstance = ModuleInstance>(modules: ModuleInstance[], address?: string[]): T[] {
103
- return (
104
- address ?
105
- compact(
106
- flatten(
107
- address?.map((address) => {
108
- return modules.filter((module) => module.address === address)
109
- }),
110
- ),
111
- )
112
- : modules) as T[]
119
+ private resolveByAddress<T extends ModuleInstance = ModuleInstance>(modules: Record<Address, ModuleInstance>, address: Address[]): T[] {
120
+ return compact(
121
+ address.map((address) => {
122
+ return modules[address]
123
+ }),
124
+ ) as T[]
113
125
  }
114
126
 
115
- private resolveByName<T extends ModuleInstance = ModuleInstance>(modules: ModuleInstance[], name?: string[]): T[] {
116
- if (name) {
117
- return compact(name.flatMap((name) => modules.filter((module) => module.config?.name === name))) as T[]
118
- }
119
- return modules as T[]
127
+ private resolveByName<T extends ModuleInstance = ModuleInstance>(modules: ModuleInstance[], name: ModuleName[]): T[] {
128
+ return compact(
129
+ name.map((name) => {
130
+ return modules.find((module) => module.config.name === name)
131
+ }),
132
+ ) as T[]
120
133
  }
121
134
 
122
- private resolveByQuery<T extends ModuleInstance = ModuleInstance>(modules: ModuleInstance[], query?: string[][]): T[] {
123
- return (
124
- query ?
125
- compact(
126
- modules.filter((module) =>
127
- query?.reduce((supported, queryList) => {
128
- return (
129
- // eslint-disable-next-line unicorn/no-array-reduce
130
- queryList.reduce((supported, query) => {
131
- const queryable = module.queries.includes(query)
132
- return supported && queryable
133
- }, true) || supported
134
- )
135
- }, false),
136
- ),
137
- )
138
- : modules) as T[]
135
+ private resolveByQuery<T extends ModuleInstance = ModuleInstance>(modules: ModuleInstance[], query: string[][]): T[] {
136
+ return compact(
137
+ modules.filter((module) =>
138
+ query?.reduce((supported, queryList) => {
139
+ return (
140
+ // eslint-disable-next-line unicorn/no-array-reduce
141
+ queryList.reduce((supported, query) => {
142
+ const queryable = module.queries.includes(query)
143
+ return supported && queryable
144
+ }, true) || supported
145
+ )
146
+ }, false),
147
+ ),
148
+ ) as T[]
139
149
  }
140
150
  }