@xyo-network/sentinel-memory 2.85.5

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.
Files changed (64) hide show
  1. package/LICENSE +165 -0
  2. package/README.md +13 -0
  3. package/dist/browser/MemorySentinel.d.cts +16 -0
  4. package/dist/browser/MemorySentinel.d.cts.map +1 -0
  5. package/dist/browser/MemorySentinel.d.mts +16 -0
  6. package/dist/browser/MemorySentinel.d.mts.map +1 -0
  7. package/dist/browser/MemorySentinel.d.ts +16 -0
  8. package/dist/browser/MemorySentinel.d.ts.map +1 -0
  9. package/dist/browser/SentinelIntervalAutomationWrapper.d.cts +21 -0
  10. package/dist/browser/SentinelIntervalAutomationWrapper.d.cts.map +1 -0
  11. package/dist/browser/SentinelIntervalAutomationWrapper.d.mts +21 -0
  12. package/dist/browser/SentinelIntervalAutomationWrapper.d.mts.map +1 -0
  13. package/dist/browser/SentinelIntervalAutomationWrapper.d.ts +21 -0
  14. package/dist/browser/SentinelIntervalAutomationWrapper.d.ts.map +1 -0
  15. package/dist/browser/SentinelRunner.d.cts +23 -0
  16. package/dist/browser/SentinelRunner.d.cts.map +1 -0
  17. package/dist/browser/SentinelRunner.d.mts +23 -0
  18. package/dist/browser/SentinelRunner.d.mts.map +1 -0
  19. package/dist/browser/SentinelRunner.d.ts +23 -0
  20. package/dist/browser/SentinelRunner.d.ts.map +1 -0
  21. package/dist/browser/index.cjs +310 -0
  22. package/dist/browser/index.cjs.map +1 -0
  23. package/dist/browser/index.d.cts +2 -0
  24. package/dist/browser/index.d.cts.map +1 -0
  25. package/dist/browser/index.d.mts +2 -0
  26. package/dist/browser/index.d.mts.map +1 -0
  27. package/dist/browser/index.d.ts +2 -0
  28. package/dist/browser/index.d.ts.map +1 -0
  29. package/dist/browser/index.js +289 -0
  30. package/dist/browser/index.js.map +1 -0
  31. package/dist/node/MemorySentinel.d.cts +16 -0
  32. package/dist/node/MemorySentinel.d.cts.map +1 -0
  33. package/dist/node/MemorySentinel.d.mts +16 -0
  34. package/dist/node/MemorySentinel.d.mts.map +1 -0
  35. package/dist/node/MemorySentinel.d.ts +16 -0
  36. package/dist/node/MemorySentinel.d.ts.map +1 -0
  37. package/dist/node/SentinelIntervalAutomationWrapper.d.cts +21 -0
  38. package/dist/node/SentinelIntervalAutomationWrapper.d.cts.map +1 -0
  39. package/dist/node/SentinelIntervalAutomationWrapper.d.mts +21 -0
  40. package/dist/node/SentinelIntervalAutomationWrapper.d.mts.map +1 -0
  41. package/dist/node/SentinelIntervalAutomationWrapper.d.ts +21 -0
  42. package/dist/node/SentinelIntervalAutomationWrapper.d.ts.map +1 -0
  43. package/dist/node/SentinelRunner.d.cts +23 -0
  44. package/dist/node/SentinelRunner.d.cts.map +1 -0
  45. package/dist/node/SentinelRunner.d.mts +23 -0
  46. package/dist/node/SentinelRunner.d.mts.map +1 -0
  47. package/dist/node/SentinelRunner.d.ts +23 -0
  48. package/dist/node/SentinelRunner.d.ts.map +1 -0
  49. package/dist/node/index.cjs +322 -0
  50. package/dist/node/index.cjs.map +1 -0
  51. package/dist/node/index.d.cts +2 -0
  52. package/dist/node/index.d.cts.map +1 -0
  53. package/dist/node/index.d.mts +2 -0
  54. package/dist/node/index.d.mts.map +1 -0
  55. package/dist/node/index.d.ts +2 -0
  56. package/dist/node/index.d.ts.map +1 -0
  57. package/dist/node/index.js +297 -0
  58. package/dist/node/index.js.map +1 -0
  59. package/package.json +77 -0
  60. package/src/MemorySentinel.ts +128 -0
  61. package/src/SentinelIntervalAutomationWrapper.ts +76 -0
  62. package/src/SentinelRunner.ts +114 -0
  63. package/src/index.ts +1 -0
  64. package/typedoc.json +5 -0
