@xyo-network/bridge-pub-sub 3.5.2 → 3.6.0-rc.10

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/bridge-pub-sub",
3
- "version": "3.5.2",
3
+ "version": "3.6.0-rc.10",
4
4
  "description": "Primary SDK for using XYO Protocol 2.0",
5
5
  "homepage": "https://xyo.network",
6
6
  "bugs": {
@@ -29,45 +29,46 @@
29
29
  "module": "dist/neutral/index.mjs",
30
30
  "types": "dist/neutral/index.d.ts",
31
31
  "dependencies": {
32
- "@xylabs/array": "^4.4.9",
33
- "@xylabs/assert": "^4.4.9",
34
- "@xylabs/delay": "^4.4.9",
35
- "@xylabs/exists": "^4.4.9",
36
- "@xylabs/forget": "^4.4.9",
37
- "@xylabs/hex": "^4.4.9",
38
- "@xylabs/object": "^4.4.9",
39
- "@xylabs/promise": "^4.4.9",
40
- "@xylabs/timer": "^4.4.9",
41
- "@xyo-network/account": "^3.5.2",
42
- "@xyo-network/archivist-model": "^3.5.2",
43
- "@xyo-network/boundwitness-model": "^3.5.2",
44
- "@xyo-network/bridge-abstract": "^3.5.2",
45
- "@xyo-network/bridge-model": "^3.5.2",
46
- "@xyo-network/config-payload-plugin": "^3.5.2",
47
- "@xyo-network/diviner-boundwitness-model": "^3.5.2",
48
- "@xyo-network/diviner-model": "^3.5.2",
49
- "@xyo-network/module-model": "^3.5.2",
50
- "@xyo-network/node-model": "^3.5.2",
51
- "@xyo-network/payload-builder": "^3.5.2",
52
- "@xyo-network/payload-model": "^3.5.2",
32
+ "@xylabs/array": "^4.4.21",
33
+ "@xylabs/assert": "^4.4.21",
34
+ "@xylabs/delay": "^4.4.21",
35
+ "@xylabs/exists": "^4.4.21",
36
+ "@xylabs/forget": "^4.4.21",
37
+ "@xylabs/hex": "^4.4.21",
38
+ "@xylabs/object": "^4.4.21",
39
+ "@xylabs/promise": "^4.4.21",
40
+ "@xylabs/timer": "^4.4.21",
41
+ "@xyo-network/account": "^3.6.0-rc.10",
42
+ "@xyo-network/archivist-model": "^3.6.0-rc.10",
43
+ "@xyo-network/boundwitness-model": "^3.6.0-rc.10",
44
+ "@xyo-network/bridge-abstract": "^3.6.0-rc.10",
45
+ "@xyo-network/bridge-model": "^3.6.0-rc.10",
46
+ "@xyo-network/config-payload-plugin": "^3.6.0-rc.10",
47
+ "@xyo-network/diviner-boundwitness-model": "^3.6.0-rc.10",
48
+ "@xyo-network/diviner-model": "^3.6.0-rc.10",
49
+ "@xyo-network/module-model": "^3.6.0-rc.10",
50
+ "@xyo-network/node-model": "^3.6.0-rc.10",
51
+ "@xyo-network/payload-builder": "^3.6.0-rc.10",
52
+ "@xyo-network/payload-model": "^3.6.0-rc.10",
53
53
  "async-mutex": "^0.5.0",
54
54
  "lru-cache": "^11.0.2"
55
55
  },
56
56
  "devDependencies": {
57
- "@xylabs/logger": "^4.4.9",
58
- "@xylabs/ts-scripts-yarn3": "^4.2.4",
59
- "@xylabs/tsconfig": "^4.2.4",
60
- "@xylabs/vitest-extended": "^4.4.9",
61
- "@xyo-network/archivist-memory": "^3.5.2",
62
- "@xyo-network/diviner-boundwitness-memory": "^3.5.2",
63
- "@xyo-network/module-abstract": "^3.5.2",
64
- "@xyo-network/node-memory": "^3.5.2",
65
- "@xyo-network/node-model": "^3.5.2",
66
- "@xyo-network/payload-wrapper": "^3.5.2",
57
+ "@xylabs/logger": "^4.4.21",
58
+ "@xylabs/ts-scripts-yarn3": "^4.2.6",
59
+ "@xylabs/tsconfig": "^4.2.6",
60
+ "@xylabs/vitest-extended": "^4.4.21",
61
+ "@xyo-network/archivist-memory": "^3.6.0-rc.10",
62
+ "@xyo-network/diviner-boundwitness-memory": "^3.6.0-rc.10",
63
+ "@xyo-network/module-abstract": "^3.6.0-rc.10",
64
+ "@xyo-network/node-memory": "^3.6.0-rc.10",
65
+ "@xyo-network/node-model": "^3.6.0-rc.10",
66
+ "@xyo-network/payload-wrapper": "^3.6.0-rc.10",
67
67
  "typescript": "^5.7.2",
68
- "vitest": "^2.1.5"
68
+ "vitest": "^2.1.8"
69
69
  },
70
70
  "publishConfig": {
71
71
  "access": "public"
72
- }
72
+ },
73
+ "stableVersion": "3.5.2"
73
74
  }
