@xyo-network/bridge-http-express 5.3.20 → 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/dist/neutral/HttpBridge.d.ts +1 -1
- package/dist/neutral/HttpBridge.d.ts.map +1 -1
- package/dist/neutral/index.mjs.map +1 -1
- package/package.json +41 -29
- package/src/HttpBridge.ts +0 -241
- package/src/index.ts +0 -1
- package/src/spec/HttpBridge.baddns.spec.ts +0 -42
- package/src/spec/HttpBridge.copilot.spec.ts +0 -62
- package/src/spec/HttpBridge.host-resolve.spec.ts +0 -89
- package/src/spec/HttpBridge.host.spec.ts +0 -156
- package/src/spec/HttpBridge.legacy.spec.ts +0 -55
- package/src/spec/HttpBridge.spec.ts +0 -207
- package/src/spec/HttpBridge.tests.spec.ts +0 -85
- package/src/spec/HttpBridge.xns.spec.ts +0 -57
|
@@ -39,7 +39,7 @@ export declare class HttpBridgeExpress<TParams extends HttpBridgeExpressParams>
|
|
|
39
39
|
protected callLocalModule(address: Address, query: QueryBoundWitness, payloads: Payload[]): Promise<ModuleQueryResult | null>;
|
|
40
40
|
protected handleGet(req: Request<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>, res: Response): Promise<void>;
|
|
41
41
|
protected handlePost(req: Request<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>, res: Response): Promise<express.Response<any, Record<string, any>> | undefined>;
|
|
42
|
-
protected initializeApp():
|
|
42
|
+
protected initializeApp(): Application;
|
|
43
43
|
protected startHttpServer(): Promise<boolean>;
|
|
44
44
|
protected stopHttpServer(): Promise<boolean>;
|
|
45
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpBridge.d.ts","sourceRoot":"","sources":["../../src/HttpBridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAWlC,OAAO,EACL,OAAO,EAER,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAuB,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACxF,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AACvE,OAAO,EACL,mBAAmB,EAAE,YAAY,EAAE,qBAAqB,EACzD,MAAM,2BAA2B,CAAA;AAElC,OAAO,EACL,eAAe,EAAmB,cAAc,EAAE,iBAAiB,EACpE,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACK,OAAO,EAAE,MAAM,EAC1B,MAAM,4BAA4B,CAAA;AACnC,OAAO,OAAO,EAAE,EACd,WAAW,EAAE,OAAO,EAAE,QAAQ,EAC/B,MAAM,SAAS,CAAA;AAGhB;;GAEG;AACH,KAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;GAEG;AACH,KAAK,sBAAsB,GAAG,CAAC,iBAAiB,EAAE,SAAS,GAAG,OAAO,EAAE,CAAC,CAAA;AASxE,eAAO,MAAM,6BAA6B;;CAA2D,CAAA;AACrG,MAAM,MAAM,6BAA6B,GAAG,OAAO,6BAA6B,CAAA;AAEhF,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB,CAAC,EAAE,EAAE,6BAA6B,CAAC;CAAG;AAEvG,MAAM,WAAW,uBAAwB,SAAQ,YAAY,CAAC,eAAe,CAAC,uBAAuB,CAAC,CAAC;CAAG;AAE1G,qBACa,iBAAiB,CAAC,OAAO,SAAS,uBAAuB,CAAE,SAAQ,UAAU,CAAC,OAAO,CAAC;IACjG,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA0D;IAC1G,SAAS,CAAC,IAAI,CAAC,EAAE,WAAW,CAAA;IAC5B,SAAS,CAAC,eAAe,EAAE,OAAO,CAAC,cAAc,CAAC,EAAE,CAAK;IACzD,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IAE1B,SAAS,KAAK,GAAG,wBAGhB;IAEK,WAAW,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,SAAS,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAgB7F,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,SAAS,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAY3G,cAAc,IAAI,OAAO,EAAE;IAIrB,YAAY;IAKZ,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS;IAKzC,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,SAAS,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;cAkBxG,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;cAKnH,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,sBAAsB,CAAC,EAAE,GAAG,EAAE,QAAQ;cAoBnG,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,sBAAsB,CAAC,EAAE,GAAG,EAAE,QAAQ;IA4BpH,SAAS,CAAC,aAAa;
|
|
1
|
+
{"version":3,"file":"HttpBridge.d.ts","sourceRoot":"","sources":["../../src/HttpBridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAWlC,OAAO,EACL,OAAO,EAER,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAuB,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACxF,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AACvE,OAAO,EACL,mBAAmB,EAAE,YAAY,EAAE,qBAAqB,EACzD,MAAM,2BAA2B,CAAA;AAElC,OAAO,EACL,eAAe,EAAmB,cAAc,EAAE,iBAAiB,EACpE,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACK,OAAO,EAAE,MAAM,EAC1B,MAAM,4BAA4B,CAAA;AACnC,OAAO,OAAO,EAAE,EACd,WAAW,EAAE,OAAO,EAAE,QAAQ,EAC/B,MAAM,SAAS,CAAA;AAGhB;;GAEG;AACH,KAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED;;GAEG;AACH,KAAK,sBAAsB,GAAG,CAAC,iBAAiB,EAAE,SAAS,GAAG,OAAO,EAAE,CAAC,CAAA;AASxE,eAAO,MAAM,6BAA6B;;CAA2D,CAAA;AACrG,MAAM,MAAM,6BAA6B,GAAG,OAAO,6BAA6B,CAAA;AAEhF,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB,CAAC,EAAE,EAAE,6BAA6B,CAAC;CAAG;AAEvG,MAAM,WAAW,uBAAwB,SAAQ,YAAY,CAAC,eAAe,CAAC,uBAAuB,CAAC,CAAC;CAAG;AAE1G,qBACa,iBAAiB,CAAC,OAAO,SAAS,uBAAuB,CAAE,SAAQ,UAAU,CAAC,OAAO,CAAC;IACjG,gBAAyB,aAAa,EAAE,MAAM,EAAE,CAA0D;IAC1G,SAAS,CAAC,IAAI,CAAC,EAAE,WAAW,CAAA;IAC5B,SAAS,CAAC,eAAe,EAAE,OAAO,CAAC,cAAc,CAAC,EAAE,CAAK;IACzD,SAAS,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IAE1B,SAAS,KAAK,GAAG,wBAGhB;IAEK,WAAW,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,SAAS,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAgB7F,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,SAAS,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAY3G,cAAc,IAAI,OAAO,EAAE;IAIrB,YAAY;IAKZ,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS;IAKzC,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,SAAS,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;cAkBxG,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;cAKnH,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,sBAAsB,CAAC,EAAE,GAAG,EAAE,QAAQ;cAoBnG,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,sBAAsB,CAAC,EAAE,GAAG,EAAE,QAAQ;IA4BpH,SAAS,CAAC,aAAa,IAAI,WAAW;IAgCtC,SAAS,CAAC,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAQ7C,SAAS,CAAC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAiB7C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/HttpBridge.ts"],"sourcesContent":["import { Server } from 'node:http'\n\nimport {\n asyncHandler,\n customPoweredByHeader,\n disableCaseSensitiveRouting,\n disableExpressDefaultPoweredByHeader,\n jsonBodyParser,\n responseProfiler,\n useRequestCounters,\n} from '@xylabs/express'\nimport {\n Address, assertEx,\n exists, toSafeJsonString,\n} from '@xylabs/sdk-js'\nimport { isQueryBoundWitness, QueryBoundWitness } from '@xyo-network/boundwitness-model'\nimport { HttpBridge, HttpBridgeConfig } from '@xyo-network/bridge-http'\nimport {\n BridgeExposeOptions, BridgeParams, BridgeUnexposeOptions,\n} from '@xyo-network/bridge-model'\n// import { standardResponses } from '@xyo-network/express-node-middleware'\nimport {\n AnyConfigSchema, creatableModule, ModuleInstance, ModuleQueryResult, resolveAddressToInstanceUp,\n} from '@xyo-network/module-model'\nimport {\n asSchema, Payload, Schema,\n} from '@xyo-network/payload-model'\nimport express, {\n Application, Request, Response,\n} from 'express'\nimport { StatusCodes } from 'http-status-codes'\n\n/**\n * The type of the path parameters for the address path.\n */\ntype AddressPathParams = {\n address: Address\n}\n\n/**\n * The type of the request body for the address path.\n */\ntype PostAddressRequestBody = [QueryBoundWitness, undefined | Payload[]]\n\n// TODO: This does not match the error response shape of the legacy bridge BUT it its the\n// shape this bridge is currently returning. Massage this into the standard\n// error shape constructed via middleware.\n/* type ErrorResponseBody = {\n error: string\n} */\n\nexport const HttpBridgeExpressConfigSchema = asSchema('network.xyo.bridge.http.express.config', true)\nexport type HttpBridgeExpressConfigSchema = typeof HttpBridgeExpressConfigSchema\n\nexport interface HttpBridgeExpressConfig extends HttpBridgeConfig<{}, HttpBridgeExpressConfigSchema> {}\n\nexport interface HttpBridgeExpressParams extends BridgeParams<AnyConfigSchema<HttpBridgeExpressConfig>> {}\n\n@creatableModule()\nexport class HttpBridgeExpress<TParams extends HttpBridgeExpressParams> extends HttpBridge<TParams> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, HttpBridgeExpressConfigSchema]\n protected _app?: Application\n protected _exposedModules: WeakRef<ModuleInstance>[] = []\n protected _server?: Server\n\n protected get app() {\n if (!this._app) this._app = this.initializeApp()\n return assertEx(this._app, () => 'App not initialized')\n }\n\n async exposeChild(mod: ModuleInstance, options?: BridgeExposeOptions | undefined): Promise<ModuleInstance[]> {\n const { maxDepth = 5 } = options ?? {}\n assertEx(this.config.host, () => 'Not configured as a host')\n this._exposedModules.push(new WeakRef(mod))\n const children = maxDepth > 0 ? ((await mod.publicChildren?.()) ?? []) : []\n this.logger?.log(`childrenToExpose [${mod.id}][${mod.address}]: ${toSafeJsonString(children.map(child => child.id))}`)\n const exposedChildren = (await Promise.all(children.map(child => this.exposeChild(child, { maxDepth: maxDepth - 1, required: false }))))\n .flat()\n .filter(exists)\n const allExposed = [mod, ...exposedChildren]\n\n for (const exposedMod of allExposed) this.logger?.log(`exposed: ${exposedMod.address} [${mod.id}]`)\n\n return allExposed\n }\n\n override async exposeHandler(address: Address, options?: BridgeExposeOptions | undefined): Promise<ModuleInstance[]> {\n const { required = true } = options ?? {}\n const mod = await resolveAddressToInstanceUp(this, address)\n if (required && !mod) {\n throw new Error(`Unable to find required module: ${address}`)\n }\n if (mod) {\n return this.exposeChild(mod, options)\n }\n return []\n }\n\n override exposedHandler(): Address[] {\n return this._exposedModules.map(ref => ref.deref()?.address).filter(exists)\n }\n\n override async startHandler() {\n await super.startHandler()\n await this.startHttpServer()\n }\n\n override async stopHandler(_timeout?: number | undefined) {\n await super.stopHandler()\n await this.stopHttpServer()\n }\n\n override async unexposeHandler(address: Address, options?: BridgeUnexposeOptions | undefined): Promise<ModuleInstance[]> {\n const { maxDepth = 2, required = true } = options ?? {}\n assertEx(this.config.host, () => 'Not configured as a host')\n const mod = this._exposedModules.find(ref => ref.deref()?.address === address)?.deref()\n assertEx(!required || mod, () => `Module not exposed: ${address}`)\n this._exposedModules = this._exposedModules.filter(ref => ref.deref()?.address !== address)\n if (mod) {\n const children = maxDepth > 0 ? ((await mod.publicChildren?.()) ?? []) : []\n const exposedChildren = (\n await Promise.all(children.map(child => this.unexposeHandler(child.address, { maxDepth: maxDepth - 1, required: false })))\n )\n .flat()\n .filter(exists)\n return [mod, ...exposedChildren]\n }\n return []\n }\n\n protected async callLocalModule(address: Address, query: QueryBoundWitness, payloads: Payload[]): Promise<ModuleQueryResult | null> {\n const mod = this._exposedModules.find(ref => ref.deref()?.address === address)?.deref()\n return mod ? await mod.query(query, payloads) : null\n }\n\n protected async handleGet(req: Request<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>, res: Response) {\n const { address } = req.params\n try {\n if (address == this.address) {\n res.json(await this.stateQuery(this.account))\n } else {\n const mod = this._exposedModules.find(ref => ref.deref()?.address === address)?.deref()\n // TODO: Use standard errors middleware\n if (mod) {\n res.json(await mod.stateQuery(this.account))\n } else {\n res.status(StatusCodes.NOT_FOUND).json({ error: 'Module not found' })\n }\n }\n } catch (ex) {\n // TODO: Sanitize message\n res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: (ex as Error).message })\n }\n }\n\n protected async handlePost(req: Request<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>, res: Response) {\n const { address } = req.params\n const [bw, payloads = []] = Array.isArray(req.body) ? req.body : []\n const query = isQueryBoundWitness(bw) ? bw : undefined\n if (!query) {\n // TODO: Use standard errors middleware\n res.status(StatusCodes.BAD_REQUEST).json({ error: 'No query provided' })\n return\n }\n try {\n if (address == this.address) {\n const result = await this.query(query, payloads)\n return res.json(result)\n } else {\n const result = await this.callLocalModule(address, query, payloads)\n // TODO: Use standard errors middleware\n if (result === null) {\n res.status(StatusCodes.NOT_FOUND).json({ error: 'Module not found' })\n } else {\n res.json(result)\n }\n }\n } catch (ex) {\n // TODO: Sanitize message\n res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: (ex as Error).message })\n }\n }\n\n protected initializeApp() {\n // Create the express app\n const app = express()\n\n // Add middleware\n app.use(responseProfiler)\n app.use(jsonBodyParser)\n // removed for now since this causes a cycle\n // app.use(standardResponses)\n disableExpressDefaultPoweredByHeader(app)\n app.use(customPoweredByHeader)\n disableCaseSensitiveRouting(app)\n useRequestCounters(app)\n\n // Add routes\n // Redirect all requests to the root to this module's address\n app.get('/', (_req, res) => res.redirect(StatusCodes.MOVED_TEMPORARILY, `/${this.address}`))\n app.post('/', (_req, res) => res.redirect(StatusCodes.TEMPORARY_REDIRECT, `/${this.address}`))\n\n app.get<AddressPathParams, ModuleQueryResult>(\n '/:address',\n\n asyncHandler(async (req, res) => await this.handleGet(req, res)),\n )\n app.post<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>(\n '/:address',\n\n asyncHandler(async (req, res) => { await this.handlePost(req, res) }),\n )\n return app\n }\n\n protected startHttpServer(): Promise<boolean> {\n if (this.config.host) {\n assertEx(!this._server, () => 'Server already started')\n this._server = this.app.listen(this.config.host?.port ?? 3030)\n }\n return Promise.resolve(true)\n }\n\n protected stopHttpServer(): Promise<boolean> {\n if (this.config.host) {\n return new Promise((resolve, reject) => {\n if (this._server) {\n this._server.close((err) => {\n if (err) {\n reject(err)\n } else {\n this._server = undefined\n resolve(true)\n }\n })\n }\n })\n }\n return Promise.resolve(true)\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/HttpBridge.ts"],"sourcesContent":["import { Server } from 'node:http'\n\nimport {\n asyncHandler,\n customPoweredByHeader,\n disableCaseSensitiveRouting,\n disableExpressDefaultPoweredByHeader,\n jsonBodyParser,\n responseProfiler,\n useRequestCounters,\n} from '@xylabs/express'\nimport {\n Address, assertEx,\n exists, toSafeJsonString,\n} from '@xylabs/sdk-js'\nimport { isQueryBoundWitness, QueryBoundWitness } from '@xyo-network/boundwitness-model'\nimport { HttpBridge, HttpBridgeConfig } from '@xyo-network/bridge-http'\nimport {\n BridgeExposeOptions, BridgeParams, BridgeUnexposeOptions,\n} from '@xyo-network/bridge-model'\n// import { standardResponses } from '@xyo-network/express-node-middleware'\nimport {\n AnyConfigSchema, creatableModule, ModuleInstance, ModuleQueryResult, resolveAddressToInstanceUp,\n} from '@xyo-network/module-model'\nimport {\n asSchema, Payload, Schema,\n} from '@xyo-network/payload-model'\nimport express, {\n Application, Request, Response,\n} from 'express'\nimport { StatusCodes } from 'http-status-codes'\n\n/**\n * The type of the path parameters for the address path.\n */\ntype AddressPathParams = {\n address: Address\n}\n\n/**\n * The type of the request body for the address path.\n */\ntype PostAddressRequestBody = [QueryBoundWitness, undefined | Payload[]]\n\n// TODO: This does not match the error response shape of the legacy bridge BUT it its the\n// shape this bridge is currently returning. Massage this into the standard\n// error shape constructed via middleware.\n/* type ErrorResponseBody = {\n error: string\n} */\n\nexport const HttpBridgeExpressConfigSchema = asSchema('network.xyo.bridge.http.express.config', true)\nexport type HttpBridgeExpressConfigSchema = typeof HttpBridgeExpressConfigSchema\n\nexport interface HttpBridgeExpressConfig extends HttpBridgeConfig<{}, HttpBridgeExpressConfigSchema> {}\n\nexport interface HttpBridgeExpressParams extends BridgeParams<AnyConfigSchema<HttpBridgeExpressConfig>> {}\n\n@creatableModule()\nexport class HttpBridgeExpress<TParams extends HttpBridgeExpressParams> extends HttpBridge<TParams> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, HttpBridgeExpressConfigSchema]\n protected _app?: Application\n protected _exposedModules: WeakRef<ModuleInstance>[] = []\n protected _server?: Server\n\n protected get app() {\n if (!this._app) this._app = this.initializeApp()\n return assertEx(this._app, () => 'App not initialized')\n }\n\n async exposeChild(mod: ModuleInstance, options?: BridgeExposeOptions | undefined): Promise<ModuleInstance[]> {\n const { maxDepth = 5 } = options ?? {}\n assertEx(this.config.host, () => 'Not configured as a host')\n this._exposedModules.push(new WeakRef(mod))\n const children = maxDepth > 0 ? ((await mod.publicChildren?.()) ?? []) : []\n this.logger?.log(`childrenToExpose [${mod.id}][${mod.address}]: ${toSafeJsonString(children.map(child => child.id))}`)\n const exposedChildren = (await Promise.all(children.map(child => this.exposeChild(child, { maxDepth: maxDepth - 1, required: false }))))\n .flat()\n .filter(exists)\n const allExposed = [mod, ...exposedChildren]\n\n for (const exposedMod of allExposed) this.logger?.log(`exposed: ${exposedMod.address} [${mod.id}]`)\n\n return allExposed\n }\n\n override async exposeHandler(address: Address, options?: BridgeExposeOptions | undefined): Promise<ModuleInstance[]> {\n const { required = true } = options ?? {}\n const mod = await resolveAddressToInstanceUp(this, address)\n if (required && !mod) {\n throw new Error(`Unable to find required module: ${address}`)\n }\n if (mod) {\n return this.exposeChild(mod, options)\n }\n return []\n }\n\n override exposedHandler(): Address[] {\n return this._exposedModules.map(ref => ref.deref()?.address).filter(exists)\n }\n\n override async startHandler() {\n await super.startHandler()\n await this.startHttpServer()\n }\n\n override async stopHandler(_timeout?: number | undefined) {\n await super.stopHandler()\n await this.stopHttpServer()\n }\n\n override async unexposeHandler(address: Address, options?: BridgeUnexposeOptions | undefined): Promise<ModuleInstance[]> {\n const { maxDepth = 2, required = true } = options ?? {}\n assertEx(this.config.host, () => 'Not configured as a host')\n const mod = this._exposedModules.find(ref => ref.deref()?.address === address)?.deref()\n assertEx(!required || mod, () => `Module not exposed: ${address}`)\n this._exposedModules = this._exposedModules.filter(ref => ref.deref()?.address !== address)\n if (mod) {\n const children = maxDepth > 0 ? ((await mod.publicChildren?.()) ?? []) : []\n const exposedChildren = (\n await Promise.all(children.map(child => this.unexposeHandler(child.address, { maxDepth: maxDepth - 1, required: false })))\n )\n .flat()\n .filter(exists)\n return [mod, ...exposedChildren]\n }\n return []\n }\n\n protected async callLocalModule(address: Address, query: QueryBoundWitness, payloads: Payload[]): Promise<ModuleQueryResult | null> {\n const mod = this._exposedModules.find(ref => ref.deref()?.address === address)?.deref()\n return mod ? await mod.query(query, payloads) : null\n }\n\n protected async handleGet(req: Request<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>, res: Response) {\n const { address } = req.params\n try {\n if (address == this.address) {\n res.json(await this.stateQuery(this.account))\n } else {\n const mod = this._exposedModules.find(ref => ref.deref()?.address === address)?.deref()\n // TODO: Use standard errors middleware\n if (mod) {\n res.json(await mod.stateQuery(this.account))\n } else {\n res.status(StatusCodes.NOT_FOUND).json({ error: 'Module not found' })\n }\n }\n } catch (ex) {\n // TODO: Sanitize message\n res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: (ex as Error).message })\n }\n }\n\n protected async handlePost(req: Request<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>, res: Response) {\n const { address } = req.params\n const [bw, payloads = []] = Array.isArray(req.body) ? req.body : []\n const query = isQueryBoundWitness(bw) ? bw : undefined\n if (!query) {\n // TODO: Use standard errors middleware\n res.status(StatusCodes.BAD_REQUEST).json({ error: 'No query provided' })\n return\n }\n try {\n if (address == this.address) {\n const result = await this.query(query, payloads)\n return res.json(result)\n } else {\n const result = await this.callLocalModule(address, query, payloads)\n // TODO: Use standard errors middleware\n if (result === null) {\n res.status(StatusCodes.NOT_FOUND).json({ error: 'Module not found' })\n } else {\n res.json(result)\n }\n }\n } catch (ex) {\n // TODO: Sanitize message\n res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: (ex as Error).message })\n }\n }\n\n protected initializeApp(): Application {\n // Create the express app\n const app = express()\n\n // Add middleware\n app.use(responseProfiler)\n app.use(jsonBodyParser)\n // removed for now since this causes a cycle\n // app.use(standardResponses)\n disableExpressDefaultPoweredByHeader(app)\n app.use(customPoweredByHeader)\n disableCaseSensitiveRouting(app)\n useRequestCounters(app)\n\n // Add routes\n // Redirect all requests to the root to this module's address\n app.get('/', (_req, res) => res.redirect(StatusCodes.MOVED_TEMPORARILY, `/${this.address}`))\n app.post('/', (_req, res) => res.redirect(StatusCodes.TEMPORARY_REDIRECT, `/${this.address}`))\n\n app.get<AddressPathParams, ModuleQueryResult>(\n '/:address',\n\n asyncHandler(async (req, res) => await this.handleGet(req, res)),\n )\n app.post<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>(\n '/:address',\n\n asyncHandler(async (req, res) => { await this.handlePost(req, res) }),\n )\n return app\n }\n\n protected startHttpServer(): Promise<boolean> {\n if (this.config.host) {\n assertEx(!this._server, () => 'Server already started')\n this._server = this.app.listen(this.config.host?.port ?? 3030)\n }\n return Promise.resolve(true)\n }\n\n protected stopHttpServer(): Promise<boolean> {\n if (this.config.host) {\n return new Promise((resolve, reject) => {\n if (this._server) {\n this._server.close((err) => {\n if (err) {\n reject(err)\n } else {\n this._server = undefined\n resolve(true)\n }\n })\n }\n })\n }\n return Promise.resolve(true)\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xyo-network/bridge-http-express",
|
|
3
|
-
"version": "5.3.
|
|
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,50 +30,62 @@
|
|
|
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
|
-
"@
|
|
40
|
-
"
|
|
41
|
-
"@xyo-network/boundwitness-model": "~5.3.
|
|
42
|
-
"@xyo-network/bridge-http": "~5.3.
|
|
43
|
-
"@xyo-network/bridge-model": "~5.3.
|
|
44
|
-
"@xyo-network/module-model": "~5.3.
|
|
45
|
-
"@xyo-network/payload-model": "~5.3.
|
|
46
|
-
"http-status-codes": "~2.3.0"
|
|
38
|
+
"@xylabs/express": "~5.0.93",
|
|
39
|
+
"http-status-codes": "~2.3.0",
|
|
40
|
+
"@xyo-network/boundwitness-model": "~5.3.24",
|
|
41
|
+
"@xyo-network/bridge-http": "~5.3.24",
|
|
42
|
+
"@xyo-network/bridge-model": "~5.3.24",
|
|
43
|
+
"@xyo-network/module-model": "~5.3.24",
|
|
44
|
+
"@xyo-network/payload-model": "~5.3.24"
|
|
47
45
|
},
|
|
48
46
|
"devDependencies": {
|
|
47
|
+
"@opentelemetry/api": "^1.9.1",
|
|
49
48
|
"@types/express": "~5.0.6",
|
|
50
49
|
"@types/node": "^25.5.0",
|
|
51
|
-
"@xylabs/
|
|
52
|
-
"@xylabs/
|
|
53
|
-
"@xylabs/ts-scripts-
|
|
54
|
-
"@xylabs/
|
|
55
|
-
"@xylabs/
|
|
56
|
-
"@
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"@xyo-network/module-resolver": "~5.3.20",
|
|
62
|
-
"@xyo-network/node-memory": "~5.3.20",
|
|
63
|
-
"@xyo-network/node-model": "~5.3.20",
|
|
64
|
-
"@xyo-network/payload-builder": "~5.3.20",
|
|
65
|
-
"@xyo-network/payload-wrapper": "~5.3.20",
|
|
66
|
-
"@xyo-network/wallet": "~5.3.20",
|
|
67
|
-
"axios": "^1.13.6",
|
|
50
|
+
"@xylabs/express": "~5.0.93",
|
|
51
|
+
"@xylabs/sdk-js": "^5.0.93",
|
|
52
|
+
"@xylabs/ts-scripts-common": "~7.6.16",
|
|
53
|
+
"@xylabs/ts-scripts-pnpm": "~7.6.16",
|
|
54
|
+
"@xylabs/tsconfig": "~7.6.16",
|
|
55
|
+
"@xylabs/vitest-extended": "~5.0.93",
|
|
56
|
+
"acorn": "^8.16.0",
|
|
57
|
+
"axios": "^1.14.0",
|
|
58
|
+
"esbuild": "^0.28.0",
|
|
59
|
+
"ethers": "^6.16.0",
|
|
68
60
|
"express": "^5.2.1",
|
|
69
61
|
"get-port-please": "~3.2.0",
|
|
62
|
+
"http-status-codes": "~2.3.0",
|
|
63
|
+
"tslib": "^2.8.1",
|
|
70
64
|
"typescript": "~5.9.3",
|
|
65
|
+
"vite": "^8.0.3",
|
|
71
66
|
"vitest": "~4.1.2",
|
|
72
|
-
"zod": "^4.3.6"
|
|
67
|
+
"zod": "^4.3.6",
|
|
68
|
+
"@xyo-network/archivist-model": "~5.3.24",
|
|
69
|
+
"@xyo-network/bridge-abstract": "~5.3.24",
|
|
70
|
+
"@xyo-network/api-models": "~5.3.24",
|
|
71
|
+
"@xyo-network/bridge-pub-sub": "~5.3.24",
|
|
72
|
+
"@xyo-network/diviner-model": "~5.3.24",
|
|
73
|
+
"@xyo-network/module-resolver": "~5.3.24",
|
|
74
|
+
"@xyo-network/boundwitness-model": "~5.3.24",
|
|
75
|
+
"@xyo-network/bridge-http": "~5.3.24",
|
|
76
|
+
"@xyo-network/node-memory": "~5.3.24",
|
|
77
|
+
"@xyo-network/node-model": "~5.3.24",
|
|
78
|
+
"@xyo-network/payload-model": "~5.3.24",
|
|
79
|
+
"@xyo-network/payload-builder": "~5.3.24",
|
|
80
|
+
"@xyo-network/bridge-model": "~5.3.24",
|
|
81
|
+
"@xyo-network/module-model": "~5.3.24",
|
|
82
|
+
"@xyo-network/payload-wrapper": "~5.3.24",
|
|
83
|
+
"@xyo-network/wallet": "~5.3.24"
|
|
73
84
|
},
|
|
74
85
|
"peerDependencies": {
|
|
75
86
|
"@xylabs/sdk-js": "^5",
|
|
76
87
|
"axios": "^1",
|
|
88
|
+
"ethers": "^6",
|
|
77
89
|
"express": "^5",
|
|
78
90
|
"tslib": "^2.8.1",
|
|
79
91
|
"zod": "^4"
|
|
@@ -81,4 +93,4 @@
|
|
|
81
93
|
"publishConfig": {
|
|
82
94
|
"access": "public"
|
|
83
95
|
}
|
|
84
|
-
}
|
|
96
|
+
}
|
package/src/HttpBridge.ts
DELETED
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
import { Server } from 'node:http'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
asyncHandler,
|
|
5
|
-
customPoweredByHeader,
|
|
6
|
-
disableCaseSensitiveRouting,
|
|
7
|
-
disableExpressDefaultPoweredByHeader,
|
|
8
|
-
jsonBodyParser,
|
|
9
|
-
responseProfiler,
|
|
10
|
-
useRequestCounters,
|
|
11
|
-
} from '@xylabs/express'
|
|
12
|
-
import {
|
|
13
|
-
Address, assertEx,
|
|
14
|
-
exists, toSafeJsonString,
|
|
15
|
-
} from '@xylabs/sdk-js'
|
|
16
|
-
import { isQueryBoundWitness, QueryBoundWitness } from '@xyo-network/boundwitness-model'
|
|
17
|
-
import { HttpBridge, HttpBridgeConfig } from '@xyo-network/bridge-http'
|
|
18
|
-
import {
|
|
19
|
-
BridgeExposeOptions, BridgeParams, BridgeUnexposeOptions,
|
|
20
|
-
} from '@xyo-network/bridge-model'
|
|
21
|
-
// import { standardResponses } from '@xyo-network/express-node-middleware'
|
|
22
|
-
import {
|
|
23
|
-
AnyConfigSchema, creatableModule, ModuleInstance, ModuleQueryResult, resolveAddressToInstanceUp,
|
|
24
|
-
} from '@xyo-network/module-model'
|
|
25
|
-
import {
|
|
26
|
-
asSchema, Payload, Schema,
|
|
27
|
-
} from '@xyo-network/payload-model'
|
|
28
|
-
import express, {
|
|
29
|
-
Application, Request, Response,
|
|
30
|
-
} from 'express'
|
|
31
|
-
import { StatusCodes } from 'http-status-codes'
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* The type of the path parameters for the address path.
|
|
35
|
-
*/
|
|
36
|
-
type AddressPathParams = {
|
|
37
|
-
address: Address
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* The type of the request body for the address path.
|
|
42
|
-
*/
|
|
43
|
-
type PostAddressRequestBody = [QueryBoundWitness, undefined | Payload[]]
|
|
44
|
-
|
|
45
|
-
// TODO: This does not match the error response shape of the legacy bridge BUT it its the
|
|
46
|
-
// shape this bridge is currently returning. Massage this into the standard
|
|
47
|
-
// error shape constructed via middleware.
|
|
48
|
-
/* type ErrorResponseBody = {
|
|
49
|
-
error: string
|
|
50
|
-
} */
|
|
51
|
-
|
|
52
|
-
export const HttpBridgeExpressConfigSchema = asSchema('network.xyo.bridge.http.express.config', true)
|
|
53
|
-
export type HttpBridgeExpressConfigSchema = typeof HttpBridgeExpressConfigSchema
|
|
54
|
-
|
|
55
|
-
export interface HttpBridgeExpressConfig extends HttpBridgeConfig<{}, HttpBridgeExpressConfigSchema> {}
|
|
56
|
-
|
|
57
|
-
export interface HttpBridgeExpressParams extends BridgeParams<AnyConfigSchema<HttpBridgeExpressConfig>> {}
|
|
58
|
-
|
|
59
|
-
@creatableModule()
|
|
60
|
-
export class HttpBridgeExpress<TParams extends HttpBridgeExpressParams> extends HttpBridge<TParams> {
|
|
61
|
-
static override readonly configSchemas: Schema[] = [...super.configSchemas, HttpBridgeExpressConfigSchema]
|
|
62
|
-
protected _app?: Application
|
|
63
|
-
protected _exposedModules: WeakRef<ModuleInstance>[] = []
|
|
64
|
-
protected _server?: Server
|
|
65
|
-
|
|
66
|
-
protected get app() {
|
|
67
|
-
if (!this._app) this._app = this.initializeApp()
|
|
68
|
-
return assertEx(this._app, () => 'App not initialized')
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async exposeChild(mod: ModuleInstance, options?: BridgeExposeOptions | undefined): Promise<ModuleInstance[]> {
|
|
72
|
-
const { maxDepth = 5 } = options ?? {}
|
|
73
|
-
assertEx(this.config.host, () => 'Not configured as a host')
|
|
74
|
-
this._exposedModules.push(new WeakRef(mod))
|
|
75
|
-
const children = maxDepth > 0 ? ((await mod.publicChildren?.()) ?? []) : []
|
|
76
|
-
this.logger?.log(`childrenToExpose [${mod.id}][${mod.address}]: ${toSafeJsonString(children.map(child => child.id))}`)
|
|
77
|
-
const exposedChildren = (await Promise.all(children.map(child => this.exposeChild(child, { maxDepth: maxDepth - 1, required: false }))))
|
|
78
|
-
.flat()
|
|
79
|
-
.filter(exists)
|
|
80
|
-
const allExposed = [mod, ...exposedChildren]
|
|
81
|
-
|
|
82
|
-
for (const exposedMod of allExposed) this.logger?.log(`exposed: ${exposedMod.address} [${mod.id}]`)
|
|
83
|
-
|
|
84
|
-
return allExposed
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
override async exposeHandler(address: Address, options?: BridgeExposeOptions | undefined): Promise<ModuleInstance[]> {
|
|
88
|
-
const { required = true } = options ?? {}
|
|
89
|
-
const mod = await resolveAddressToInstanceUp(this, address)
|
|
90
|
-
if (required && !mod) {
|
|
91
|
-
throw new Error(`Unable to find required module: ${address}`)
|
|
92
|
-
}
|
|
93
|
-
if (mod) {
|
|
94
|
-
return this.exposeChild(mod, options)
|
|
95
|
-
}
|
|
96
|
-
return []
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
override exposedHandler(): Address[] {
|
|
100
|
-
return this._exposedModules.map(ref => ref.deref()?.address).filter(exists)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
override async startHandler() {
|
|
104
|
-
await super.startHandler()
|
|
105
|
-
await this.startHttpServer()
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
override async stopHandler(_timeout?: number | undefined) {
|
|
109
|
-
await super.stopHandler()
|
|
110
|
-
await this.stopHttpServer()
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
override async unexposeHandler(address: Address, options?: BridgeUnexposeOptions | undefined): Promise<ModuleInstance[]> {
|
|
114
|
-
const { maxDepth = 2, required = true } = options ?? {}
|
|
115
|
-
assertEx(this.config.host, () => 'Not configured as a host')
|
|
116
|
-
const mod = this._exposedModules.find(ref => ref.deref()?.address === address)?.deref()
|
|
117
|
-
assertEx(!required || mod, () => `Module not exposed: ${address}`)
|
|
118
|
-
this._exposedModules = this._exposedModules.filter(ref => ref.deref()?.address !== address)
|
|
119
|
-
if (mod) {
|
|
120
|
-
const children = maxDepth > 0 ? ((await mod.publicChildren?.()) ?? []) : []
|
|
121
|
-
const exposedChildren = (
|
|
122
|
-
await Promise.all(children.map(child => this.unexposeHandler(child.address, { maxDepth: maxDepth - 1, required: false })))
|
|
123
|
-
)
|
|
124
|
-
.flat()
|
|
125
|
-
.filter(exists)
|
|
126
|
-
return [mod, ...exposedChildren]
|
|
127
|
-
}
|
|
128
|
-
return []
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
protected async callLocalModule(address: Address, query: QueryBoundWitness, payloads: Payload[]): Promise<ModuleQueryResult | null> {
|
|
132
|
-
const mod = this._exposedModules.find(ref => ref.deref()?.address === address)?.deref()
|
|
133
|
-
return mod ? await mod.query(query, payloads) : null
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
protected async handleGet(req: Request<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>, res: Response) {
|
|
137
|
-
const { address } = req.params
|
|
138
|
-
try {
|
|
139
|
-
if (address == this.address) {
|
|
140
|
-
res.json(await this.stateQuery(this.account))
|
|
141
|
-
} else {
|
|
142
|
-
const mod = this._exposedModules.find(ref => ref.deref()?.address === address)?.deref()
|
|
143
|
-
// TODO: Use standard errors middleware
|
|
144
|
-
if (mod) {
|
|
145
|
-
res.json(await mod.stateQuery(this.account))
|
|
146
|
-
} else {
|
|
147
|
-
res.status(StatusCodes.NOT_FOUND).json({ error: 'Module not found' })
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
} catch (ex) {
|
|
151
|
-
// TODO: Sanitize message
|
|
152
|
-
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: (ex as Error).message })
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
protected async handlePost(req: Request<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>, res: Response) {
|
|
157
|
-
const { address } = req.params
|
|
158
|
-
const [bw, payloads = []] = Array.isArray(req.body) ? req.body : []
|
|
159
|
-
const query = isQueryBoundWitness(bw) ? bw : undefined
|
|
160
|
-
if (!query) {
|
|
161
|
-
// TODO: Use standard errors middleware
|
|
162
|
-
res.status(StatusCodes.BAD_REQUEST).json({ error: 'No query provided' })
|
|
163
|
-
return
|
|
164
|
-
}
|
|
165
|
-
try {
|
|
166
|
-
if (address == this.address) {
|
|
167
|
-
const result = await this.query(query, payloads)
|
|
168
|
-
return res.json(result)
|
|
169
|
-
} else {
|
|
170
|
-
const result = await this.callLocalModule(address, query, payloads)
|
|
171
|
-
// TODO: Use standard errors middleware
|
|
172
|
-
if (result === null) {
|
|
173
|
-
res.status(StatusCodes.NOT_FOUND).json({ error: 'Module not found' })
|
|
174
|
-
} else {
|
|
175
|
-
res.json(result)
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
} catch (ex) {
|
|
179
|
-
// TODO: Sanitize message
|
|
180
|
-
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ error: (ex as Error).message })
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
protected initializeApp() {
|
|
185
|
-
// Create the express app
|
|
186
|
-
const app = express()
|
|
187
|
-
|
|
188
|
-
// Add middleware
|
|
189
|
-
app.use(responseProfiler)
|
|
190
|
-
app.use(jsonBodyParser)
|
|
191
|
-
// removed for now since this causes a cycle
|
|
192
|
-
// app.use(standardResponses)
|
|
193
|
-
disableExpressDefaultPoweredByHeader(app)
|
|
194
|
-
app.use(customPoweredByHeader)
|
|
195
|
-
disableCaseSensitiveRouting(app)
|
|
196
|
-
useRequestCounters(app)
|
|
197
|
-
|
|
198
|
-
// Add routes
|
|
199
|
-
// Redirect all requests to the root to this module's address
|
|
200
|
-
app.get('/', (_req, res) => res.redirect(StatusCodes.MOVED_TEMPORARILY, `/${this.address}`))
|
|
201
|
-
app.post('/', (_req, res) => res.redirect(StatusCodes.TEMPORARY_REDIRECT, `/${this.address}`))
|
|
202
|
-
|
|
203
|
-
app.get<AddressPathParams, ModuleQueryResult>(
|
|
204
|
-
'/:address',
|
|
205
|
-
|
|
206
|
-
asyncHandler(async (req, res) => await this.handleGet(req, res)),
|
|
207
|
-
)
|
|
208
|
-
app.post<AddressPathParams, ModuleQueryResult, PostAddressRequestBody>(
|
|
209
|
-
'/:address',
|
|
210
|
-
|
|
211
|
-
asyncHandler(async (req, res) => { await this.handlePost(req, res) }),
|
|
212
|
-
)
|
|
213
|
-
return app
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
protected startHttpServer(): Promise<boolean> {
|
|
217
|
-
if (this.config.host) {
|
|
218
|
-
assertEx(!this._server, () => 'Server already started')
|
|
219
|
-
this._server = this.app.listen(this.config.host?.port ?? 3030)
|
|
220
|
-
}
|
|
221
|
-
return Promise.resolve(true)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
protected stopHttpServer(): Promise<boolean> {
|
|
225
|
-
if (this.config.host) {
|
|
226
|
-
return new Promise((resolve, reject) => {
|
|
227
|
-
if (this._server) {
|
|
228
|
-
this._server.close((err) => {
|
|
229
|
-
if (err) {
|
|
230
|
-
reject(err)
|
|
231
|
-
} else {
|
|
232
|
-
this._server = undefined
|
|
233
|
-
resolve(true)
|
|
234
|
-
}
|
|
235
|
-
})
|
|
236
|
-
}
|
|
237
|
-
})
|
|
238
|
-
}
|
|
239
|
-
return Promise.resolve(true)
|
|
240
|
-
}
|
|
241
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './HttpBridge.ts'
|
|
@@ -1,42 +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 { HttpBridgeExpress, HttpBridgeExpressConfigSchema } from '../HttpBridge.ts'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @group module
|
|
12
|
-
* @group bridge
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
describe('HttpBridge', () => {
|
|
16
|
-
const baseUrl = 'https://sfjhskjdsfhdsk.com'
|
|
17
|
-
|
|
18
|
-
console.log(`HttpBridge:baseUrl ${baseUrl}`)
|
|
19
|
-
const cases = [
|
|
20
|
-
['/', `${baseUrl}`],
|
|
21
|
-
/* ['/node', `${baseUrl}/node`], */
|
|
22
|
-
]
|
|
23
|
-
|
|
24
|
-
it.each(cases)('HttpBridge: %s', async (_, nodeUrl) => {
|
|
25
|
-
const memNode = await MemoryNode.create({ account: 'random' })
|
|
26
|
-
|
|
27
|
-
const bridge = await HttpBridgeExpress.create({
|
|
28
|
-
account: 'random',
|
|
29
|
-
config: {
|
|
30
|
-
client: { url: nodeUrl }, schema: HttpBridgeExpressConfigSchema, security: { allowAnonymous: true },
|
|
31
|
-
},
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
await bridge?.start?.()
|
|
35
|
-
|
|
36
|
-
await memNode.register(bridge)
|
|
37
|
-
await memNode.attach(bridge.address, true)
|
|
38
|
-
|
|
39
|
-
const modules = await memNode.resolve('*')
|
|
40
|
-
expect(modules.length).toBe(2)
|
|
41
|
-
})
|
|
42
|
-
})
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import '@xylabs/vitest-extended'
|
|
2
|
-
|
|
3
|
-
import type { Address } from '@xylabs/sdk-js'
|
|
4
|
-
import {
|
|
5
|
-
beforeEach,
|
|
6
|
-
describe, expect, it,
|
|
7
|
-
} from 'vitest'
|
|
8
|
-
|
|
9
|
-
import type { HttpBridgeExpressParams } from '../HttpBridge.ts'
|
|
10
|
-
import { HttpBridgeExpress, HttpBridgeExpressConfigSchema } from '../HttpBridge.ts'
|
|
11
|
-
|
|
12
|
-
describe('HttpBridgeExpress', () => {
|
|
13
|
-
let httpBridge: HttpBridgeExpress<HttpBridgeExpressParams>
|
|
14
|
-
|
|
15
|
-
beforeEach(async () => {
|
|
16
|
-
httpBridge = await HttpBridgeExpress.create({
|
|
17
|
-
account: 'random',
|
|
18
|
-
config: {
|
|
19
|
-
name: 'TestBridge', client: { url: 'http://localhost:8080' }, schema: HttpBridgeExpressConfigSchema, security: { allowAnonymous: true },
|
|
20
|
-
},
|
|
21
|
-
})
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('should create an instance of HttpBridgeExpress', () => {
|
|
25
|
-
expect(httpBridge).toBeInstanceOf(HttpBridgeExpress)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('should have axios instance', () => {
|
|
29
|
-
expect(httpBridge.axios).toBeDefined()
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('should have nodeUrl defined', () => {
|
|
33
|
-
expect(httpBridge.clientUrl).toBe('http://localhost:8080')
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
it('should have resolver defined', () => {
|
|
37
|
-
expect(httpBridge.resolver).toBeDefined()
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
it('should return correct moduleUrl', () => {
|
|
41
|
-
const address = '0x1234' as Address
|
|
42
|
-
expect(httpBridge.moduleUrl(address).toString()).toBe('http://localhost:8080/0x1234')
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
it('should throw error on call to exposeHandler', async () => {
|
|
46
|
-
try {
|
|
47
|
-
await httpBridge.exposeHandler('test' as Address)
|
|
48
|
-
expect('').toBe('exposeHandler should have thrown an error')
|
|
49
|
-
} catch (error) {
|
|
50
|
-
expect(error).toBeInstanceOf(Error)
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
it('should throw error on call to unexposeHandler', async () => {
|
|
55
|
-
try {
|
|
56
|
-
await httpBridge.unexposeHandler('test' as Address)
|
|
57
|
-
expect('').toBe('unexposeHandler should have thrown an error')
|
|
58
|
-
} catch (error) {
|
|
59
|
-
expect(error).toBeInstanceOf(Error)
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
})
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import '@xylabs/vitest-extended'
|
|
2
|
-
|
|
3
|
-
import type { CreatableName } from '@xylabs/sdk-js'
|
|
4
|
-
import { HttpBridge, HttpBridgeConfigSchema } from '@xyo-network/bridge-http'
|
|
5
|
-
import type {
|
|
6
|
-
AsyncQueryBusIntersectConfig,
|
|
7
|
-
PubSubBridgeConfig,
|
|
8
|
-
PubSubBridgeParams,
|
|
9
|
-
} from '@xyo-network/bridge-pub-sub'
|
|
10
|
-
import {
|
|
11
|
-
PubSubBridge,
|
|
12
|
-
PubSubBridgeConfigSchema,
|
|
13
|
-
} from '@xyo-network/bridge-pub-sub'
|
|
14
|
-
import { MemoryNode } from '@xyo-network/node-memory'
|
|
15
|
-
import { NodeConfigSchema } from '@xyo-network/node-model'
|
|
16
|
-
import {
|
|
17
|
-
describe, expect, it,
|
|
18
|
-
} from 'vitest'
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @group module
|
|
22
|
-
* @group bridge
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
describe.skip('HttpBridge with PubSubBridge', () => {
|
|
26
|
-
const httpBaseUrl = process.env.XNS_API_DOMAIN ?? 'https://beta.xns.xyo.network' // ?? 'http://localhost:80'
|
|
27
|
-
|
|
28
|
-
console.log(`HttpBridge:baseUrl ${httpBaseUrl}`)
|
|
29
|
-
const cases = [
|
|
30
|
-
['/', `${httpBaseUrl}`],
|
|
31
|
-
/* ['/node', `${baseUrl}/node`], */
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
it.each(cases)('HttpBridge: %s', async (_, nodeUrl) => {
|
|
35
|
-
const memNode = await MemoryNode.create({ account: 'random', config: { name: 'MemNodeArie', schema: NodeConfigSchema } })
|
|
36
|
-
const intersect: AsyncQueryBusIntersectConfig = {
|
|
37
|
-
queries: { archivist: 'MemNodeArie:XNS:Intersect:QueryArchivist', boundWitnessDiviner: 'MemNodeArie:XNS:Intersect:QueryBoundWitnessDiviner' },
|
|
38
|
-
responses: {
|
|
39
|
-
archivist: 'MemNodeArie:XNS:Intersect:ResponseArchivist',
|
|
40
|
-
boundWitnessDiviner: 'MemNodeArie:XNS:Intersect:ResponseBoundWitnessDiviner',
|
|
41
|
-
},
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const bridge = await HttpBridge.create({
|
|
45
|
-
account: 'random',
|
|
46
|
-
config: {
|
|
47
|
-
name: 'TestBridge', client: { url: nodeUrl, discoverRoots: 'start' }, schema: HttpBridgeConfigSchema, security: { allowAnonymous: true },
|
|
48
|
-
},
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
await bridge?.start?.()
|
|
52
|
-
await memNode.register(bridge)
|
|
53
|
-
await memNode.attach(bridge?.address, true)
|
|
54
|
-
|
|
55
|
-
const config: PubSubBridgeConfig = {
|
|
56
|
-
client: { intersect }, host: { intersect }, name: 'PubSubBridgeArie', schema: PubSubBridgeConfigSchema,
|
|
57
|
-
}
|
|
58
|
-
const psParams: PubSubBridgeParams = {
|
|
59
|
-
account: 'random', config, name: 'PubSubBridge' as CreatableName,
|
|
60
|
-
}
|
|
61
|
-
const psBridge = await PubSubBridge.create(psParams)
|
|
62
|
-
await memNode.register(psBridge)
|
|
63
|
-
await memNode.attach(psBridge?.address, true)
|
|
64
|
-
|
|
65
|
-
await psBridge.start()
|
|
66
|
-
console.log(`Exposing: ${memNode.address}`)
|
|
67
|
-
await bridge.expose(memNode.address)
|
|
68
|
-
|
|
69
|
-
const subNodeInstance = await memNode?.resolve('PubSubBridgeArie')
|
|
70
|
-
expect(subNodeInstance).toBeDefined()
|
|
71
|
-
|
|
72
|
-
const testBridgeInstance = await memNode?.resolve('PubSubBridgeArie:TestBridge')
|
|
73
|
-
expect(testBridgeInstance).toBeDefined()
|
|
74
|
-
|
|
75
|
-
const xns1 = await testBridgeInstance?.resolve('XNS')
|
|
76
|
-
expect(xns1).toBeDefined()
|
|
77
|
-
|
|
78
|
-
const xns = await memNode?.resolve('PubSubBridgeArie:TestBridge:XNS')
|
|
79
|
-
expect(xns).toBeDefined()
|
|
80
|
-
|
|
81
|
-
const intersectNode = await memNode?.resolve('PubSubBridgeArie:TestBridge:XNS:Intersect')
|
|
82
|
-
expect(intersectNode).toBeDefined()
|
|
83
|
-
|
|
84
|
-
const queryArchivist = await memNode?.resolve('XNS:Intersect:QueryArchivist')
|
|
85
|
-
expect(queryArchivist?.id).toBe('QueryArchivist')
|
|
86
|
-
|
|
87
|
-
await psBridge.unexpose(memNode.address)
|
|
88
|
-
})
|
|
89
|
-
})
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import '@xylabs/vitest-extended'
|
|
2
|
-
|
|
3
|
-
import type { HttpBridgeConfig, HttpBridgeParams } from '@xyo-network/bridge-http'
|
|
4
|
-
import { HttpBridge, HttpBridgeConfigSchema } from '@xyo-network/bridge-http'
|
|
5
|
-
import type { ModuleDescriptionPayload } from '@xyo-network/module-model'
|
|
6
|
-
import { ModuleDescriptionSchema } from '@xyo-network/module-model'
|
|
7
|
-
import { MemoryNode } from '@xyo-network/node-memory'
|
|
8
|
-
import { asAttachableNodeInstance } from '@xyo-network/node-model'
|
|
9
|
-
import { isPayloadOfSchemaType } from '@xyo-network/payload-model'
|
|
10
|
-
import { getPort } from 'get-port-please'
|
|
11
|
-
import {
|
|
12
|
-
beforeAll,
|
|
13
|
-
beforeEach,
|
|
14
|
-
describe, expect, it,
|
|
15
|
-
} from 'vitest'
|
|
16
|
-
|
|
17
|
-
import type { HttpBridgeExpressConfig, HttpBridgeExpressParams } from '../HttpBridge.ts'
|
|
18
|
-
import { HttpBridgeExpress, HttpBridgeExpressConfigSchema } from '../HttpBridge.ts'
|
|
19
|
-
|
|
20
|
-
const account = 'random'
|
|
21
|
-
const hostSchema = HttpBridgeExpressConfigSchema
|
|
22
|
-
const clientSchema = HttpBridgeConfigSchema
|
|
23
|
-
const security = { allowAnonymous: true }
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @group module
|
|
27
|
-
* @group bridge
|
|
28
|
-
*/
|
|
29
|
-
describe('HttpBridgeExpress', () => {
|
|
30
|
-
let port: number
|
|
31
|
-
let url: string
|
|
32
|
-
let hostBridge: HttpBridgeExpress<HttpBridgeExpressParams>
|
|
33
|
-
let clientBridge: HttpBridge<HttpBridgeParams>
|
|
34
|
-
let hostNode: MemoryNode
|
|
35
|
-
let clientNode: MemoryNode
|
|
36
|
-
let hostSibling: MemoryNode
|
|
37
|
-
let clientSibling: MemoryNode
|
|
38
|
-
let hostDescendent: MemoryNode
|
|
39
|
-
let clientDescendent: MemoryNode
|
|
40
|
-
|
|
41
|
-
beforeAll(async () => {
|
|
42
|
-
// Create Host/Client Nodes
|
|
43
|
-
hostNode = await MemoryNode.create({ account })
|
|
44
|
-
clientNode = await MemoryNode.create({ account })
|
|
45
|
-
|
|
46
|
-
// Create Host/Client Bridges
|
|
47
|
-
port = await getPort()
|
|
48
|
-
url = `http://localhost:${port}`
|
|
49
|
-
|
|
50
|
-
const host: HttpBridgeExpressConfig['host'] = { port }
|
|
51
|
-
const client: HttpBridgeConfig['client'] = { discoverRoots: 'start', url }
|
|
52
|
-
hostBridge = await HttpBridgeExpress.create({
|
|
53
|
-
account,
|
|
54
|
-
config: {
|
|
55
|
-
host, name: 'TestBridgeHost', schema: hostSchema, security,
|
|
56
|
-
},
|
|
57
|
-
})
|
|
58
|
-
clientBridge = await HttpBridge.create({
|
|
59
|
-
account,
|
|
60
|
-
config: {
|
|
61
|
-
client, name: 'TestBridgeClient', schema: clientSchema, security,
|
|
62
|
-
},
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
// Register Host/Client Bridges
|
|
66
|
-
await hostNode.register(hostBridge)
|
|
67
|
-
await hostNode.attach(hostBridge.address, true)
|
|
68
|
-
await clientNode.register(clientBridge)
|
|
69
|
-
await clientNode.attach(clientBridge.address, true)
|
|
70
|
-
|
|
71
|
-
// Create Host/Client Sibling Nodes
|
|
72
|
-
hostSibling = await MemoryNode.create({ account })
|
|
73
|
-
clientSibling = await MemoryNode.create({ account })
|
|
74
|
-
|
|
75
|
-
// Register Host/Client Siblings
|
|
76
|
-
await hostNode.register(hostSibling)
|
|
77
|
-
await hostNode.attach(hostSibling.address, true)
|
|
78
|
-
await clientNode.register(clientSibling)
|
|
79
|
-
await clientNode.attach(clientSibling.address, true)
|
|
80
|
-
|
|
81
|
-
// Create Host/Client Descendent Nodes
|
|
82
|
-
hostDescendent = await MemoryNode.create({ account })
|
|
83
|
-
clientDescendent = await MemoryNode.create({ account })
|
|
84
|
-
|
|
85
|
-
// Register Host/Client Siblings
|
|
86
|
-
await hostSibling.register(hostDescendent)
|
|
87
|
-
await hostSibling.attach(hostDescendent.address, true)
|
|
88
|
-
await clientSibling.register(clientDescendent)
|
|
89
|
-
await clientSibling.attach(clientDescendent.address, true)
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
describe('exposed module behavior', () => {
|
|
93
|
-
const cases: [string, () => MemoryNode][] = [
|
|
94
|
-
['parent', () => hostNode],
|
|
95
|
-
['sibling', () => hostSibling],
|
|
96
|
-
['descendent', () => hostDescendent],
|
|
97
|
-
]
|
|
98
|
-
describe.each(cases)('with %s module', (_, getSutModule) => {
|
|
99
|
-
let exposedMod: MemoryNode
|
|
100
|
-
beforeEach(() => {
|
|
101
|
-
exposedMod = getSutModule()
|
|
102
|
-
})
|
|
103
|
-
describe('before expose', () => {
|
|
104
|
-
it('should not be exposed', async () => {
|
|
105
|
-
expect(await hostBridge.exposed()).toBeEmpty()
|
|
106
|
-
})
|
|
107
|
-
it('should not be resolvable', async () => {
|
|
108
|
-
expect(await clientBridge.resolve(exposedMod.address)).toBeUndefined()
|
|
109
|
-
})
|
|
110
|
-
})
|
|
111
|
-
describe('after expose', () => {
|
|
112
|
-
beforeEach(async () => {
|
|
113
|
-
await hostBridge.expose(exposedMod.address)
|
|
114
|
-
})
|
|
115
|
-
it('should be exposed on host', async () => {
|
|
116
|
-
expect((await hostBridge.exposed()).includes(exposedMod.address)).toBeTrue()
|
|
117
|
-
})
|
|
118
|
-
it.skip('should be resolvable from client', async () => {
|
|
119
|
-
// TODO: Implement .connect on HttpBridgeExpress and call here before resolving
|
|
120
|
-
const result = await clientBridge.resolve(exposedMod.address)
|
|
121
|
-
expect(result).toBeDefined()
|
|
122
|
-
expect(asAttachableNodeInstance(result, () => `Failed to resolve correct object type [${result?.constructor.name}]`)).toBeDefined()
|
|
123
|
-
})
|
|
124
|
-
it.skip('should be queryable from client', async () => {
|
|
125
|
-
const bridgedHostedModule = await clientBridge.resolve(exposedMod.address)
|
|
126
|
-
expect(bridgedHostedModule).toBeDefined()
|
|
127
|
-
|
|
128
|
-
const bridgedHostedNode = asAttachableNodeInstance(
|
|
129
|
-
bridgedHostedModule,
|
|
130
|
-
() => `Failed to resolve correct object type [${bridgedHostedModule?.constructor.name}]`,
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
if (bridgedHostedNode) {
|
|
134
|
-
const state = await bridgedHostedNode.state()
|
|
135
|
-
const description = state.find(isPayloadOfSchemaType<ModuleDescriptionPayload>(ModuleDescriptionSchema))
|
|
136
|
-
expect(description?.children).toBeArray()
|
|
137
|
-
expect(description?.queries).toBeArray()
|
|
138
|
-
expect(description?.queries?.length).toBeGreaterThan(0)
|
|
139
|
-
}
|
|
140
|
-
})
|
|
141
|
-
})
|
|
142
|
-
describe('after unexpose', () => {
|
|
143
|
-
beforeEach(async () => {
|
|
144
|
-
await hostBridge.expose(exposedMod.address)
|
|
145
|
-
await hostBridge.unexpose(exposedMod.address)
|
|
146
|
-
})
|
|
147
|
-
it('should not be exposed', async () => {
|
|
148
|
-
expect(await hostBridge.exposed()).toBeEmpty()
|
|
149
|
-
})
|
|
150
|
-
it('should not be resolvable', async () => {
|
|
151
|
-
expect(await clientBridge.resolve(exposedMod.address)).toBeUndefined()
|
|
152
|
-
})
|
|
153
|
-
})
|
|
154
|
-
})
|
|
155
|
-
})
|
|
156
|
-
})
|
|
@@ -1,55 +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 { HttpBridgeExpress, HttpBridgeExpressConfigSchema } from '../HttpBridge.ts'
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @group module
|
|
14
|
-
* @group bridge
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
describe('HttpBridgeExpress', () => {
|
|
18
|
-
const baseUrl = `${process.env.API_DOMAIN ?? 'http://localhost:8080'}`
|
|
19
|
-
|
|
20
|
-
console.log(`HttpBridgeExpress:baseUrl ${baseUrl}`)
|
|
21
|
-
it('Discover', async () => {
|
|
22
|
-
const nodeUrl = `${baseUrl}/`
|
|
23
|
-
const memNode = await MemoryNode.create({ account: 'random', config: { name: 'MemoryNode', schema: NodeConfigSchema } })
|
|
24
|
-
|
|
25
|
-
const bridge = await HttpBridgeExpress.create({
|
|
26
|
-
account: 'random',
|
|
27
|
-
config: {
|
|
28
|
-
name: 'HttpBridgeExpress', client: { url: nodeUrl, discoverRoots: 'start' }, schema: HttpBridgeExpressConfigSchema, security: { allowAnonymous: true },
|
|
29
|
-
},
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
await memNode.register(bridge)
|
|
33
|
-
await memNode.attach(bridge.address, true)
|
|
34
|
-
|
|
35
|
-
const publicNode = await bridge.resolve<NodeInstance>('XYOPublic')
|
|
36
|
-
expect(publicNode).toBeDefined()
|
|
37
|
-
|
|
38
|
-
if (publicNode) {
|
|
39
|
-
console.log(`publicNode[${publicNode.address}]: ${publicNode.modName}`)
|
|
40
|
-
const publicNodeModules = await publicNode.resolve('*', { direction: 'down' })
|
|
41
|
-
expect(publicNodeModules).toBeArray()
|
|
42
|
-
expect(publicNodeModules.length).toBeGreaterThan(0)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const bridgeModules = await bridge.resolve('*', { direction: 'down' })
|
|
46
|
-
expect(bridgeModules).toBeArray()
|
|
47
|
-
expect(bridgeModules.length).toBeGreaterThan(0)
|
|
48
|
-
|
|
49
|
-
/*
|
|
50
|
-
const modules = await memNode.resolve('*')
|
|
51
|
-
expect(modules).toBeArray()
|
|
52
|
-
expect(modules.length).toBeGreaterThan(20)
|
|
53
|
-
*/
|
|
54
|
-
})
|
|
55
|
-
})
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
/* eslint-disable complexity */
|
|
2
|
-
/* eslint-disable max-statements */
|
|
3
|
-
|
|
4
|
-
import '@xylabs/vitest-extended'
|
|
5
|
-
|
|
6
|
-
import { assertEx, isString } 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 { 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 = isString(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
|
-
name: 'TestBridge', client: { url: nodeUrl, discoverRoots: 'start' }, 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
|
-
{ required: true },
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
const state = await remoteNode.state()
|
|
101
|
-
const description = state.find(isPayloadOfSchemaType<ModuleDescriptionPayload>(ModuleDescriptionSchema))
|
|
102
|
-
expect(description?.children).toBeArray()
|
|
103
|
-
expect(description?.children?.length).toBeGreaterThan(0)
|
|
104
|
-
expect(description?.queries).toBeArray()
|
|
105
|
-
expect(description?.queries?.length).toBeGreaterThan(0)
|
|
106
|
-
|
|
107
|
-
const archivistByName1 = await rootModule?.resolve('Archivist')
|
|
108
|
-
expect(archivistByName1).toBeDefined()
|
|
109
|
-
const archivistByName2 = await bridge.resolve('XYOPublic:Archivist')
|
|
110
|
-
expect(archivistByName2).toBeDefined()
|
|
111
|
-
const publicXyo = await bridge.resolve('XYOPublic')
|
|
112
|
-
expect(publicXyo).toBeDefined()
|
|
113
|
-
const publicXyoSelfResolve = publicXyo?.resolve('XYOPublic')
|
|
114
|
-
expect(publicXyoSelfResolve).toBeDefined()
|
|
115
|
-
if (publicXyo) {
|
|
116
|
-
const bridgedArchivist = await getArchivist()
|
|
117
|
-
expect(bridgedArchivist).toBeDefined()
|
|
118
|
-
if (bridgedArchivist) {
|
|
119
|
-
const attachablePublicXyo = asAttachableArchivistInstance(archivistByName2, 'Failed to cast publicXyo')
|
|
120
|
-
expect(attachablePublicXyo).toBeDefined()
|
|
121
|
-
await extraMemNode.register(bridgedArchivist)
|
|
122
|
-
await extraMemNode.attach(bridgedArchivist.address, true)
|
|
123
|
-
const publicXyoNodeResolveAddress = await extraMemNode?.resolve(bridgedArchivist.address)
|
|
124
|
-
expect(publicXyoNodeResolveAddress).toBeDefined()
|
|
125
|
-
const publicXyoNodeResolve = await extraMemNode?.resolve('Archivist')
|
|
126
|
-
expect(publicXyoNodeResolve).toBeDefined()
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
const archivistByName3 = await publicXyo?.resolve('Archivist')
|
|
130
|
-
expect(archivistByName3).toBeDefined()
|
|
131
|
-
expect(archivistByName3).toEqual(archivistByName1)
|
|
132
|
-
expect(archivistByName3).toEqual(archivistByName2)
|
|
133
|
-
expect(archivistByName2).toBeDefined()
|
|
134
|
-
const archivistInstance = asArchivistInstance(archivistByName2, 'Failed to cast archivist', { required: true })
|
|
135
|
-
expect(archivistInstance).toBeDefined()
|
|
136
|
-
const knownPayload = PayloadWrapper.parse({ schema: 'network.xyo.test' })?.payload as Payload
|
|
137
|
-
expect(knownPayload).toBeDefined()
|
|
138
|
-
const knownHash = await PayloadBuilder.dataHash(knownPayload as Payload)
|
|
139
|
-
const insertResult = await archivistInstance.insert([knownPayload])
|
|
140
|
-
expect(insertResult).toBeDefined()
|
|
141
|
-
const roundTripPayload = (await archivistInstance.get([knownHash]))[0]
|
|
142
|
-
expect(roundTripPayload).toBeDefined()
|
|
143
|
-
})
|
|
144
|
-
it.each(cases)('HttpBridgeExpress - Nested: %s', async (_, nodeUrl) => {
|
|
145
|
-
const memNode1 = await MemoryNode.create({ account: 'random', config: { schema: asSchema('network.xyo.node.config', true) } })
|
|
146
|
-
const memNode2 = await MemoryNode.create({ account: 'random', config: { schema: asSchema('network.xyo.node.config', true) } })
|
|
147
|
-
const memNode3 = await MemoryNode.create({ account: 'random', config: { schema: asSchema('network.xyo.node.config', true) } })
|
|
148
|
-
|
|
149
|
-
await memNode1.register(memNode2)
|
|
150
|
-
await memNode1.attach(memNode2.address, true)
|
|
151
|
-
await memNode2.register(memNode3)
|
|
152
|
-
await memNode2.attach(memNode3.address, true)
|
|
153
|
-
|
|
154
|
-
const bridge = await HttpBridgeExpress.create({
|
|
155
|
-
account: 'random',
|
|
156
|
-
config: {
|
|
157
|
-
client: { url: nodeUrl }, schema: HttpBridgeExpressConfigSchema, security: { allowAnonymous: true },
|
|
158
|
-
},
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
await bridge.getRoots()
|
|
162
|
-
const mod = await bridge.resolve('XYOPublic')
|
|
163
|
-
|
|
164
|
-
expect(mod).toBeDefined()
|
|
165
|
-
expect(isQueryableModule(mod)).toBeTrue()
|
|
166
|
-
expect(isQueryableModuleObject(mod)).toBeTrue()
|
|
167
|
-
|
|
168
|
-
const remoteNode = asAttachableNodeInstance(
|
|
169
|
-
mod,
|
|
170
|
-
`Failed to resolve [XYOPublic] - ${mod?.address} [${mod?.id}] [${mod?.constructor.name}]`,
|
|
171
|
-
{ required: true },
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
expect(isNodeInstance(remoteNode)).toBeTrue()
|
|
175
|
-
expect(isModuleInstance(remoteNode)).toBeTrue()
|
|
176
|
-
|
|
177
|
-
await memNode3.register(remoteNode)
|
|
178
|
-
await memNode3.attach(remoteNode?.address, true)
|
|
179
|
-
const description = (await remoteNode.state()).find(isPayloadOfSchemaType<ModuleDescriptionPayload>(ModuleDescriptionSchema))
|
|
180
|
-
expect(description?.children).toBeArray()
|
|
181
|
-
expect(description?.children?.length).toBeGreaterThan(0)
|
|
182
|
-
expect(description?.queries).toBeArray()
|
|
183
|
-
expect(description?.queries?.length).toBeGreaterThan(0)
|
|
184
|
-
|
|
185
|
-
// Works if you supply the known address for 'Archivist'
|
|
186
|
-
// const [archivistByAddress] = await memNode.resolve({ address: ['461fd6970770e97d9f66c71658f4b96212581f0b'] })
|
|
187
|
-
// expect(archivistByAddress).toBeDefined()
|
|
188
|
-
|
|
189
|
-
/* const mods = await bridge.resolve('*')
|
|
190
|
-
for (const mod of mods) {
|
|
191
|
-
console.log(`module [${mod.address}]: ${mod.modName}`)
|
|
192
|
-
} */
|
|
193
|
-
|
|
194
|
-
const node = await bridge.resolve('XYOPublic')
|
|
195
|
-
expect(node).toBeDefined()
|
|
196
|
-
|
|
197
|
-
const archivistByName1 = await node?.resolve('Archivist')
|
|
198
|
-
expect(archivistByName1).toBeDefined()
|
|
199
|
-
|
|
200
|
-
const archivistByName2 = (await node?.resolve('Archivist'))
|
|
201
|
-
expect(archivistByName2).toBeDefined()
|
|
202
|
-
const payloadStatsDivinerByName = (await node?.resolve('PayloadStatsDiviner'))
|
|
203
|
-
expect(payloadStatsDivinerByName).toBeDefined()
|
|
204
|
-
const boundwitnessStatsDivinerByName = (await node?.resolve('BoundWitnessStatsDiviner'))
|
|
205
|
-
expect(boundwitnessStatsDivinerByName).toBeDefined()
|
|
206
|
-
})
|
|
207
|
-
})
|
|
@@ -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,57 +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 { 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
|
-
name: 'TestBridge',
|
|
27
|
-
client: { url: 'https://beta.xns.xyo.network', discoverRoots: 'start' },
|
|
28
|
-
schema: HttpBridgeExpressConfigSchema,
|
|
29
|
-
security: { allowAnonymous: true },
|
|
30
|
-
},
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
await bridge?.start?.()
|
|
34
|
-
await memNode.register(bridge)
|
|
35
|
-
await memNode.attach(bridge?.address, true)
|
|
36
|
-
const resolvedBridge = await memNode.resolve(bridge.id)
|
|
37
|
-
expect(resolvedBridge).toBeDefined()
|
|
38
|
-
|
|
39
|
-
const rootModule = await bridge?.resolve('XNS')
|
|
40
|
-
expect(rootModule).toBeDefined()
|
|
41
|
-
|
|
42
|
-
const remoteNode = asAttachableNodeInstance(
|
|
43
|
-
rootModule,
|
|
44
|
-
() => `Failed to resolve correct object type [XYO] [${rootModule?.constructor.name}]`,
|
|
45
|
-
{ required: true },
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
const registrarDiviner = asDivinerInstance(await remoteNode.resolve('XNS:AddressRecords:AddressRecordIndexDiviner'))
|
|
49
|
-
expect(registrarDiviner).toBeDefined()
|
|
50
|
-
if (registrarDiviner) {
|
|
51
|
-
const transformer = new NameRegistrarTransformer(registrarDiviner, 'xyo')
|
|
52
|
-
ResolveHelper.transformers = [transformer]
|
|
53
|
-
const address = await transformer.transform('nippyflight.xyo')
|
|
54
|
-
expect(address).toBe('c5fa710300a8a43568678d0fe72810e34d880357')
|
|
55
|
-
}
|
|
56
|
-
})
|
|
57
|
-
})
|