@xyo-network/archivist 2.44.1 → 2.45.0-rc.2

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.
@@ -40,12 +40,8 @@ export abstract class AbstractArchivist<TConfig extends ArchivistConfig = Archiv
40
40
  {
41
41
  private _parents?: XyoArchivistParentWrappers
42
42
 
43
- protected get cacheParentReads() {
44
- return !!this.config?.cacheParentReads
45
- }
46
-
47
- protected get writeThrough() {
48
- return !!this.config?.writeThrough
43
+ protected get storeParentReads() {
44
+ return !!this.config?.storeParentReads
49
45
  }
50
46
 
51
47
  public all(): PromisableArray<XyoPayload> {
@@ -74,6 +70,16 @@ export abstract class AbstractArchivist<TConfig extends ArchivistConfig = Archiv
74
70
  }
75
71
  }
76
72
 
73
+ public async get(hashes: string[]): Promise<XyoPayload[]> {
74
+ return compact(
75
+ await Promise.all(
76
+ hashes.map(async (hash) => {
77
+ return (await this.getFromParents(hash)) ?? null
78
+ }),
79
+ ),
80
+ )
81
+ }
82
+
77
83
  public override queries() {
78
84
  return [ArchivistGetQuerySchema, ...super.queries()]
79
85
  }
@@ -128,21 +134,25 @@ export abstract class AbstractArchivist<TConfig extends ArchivistConfig = Archiv
128
134
 
129
135
  protected async getFromParents(hash: string) {
130
136
  const parents = await this.parents()
131
- return compact(
132
- await Promise.all(
133
- Object.values(parents.read ?? {}).map(async (parent) => {
134
- const queryPayload = PayloadWrapper.parse<ArchivistGetQuery>({ hashes: [hash], schema: ArchivistGetQuerySchema })
135
- const query = await this.bindQuery(queryPayload)
136
- const [, payloads] = (await parent?.query(query[0], query[1])) ?? []
137
- const wrapper = payloads?.[0] ? new PayloadWrapper(payloads?.[0]) : undefined
138
- if (wrapper && wrapper.hash !== hash) {
139
- console.warn(`Parent [${parent?.address}] returned payload with invalid hash [${hash} != ${wrapper.hash}]`)
140
- return null
141
- }
142
- return wrapper?.payload
143
- }),
144
- ),
145
- )[0]
137
+ if (Object.entries(parents.read ?? {}).length > 0) {
138
+ const results = compact(
139
+ await Promise.all(
140
+ Object.values(parents.read ?? {}).map(async (parent) => {
141
+ const queryPayload = PayloadWrapper.parse<ArchivistGetQuery>({ hashes: [hash], schema: ArchivistGetQuerySchema })
142
+ const query = await this.bindQuery(queryPayload)
143
+ const [, payloads] = (await parent?.query(query[0], query[1])) ?? []
144
+ const wrapper = payloads?.[0] ? new PayloadWrapper(payloads?.[0]) : undefined
145
+ if (wrapper && wrapper.hash !== hash) {
146
+ console.warn(`Parent [${parent?.address}] returned payload with invalid hash [${hash} != ${wrapper.hash}]`)
147
+ return null
148
+ }
149
+ return wrapper?.payload
150
+ }),
151
+ ),
152
+ )
153
+ return results[0]
154
+ }
155
+ return null
146
156
  }
147
157
 
148
158
  protected async parents() {
@@ -171,9 +181,10 @@ export abstract class AbstractArchivist<TConfig extends ArchivistConfig = Archiv
171
181
  ).flat()
172
182
  }
173
183
 