@@ -1,5 +1,5 @@
1
1
  import { assertEx } from '@xylabs/assert'
2
- import type { Address } from '@xylabs/hex'
2
+ import type { Address, Hex } from '@xylabs/hex'
3
3
  import type { TypeCheck } from '@xylabs/object'
4
4
  import { Base } from '@xylabs/object'
5
5
  import type { ArchivistInstance } from '@xyo-network/archivist-model'
@@ -12,6 +12,7 @@ import type {
12
12
  ModuleConfig, ModuleIdentifier, ModuleInstance,
13
13
  } from '@xyo-network/module-model'
14
14
  import { ResolveHelper } from '@xyo-network/module-model'
15
+ import { SequenceConstants } from '@xyo-network/payload-model'
15
16
  import { Mutex } from 'async-mutex'
16
17
  import { LRUCache } from 'lru-cache'
17
18
 
@@ -22,7 +23,7 @@ const POLLING_FREQUENCY_MAX = 60_000 as const
22
23
  const POLLING_FREQUENCY_DEFAULT = 1000 as const
23
24
 
24
25
  export class AsyncQueryBusBase<TParams extends AsyncQueryBusParams = AsyncQueryBusParams> extends Base<TParams> {
25
- protected _lastState?: LRUCache<Address, number>
26
+ protected _lastState?: LRUCache<Address, Hex>
26
27
  protected _targetConfigs: Record<Address, ModuleConfig> = {}
27
28
  protected _targetQueries: Record<Address, string[]> = {}
28
29
 
@@ -57,9 +58,9 @@ export class AsyncQueryBusBase<TParams extends AsyncQueryBusParams = AsyncQueryB
57
58
  /**
58
59
  * A cache of the last offset of the Diviner process per address
59
60
  */
60
- protected get lastState(): LRUCache<Address, number> {
61
+ protected get lastState(): LRUCache<Address, Hex> {
61
62
  const requiredConfig = { max: 1000, ttl: 0 }
62
- this._lastState = this._lastState ?? new LRUCache<Address, number>(requiredConfig)
63
+ this._lastState = this._lastState ?? new LRUCache<Address, Hex>(requiredConfig)
63
64
  return this._lastState
64
65
  }
65
66
 
@@ -119,7 +120,7 @@ export class AsyncQueryBusBase<TParams extends AsyncQueryBusParams = AsyncQueryB
119
120
  * @param address The module address to commit the state for
120
121
  * @param nextState The state to commit
121
122
  */
122
- protected async commitState(address: Address, nextState: number) {
123
+ protected async commitState(address: Address, nextState: Hex) {
123
124
  await Promise.resolve()
124
125
  // TODO: Offload to Archivist/Diviner instead of in-memory
125
126
  const lastState = this.lastState.get(address)
@@ -131,13 +132,11 @@ export class AsyncQueryBusBase<TParams extends AsyncQueryBusParams = AsyncQueryB
131
132
  * Retrieves the last state of the process. Used to recover state after
132
133
  * preemptions, reboots, etc.
133
134
  */
134
- protected async retrieveState(address: Address): Promise<number> {
135
+ protected async retrieveState(address: Address): Promise<Hex> {
135
136
  await Promise.resolve()
136
137
  const state = this.lastState.get(address)
137
138
  if (state === undefined) {
138
- // If this is a boot we can go back a bit in time
139
- // and begin processing recent commands
140
- const newState = Date.now() - 1000
139
+ const newState = SequenceConstants.minLocalSequence
141
140
  this.lastState.set(address, newState)
142
141
  return newState
143
142
  } else {
@@ -4,13 +4,13 @@ import { forget } from '@xylabs/forget'
4
4
  import type { Address } from '@xylabs/hex'
5
5
  import { clearTimeoutEx, setTimeoutEx } from '@xylabs/timer'
6
6
  import type { QueryBoundWitness } from '@xyo-network/boundwitness-model'
7
- import { isBoundWitnessWithMeta } from '@xyo-network/boundwitness-model'
7
+ import { isBoundWitness } from '@xyo-network/boundwitness-model'
8
8
  import type { BoundWitnessDivinerQueryPayload } from '@xyo-network/diviner-boundwitness-model'
9
9
  import { BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'
10
10
  import type { CacheConfig, ModuleQueryResult } from '@xyo-network/module-model'
11
11
  import { PayloadBuilder } from '@xyo-network/payload-builder'
12
12
  import type {
13
- ModuleError, Payload, PayloadWithMeta, WithMeta,
13
+ ModuleError, Payload, WithSources,
14
14
  } from '@xyo-network/payload-model'
15
15
  import { LRUCache } from 'lru-cache'
16
16
 
@@ -54,8 +54,7 @@ export class AsyncQueryBusClient<TParams extends AsyncQueryBusClientParams = Asy
54
54
 
55
55
  async send(address: Address, query: QueryBoundWitness, payloads?: Payload[] | undefined): Promise<ModuleQueryResult> {
56
56
  this.logger?.debug(`Begin issuing query to: ${address}`)
57
- const $meta = { ...query?.$meta, destination: [address] }
58
- const routedQuery = await PayloadBuilder.build({ ...query, $meta })
57
+ const routedQuery = { ...query, $destination: [address] }
59
58
  // console.log('queryArchivist - calling')
60
59
  const queryArchivist = assertEx(
61
60
  await this.queriesArchivist(),
@@ -69,11 +68,7 @@ export class AsyncQueryBusClient<TParams extends AsyncQueryBusClientParams = Asy
69
68
  // they sent us (which might be OK since it reflect the chain of custody)
70
69
  // Revisit this once we have proxy module support as they are another
71
70
  // intermediary to consider.
72
- const routedQueryHash
73
- // Trust the signed hash if it's there
74
- = (routedQuery as WithMeta<QueryBoundWitness>)?.$hash
75
- // Calculate the hash otherwise
76
- ?? Object.keys(await PayloadBuilder.dataHash(routedQuery))
71
+ const routedQueryHash = await PayloadBuilder.dataHash(routedQuery)
77
72
  this.logger?.debug(`Issuing query: ${routedQueryHash} to: ${address}`)
78
73
  // If there was data associated with the query, add it to the insert
79
74
  const data = payloads ? [routedQuery, ...payloads] : [routedQuery]
@@ -110,11 +105,11 @@ export class AsyncQueryBusClient<TParams extends AsyncQueryBusClientParams = Asy
110
105
  this.logger?.error('Timeout waiting for query response')
111
106
  // Resolve with error to match what a local module would do if it were to error
112
107
  // TODO: BW Builder/Sign result as this module?
113
- const error: ModuleError = {
108
+ const error: WithSources<ModuleError> = {
114
109
  message: 'Timeout waiting for query response',
115
110
  query: 'network.xyo.boundwitness',
116
111
  schema: 'network.xyo.error.module',
117
- sources: [routedQueryHash],
112
+ $sources: [routedQueryHash],
118
113
  }
119
114
  reject(error)
120
115
  return
@@ -162,11 +157,11 @@ export class AsyncQueryBusClient<TParams extends AsyncQueryBusClientParams = Asy
162
157
  }
163
158
  const result = await responseBoundWitnessDiviner.divine([divinerQuery])
164
159
  if (result && result.length > 0) {
165
- const response = result.find(isBoundWitnessWithMeta)
166
- if (response && (response?.$meta as unknown as { sourceQuery: string })?.sourceQuery === sourceQuery) {
160
+ const response = result.find(isBoundWitness)
161
+ if (response && (response as unknown as { $sourceQuery: string })?.$sourceQuery === sourceQuery) {
167
162
  this.logger?.debug(`Found response to query: ${sourceQuery}`)
168
163
  // Get any payloads associated with the response
169
- const payloads: PayloadWithMeta[] = response.payload_hashes?.length > 0 ? await responseArchivist.get(response.payload_hashes) : []
164
+ const payloads: Payload[] = response.payload_hashes?.length > 0 ? await responseArchivist.get(response.payload_hashes) : []
170
165
  this.queryCache.set(sourceQuery, [response, payloads, []])
171
166
  }
172
167
  }
@@ -3,7 +3,7 @@ import { assertEx } from '@xylabs/assert'
3
3
  import type { Address } from '@xylabs/hex'
4
4
  import { clearTimeoutEx, setTimeoutEx } from '@xylabs/timer'
5
5
  import type { QueryBoundWitness } from '@xyo-network/boundwitness-model'
6
- import { isQueryBoundWitnessWithMeta } from '@xyo-network/boundwitness-model'
6
+ import { isQueryBoundWitnessWithStorageMeta } from '@xyo-network/boundwitness-model'
7
7
  import { isBridgeInstance } from '@xyo-network/bridge-model'
8
8
  import type { BoundWitnessDivinerQueryPayload } from '@xyo-network/diviner-boundwitness-model'
9
9
  import { BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'
@@ -18,7 +18,9 @@ import {
18
18
  ResolveHelper,
19
19
  } from '@xyo-network/module-model'
20
20
  import { PayloadBuilder } from '@xyo-network/payload-builder'
21
- import type { Schema, WithMeta } from '@xyo-network/payload-model'
21
+ import {
22
+ type Schema, SequenceConstants, type WithStorageMeta,
23
+ } from '@xyo-network/payload-model'
22
24
 
23
25
  import { AsyncQueryBusBase } from './AsyncQueryBusBase.ts'
24
26
  import type { AsyncQueryBusHostParams } from './model/index.ts'
@@ -132,7 +134,7 @@ export class AsyncQueryBusHost<TParams extends AsyncQueryBusHostParams = AsyncQu
132
134
  }
133
135
 
134
136
  // eslint-disable-next-line complexity
135
- protected callLocalModule = async (localModule: ModuleInstance, query: WithMeta<QueryBoundWitness>) => {
137
+ protected callLocalModule = async (localModule: ModuleInstance, query: WithStorageMeta<QueryBoundWitness>) => {
136
138
  this._idle = false
137
139
  this._lastQueryTime = Date.now()
138
140
  const localModuleName = localModule.id
@@ -144,7 +146,7 @@ export class AsyncQueryBusHost<TParams extends AsyncQueryBusHostParams = AsyncQu
144
146
  await this.responsesArchivist(),
145
147
  () => `Unable to contact responsesArchivist [${this.config?.intersect?.queries?.archivist}]`,
146
148
  )
147
- const queryDestination = (query.$meta as { destination?: string[] })?.destination
149
+ const queryDestination = (query as { $destination?: string[] })?.$destination
148
150
  if (queryDestination && queryDestination?.includes(localModule.address)) {
149
151
  // Find the query
150
152
  const queryIndex = query.payload_hashes.indexOf(query.query)
@@ -156,7 +158,7 @@ export class AsyncQueryBusHost<TParams extends AsyncQueryBusHostParams = AsyncQu
156
158
  const queryPayloads = await queryArchivist.get(query.payload_hashes)
157
159
  this.params.onQueryFulfillStarted?.({ payloads: queryPayloads, query })
158
160
  const queryPayloadsDict = await PayloadBuilder.toAllHashMap(queryPayloads)
159
- const queryHash = (await PayloadBuilder.build(query)).$hash
161
+ const queryHash = await PayloadBuilder.dataHash(query)
160
162
  // Check that we have all the arguments for the command
161
163
  if (!containsAll(Object.keys(queryPayloadsDict), query.payload_hashes)) {
162
164
  this.logger?.error(`Error processing command ${queryHash} for module ${localModuleName}, missing payloads`)
@@ -179,11 +181,11 @@ export class AsyncQueryBusHost<TParams extends AsyncQueryBusHostParams = AsyncQu
179
181
  if (insertResult.length === 0) {
180
182
  this.logger?.error(`Error replying to query ${queryHash} addressed to module: ${localModuleName}`)
181
183
  }
182
- if (query?.timestamp) {
184
+ if (query?._sequence) {
183
185
  // TODO: This needs to be thought through as we can't use a distributed timestamp
184
186
  // because of collisions. We need to ensure we are using the timestamp of the store
185
187
  // so there's no chance of multiple commands at the same time
186
- await this.commitState(localModule.address, query.timestamp)
188
+ await this.commitState(localModule.address, query._sequence)
187
189
  }
188
190
  this.params.onQueryFulfillFinished?.({
189
191
  payloads: queryPayloads, query, result, status: 'success',
@@ -217,11 +219,13 @@ export class AsyncQueryBusHost<TParams extends AsyncQueryBusHostParams = AsyncQu
217
219
  limit,
218
220
  order: 'asc',
219
221
  schema: BoundWitnessDivinerQuerySchema,
220
- timestamp: prevState + 1,
222
+ cursor: prevState,
221
223
  }
222
224
  const result = await queriesBoundWitnessDiviner.divine([divinerQuery])
223
- const queries = result.filter(isQueryBoundWitnessWithMeta)
224
- const nextState = queries.length > 0 ? Math.max(...queries.map(c => c.timestamp ?? prevState)) + 1 : Date.now()
225
+ const queries = result.filter(isQueryBoundWitnessWithStorageMeta)
226
+ // eslint-disable-next-line unicorn/no-array-reduce, unicorn/prefer-math-min-max
227
+ const highestQuerySequence = queries.reduce((acc, query) => acc = (query._sequence > acc ? query._sequence : acc), SequenceConstants.minLocalSequence)
228
+ const nextState = queries.length > 0 ? highestQuerySequence : SequenceConstants.minLocalSequence
225
229
  // TODO: This needs to be thought through as we can't use a distributed timestamp
226
230
  // because of collisions. We need to use the timestamp of the store so there's no
227
231
  // chance of multiple commands at the same time