@xyo-network/bridge-http 5.3.22 → 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/bridge-http",
3
- "version": "5.3.22",
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,63 +30,59 @@
30
30
  "types": "dist/neutral/index.d.ts",
31
31
  "files": [
32
32
  "dist",
33
- "src",
34
33
  "README.md",
35
34
  "LICENSE",
36
35
  "package.json"
37
36
  ],
38
37
  "dependencies": {
39
- "@xyo-network/account": "~5.3.22",
40
- "@xyo-network/boundwitness-model": "~5.3.22",
41
- "@xyo-network/bridge-abstract": "~5.3.22",
42
- "@xyo-network/bridge-model": "~5.3.22",
43
- "@xyo-network/config-payload-plugin": "~5.3.22",
44
- "@xyo-network/manifest-model": "~5.3.22",
45
- "@xyo-network/module-model": "~5.3.22",
46
- "@xyo-network/node-model": "~5.3.22",
47
- "@xyo-network/payload-model": "~5.3.22",
48
38
  "async-mutex": "~0.5.0",
49
- "lru-cache": "~11.2.7"
39
+ "lru-cache": "~11.2.7",
40
+ "@xyo-network/account": "~5.3.24",
41
+ "@xyo-network/boundwitness-model": "~5.3.24",
42
+ "@xyo-network/bridge-abstract": "~5.3.24",
43
+ "@xyo-network/config-payload-plugin": "~5.3.24",
44
+ "@xyo-network/node-model": "~5.3.24",
45
+ "@xyo-network/bridge-model": "~5.3.24",
46
+ "@xyo-network/module-model": "~5.3.24",
47
+ "@xyo-network/manifest-model": "~5.3.24",
48
+ "@xyo-network/payload-model": "~5.3.24"
50
49
  },
51
50
  "devDependencies": {
52
51
  "@opentelemetry/api": "^1.9.1",
53
52
  "@types/node": "^25.5.0",
54
- "@xylabs/sdk-js": "^5.0.91",
55
- "@xylabs/ts-scripts-common": "~7.6.8",
56
- "@xylabs/ts-scripts-yarn3": "~7.6.8",
57
- "@xylabs/tsconfig": "~7.6.8",
58
- "@xylabs/vitest-extended": "~5.0.91",
59
- "@xyo-network/account": "~5.3.22",
60
- "@xyo-network/api-models": "~5.3.22",
61
- "@xyo-network/archivist-model": "~5.3.22",
62
- "@xyo-network/boundwitness-model": "~5.3.22",
63
- "@xyo-network/bridge-abstract": "~5.3.22",
64
- "@xyo-network/bridge-model": "~5.3.22",
65
- "@xyo-network/config-payload-plugin": "~5.3.22",
66
- "@xyo-network/diviner-model": "~5.3.22",
67
- "@xyo-network/manifest-model": "~5.3.22",
68
- "@xyo-network/module-model": "~5.3.22",
69
- "@xyo-network/module-resolver": "~5.3.22",
70
- "@xyo-network/node-memory": "~5.3.22",
71
- "@xyo-network/node-model": "~5.3.22",
72
- "@xyo-network/payload-builder": "~5.3.22",
73
- "@xyo-network/payload-model": "~5.3.22",
74
- "@xyo-network/payload-wrapper": "~5.3.22",
75
- "@xyo-network/wallet": "~5.3.22",
53
+ "@xylabs/sdk-js": "^5.0.93",
54
+ "@xylabs/ts-scripts-common": "~7.6.16",
55
+ "@xylabs/ts-scripts-pnpm": "~7.6.16",
56
+ "@xylabs/tsconfig": "~7.6.16",
57
+ "@xylabs/vitest-extended": "~5.0.93",
76
58
  "acorn": "^8.16.0",
77
59
  "async-mutex": "~0.5.0",
78
60
  "axios": "^1.14.0",
79
- "cosmiconfig": "^9.0.1",
80
- "esbuild": "^0.27.4",
81
- "eslint": "^10.1.0",
61
+ "esbuild": "^0.28.0",
82
62
  "ethers": "^6.16.0",
83
- "lru-cache": "^11.2.7",
84
- "rollup": "^4.60.1",
63
+ "lru-cache": "~11.2.7",
85
64
  "tslib": "^2.8.1",
86
65
  "typescript": "~5.9.3",
87
66
  "vite": "^8.0.3",
88
67
  "vitest": "~4.1.2",
89
- "zod": "^4.3.6"
68
+ "zod": "^4.3.6",
69
+ "@xyo-network/account": "~5.3.24",
70
+ "@xyo-network/boundwitness-model": "~5.3.24",
71
+ "@xyo-network/bridge-abstract": "~5.3.24",
72
+ "@xyo-network/archivist-model": "~5.3.24",
73
+ "@xyo-network/api-models": "~5.3.24",
74
+ "@xyo-network/config-payload-plugin": "~5.3.24",
75
+ "@xyo-network/bridge-model": "~5.3.24",
76
+ "@xyo-network/manifest-model": "~5.3.24",
77
+ "@xyo-network/module-model": "~5.3.24",
78
+ "@xyo-network/diviner-model": "~5.3.24",
79
+ "@xyo-network/module-resolver": "~5.3.24",
80
+ "@xyo-network/node-model": "~5.3.24",
81
+ "@xyo-network/payload-model": "~5.3.24",
82
+ "@xyo-network/payload-builder": "~5.3.24",
83
+ "@xyo-network/node-memory": "~5.3.24",
84
+ "@xyo-network/payload-wrapper": "~5.3.24",
85
+ "@xyo-network/wallet": "~5.3.24"
90
86
  },