174
- private async resolveArchivists(archivists?: string[]) {
184
+ private async resolveArchivists(archivists: string[] = []) {
175
185
  const resolvedWrappers: Record<string, ArchivistWrapper> = {}
176
- const modules = (await this.resolver?.resolve({ address: archivists })) ?? []
186
+ const resolvedModules = await this.resolver?.resolve({ address: archivists })
187
+ const modules = resolvedModules ?? []
177
188
  modules.forEach((module) => {
178
189
  const wrapper = new ArchivistWrapper(module)
179
190
  resolvedWrappers[wrapper.address] = wrapper
@@ -181,7 +192,5 @@ export abstract class AbstractArchivist<TConfig extends ArchivistConfig = Archiv
181
192
  return resolvedWrappers
182
193
  }
183
194
 
184
- abstract get(hashes: string[]): PromisableArray<XyoPayload>
185
-
186
195
  abstract insert(item: XyoPayload[]): PromisableArray<XyoBoundWitness>
187
196
  }
@@ -142,7 +142,8 @@ export class CookieArchivist extends AbstractArchivist<CookieArchivistConfig> {
142
142
  })
143
143
  const result = await this.bindResult([...storedPayloads])
144
144
  const parentBoundWitnesses: XyoBoundWitness[] = []
145
- if (this.writeThrough) {
145
+ const parents = await this.parents()
146
+ if (Object.entries(parents.write ?? {}).length) {
146
147
  //we store the child bw also
147
148
  parentBoundWitnesses.push(...(await this.writeToParents([result[0], ...storedPayloads])))
148
149
  }
@@ -31,11 +31,11 @@ export type MemoryArchivistConfig = ArchivistConfig<{
31
31
  export class MemoryArchivist<TConfig extends MemoryArchivistConfig = MemoryArchivistConfig> extends AbstractArchivist<TConfig> {
32
32
  static override configSchema = MemoryArchivistConfigSchema
33
33
 
34
- private cache: LruCache<string, XyoPayload>
34
+ private cache: LruCache<string, XyoPayload | null>
35
35
 
36
36
  protected constructor(params: ModuleParams<TConfig>) {
37
37
  super(params)
38
- this.cache = new LruCache<string, XyoPayload>({ max: this.max })
38
+ this.cache = new LruCache<string, XyoPayload | null>({ max: this.max })
39
39
  }
40
40
 
41
41
  public get max() {
@@ -47,94 +47,67 @@ export class MemoryArchivist<TConfig extends MemoryArchivistConfig = MemoryArchi
47
47
  }
48
48
 
49
49
  public override all(): PromisableArray<XyoPayload> {
50
- try {
51
- return this.cache.dump().map((value) => value[1].value)
52
- } catch (ex) {
53
- console.error(`Error: ${JSON.stringify(ex, null, 2)}`)
54
- throw ex
55
- }
50
+ return compact(this.cache.dump().map((value) => value[1].value))
56
51
  }
57
52
 
58
53
  public override clear(): void | Promise<void> {
59
- try {
60
- this.cache.clear()
61
- } catch (ex) {
62
- console.error(`Error: ${JSON.stringify(ex, null, 2)}`)
63
- throw ex
64
- }
54
+ this.cache.clear()
65
55
  }
66
56
 
67
57
  public override async commit(): Promise<XyoBoundWitness[]> {
68
- try {
69
- const payloads = assertEx(await this.all(), 'Nothing to commit')
70
- const settled = await Promise.allSettled(
71
- compact(
72
- Object.values((await this.parents()).commit ?? [])?.map(async (parent) => {
73
- const queryPayload = PayloadWrapper.parse<ArchivistInsertQuery>({
74
- payloads: payloads.map((payload) => PayloadWrapper.hash(payload)),
75
- schema: ArchivistInsertQuerySchema,
76
- })
77
- const query = await this.bindQuery(queryPayload, payloads)
78
- return (await parent?.query(query[0], query[1]))?.[0]
79
- }),
80
- ),
81
- )
82
- await this.clear()
83
- return compact(settled.filter(fulfilled).map((result) => result.value))
84
- } catch (ex) {
85
- console.error(`Error: ${JSON.stringify(ex, null, 2)}`)
86
- throw ex
87
- }
58
+ const payloads = assertEx(await this.all(), 'Nothing to commit')
59
+ const settled = await Promise.allSettled(
60
+ compact(
61
+ Object.values((await this.parents()).commit ?? [])?.map(async (parent) => {
62
+ const queryPayload = PayloadWrapper.parse<ArchivistInsertQuery>({
63
+ payloads: payloads.map((payload) => PayloadWrapper.hash(payload)),
64
+ schema: ArchivistInsertQuerySchema,
65
+ })
66
+ const query = await this.bindQuery(queryPayload, payloads)
67
+ return (await parent?.query(query[0], query[1]))?.[0]
68
+ }),
69
+ ),
70
+ )
71
+ await this.clear()
72
+ return compact(settled.filter(fulfilled).map((result) => result.value))
88
73
  }
89
74
 
90
75
  public override delete(hashes: string[]): PromisableArray<boolean> {
91
- try {
92
- return hashes.map((hash) => {
93
- return this.cache.delete(hash)
94
- })
95
- } catch (ex) {
96
- console.error(`Error: ${JSON.stringify(ex, null, 2)}`)
97
- throw ex
98
- }
76
+ return hashes.map((hash) => {
77
+ return this.cache.delete(hash)
78
+ })
99
79
  }
100
80
 
101
81
  public async get(hashes: string[]): Promise<XyoPayload[]> {
102
- try {
103
- return await Promise.all(
82
+ return compact(
83
+ await Promise.all(
104
84
  hashes.map(async (hash) => {
105
- const payload = this.cache.get(hash) ?? (await this.getFromParents(hash)) ?? null
106
- if (this.cacheParentReads) {
85
+ const payload = this.cache.get(hash) ?? (await super.get([hash]))[0] ?? null
86
+ if (this.storeParentReads) {
107
87
  this.cache.set(hash, payload)
108
88
  }
109
89
  return payload
110
90
  }),
111
- )
112
- } catch (ex) {
113
- console.error(`Error: ${JSON.stringify(ex, null, 2)}`)
114
- throw ex
115
- }
91
+ ),
92
+ )
116
93
  }
117
94
 
118
95
  public async insert(payloads: XyoPayload[]): Promise<XyoBoundWitness[]> {
119
- try {
120
- payloads.map((payload) => {
121
- const wrapper = new PayloadWrapper(payload)
122
- const payloadWithMeta = { ...payload, _hash: wrapper.hash, _timestamp: Date.now() }
123
- this.cache.set(payloadWithMeta._hash, payloadWithMeta)
124
- return payloadWithMeta
125
- })
126
-
127
- const result = await this.bindResult([...payloads])
128
- const parentBoundWitnesses: XyoBoundWitness[] = []
129
- if (this.writeThrough) {
130
- //we store the child bw also
131
- parentBoundWitnesses.push(...(await this.writeToParents([result[0], ...payloads])))
132
- }
133
- return [result[0], ...parentBoundWitnesses]
134
- } catch (ex) {
135
- console.error(`Error: ${JSON.stringify(ex, null, 2)}`)
136
- throw ex
96
+ payloads.map((payload) => {
97
+ const wrapper = new PayloadWrapper(payload)
98
+ const payloadWithMeta = { ...payload, _hash: wrapper.hash, _timestamp: Date.now() }
99
+ this.cache.set(payloadWithMeta._hash, payloadWithMeta)
100
+ return payloadWithMeta
101
+ })
102
+
103
+ const result = await this.bindResult([...payloads])
104
+ const parentBoundWitnesses: XyoBoundWitness[] = []
105
+ const parents = await this.parents()
106
+ if (Object.entries(parents.write ?? {}).length) {
107
+ //we store the child bw also
108
+ parentBoundWitnesses.push(...(await this.writeToParents([result[0], ...payloads])))
137
109
  }
110
+ return [result[0], ...parentBoundWitnesses]
138
111
  }
139
112
 
140
113
  public override queries() {
@@ -81,100 +81,77 @@ export class XyoStorageArchivist extends AbstractArchivist<StorageArchivistConfi
81
81
 
82
82
  public override all(): PromisableArray<XyoPayload> {
83
83
  this.logger?.log(`this.storage.length: ${this.storage.length}`)
84
- try {
85
- return Object.entries(this.storage.getAll()).map(([, value]) => value)
86
- } catch (ex) {
87
- console.error(`Error: ${JSON.stringify(ex, null, 2)}`)
88
- throw ex
89
- }
84
+ return Object.entries(this.storage.getAll()).map(([, value]) => value)
90
85
  }
91
86
 
92
87
  public override clear(): void | Promise<void> {
93
88
  this.logger?.log(`this.storage.length: ${this.storage.length}`)
94
- try {
95
- this.storage.clear()
96
- } catch (ex) {
97
- console.error(`Error: ${JSON.stringify(ex, null, 2)}`)
98
- throw ex
99
- }
89
+ this.storage.clear()
100
90
  }
101
91
 
102
92
  public override async commit(): Promise<XyoBoundWitness[]> {
103
93
  this.logger?.log(`this.storage.length: ${this.storage.length}`)
104
- try {
105
- const payloads = await this.all()
106
- assertEx(payloads.length > 0, 'Nothing to commit')
107
- const settled = await Promise.allSettled(
108
- compact(
109
- Object.values((await this.parents()).commit ?? [])?.map(async (parent) => {
110
- const queryPayload = PayloadWrapper.parse<ArchivistInsertQuery>({
111
- payloads: payloads.map((payload) => PayloadWrapper.hash(payload)),
112
- schema: ArchivistInsertQuerySchema,
113
- })
114
- const query = await this.bindQuery(queryPayload, payloads)
115
- return (await parent?.query(query[0], query[1]))?.[0]
116
- }),
117
- ),
118
- )
119
- // TODO - rather than clear, delete the payloads that come back as successfully inserted
120
- await this.clear()
121
- return compact(settled.filter(fulfilled).map((result) => result.value))
122
- } catch (ex) {
123
- console.error(`Error: ${JSON.stringify(ex, null, 2)}`)
124
- throw ex
125
- }
94
+ const payloads = await this.all()
95
+ assertEx(payloads.length > 0, 'Nothing to commit')
96
+ const settled = await Promise.allSettled(
97
+ compact(
98
+ Object.values((await this.parents()).commit ?? [])?.map(async (parent) => {
99
+ const queryPayload = PayloadWrapper.parse<ArchivistInsertQuery>({
100
+ payloads: payloads.map((payload) => PayloadWrapper.hash(payload)),
101
+ schema: ArchivistInsertQuerySchema,
102
+ })
103
+ const query = await this.bindQuery(queryPayload, payloads)
104
+ return (await parent?.query(query[0], query[1]))?.[0]
105
+ }),
106
+ ),
107
+ )
108
+ // TODO - rather than clear, delete the payloads that come back as successfully inserted
109
+ await this.clear()
110
+ return compact(settled.filter(fulfilled).map((result) => result.value))
126
111
  }
127
112
 
128
113
  public override delete(hashes: string[]): PromisableArray<boolean> {
129
114
  this.logger?.log(`hashes.length: ${hashes.length}`)
130
- try {
131
- return hashes.map((hash) => {
132
- this.storage.remove(hash)
133
- return true
134
- })
135
- } catch (ex) {
136
- console.error(`Error: ${JSON.stringify(ex, null, 2)}`)
137
- throw ex
138
- }
115
+ return hashes.map((hash) => {
116
+ this.storage.remove(hash)
117
+ return true
118
+ })
139
119
  }
140
120
 
141
121
  public async get(hashes: string[]): Promise<XyoPayload[]> {
142
122
  this.logger?.log(`hashes.length: ${hashes.length}`)
143
- try {
144
- return await Promise.all(
145
- hashes.map(async (hash) => {
146
- const value = this.storage.get(hash)
147
- return value ?? (await this.getFromParents(hash)) ?? null
148
- }),
149
- )
150
- } catch (ex) {
151
- console.error(`Error: ${JSON.stringify(ex, null, 2)}`)
152
- throw ex
153
- }
123
+
124
+ return await Promise.all(
125
+ hashes.map(async (hash) => {
126
+ const payload = this.storage.get(hash) ?? (await super.get([hash]))[0] ?? null
127
+ if (this.storeParentReads) {
128
+ this.storage.set(hash, payload)
129
+ }
130
+ return payload
131
+ }),
132
+ )
154
133
  }
155
134
 
156
135
  public async insert(payloads: XyoPayload[]): Promise<XyoBoundWitness[]> {
157
136
  this.logger?.log(`payloads.length: ${payloads.length}`)
158
- try {
159
- const storedPayloads = payloads.map((payload) => {
160
- const wrapper = new PayloadWrapper(payload)
161
- const hash = wrapper.hash
162
- const value = JSON.stringify(wrapper.payload)
163
- assertEx(value.length < this.maxEntrySize, `Payload too large [${wrapper.hash}, ${value.length}]`)
164
- this.storage.set(hash, wrapper.payload)
165
- return wrapper.payload
166
- })
167
- const result = await this.bindResult([...storedPayloads])
168
- const parentBoundWitnesses: XyoBoundWitness[] = []
169
- if (this.writeThrough) {
170
- //we store the child bw also
171
- parentBoundWitnesses.push(...(await this.writeToParents([result[0], ...storedPayloads])))
172
- }
173
- return [result[0], ...parentBoundWitnesses]
174
- } catch (ex) {
175
- console.error(`Error: ${ex}`)
176
- throw ex
137
+
138
+ const storedPayloads = payloads.map((payload) => {
139
+ const wrapper = new PayloadWrapper(payload)
140
+ const hash = wrapper.hash
141
+ const value = JSON.stringify(wrapper.payload)
142
+ assertEx(value.length < this.maxEntrySize, `Payload too large [${wrapper.hash}, ${value.length}]`)
143
+ this.storage.set(hash, wrapper.payload)
144
+ return wrapper.payload
145
+ })
146
+ const [storageBoundWitness] = await this.bindResult([...storedPayloads])
147
+ const parentBoundWitnesses: XyoBoundWitness[] = []
148
+ const parents = await this.parents()
149
+ if (Object.entries(parents.write ?? {}).length) {
150
+ //we store the child bw also
151
+ const [parentBoundWitness] = await this.writeToParents([storageBoundWitness, ...storedPayloads])
152
+ parentBoundWitnesses.push(parentBoundWitness)
177
153
  }
154
+ return [storageBoundWitness, ...parentBoundWitnesses]
178
155
  }
179
156
 
180
157
  public override queries() {
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import { Account } from '@xyo-network/account'
6
- import { SimpleModuleResolver } from '@xyo-network/module'
6
+ import { CompositeModuleResolver } from '@xyo-network/module'
7
7
  import { PayloadWrapper } from '@xyo-network/payload-wrapper'
8
8
 
9
9
  import { MemoryArchivist } from '../MemoryArchivist'
@@ -76,14 +76,21 @@ test('XyoArchivist Parent Write Through', async () => {
76
76
  schema: StorageArchivistConfigSchema,
77
77
  type: 'local',
78
78
  },
79
- resolver: new SimpleModuleResolver().add(memory),
79
+ resolver: new CompositeModuleResolver().add(memory),
80
80
  })
81
- await storage.start()
81
+ expect(await storage.start()).toBeDefined()
82
82
 
83
83
  const wrapper = new PayloadWrapper({ schema: 'network.xyo.test' })
84
84
 
85
- await storage.insert([wrapper.payload])
85
+ expect(wrapper).toBeDefined()
86
86
 
87
- expect((await storage.get([wrapper.hash])).length).toBe(1)
88
- expect((await memory.get([wrapper.hash])).length).toBe(1)
87
+ const inserted = await storage.insert([wrapper.payload])
88
+
89
+ expect(inserted).toBeArrayOfSize(2)
90
+
91
+ const fromStorage = await storage.get([wrapper.hash])
92
+ const fromMemory = await memory.get([wrapper.hash])
93
+
94
+ expect(fromStorage).toBeArrayOfSize(1)
95
+ expect(fromMemory).toBeArrayOfSize(1)
89
96
  })