@xyo-network/module-abstract 2.51.10
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/LICENSE +165 -0
- package/README.md +13 -0
- package/dist/cjs/AbstractModule.js +253 -0
- package/dist/cjs/AbstractModule.js.map +1 -0
- package/dist/cjs/BaseEmitter.js +40 -0
- package/dist/cjs/BaseEmitter.js.map +1 -0
- package/dist/cjs/Error.js +21 -0
- package/dist/cjs/Error.js.map +1 -0
- package/dist/cjs/IdLogger.js +38 -0
- package/dist/cjs/IdLogger.js.map +1 -0
- package/dist/cjs/ModuleWrapper.js +226 -0
- package/dist/cjs/ModuleWrapper.js.map +1 -0
- package/dist/cjs/Query/QueryBoundWitnessBuilder.js +25 -0
- package/dist/cjs/Query/QueryBoundWitnessBuilder.js.map +1 -0
- package/dist/cjs/Query/QueryBoundWitnessValidator.js +38 -0
- package/dist/cjs/Query/QueryBoundWitnessValidator.js.map +1 -0
- package/dist/cjs/Query/QueryBoundWitnessWrapper.js +47 -0
- package/dist/cjs/Query/QueryBoundWitnessWrapper.js.map +1 -0
- package/dist/cjs/Query/index.js +7 -0
- package/dist/cjs/Query/index.js.map +1 -0
- package/dist/cjs/QueryValidator/ModuleConfigQueryValidator.js +65 -0
- package/dist/cjs/QueryValidator/ModuleConfigQueryValidator.js.map +1 -0
- package/dist/cjs/QueryValidator/QueryValidator.js +3 -0
- package/dist/cjs/QueryValidator/QueryValidator.js.map +1 -0
- package/dist/cjs/QueryValidator/SupportedQueryValidator.js +20 -0
- package/dist/cjs/QueryValidator/SupportedQueryValidator.js.map +1 -0
- package/dist/cjs/QueryValidator/index.js +7 -0
- package/dist/cjs/QueryValidator/index.js.map +1 -0
- package/dist/cjs/Resolver/CompositeModuleResolver.js +66 -0
- package/dist/cjs/Resolver/CompositeModuleResolver.js.map +1 -0
- package/dist/cjs/Resolver/ResolverEventEmitter.js +38 -0
- package/dist/cjs/Resolver/ResolverEventEmitter.js.map +1 -0
- package/dist/cjs/Resolver/SimpleModuleResolver.js +91 -0
- package/dist/cjs/Resolver/SimpleModuleResolver.js.map +1 -0
- package/dist/cjs/Resolver/index.js +12 -0
- package/dist/cjs/Resolver/index.js.map +1 -0
- package/dist/cjs/index.js +12 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/lib/duplicateModules.js +17 -0
- package/dist/cjs/lib/duplicateModules.js.map +1 -0
- package/dist/cjs/lib/index.js +6 -0
- package/dist/cjs/lib/index.js.map +1 -0
- package/dist/cjs/lib/serializable.js +38 -0
- package/dist/cjs/lib/serializable.js.map +1 -0
- package/dist/docs.json +70567 -0
- package/dist/esm/AbstractModule.js +241 -0
- package/dist/esm/AbstractModule.js.map +1 -0
- package/dist/esm/BaseEmitter.js +37 -0
- package/dist/esm/BaseEmitter.js.map +1 -0
- package/dist/esm/Error.js +19 -0
- package/dist/esm/Error.js.map +1 -0
- package/dist/esm/IdLogger.js +31 -0
- package/dist/esm/IdLogger.js.map +1 -0
- package/dist/esm/ModuleWrapper.js +209 -0
- package/dist/esm/ModuleWrapper.js.map +1 -0
- package/dist/esm/Query/QueryBoundWitnessBuilder.js +22 -0
- package/dist/esm/Query/QueryBoundWitnessBuilder.js.map +1 -0
- package/dist/esm/Query/QueryBoundWitnessValidator.js +35 -0
- package/dist/esm/Query/QueryBoundWitnessValidator.js.map +1 -0
- package/dist/esm/Query/QueryBoundWitnessWrapper.js +41 -0
- package/dist/esm/Query/QueryBoundWitnessWrapper.js.map +1 -0
- package/dist/esm/Query/index.js +4 -0
- package/dist/esm/Query/index.js.map +1 -0
- package/dist/esm/QueryValidator/ModuleConfigQueryValidator.js +62 -0
- package/dist/esm/QueryValidator/ModuleConfigQueryValidator.js.map +1 -0
- package/dist/esm/QueryValidator/QueryValidator.js +2 -0
- package/dist/esm/QueryValidator/QueryValidator.js.map +1 -0
- package/dist/esm/QueryValidator/SupportedQueryValidator.js +16 -0
- package/dist/esm/QueryValidator/SupportedQueryValidator.js.map +1 -0
- package/dist/esm/QueryValidator/index.js +4 -0
- package/dist/esm/QueryValidator/index.js.map +1 -0
- package/dist/esm/Resolver/CompositeModuleResolver.js +60 -0
- package/dist/esm/Resolver/CompositeModuleResolver.js.map +1 -0
- package/dist/esm/Resolver/ResolverEventEmitter.js +33 -0
- package/dist/esm/Resolver/ResolverEventEmitter.js.map +1 -0
- package/dist/esm/Resolver/SimpleModuleResolver.js +84 -0
- package/dist/esm/Resolver/SimpleModuleResolver.js.map +1 -0
- package/dist/esm/Resolver/index.js +8 -0
- package/dist/esm/Resolver/index.js.map +1 -0
- package/dist/esm/index.js +9 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lib/duplicateModules.js +13 -0
- package/dist/esm/lib/duplicateModules.js.map +1 -0
- package/dist/esm/lib/index.js +3 -0
- package/dist/esm/lib/index.js.map +1 -0
- package/dist/esm/lib/serializable.js +32 -0
- package/dist/esm/lib/serializable.js.map +1 -0
- package/dist/types/AbstractModule.d.ts +42 -0
- package/dist/types/AbstractModule.d.ts.map +1 -0
- package/dist/types/BaseEmitter.d.ts +16 -0
- package/dist/types/BaseEmitter.d.ts.map +1 -0
- package/dist/types/Error.d.ts +16 -0
- package/dist/types/Error.d.ts.map +1 -0
- package/dist/types/IdLogger.d.ts +14 -0
- package/dist/types/IdLogger.d.ts.map +1 -0
- package/dist/types/ModuleWrapper.d.ts +73 -0
- package/dist/types/ModuleWrapper.d.ts.map +1 -0
- package/dist/types/Query/QueryBoundWitnessBuilder.d.ts +12 -0
- package/dist/types/Query/QueryBoundWitnessBuilder.d.ts.map +1 -0
- package/dist/types/Query/QueryBoundWitnessValidator.d.ts +10 -0
- package/dist/types/Query/QueryBoundWitnessValidator.d.ts.map +1 -0
- package/dist/types/Query/QueryBoundWitnessWrapper.d.ts +16 -0
- package/dist/types/Query/QueryBoundWitnessWrapper.d.ts.map +1 -0
- package/dist/types/Query/index.d.ts +4 -0
- package/dist/types/Query/index.d.ts.map +1 -0
- package/dist/types/QueryValidator/ModuleConfigQueryValidator.d.ts +15 -0
- package/dist/types/QueryValidator/ModuleConfigQueryValidator.d.ts.map +1 -0
- package/dist/types/QueryValidator/QueryValidator.d.ts +7 -0
- package/dist/types/QueryValidator/QueryValidator.d.ts.map +1 -0
- package/dist/types/QueryValidator/SupportedQueryValidator.d.ts +18 -0
- package/dist/types/QueryValidator/SupportedQueryValidator.d.ts.map +1 -0
- package/dist/types/QueryValidator/index.d.ts +4 -0
- package/dist/types/QueryValidator/index.d.ts.map +1 -0
- package/dist/types/Resolver/CompositeModuleResolver.d.ts +16 -0
- package/dist/types/Resolver/CompositeModuleResolver.d.ts.map +1 -0
- package/dist/types/Resolver/ResolverEventEmitter.d.ts +10 -0
- package/dist/types/Resolver/ResolverEventEmitter.d.ts.map +1 -0
- package/dist/types/Resolver/SimpleModuleResolver.d.ts +19 -0
- package/dist/types/Resolver/SimpleModuleResolver.d.ts.map +1 -0
- package/dist/types/Resolver/index.d.ts +7 -0
- package/dist/types/Resolver/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/lib/duplicateModules.d.ts +32 -0
- package/dist/types/lib/duplicateModules.d.ts.map +1 -0
- package/dist/types/lib/index.d.ts +3 -0
- package/dist/types/lib/index.d.ts.map +1 -0
- package/dist/types/lib/serializable.d.ts +3 -0
- package/dist/types/lib/serializable.d.ts.map +1 -0
- package/package.json +73 -0
- package/src/AbstractModule.ts +307 -0
- package/src/BaseEmitter.ts +47 -0
- package/src/Error.ts +25 -0
- package/src/IdLogger.ts +37 -0
- package/src/ModuleWrapper.ts +330 -0
- package/src/Query/QueryBoundWitnessBuilder.ts +29 -0
- package/src/Query/QueryBoundWitnessValidator.ts +41 -0
- package/src/Query/QueryBoundWitnessWrapper.ts +55 -0
- package/src/Query/index.ts +3 -0
- package/src/QueryValidator/ModuleConfigQueryValidator.ts +67 -0
- package/src/QueryValidator/QueryValidator.ts +8 -0
- package/src/QueryValidator/SupportedQueryValidator.ts +22 -0
- package/src/QueryValidator/index.ts +3 -0
- package/src/Resolver/CompositeModuleResolver.ts +70 -0
- package/src/Resolver/ResolverEventEmitter.ts +46 -0
- package/src/Resolver/SimpleModuleResolver.ts +118 -0
- package/src/Resolver/index.ts +8 -0
- package/src/index.ts +8 -0
- package/src/lib/duplicateModules.ts +14 -0
- package/src/lib/index.ts +2 -0
- package/src/lib/serializable.ts +41 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { assertEx } from '@xylabs/assert'
|
|
2
|
+
import { Account } from '@xyo-network/account'
|
|
3
|
+
import { AccountInstance } from '@xyo-network/account-model'
|
|
4
|
+
import { AddressPayload, AddressSchema } from '@xyo-network/address-payload-plugin'
|
|
5
|
+
import { BoundWitnessWrapper } from '@xyo-network/boundwitness-wrapper'
|
|
6
|
+
import { BaseParams } from '@xyo-network/core'
|
|
7
|
+
import { EventAnyListener, EventListener } from '@xyo-network/module-events'
|
|
8
|
+
import {
|
|
9
|
+
Module,
|
|
10
|
+
ModuleDescription,
|
|
11
|
+
ModuleDiscoverQuery,
|
|
12
|
+
ModuleDiscoverQuerySchema,
|
|
13
|
+
ModuleFilter,
|
|
14
|
+
ModuleQueryResult,
|
|
15
|
+
XyoQuery,
|
|
16
|
+
XyoQueryBoundWitness,
|
|
17
|
+
} from '@xyo-network/module-model'
|
|
18
|
+
import { XyoPayload, XyoPayloads } from '@xyo-network/payload-model'
|
|
19
|
+
import { PayloadWrapper } from '@xyo-network/payload-wrapper'
|
|
20
|
+
import { Promisable, PromiseEx } from '@xyo-network/promise'
|
|
21
|
+
import compact from 'lodash/compact'
|
|
22
|
+
|
|
23
|
+
import { BaseEmitter } from './BaseEmitter'
|
|
24
|
+
import { XyoError, XyoErrorSchema } from './Error'
|
|
25
|
+
import { duplicateModules } from './lib'
|
|
26
|
+
import { QueryBoundWitnessBuilder, QueryBoundWitnessWrapper } from './Query'
|
|
27
|
+
|
|
28
|
+
export interface WrapperError extends Error {
|
|
29
|
+
errors: (XyoError | null)[]
|
|
30
|
+
query: [XyoQueryBoundWitness, XyoPayloads]
|
|
31
|
+
result: ModuleQueryResult | undefined
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type ModuleConstructable<TModule extends Module = Module, TWrapper extends ModuleWrapper<TModule> = ModuleWrapper<TModule>> = {
|
|
35
|
+
new (params: ModuleWrapperParams): TWrapper
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function moduleConstructable<TModule extends Module = Module, TWrapper extends ModuleWrapper<TModule> = ModuleWrapper<TModule>>() {
|
|
39
|
+
return <U extends ModuleConstructable<TModule, TWrapper>>(constructor: U) => {
|
|
40
|
+
constructor
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type ModuleWrapperParams<TWrappedModule extends Module = Module> = BaseParams<{
|
|
45
|
+
account?: AccountInstance
|
|
46
|
+
module: TWrappedModule
|
|
47
|
+
}>
|
|
48
|
+
|
|
49
|
+
@moduleConstructable()
|
|
50
|
+
export class ModuleWrapper<TWrappedModule extends Module = Module>
|
|
51
|
+
extends BaseEmitter<TWrappedModule['params']>
|
|
52
|
+
implements Module<TWrappedModule['params']>
|
|
53
|
+
{
|
|
54
|
+
static requiredQueries: string[] = [ModuleDiscoverQuerySchema]
|
|
55
|
+
|
|
56
|
+
protected readonly wrapperParams: ModuleWrapperParams<TWrappedModule>
|
|
57
|
+
|
|
58
|
+
constructor(params: ModuleWrapperParams<TWrappedModule>) {
|
|
59
|
+
const mutatedParams = { ...params } as ModuleWrapperParams<TWrappedModule>
|
|
60
|
+
//unwrap it if already wrapped
|
|
61
|
+
const wrapper = params.module as unknown as ModuleWrapper<TWrappedModule>
|
|
62
|
+
if (wrapper.module) {
|
|
63
|
+
mutatedParams.module = wrapper.module
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
//set the root params to the wrapped module params
|
|
67
|
+
super(params.module.params)
|
|
68
|
+
this.wrapperParams = params
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get account() {
|
|
72
|
+
return this.wrapperParams.account
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
get address() {
|
|
76
|
+
return this.module.address
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get config(): TWrappedModule['config'] {
|
|
80
|
+
return this.module.config
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get downResolver() {
|
|
84
|
+
return this.module.downResolver
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get module() {
|
|
88
|
+
return this.wrapperParams.module
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get queries(): string[] {
|
|
92
|
+
return this.module.queries
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get upResolver() {
|
|
96
|
+
return this.module.upResolver
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static canWrap(module?: Module) {
|
|
100
|
+
return !!module && this.missingRequiredQueries(module).length === 0
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static hasRequiredQueries(module: Module) {
|
|
104
|
+
return this.missingRequiredQueries(module).length === 0
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
static missingRequiredQueries(module: Module): string[] {
|
|
108
|
+
const moduleQueries = module.queries
|
|
109
|
+
return compact(
|
|
110
|
+
this.requiredQueries.map((query) => {
|
|
111
|
+
return moduleQueries.find((item) => item === query) ? null : query
|
|
112
|
+
}),
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
static tryWrap(module?: Module, account?: AccountInstance): ModuleWrapper | undefined {
|
|
117
|
+
if (this.canWrap(module)) {
|
|
118
|
+
if (!account) {
|
|
119
|
+
this.defaultLogger?.info('Anonymous Module Wrapper Created')
|
|
120
|
+
}
|
|
121
|
+
return new ModuleWrapper({ account, module: module as Module })
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static wrap(module?: Module, account?: AccountInstance): ModuleWrapper {
|
|
126
|
+
return assertEx(this.tryWrap(module, account), 'Unable to wrap module as ModuleWrapper')
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
override clearListeners(eventNames: keyof TWrappedModule['params']['eventData'] | keyof TWrappedModule['params']['eventData'][]) {
|
|
130
|
+
return this.module.clearListeners(eventNames)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async describe(): Promise<Promise<Promisable<ModuleDescription>>> {
|
|
134
|
+
const description: ModuleDescription = {
|
|
135
|
+
address: this.module.address,
|
|
136
|
+
queries: this.module.queries,
|
|
137
|
+
}
|
|
138
|
+
if (this.config.name) {
|
|
139
|
+
description.name = this.config.name
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const discover = await this.discover()
|
|
143
|
+
|
|
144
|
+
description.children = compact(
|
|
145
|
+
discover?.map((payload) => {
|
|
146
|
+
const address = payload.schema === AddressSchema ? (payload as AddressPayload).address : undefined
|
|
147
|
+
return address != this.module.address ? address : undefined
|
|
148
|
+
}) ?? [],
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return description
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
discover(): Promise<XyoPayload[]> {
|
|
155
|
+
const queryPayload = PayloadWrapper.parse<ModuleDiscoverQuery>({ schema: ModuleDiscoverQuerySchema })
|
|
156
|
+
return this.sendQuery(queryPayload)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
override emit(
|
|
160
|
+
eventName: keyof TWrappedModule['params']['eventData'],
|
|
161
|
+
eventArgs?: TWrappedModule['params']['eventData'][keyof TWrappedModule['params']['eventData']],
|
|
162
|
+
) {
|
|
163
|
+
return this.module.emit(eventName, eventArgs)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
override emitSerial(
|
|
167
|
+
eventName: keyof TWrappedModule['params']['eventData'],
|
|
168
|
+
eventArgs?: TWrappedModule['params']['eventData'][keyof TWrappedModule['params']['eventData']],
|
|
169
|
+
) {
|
|
170
|
+
return this.module.emitSerial(eventName, eventArgs)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
override listenerCount(eventNames: keyof TWrappedModule['params']['eventData'] | keyof TWrappedModule['params']['eventData'][]) {
|
|
174
|
+
return this.module.listenerCount(eventNames)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
override off(
|
|
178
|
+
eventNames: keyof TWrappedModule['params']['eventData'] | keyof TWrappedModule['params']['eventData'][],
|
|
179
|
+
listener: EventListener<TWrappedModule['params']['eventData']>,
|
|
180
|
+
) {
|
|
181
|
+
return this.module.off(eventNames, listener)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
override offAny(listener: EventAnyListener<TWrappedModule['params']['eventData']>) {
|
|
185
|
+
return this.module.offAny(listener)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
override on(
|
|
189
|
+
eventNames: keyof TWrappedModule['params']['eventData'] | keyof TWrappedModule['params']['eventData'][],
|
|
190
|
+
listener: EventListener<TWrappedModule['params']['eventData']>,
|
|
191
|
+
) {
|
|
192
|
+
return this.module.on(eventNames, listener)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
override onAny(listener: EventAnyListener<TWrappedModule['params']['eventData']>) {
|
|
196
|
+
return this.module.onAny(listener)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
override once(
|
|
200
|
+
eventNames: keyof TWrappedModule['params']['eventData'] | keyof TWrappedModule['params']['eventData'][],
|
|
201
|
+
listener: EventListener<TWrappedModule['params']['eventData']>,
|
|
202
|
+
) {
|
|
203
|
+
return this.module.once(eventNames, listener)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async query<T extends XyoQueryBoundWitness = XyoQueryBoundWitness>(query: T, payloads?: XyoPayload[]): Promise<ModuleQueryResult> {
|
|
207
|
+
return await this.module.query(query, payloads)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
queryable<T extends XyoQueryBoundWitness = XyoQueryBoundWitness>(query: T, payloads?: XyoPayload[]) {
|
|
211
|
+
return this.module.queryable(query, payloads)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async resolve<TModule extends Module = Module>(filter?: ModuleFilter): Promise<TModule[]>
|
|
215
|
+
async resolve<TModule extends Module = Module>(nameOrAddress: string): Promise<TModule | undefined>
|
|
216
|
+
async resolve<TModule extends Module = Module>(nameOrAddressOrFilter?: ModuleFilter | string): Promise<TModule | TModule[] | undefined> {
|
|
217
|
+
switch (typeof nameOrAddressOrFilter) {
|
|
218
|
+
case 'string': {
|
|
219
|
+
const byAddress = Account.isAddress(nameOrAddressOrFilter)
|
|
220
|
+
? (await this.resolve<TModule>({ address: [nameOrAddressOrFilter] })).pop()
|
|
221
|
+
: undefined
|
|
222
|
+
return byAddress ?? (await this.resolve<TModule>({ name: [nameOrAddressOrFilter] })).pop()
|
|
223
|
+
}
|
|
224
|
+
default: {
|
|
225
|
+
const filter: ModuleFilter | undefined = nameOrAddressOrFilter
|
|
226
|
+
return [...(await this.module.downResolver.resolve<TModule>(filter)), ...(await this.module.upResolver.resolve<TModule>(filter))].filter(
|
|
227
|
+
duplicateModules,
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Resolves the supplied filter into wrapped modules
|
|
235
|
+
* @example <caption>Example using ArchivistWrapper</caption>
|
|
236
|
+
* const filter = { address: [address] }
|
|
237
|
+
* const mods: ArchivistWrapper[] = await node.resolveWrapped(ArchivistWrapper, filter)
|
|
238
|
+
* @param wrapper The ModuleWrapper class (ArchivistWrapper,
|
|
239
|
+
* DivinerWrapper, etc.)
|
|
240
|
+
* @param filter The ModuleFilter
|
|
241
|
+
* @returns An array of ModuleWrapper instances corresponding to
|
|
242
|
+
* the underlying modules matching the supplied filter
|
|
243
|
+
*/
|
|
244
|
+
async resolveWrapped<T extends ModuleWrapper<Module> = ModuleWrapper<Module>>(
|
|
245
|
+
wrapper: ModuleConstructable<Module, T>,
|
|
246
|
+
filter?: ModuleFilter,
|
|
247
|
+
): Promise<T[]>
|
|
248
|
+
async resolveWrapped<T extends ModuleWrapper<Module> = ModuleWrapper<Module>>(
|
|
249
|
+
wrapper: ModuleConstructable<Module, T>,
|
|
250
|
+
nameOrAddress: string,
|
|
251
|
+
): Promise<T | undefined>
|
|
252
|
+
async resolveWrapped<T extends ModuleWrapper<Module> = ModuleWrapper<Module>>(
|
|
253
|
+
wrapper: ModuleConstructable<Module, T>,
|
|
254
|
+
nameOrAddressOrFilter?: ModuleFilter | string,
|
|
255
|
+
): Promise<T[] | T | undefined> {
|
|
256
|
+
switch (typeof nameOrAddressOrFilter) {
|
|
257
|
+
case 'string': {
|
|
258
|
+
const nameOrAddress: string = nameOrAddressOrFilter
|
|
259
|
+
const mod = await this.resolve<T['module']>(nameOrAddress)
|
|
260
|
+
return mod ? new wrapper({ account: this.account, module: mod }) : undefined
|
|
261
|
+
}
|
|
262
|
+
default: {
|
|
263
|
+
const filter: ModuleFilter | undefined = nameOrAddressOrFilter
|
|
264
|
+
return (await this.resolve<T['module']>(filter)).map((mod) => new wrapper({ account: this.account, module: mod }))
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
protected bindQuery<T extends XyoQuery | PayloadWrapper<XyoQuery>>(
|
|
270
|
+
query: T,
|
|
271
|
+
payloads?: XyoPayload[],
|
|
272
|
+
account: AccountInstance | undefined = this.account,
|
|
273
|
+
): PromiseEx<[XyoQueryBoundWitness, XyoPayload[]], AccountInstance> {
|
|
274
|
+
const promise = new PromiseEx<[XyoQueryBoundWitness, XyoPayload[]], AccountInstance>((resolve) => {
|
|
275
|
+
const result = this.bindQueryInternal(query, payloads, account)
|
|
276
|
+
resolve?.(result)
|
|
277
|
+
return result
|
|
278
|
+
}, account)
|
|
279
|
+
return promise
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
protected bindQueryInternal<T extends XyoQuery | PayloadWrapper<XyoQuery>>(
|
|
283
|
+
query: T,
|
|
284
|
+
payloads?: XyoPayload[],
|
|
285
|
+
account: AccountInstance | undefined = this.account,
|
|
286
|
+
): [XyoQueryBoundWitness, XyoPayload[]] {
|
|
287
|
+
const builder = new QueryBoundWitnessBuilder().payloads(payloads).query(query)
|
|
288
|
+
const result = (account ? builder.witness(account) : builder).build()
|
|
289
|
+
return result
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
protected filterErrors(query: [XyoQueryBoundWitness, XyoPayloads], result: ModuleQueryResult | undefined): (XyoError | null)[] {
|
|
293
|
+
return (result?.[1]?.filter((payload) => {
|
|
294
|
+
if (payload?.schema === XyoErrorSchema) {
|
|
295
|
+
const wrapper = new QueryBoundWitnessWrapper(query[0])
|
|
296
|
+
return payload.sources?.includes(wrapper.hash)
|
|
297
|
+
}
|
|
298
|
+
return false
|
|
299
|
+
}) ?? []) as XyoError[]
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
protected async sendQuery<T extends XyoQuery | PayloadWrapper<XyoQuery>>(queryPayload: T, payloads?: XyoPayloads): Promise<XyoPayload[]> {
|
|
303
|
+
//make sure we did not get wrapped payloads
|
|
304
|
+
const unwrappedPayloads = payloads?.map((payload) => assertEx(PayloadWrapper.unwrap(payload), 'Unable to parse payload'))
|
|
305
|
+
const unwrappedQueryPayload = assertEx(BoundWitnessWrapper.unwrap<XyoQueryBoundWitness>(queryPayload), 'Unable to parse queryPayload')
|
|
306
|
+
|
|
307
|
+
// Bind them
|
|
308
|
+
const query = await this.bindQuery(unwrappedQueryPayload, unwrappedPayloads)
|
|
309
|
+
|
|
310
|
+
// Send them off
|
|
311
|
+
const result = await this.module.query(query[0], query[1])
|
|
312
|
+
|
|
313
|
+
this.throwErrors(query, result)
|
|
314
|
+
return result[1]
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
protected throwErrors(query: [XyoQueryBoundWitness, XyoPayloads], result: ModuleQueryResult | undefined) {
|
|
318
|
+
const errors = this.filterErrors(query, result)
|
|
319
|
+
if (errors?.length > 0) {
|
|
320
|
+
const error: WrapperError = {
|
|
321
|
+
errors,
|
|
322
|
+
message: errors.reduce((message, error) => `${message}${message.length > 0 ? '|' : ''}${error?.message}`, ''),
|
|
323
|
+
name: 'XyoError',
|
|
324
|
+
query,
|
|
325
|
+
result,
|
|
326
|
+
}
|
|
327
|
+
throw error
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { assertEx } from '@xylabs/assert'
|
|
2
|
+
import { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'
|
|
3
|
+
import { XyoQuery, XyoQueryBoundWitness, XyoQueryBoundWitnessSchema } from '@xyo-network/module-model'
|
|
4
|
+
import { PayloadSetPayload } from '@xyo-network/payload-model'
|
|
5
|
+
import { PayloadWrapper } from '@xyo-network/payload-wrapper'
|
|
6
|
+
|
|
7
|
+
export class QueryBoundWitnessBuilder<
|
|
8
|
+
TBoundWitness extends XyoQueryBoundWitness = XyoQueryBoundWitness,
|
|
9
|
+
TQuery extends XyoQuery = XyoQuery,
|
|
10
|
+
> extends BoundWitnessBuilder<TBoundWitness> {
|
|
11
|
+
private _query: PayloadWrapper<TQuery> | undefined
|
|
12
|
+
private _resultSet: PayloadWrapper<PayloadSetPayload> | undefined
|
|
13
|
+
|
|
14
|
+
override hashableFields(): TBoundWitness {
|
|
15
|
+
return { ...super.hashableFields(), query: assertEx(this._query?.hash, 'No Query Specified'), schema: XyoQueryBoundWitnessSchema }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
query<T extends TQuery | PayloadWrapper<TQuery>>(query: T) {
|
|
19
|
+
this._query = PayloadWrapper.parse(query)
|
|
20
|
+
this.payload(this._query.payload)
|
|
21
|
+
return this
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
resultSet<T extends PayloadSetPayload | PayloadWrapper<PayloadSetPayload>>(payloadSet: T) {
|
|
25
|
+
this._resultSet = PayloadWrapper.parse(payloadSet)
|
|
26
|
+
this.payload(this._resultSet.payload)
|
|
27
|
+
return this
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { BoundWitnessValidator } from '@xyo-network/boundwitness-validator'
|
|
2
|
+
import { XyoQuery, XyoQueryBoundWitness, XyoQueryBoundWitnessSchema } from '@xyo-network/module-model'
|
|
3
|
+
import { PayloadWrapper } from '@xyo-network/payload-wrapper'
|
|
4
|
+
|
|
5
|
+
import { QueryBoundWitnessWrapper } from './QueryBoundWitnessWrapper'
|
|
6
|
+
|
|
7
|
+
export class QueryBoundWitnessValidator<T extends XyoQuery = XyoQuery> extends BoundWitnessValidator<XyoQueryBoundWitness> {
|
|
8
|
+
private _query: PayloadWrapper<T> | undefined
|
|
9
|
+
|
|
10
|
+
protected override get expectedSchema(): string {
|
|
11
|
+
return XyoQueryBoundWitnessSchema
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static isQueryBoundWitnessValidator(obj: unknown) {
|
|
15
|
+
return (obj as QueryBoundWitnessValidator)?.constructor === QueryBoundWitnessValidator
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override validate() {
|
|
19
|
+
return [
|
|
20
|
+
...super.validate(),
|
|
21
|
+
// ...this.validateResultSet()
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
validateResultSet() {
|
|
26
|
+
const errors: Error[] = []
|
|
27
|
+
const wrapper = new QueryBoundWitnessWrapper(this.obj)
|
|
28
|
+
const required = wrapper.resultSet.payload.required
|
|
29
|
+
if (required) {
|
|
30
|
+
Object.entries(required).forEach(([key, value]) => {
|
|
31
|
+
const found = wrapper.payloadSchemas.reduce((count, schema) => {
|
|
32
|
+
return count + (schema === key ? 1 : 0)
|
|
33
|
+
}, 0)
|
|
34
|
+
if (found !== value) {
|
|
35
|
+
errors.push(Error(`validateResultSet: Missing Schema [${key}:${found}:${value}]`))
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
return errors
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { assertEx } from '@xylabs/assert'
|
|
2
|
+
import { BoundWitnessWrapper } from '@xyo-network/boundwitness-wrapper'
|
|
3
|
+
import { XyoQuery, XyoQueryBoundWitness } from '@xyo-network/module-model'
|
|
4
|
+
import { PayloadSetPayload, XyoPayloads } from '@xyo-network/payload-model'
|
|
5
|
+
import { PayloadWrapper } from '@xyo-network/payload-wrapper'
|
|
6
|
+
|
|
7
|
+
import { QueryBoundWitnessValidator } from './QueryBoundWitnessValidator'
|
|
8
|
+
|
|
9
|
+
export class QueryBoundWitnessWrapper<T extends XyoQuery = XyoQuery> extends BoundWitnessWrapper<XyoQueryBoundWitness> {
|
|
10
|
+
private _query: PayloadWrapper<T> | undefined
|
|
11
|
+
private _resultSet: PayloadWrapper<PayloadSetPayload> | undefined
|
|
12
|
+
|
|
13
|
+
private isQueryBoundWitnessWrapper = true
|
|
14
|
+
|
|
15
|
+
override get errors() {
|
|
16
|
+
return new QueryBoundWitnessValidator(this.boundwitness).validate()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get query() {
|
|
20
|
+
return assertEx(
|
|
21
|
+
(this._query =
|
|
22
|
+
this._query ?? this.payloads[this.boundwitness.query] ? PayloadWrapper.parse<T>(this.payloads[this.boundwitness.query]) : undefined),
|
|
23
|
+
`Missing Query [${this.boundwitness}, ${JSON.stringify(this.payloads, null, 2)}]`,
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get resultSet() {
|
|
28
|
+
const resultSetHash = this.boundwitness.resultSet
|
|
29
|
+
return assertEx(
|
|
30
|
+
(this._resultSet =
|
|
31
|
+
this._resultSet ??
|
|
32
|
+
(resultSetHash
|
|
33
|
+
? this.payloads[resultSetHash]
|
|
34
|
+
? PayloadWrapper.parse<PayloadSetPayload>(this.payloads[resultSetHash])
|
|
35
|
+
: undefined
|
|
36
|
+
: undefined)),
|
|
37
|
+
`Missing resultSet [${resultSetHash}, ${JSON.stringify(this.payloads, null, 2)}]`,
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static parseQuery<T extends XyoQuery = XyoQuery>(obj: unknown, payloads?: XyoPayloads): QueryBoundWitnessWrapper<T> {
|
|
42
|
+
assertEx(!Array.isArray(obj), 'Array can not be converted to QueryBoundWitnessWrapper')
|
|
43
|
+
switch (typeof obj) {
|
|
44
|
+
case 'object': {
|
|
45
|
+
const castWrapper = obj as QueryBoundWitnessWrapper<T>
|
|
46
|
+
const wrapper = castWrapper?.isQueryBoundWitnessWrapper ? castWrapper : new QueryBoundWitnessWrapper<T>(obj as XyoQueryBoundWitness, payloads)
|
|
47
|
+
if (!wrapper.valid) {
|
|
48
|
+
console.warn(`Parsed invalid QueryBoundWitness ${JSON.stringify(wrapper.errors.map((error) => error.message))}`)
|
|
49
|
+
}
|
|
50
|
+
return wrapper
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
throw Error(`Unable to parse [${typeof obj}]`)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { AddressString, AnyConfigSchema, CosigningAddressSet, ModuleConfig, ModuleQuery, SchemaString } from '@xyo-network/module-model'
|
|
2
|
+
|
|
3
|
+
import { QueryBoundWitnessWrapper } from '../Query'
|
|
4
|
+
import { Queryable, QueryValidator } from './QueryValidator'
|
|
5
|
+
|
|
6
|
+
export type SortedPipedAddressesString = string
|
|
7
|
+
|
|
8
|
+
const delimiter = ''
|
|
9
|
+
|
|
10
|
+
export class ModuleConfigQueryValidator<TConfig extends AnyConfigSchema<ModuleConfig>> implements QueryValidator {
|
|
11
|
+
protected allowed: Record<SchemaString, SortedPipedAddressesString[]> = {}
|
|
12
|
+
protected disallowed: Record<SchemaString, AddressString[]> = {}
|
|
13
|
+
protected readonly hasAllowedRules: boolean
|
|
14
|
+
protected readonly hasDisallowedRules: boolean
|
|
15
|
+
protected readonly hasRules: boolean
|
|
16
|
+
|
|
17
|
+
constructor(config?: TConfig) {
|
|
18
|
+
if (config?.security?.allowed) {
|
|
19
|
+
Object.entries(config.security?.allowed).forEach(([schema, addresses]) => {
|
|
20
|
+
this.allowed[schema] = addresses.map(toAddressesString)
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
if (config?.security?.disallowed) {
|
|
24
|
+
Object.entries(config.security?.disallowed).forEach(([schema, addresses]) => {
|
|
25
|
+
this.disallowed[schema] = addresses.map(toAddressesString)
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
this.hasAllowedRules = Object.keys(this.allowed).length > 0
|
|
29
|
+
this.hasDisallowedRules = Object.keys(this.disallowed).length > 0
|
|
30
|
+
this.hasRules = this.hasAllowedRules || this.hasDisallowedRules
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
queryable: Queryable = (query, payloads) => {
|
|
34
|
+
if (!this.hasRules) return true
|
|
35
|
+
const addresses = query.addresses
|
|
36
|
+
if (!addresses.length) return false
|
|
37
|
+
const wrapper = QueryBoundWitnessWrapper.parseQuery<ModuleQuery>(query, payloads)
|
|
38
|
+
const schema = wrapper.query.schema
|
|
39
|
+
return this.queryAllowed(schema, addresses) && !this.queryDisallowed(schema, addresses)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
protected queryAllowed = (schema: SchemaString, addresses: string[]): boolean => {
|
|
43
|
+
if (!this.hasAllowedRules) return true
|
|
44
|
+
// All cosigners must sign
|
|
45
|
+
if (addresses.length > 1) {
|
|
46
|
+
const signatories = toAddressesString(addresses)
|
|
47
|
+
const validCosigners = this.allowed?.[schema]?.includes(signatories)
|
|
48
|
+
if (validCosigners) return true
|
|
49
|
+
}
|
|
50
|
+
// OR all signers have to be allowed individually
|
|
51
|
+
return addresses.every((address) => this.allowed?.[schema]?.includes(address) || false)
|
|
52
|
+
}
|
|
53
|
+
protected queryDisallowed = (schema: SchemaString, addresses: string[]): boolean => {
|
|
54
|
+
if (!this.hasDisallowedRules) return false
|
|
55
|
+
return addresses.some((address) => this.disallowed?.[schema]?.includes(address))
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// TODO: Handle 0x prefix
|
|
60
|
+
const toAddressesString = (addresses: string | CosigningAddressSet): SortedPipedAddressesString => {
|
|
61
|
+
return Array.isArray(addresses)
|
|
62
|
+
? addresses
|
|
63
|
+
.sort()
|
|
64
|
+
.map((address) => address.toLowerCase())
|
|
65
|
+
.join(delimiter)
|
|
66
|
+
: addresses.toLowerCase()
|
|
67
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { XyoQueryBoundWitness } from '@xyo-network/module-model'
|
|
2
|
+
import { XyoPayload } from '@xyo-network/payload-model'
|
|
3
|
+
|
|
4
|
+
export type Queryable<T extends XyoQueryBoundWitness = XyoQueryBoundWitness> = (query: T, payloads?: XyoPayload[]) => boolean
|
|
5
|
+
|
|
6
|
+
export interface QueryValidator<T extends XyoQueryBoundWitness = XyoQueryBoundWitness> {
|
|
7
|
+
queryable: Queryable<T>
|
|
8
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Module, ModuleQuery, XyoQueryBoundWitness } from '@xyo-network/module-model'
|
|
2
|
+
import { XyoPayload } from '@xyo-network/payload-model'
|
|
3
|
+
|
|
4
|
+
import { QueryBoundWitnessWrapper } from '../Query'
|
|
5
|
+
import { Queryable, QueryValidator } from './QueryValidator'
|
|
6
|
+
|
|
7
|
+
export const isQuerySupportedByModule = <T extends XyoQueryBoundWitness = XyoQueryBoundWitness>(
|
|
8
|
+
mod: Module,
|
|
9
|
+
query: T,
|
|
10
|
+
payloads?: XyoPayload[],
|
|
11
|
+
): boolean => {
|
|
12
|
+
const wrapper = QueryBoundWitnessWrapper.parseQuery<ModuleQuery>(query, payloads)
|
|
13
|
+
const schema = wrapper.query.schema
|
|
14
|
+
return mod.queries.includes(schema)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class SupportedQueryValidator implements QueryValidator {
|
|
18
|
+
constructor(protected readonly mod: Module) {}
|
|
19
|
+
queryable: Queryable = (query, payloads) => {
|
|
20
|
+
return isQuerySupportedByModule(this.mod, query, payloads)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { fulfilled } from '@xylabs/promise'
|
|
2
|
+
import { Module, ModuleFilter, ModuleRepository, ModuleResolver } from '@xyo-network/module-model'
|
|
3
|
+
|
|
4
|
+
import { duplicateModules } from '../lib'
|
|
5
|
+
import { SimpleModuleResolver } from './SimpleModuleResolver'
|
|
6
|
+
|
|
7
|
+
export class CompositeModuleResolver implements ModuleRepository, ModuleResolver {
|
|
8
|
+
protected resolvers: ModuleResolver[] = []
|
|
9
|
+
private localResolver: SimpleModuleResolver
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
const localResolver = new SimpleModuleResolver()
|
|
13
|
+
this.addResolver(localResolver)
|
|
14
|
+
this.localResolver = localResolver
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
get isModuleResolver() {
|
|
18
|
+
return true
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
add(module: Module): this
|
|
22
|
+
add(module: Module[]): this
|
|
23
|
+
add(module: Module | Module[]): this {
|
|
24
|
+
if (Array.isArray(module)) {
|
|
25
|
+
module.forEach((module) => this.addSingleModule(module))
|
|
26
|
+
} else {
|
|
27
|
+
this.addSingleModule(module)
|
|
28
|
+
}
|
|
29
|
+
return this
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
addResolver(resolver: ModuleResolver): this {
|
|
33
|
+
this.resolvers.push(resolver)
|
|
34
|
+
return this
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
remove(addressOrName: string | string[]): this {
|
|
38
|
+
if (Array.isArray(addressOrName)) {
|
|
39
|
+
addressOrName.forEach((address) => this.removeSingleModule(address))
|
|
40
|
+
} else {
|
|
41
|
+
this.removeSingleModule(addressOrName)
|
|
42
|
+
}
|
|
43
|
+
return this
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
removeResolver(resolver: ModuleResolver): this {
|
|
47
|
+
this.resolvers = this.resolvers.filter((item) => item !== resolver)
|
|
48
|
+
return this
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async resolve<T extends Module = Module>(filter?: ModuleFilter): Promise<T[]> {
|
|
52
|
+
const modules = this.resolvers.map((resolver) => resolver.resolve(filter))
|
|
53
|
+
const settled = await Promise.allSettled(modules)
|
|
54
|
+
const result = settled
|
|
55
|
+
.filter(fulfilled)
|
|
56
|
+
.map((r) => r.value)
|
|
57
|
+
.flat()
|
|
58
|
+
.filter(duplicateModules)
|
|
59
|
+
return result as T[]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private addSingleModule(module?: Module) {
|
|
63
|
+
if (module) {
|
|
64
|
+
this.localResolver.add(module)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
private removeSingleModule(addressOrName: string) {
|
|
68
|
+
this.localResolver.remove(addressOrName)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Module, ModuleFilter, ModuleResolver } from '@xyo-network/module-model'
|
|
2
|
+
|
|
3
|
+
export interface ModuleResolvedEventArgs {
|
|
4
|
+
filter?: ModuleFilter
|
|
5
|
+
module: Module
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ResolverEventEmitter {
|
|
9
|
+
on(event: 'moduleResolved', listener: (args: ModuleResolvedEventArgs) => void): void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type ListenerFunction = (args: ModuleResolvedEventArgs) => void
|
|
13
|
+
|
|
14
|
+
const getMixin = <T extends ModuleResolver = ModuleResolver>(resolver: T) => {
|
|
15
|
+
const listeners: ListenerFunction[] = []
|
|
16
|
+
const emit = (event: 'moduleResolved', args: ModuleResolvedEventArgs): boolean => {
|
|
17
|
+
if (listeners.length < 1) return false
|
|
18
|
+
listeners.map((listener) => listener(args))
|
|
19
|
+
return true
|
|
20
|
+
}
|
|
21
|
+
const onModuleResolved = (module: Module, filter?: ModuleFilter) => {
|
|
22
|
+
const args = { filter, module }
|
|
23
|
+
emit('moduleResolved', args)
|
|
24
|
+
}
|
|
25
|
+
const { resolve } = resolver
|
|
26
|
+
function originalResolve(filter?: ModuleFilter) {
|
|
27
|
+
return resolve.bind(resolver)(filter)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
on: (event: 'moduleResolved', listener: (args: ModuleResolvedEventArgs) => void) => {
|
|
32
|
+
listeners.push(listener)
|
|
33
|
+
},
|
|
34
|
+
resolve: async (filter?: ModuleFilter): Promise<Module[]> => {
|
|
35
|
+
const modules: Module[] = await originalResolve(filter)
|
|
36
|
+
await Promise.allSettled(modules.map((mod) => onModuleResolved(mod, filter)))
|
|
37
|
+
return modules
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const mixinResolverEventEmitter = <T extends ModuleResolver = ModuleResolver>(resolver: T): T & ResolverEventEmitter => {
|
|
43
|
+
const mixin = getMixin(resolver)
|
|
44
|
+
const ret = Object.assign(resolver, mixin)
|
|
45
|
+
return ret
|
|
46
|
+
}
|