@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.
- package/dist/browser/CompositeModuleResolver.d.cts +11 -4
- package/dist/browser/CompositeModuleResolver.d.cts.map +1 -1
- package/dist/browser/CompositeModuleResolver.d.mts +11 -4
- package/dist/browser/CompositeModuleResolver.d.mts.map +1 -1
- package/dist/browser/CompositeModuleResolver.d.ts +11 -4
- package/dist/browser/CompositeModuleResolver.d.ts.map +1 -1
- package/dist/browser/ResolverEventEmitter.d.cts.map +1 -1
- package/dist/browser/ResolverEventEmitter.d.mts.map +1 -1
- package/dist/browser/ResolverEventEmitter.d.ts.map +1 -1
- package/dist/browser/SimpleModuleResolver.d.cts +6 -3
- package/dist/browser/SimpleModuleResolver.d.cts.map +1 -1
- package/dist/browser/SimpleModuleResolver.d.mts +6 -3
- package/dist/browser/SimpleModuleResolver.d.mts.map +1 -1
- package/dist/browser/SimpleModuleResolver.d.ts +6 -3
- package/dist/browser/SimpleModuleResolver.d.ts.map +1 -1
- package/dist/browser/index.cjs +68 -25
- package/dist/browser/index.cjs.map +1 -1
- package/dist/browser/index.js +70 -27
- package/dist/browser/index.js.map +1 -1
- package/dist/node/CompositeModuleResolver.d.cts +11 -4
- package/dist/node/CompositeModuleResolver.d.cts.map +1 -1
- package/dist/node/CompositeModuleResolver.d.mts +11 -4
- package/dist/node/CompositeModuleResolver.d.mts.map +1 -1
- package/dist/node/CompositeModuleResolver.d.ts +11 -4
- package/dist/node/CompositeModuleResolver.d.ts.map +1 -1
- package/dist/node/ResolverEventEmitter.d.cts.map +1 -1
- package/dist/node/ResolverEventEmitter.d.mts.map +1 -1
- package/dist/node/ResolverEventEmitter.d.ts.map +1 -1
- package/dist/node/SimpleModuleResolver.d.cts +6 -3
- package/dist/node/SimpleModuleResolver.d.cts.map +1 -1
- package/dist/node/SimpleModuleResolver.d.mts +6 -3
- package/dist/node/SimpleModuleResolver.d.mts.map +1 -1
- package/dist/node/SimpleModuleResolver.d.ts +6 -3
- package/dist/node/SimpleModuleResolver.d.ts.map +1 -1
- package/dist/node/index.cjs +68 -28
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.js +70 -30
- package/dist/node/index.js.map +1 -1
- package/package.json +9 -8
- package/src/CompositeModuleResolver.ts +49 -9
- package/src/ResolverEventEmitter.ts +1 -0
- 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
|
|
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
|
-
|
|
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
|
|
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
|
|
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.
|
|
158
|
+
this._localResolver.add(module)
|
|
119
159
|
}
|
|
120
160
|
}
|
|
121
161
|
private removeSingleModule(address: Address) {
|
|
122
|
-
this.
|
|
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 {
|
|
2
|
-
import {
|
|
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<
|
|
19
|
-
private modules: Record<
|
|
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>(
|
|
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
|
|
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
|
-
|
|
59
|
-
|
|
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>(
|
|
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:
|
|
103
|
-
return (
|
|
104
|
-
address
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
|
123
|
-
return (
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
}
|