@xyo-network/module-abstract 5.3.22 → 5.3.24
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/package.json +41 -45
- package/src/AbstractModule.ts +0 -672
- package/src/AbstractModuleInstance.ts +0 -357
- package/src/Error.ts +0 -44
- package/src/LoggerModuleStatusReporter.ts +0 -21
- package/src/QueryValidator/ModuleConfigQueryValidator.ts +0 -75
- package/src/QueryValidator/QueryValidator.ts +0 -9
- package/src/QueryValidator/SupportedQueryValidator.ts +0 -27
- package/src/QueryValidator/index.ts +0 -3
- package/src/determineAccount.ts +0 -53
- package/src/index.ts +0 -5
|
@@ -1,357 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Address, Promisable,
|
|
3
|
-
TypeCheck,
|
|
4
|
-
TypedValue,
|
|
5
|
-
} from '@xylabs/sdk-js'
|
|
6
|
-
import {
|
|
7
|
-
exists, globallyUnique, isDefined,
|
|
8
|
-
} from '@xylabs/sdk-js'
|
|
9
|
-
import type { AccountInstance } from '@xyo-network/account-model'
|
|
10
|
-
import type { ArchivistInstance } from '@xyo-network/archivist-model'
|
|
11
|
-
import { asArchivistInstance } from '@xyo-network/archivist-model'
|
|
12
|
-
import type { ModuleManifestPayload } from '@xyo-network/manifest-model'
|
|
13
|
-
import { ModuleManifestPayloadSchema } from '@xyo-network/manifest-model'
|
|
14
|
-
import type {
|
|
15
|
-
AddressPayload,
|
|
16
|
-
AddressPreviousHashPayload,
|
|
17
|
-
AttachableModuleInstance,
|
|
18
|
-
ModuleEventData,
|
|
19
|
-
ModuleFilterOptions,
|
|
20
|
-
ModuleIdentifier,
|
|
21
|
-
ModuleInstance,
|
|
22
|
-
ModuleInstanceParams,
|
|
23
|
-
ModuleManifestQuery,
|
|
24
|
-
ModuleName,
|
|
25
|
-
ModuleNameResolver,
|
|
26
|
-
ModuleQueryResult,
|
|
27
|
-
ModuleStateQuery,
|
|
28
|
-
ObjectFilterOptions,
|
|
29
|
-
ResolveHelperConfig,
|
|
30
|
-
} from '@xyo-network/module-model'
|
|
31
|
-
import {
|
|
32
|
-
duplicateModules,
|
|
33
|
-
ModuleManifestQuerySchema,
|
|
34
|
-
ModuleStateQuerySchema,
|
|
35
|
-
resolveAll,
|
|
36
|
-
resolveAllDown,
|
|
37
|
-
resolveAllUp,
|
|
38
|
-
ResolveHelper,
|
|
39
|
-
resolvePathToInstance,
|
|
40
|
-
} from '@xyo-network/module-model'
|
|
41
|
-
import { CompositeModuleResolver } from '@xyo-network/module-resolver'
|
|
42
|
-
import type { NodeInstance } from '@xyo-network/node-model'
|
|
43
|
-
import { asNodeInstance } from '@xyo-network/node-model'
|
|
44
|
-
import type { Payload, Query } from '@xyo-network/payload-model'
|
|
45
|
-
|
|
46
|
-
import { AbstractModule } from './AbstractModule.ts'
|
|
47
|
-
|
|
48
|
-
function filterIdentity<T extends TypedValue>(mod?: ModuleInstance, identityFunc?: TypeCheck<T>): T
|
|
49
|
-
function filterIdentity<T extends TypedValue>(mods?: ModuleInstance[], identityFunc?: TypeCheck<T>): T[]
|
|
50
|
-
function filterIdentity<T extends TypedValue>(mod?: ModuleInstance | ModuleInstance[], identityFunc?: TypeCheck<T>) {
|
|
51
|
-
if (Array.isArray(mod)) {
|
|
52
|
-
if (identityFunc) {
|
|
53
|
-
return mod.map(m => identityFunc(m)).filter(exists)
|
|
54
|
-
}
|
|
55
|
-
return mod
|
|
56
|
-
}
|
|
57
|
-
return (mod ? (identityFunc ? identityFunc(mod) : true) : false) ? mod : undefined
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export abstract class AbstractModuleInstance<TParams extends ModuleInstanceParams = ModuleInstanceParams, TEventData extends ModuleEventData = ModuleEventData>
|
|
61
|
-
extends AbstractModule<TParams, TEventData>
|
|
62
|
-
implements AttachableModuleInstance<TParams, TEventData>, ModuleNameResolver {
|
|
63
|
-
static override readonly uniqueName = globallyUnique('AbstractModuleInstance', AbstractModuleInstance, 'xyo')
|
|
64
|
-
|
|
65
|
-
// switches between old and new resolution system
|
|
66
|
-
static readonly useNewResolver = false
|
|
67
|
-
|
|
68
|
-
private _downResolver?: CompositeModuleResolver
|
|
69
|
-
private _parents: NodeInstance[] = []
|
|
70
|
-
private _privateResolver?: CompositeModuleResolver
|
|
71
|
-
private _upResolver?: CompositeModuleResolver
|
|
72
|
-
|
|
73
|
-
get downResolver() {
|
|
74
|
-
this._downResolver
|
|
75
|
-
= this._downResolver
|
|
76
|
-
?? new CompositeModuleResolver({
|
|
77
|
-
allowNameResolution: this.allowNameResolution,
|
|
78
|
-
moduleIdentifierTransformers: this.params.moduleIdentifierTransformers,
|
|
79
|
-
root: this,
|
|
80
|
-
})
|
|
81
|
-
return this._downResolver
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
override get modName() {
|
|
85
|
-
return super.modName
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
get moduleIdentifierTransformers() {
|
|
89
|
-
return this.params.moduleIdentifierTransformers ?? ResolveHelper.transformers
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
get privateResolver() {
|
|
93
|
-
this._privateResolver
|
|
94
|
-
= this._privateResolver
|
|
95
|
-
?? new CompositeModuleResolver({
|
|
96
|
-
allowNameResolution: this.allowNameResolution,
|
|
97
|
-
moduleIdentifierTransformers: this.params.moduleIdentifierTransformers,
|
|
98
|
-
root: this,
|
|
99
|
-
})
|
|
100
|
-
return this._privateResolver
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
get root() {
|
|
104
|
-
return this
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
get timeBudget() {
|
|
108
|
-
return this.config.timeBudget
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
get upResolver() {
|
|
112
|
-
this._upResolver
|
|
113
|
-
= this._upResolver
|
|
114
|
-
?? new CompositeModuleResolver({
|
|
115
|
-
allowNameResolution: this.allowNameResolution,
|
|
116
|
-
moduleIdentifierTransformers: this.params.moduleIdentifierTransformers,
|
|
117
|
-
root: this,
|
|
118
|
-
})
|
|
119
|
-
return this._upResolver
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
addParent(mod: ModuleInstance) {
|
|
123
|
-
const existingEntry = this._parents.find(parent => parent.address === mod.address)
|
|
124
|
-
if (!existingEntry) {
|
|
125
|
-
this._parents.push(asNodeInstance(mod, 'Only NodeInstances can be parents', { required: true }))
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
async certifyParents(): Promise<Payload[]> {
|
|
130
|
-
const parents = await this.parents()
|
|
131
|
-
return (
|
|
132
|
-
await Promise.all(
|
|
133
|
-
parents.map(async (parent) => {
|
|
134
|
-
const [bw, payloads, errors] = await parent.certifyQuery(this.address)
|
|
135
|
-
return errors.length === 0 ? [bw, ...payloads] : []
|
|
136
|
-
}),
|
|
137
|
-
)
|
|
138
|
-
).flat()
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
override async createHandler() {
|
|
142
|
-
await super.createHandler()
|
|
143
|
-
const addToResolvers = this.params.addToResolvers ?? true
|
|
144
|
-
if (addToResolvers) {
|
|
145
|
-
this.upResolver.add(this)
|
|
146
|
-
this.downResolver.add(this)
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
manifest(maxDepth?: number): Promise<ModuleManifestPayload> {
|
|
151
|
-
this._checkDead()
|
|
152
|
-
return this.busy(async () => {
|
|
153
|
-
return await this.manifestHandler(maxDepth)
|
|
154
|
-
})
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
async manifestQuery(account: AccountInstance, maxDepth?: number): Promise<ModuleQueryResult<ModuleManifestPayload>> {
|
|
158
|
-
const queryPayload: ModuleManifestQuery = { schema: ModuleManifestQuerySchema, ...(maxDepth === undefined ? {} : { maxDepth }) }
|
|
159
|
-
return await this.sendQueryRaw<ModuleManifestQuery, Payload, ModuleManifestPayload>(queryPayload, undefined, account)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
moduleAddress(): Promise<(AddressPayload | AddressPreviousHashPayload)[]> {
|
|
163
|
-
this._checkDead()
|
|
164
|
-
return this.busy(async () => {
|
|
165
|
-
return await this.moduleAddressHandler()
|
|
166
|
-
})
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
parents(): Promisable<NodeInstance[]> {
|
|
170
|
-
return this._parents
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
privateChildren(): Promisable<ModuleInstance[]> {
|
|
174
|
-
return [...this.params.privateChildren ?? []]
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
publicChildren(): Promisable<ModuleInstance[]> {
|
|
178
|
-
return [...this.params.publicChildren ?? []]
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
removeParent(address: Address) {
|
|
182
|
-
this._parents = this._parents.filter(item => item.address !== address)
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
async resolve(): Promise<ModuleInstance[]>
|
|
186
|
-
async resolve<T extends ModuleInstance = ModuleInstance>(all: '*', options?: ModuleFilterOptions<T>): Promise<T[]>
|
|
187
|
-
async resolve<T extends ModuleInstance = ModuleInstance>(id: ModuleIdentifier, options?: ModuleFilterOptions<T>): Promise<T | undefined>
|
|
188
|
-
async resolve<T extends ModuleInstance = ModuleInstance>(
|
|
189
|
-
id: ModuleIdentifier = '*',
|
|
190
|
-
options: ModuleFilterOptions<T> = {},
|
|
191
|
-
): Promise<T | T[] | undefined> {
|
|
192
|
-
if (AbstractModuleInstance.useNewResolver) {
|
|
193
|
-
if (id === '*') {
|
|
194
|
-
const { maxDepth = 10, direction } = options
|
|
195
|
-
if (direction === 'down') {
|
|
196
|
-
return filterIdentity<T>((await resolveAllDown(this, maxDepth)) ?? [], options.identity)
|
|
197
|
-
}
|
|
198
|
-
if (direction === 'up') {
|
|
199
|
-
return filterIdentity<T>(await resolveAllUp(this, maxDepth) ?? [], options.identity)
|
|
200
|
-
}
|
|
201
|
-
return filterIdentity<T>(await resolveAll(this, maxDepth) ?? [], options.identity)
|
|
202
|
-
} else if (typeof id === 'string') {
|
|
203
|
-
return filterIdentity<T>(await resolvePathToInstance(this, id, true), options.identity)
|
|
204
|
-
} else {
|
|
205
|
-
throw new TypeError('Invalid id type')
|
|
206
|
-
}
|
|
207
|
-
} else {
|
|
208
|
-
const config: ResolveHelperConfig = {
|
|
209
|
-
address: this.address,
|
|
210
|
-
dead: this.dead,
|
|
211
|
-
downResolver: this.downResolver,
|
|
212
|
-
logger: this.logger,
|
|
213
|
-
mod: this,
|
|
214
|
-
transformers: this.moduleIdentifierTransformers,
|
|
215
|
-
upResolver: this.upResolver,
|
|
216
|
-
}
|
|
217
|
-
if (id === '*') {
|
|
218
|
-
return filterIdentity<T>(await ResolveHelper.resolve(config, '*', options) ?? [], options.identity)
|
|
219
|
-
}
|
|
220
|
-
return filterIdentity<T>(await ResolveHelper.resolve(config, id, options), options.identity)
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
resolveIdentifier(id: ModuleIdentifier, options?: ObjectFilterOptions): Promise<Address | undefined> {
|
|
225
|
-
const { direction = 'all' } = options ?? {}
|
|
226
|
-
switch (direction) {
|
|
227
|
-
case 'down': {
|
|
228
|
-
return this.downResolver.resolveIdentifier(id, options)
|
|
229
|
-
}
|
|
230
|
-
default: {
|
|
231
|
-
const mutatedOptions = { ...options, direction: 'all' } as ObjectFilterOptions
|
|
232
|
-
return this.upResolver.resolveIdentifier(id, mutatedOptions)
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
async resolvePrivate<T extends ModuleInstance = ModuleInstance>(all: '*', options?: ModuleFilterOptions<T>): Promise<T[]>
|
|
238
|
-
async resolvePrivate<T extends ModuleInstance = ModuleInstance>(id: ModuleIdentifier, options?: ModuleFilterOptions<T>): Promise<T | undefined>
|
|
239
|
-
async resolvePrivate<T extends ModuleInstance = ModuleInstance>(
|
|
240
|
-
id: ModuleIdentifier = '*',
|
|
241
|
-
options: ModuleFilterOptions<T> = {},
|
|
242
|
-
): Promise<T | T[] | undefined> {
|
|
243
|
-
return (
|
|
244
|
-
(await this.privateResolver.resolve(id, options))
|
|
245
|
-
?? (await this.upResolver.resolve(id, options))
|
|
246
|
-
?? (await this.downResolver.resolve(id, options))
|
|
247
|
-
)
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
async siblings(): Promise<ModuleInstance[]> {
|
|
251
|
-
return (await Promise.all((await this.parents()).map(parent => parent.publicChildren()))).flat().filter(duplicateModules)
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
state() {
|
|
255
|
-
this._checkDead()
|
|
256
|
-
return this.busy(async () => {
|
|
257
|
-
return await this.stateHandler()
|
|
258
|
-
})
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
async stateQuery(account: AccountInstance): Promise<ModuleQueryResult> {
|
|
262
|
-
const queryPayload: ModuleStateQuery = { schema: ModuleStateQuerySchema }
|
|
263
|
-
return await this.sendQueryRaw(queryPayload, undefined, account)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
subscribe(_queryAccount?: AccountInstance) {
|
|
267
|
-
this._checkDead()
|
|
268
|
-
return this.subscribeHandler()
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
protected override async manifestHandler(maxDepth: number = 1, _ignoreAddresses: Address[] = []): Promise<ModuleManifestPayload> {
|
|
272
|
-
const cachedResult = this._cachedManifests.get(maxDepth)
|
|
273
|
-
if (cachedResult) {
|
|
274
|
-
return cachedResult
|
|
275
|
-
}
|
|
276
|
-
const modName = this.modName ?? '<Anonymous>'
|
|
277
|
-
const children = await this.publicChildren()
|
|
278
|
-
const childAddressToName: Record<Address, ModuleName | null> = {}
|
|
279
|
-
for (const child of children) {
|
|
280
|
-
if (child.address !== this.address) {
|
|
281
|
-
childAddressToName[child.address] = child.modName ?? null
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
const result = {
|
|
285
|
-
config: { name: modName, ...this.config },
|
|
286
|
-
name: modName,
|
|
287
|
-
schema: ModuleManifestPayloadSchema,
|
|
288
|
-
status: { address: this.address, children: childAddressToName },
|
|
289
|
-
}
|
|
290
|
-
this._cachedManifests.set(maxDepth, result)
|
|
291
|
-
return result
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
protected async resolveArchivingArchivists(): Promise<ArchivistInstance[]> {
|
|
295
|
-
const archivists = this.archiving?.archivists
|
|
296
|
-
if (!archivists) return []
|
|
297
|
-
const resolved = await Promise.all(archivists.map(archivist => this.resolve(archivist)))
|
|
298
|
-
return (resolved.map(mod => asArchivistInstance(mod))).filter(exists)
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
protected async sendQuery<T extends Query, P extends Payload = Payload, R extends Payload = Payload>(
|
|
302
|
-
queryPayload: T,
|
|
303
|
-
payloads?: P[],
|
|
304
|
-
account?: AccountInstance,
|
|
305
|
-
): Promise<R[]> {
|
|
306
|
-
const queryResults = await this.sendQueryRaw(queryPayload, payloads, account)
|
|
307
|
-
const [, resultPayloads, errors] = queryResults
|
|
308
|
-
|
|
309
|
-
/* TODO: Figure out what to do with the returning BW. Should we store them in a queue in case the caller wants to see them? */
|
|
310
|
-
|
|
311
|
-
if (isDefined(errors) && errors.length > 0) {
|
|
312
|
-
/* TODO: Figure out how to rollup multiple Errors */
|
|
313
|
-
throw errors[0]
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
return resultPayloads as R[]
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
protected async sendQueryRaw<T extends Query, P extends Payload = Payload, R extends Payload = Payload>(
|
|
320
|
-
queryPayload: T,
|
|
321
|
-
payloads?: P[],
|
|
322
|
-
account?: AccountInstance,
|
|
323
|
-
): Promise<ModuleQueryResult<R>> {
|
|
324
|
-
// Bind them
|
|
325
|
-
const query = await this.bindQuery(queryPayload, payloads, account, this.additionalSigners)
|
|
326
|
-
|
|
327
|
-
// Send them off
|
|
328
|
-
return (await this.query(query[0], query[1])) as ModuleQueryResult<R>
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
protected override startHandler() {
|
|
332
|
-
this._checkDead()
|
|
333
|
-
return this.busy(async () => {
|
|
334
|
-
if (this.status === 'started' || this.status === 'creating') {
|
|
335
|
-
return
|
|
336
|
-
}
|
|
337
|
-
await super.startHandler()
|
|
338
|
-
})
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
protected async storeToArchivists(payloads: Payload[]): Promise<Payload[]> {
|
|
342
|
-
try {
|
|
343
|
-
const archivists = await this.resolveArchivingArchivists()
|
|
344
|
-
return (
|
|
345
|
-
await Promise.all(
|
|
346
|
-
archivists.map((archivist) => {
|
|
347
|
-
return archivist.insert?.(payloads)
|
|
348
|
-
}),
|
|
349
|
-
)
|
|
350
|
-
).map(([bw]) => bw)
|
|
351
|
-
} catch (ex) {
|
|
352
|
-
const error = ex as Error
|
|
353
|
-
this.logger?.error(`Error storing to archivists: ${error.message}`)
|
|
354
|
-
return []
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
package/src/Error.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { Hash, JsonValue } from '@xylabs/sdk-js'
|
|
2
|
-
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
3
|
-
import type { ModuleError, Schema } from '@xyo-network/payload-model'
|
|
4
|
-
import { ModuleErrorSchema } from '@xyo-network/payload-model'
|
|
5
|
-
|
|
6
|
-
export class ModuleErrorBuilder extends PayloadBuilder<ModuleError> {
|
|
7
|
-
_details?: JsonValue
|
|
8
|
-
_message?: string
|
|
9
|
-
_name?: string
|
|
10
|
-
_query?: Hash | Schema
|
|
11
|
-
constructor() {
|
|
12
|
-
super({ schema: ModuleErrorSchema })
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
override build(): ModuleError {
|
|
16
|
-
this.fields({
|
|
17
|
-
details: this._details,
|
|
18
|
-
message: this._message,
|
|
19
|
-
name: this._name,
|
|
20
|
-
query: this._query,
|
|
21
|
-
})
|
|
22
|
-
return super.build()
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
details(details?: JsonValue) {
|
|
26
|
-
this._details = details
|
|
27
|
-
return this
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
message(message: string) {
|
|
31
|
-
this._message = message
|
|
32
|
-
return this
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
name(name: string) {
|
|
36
|
-
this._name = name
|
|
37
|
-
return this
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
query(query: Hash | Schema) {
|
|
41
|
-
this._query = query
|
|
42
|
-
return this
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CreatableName, CreatableStatus, Logger,
|
|
3
|
-
} from '@xylabs/sdk-js'
|
|
4
|
-
import type { ModuleStatusReporter } from '@xyo-network/module-model'
|
|
5
|
-
|
|
6
|
-
export class LoggerModuleStatusReporter implements ModuleStatusReporter {
|
|
7
|
-
protected logger: Logger
|
|
8
|
-
|
|
9
|
-
protected statusMap: Record<CreatableName, CreatableStatus> = {}
|
|
10
|
-
|
|
11
|
-
constructor(logger: Logger) {
|
|
12
|
-
this.logger = logger
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
report(name: CreatableName, status: CreatableStatus, progress?: number | Error): void {
|
|
16
|
-
this.statusMap[name] = status
|
|
17
|
-
const starting = (Object.entries(this.statusMap).map(([, value]): number => value === 'starting' ? 1 : 0)).reduce((a, b) => a + b, 0)
|
|
18
|
-
const started = (Object.entries(this.statusMap).map(([, value]): number => value === 'started' ? 1 : 0)).reduce((a, b) => a + b, 0)
|
|
19
|
-
this.logger.log(`${started}/${starting + started} ${name} status: ${status}`, { progress })
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import type { Address } from '@xylabs/sdk-js'
|
|
2
|
-
import { QueryBoundWitnessWrapper } from '@xyo-network/boundwitness-wrapper'
|
|
3
|
-
import type {
|
|
4
|
-
AnyConfigSchema, CosigningAddressSet, ModuleConfig, ModuleQueries,
|
|
5
|
-
} from '@xyo-network/module-model'
|
|
6
|
-
import { asSchema, type Schema } from '@xyo-network/payload-model'
|
|
7
|
-
|
|
8
|
-
import type { Queryable, QueryValidator } from './QueryValidator.ts'
|
|
9
|
-
|
|
10
|
-
export type SortedPipedAddressesString = string
|
|
11
|
-
|
|
12
|
-
const delimiter = ''
|
|
13
|
-
|
|
14
|
-
export class ModuleConfigQueryValidator<TConfig extends AnyConfigSchema<ModuleConfig>> implements QueryValidator {
|
|
15
|
-
protected allowed: Record<Schema, SortedPipedAddressesString[]> = {}
|
|
16
|
-
protected disallowed: Record<Schema, SortedPipedAddressesString[]> = {}
|
|
17
|
-
protected readonly hasAllowedRules: boolean
|
|
18
|
-
protected readonly hasDisallowedRules: boolean
|
|
19
|
-
protected readonly hasRules: boolean
|
|
20
|
-
|
|
21
|
-
constructor(config?: TConfig) {
|
|
22
|
-
if (config?.security?.allowed) {
|
|
23
|
-
for (const [schema, addresses] of Object.entries(config.security?.allowed)) {
|
|
24
|
-
const typedSchema = asSchema(schema, true)
|
|
25
|
-
this.allowed[typedSchema] = addresses.map(toAddressesString)
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
if (config?.security?.disallowed) {
|
|
29
|
-
for (const [schema, addresses] of Object.entries(config.security?.disallowed)) {
|
|
30
|
-
const typedSchema = asSchema(schema, true)
|
|
31
|
-
this.disallowed[typedSchema] = addresses.map(toAddressesString)
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
this.hasAllowedRules = Object.keys(this.allowed).length > 0
|
|
35
|
-
this.hasDisallowedRules = Object.keys(this.disallowed).length > 0
|
|
36
|
-
this.hasRules = this.hasAllowedRules || this.hasDisallowedRules
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
queryable: Queryable = async (query, payloads) => {
|
|
40
|
-
if (!this.hasRules) return true
|
|
41
|
-
const addresses = query.addresses
|
|
42
|
-
if (addresses.length === 0) return false
|
|
43
|
-
const wrapper = QueryBoundWitnessWrapper.parseQuery<ModuleQueries>(query, payloads)
|
|
44
|
-
const schema = (await wrapper.getQuery()).schema
|
|
45
|
-
return this.queryAllowed(schema, addresses) && !this.queryDisallowed(schema, addresses)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
protected queryAllowed = (schema: Schema, addresses: Address[]): boolean => {
|
|
49
|
-
if (!this.hasAllowedRules) return true
|
|
50
|
-
// All cosigners must sign
|
|
51
|
-
if (addresses.length > 1) {
|
|
52
|
-
const signatories = toAddressesString(addresses)
|
|
53
|
-
const validCosigners = this.allowed?.[schema]?.includes(signatories)
|
|
54
|
-
if (validCosigners) return true
|
|
55
|
-
}
|
|
56
|
-
// OR all signers have to be allowed individually
|
|
57
|
-
return addresses.every(address => this.allowed?.[schema]?.includes(address) || false)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
protected queryDisallowed = (schema: Schema, addresses: string[]): boolean => {
|
|
61
|
-
if (!this.hasDisallowedRules) return false
|
|
62
|
-
return addresses.some(address => this.disallowed?.[schema]?.includes(address))
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// TODO: Handle 0x prefix
|
|
67
|
-
const toAddressesString = (addresses: string | CosigningAddressSet): SortedPipedAddressesString => {
|
|
68
|
-
return Array.isArray(addresses)
|
|
69
|
-
? addresses
|
|
70
|
-
// eslint-disable-next-line sonarjs/no-alphabetical-sort
|
|
71
|
-
.toSorted()
|
|
72
|
-
.map(address => address.toLowerCase())
|
|
73
|
-
.join(delimiter)
|
|
74
|
-
: addresses.toLowerCase()
|
|
75
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Promisable } from '@xylabs/sdk-js'
|
|
2
|
-
import type { QueryBoundWitness } from '@xyo-network/boundwitness-model'
|
|
3
|
-
import type { Payload } from '@xyo-network/payload-model'
|
|
4
|
-
|
|
5
|
-
export type Queryable<T extends QueryBoundWitness = QueryBoundWitness> = (query: T, payloads?: Payload[]) => Promisable<boolean>
|
|
6
|
-
|
|
7
|
-
export interface QueryValidator<T extends QueryBoundWitness = QueryBoundWitness> {
|
|
8
|
-
queryable: Queryable<T>
|
|
9
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { QueryBoundWitness } from '@xyo-network/boundwitness-model'
|
|
2
|
-
import { QueryBoundWitnessWrapper } from '@xyo-network/boundwitness-wrapper'
|
|
3
|
-
import type { ModuleQueries, QueryableModule } from '@xyo-network/module-model'
|
|
4
|
-
import type { Payload } from '@xyo-network/payload-model'
|
|
5
|
-
|
|
6
|
-
import type { Queryable, QueryValidator } from './QueryValidator.ts'
|
|
7
|
-
|
|
8
|
-
export const isQuerySupportedByModule = async <T extends QueryBoundWitness = QueryBoundWitness>(
|
|
9
|
-
mod: QueryableModule,
|
|
10
|
-
query: T,
|
|
11
|
-
payloads?: Payload[],
|
|
12
|
-
): Promise<boolean> => {
|
|
13
|
-
const wrapper = QueryBoundWitnessWrapper.parseQuery<ModuleQueries>(query, payloads)
|
|
14
|
-
const schema = (await wrapper.getQuery()).schema
|
|
15
|
-
return mod.queries.includes(schema)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export class SupportedQueryValidator implements QueryValidator {
|
|
19
|
-
protected readonly mod: QueryableModule
|
|
20
|
-
constructor(mod: QueryableModule) {
|
|
21
|
-
this.mod = mod
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
queryable: Queryable = (query, payloads) => {
|
|
25
|
-
return isQuerySupportedByModule(this.mod, query, payloads)
|
|
26
|
-
}
|
|
27
|
-
}
|
package/src/determineAccount.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
assertEx,
|
|
3
|
-
isDefined, isString, isUndefined,
|
|
4
|
-
} from '@xylabs/sdk-js'
|
|
5
|
-
import { Account } from '@xyo-network/account'
|
|
6
|
-
import type { AccountInstance } from '@xyo-network/account-model'
|
|
7
|
-
import type { WalletInstance } from '@xyo-network/wallet-model'
|
|
8
|
-
|
|
9
|
-
export interface DetermineAccountFromAccountParams {
|
|
10
|
-
account: AccountInstance | 'random'
|
|
11
|
-
accountPath?: never
|
|
12
|
-
wallet?: never
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface DetermineAccountFromWalletParams {
|
|
16
|
-
account?: never
|
|
17
|
-
accountPath?: string
|
|
18
|
-
wallet: WalletInstance
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface DetermineRandomParams {}
|
|
22
|
-
|
|
23
|
-
export type DetermineAccountParams = DetermineAccountFromAccountParams | DetermineAccountFromWalletParams | DetermineRandomParams
|
|
24
|
-
|
|
25
|
-
const isDetermineAccountFromAccountParams = (params: DetermineAccountParams): params is DetermineAccountFromAccountParams => {
|
|
26
|
-
assertEx(isUndefined((params as DetermineAccountFromWalletParams).accountPath), () => 'accountPath may not be provided when account is provided')
|
|
27
|
-
return isDefined((params as DetermineAccountFromAccountParams).account)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const isDetermineAccountFromWalletParams = (params: DetermineAccountParams): params is DetermineAccountFromWalletParams => {
|
|
31
|
-
return isDefined((params as DetermineAccountFromWalletParams).wallet)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export async function determineAccount(params: DetermineAccountParams, allowRandomAccount = true): Promise<AccountInstance> {
|
|
35
|
-
if (isDetermineAccountFromAccountParams(params)) {
|
|
36
|
-
if (params.account === 'random') {
|
|
37
|
-
assertEx(allowRandomAccount, () => 'Random address not allowed')
|
|
38
|
-
return await Account.random()
|
|
39
|
-
}
|
|
40
|
-
return params.account
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (isDetermineAccountFromWalletParams(params)) {
|
|
44
|
-
return assertEx(
|
|
45
|
-
isString(params.accountPath) ? await params.wallet.derivePath(params.accountPath) : params.wallet,
|
|
46
|
-
() => 'Failed to derive account from path',
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// this should eventually be removed/thrown
|
|
51
|
-
console.warn('AbstractModule.determineAccount: No account or wallet provided - Creating Random account')
|
|
52
|
-
return await Account.random()
|
|
53
|
-
}
|