@xyo-network/module-abstract 2.62.1 → 2.63.0

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.
@@ -47,16 +47,17 @@ import { QueryBoundWitnessBuilder, QueryBoundWitnessWrapper } from './Query'
47
47
  import { ModuleConfigQueryValidator, Queryable, SupportedQueryValidator } from './QueryValidator'
48
48
  import { CompositeModuleResolver } from './Resolver'
49
49
 
50
- // @creatableModule()
51
50
  export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams, TEventData extends ModuleEventData = ModuleEventData>
52
51
  extends BaseEmitter<TParams, TEventData>
53
52
  implements Module<TParams, TEventData>
54
53
  {
55
54
  static configSchema: string
55
+ protected static privateConstructorKey = Date.now().toString()
56
56
 
57
57
  readonly downResolver = new CompositeModuleResolver()
58
58
  readonly upResolver = new CompositeModuleResolver()
59
59
 
60
+ protected _account: AccountInstance | undefined = undefined
60
61
  protected readonly _baseModuleQueryAccountPaths: Record<ModuleQueryBase['schema'], string> = {
61
62
  'network.xyo.query.module.account': '1',
62
63
  'network.xyo.query.module.discover': '2',
@@ -68,29 +69,25 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
68
69
  'network.xyo.query.module.subscribe': undefined,
69
70
  }
70
71
  protected _started = false
71
- protected readonly account: AccountInstance
72
72
  protected readonly moduleConfigQueryValidator: Queryable
73
73
  protected readonly supportedQueryValidator: Queryable
74
74
 
75
- constructor(params: TParams) {
75
+ constructor(privateConstructorKey: string, params: TParams) {
76
+ assertEx(AbstractModule.privateConstructorKey === privateConstructorKey, 'Use create function instead of constructor')
76
77
  // Clone params to prevent mutation of the incoming object
77
78
  const mutatedParams = { ...params } as TParams
78
- const activeLogger = params.logger ?? AbstractModule.defaultLogger
79
- let { account } = mutatedParams as AccountModuleParams<TParams['config']>
80
- const { wallet, accountDerivationPath } = mutatedParams as WalletModuleParams<TParams['config']>
81
- if (wallet) {
82
- account = accountDerivationPath ? wallet.derivePath(accountDerivationPath) : wallet
83
- }
84
- mutatedParams.logger = activeLogger ? new IdLogger(activeLogger, () => `0x${this.account.addressValue.hex}`) : undefined
85
79
  super(mutatedParams)
86
- this.account = this.loadAccount(account)
87
- this.downResolver.add(this as Module)
80
+
88
81
  this.supportedQueryValidator = new SupportedQueryValidator(this as Module).queryable
89
82
  this.moduleConfigQueryValidator = new ModuleConfigQueryValidator(mutatedParams?.config).queryable
90
83
  }
91
84
 
85
+ get account() {
86
+ return assertEx(this._account, 'Missing account')
87
+ }
88
+
92
89
  get address() {
93
- return this.account.addressValue.hex
90
+ return this.account.address
94
91
  }
95
92
 
96
93
  get allowAnonymous() {
@@ -128,7 +125,8 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
128
125
  params?.logger?.debug(`config: ${JSON.stringify(params?.config, null, 2)}`)
129
126
  const mutatedConfig = { ...params?.config, schema } as TModule['params']['config']
130
127
  const mutatedParams = { ...params, config: mutatedConfig } as TModule['params']
131
- const newModule = new this(mutatedParams)
128
+ const newModule = new this(AbstractModule.privateConstructorKey, mutatedParams)
129
+ await newModule.loadAccount?.()
132
130
  await newModule.start?.()
133
131
  return newModule
134
132
  }
@@ -150,6 +148,21 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
150
148
  return compact([config, configSchema, address, ...queries])
151
149
  }
152
150
 
151
+ async loadAccount() {
152
+ if (!this._account) {
153
+ const activeLogger = this.params.logger ?? AbstractModule.defaultLogger
154
+ let { account } = this.params as AccountModuleParams<TParams['config']>
155
+ const { wallet, accountDerivationPath } = this.params as WalletModuleParams<TParams['config']>
156
+ if (wallet) {
157
+ account = assertEx(accountDerivationPath ? await wallet.derivePath?.(accountDerivationPath) : wallet, 'Failed to derive account from path')
158
+ }
159
+ this.params.logger = activeLogger ? new IdLogger(activeLogger, () => `0x${account.addressValue.hex}`) : undefined
160
+ this._account = account ?? Account.random()
161
+ }
162
+ this.downResolver.add(this as Module)
163
+ return this._account
164
+ }
165
+
153
166
  moduleAccountQuery(): Promisable<(AddressPayload | AddressPreviousHashPayload)[]> {
154
167
  // Return array of all addresses and their previous hash
155
168
  const queryAccounts = Object.entries(this.queryAccounts)
@@ -164,9 +177,9 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
164
177
  { address, previousHash, schema: AddressPreviousHashSchema },
165
178
  ]
166
179
  })