@@ -0,0 +1,76 @@
1
+ import { PayloadWrapper } from '@xyo-network/payload-wrapper'
2
+ import { 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.jsonPayload().frequency
13
+ if (frequency === undefined) return Number.POSITIVE_INFINITY
14
+ const frequencyUnits = this.jsonPayload().frequencyUnits
15
+ switch (frequencyUnits ?? 'hour') {
16
+ case 'second': {
17
+ return frequency * 1000
18
+ }
19
+ case 'minute': {
20
+ return frequency * 60 * 1000
21
+ }
22
+ case 'hour': {
23
+ return frequency * 60 * 60 * 1000
24
+ }
25
+ case 'day': {
26
+ return frequency * 24 * 60 * 60 * 1000
27
+ }
28
+ default: {
29
+ return Number.POSITIVE_INFINITY
30
+ }
31
+ }
32
+ }
33
+
34
+ protected get remaining() {
35
+ return this.jsonPayload().remaining ?? Number.POSITIVE_INFINITY
36
+ }
37
+
38
+ next() {
39
+ const now = Date.now()
40
+ const previousStart = this.jsonPayload()?.start ?? now
41
+ const start = Math.max(previousStart, now)
42
+ const nextStart = start + this.frequencyMillis
43
+ this.setStart(nextStart)
44
+ this.consumeRemaining()
45
+ this.checkEnd()
46
+ return this
47
+ }
48
+
49
+ protected checkEnd() {
50
+ if (this.jsonPayload().start > (this.jsonPayload().end ?? Number.POSITIVE_INFINITY)) {
51
+ this.setStart(Number.POSITIVE_INFINITY)
52
+ }
53
+ }
54
+
55
+ protected consumeRemaining(count = 1) {
56
+ const remaining = Math.max(this.remaining - count, 0)
57
+ this.setRemaining(remaining)
58
+ if (remaining <= 0) this.setStart(Number.POSITIVE_INFINITY)
59
+ }
60
+
61
+ /**
62
+ * Sets the remaining of the wrapped automation
63
+ * @param remaining The remaining time in milliseconds
64
+ */
65
+ protected setRemaining(remaining: number) {
66
+ this.obj.remaining = remaining
67
+ }
68
+
69
+ /**
70
+ * Sets the start of the wrapped automation
71
+ * @param start The start time in milliseconds
72
+ */
73
+ protected setStart(start: number) {
74
+ this.obj.start = start
75
+ }
76
+ }
@@ -0,0 +1,114 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { Payload } from '@xyo-network/payload-model'
3
+ import { PayloadWrapper } from '@xyo-network/payload-wrapper'
4
+ import {
5
+ isSentinelIntervalAutomation,
6
+ SentinelAutomationPayload,
7
+ SentinelInstance,
8
+ SentinelIntervalAutomationPayload,
9
+ } from '@xyo-network/sentinel-model'
10
+
11
+ import { SentinelIntervalAutomationWrapper } from './SentinelIntervalAutomationWrapper'
12
+
13
+ export type OnSentinelRunnerTriggerResult = (result: Payload[]) => void
14
+
15
+ export class SentinelRunner {
16
+ protected _automations: Record<string, SentinelAutomationPayload> = {}
17
+ protected onTriggerResult: OnSentinelRunnerTriggerResult | undefined
18
+ protected sentinel: SentinelInstance
19
+ protected timeoutId?: NodeJS.Timeout | string | number
20
+
21
+ constructor(sentinel: SentinelInstance, automations?: SentinelAutomationPayload[], onTriggerResult?: OnSentinelRunnerTriggerResult) {
22
+ this.sentinel = sentinel
23
+ this.onTriggerResult = onTriggerResult
24
+ if (automations) for (const automation of automations) this.add(automation)
25
+ }
26
+
27
+ get automations() {
28
+ return this._automations
29
+ }
30
+
31
+ private get next() {
32
+ // eslint-disable-next-line unicorn/no-array-reduce
33
+ return Object.values(this._automations).reduce<SentinelAutomationPayload | undefined>((previous, current) => {
34
+ if (isSentinelIntervalAutomation(current) && isSentinelIntervalAutomation(previous)) {
35
+ return current.start < (previous?.start ?? Number.POSITIVE_INFINITY) ? current : previous
36
+ }
37
+ return current
38
+ // eslint-disable-next-line unicorn/no-useless-undefined
39
+ }, undefined)
40
+ }
41
+
42
+ async add(automation: SentinelAutomationPayload, restart = true) {
43
+ const hash = await PayloadWrapper.hashAsync(automation)
44
+ this._automations[hash] = automation
45
+ if (restart) await this.restart()
46
+ return hash
47
+ }
48
+
49
+ find(hash: string) {
50
+ Object.entries(this._automations).find(([key]) => key === hash)
51
+ }
52
+
53
+ async remove(hash: string, restart = true) {
54
+ delete this._automations[hash]
55
+ if (restart) await this.restart()
56
+ }
57
+
58
+ removeAll() {
59
+ this.stop()
60
+ this._automations = {}
61
+ }
62
+
63
+ async restart() {
64
+ this.stop()
65
+ await this.start()
66
+ }
67
+
68
+ async start() {
69
+ // NOTE: Keep async to match module start signature
70
+ await Promise.resolve()
71
+ assertEx(this.timeoutId === undefined, 'Already started')
72
+ const automation = this.next
73
+ if (isSentinelIntervalAutomation(automation)) {
74
+ const now = Date.now()
75
+ const start = Math.max(automation.start ?? now, now)
76
+ const delay = Math.max(start - now, 0)
77
+ if (delay < Number.POSITIVE_INFINITY) {
78
+ this.timeoutId = setTimeout(async () => {
79
+ try {
80
+ // Run the automation
81
+ await this.trigger(automation)
82
+ this.stop()
83
+ } finally {
84
+ // No matter what start the next automation
85
+ await this.start()
86
+ }
87
+ }, delay)
88
+ }
89
+ }
90
+ }
91
+
92
+ stop() {
93
+ if (this.timeoutId) {
94
+ clearTimeout(this.timeoutId)
95
+ this.timeoutId = undefined
96
+ }
97
+ }
98
+
99
+ async update(hash: string, automation: SentinelAutomationPayload, restart = true) {
100
+ await this.remove(hash, false)
101
+ await this.add(automation, false)
102
+ if (restart) await this.restart()
103
+ }
104
+
105
+ private async trigger(automation: SentinelIntervalAutomationPayload) {
106
+ const wrapper = new SentinelIntervalAutomationWrapper(automation)
107
+ await this.remove(await wrapper.hashAsync(), false)
108
+ wrapper.next()
109
+ await this.add(wrapper.jsonPayload(), false)
110
+ const triggerResult = await this.sentinel.report()
111
+ this.onTriggerResult?.(triggerResult)
112
+ // await this.start()
113
+ }
114
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './MemorySentinel'
package/typedoc.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "$schema": "https://typedoc.org/schema.json",
3
+ "entryPoints": ["src/index.ts"],
4
+ "tsconfig": "./tsconfig.typedoc.json"
5
+ }