@xyo-network/module-abstract 2.92.5 → 2.92.7

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.
@@ -21,6 +21,7 @@ import {
21
21
  AddressPreviousHashSchema,
22
22
  CreatableModule,
23
23
  CreatableModuleFactory,
24
+ DeadModuleError,
24
25
  duplicateModules,
25
26
  isModuleName,
26
27
  Module,
@@ -44,6 +45,7 @@ import {
44
45
  ModuleQueryHandlerResult,
45
46
  ModuleQueryResult,
46
47
  ModuleStateQuerySchema,
48
+ ModuleStatus,
47
49
  ModuleSubscribeQuerySchema,
48
50
  serializableField,
49
51
  } from '@xyo-network/module-model'
@@ -81,6 +83,7 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
81
83
  [ModuleStateQuerySchema]: '6',
82
84
  [ModuleSubscribeQuerySchema]: '3',
83
85
  }
86
+ protected _lastError?: Error
84
87
  protected readonly _queryAccounts: Record<ModuleQueries['schema'], AccountInstance | undefined> = {
85
88
  [ModuleAddressQuerySchema]: undefined,
86
89
  [ModuleDescribeQuerySchema]: undefined,
@@ -95,6 +98,7 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
95
98
  protected readonly supportedQueryValidator: Queryable
96
99
 
97
100
  private _busyCount = 0
101
+ private _status: ModuleStatus = 'stopped'
98
102
 
99
103
  constructor(privateConstructorKey: string, params: TParams, account: AccountInstance) {
100
104
  assertEx(AbstractModule.privateConstructorKey === privateConstructorKey, 'Use create function instead of constructor')
@@ -128,6 +132,10 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
128
132
  return this.params.config
129
133
  }
130
134
 
135
+ get dead() {
136
+ return this.status === 'dead'
137
+ }
138
+
131
139
  get ephemeralQueryAccountEnabled(): boolean {
132
140
  return !!this.params.ephemeralQueryAccountEnabled
133
141
  }
@@ -155,6 +163,10 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
155
163
  return this._queryAccounts
156
164
  }
157
165
 
166
+ get status() {
167
+ return this._status
168
+ }
169
+
158
170
  get timestamp() {
159
171
  return this.config.timestamp ?? false
160
172
  }
@@ -167,6 +179,12 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
167
179
  return this.params?.logger ?? AbstractModule.defaultLogger ?? Base.defaultLogger
168
180
  }
169
181
 
182
+ protected set status(value: ModuleStatus) {
183
+ if (this._status !== 'dead') {
184
+ this._status = value
185
+ }
186
+ }
187
+
170
188
  protected abstract get _queryAccountPaths(): Record<Query['schema'], string>
171
189
 
172
190
  static _getRootFunction(funcName: string) {
@@ -244,14 +262,6 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
244
262
  return anyThis[funcName]
245
263
  }
246
264
 