167
- const address = this.account.addressValue.hex
180
+ const address = this.address
168
181
  const name = this.config.name
169
- const previousHash = this.account.previousHash?.hex
182
+ const previousHash = this.address
170
183
  const moduleAccount = name ? { address, name, schema: AddressSchema } : { address, schema: AddressSchema }
171
184
  const moduleAccountPreviousHash = previousHash
172
185
  ? { address, previousHash, schema: AddressPreviousHashSchema }
@@ -202,9 +215,9 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
202
215
  return validators.every((validator) => validator(query, payloads))
203
216
  }
204
217
 
205
- start(_timeout?: number): Promisable<void> {
218
+ async start(_timeout?: number): Promise<void> {
206
219
  this.validateConfig()
207
- this.initializeQueryAccounts()
220
+ await this.initializeQueryAccounts()
208
221
  this._started = true
209
222
  }
210
223
 
@@ -272,25 +285,22 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
272
285
  return result
273
286
  }
274
287
 
275
- protected bindQueryResult<T extends Query | PayloadWrapper<Query>>(
288
+ protected async bindQueryResult<T extends Query | PayloadWrapper<Query>>(
276
289
  query: T,
277
290
  payloads: Payload[],
278
291
  additionalWitnesses: AccountInstance[] = [],
279
- ): PromiseEx<ModuleQueryResult, AccountInstance[]> {
292
+ ): Promise<[ModuleQueryResult, AccountInstance[]]> {
280
293
  const builder = new BoundWitnessBuilder().payloads(payloads)
281
294
  const queryWitnessAccount = this.queryAccounts[query.schema as ModuleQueryBase['schema']]
282
295
  const witnesses = [this.account, queryWitnessAccount, ...additionalWitnesses].filter(exists)
283
296
  builder.witnesses(witnesses)
284
- return new PromiseEx<ModuleQueryResult, AccountInstance[]>(async (resolve) => {
285
- const result: ModuleQueryResult = [(await builder.build())[0], payloads]
286
- resolve?.(result)
287
- return result
288
- }, witnesses)
297
+ const result: ModuleQueryResult = [(await builder.build())[0], payloads]
298
+ return [result, witnesses]
289
299
  }
290
300
 
291
301
  protected commitArchivist = () => this.getArchivist('commit')
292
302
 
293
- protected initializeQueryAccounts() {
303
+ protected async initializeQueryAccounts() {
294
304
  // Ensure distinct/unique wallet paths
295
305
  const paths = Object.values(this.queryAccountPaths).filter(exists)
296
306
  const distinctPaths = new Set<string>(paths)
@@ -303,17 +313,13 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
303
313
  const query = key as ModuleQueryBase['schema']
304
314
  const queryAccountPath = this.queryAccountPaths[query]
305
315
  if (queryAccountPath) {
306
- this._queryAccounts[query] = wallet.derivePath(queryAccountPath)
316
+ this._queryAccounts[query] = await wallet.derivePath?.(queryAccountPath)
307
317
  }
308
318
  }
309
319
  }
310
320
  }
311
321
  }
312
322
 
313
- protected loadAccount(account?: AccountInstance): AccountInstance {
314
- return account ?? new Account()
315
- }
316
-
317
323
  protected async queryHandler<T extends QueryBoundWitness = QueryBoundWitness, TConfig extends ModuleConfig = ModuleConfig>(
318
324
  query: T,
319
325
  payloads?: Payload[],
@@ -329,7 +335,7 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
329
335
  const queryPayload = await wrapper.getQuery()
330
336
  assertEx(this.queryable(query, payloads, queryConfig))
331
337
  const resultPayloads: Payload[] = []
332
- const queryAccount = new Account()
338
+ const queryAccount = await Account.random()
333
339
  try {
334
340
  switch (queryPayload.schema) {
335
341
  case ModuleDiscoverQuerySchema: {
@@ -356,7 +362,7 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
356
362
  .build(),
357
363
  )
358
364
  }
359
- return await this.bindQueryResult(queryPayload, resultPayloads, [queryAccount])
365
+ return (await this.bindQueryResult(queryPayload, resultPayloads, [queryAccount]))[0]
360
366
  }
361
367
 
362
368
  protected readArchivist = () => this.getArchivist('read')
@@ -94,7 +94,7 @@ export class SimpleModuleResolver implements ModuleRepository {
94
94
  ? compact(
95
95
  flatten(
96
96
  address?.map((address) => {
97
- return modules.filter((module) => module.address === address)
97
+ return modules.filter((modules) => modules.address === address)
98
98
  }),
99
99
  ),
100
100
  )