@xyo-network/sentinel-memory 5.3.20 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xyo-network/sentinel-memory",
3
- "version": "5.3.20",
3
+ "version": "5.3.24",
4
4
  "description": "Primary SDK for using XYO Protocol 2.0",
5
5
  "homepage": "https://xyo.network",
6
6
  "bugs": {
@@ -30,41 +30,59 @@
30
30
  "types": "dist/neutral/index.d.ts",
31
31
  "files": [
32
32
  "dist",
33
- "src",
34
33
  "!**/*.bench.*",
35
34
  "!**/*.spec.*",
36
- "!**/*.test.*"
35
+ "!**/*.test.*",
36
+ "README.md"
37
37
  ],
38
38
  "dependencies": {
39
- "@xyo-network/diviner-model": "~5.3.20",
40
- "@xyo-network/module-model": "~5.3.20",
41
- "@xyo-network/payload-builder": "~5.3.20",
42
- "@xyo-network/payload-model": "~5.3.20",
43
- "@xyo-network/payload-wrapper": "~5.3.20",
44
- "@xyo-network/sentinel-abstract": "~5.3.20",
45
- "@xyo-network/sentinel-model": "~5.3.20",
46
- "@xyo-network/witness-model": "~5.3.20"
39
+ "@xyo-network/diviner-model": "~5.3.24",
40
+ "@xyo-network/payload-builder": "~5.3.24",
41
+ "@xyo-network/payload-model": "~5.3.24",
42
+ "@xyo-network/module-model": "~5.3.24",
43
+ "@xyo-network/sentinel-abstract": "~5.3.24",
44
+ "@xyo-network/payload-wrapper": "~5.3.24",
45
+ "@xyo-network/witness-model": "~5.3.24",
46
+ "@xyo-network/sentinel-model": "~5.3.24"
47
47
  },
48
48
  "devDependencies": {
49
- "@xylabs/sdk-js": "^5.0.90",
50
- "@xylabs/ts-scripts-common": "~7.5.6",
51
- "@xylabs/ts-scripts-yarn3": "~7.5.6",
52
- "@xylabs/tsconfig": "~7.5.6",
53
- "@xylabs/vitest-extended": "~5.0.90",
54
- "@xyo-network/abstract-witness": "~5.3.20",
55
- "@xyo-network/archivist-memory": "~5.3.20",
56
- "@xyo-network/id-payload-plugin": "~5.3.20",
57
- "@xyo-network/node-memory": "~5.3.20",
58
- "@xyo-network/witness-adhoc": "~5.3.20",
49
+ "@opentelemetry/api": "^1.9.1",
50
+ "@types/node": "^25.5.0",
51
+ "@xylabs/sdk-js": "^5.0.93",
52
+ "@xylabs/ts-scripts-common": "~7.6.16",
53
+ "@xylabs/ts-scripts-pnpm": "~7.6.16",
54
+ "@xylabs/tsconfig": "~7.6.16",
55
+ "@xylabs/vitest-extended": "~5.0.93",
56
+ "acorn": "^8.16.0",
57
+ "axios": "^1.14.0",
58
+ "esbuild": "^0.28.0",
59
+ "ethers": "^6.16.0",
60
+ "tslib": "^2.8.1",
59
61
  "typescript": "~5.9.3",
62
+ "vite": "^8.0.3",
60
63
  "vitest": "~4.1.2",
61
- "zod": "^4.3.6"
64
+ "zod": "^4.3.6",
65
+ "@xyo-network/abstract-witness": "~5.3.24",
66
+ "@xyo-network/diviner-model": "~5.3.24",
67
+ "@xyo-network/id-payload-plugin": "~5.3.24",
68
+ "@xyo-network/payload-builder": "~5.3.24",
69
+ "@xyo-network/node-memory": "~5.3.24",
70
+ "@xyo-network/payload-model": "~5.3.24",
71
+ "@xyo-network/sentinel-abstract": "~5.3.24",
72
+ "@xyo-network/archivist-memory": "~5.3.24",
73
+ "@xyo-network/sentinel-model": "~5.3.24",
74
+ "@xyo-network/payload-wrapper": "~5.3.24",
75
+ "@xyo-network/module-model": "~5.3.24",
76
+ "@xyo-network/witness-adhoc": "~5.3.24",
77
+ "@xyo-network/witness-model": "~5.3.24"
62
78
  },
63
79
  "peerDependencies": {
64
80
  "@xylabs/sdk-js": "^5",
81
+ "ethers": "^6",
82
+ "tslib": "^2.8.1",
65
83
  "zod": "^4"
66
84
  },
67
85
  "publishConfig": {
68
86
  "access": "public"
69
87
  }
70
- }
88
+ }
@@ -1,156 +0,0 @@
1
- import type { Address } from '@xylabs/sdk-js'
2
- import { fulfilled, rejected } from '@xylabs/sdk-js'
3
- import { asDivinerInstance } from '@xyo-network/diviner-model'
4
- import { type AnyConfigSchema, type ModuleIdentifier } from '@xyo-network/module-model'
5
- import type { Payload, Schema } from '@xyo-network/payload-model'
6
- import { AbstractSentinel } from '@xyo-network/sentinel-abstract'
7
- import type {
8
- ResolvedTask,
9
- SentinelConfig,
10
- SentinelInstance,
11
- SentinelModuleEventData,
12
- SentinelParams,
13
- } from '@xyo-network/sentinel-model'
14
- import {
15
- asSentinelInstance,
16
- SentinelConfigSchema,
17
- } from '@xyo-network/sentinel-model'
18
- import { asWitnessInstance } from '@xyo-network/witness-model'
19
-
20
- import { SentinelRunner } from './SentinelRunner.ts'
21
-
22
- export type MemorySentinelParams<TConfig extends AnyConfigSchema<SentinelConfig> = AnyConfigSchema<SentinelConfig>> = SentinelParams<TConfig>
23
-
24
- export class MemorySentinel<
25
- TParams extends MemorySentinelParams = MemorySentinelParams,
26
- TEventData extends SentinelModuleEventData<SentinelInstance<TParams>> = SentinelModuleEventData<SentinelInstance<TParams>>,
27
- > extends AbstractSentinel<TParams, TEventData> {
28
- static override readonly configSchemas: Schema[] = [...super.configSchemas, SentinelConfigSchema]
29
- static override readonly defaultConfigSchema: Schema = SentinelConfigSchema
30
-
31
- private runner?: SentinelRunner
32
-
33
- async reportHandler(inPayloads: Payload[] = []): Promise<Payload[]> {
34
- await this.startedAsync('throw')
35
- this.logger?.debug(`reportHandler:in: ${JSON.stringify(inPayloads)}`)
36
- const job = await this.jobPromise
37
-
38
- let index = 0
39
- let previousResults: Record<Address, Payload[]> = {}
40
- while (index < job.tasks.length) {
41
- const generatedPayloads = await this.runJob(job.tasks[index], previousResults, inPayloads)
42
- previousResults = generatedPayloads
43
- index++
44
- }
45
- const result = Object.values(previousResults).flat()
46
- this.logger?.debug(`reportHandler:out: ${JSON.stringify(result)}`)
47
- return result
48
- }
49
-
50
- override async startHandler() {
51
- await super.startHandler()
52
- if ((this.config.automations?.length ?? 0) > 0) {
53
- this.runner = new SentinelRunner({
54
- sentinel: this, automations: this.config.automations, traceProvider: this.params.traceProvider,
55
- })
56
- this.runner.start()
57
- }
58
- }
59
-
60
- override async stopHandler() {
61
- if (this.runner) {
62
- this.runner.stop()
63
- this.runner = undefined
64
- }
65
- await super.stopHandler()
66
- }
67
-
68
- private async inputAddresses(input: ModuleIdentifier | ModuleIdentifier[]): Promise<Address[]> {
69
- if (Array.isArray(input)) {
70
- return (await Promise.all(input.map(async inputItem => await this.inputAddresses(inputItem)))).flat()
71
- } else {
72
- const resolved = await this.resolve(input)
73
- return resolved ? [resolved.address] : []
74
- }
75
- }
76
-
77
- private processPreviousResults(payloads: Record<string, Payload[]>, inputs: string[]) {
78
- return inputs.flatMap(input => payloads[input] ?? [])
79
- }
80
-
81
- private async runJob(
82
- tasks: ResolvedTask[],
83
- previousResults: Record<Address, Payload[]>,
84
- inPayloads?: Payload[],
85
- ): Promise<Record<Address, Payload[]>> {
86
- await this.emit('jobStart', { inPayloads, mod: this })
87
- this.logger?.debug(`runJob:tasks: ${JSON.stringify(tasks.length)}`)
88
- this.logger?.debug(`runJob:previous: ${JSON.stringify(previousResults)}`)
89
- this.logger?.debug(`runJob:in: ${JSON.stringify(inPayloads)}`)
90
- const results: PromiseSettledResult<[Address, Payload[]]>[] = await Promise.allSettled(
91
- tasks?.map(async (task) => {
92
- const input = task.input ?? false
93
- const inPayloadsFound
94
- = input === true
95
- ? inPayloads
96
- : input === false
97
- ? []
98
- : this.processPreviousResults(previousResults, await this.inputAddresses(input))
99
- const witness = asWitnessInstance(task.mod)
100
- if (witness) {
101
- await this.emit('taskStart', {
102
- address: witness.address, inPayloads: inPayloadsFound, mod: this,
103
- })
104
- const observed = await witness.observe(inPayloadsFound)
105
- this.logger?.debug(`observed [${witness.id}]: ${JSON.stringify(observed)}`)
106
- await this.emit('taskEnd', {
107
- address: witness.address, inPayloads: inPayloadsFound, mod: this, outPayloads: observed,
108
- })
109
- return [witness.address, observed]
110
- }
111
- const diviner = asDivinerInstance(task.mod)
112
- if (diviner) {
113
- await this.emit('taskStart', {
114
- address: diviner.address, inPayloads: inPayloadsFound, mod: this,
115
- })
116
- const divined = await diviner.divine(inPayloadsFound)
117
- this.logger?.debug(`divined [${diviner.id}]: ${JSON.stringify(divined)}`)
118
- await this.emit('taskEnd', {
119
- address: diviner.address, inPayloads: inPayloadsFound, mod: this, outPayloads: divined,
120
- })
121
- return [diviner.address, divined]
122
- }
123
- const sentinel = asSentinelInstance(task.mod)
124
- if (sentinel) {
125
- await this.emit('taskStart', {
126
- address: sentinel.address, inPayloads: inPayloadsFound, mod: this,
127
- })
128
- const reported = await sentinel.report(inPayloadsFound)
129
- this.logger?.debug(`reported [${sentinel.id}]: ${JSON.stringify(reported)}`)
130
- await this.emit('taskEnd', {
131
- address: sentinel.address, inPayloads: inPayloadsFound, mod: this, outPayloads: reported,
132
- })
133
- return [sentinel.address, reported]
134
- }
135
- throw new Error('Unsupported module type')
136
- }),
137
- )
138
- const finalResult: Record<Address, Payload[]> = {}
139
- for (const result of results.filter(fulfilled)) {
140
- const [address, payloads] = result.value
141
- finalResult[address] = finalResult[address] ?? []
142
- finalResult[address].push(...payloads)
143
- }
144
- if (this.throwErrors) {
145
- const errors = results.filter(rejected).map(result => result.reason)
146
- if (errors.length > 0) {
147
- throw new Error('At least one module failed')
148
- }
149
- }
150
- this.logger?.debug(`generateResults:out: ${JSON.stringify(finalResult)}`)
151
- await this.emit('jobEnd', {
152
- finalResult, inPayloads, mod: this,
153
- })
154
- return finalResult
155
- }
156
- }
@@ -1,79 +0,0 @@
1
- import { PayloadWrapper } from '@xyo-network/payload-wrapper'
2
- import type { SentinelIntervalAutomationPayload } from '@xyo-network/sentinel-model'
3
-
4
- export class SentinelIntervalAutomationWrapper<
5
- T extends SentinelIntervalAutomationPayload = SentinelIntervalAutomationPayload,
6
- > extends PayloadWrapper<T> {
7
- constructor(payload: T) {
8
- super(payload)
9
- }
10
-
11
- protected get frequencyMillis() {
12
- const frequency = this.payload.frequency
13
- if (frequency === undefined) return Number.POSITIVE_INFINITY
14
- const frequencyUnits = this.payload.frequencyUnits
15
- switch (frequencyUnits ?? 'hour') {
16
- case 'millis': {
17
- return frequency
18
- }
19
- case 'second': {
20
- return frequency * 1000
21
- }
22
- case 'minute': {
23
- return frequency * 60 * 1000
24
- }
25
- case 'hour': {
26
- return frequency * 60 * 60 * 1000
27
- }
28
- case 'day': {
29
- return frequency * 24 * 60 * 60 * 1000
30
- }
31
- default: {
32
- return Number.POSITIVE_INFINITY
33
- }
34
- }
35
- }
36
-
37
- protected get remaining() {
38
- return this.payload.remaining ?? Number.POSITIVE_INFINITY
39
- }
40
-
41
- next() {
42
- const now = Date.now()
43
- const previousStart = this.payload?.start ?? now
44
- const start = Math.max(previousStart, now)
45
- const nextStart = start + this.frequencyMillis
46
- this.setStart(nextStart)
47
- this.consumeRemaining()
48
- this.checkEnd()
49
- return this
50
- }
51
-
52
- protected checkEnd() {
53
- if (this.payload.start > (this.payload.end ?? Number.POSITIVE_INFINITY)) {
54
- this.setStart(Number.POSITIVE_INFINITY)
55
- }
56
- }
57
-
58
- protected consumeRemaining(count = 1) {
59
- const remaining = Math.max(this.remaining - count, 0)
60
- this.setRemaining(remaining)
61
- if (remaining <= 0) this.setStart(Number.POSITIVE_INFINITY)
62
- }
63
-
64
- /**
65
- * Sets the remaining of the wrapped automation
66
- * @param remaining The remaining time in milliseconds
67
- */
68
- protected setRemaining(remaining: number) {
69
- this.payload.remaining = remaining
70
- }
71
-
72
- /**
73
- * Sets the start of the wrapped automation
74
- * @param start The start time in milliseconds
75
- */
76
- protected setStart(start: number) {
77
- this.payload.start = start
78
- }
79
- }
@@ -1,136 +0,0 @@
1
- import type { BaseParams } from '@xylabs/sdk-js'
2
- import {
3
- assertEx, Base, forget,
4
- isDefined, spanRootAsync,
5
- } from '@xylabs/sdk-js'
6
- import { PayloadBuilder } from '@xyo-network/payload-builder'
7
- import type { Payload } from '@xyo-network/payload-model'
8
- import type {
9
- SentinelAutomationPayload,
10
- SentinelInstance,
11
- SentinelIntervalAutomationPayload,
12
- } from '@xyo-network/sentinel-model'
13
- import { isSentinelIntervalAutomation } from '@xyo-network/sentinel-model'
14
-
15
- import { SentinelIntervalAutomationWrapper } from './SentinelIntervalAutomationWrapper.ts'
16
-
17
- export type OnSentinelRunnerTriggerResult = (result: Payload[]) => void
18
-
19
- export interface SentinelRunnerParams extends BaseParams {
20
- automations?: SentinelAutomationPayload[]
21
- onTriggerResult?: OnSentinelRunnerTriggerResult
22
- sentinel: SentinelInstance
23
- }
24
-
25
- export class SentinelRunner extends Base {
26
- protected _automations: Record<string, SentinelAutomationPayload> = {}
27
- protected onTriggerResult: OnSentinelRunnerTriggerResult | undefined
28
- protected sentinel: SentinelInstance
29
- protected timeoutId?: NodeJS.Timeout | string | number
30
-
31
- constructor(params: SentinelRunnerParams) {
32
- super(params)
33
- this.sentinel = params.sentinel
34
- this.onTriggerResult = params.onTriggerResult
35
-
36
- if (params.automations) for (const automation of params.automations) forget(this.add(automation))
37
- }
38
-
39
- get automations() {
40
- return this._automations
41
- }
42
-
43
- private get next() {
44
- // eslint-disable-next-line unicorn/no-array-reduce
45
- return Object.values(this._automations).reduce<SentinelAutomationPayload | undefined>((previous, current) => {
46
- if (isSentinelIntervalAutomation(current) && isSentinelIntervalAutomation(previous)) {
47
- return current.start < (previous?.start ?? Number.POSITIVE_INFINITY) ? current : previous
48
- }
49
- return current
50
- // eslint-disable-next-line unicorn/no-useless-undefined
51
- }, undefined)
52
- }
53
-
54
- async add(automation: SentinelAutomationPayload, restart = true) {
55
- const hash = await PayloadBuilder.dataHash(automation)
56
- this._automations[hash] = automation
57
- if (restart) this.restart()
58
- return hash
59
- }
60
-
61
- find(hash: string) {
62
- return Object.entries(this._automations).find(([key]) => key === hash)
63
- }
64
-
65
- remove(hash: string, restart = true) {
66
- delete this._automations[hash]
67
- if (restart) this.restart()
68
- }
69
-
70
- removeAll() {
71
- this.stop()
72
- this._automations = {}
73
- }
74
-
75
- restart() {
76
- this.stop()
77
- this.start()
78
- }
79
-
80
- start() {
81
- this.startHandler()
82
- }
83
-
84
- startHandler() {
85
- assertEx(this.timeoutId === undefined, () => 'Already started')
86
- const automation = this.next
87
- if (isSentinelIntervalAutomation(automation)) {
88
- const now = Date.now()
89
- const start = Math.max(automation.start ?? now, now)
90
- const delay = Math.max(start - now, 0)
91
- if (delay < Number.POSITIVE_INFINITY) {
92
- // eslint-disable-next-line @typescript-eslint/no-misused-promises
93
- this.timeoutId = setTimeout(async () => {
94
- this.timeoutId = undefined
95
- return await spanRootAsync('start.setTimeout', async () => {
96
- try {
97
- // Run the automation
98
- await this.trigger(automation)
99
- this.stop()
100
- } catch (ex) {
101
- this.logger?.error('Error running automation', { error: ex })
102
- this.stop()
103
- } finally {
104
- // No matter what start the next automation
105
- this.start()
106
- }
107
- }, { tracer: this.tracer })
108
- }, delay)
109
- }
110
- }
111
- }
112
-
113
- stop() {
114
- if (isDefined(this.timeoutId)) {
115
- clearTimeout(this.timeoutId)
116
- this.timeoutId = undefined
117
- }
118
- }
119
-
120
- async update(hash: string, automation: SentinelAutomationPayload, restart = true) {
121
- this.remove(hash, false)
122
- await this.add(automation, false)
123
- if (restart) this.restart()
124
- }
125
-
126
- private async trigger(automation: SentinelIntervalAutomationPayload) {
127
- return await spanRootAsync('trigger', async () => {
128
- const wrapper = new SentinelIntervalAutomationWrapper(automation)
129
- this.remove(await wrapper.dataHash(), false)
130
- wrapper.next()
131
- await this.add(wrapper.payload, false)
132
- const triggerResult = await this.sentinel.report()
133
- this.onTriggerResult?.(triggerResult)
134
- }, { tracer: this.tracer })
135
- }
136
- }
package/src/index.ts DELETED
@@ -1,3 +0,0 @@
1
- export * from './MemorySentinel.ts'
2
- export * from './SentinelIntervalAutomationWrapper.ts'
3
- export * from './SentinelRunner.ts'