247
- _noOverride(functionName: string) {
248
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
249
- const thisFunc = (this as any)[functionName]
250
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
251
- const rootFunc = this._getRootFunction(functionName)
252
- assertEx(thisFunc === rootFunc, () => `Override not allowed for [${functionName}] - override ${functionName}Handler instead`)
253
- }
254
-
255
265
  async busy<R>(closure: () => Promise<R>) {
256
266
  if (this._busyCount <= 0) {
257
267
  this._busyCount = 0
@@ -279,6 +289,7 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
279
289
  }
280
290
 
281
291
  previousHash(): Promisable<string | undefined> {
292
+ this._checkDead()
282
293
  return this.account.previousHash
283
294
  }
284
295
 
@@ -287,6 +298,7 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
287
298
  payloads?: Payload[],
288
299
  queryConfig?: TConfig,
289
300
  ): Promise<ModuleQueryResult> {
301
+ this._checkDead()
290
302
  this._noOverride('query')
291
303
  const sourceQuery = await PayloadBuilder.build(assertEx(QueryBoundWitnessWrapper.unwrap(query), 'Invalid query'))
292
304
  return await this.busy(async () => {
@@ -301,6 +313,8 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
301
313
  resultPayloads.push(...(await this.queryHandler(sourceQuery, payloads, queryConfig)))
302
314
  } catch (ex) {
303
315
  await handleErrorAsync(ex, async (error) => {
316
+ this._lastError = error
317
+ this.status = 'dead'
304
318
  errorPayloads.push(
305
319
  await new ModuleErrorBuilder()
306
320
  .sources([sourceQuery.$hash])
@@ -327,6 +341,9 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
327
341
  payloads?: Payload[],
328
342
  queryConfig?: TConfig,
329
343
  ): Promise<boolean> {
344
+ if (this.dead) {
345
+ return false
346
+ }
330
347
  if (!(await this.started('warn'))) return false
331
348
  const configValidator =
332
349
  queryConfig ? new ModuleConfigQueryValidator(Object.assign({}, this.config, queryConfig)).queryable : this.moduleConfigQueryValidator
@@ -348,12 +365,18 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
348
365
  let result: T | T[] | undefined
349
366
  switch (typeof idOrFilter) {
350
367
  case 'string': {
368
+ if (this.dead) {
369
+ return undefined
370
+ }
351
371
  result =
352
372
  (down ? await (this.downResolver as CompositeModuleResolver).resolve<T>(idOrFilter, childOptions) : undefined) ??
353
373
  (up ? await (this.upResolver as CompositeModuleResolver).resolve<T>(idOrFilter, childOptions) : undefined)
354
374
  break
355
375
  }
356
376
  default: {
377
+ if (this.dead) {
378
+ return []
379
+ }
357
380
  const filter: ModuleFilter<T> | undefined = idOrFilter
358
381
  result = [
359
382
  ...(down ? await (this.downResolver as CompositeModuleResolver).resolve<T>(filter, childOptions) : []),
@@ -384,7 +407,9 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
384
407
  start(_timeout?: number): Promisable<boolean> {
385
408
  //using promise as mutex
386
409
  this._startPromise = this._startPromise ?? this.startHandler()
387
- return this._startPromise
410
+ const result = this._startPromise
411
+ this.status = result ? 'started' : 'dead'
412
+ return result
388
413
  }
389
414
 
390
415
  async started(notStartedAction: 'error' | 'throw' | 'warn' | 'log' | 'none' = 'log', tryStart = true): Promise<boolean> {
@@ -440,10 +465,25 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
440
465
  const result = await this.stopHandler()
441
466
  this._started = undefined
442
467
  this._startPromise = undefined
468
+ this.status = result ? 'stopped' : 'dead'
443
469
  return result
444
470
  })
445
471
  }
446
472
 
473
+ protected _checkDead() {
474
+ if (this.dead) {
475
+ throw new DeadModuleError(this.id, this._lastError)
476
+ }
477
+ }
478
+
479
+ protected _noOverride(functionName: string) {
480
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
481
+ const thisFunc = (this as any)[functionName]
482
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
483
+ const rootFunc = this._getRootFunction(functionName)
484
+ assertEx(thisFunc === rootFunc, () => `Override not allowed for [${functionName}] - override ${functionName}Handler instead`)
485
+ }
486
+
447
487
  protected bindHashes(hashes: Hash[], schema: Schema[], account?: AccountInstance) {
448
488
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
449
489
  const promise = new PromiseEx((resolve) => {
@@ -20,36 +20,42 @@ export abstract class AbstractModuleInstance<TParams extends ModuleParams = Modu
20
20
  }
21
21
 
22
22
  describe(): Promise<ModuleDescriptionPayload> {
23
+ this._checkDead()
23
24
  return this.busy(async () => {
24
25
  return await this.describeHandler()
25
26
  })
26
27
  }
27
28
 
28
29
  discover(): Promise<Payload[]> {
30
+ this._checkDead()
29
31
  return this.busy(async () => {
30
32
  return await this.discoverHandler()
31
33
  })
32
34
  }
33
35
 
34
36
  manifest(maxDepth?: number, ignoreAddresses?: string[]): Promise<ModuleManifestPayload> {
37
+ this._checkDead()
35
38
  return this.busy(async () => {
36
39
  return await this.manifestHandler(maxDepth, ignoreAddresses)
37
40
  })
38
41
  }
39
42
 
40
43
  moduleAddress(): Promise<AddressPreviousHashPayload[]> {
44
+ this._checkDead()
41
45
  return this.busy(async () => {
42
46
  return await this.moduleAddressHandler()
43
47
  })
44
48
  }
45
49
 
46
50
  state() {
51
+ this._checkDead()
47
52
  return this.busy(async () => {
48
53
  return await this.stateHandler()
49
54
  })
50
55
  }
51
56
 
52
57
  subscribe(_queryAccount?: AccountInstance) {
58
+ this._checkDead()
53
59
  return this.subscribeHandler()
54
60
  }
55
61
  }