@xyo-network/bridge-http 2.107.6 → 2.109.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/dist/browser/HttpBridgeBase.d.cts.map +1 -1
- package/dist/browser/HttpBridgeBase.d.mts.map +1 -1
- package/dist/browser/HttpBridgeBase.d.ts.map +1 -1
- package/dist/browser/HttpBridgeFull.d.cts +11 -4
- package/dist/browser/HttpBridgeFull.d.cts.map +1 -1
- package/dist/browser/HttpBridgeFull.d.mts +11 -4
- package/dist/browser/HttpBridgeFull.d.mts.map +1 -1
- package/dist/browser/HttpBridgeFull.d.ts +11 -4
- package/dist/browser/HttpBridgeFull.d.ts.map +1 -1
- package/dist/browser/index-browser.cjs +4 -4
- package/dist/browser/index-browser.cjs.map +1 -1
- package/dist/browser/index-browser.js +4 -4
- package/dist/browser/index-browser.js.map +1 -1
- package/dist/neutral/HttpBridgeBase.d.cts.map +1 -1
- package/dist/neutral/HttpBridgeBase.d.mts.map +1 -1
- package/dist/neutral/HttpBridgeBase.d.ts.map +1 -1
- package/dist/neutral/HttpBridgeFull.d.cts +11 -4
- package/dist/neutral/HttpBridgeFull.d.cts.map +1 -1
- package/dist/neutral/HttpBridgeFull.d.mts +11 -4
- package/dist/neutral/HttpBridgeFull.d.mts.map +1 -1
- package/dist/neutral/HttpBridgeFull.d.ts +11 -4
- package/dist/neutral/HttpBridgeFull.d.ts.map +1 -1
- package/dist/neutral/index-browser.cjs +4 -4
- package/dist/neutral/index-browser.cjs.map +1 -1
- package/dist/neutral/index-browser.js +4 -4
- package/dist/neutral/index-browser.js.map +1 -1
- package/dist/node/HttpBridgeBase.d.cts.map +1 -1
- package/dist/node/HttpBridgeBase.d.mts.map +1 -1
- package/dist/node/HttpBridgeBase.d.ts.map +1 -1
- package/dist/node/HttpBridgeFull.d.cts +11 -4
- package/dist/node/HttpBridgeFull.d.cts.map +1 -1
- package/dist/node/HttpBridgeFull.d.mts +11 -4
- package/dist/node/HttpBridgeFull.d.mts.map +1 -1
- package/dist/node/HttpBridgeFull.d.ts +11 -4
- package/dist/node/HttpBridgeFull.d.ts.map +1 -1
- package/dist/node/index.cjs +93 -42
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.js +93 -42
- package/dist/node/index.js.map +1 -1
- package/package.json +25 -21
- package/src/HttpBridgeBase.ts +5 -4
- package/src/HttpBridgeFull.ts +125 -44
- package/src/HttpBridgeModuleResolver.ts +1 -1
- package/src/ModuleProxy/ModuleProxy.ts +1 -1
- package/xy.config.ts +1 -0
package/src/HttpBridgeFull.ts
CHANGED
|
@@ -4,16 +4,45 @@ import { assertEx } from '@xylabs/assert'
|
|
|
4
4
|
import { exists } from '@xylabs/exists'
|
|
5
5
|
import { Address } from '@xylabs/hex'
|
|
6
6
|
import { toJsonString } from '@xylabs/object'
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
asyncHandler,
|
|
9
|
+
customPoweredByHeader,
|
|
10
|
+
disableCaseSensitiveRouting,
|
|
11
|
+
disableExpressDefaultPoweredByHeader,
|
|
12
|
+
jsonBodyParser,
|
|
13
|
+
responseProfiler,
|
|
14
|
+
useRequestCounters,
|
|
15
|
+
} from '@xylabs/sdk-api-express-ecs'
|
|
8
16
|
import { isQueryBoundWitness, QueryBoundWitness } from '@xyo-network/boundwitness-model'
|
|
9
17
|
import { BridgeExposeOptions, BridgeParams, BridgeUnexposeOptions } from '@xyo-network/bridge-model'
|
|
18
|
+
import { standardResponses } from '@xyo-network/express-node-middleware'
|
|
10
19
|
import { AnyConfigSchema, creatableModule, ModuleInstance, ModuleQueryResult, resolveAddressToInstanceUp } from '@xyo-network/module-model'
|
|
11
20
|
import { Payload } from '@xyo-network/payload-model'
|
|
12
21
|
import express, { Application, Request, Response } from 'express'
|
|
22
|
+
import { StatusCodes } from 'http-status-codes'
|
|
13
23
|
|
|
14
24
|
import { HttpBridgeBase } from './HttpBridgeBase'
|
|
15
25
|
import { HttpBridgeConfig } from './HttpBridgeConfig'
|
|
16
26
|
|
|
27
|
+
/**
|
|
28
|
+
* The type of the path parameters for the address path.
|
|
29
|
+
*/
|
|
30
|
+
type AddressPathParams = {
|
|
31
|
+
address: Address
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The type of the request body for the address path.
|
|
36
|
+
*/
|
|
37
|
+
type PostAddressRequestBody = [QueryBoundWitness, undefined | Payload[]]
|
|
38
|
+
|
|
39
|
+
// TODO: This does not match the error response shape of the legacy bridge BUT it its the
|
|
40
|
+
// shape this bridge is currently returning. Massage this into the standard
|
|
41
|
+
// error shape constructed via middleware.
|
|
42
|
+
type ErrorResponseBody = {
|
|
43
|
+
error: string
|
|
44
|
+
}
|
|
45
|
+
|
|
17
46
|
export interface HttpBridgeParams extends BridgeParams<AnyConfigSchema<HttpBridgeConfig>> {}
|
|
18
47
|
|
|
19
48
|
@creatableModule()
|
|
@@ -22,25 +51,13 @@ export class HttpBridge<TParams extends HttpBridgeParams> extends HttpBridgeBase
|
|
|
22
51
|
protected _exposedModules: WeakRef<ModuleInstance>[] = []
|
|
23
52
|
protected _server?: Server
|
|
24
53
|
|
|
25
|
-
get app() {
|
|
26
|
-
this._app =
|
|
27
|
-
|
|
28
|
-
(() => {
|
|
29
|
-
const app = express()
|
|
30
|
-
app.use(express.json())
|
|
31
|
-
|
|
32
|
-
app.post<Payload[]>('/', (req, res) => {
|
|
33
|
-
this.handlePost(req, res)
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
return app
|
|
37
|
-
})()
|
|
38
|
-
return this._app
|
|
54
|
+
protected get app() {
|
|
55
|
+
if (!this._app) this._app = this.initializeApp()
|
|
56
|
+
return assertEx(this._app, () => 'App not initialized')
|
|
39
57
|
}
|
|
40
58
|
|
|
41
59
|
async exposeChild(mod: ModuleInstance, options?: BridgeExposeOptions | undefined): Promise<ModuleInstance[]> {
|
|
42
60
|
const { maxDepth = 5 } = options ?? {}
|
|
43
|
-
console.log(`exposeChild: ${mod.address} ${mod?.id} ${maxDepth}`)
|
|
44
61
|
assertEx(this.config.host, () => 'Not configured as a host')
|
|
45
62
|
this._exposedModules.push(new WeakRef(mod))
|
|
46
63
|
const children = maxDepth > 0 ? (await mod.publicChildren?.()) ?? [] : []
|
|
@@ -58,7 +75,6 @@ export class HttpBridge<TParams extends HttpBridgeParams> extends HttpBridgeBase
|
|
|
58
75
|
override async exposeHandler(address: Address, options?: BridgeExposeOptions | undefined): Promise<ModuleInstance[]> {
|
|
59
76
|
const { required = true } = options ?? {}
|
|
60
77
|
const mod = await resolveAddressToInstanceUp(this, address)
|
|
61
|
-
console.log(`exposeHandler: ${address} ${mod?.id}`)
|
|
62
78
|
if (required && !mod) {
|
|
63
79
|
throw new Error(`Unable to find required module: ${address}`)
|
|
64
80
|
}
|
|
@@ -73,11 +89,11 @@ export class HttpBridge<TParams extends HttpBridgeParams> extends HttpBridgeBase
|
|
|
73
89
|
}
|
|
74
90
|
|
|
75
91
|
override async startHandler(): Promise<boolean> {
|
|
76
|
-
return (await super.startHandler()) && this.startHttpServer()
|
|
92
|
+
return (await super.startHandler()) && (await this.startHttpServer())
|
|
77
93
|
}
|
|
78
94
|
|
|
79
95
|
override async stopHandler(_timeout?: number | undefined): Promise<boolean> {
|
|
80
|
-
return (await super.stopHandler()) && this.stopHttpServer()
|
|
96
|
+
return (await super.stopHandler()) && (await this.stopHttpServer())
|
|
81
97
|
}
|
|
82
98
|
|
|
83
99
|
override async unexposeHandler(address: Address, options?: BridgeUnexposeOptions | undefined): Promise<ModuleInstance[]> {
|
|
@@ -100,44 +116,109 @@ export class HttpBridge<TParams extends HttpBridgeParams> extends HttpBridgeBase
|
|
|
100
116
|
|
|
101
117
|
protected async callLocalModule(address: Address, query: QueryBoundWitness, payloads: Payload[]): Promise<ModuleQueryResult | null> {
|
|
102
118
|
const mod = this._exposedModules.find((ref) => ref.deref()?.address === address)?.deref()
|
|
103
|
-
|
|
104
|
-
|
|
119
|
+
return mod ? await mod.query(query, payloads) : null
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
protected async handleGet(req: Request<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>, res: Response) {
|
|
123
|
+
const { address } = req.params
|
|
124
|
+
try {
|
|
125
|
+
if (address == this.address) {
|
|
126
|
+
res.json(await this.stateQuery(this.account))
|
|
127
|
+
} else {
|
|
128
|
+
const mod = this._exposedModules.find((ref) => ref.deref()?.address === address)?.deref()
|
|
129
|
+
// TODO: Use standard errors middleware
|
|
130
|
+
if (mod) {
|
|
131
|
+
res.json(await mod.stateQuery(this.account))
|
|
132
|
+
} else {
|
|
133
|
+
res.status(StatusCodes.NOT_FOUND).json({ error: 'Module not found' })
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
} catch (ex) {
|
|
137
|
+
// TODO: Sanitize message
|
|
138
|
+
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: (ex as Error).message })
|
|
105
139
|
}
|
|
106
|
-
return null
|
|
107
140
|
}
|
|
108
141
|
|
|
109
|
-
protected handlePost(req: Request<
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
142
|
+
protected async handlePost(req: Request<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>, res: Response) {
|
|
143
|
+
const { address } = req.params
|
|
144
|
+
const [bw, payloads = []] = Array.isArray(req.body) ? req.body : []
|
|
145
|
+
const query = isQueryBoundWitness(bw) ? bw : undefined
|
|
146
|
+
if (!query) {
|
|
147
|
+
// TODO: Use standard errors middleware
|
|
148
|
+
res.status(StatusCodes.BAD_REQUEST).json({ error: 'No query provided' })
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
if (address == this.address) {
|
|
153
|
+
const result = await this.query(query, payloads)
|
|
154
|
+
return res.json(result)
|
|
155
|
+
} else {
|
|
156
|
+
const result = await this.callLocalModule(address, query, payloads)
|
|
157
|
+
// TODO: Use standard errors middleware
|
|
115
158
|
if (result === null) {
|
|
116
|
-
res.status(
|
|
159
|
+
res.status(StatusCodes.NOT_FOUND).json({ error: 'Module not found' })
|
|
117
160
|
} else {
|
|
118
|
-
|
|
119
|
-
data: result,
|
|
120
|
-
} as ApiEnvelopeSuccess<ModuleQueryResult>
|
|
121
|
-
res.json(envelope)
|
|
161
|
+
res.json(result)
|
|
122
162
|
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
})
|
|
163
|
+
}
|
|
164
|
+
} catch (ex) {
|
|
165
|
+
// TODO: Sanitize message
|
|
166
|
+
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: (ex as Error).message })
|
|
167
|
+
}
|
|
127
168
|
}
|
|
128
169
|
|
|
129
|
-
protected
|
|
170
|
+
protected initializeApp() {
|
|
171
|
+
// Create the express app
|
|
172
|
+
const app = express()
|
|
173
|
+
|
|
174
|
+
// Add middleware
|
|
175
|
+
app.use(responseProfiler)
|
|
176
|
+
app.use(jsonBodyParser)
|
|
177
|
+
app.use(standardResponses)
|
|
178
|
+
disableExpressDefaultPoweredByHeader(app)
|
|
179
|
+
app.use(customPoweredByHeader)
|
|
180
|
+
disableCaseSensitiveRouting(app)
|
|
181
|
+
useRequestCounters(app)
|
|
182
|
+
|
|
183
|
+
// Add routes
|
|
184
|
+
// Redirect all requests to the root to this module's address
|
|
185
|
+
app.get('/', (_req, res) => res.redirect(StatusCodes.MOVED_TEMPORARILY, `/${this.address}`))
|
|
186
|
+
app.post('/', (_req, res) => res.redirect(StatusCodes.TEMPORARY_REDIRECT, `/${this.address}`))
|
|
187
|
+
|
|
188
|
+
app.get<AddressPathParams, ModuleQueryResult>(
|
|
189
|
+
'/:address',
|
|
190
|
+
asyncHandler(async (req, res) => await this.handleGet(req, res)),
|
|
191
|
+
)
|
|
192
|
+
app.post<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>(
|
|
193
|
+
'/:address',
|
|
194
|
+
asyncHandler(async (req, res) => await this.handlePost(req, res)),
|
|
195
|
+
)
|
|
196
|
+
return app
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
protected startHttpServer(): Promise<boolean> {
|
|
130
200
|
if (this.config.host) {
|
|
131
201
|
assertEx(!this._server, () => 'Server already started')
|
|
132
202
|
this._server = this.app.listen(this.config.host?.port ?? 3030)
|
|
133
203
|
}
|
|
134
|
-
return true
|
|
204
|
+
return Promise.resolve(true)
|
|
135
205
|
}
|
|
136
206
|
|
|
137
|
-
protected stopHttpServer() {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
207
|
+
protected stopHttpServer(): Promise<boolean> {
|
|
208
|
+
if (this.config.host) {
|
|
209
|
+
return new Promise((resolve, reject) => {
|
|
210
|
+
if (this._server) {
|
|
211
|
+
this._server.close((err) => {
|
|
212
|
+
if (err) {
|
|
213
|
+
reject(err)
|
|
214
|
+
} else {
|
|
215
|
+
this._server = undefined
|
|
216
|
+
resolve(true)
|
|
217
|
+
}
|
|
218
|
+
})
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
return Promise.resolve(true)
|
|
142
223
|
}
|
|
143
224
|
}
|