91
87
  "peerDependencies": {
92
88
  "@xylabs/sdk-js": "^5",
@@ -98,4 +94,4 @@
98
94
  "publishConfig": {
99
95
  "access": "public"
100
96
  }
101
- }
97
+ }
package/src/HttpBridge.ts DELETED
@@ -1,224 +0,0 @@
1
- import {
2
- Address, assertEx,
3
- axiosJsonConfig,
4
- exists,
5
- forget,
6
- Promisable, toSafeJsonString,
7
- } from '@xylabs/sdk-js'
8
- import { ApiEnvelope } from '@xyo-network/api-models'
9
- import { QueryBoundWitness } from '@xyo-network/boundwitness-model'
10
- import { AbstractBridge } from '@xyo-network/bridge-abstract'
11
- import {
12
- BridgeExposeOptions,
13
- BridgeModule,
14
- BridgeParams,
15
- BridgeUnexposeOptions,
16
- QuerySendFinishedEventArgs,
17
- QuerySendStartedEventArgs,
18
- } from '@xyo-network/bridge-model'
19
- import {
20
- ModuleManifestPayload, NodeManifestPayload, NodeManifestPayloadSchema,
21
- } from '@xyo-network/manifest-model'
22
- import {
23
- AnyConfigSchema,
24
- creatableModule,
25
- ModuleInstance,
26
- ModuleQueryResult,
27
- ModuleResolverInstance,
28
- ModuleStateQuery,
29
- ModuleStateQuerySchema,
30
- } from '@xyo-network/module-model'
31
- import { asAttachableNodeInstance } from '@xyo-network/node-model'
32
- import {
33
- isPayloadOfSchemaType, Payload, Schema,
34
- } from '@xyo-network/payload-model'
35
- import { Mutex, Semaphore } from 'async-mutex'
36
- import { Axios, AxiosError } from 'axios'
37
- import { LRUCache } from 'lru-cache'
38
-
39
- import { HttpBridgeConfig, HttpBridgeConfigSchema } from './HttpBridgeConfig.ts'
40
- import { HttpBridgeModuleResolver } from './HttpBridgeModuleResolver.ts'
41
- import { BridgeQuerySender } from './ModuleProxy/index.ts'
42
-
43
- export interface HttpBridgeParams extends BridgeParams<AnyConfigSchema<HttpBridgeConfig>> {
44
- axios?: Axios
45
- }
46
-
47
- @creatableModule()
48
- export class HttpBridge<TParams extends HttpBridgeParams> extends AbstractBridge<TParams> implements BridgeModule<TParams>, BridgeQuerySender {
49
- static readonly axios = new Axios(axiosJsonConfig())
50
- static override readonly configSchemas: Schema[] = [...super.configSchemas, HttpBridgeConfigSchema]
51
- static override readonly defaultConfigSchema: Schema = HttpBridgeConfigSchema
52
- static readonly defaultFailureRetryTime = 1000 * 60
53
- static readonly defaultMaxConnections = 4
54
- static readonly defaultMaxPayloadSizeWarning = 256 * 256
55
- static readonly maxFailureCacheSize = 1000
56
-
57
- private _axios?: Axios
58
- private _discoverRootsMutex = new Mutex()
59
- private _failureTimeCache = new LRUCache<Address, number>({ max: HttpBridge.maxFailureCacheSize })
60
- private _querySemaphore?: Semaphore
61
- private _resolver?: HttpBridgeModuleResolver
62
-
63
- get axios() {
64
- this._axios = this._axios ?? this.params.axios ?? HttpBridge.axios
65
- return this._axios
66
- }
67
-
68
- get clientUrl() {
69
- return assertEx(this.config.client?.url, () => 'No Url Set')
70
- }
71
-
72
- get failureRetryTime() {
73
- return this.config.failureRetryTime ?? HttpBridge.defaultFailureRetryTime
74
- }
75
-
76
- get maxConnections() {
77
- return this.config.maxConnections ?? HttpBridge.defaultMaxConnections
78
- }
79
-
80
- get maxPayloadSizeWarning() {
81
- return this.config.maxPayloadSizeWarning ?? HttpBridge.defaultMaxPayloadSizeWarning
82
- }
83
-
84
- get querySemaphore() {
85
- this._querySemaphore = this._querySemaphore ?? new Semaphore(this.maxConnections)
86
- return this._querySemaphore
87
- }
88
-
89
- override get resolver() {
90
- this._resolver
91
- = this._resolver
92
- ?? new HttpBridgeModuleResolver({
93
- additionalSigners: this.additionalSigners,
94
- archiving: { ...this.archiving, resolveArchivists: this.resolveArchivingArchivists.bind(this) },
95
- bridge: this,
96
- onQuerySendFinished: (args: Omit<QuerySendFinishedEventArgs, 'mod'>) => {
97
- forget(this.emit('querySendFinished', { mod: this, ...args }))
98
- },
99
- onQuerySendStarted: (args: Omit<QuerySendStartedEventArgs, 'mod'>) => {
100
- forget(this.emit('querySendStarted', { mod: this, ...args }))
101
- },
102
- querySender: this,
103
- root: this,
104
- rootUrl: this.clientUrl,
105
- wrapperAccount: this.account,
106
- })
107
- return this._resolver
108
- }
109
-
110
- override exposeHandler(_id: string, _options?: BridgeExposeOptions | undefined): Promisable<ModuleInstance[]> {
111
- throw new Error('Unsupported')
112
- }
113
-
114
- override exposedHandler(): Promisable<Address[]> {
115
- throw new Error('Unsupported')
116
- }
117
-
118
- async getRoots(force?: boolean): Promise<ModuleInstance[]> {
119
- return await this._discoverRootsMutex.runExclusive(async () => {
120
- if (this._roots === undefined || force) {
121
- const state = await this.getRootState()
122
- this.logger?.debug(`HttpBridge:discoverRoots.state [${state?.length}]`)
123
- const nodeManifest = state?.find(isPayloadOfSchemaType<NodeManifestPayload>(NodeManifestPayloadSchema))
124
- if (nodeManifest) {
125
- const mods = (await this.resolveRootNode(nodeManifest)).filter(exists)
126
- this.logger?.debug(`HttpBridge:discoverRoots [${mods.length}]`)
127
- this._roots = mods
128
- } else {
129
- this._roots = []
130
- }
131
- }
132
- return this._roots
133
- })
134
- }
135
-
136
- moduleUrl(address: Address) {
137
- return new URL(address, this.clientUrl)
138
- }
139
-
140
- async sendBridgeQuery<TOut extends Payload = Payload, TQuery extends QueryBoundWitness = QueryBoundWitness, TIn extends Payload = Payload>(
141
- targetAddress: Address,
142
- query: TQuery,
143
- payloads?: TIn[],
144
- ): Promise<ModuleQueryResult<TOut>> {
145
- const lastFailureTime = this._failureTimeCache.get(targetAddress)
146
- if (lastFailureTime !== undefined) {
147
- const now = Date.now()
148
- const timeSincePreviousFailure = now - lastFailureTime
149
- if (timeSincePreviousFailure > this.failureRetryTime) {
150
- throw new Error(`target module failed recently [${targetAddress}] [${timeSincePreviousFailure}ms ago]`)
151
- }
152
- this._failureTimeCache.delete(targetAddress)
153
- }
154
- try {
155
- await this.querySemaphore.acquire()
156
- const payloadSize = JSON.stringify([query, payloads]).length
157
- if (payloadSize > this.maxPayloadSizeWarning) {
158
- this.logger?.warn(
159
- `Large targetQuery being sent: ${payloadSize} bytes [${this.address}][${this.moduleAddress}] [${query.schema}] [${payloads?.length}]`,
160
- )
161
- }
162
- const moduleUrl = this.moduleUrl(targetAddress).href
163
- const result = await this.axios.post<ApiEnvelope<ModuleQueryResult<TOut>>>(moduleUrl, [query, payloads])
164
- if (result.status === 404) {
165
- throw `target module not found [${moduleUrl}] [${result.status}]`
166
- }
167
- if (result.status >= 400) {
168
- this.logger?.error(`targetQuery failed [${moduleUrl}]`)
169
- throw `targetQuery failed [${moduleUrl}] [${result.status}]`
170
- }
171
- return result.data?.data
172
- } catch (ex) {
173
- const error = ex as AxiosError
174
- this.logger?.error(`Error: ${toSafeJsonString(error)}`)
175
- throw error
176
- } finally {
177
- this.querySemaphore.release()
178
- }
179
- }
180
-
181
- override unexposeHandler(_id: string, _options?: BridgeUnexposeOptions | undefined): Promisable<ModuleInstance[]> {
182
- throw new Error('Unsupported')
183
- }
184
-
185
- private async getRootState() {
186
- const queryPayload: ModuleStateQuery = { schema: ModuleStateQuerySchema }
187
- const boundQuery = await this.bindQuery(queryPayload)
188
- try {
189
- const response = await this.axios.post<ApiEnvelope<ModuleQueryResult>>(this.clientUrl.toString(), boundQuery)
190
- if (response.status === 404) {
191
- return []
192
- }
193
- const [, payloads, errors] = response.data.data
194
- if (errors.length > 0) {
195
- throw new Error(`getRootState failed: ${JSON.stringify(errors, null, 2)}`)
196
- }
197
- return payloads
198
- } catch (ex) {
199
- const error = ex as Error
200
- this.logger?.warn(`Unable to connect to remote node: ${error.message} [${this.clientUrl}]`)
201
- }
202
- }
203
-
204
- private async resolveRootNode(nodeManifest: ModuleManifestPayload): Promise<ModuleInstance[]> {
205
- const rootModule = assertEx(
206
- (
207
- await this.resolver.resolveHandler(
208
- assertEx(nodeManifest.status?.address, () => 'Root has no address'),
209
- undefined,
210
- { manifest: nodeManifest },
211
- )
212
- ).at(0),
213
- () => `Root not found [${nodeManifest.status?.address}]`,
214
- )
215
- assertEx(rootModule.constructor.name !== 'HttpModuleProxy', () => 'rootModule is not a Wrapper')
216
- const rootNode = asAttachableNodeInstance(rootModule, 'Root modules is not a node')
217
- if (rootNode) {
218
- this.logger?.debug(`rootNode: ${rootNode.id}`)
219
- this.downResolver.addResolver(rootNode as unknown as ModuleResolverInstance)
220
- return [rootNode]
221
- }
222
- return []
223
- }
224
- }
@@ -1,24 +0,0 @@
1
- import type { EmptyObject } from '@xylabs/sdk-js'
2
- import type { BridgeConfig } from '@xyo-network/bridge-model'
3
- import type { Schema } from '@xyo-network/payload-model'
4
- import { asSchema } from '@xyo-network/payload-model'
5
-
6
- export const HttpBridgeConfigSchema = asSchema('network.xyo.bridge.http.config', true)
7
- export type HttpBridgeConfigSchema = typeof HttpBridgeConfigSchema
8
-
9
- export type HttpBridgeConfig<TConfig extends EmptyObject = EmptyObject, TSchema extends string | void = void> = BridgeConfig<
10
- {
11
- client?: BridgeConfig['client'] & {
12
- url: string
13
- }
14
- failureRetryTime?: number
15
- failureTimeCacheMax?: number
16
- host?: {
17
- port: number
18
- }
19
- maxConnections?: number
20
- maxPayloadSizeWarning?: number
21
- schema: HttpBridgeConfigSchema
22
- } & TConfig,
23
- TSchema extends Schema ? TSchema : HttpBridgeConfigSchema
24
- >
@@ -1,129 +0,0 @@
1
- import type { Address, CreatableName } from '@xylabs/sdk-js'
2
- import {
3
- assertEx, isAddress, isDefined,
4
- } from '@xylabs/sdk-js'
5
- import { Account } from '@xyo-network/account'
6
- import type { BridgeModuleResolverParams } from '@xyo-network/bridge-abstract'
7
- import { AbstractBridgeModuleResolver, wrapModuleWithType } from '@xyo-network/bridge-abstract'
8
- import type { ConfigPayload } from '@xyo-network/config-payload-plugin'
9
- import { ConfigSchema } from '@xyo-network/config-payload-plugin'
10
- import type {
11
- ModuleConfig,
12
- ModuleFilterOptions,
13
- ModuleIdentifier,
14
- ModuleInstance,
15
- } from '@xyo-network/module-model'
16
- import {
17
- asModuleInstance,
18
- isModuleInstance,
19
- ModuleConfigSchema,
20
- ResolveHelper,
21
- } from '@xyo-network/module-model'
22
- import type { Payload } from '@xyo-network/payload-model'
23
- import { Mutex } from 'async-mutex'
24
- import { LRUCache } from 'lru-cache'
25
-
26
- import type { BridgeQuerySender, HttpModuleProxyParams } from './ModuleProxy/index.ts'
27
- import { HttpModuleProxy } from './ModuleProxy/index.ts'
28
-
29
- const NotFoundModule = { notFound: true }
30
-
31
- export interface HttpBridgeModuleResolverParams extends BridgeModuleResolverParams {
32
- querySender: BridgeQuerySender
33
- rootUrl: string
34
- }
35
-
36
- export class HttpBridgeModuleResolver<
37
- T extends HttpBridgeModuleResolverParams = HttpBridgeModuleResolverParams,
38
- > extends AbstractBridgeModuleResolver<T> {
39
- protected _resolvedCache = new LRUCache<Address, ModuleInstance | typeof NotFoundModule>({ max: 1000 })
40
- protected _resolvedCacheMutex = new Mutex()
41
-
42
- get querySender() {
43
- return this.params.querySender
44
- }
45
-
46
- moduleUrl(address: Address) {
47
- return new URL(address, this.params.rootUrl)
48
- }
49
-
50
- override async resolveHandler<T extends ModuleInstance = ModuleInstance>(
51
- id: ModuleIdentifier,
52
- options?: ModuleFilterOptions<T>,
53
- params?: Partial<HttpModuleProxyParams>,
54
- ): Promise<T[]> {
55
- const parentResult = await super.resolveHandler(id, options)
56
- if (parentResult.length > 0) {
57
- return parentResult
58
- }
59
- const idParts = id.split(':')
60
- const untransformedFirstPart = assertEx(idParts.shift(), () => 'Missing module identifier')
61
- const firstPart = await ResolveHelper.transformModuleIdentifier(untransformedFirstPart)
62
- assertEx(isAddress(firstPart), () => `Invalid module address: ${firstPart}`)
63
- const remainderParts = idParts.join(':')
64
- const instance: T | undefined = await this._resolvedCacheMutex.runExclusive(async () => {
65
- const cachedMod = this._resolvedCache.get(firstPart as Address)
66
- if (cachedMod) {
67
- if (isModuleInstance(cachedMod)) {
68
- const result = idParts.length <= 0 ? cachedMod : cachedMod.resolve(remainderParts, { ...options, maxDepth: (options?.maxDepth ?? 5) - 1 })
69
- return result as T
70
- } else {
71
- // return cached 404
72
- return
73
- }
74
- }
75
- const account = await Account.random()
76
- const finalParams: HttpModuleProxyParams = {
77
- name: 'HttpBridgeModuleResolver' as CreatableName,
78
- account,
79
- archiving: this.params.archiving,
80
- config: { schema: ModuleConfigSchema },
81
- host: this,
82
- moduleAddress: firstPart as Address,
83
- onQuerySendFinished: this.params.onQuerySendFinished,
84
- onQuerySendStarted: this.params.onQuerySendStarted,
85
- querySender: this.params.querySender,
86
- ...params,
87
- }
88
-
89
- this.logger?.debug(`creating HttpProxy [${firstPart}] ${id}`)
90
-
91
- let proxy: HttpModuleProxy | undefined
92
-
93
- let state: Payload[] | undefined
94
-
95
- try {
96
- proxy = await HttpModuleProxy.create(finalParams)
97
- state = await proxy.state()
98
- } catch (ex) {
99
- const error = ex as Error
100
- this.logger?.error(error.message)
101
- }
102
-
103
- if (isDefined(proxy)) {
104
- if (!state) {
105
- // cache the fact that it was not found
106
- this._resolvedCache.set(firstPart as Address, NotFoundModule)
107
- return
108
- }
109
-
110
- const configSchema = (state.find(payload => payload.schema === ConfigSchema) as ConfigPayload | undefined)?.config
111
- const config = assertEx(
112
- state.find(payload => payload.schema === configSchema),
113
- () => 'Unable to locate config',
114
- ) as ModuleConfig
115
- proxy.setConfig(config)
116
-
117
- this.logger?.log(`created HttpProxy [${firstPart}] ${proxy.id}`)
118
-
119
- await proxy.start?.()
120
- const wrapped = wrapModuleWithType(proxy, account) as unknown as T
121
- assertEx(asModuleInstance<T>(wrapped, {}), () => `Failed to asModuleInstance [${id}]`)
122
- this._resolvedCache.set(wrapped.address, wrapped)
123
- return wrapped as ModuleInstance as T
124
- }
125
- })
126
- const result = remainderParts.length > 0 ? await instance?.resolve(remainderParts, options) : instance
127
- return result ? [result] : []
128
- }
129
- }
@@ -1,105 +0,0 @@
1
- import type { Address } from '@xylabs/sdk-js'
2
- import {
3
- exists, forget,
4
- isAddress, isString,
5
- } from '@xylabs/sdk-js'
6
- import type { QueryBoundWitness } from '@xyo-network/boundwitness-model'
7
- import type { ModuleProxyParams } from '@xyo-network/bridge-abstract'
8
- import { AbstractModuleProxy } from '@xyo-network/bridge-abstract'
9
- import type {
10
- AttachableModuleInstance,
11
- ModuleFilterOptions,
12
- ModuleIdentifier,
13
- ModuleInstance,
14
- ModuleQueryResult,
15
- ResolveHelperConfig,
16
- } from '@xyo-network/module-model'
17
- import { creatableModule, ResolveHelper } from '@xyo-network/module-model'
18
- import type { Payload } from '@xyo-network/payload-model'
19
-
20
- export interface BridgeQuerySender {
21
- sendBridgeQuery: <TOut extends Payload = Payload, TQuery extends QueryBoundWitness = QueryBoundWitness, TIn extends Payload = Payload>(
22
- targetAddress: Address,
23
- query: TQuery,
24
- payloads?: TIn[],
25
- ) => Promise<ModuleQueryResult<TOut>>
26
- }
27
-
28
- export type HttpModuleProxyParams = ModuleProxyParams & {
29
- querySender: BridgeQuerySender
30
- }
31
-
32
- @creatableModule()
33
- export class HttpModuleProxy<
34
- TWrappedModule extends ModuleInstance = ModuleInstance,
35
- TParams extends Omit<HttpModuleProxyParams, 'config'> & { config: TWrappedModule['config'] } = Omit<HttpModuleProxyParams, 'config'> & {
36
- config: TWrappedModule['config']
37
- },
38
- >
39
- extends AbstractModuleProxy<TWrappedModule, TParams>
40
- implements AttachableModuleInstance<TParams, TWrappedModule['eventData']> {
41
- async proxyQueryHandler<T extends QueryBoundWitness = QueryBoundWitness>(query: T, payloads: Payload[] = []): Promise<ModuleQueryResult> {
42
- if (this.archiving && this.isAllowedArchivingQuery(query.schema)) {
43
- forget(this.storeToArchivists([query, ...(payloads ?? [])]))
44
- }
45
- const result = await this.params.querySender.sendBridgeQuery(this.params.moduleAddress, query, payloads)
46
- if (this.archiving && this.isAllowedArchivingQuery(query.schema)) {
47
- forget(this.storeToArchivists(result.flat()))
48
- }
49
- return result
50
- }
51
-
52
- override async publicChildren(): Promise<ModuleInstance[]> {
53
- return (
54
- await Promise.all(
55
- Object.values(await this.childAddressMap())
56
- .filter(exists)
57
- .map(address => this.resolve(address)),
58
- )
59
- ).filter(exists)
60
- }
61
-
62
- /** @deprecated do not pass undefined. If trying to get all, pass '*' */
63
- override async resolve(): Promise<ModuleInstance[]>
64
- override async resolve<T extends ModuleInstance = ModuleInstance>(all: '*', options?: ModuleFilterOptions<T>): Promise<T[]>
65
- override async resolve<T extends ModuleInstance = ModuleInstance>(id: ModuleIdentifier, options?: ModuleFilterOptions<T>): Promise<T | undefined>
66
- override async resolve<T extends ModuleInstance = ModuleInstance>(
67
- id: ModuleIdentifier = '*',
68
- options: ModuleFilterOptions<T> = {},
69
- ): Promise<T | T[] | undefined> {
70
- const config: ResolveHelperConfig = {
71
- address: this.address,
72
- dead: this.dead,
73
- downResolver: this.downResolver,
74
- logger: this.logger,
75
- mod: this,
76
- transformers: this.moduleIdentifierTransformers,
77
- upResolver: this.upResolver,
78
- }
79
- if (id === '*') {
80
- return [...(await this.publicChildren()), await this.params.host.resolve(this.address)] as T[]
81
- }
82
- switch (typeof id) {
83
- case 'string': {
84
- const parts = id.split(':')
85
- const first = parts.shift()
86
- if (isString(first)) {
87
- const remainingPath = parts.length > 0 ? parts.join(':') : undefined
88
- const address
89
- = isAddress(first)
90
- ? first
91
- : this.id === first
92
- ? this.address
93
- : this.childAddressByName(first)
94
- if (!isAddress(address)) return undefined
95
- const firstInstance = (await this.params.host.resolve(address)) as ModuleInstance | undefined
96
- return (isString(remainingPath) ? await firstInstance?.resolve(remainingPath) : firstInstance) as T | undefined
97
- }
98
- return undefined
99
- }
100
- default: {
101
- return (await ResolveHelper.resolve(config, id, options)).filter(mod => mod.address !== this.address)
102
- }
103
- }
104
- }
105
- }
@@ -1 +0,0 @@
1
- export * from './ModuleProxy.ts'
package/src/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './HttpBridge.ts'
2
- export * from './HttpBridgeConfig.ts'
@@ -1,43 +0,0 @@
1
- import '@xylabs/vitest-extended'
2
-
3
- import { MemoryNode } from '@xyo-network/node-memory'
4
- import {
5
- describe, expect, it,
6
- } from 'vitest'
7
-
8
- import { HttpBridge } from '../HttpBridge.ts'
9
- import { HttpBridgeConfigSchema } from '../HttpBridgeConfig.ts'
10
-
11
- /**
12
- * @group module
13
- * @group bridge
14
- */
15
-
16
- describe('HttpBridge', () => {
17
- const baseUrl = 'https://sfjhskjdsfhdsk.com'
18
-
19
- console.log(`HttpBridge:baseUrl ${baseUrl}`)
20
- const cases = [
21
- ['/', `${baseUrl}`],
22
- /* ['/node', `${baseUrl}/node`], */
23
- ]
24
-
25
- it.each(cases)('HttpBridge: %s', async (_, nodeUrl) => {
26
- const memNode = await MemoryNode.create({ account: 'random' })
27
-
28
- const bridge = await HttpBridge.create({
29
- account: 'random',
30
- config: {
31
- client: { url: nodeUrl }, schema: HttpBridgeConfigSchema, security: { allowAnonymous: true },
32
- },
33
- })
34
-
35
- await bridge?.start?.()
36
-
37
- await memNode.register(bridge)
38
- await memNode.attach(bridge.address, true)
39
-
40
- const modules = await memNode.resolve('*')
41
- expect(modules.length).toBe(2)
42
- })
43
- })
@@ -1,56 +0,0 @@
1
- import '@xylabs/vitest-extended'
2
-
3
- import { MemoryNode } from '@xyo-network/node-memory'
4
- import type { NodeInstance } from '@xyo-network/node-model'
5
- import { NodeConfigSchema } from '@xyo-network/node-model'
6
- import {
7
- describe, expect, it,
8
- } from 'vitest'
9
-
10
- import { HttpBridge } from '../HttpBridge.ts'
11
- import { HttpBridgeConfigSchema } from '../HttpBridgeConfig.ts'
12
-
13
- /**
14
- * @group module
15
- * @group bridge
16
- */
17
-
18
- describe('HttpBridge', () => {
19
- const baseUrl = `${process.env.API_DOMAIN ?? 'http://localhost:8080'}`
20
-
21
- console.log(`HttpBridge:baseUrl ${baseUrl}`)
22
- it('Discover', async () => {
23
- const nodeUrl = `${baseUrl}/`
24
- const memNode = await MemoryNode.create({ account: 'random', config: { name: 'MemoryNode', schema: NodeConfigSchema } })
25
-
26
- const bridge = await HttpBridge.create({
27
- account: 'random',
28
- config: {
29
- name: 'HttpBridge', client: { url: nodeUrl, discoverRoots: 'start' }, schema: HttpBridgeConfigSchema, security: { allowAnonymous: true },
30
- },
31
- })
32
-
33
- await memNode.register(bridge)
34
- await memNode.attach(bridge.address, true)
35
-
36
- const publicNode = await bridge.resolve<NodeInstance>('XYOPublic')
37
- expect(publicNode).toBeDefined()
38
-
39
- if (publicNode) {
40
- console.log(`publicNode[${publicNode.address}]: ${publicNode.modName}`)
41
- const publicNodeModules = await publicNode.resolve('*', { direction: 'down' })
42
- expect(publicNodeModules).toBeArray()
43
- expect(publicNodeModules.length).toBeGreaterThan(0)
44
- }
45
-
46
- const bridgeModules = await bridge.resolve('*', { direction: 'down' })
47
- expect(bridgeModules).toBeArray()
48
- expect(bridgeModules.length).toBeGreaterThan(0)
49
-
50
- /*
51
- const modules = await memNode.resolve('*')
52
- expect(modules).toBeArray()
53
- expect(modules.length).toBeGreaterThan(20)
54
- */
55
- })
56
- })
@@ -1,208 +0,0 @@
1
- /* eslint-disable complexity */
2
- /* eslint-disable max-statements */
3
-
4
- import '@xylabs/vitest-extended'
5
-
6
- import { assertEx } from '@xylabs/sdk-js'
7
- import type { ApiConfig } from '@xyo-network/api-models'
8
- import type { AttachableArchivistInstance } from '@xyo-network/archivist-model'
9
- import {
10
- asArchivistInstance,
11
- asAttachableArchivistInstance,
12
- isAttachableArchivistInstance,
13
- } from '@xyo-network/archivist-model'
14
- import type { ModuleDescriptionPayload } from '@xyo-network/module-model'
15
- import {
16
- isModuleInstance, isQueryableModule, isQueryableModuleObject,
17
- ModuleDescriptionSchema,
18
- } from '@xyo-network/module-model'
19
- import { MemoryNode } from '@xyo-network/node-memory'
20
- import { asAttachableNodeInstance, isNodeInstance } from '@xyo-network/node-model'
21
- import { PayloadBuilder } from '@xyo-network/payload-builder'
22
- import type { Payload } from '@xyo-network/payload-model'
23
- import { asSchema, isPayloadOfSchemaType } from '@xyo-network/payload-model'
24
- import { PayloadWrapper } from '@xyo-network/payload-wrapper'
25
- import { HDWallet } from '@xyo-network/wallet'
26
- import {
27
- describe, expect, it,
28
- } from 'vitest'
29
-
30
- import { HttpBridge } from '../HttpBridge.ts'
31
- import { HttpBridgeConfigSchema } from '../HttpBridgeConfig.ts'
32
-
33
- const archivistName = 'XYOPublic:Archivist' // TODO: This should be configurable
34
- const discoverRoots = 'start'
35
- const schema = HttpBridgeConfigSchema
36
- const security = { allowAnonymous: true }
37
-
38
- export const getApiConfig = (): ApiConfig => {
39
- return { apiDomain: process.env.ARCHIVIST_API_DOMAIN || 'https://beta.api.archivist.xyo.network' }
40
- }
41
-
42
- export const getArchivist = async (config: ApiConfig = getApiConfig()): Promise<AttachableArchivistInstance> => {
43
- return assertEx(await tryGetArchivist(config), () => 'Archivist not found')
44
- }
45
-
46
- export const tryGetArchivist = async (config: ApiConfig = getApiConfig()): Promise<AttachableArchivistInstance | undefined> => {
47
- const url = config.root ? `${config.apiDomain}/${config.root}` : config.apiDomain
48
- const account = await HDWallet.random()
49
- const bridge = await HttpBridge.create({
50
- account,
51
- config: {
52
- client: { discoverRoots, url }, schema, security,
53
- },
54
- })
55
- await bridge.start()
56
- const mod = await bridge.resolve(archivistName)
57
- return isAttachableArchivistInstance(mod) ? mod : undefined
58
- }
59
-
60
- /**
61
- * @group module
62
- * @group bridge
63
- */
64
-
65
- describe('HttpBridge', () => {
66
- const baseUrl = `${process.env.API_DOMAIN ?? 'http://localhost:8080'}`
67
-
68
- console.log(`HttpBridge:baseUrl ${baseUrl}`)
69
- const cases = [
70
- ['/', `${baseUrl}`],
71
- /* ['/node', `${baseUrl}/node`], */
72
- ]
73
-
74
- it.each(cases)('HttpBridge: %s', async (_, nodeUrl) => {
75
- const memNode = await MemoryNode.create({ account: 'random' })
76
- const extraMemNode = await MemoryNode.create({ account: 'random' })
77
-
78
- const bridge = await HttpBridge.create({
79
- account: 'random',
80
- config: {
81
- name: 'TestBridge', client: { url: nodeUrl, discoverRoots: 'start' }, schema: HttpBridgeConfigSchema, security: { allowAnonymous: true },
82
- },
83
- })
84
-
85
- await bridge?.start?.()
86
- await memNode.register(bridge)
87
- await memNode.attach(bridge?.address, true)
88
-
89
- const resolvedBridge = await memNode.resolve(bridge.id)
90
- expect(resolvedBridge).toBeDefined()
91
-
92
- const rootModule = await bridge?.resolve('XYOPublic')
93
- expect(rootModule).toBeDefined()
94
-
95
- const remoteNode = asAttachableNodeInstance(
96
- rootModule,
97
- () => `Failed to resolve correct object type [XYOPublic] [${rootModule?.constructor.name}]`,
98
- { required: true },
99
- )
100
-
101
- const state = await remoteNode.state()
102
- const description = state.find(isPayloadOfSchemaType<ModuleDescriptionPayload>(ModuleDescriptionSchema))
103
- expect(description?.children).toBeArray()
104
- expect(description?.children?.length).toBeGreaterThan(0)
105
- expect(description?.queries).toBeArray()
106
- expect(description?.queries?.length).toBeGreaterThan(0)
107
-
108
- const archivistByName1 = await rootModule?.resolve('Archivist')
109
- expect(archivistByName1).toBeDefined()
110
- const archivistByName2 = await bridge.resolve('XYOPublic:Archivist')
111
- expect(archivistByName2).toBeDefined()
112
- const publicXyo = await bridge.resolve('XYOPublic')
113
- expect(publicXyo).toBeDefined()
114
- const publicXyoSelfResolve = publicXyo?.resolve('XYOPublic')
115
- expect(publicXyoSelfResolve).toBeDefined()
116
- if (publicXyo) {
117
- const bridgedArchivist = await getArchivist()
118
- expect(bridgedArchivist).toBeDefined()
119
- if (bridgedArchivist) {
120
- const attachablePublicXyo = asAttachableArchivistInstance(archivistByName2, 'Failed to cast publicXyo')
121
- expect(attachablePublicXyo).toBeDefined()
122
- await extraMemNode.register(bridgedArchivist)
123
- await extraMemNode.attach(bridgedArchivist.address, true)
124
- const publicXyoNodeResolveAddress = await extraMemNode?.resolve(bridgedArchivist.address)
125
- expect(publicXyoNodeResolveAddress).toBeDefined()
126
- const publicXyoNodeResolve = await extraMemNode?.resolve('Archivist')
127
- expect(publicXyoNodeResolve).toBeDefined()
128
- }
129
- }
130
- const archivistByName3 = await publicXyo?.resolve('Archivist')
131
- expect(archivistByName3).toBeDefined()
132
- expect(archivistByName3).toEqual(archivistByName1)
133
- expect(archivistByName3).toEqual(archivistByName2)
134
- expect(archivistByName2).toBeDefined()
135
- const archivistInstance = asArchivistInstance(archivistByName2, 'Failed to cast archivist', { required: true })
136
- expect(archivistInstance).toBeDefined()
137
- const knownPayload = PayloadWrapper.parse({ schema: asSchema('network.xyo.test', true) })?.payload as Payload
138
- expect(knownPayload).toBeDefined()
139
- const knownHash = await PayloadBuilder.dataHash(knownPayload as Payload)
140
- const insertResult = await archivistInstance.insert([knownPayload])
141
- expect(insertResult).toBeDefined()
142
- const roundTripPayload = (await archivistInstance.get([knownHash]))[0]
143
- expect(roundTripPayload).toBeDefined()
144
- })
145
- it.each(cases)('HttpBridge - Nested: %s', async (_, nodeUrl) => {
146
- const memNode1 = await MemoryNode.create({ account: 'random', config: { schema: asSchema('network.xyo.node.config', true) } })
147
- const memNode2 = await MemoryNode.create({ account: 'random', config: { schema: asSchema('network.xyo.node.config', true) } })
148
- const memNode3 = await MemoryNode.create({ account: 'random', config: { schema: asSchema('network.xyo.node.config', true) } })
149
-
150
- await memNode1.register(memNode2)
151
- await memNode1.attach(memNode2.address, true)
152
- await memNode2.register(memNode3)
153
- await memNode2.attach(memNode3.address, true)
154
-
155
- const bridge = await HttpBridge.create({
156
- account: 'random',
157
- config: {
158
- client: { url: nodeUrl }, schema: HttpBridgeConfigSchema, security: { allowAnonymous: true },
159
- },
160
- })
161
-
162
- await bridge.getRoots()
163
- const mod = await bridge.resolve('XYOPublic')
164
-
165
- expect(mod).toBeDefined()
166
- expect(isQueryableModule(mod)).toBeTrue()
167
- expect(isQueryableModuleObject(mod)).toBeTrue()
168
-
169
- const remoteNode = asAttachableNodeInstance(
170
- mod,
171
- `Failed to resolve [XYOPublic] - ${mod?.address} [${mod?.id}] [${mod?.constructor.name}]`,
172
- { required: true },
173
- )
174
-
175
- expect(isNodeInstance(remoteNode)).toBeTrue()
176
- expect(isModuleInstance(remoteNode)).toBeTrue()
177
-
178
- await memNode3.register(remoteNode)
179
- await memNode3.attach(remoteNode?.address, true)
180
- const description = (await remoteNode.state()).find(isPayloadOfSchemaType<ModuleDescriptionPayload>(ModuleDescriptionSchema))
181
- expect(description?.children).toBeArray()
182
- expect(description?.children?.length).toBeGreaterThan(0)
183
- expect(description?.queries).toBeArray()
184
- expect(description?.queries?.length).toBeGreaterThan(0)
185
-
186
- // Works if you supply the known address for 'Archivist'
187
- // const [archivistByAddress] = await memNode.resolve({ address: ['461fd6970770e97d9f66c71658f4b96212581f0b'] })
188
- // expect(archivistByAddress).toBeDefined()
189
-
190
- /* const mods = await bridge.resolve('*')
191
- for (const mod of mods) {
192
- console.log(`module [${mod.address}]: ${mod.modName}`)
193
- } */
194
-
195
- const node = await bridge.resolve('XYOPublic')
196
- expect(node).toBeDefined()
197
-
198
- const archivistByName1 = await node?.resolve('Archivist')
199
- expect(archivistByName1).toBeDefined()
200
-
201
- const archivistByName2 = (await node?.resolve('Archivist'))
202
- expect(archivistByName2).toBeDefined()
203
- const payloadStatsDivinerByName = (await node?.resolve('PayloadStatsDiviner'))
204
- expect(payloadStatsDivinerByName).toBeDefined()
205
- const boundwitnessStatsDivinerByName = (await node?.resolve('BoundWitnessStatsDiviner'))
206
- expect(boundwitnessStatsDivinerByName).toBeDefined()
207
- })
208
- })
@@ -1,85 +0,0 @@
1
- /* eslint-disable max-nested-callbacks */
2
- import '@xylabs/vitest-extended'
3
-
4
- import type { AbstractBridge } from '@xyo-network/bridge-abstract'
5
- import {
6
- describe, expect, it,
7
- } from 'vitest'
8
-
9
- // TODO: Implement standard test suite for all Bridges here and then run
10
- // against specific bridges
11
- export const generateBridgeTests = (title: string, _bridge: AbstractBridge) => {
12
- describe(title, () => {
13
- describe('HttpBridge', () => {
14
- describe('By name', () => {
15
- it('should handle the case by name', () => {
16
- // Add your test logic here
17
- })
18
- })
19
-
20
- describe('By address', () => {
21
- it('should handle the case by address', () => {
22
- // Add your test logic here
23
- })
24
- })
25
-
26
- describe('By exposed/unexposed', () => {
27
- describe('Pre Exposed', () => {
28
- it('should handle the case when pre exposed', () => {
29
- // Add your test logic here
30
- })
31
- })
32
-
33
- describe('Post Exposed', () => {
34
- it('should handle the case when post exposed', () => {
35
- // Add your test logic here
36
- })
37
- })
38
-
39
- describe('Post Unexposed', () => {
40
- it('should handle the case when post unexposed', () => {
41
- // Add your test logic here
42
- })
43
- })
44
- })
45
-
46
- describe('By parent/sibling/child/grandchild', () => {
47
- describe('ParentNode', () => {
48
- it('should handle the case for ParentNode', () => {
49
- // Add your test logic here
50
- })
51
-
52
- describe('Bridge', () => {
53
- it('should handle the case for Bridge', () => {
54
- // Add your test logic here
55
- })
56
- })
57
-
58
- describe('SiblingNode', () => {
59
- it('should handle the case for SiblingNode', () => {
60
- // Add your test logic here
61
- })
62
-
63
- describe('ChildNode', () => {
64
- it('should handle the case for ChildNode', () => {
65
- // Add your test logic here
66
- })
67
- })
68
- })
69
- })
70
-
71
- describe('GrandchildNode', () => {
72
- it('should handle the case for GrandchildNode', () => {
73
- // Add your test logic here
74
- })
75
- })
76
- })
77
- })
78
- })
79
- }
80
-
81
- describe('HttpBridge', () => {
82
- it('No tests', () => {
83
- expect(true).toBeTruthy()
84
- })
85
- })
@@ -1,58 +0,0 @@
1
- import '@xylabs/vitest-extended'
2
-
3
- import { asDivinerInstance } from '@xyo-network/diviner-model'
4
- import { ResolveHelper } from '@xyo-network/module-model'
5
- import { NameRegistrarTransformer } from '@xyo-network/module-resolver'
6
- import { MemoryNode } from '@xyo-network/node-memory'
7
- import { asAttachableNodeInstance } from '@xyo-network/node-model'
8
- import {
9
- describe, expect, it,
10
- } from 'vitest'
11
-
12
- import { HttpBridge } from '../HttpBridge.ts'
13
- import { HttpBridgeConfigSchema } from '../HttpBridgeConfig.ts'
14
-
15
- /**
16
- * @group module
17
- * @group bridge
18
- */
19
-
20
- describe('HttpBridge - Xns', () => {
21
- it('HttpBridge-Xns: Simple Resolve', async () => {
22
- const memNode = await MemoryNode.create({ account: 'random' })
23
-
24
- const bridge = await HttpBridge.create({
25
- account: 'random',
26
- config: {
27
- name: 'TestBridge',
28
- client: { url: 'https://beta.xns.xyo.network', discoverRoots: 'start' },
29
- schema: HttpBridgeConfigSchema,
30
- security: { allowAnonymous: true },
31
- },
32
- })
33
-
34
- await bridge?.start?.()
35
- await memNode.register(bridge)
36
- await memNode.attach(bridge?.address, true)
37
- const resolvedBridge = await memNode.resolve(bridge.id)
38
- expect(resolvedBridge).toBeDefined()
39
-
40
- const rootModule = await bridge?.resolve('XNS')
41
- expect(rootModule).toBeDefined()
42
-
43
- const remoteNode = asAttachableNodeInstance(
44
- rootModule,
45
- () => `Failed to resolve correct object type [XYO] [${rootModule?.constructor.name}]`,
46
- { required: true },
47
- )
48
-
49
- const registrarDiviner = asDivinerInstance(await remoteNode.resolve('XNS:AddressRecords:AddressRecordIndexDiviner'))
50
- expect(registrarDiviner).toBeDefined()
51
- if (registrarDiviner) {
52
- const transformer = new NameRegistrarTransformer(registrarDiviner, 'xyo')
53
- ResolveHelper.transformers = [transformer]
54
- const address = await transformer.transform('nippyflight.xyo')
55
- expect(address).toBe('c5fa710300a8a43568678d0fe72810e34d880357')
56
- }
57
- })
58
- })