@xyo-network/bridge-http-express 3.14.0
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/LICENSE +165 -0
- package/README.md +13 -0
- package/dist/neutral/index.mjs +191 -0
- package/dist/neutral/index.mjs.map +1 -0
- package/dist/types/HttpBridge.d.ts +45 -0
- package/dist/types/HttpBridge.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/package.json +78 -0
- package/src/HttpBridge.ts +237 -0
- package/src/index.ts +1 -0
- package/src/spec/HttpBridge.baddns.spec.ts +42 -0
- package/src/spec/HttpBridge.copilot.spec.ts +61 -0
- package/src/spec/HttpBridge.host-resolve.spec.ts +86 -0
- package/src/spec/HttpBridge.host.spec.ts +156 -0
- package/src/spec/HttpBridge.legacy.spec.ts +55 -0
- package/src/spec/HttpBridge.spec.ts +202 -0
- package/src/spec/HttpBridge.tests.spec.ts +86 -0
- package/src/spec/HttpBridge.xns.spec.ts +54 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/* eslint-disable complexity */
|
|
2
|
+
/* eslint-disable max-statements */
|
|
3
|
+
|
|
4
|
+
import '@xylabs/vitest-extended'
|
|
5
|
+
|
|
6
|
+
import { assertEx } from '@xylabs/assert'
|
|
7
|
+
import { HDWallet } from '@xyo-network/account'
|
|
8
|
+
import type { ApiConfig } from '@xyo-network/api-models'
|
|
9
|
+
import type { AttachableArchivistInstance } from '@xyo-network/archivist-model'
|
|
10
|
+
import {
|
|
11
|
+
asArchivistInstance,
|
|
12
|
+
asAttachableArchivistInstance,
|
|
13
|
+
isAttachableArchivistInstance,
|
|
14
|
+
} from '@xyo-network/archivist-model'
|
|
15
|
+
import type { ModuleDescriptionPayload } from '@xyo-network/module-model'
|
|
16
|
+
import {
|
|
17
|
+
isModule, isModuleInstance, isModuleObject,
|
|
18
|
+
ModuleDescriptionSchema,
|
|
19
|
+
} from '@xyo-network/module-model'
|
|
20
|
+
import { MemoryNode } from '@xyo-network/node-memory'
|
|
21
|
+
import { asAttachableNodeInstance, isNodeInstance } from '@xyo-network/node-model'
|
|
22
|
+
import { PayloadBuilder } from '@xyo-network/payload-builder'
|
|
23
|
+
import type { Payload } from '@xyo-network/payload-model'
|
|
24
|
+
import { isPayloadOfSchemaType } from '@xyo-network/payload-model'
|
|
25
|
+
import { PayloadWrapper } from '@xyo-network/payload-wrapper'
|
|
26
|
+
import {
|
|
27
|
+
describe, expect, it,
|
|
28
|
+
} from 'vitest'
|
|
29
|
+
|
|
30
|
+
import { HttpBridgeExpress, HttpBridgeExpressConfigSchema } from '../HttpBridge.ts'
|
|
31
|
+
|
|
32
|
+
const archivistName = 'XYOPublic:Archivist' // TODO: This should be configurable
|
|
33
|
+
const discoverRoots = 'start'
|
|
34
|
+
const schema = HttpBridgeExpressConfigSchema
|
|
35
|
+
const security = { allowAnonymous: true }
|
|
36
|
+
|
|
37
|
+
export const getApiConfig = (): ApiConfig => {
|
|
38
|
+
return { apiDomain: process.env.ARCHIVIST_API_DOMAIN || 'https://beta.api.archivist.xyo.network' }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const getArchivist = async (config: ApiConfig = getApiConfig()): Promise<AttachableArchivistInstance> => {
|
|
42
|
+
return assertEx(await tryGetArchivist(config), () => 'Archivist not found')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const tryGetArchivist = async (config: ApiConfig = getApiConfig()): Promise<AttachableArchivistInstance | undefined> => {
|
|
46
|
+
const url = config.root ? `${config.apiDomain}/${config.root}` : config.apiDomain
|
|
47
|
+
const account = await HDWallet.random()
|
|
48
|
+
const bridge = await HttpBridgeExpress.create({
|
|
49
|
+
account,
|
|
50
|
+
config: {
|
|
51
|
+
client: { discoverRoots, url }, schema, security,
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
await bridge.start()
|
|
55
|
+
const mod = await bridge.resolve(archivistName)
|
|
56
|
+
return isAttachableArchivistInstance(mod) ? mod : undefined
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @group module
|
|
61
|
+
* @group bridge
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
describe('HttpBridgeExpress', () => {
|
|
65
|
+
const baseUrl = `${process.env.API_DOMAIN ?? 'http://localhost:8080'}`
|
|
66
|
+
|
|
67
|
+
console.log(`HttpBridgeExpress:baseUrl ${baseUrl}`)
|
|
68
|
+
const cases = [
|
|
69
|
+
['/', `${baseUrl}`],
|
|
70
|
+
/* ['/node', `${baseUrl}/node`], */
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
it.each(cases)('HttpBridgeExpress: %s', async (_, nodeUrl) => {
|
|
74
|
+
const memNode = await MemoryNode.create({ account: 'random' })
|
|
75
|
+
const extraMemNode = await MemoryNode.create({ account: 'random' })
|
|
76
|
+
|
|
77
|
+
const bridge = await HttpBridgeExpress.create({
|
|
78
|
+
account: 'random',
|
|
79
|
+
config: {
|
|
80
|
+
discoverRoots: 'start', name: 'TestBridge', nodeUrl, schema: HttpBridgeExpressConfigSchema, security: { allowAnonymous: true },
|
|
81
|
+
},
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
await bridge?.start?.()
|
|
85
|
+
await memNode.register(bridge)
|
|
86
|
+
await memNode.attach(bridge?.address, true)
|
|
87
|
+
|
|
88
|
+
const resolvedBridge = await memNode.resolve(bridge.id)
|
|
89
|
+
expect(resolvedBridge).toBeDefined()
|
|
90
|
+
|
|
91
|
+
const rootModule = await bridge?.resolve('XYOPublic')
|
|
92
|
+
expect(rootModule).toBeDefined()
|
|
93
|
+
|
|
94
|
+
const remoteNode = asAttachableNodeInstance(
|
|
95
|
+
rootModule,
|
|
96
|
+
() => `Failed to resolve correct object type [XYOPublic] [${rootModule?.constructor.name}]`,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
const state = await remoteNode.state()
|
|
100
|
+
const description = state.find(isPayloadOfSchemaType<ModuleDescriptionPayload>(ModuleDescriptionSchema))
|
|
101
|
+
expect(description?.children).toBeArray()
|
|
102
|
+
expect(description?.children?.length).toBeGreaterThan(0)
|
|
103
|
+
expect(description?.queries).toBeArray()
|
|
104
|
+
expect(description?.queries?.length).toBeGreaterThan(0)
|
|
105
|
+
|
|
106
|
+
const archivistByName1 = await rootModule?.resolve('Archivist')
|
|
107
|
+
expect(archivistByName1).toBeDefined()
|
|
108
|
+
const archivistByName2 = await bridge.resolve('XYOPublic:Archivist')
|
|
109
|
+
expect(archivistByName2).toBeDefined()
|
|
110
|
+
const publicXyo = await bridge.resolve('XYOPublic')
|
|
111
|
+
expect(publicXyo).toBeDefined()
|
|
112
|
+
const publicXyoSelfResolve = publicXyo?.resolve('XYOPublic')
|
|
113
|
+
expect(publicXyoSelfResolve).toBeDefined()
|
|
114
|
+
if (publicXyo) {
|
|
115
|
+
const bridgedArchivist = await getArchivist()
|
|
116
|
+
expect(bridgedArchivist).toBeDefined()
|
|
117
|
+
if (bridgedArchivist) {
|
|
118
|
+
const attachablePublicXyo = asAttachableArchivistInstance(archivistByName2, 'Failed to cast publicXyo')
|
|
119
|
+
expect(attachablePublicXyo).toBeDefined()
|
|
120
|
+
await extraMemNode.register(bridgedArchivist)
|
|
121
|
+
await extraMemNode.attach(bridgedArchivist.address, true)
|
|
122
|
+
const publicXyoNodeResolveAddress = await extraMemNode?.resolve(bridgedArchivist.address)
|
|
123
|
+
expect(publicXyoNodeResolveAddress).toBeDefined()
|
|
124
|
+
const publicXyoNodeResolve = await extraMemNode?.resolve('Archivist')
|
|
125
|
+
expect(publicXyoNodeResolve).toBeDefined()
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const archivistByName3 = await publicXyo?.resolve('Archivist')
|
|
129
|
+
expect(archivistByName3).toBeDefined()
|
|
130
|
+
expect(archivistByName3).toEqual(archivistByName1)
|
|
131
|
+
expect(archivistByName3).toEqual(archivistByName2)
|
|
132
|
+
expect(archivistByName2).toBeDefined()
|
|
133
|
+
const archivistInstance = asArchivistInstance(archivistByName2, 'Failed to cast archivist')
|
|
134
|
+
expect(archivistInstance).toBeDefined()
|
|
135
|
+
const knownPayload = PayloadWrapper.parse({ schema: 'network.xyo.test' })?.payload as Payload
|
|
136
|
+
expect(knownPayload).toBeDefined()
|
|
137
|
+
const knownHash = await PayloadBuilder.dataHash(knownPayload as Payload)
|
|
138
|
+
const insertResult = await archivistInstance.insert([knownPayload])
|
|
139
|
+
expect(insertResult).toBeDefined()
|
|
140
|
+
const roundTripPayload = (await archivistInstance.get([knownHash]))[0]
|
|
141
|
+
expect(roundTripPayload).toBeDefined()
|
|
142
|
+
})
|
|
143
|
+
it.each(cases)('HttpBridgeExpress - Nested: %s', async (_, nodeUrl) => {
|
|
144
|
+
const memNode1 = await MemoryNode.create({ account: 'random', config: { schema: 'network.xyo.node.config' } })
|
|
145
|
+
const memNode2 = await MemoryNode.create({ account: 'random', config: { schema: 'network.xyo.node.config' } })
|
|
146
|
+
const memNode3 = await MemoryNode.create({ account: 'random', config: { schema: 'network.xyo.node.config' } })
|
|
147
|
+
|
|
148
|
+
await memNode1.register(memNode2)
|
|
149
|
+
await memNode1.attach(memNode2.address, true)
|
|
150
|
+
await memNode2.register(memNode3)
|
|
151
|
+
await memNode2.attach(memNode3.address, true)
|
|
152
|
+
|
|
153
|
+
const bridge = await HttpBridgeExpress.create({
|
|
154
|
+
account: 'random',
|
|
155
|
+
config: {
|
|
156
|
+
nodeUrl, schema: HttpBridgeExpressConfigSchema, security: { allowAnonymous: true },
|
|
157
|
+
},
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
await bridge.getRoots()
|
|
161
|
+
const mod = await bridge.resolve('XYOPublic')
|
|
162
|
+
|
|
163
|
+
expect(mod).toBeDefined()
|
|
164
|
+
expect(isModule(mod)).toBeTrue()
|
|
165
|
+
expect(isModuleObject(mod)).toBeTrue()
|
|
166
|
+
|
|
167
|
+
const remoteNode = asAttachableNodeInstance(mod, `Failed to resolve [XYOPublic] - ${mod?.address} [${mod?.id}] [${mod?.constructor.name}]`)
|
|
168
|
+
|
|
169
|
+
expect(isNodeInstance(remoteNode)).toBeTrue()
|
|
170
|
+
expect(isModuleInstance(remoteNode)).toBeTrue()
|
|
171
|
+
|
|
172
|
+
await memNode3.register(remoteNode)
|
|
173
|
+
await memNode3.attach(remoteNode?.address, true)
|
|
174
|
+
const description = (await remoteNode.state()).find(isPayloadOfSchemaType<ModuleDescriptionPayload>(ModuleDescriptionSchema))
|
|
175
|
+
expect(description?.children).toBeArray()
|
|
176
|
+
expect(description?.children?.length).toBeGreaterThan(0)
|
|
177
|
+
expect(description?.queries).toBeArray()
|
|
178
|
+
expect(description?.queries?.length).toBeGreaterThan(0)
|
|
179
|
+
|
|
180
|
+
// Works if you supply the known address for 'Archivist'
|
|
181
|
+
// const [archivistByAddress] = await memNode.resolve({ address: ['461fd6970770e97d9f66c71658f4b96212581f0b'] })
|
|
182
|
+
// expect(archivistByAddress).toBeDefined()
|
|
183
|
+
|
|
184
|
+
/* const mods = await bridge.resolve('*')
|
|
185
|
+
for (const mod of mods) {
|
|
186
|
+
console.log(`module [${mod.address}]: ${mod.modName}`)
|
|
187
|
+
} */
|
|
188
|
+
|
|
189
|
+
const node = await bridge.resolve('XYOPublic')
|
|
190
|
+
expect(node).toBeDefined()
|
|
191
|
+
|
|
192
|
+
const archivistByName1 = await node?.resolve('Archivist')
|
|
193
|
+
expect(archivistByName1).toBeDefined()
|
|
194
|
+
|
|
195
|
+
const archivistByName2 = (await node?.resolve('Archivist'))
|
|
196
|
+
expect(archivistByName2).toBeDefined()
|
|
197
|
+
const payloadStatsDivinerByName = (await node?.resolve('PayloadStatsDiviner'))
|
|
198
|
+
expect(payloadStatsDivinerByName).toBeDefined()
|
|
199
|
+
const boundwitnessStatsDivinerByName = (await node?.resolve('BoundWitnessStatsDiviner'))
|
|
200
|
+
expect(boundwitnessStatsDivinerByName).toBeDefined()
|
|
201
|
+
})
|
|
202
|
+
})
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/* eslint-disable sonarjs/assertions-in-tests */
|
|
2
|
+
/* eslint-disable max-nested-callbacks */
|
|
3
|
+
import '@xylabs/vitest-extended'
|
|
4
|
+
|
|
5
|
+
import type { AbstractBridge } from '@xyo-network/bridge-abstract'
|
|
6
|
+
import {
|
|
7
|
+
describe, expect, it,
|
|
8
|
+
} from 'vitest'
|
|
9
|
+
|
|
10
|
+
// TODO: Implement standard test suite for all Bridges here and then run
|
|
11
|
+
// against specific bridges
|
|
12
|
+
export const generateBridgeTests = (title: string, _bridge: AbstractBridge) => {
|
|
13
|
+
describe(title, () => {
|
|
14
|
+
describe('HttpBridge', () => {
|
|
15
|
+
describe('By name', () => {
|
|
16
|
+
it('should handle the case by name', () => {
|
|
17
|
+
// Add your test logic here
|
|
18
|
+
})
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
describe('By address', () => {
|
|
22
|
+
it('should handle the case by address', () => {
|
|
23
|
+
// Add your test logic here
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe('By exposed/unexposed', () => {
|
|
28
|
+
describe('Pre Exposed', () => {
|
|
29
|
+
it('should handle the case when pre exposed', () => {
|
|
30
|
+
// Add your test logic here
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
describe('Post Exposed', () => {
|
|
35
|
+
it('should handle the case when post exposed', () => {
|
|
36
|
+
// Add your test logic here
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe('Post Unexposed', () => {
|
|
41
|
+
it('should handle the case when post unexposed', () => {
|
|
42
|
+
// Add your test logic here
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
describe('By parent/sibling/child/grandchild', () => {
|
|
48
|
+
describe('ParentNode', () => {
|
|
49
|
+
it('should handle the case for ParentNode', () => {
|
|
50
|
+
// Add your test logic here
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
describe('Bridge', () => {
|
|
54
|
+
it('should handle the case for Bridge', () => {
|
|
55
|
+
// Add your test logic here
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
describe('SiblingNode', () => {
|
|
60
|
+
it('should handle the case for SiblingNode', () => {
|
|
61
|
+
// Add your test logic here
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('ChildNode', () => {
|
|
65
|
+
it('should handle the case for ChildNode', () => {
|
|
66
|
+
// Add your test logic here
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
describe('GrandchildNode', () => {
|
|
73
|
+
it('should handle the case for GrandchildNode', () => {
|
|
74
|
+
// Add your test logic here
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
describe('HttpBridge', () => {
|
|
83
|
+
it('No tests', () => {
|
|
84
|
+
expect(true).toBeTruthy()
|
|
85
|
+
})
|
|
86
|
+
})
|
|
@@ -0,0 +1,54 @@
|
|
|
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 { HttpBridgeExpress, HttpBridgeExpressConfigSchema } from '../HttpBridge.ts'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @group module
|
|
16
|
+
* @group bridge
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
describe('HttpBridgeExpress - Xns', () => {
|
|
20
|
+
it('HttpBridgeExpress-Xns: Simple Resolve', async () => {
|
|
21
|
+
const memNode = await MemoryNode.create({ account: 'random' })
|
|
22
|
+
|
|
23
|
+
const bridge = await HttpBridgeExpress.create({
|
|
24
|
+
account: 'random',
|
|
25
|
+
config: {
|
|
26
|
+
discoverRoots: 'start',
|
|
27
|
+
name: 'TestBridge',
|
|
28
|
+
nodeUrl: 'https://beta.xns.xyo.network',
|
|
29
|
+
schema: HttpBridgeExpressConfigSchema,
|
|
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(rootModule, () => `Failed to resolve correct object type [XYO] [${rootModule?.constructor.name}]`)
|
|
44
|
+
|
|
45
|
+
const registrarDiviner = asDivinerInstance(await remoteNode.resolve('XNS:AddressRecords:AddressRecordIndexDiviner'))
|
|
46
|
+
expect(registrarDiviner).toBeDefined()
|
|
47
|
+
if (registrarDiviner) {
|
|
48
|
+
const transformer = new NameRegistrarTransformer(registrarDiviner, 'xyo')
|
|
49
|
+
ResolveHelper.transformers = [transformer]
|
|
50
|
+
const address = await transformer.transform('nippyflight.xyo')
|
|
51
|
+
expect(address).toBe('c5fa710300a8a43568678d0fe72810e34d880357')
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
})
|