@xyo-network/module-abstract 3.18.9 → 4.0.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.
- package/dist/neutral/index.mjs +113 -114
- package/dist/neutral/index.mjs.map +1 -1
- package/dist/types/AbstractModule.d.ts +22 -23
- package/dist/types/AbstractModule.d.ts.map +1 -1
- package/dist/types/AbstractModuleInstance.d.ts +2 -1
- package/dist/types/AbstractModuleInstance.d.ts.map +1 -1
- package/dist/types/LoggerModuleStatusReporter.d.ts +5 -4
- package/dist/types/LoggerModuleStatusReporter.d.ts.map +1 -1
- package/dist/types/QueryValidator/ModuleConfigQueryValidator.d.ts.map +1 -1
- package/package.json +34 -33
- package/src/AbstractModule.ts +113 -123
- package/src/AbstractModuleInstance.ts +25 -21
- package/src/LoggerModuleStatusReporter.ts +5 -4
- package/src/QueryValidator/ModuleConfigQueryValidator.ts +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xyo-network/module-abstract",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Primary SDK for using XYO Protocol 2.0",
|
|
5
5
|
"homepage": "https://xyo.network",
|
|
6
6
|
"bugs": {
|
|
@@ -29,43 +29,44 @@
|
|
|
29
29
|
"module": "dist/neutral/index.mjs",
|
|
30
30
|
"types": "dist/types/index.d.ts",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@xylabs/assert": "^4.
|
|
33
|
-
"@xylabs/base": "^4.
|
|
34
|
-
"@xylabs/
|
|
35
|
-
"@xylabs/
|
|
36
|
-
"@xylabs/
|
|
37
|
-
"@xylabs/
|
|
38
|
-
"@xylabs/
|
|
39
|
-
"@xylabs/
|
|
40
|
-
"@xylabs/
|
|
41
|
-
"@xylabs/
|
|
42
|
-
"@xylabs/
|
|
43
|
-
"@
|
|
44
|
-
"@xyo-network/account
|
|
45
|
-
"@xyo-network/
|
|
46
|
-
"@xyo-network/
|
|
47
|
-
"@xyo-network/boundwitness-
|
|
48
|
-
"@xyo-network/boundwitness-
|
|
49
|
-
"@xyo-network/
|
|
50
|
-
"@xyo-network/
|
|
51
|
-
"@xyo-network/
|
|
52
|
-
"@xyo-network/module-
|
|
53
|
-
"@xyo-network/module-
|
|
54
|
-
"@xyo-network/
|
|
55
|
-
"@xyo-network/
|
|
56
|
-
"@xyo-network/payload-
|
|
57
|
-
"@xyo-network/
|
|
58
|
-
"@xyo-network/
|
|
32
|
+
"@xylabs/assert": "^4.12.30",
|
|
33
|
+
"@xylabs/base": "^4.12.30",
|
|
34
|
+
"@xylabs/creatable": "^4.12.30",
|
|
35
|
+
"@xylabs/error": "^4.12.30",
|
|
36
|
+
"@xylabs/exists": "^4.12.30",
|
|
37
|
+
"@xylabs/forget": "^4.12.30",
|
|
38
|
+
"@xylabs/hex": "^4.12.30",
|
|
39
|
+
"@xylabs/logger": "^4.12.30",
|
|
40
|
+
"@xylabs/object": "^4.12.30",
|
|
41
|
+
"@xylabs/promise": "^4.12.30",
|
|
42
|
+
"@xylabs/telemetry": "^4.12.30",
|
|
43
|
+
"@xylabs/typeof": "^4.12.30",
|
|
44
|
+
"@xyo-network/account": "^4.0.0",
|
|
45
|
+
"@xyo-network/account-model": "^4.0.0",
|
|
46
|
+
"@xyo-network/archivist-model": "^4.0.0",
|
|
47
|
+
"@xyo-network/boundwitness-builder": "^4.0.0",
|
|
48
|
+
"@xyo-network/boundwitness-model": "^4.0.0",
|
|
49
|
+
"@xyo-network/boundwitness-wrapper": "^4.0.0",
|
|
50
|
+
"@xyo-network/config-payload-plugin": "^4.0.0",
|
|
51
|
+
"@xyo-network/manifest-model": "^4.0.0",
|
|
52
|
+
"@xyo-network/module-event-emitter": "^4.0.0",
|
|
53
|
+
"@xyo-network/module-model": "^4.0.0",
|
|
54
|
+
"@xyo-network/module-resolver": "^4.0.0",
|
|
55
|
+
"@xyo-network/node-model": "^4.0.0",
|
|
56
|
+
"@xyo-network/payload-builder": "^4.0.0",
|
|
57
|
+
"@xyo-network/payload-model": "^4.0.0",
|
|
58
|
+
"@xyo-network/query-payload-plugin": "^4.0.0",
|
|
59
|
+
"@xyo-network/wallet-model": "^4.0.0",
|
|
59
60
|
"async-mutex": "^0.5.0",
|
|
60
61
|
"lru-cache": "^11.1.0"
|
|
61
62
|
},
|
|
62
63
|
"devDependencies": {
|
|
63
|
-
"@xylabs/ts-scripts-yarn3": "^6.5.
|
|
64
|
-
"@xylabs/tsconfig": "^6.5.
|
|
65
|
-
"@xylabs/typeof": "^4.
|
|
66
|
-
"@xylabs/vitest-extended": "^4.
|
|
64
|
+
"@xylabs/ts-scripts-yarn3": "^6.5.12",
|
|
65
|
+
"@xylabs/tsconfig": "^6.5.12",
|
|
66
|
+
"@xylabs/typeof": "^4.12.30",
|
|
67
|
+
"@xylabs/vitest-extended": "^4.12.30",
|
|
67
68
|
"typescript": "^5.8.3",
|
|
68
|
-
"vitest": "^3.2.
|
|
69
|
+
"vitest": "^3.2.4"
|
|
69
70
|
},
|
|
70
71
|
"publishConfig": {
|
|
71
72
|
"access": "public"
|
package/src/AbstractModule.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/* eslint-disable max-lines */
|
|
2
2
|
import { assertEx } from '@xylabs/assert'
|
|
3
|
-
import {
|
|
3
|
+
import { globallyUnique } from '@xylabs/base'
|
|
4
|
+
import type { CreatableInstance, CreatableStatus } from '@xylabs/creatable'
|
|
5
|
+
import { AbstractCreatable } from '@xylabs/creatable'
|
|
4
6
|
import { handleError, handleErrorAsync } from '@xylabs/error'
|
|
5
7
|
import { exists } from '@xylabs/exists'
|
|
6
8
|
import { forget } from '@xylabs/forget'
|
|
@@ -8,16 +10,17 @@ import type { Address, Hash } from '@xylabs/hex'
|
|
|
8
10
|
import type { Logger } from '@xylabs/logger'
|
|
9
11
|
import {
|
|
10
12
|
ConsoleLogger, IdLogger,
|
|
13
|
+
LevelLogger,
|
|
11
14
|
LogLevel,
|
|
12
15
|
} from '@xylabs/logger'
|
|
13
16
|
import type { Promisable } from '@xylabs/promise'
|
|
14
17
|
import { PromiseEx } from '@xylabs/promise'
|
|
15
18
|
import { spanAsync } from '@xylabs/telemetry'
|
|
16
19
|
import {
|
|
17
|
-
isDefined, isString, isUndefined,
|
|
20
|
+
isDefined, isObject, isPromise, isString, isUndefined,
|
|
18
21
|
} from '@xylabs/typeof'
|
|
19
22
|
import { Account } from '@xyo-network/account'
|
|
20
|
-
import type
|
|
23
|
+
import { type AccountInstance, isAccountInstance } from '@xyo-network/account-model'
|
|
21
24
|
import type { ArchivistInstance } from '@xyo-network/archivist-model'
|
|
22
25
|
import { asArchivistInstance } from '@xyo-network/archivist-model'
|
|
23
26
|
import { BoundWitnessBuilder, QueryBoundWitnessBuilder } from '@xyo-network/boundwitness-builder'
|
|
@@ -27,7 +30,6 @@ import { QueryBoundWitnessWrapper } from '@xyo-network/boundwitness-wrapper'
|
|
|
27
30
|
import type { ConfigPayload } from '@xyo-network/config-payload-plugin'
|
|
28
31
|
import { ConfigSchema } from '@xyo-network/config-payload-plugin'
|
|
29
32
|
import type { ModuleManifestPayload } from '@xyo-network/manifest-model'
|
|
30
|
-
import { ModuleBaseEmitter } from '@xyo-network/module-event-emitter'
|
|
31
33
|
import type {
|
|
32
34
|
AddressPayload,
|
|
33
35
|
AddressPreviousHashPayload,
|
|
@@ -35,6 +37,7 @@ import type {
|
|
|
35
37
|
AttachableModuleInstance,
|
|
36
38
|
CreatableModule,
|
|
37
39
|
CreatableModuleFactory,
|
|
40
|
+
CreatableModuleInstance,
|
|
38
41
|
Labels,
|
|
39
42
|
Module,
|
|
40
43
|
ModuleBusyEventArgs,
|
|
@@ -48,11 +51,11 @@ import type {
|
|
|
48
51
|
ModuleQueryHandlerResult,
|
|
49
52
|
ModuleQueryResult,
|
|
50
53
|
ModuleResolverInstance,
|
|
51
|
-
ModuleStatus,
|
|
52
54
|
} from '@xyo-network/module-model'
|
|
53
55
|
import {
|
|
54
56
|
AddressPreviousHashSchema,
|
|
55
57
|
AddressSchema,
|
|
58
|
+
creatableModule,
|
|
56
59
|
DeadModuleError,
|
|
57
60
|
isModuleName,
|
|
58
61
|
isSerializable,
|
|
@@ -80,8 +83,10 @@ import type { Queryable } from './QueryValidator/index.ts'
|
|
|
80
83
|
import { ModuleConfigQueryValidator, SupportedQueryValidator } from './QueryValidator/index.ts'
|
|
81
84
|
|
|
82
85
|
const MODULE_NOT_STARTED = 'Module not Started' as const
|
|
86
|
+
|
|
87
|
+
creatableModule()
|
|
83
88
|
export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams, TEventData extends ModuleEventData = ModuleEventData>
|
|
84
|
-
extends
|
|
89
|
+
extends AbstractCreatable<TParams, TEventData>
|
|
85
90
|
implements Module<TParams, TEventData> {
|
|
86
91
|
static readonly allowRandomAccount: boolean = true
|
|
87
92
|
static readonly configSchemas: Schema[] = [ModuleConfigSchema]
|
|
@@ -95,35 +100,22 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
95
100
|
|
|
96
101
|
protected static privateConstructorKey = Date.now().toString()
|
|
97
102
|
|
|
98
|
-
protected _account: AccountInstance
|
|
103
|
+
protected _account: AccountInstance | undefined
|
|
99
104
|
|
|
100
105
|
// cache manifest based on maxDepth
|
|
101
106
|
protected _cachedManifests = new LRUCache<number, ModuleManifestPayload>({ max: 10, ttl: 1000 * 60 * 5 })
|
|
102
107
|
|
|
103
|
-
protected _globalReentrancyMutex: Mutex | undefined
|
|
108
|
+
protected _globalReentrancyMutex: Mutex | undefined
|
|
104
109
|
|
|
105
110
|
protected _lastError?: ModuleDetailsError
|
|
106
111
|
|
|
107
|
-
protected
|
|
108
|
-
protected
|
|
109
|
-
protected
|
|
110
|
-
protected readonly supportedQueryValidator: Queryable
|
|
112
|
+
protected _moduleConfigQueryValidator: Queryable | undefined
|
|
113
|
+
protected _startPromise: Promisable<boolean> | undefined
|
|
114
|
+
protected _supportedQueryValidator: Queryable | undefined
|
|
111
115
|
|
|
112
116
|
private _busyCount = 0
|
|
113
|
-
private _logger: Logger | undefined = undefined
|
|
114
|
-
private _status:
|
|
115
|
-
|
|
116
|
-
constructor(privateConstructorKey: string, params: TParams, account: AccountInstance) {
|
|
117
|
-
assertEx(AbstractModule.privateConstructorKey === privateConstructorKey, () => 'Use create function instead of constructor')
|
|
118
|
-
// Clone params to prevent mutation of the incoming object
|
|
119
|
-
const mutatedParams = { ...params } as TParams
|
|
120
|
-
super(mutatedParams)
|
|
121
|
-
|
|
122
|
-
this._account = account
|
|
123
|
-
|
|
124
|
-
this.supportedQueryValidator = new SupportedQueryValidator(this as Module).queryable
|
|
125
|
-
this.moduleConfigQueryValidator = new ModuleConfigQueryValidator(mutatedParams?.config).queryable
|
|
126
|
-
}
|
|
117
|
+
private _logger: Logger | undefined | null = undefined
|
|
118
|
+
private _status: CreatableStatus = 'creating'
|
|
127
119
|
|
|
128
120
|
get account() {
|
|
129
121
|
return assertEx(this._account, () => 'Missing account')
|
|
@@ -134,7 +126,7 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
134
126
|
}
|
|
135
127
|
|
|
136
128
|
get address() {
|
|
137
|
-
return this.
|
|
129
|
+
return this.account.address
|
|
138
130
|
}
|
|
139
131
|
|
|
140
132
|
get allowAnonymous() {
|
|
@@ -153,12 +145,12 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
153
145
|
return this.config.archivist
|
|
154
146
|
}
|
|
155
147
|
|
|
156
|
-
get config(): TParams['config'] {
|
|
157
|
-
return this.params.config
|
|
148
|
+
get config(): TParams['config'] & { schema: Schema } {
|
|
149
|
+
return { ...this.params.config, schema: this.params.config.schema ?? ModuleConfigSchema }
|
|
158
150
|
}
|
|
159
151
|
|
|
160
152
|
get dead() {
|
|
161
|
-
return this.status === '
|
|
153
|
+
return this.status === 'error'
|
|
162
154
|
}
|
|
163
155
|
|
|
164
156
|
get ephemeralQueryAccountEnabled(): boolean {
|
|
@@ -175,10 +167,13 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
175
167
|
}
|
|
176
168
|
|
|
177
169
|
override get logger() {
|
|
178
|
-
|
|
179
|
-
this._logger
|
|
180
|
-
|
|
181
|
-
|
|
170
|
+
// we use null to prevent a second round of not creating a logger
|
|
171
|
+
if (isUndefined(this._logger)) {
|
|
172
|
+
const logLevel = this.config.logLevel
|
|
173
|
+
const newLogger = this._logger ?? (this.params?.logger ? new IdLogger(this.params.logger, () => `${this.constructor.name}[${this.id}]`) : null)
|
|
174
|
+
this._logger = (isObject(newLogger) && isDefined(logLevel)) ? new LevelLogger(newLogger, logLevel) : newLogger
|
|
175
|
+
}
|
|
176
|
+
return this._logger ?? undefined
|
|
182
177
|
}
|
|
183
178
|
|
|
184
179
|
get modName() {
|
|
@@ -201,7 +196,7 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
201
196
|
return this._status
|
|
202
197
|
}
|
|
203
198
|
|
|
204
|
-
get statusReporter() {
|
|
199
|
+
override get statusReporter() {
|
|
205
200
|
return this.params.statusReporter
|
|
206
201
|
}
|
|
207
202
|
|
|
@@ -209,11 +204,21 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
209
204
|
return this.config.timestamp ?? false
|
|
210
205
|
}
|
|
211
206
|
|
|
212
|
-
protected
|
|
213
|
-
|
|
214
|
-
|
|
207
|
+
protected get moduleConfigQueryValidator(): Queryable {
|
|
208
|
+
return assertEx(this._moduleConfigQueryValidator, () => 'ModuleConfigQueryValidator not initialized')
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
protected set status(value: CreatableStatus) {
|
|
212
|
+
this._status = value
|
|
213
|
+
if (value === 'error') {
|
|
214
|
+
this.statusReporter?.report(`${this.constructor.name}:${this.id}`, value, new Error('Module status changed to error'))
|
|
215
|
+
} else {
|
|
216
|
+
this.statusReporter?.report(`${this.constructor.name}:${this.id}`, value, 100)
|
|
215
217
|
}
|
|
216
|
-
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
protected get supportedQueryValidator(): Queryable {
|
|
221
|
+
return assertEx(this._supportedQueryValidator, () => 'SupportedQueryValidator not initialized')
|
|
217
222
|
}
|
|
218
223
|
|
|
219
224
|
abstract get downResolver(): ModuleResolverInstance
|
|
@@ -237,38 +242,24 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
237
242
|
assertEx(thisFunc === rootFunc, () => `Override not allowed for [${functionName}] - override ${functionName}Handler instead`)
|
|
238
243
|
}
|
|
239
244
|
|
|
240
|
-
static async
|
|
241
|
-
|
|
242
|
-
params: Omit<TModule['params'], 'config'> & { config?: TModule['params']['config'] },
|
|
245
|
+
static override async createHandler<T extends CreatableInstance>(
|
|
246
|
+
inInstance: T,
|
|
243
247
|
) {
|
|
244
|
-
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
assertEx(params?.config?.name === undefined || isModuleName(params.config.name), () => `Invalid module name: ${params?.config?.name}`)
|
|
250
|
-
|
|
251
|
-
const { account } = params ?? {}
|
|
252
|
-
|
|
253
|
-
const schema: Schema = params?.config?.schema ?? this.defaultConfigSchema
|
|
254
|
-
const allowedSchemas: Schema[] = this.configSchemas
|
|
255
|
-
|
|
256
|
-
assertEx(allowedSchemas.includes(schema), () => `Bad Config Schema [Received ${schema}] [Expected ${JSON.stringify(allowedSchemas)}]`)
|
|
257
|
-
const mutatedConfig: TModule['params']['config'] = { ...params?.config, schema } as TModule['params']['config']
|
|
258
|
-
params?.logger?.debug(`config: ${JSON.stringify(mutatedConfig, null, 2)}`)
|
|
259
|
-
const mutatedParams: TModule['params'] = { ...params, config: mutatedConfig } as TModule['params']
|
|
260
|
-
|
|
261
|
-
const activeLogger = params?.logger ?? AbstractModule.defaultLogger
|
|
262
|
-
const generatedAccount = await AbstractModule.determineAccount({ account })
|
|
263
|
-
const address = generatedAccount.address
|
|
264
|
-
mutatedParams.logger = new IdLogger(activeLogger, () => `0x${address}`)
|
|
248
|
+
const instance = (await super.createHandler(inInstance))
|
|
249
|
+
if (instance instanceof AbstractModule) {
|
|
250
|
+
if (this.configSchemas.length === 0) {
|
|
251
|
+
throw new Error(`No allowed config schemas for [${this.name}]`)
|
|
252
|
+
}
|
|
265
253
|
|
|
266
|
-
|
|
254
|
+
const schema: Schema = instance.config.schema ?? this.defaultConfigSchema
|
|
255
|
+
const allowedSchemas: Schema[] = this.configSchemas
|
|
267
256
|
|
|
268
|
-
|
|
269
|
-
|
|
257
|
+
assertEx(this.isAllowedSchema(schema), () => `Bad Config Schema [Received ${schema}] [Expected ${JSON.stringify(allowedSchemas)}]`)
|
|
258
|
+
} else {
|
|
259
|
+
throw new TypeError(`Invalid instance type [${instance.constructor.name}] for [${this.name}]`)
|
|
270
260
|
}
|
|
271
|
-
|
|
261
|
+
|
|
262
|
+
return instance
|
|
272
263
|
}
|
|
273
264
|
|
|
274
265
|
static async determineAccount(params: {
|
|
@@ -279,13 +270,30 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
279
270
|
return await determineAccount(params, this.allowRandomAccount)
|
|
280
271
|
}
|
|
281
272
|
|
|
282
|
-
static factory<TModule extends
|
|
273
|
+
static factory<TModule extends CreatableModuleInstance>(
|
|
283
274
|
this: CreatableModule<TModule>,
|
|
284
|
-
params
|
|
275
|
+
params?: Partial<TModule['params']>,
|
|
285
276
|
): CreatableModuleFactory<TModule> {
|
|
286
277
|
return ModuleFactory.withParams(this, params)
|
|
287
278
|
}
|
|
288
279
|
|
|
280
|
+
static isAllowedSchema(schema: Schema): boolean {
|
|
281
|
+
return this.configSchemas.includes(schema)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
static override async paramsHandler<T extends AttachableModuleInstance<ModuleParams, ModuleEventData>>(
|
|
285
|
+
inParams: Partial<T['params']> = {},
|
|
286
|
+
) {
|
|
287
|
+
const superParams = await super.paramsHandler(inParams)
|
|
288
|
+
const params = {
|
|
289
|
+
...superParams,
|
|
290
|
+
account: await this.determineAccount(superParams),
|
|
291
|
+
config: { schema: this.defaultConfigSchema, ...superParams.config },
|
|
292
|
+
logger: superParams.logger ?? this.defaultLogger,
|
|
293
|
+
} as T['params']
|
|
294
|
+
return params
|
|
295
|
+
}
|
|
296
|
+
|
|
289
297
|
// eslint-disable-next-line sonarjs/no-identical-functions
|
|
290
298
|
_getRootFunction(funcName: string) {
|
|
291
299
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -315,6 +323,26 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
315
323
|
}
|
|
316
324
|
}
|
|
317
325
|
|
|
326
|
+
override async createHandler() {
|
|
327
|
+
await super.createHandler()
|
|
328
|
+
assertEx(this.name === undefined || isModuleName(this.name), () => `Invalid module name: ${this.name}`)
|
|
329
|
+
|
|
330
|
+
if (this.params.account === 'random') {
|
|
331
|
+
this._account = await Account.random()
|
|
332
|
+
} else if (isAccountInstance(this.params.account)) {
|
|
333
|
+
this._account = this.params.account
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
assertEx(isAccountInstance(this._account), () => `Invalid account instance: ${this._account}`)
|
|
337
|
+
|
|
338
|
+
this._supportedQueryValidator = new SupportedQueryValidator(this as Module).queryable
|
|
339
|
+
this._moduleConfigQueryValidator = new ModuleConfigQueryValidator(this.config).queryable
|
|
340
|
+
|
|
341
|
+
if (!AbstractModule.enableLazyLoad) {
|
|
342
|
+
await this.start?.()
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
318
346
|
override emit<TEventName extends keyof TEventData = keyof TEventData, TEventArgs extends TEventData[TEventName] = TEventData[TEventName]>(
|
|
319
347
|
eventName: TEventName,
|
|
320
348
|
eventArgs: TEventArgs,
|
|
@@ -418,43 +446,29 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
418
446
|
return true
|
|
419
447
|
}
|
|
420
448
|
|
|
421
|
-
async start(timeout?: number): Promise<boolean> {
|
|
422
|
-
this._noOverride('start')
|
|
423
|
-
this.status = 'starting'
|
|
424
|
-
let startingTime = 0
|
|
425
|
-
const startingStatus = setInterval(() => {
|
|
426
|
-
startingTime += 1000
|
|
427
|
-
this.statusReporter?.reportStatus(`${this.constructor.name}:${this.id}`, 'starting', startingTime)
|
|
428
|
-
}, 1000)
|
|
429
|
-
// using promise as mutex
|
|
430
|
-
this._startPromise = this._startPromise ?? await this.startHandler(timeout)
|
|
431
|
-
const result = await this._startPromise
|
|
432
|
-
this.status = result ? 'started' : 'dead'
|
|
433
|
-
clearInterval(startingStatus)
|
|
434
|
-
return result
|
|
435
|
-
}
|
|
436
|
-
|
|
437
449
|
async started(notStartedAction: 'error' | 'throw' | 'warn' | 'log' | 'none' = 'log', tryStart = true): Promise<boolean> {
|
|
438
|
-
if (
|
|
450
|
+
if (isString(this.status) && this.status === 'started') {
|
|
439
451
|
return true
|
|
440
452
|
}
|
|
441
|
-
if (
|
|
453
|
+
if (this.status === 'created' || this.status === 'stopped') {
|
|
442
454
|
// using promise as mutex
|
|
443
|
-
this.
|
|
455
|
+
this._startPromise = this._startPromise ?? (async () => {
|
|
444
456
|
if (tryStart) {
|
|
445
457
|
try {
|
|
446
458
|
await this.start()
|
|
447
459
|
return true
|
|
448
460
|
} catch (ex) {
|
|
449
461
|
handleError(ex, (error) => {
|
|
450
|
-
this.
|
|
451
|
-
this.
|
|
462
|
+
this.status = 'error'
|
|
463
|
+
this.logger?.warn(`Autostart of Module Failed: ${error.message}`)
|
|
452
464
|
})
|
|
465
|
+
} finally {
|
|
466
|
+
this._startPromise = undefined
|
|
453
467
|
}
|
|
454
468
|
}
|
|
455
469
|
switch (notStartedAction) {
|
|
456
470
|
case 'throw': {
|
|
457
|
-
throw new Error(`${MODULE_NOT_STARTED} [${this.address}]`)
|
|
471
|
+
throw new Error(`${MODULE_NOT_STARTED} [${this.address}] current state: ${this.status}`)
|
|
458
472
|
}
|
|
459
473
|
case 'warn': {
|
|
460
474
|
this.logger?.warn(MODULE_NOT_STARTED)
|
|
@@ -476,23 +490,10 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
476
490
|
})()
|
|
477
491
|
}
|
|
478
492
|
|
|
479
|
-
if (isUndefined(this.
|
|
480
|
-
throw
|
|
493
|
+
if (isUndefined(this._startPromise)) {
|
|
494
|
+
throw new Error(`Failed to create start promise: ${this.status}`)
|
|
481
495
|
}
|
|
482
|
-
return await this.
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
async stop(_timeout?: number): Promise<boolean> {
|
|
486
|
-
this._noOverride('stop')
|
|
487
|
-
return await spanAsync('start', async () => {
|
|
488
|
-
return await this.busy(async () => {
|
|
489
|
-
const result = await this.stopHandler()
|
|
490
|
-
this._started = undefined
|
|
491
|
-
this._startPromise = undefined
|
|
492
|
-
this.status = result ? 'stopped' : 'dead'
|
|
493
|
-
return result
|
|
494
|
-
})
|
|
495
|
-
}, this.tracer)
|
|
496
|
+
return await this._startPromise
|
|
496
497
|
}
|
|
497
498
|
|
|
498
499
|
protected _checkDead() {
|
|
@@ -501,15 +502,6 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
501
502
|
}
|
|
502
503
|
}
|
|
503
504
|
|
|
504
|
-
// eslint-disable-next-line sonarjs/no-identical-functions
|
|
505
|
-
protected _noOverride(functionName: string) {
|
|
506
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
507
|
-
const thisFunc = (this as any)[functionName]
|
|
508
|
-
|
|
509
|
-
const rootFunc = this._getRootFunction(functionName)
|
|
510
|
-
assertEx(thisFunc === rootFunc, () => `Override not allowed for [${functionName}] - override ${functionName}Handler instead`)
|
|
511
|
-
}
|
|
512
|
-
|
|
513
505
|
protected async archivistInstance(): Promise<ArchivistInstance | undefined>
|
|
514
506
|
protected async archivistInstance(required: true): Promise<ArchivistInstance>
|
|
515
507
|
protected async archivistInstance(required = false): Promise<ArchivistInstance | undefined> {
|
|
@@ -693,20 +685,18 @@ export abstract class AbstractModule<TParams extends ModuleParams = ModuleParams
|
|
|
693
685
|
return PayloadBuilder.omitPrivateStorageMeta(resultPayloads)
|
|
694
686
|
}
|
|
695
687
|
|
|
696
|
-
protected async startHandler(
|
|
688
|
+
protected override async startHandler(): Promise<void> {
|
|
697
689
|
this.validateConfig()
|
|
698
|
-
await
|
|
699
|
-
this._started = true
|
|
700
|
-
return true
|
|
690
|
+
await super.startHandler()
|
|
701
691
|
}
|
|
702
692
|
|
|
703
693
|
protected async stateHandler(): Promise<Payload[]> {
|
|
704
694
|
return [await this.manifestHandler(), ...(await this.generateConfigAndAddress()), await this.generateDescribe()]
|
|
705
695
|
}
|
|
706
696
|
|
|
707
|
-
protected stopHandler(
|
|
708
|
-
|
|
709
|
-
|
|
697
|
+
protected override async stopHandler(): Promise<void> {
|
|
698
|
+
await super.stopHandler()
|
|
699
|
+
this._startPromise = undefined
|
|
710
700
|
}
|
|
711
701
|
|
|
712
702
|
protected subscribeHandler() {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { assertEx } from '@xylabs/assert'
|
|
2
1
|
import { globallyUnique } from '@xylabs/base'
|
|
3
2
|
import { exists } from '@xylabs/exists'
|
|
4
3
|
import type { Address } from '@xylabs/hex'
|
|
@@ -69,18 +68,6 @@ export abstract class AbstractModuleInstance<TParams extends ModuleParams = Modu
|
|
|
69
68
|
private _privateResolver?: CompositeModuleResolver
|
|
70
69
|
private _upResolver?: CompositeModuleResolver
|
|
71
70
|
|
|
72
|
-
constructor(privateConstructorKey: string, params: TParams, account: AccountInstance) {
|
|
73
|
-
assertEx(AbstractModule.privateConstructorKey === privateConstructorKey, () => 'Use create function instead of constructor')
|
|
74
|
-
// Clone params to prevent mutation of the incoming object
|
|
75
|
-
const mutatedParams = { ...params } as TParams
|
|
76
|
-
const addToResolvers = mutatedParams.addToResolvers ?? true
|
|
77
|
-
super(privateConstructorKey, mutatedParams, account)
|
|
78
|
-
if (addToResolvers) {
|
|
79
|
-
this.upResolver.add(this)
|
|
80
|
-
this.downResolver.add(this)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
71
|
get downResolver() {
|
|
85
72
|
this._downResolver
|
|
86
73
|
= this._downResolver
|
|
@@ -129,7 +116,7 @@ export abstract class AbstractModuleInstance<TParams extends ModuleParams = Modu
|
|
|
129
116
|
addParent(mod: ModuleInstance) {
|
|
130
117
|
const existingEntry = this._parents.find(parent => parent.address === mod.address)
|
|
131
118
|
if (!existingEntry) {
|
|
132
|
-
this._parents.push(asNodeInstance(mod, 'Only NodeInstances can be parents'))
|
|
119
|
+
this._parents.push(asNodeInstance(mod, 'Only NodeInstances can be parents', { required: true }))
|
|
133
120
|
}
|
|
134
121
|
}
|
|
135
122
|
|
|
@@ -145,6 +132,17 @@ export abstract class AbstractModuleInstance<TParams extends ModuleParams = Modu
|
|
|
145
132
|
).flat()
|
|
146
133
|
}
|
|
147
134
|
|
|
135
|
+
override async createHandler() {
|
|
136
|
+
this.status = 'creating'
|
|
137
|
+
await super.createHandler()
|
|
138
|
+
const addToResolvers = this.params.addToResolvers ?? true
|
|
139
|
+
if (addToResolvers) {
|
|
140
|
+
this.upResolver.add(this)
|
|
141
|
+
this.downResolver.add(this)
|
|
142
|
+
}
|
|
143
|
+
this.status = 'created'
|
|
144
|
+
}
|
|
145
|
+
|
|
148
146
|
manifest(maxDepth?: number): Promise<ModuleManifestPayload> {
|
|
149
147
|
this._checkDead()
|
|
150
148
|
return this.busy(async () => {
|
|
@@ -249,13 +247,6 @@ export abstract class AbstractModuleInstance<TParams extends ModuleParams = Modu
|
|
|
249
247
|
return (await Promise.all((await this.parents()).map(parent => parent.publicChildren()))).flat().filter(duplicateModules)
|
|
250
248
|
}
|
|
251
249
|
|
|
252
|
-
/* override start(_timeout?: number): Promisable<boolean> {
|
|
253
|
-
if (this.parents.length === 0) {
|
|
254
|
-
this.logger.warn(`Module is being started without being attached to a parent: ${this.id} [${this.address}]`)
|
|
255
|
-
}
|
|
256
|
-
return super.start()
|
|
257
|
-
} */
|
|
258
|
-
|
|
259
250
|
state() {
|
|
260
251
|
this._checkDead()
|
|
261
252
|
return this.busy(async () => {
|
|
@@ -288,6 +279,7 @@ export abstract class AbstractModuleInstance<TParams extends ModuleParams = Modu
|
|
|
288
279
|
}
|
|
289
280
|
const result = {
|
|
290
281
|
config: { name: modName, ...this.config },
|
|
282
|
+
name: modName,
|
|
291
283
|
schema: ModuleManifestPayloadSchema,
|
|
292
284
|
status: { address: this.address, children: childAddressToName },
|
|
293
285
|
}
|
|
@@ -332,6 +324,18 @@ export abstract class AbstractModuleInstance<TParams extends ModuleParams = Modu
|
|
|
332
324
|
return (await this.query(query[0], query[1])) as ModuleQueryResult<R>
|
|
333
325
|
}
|
|
334
326
|
|
|
327
|
+
protected override startHandler() {
|
|
328
|
+
this._checkDead()
|
|
329
|
+
return this.busy(async () => {
|
|
330
|
+
if (this.status === 'started' || this.status === 'creating') {
|
|
331
|
+
return
|
|
332
|
+
}
|
|
333
|
+
this.status = 'starting'
|
|
334
|
+
await super.startHandler()
|
|
335
|
+
this.status = 'started'
|
|
336
|
+
})
|
|
337
|
+
}
|
|
338
|
+
|
|
335
339
|
protected async storeToArchivists(payloads: Payload[]): Promise<Payload[]> {
|
|
336
340
|
try {
|
|
337
341
|
const archivists = await this.resolveArchivingArchivists()
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
import type { CreatableName, CreatableStatus } from '@xylabs/creatable'
|
|
1
2
|
import type { Logger } from '@xylabs/logger'
|
|
2
|
-
import type {
|
|
3
|
+
import type { ModuleStatusReporter } from '@xyo-network/module-model'
|
|
3
4
|
|
|
4
5
|
export class LoggerModuleStatusReporter implements ModuleStatusReporter {
|
|
5
|
-
|
|
6
|
+
protected logger: Logger
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
protected statusMap: Record<CreatableName, CreatableStatus> = {}
|
|
8
9
|
|
|
9
10
|
constructor(logger: Logger) {
|
|
10
11
|
this.logger = logger
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
report(name: string, status: CreatableStatus, progress?: number | Error): void {
|
|
14
15
|
this.statusMap[name] = status
|
|
15
16
|
const starting = (Object.entries(this.statusMap).map(([, value]): number => value === 'starting' ? 1 : 0)).reduce((a, b) => a + b, 0)
|
|
16
17
|
const started = (Object.entries(this.statusMap).map(([, value]): number => value === 'started' ? 1 : 0)).reduce((a, b) => a + b, 0)
|
|
@@ -7,7 +7,6 @@ import type { Schema } from '@xyo-network/payload-model'
|
|
|
7
7
|
|
|
8
8
|
import type { Queryable, QueryValidator } from './QueryValidator.ts'
|
|
9
9
|
|
|
10
|
-
// eslint-disable-next-line sonarjs/redundant-type-aliases
|
|
11
10
|
export type SortedPipedAddressesString = string
|
|
12
11
|
|
|
13
12
|
const delimiter = ''
|