@xyo-network/bridge-http 2.102.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.
Files changed (130) hide show
  1. package/LICENSE +165 -0
  2. package/README.md +13 -0
  3. package/dist/browser/HttpBridge.d.cts +43 -0
  4. package/dist/browser/HttpBridge.d.cts.map +1 -0
  5. package/dist/browser/HttpBridge.d.mts +43 -0
  6. package/dist/browser/HttpBridge.d.mts.map +1 -0
  7. package/dist/browser/HttpBridge.d.ts +43 -0
  8. package/dist/browser/HttpBridge.d.ts.map +1 -0
  9. package/dist/browser/HttpBridgeConfig.d.cts +13 -0
  10. package/dist/browser/HttpBridgeConfig.d.cts.map +1 -0
  11. package/dist/browser/HttpBridgeConfig.d.mts +13 -0
  12. package/dist/browser/HttpBridgeConfig.d.mts.map +1 -0
  13. package/dist/browser/HttpBridgeConfig.d.ts +13 -0
  14. package/dist/browser/HttpBridgeConfig.d.ts.map +1 -0
  15. package/dist/browser/HttpBridgeModuleResolver.d.cts +14 -0
  16. package/dist/browser/HttpBridgeModuleResolver.d.cts.map +1 -0
  17. package/dist/browser/HttpBridgeModuleResolver.d.mts +14 -0
  18. package/dist/browser/HttpBridgeModuleResolver.d.mts.map +1 -0
  19. package/dist/browser/HttpBridgeModuleResolver.d.ts +14 -0
  20. package/dist/browser/HttpBridgeModuleResolver.d.ts.map +1 -0
  21. package/dist/browser/ModuleProxy/ModuleProxy.d.cts +21 -0
  22. package/dist/browser/ModuleProxy/ModuleProxy.d.cts.map +1 -0
  23. package/dist/browser/ModuleProxy/ModuleProxy.d.mts +21 -0
  24. package/dist/browser/ModuleProxy/ModuleProxy.d.mts.map +1 -0
  25. package/dist/browser/ModuleProxy/ModuleProxy.d.ts +21 -0
  26. package/dist/browser/ModuleProxy/ModuleProxy.d.ts.map +1 -0
  27. package/dist/browser/ModuleProxy/index.d.cts +2 -0
  28. package/dist/browser/ModuleProxy/index.d.cts.map +1 -0
  29. package/dist/browser/ModuleProxy/index.d.mts +2 -0
  30. package/dist/browser/ModuleProxy/index.d.mts.map +1 -0
  31. package/dist/browser/ModuleProxy/index.d.ts +2 -0
  32. package/dist/browser/ModuleProxy/index.d.ts.map +1 -0
  33. package/dist/browser/index.cjs +306 -0
  34. package/dist/browser/index.cjs.map +1 -0
  35. package/dist/browser/index.d.cts +3 -0
  36. package/dist/browser/index.d.cts.map +1 -0
  37. package/dist/browser/index.d.mts +3 -0
  38. package/dist/browser/index.d.mts.map +1 -0
  39. package/dist/browser/index.d.ts +3 -0
  40. package/dist/browser/index.d.ts.map +1 -0
  41. package/dist/browser/index.js +285 -0
  42. package/dist/browser/index.js.map +1 -0
  43. package/dist/neutral/HttpBridge.d.cts +43 -0
  44. package/dist/neutral/HttpBridge.d.cts.map +1 -0
  45. package/dist/neutral/HttpBridge.d.mts +43 -0
  46. package/dist/neutral/HttpBridge.d.mts.map +1 -0
  47. package/dist/neutral/HttpBridge.d.ts +43 -0
  48. package/dist/neutral/HttpBridge.d.ts.map +1 -0
  49. package/dist/neutral/HttpBridgeConfig.d.cts +13 -0
  50. package/dist/neutral/HttpBridgeConfig.d.cts.map +1 -0
  51. package/dist/neutral/HttpBridgeConfig.d.mts +13 -0
  52. package/dist/neutral/HttpBridgeConfig.d.mts.map +1 -0
  53. package/dist/neutral/HttpBridgeConfig.d.ts +13 -0
  54. package/dist/neutral/HttpBridgeConfig.d.ts.map +1 -0
  55. package/dist/neutral/HttpBridgeModuleResolver.d.cts +14 -0
  56. package/dist/neutral/HttpBridgeModuleResolver.d.cts.map +1 -0
  57. package/dist/neutral/HttpBridgeModuleResolver.d.mts +14 -0
  58. package/dist/neutral/HttpBridgeModuleResolver.d.mts.map +1 -0
  59. package/dist/neutral/HttpBridgeModuleResolver.d.ts +14 -0
  60. package/dist/neutral/HttpBridgeModuleResolver.d.ts.map +1 -0
  61. package/dist/neutral/ModuleProxy/ModuleProxy.d.cts +21 -0
  62. package/dist/neutral/ModuleProxy/ModuleProxy.d.cts.map +1 -0
  63. package/dist/neutral/ModuleProxy/ModuleProxy.d.mts +21 -0
  64. package/dist/neutral/ModuleProxy/ModuleProxy.d.mts.map +1 -0
  65. package/dist/neutral/ModuleProxy/ModuleProxy.d.ts +21 -0
  66. package/dist/neutral/ModuleProxy/ModuleProxy.d.ts.map +1 -0
  67. package/dist/neutral/ModuleProxy/index.d.cts +2 -0
  68. package/dist/neutral/ModuleProxy/index.d.cts.map +1 -0
  69. package/dist/neutral/ModuleProxy/index.d.mts +2 -0
  70. package/dist/neutral/ModuleProxy/index.d.mts.map +1 -0
  71. package/dist/neutral/ModuleProxy/index.d.ts +2 -0
  72. package/dist/neutral/ModuleProxy/index.d.ts.map +1 -0
  73. package/dist/neutral/index.cjs +306 -0
  74. package/dist/neutral/index.cjs.map +1 -0
  75. package/dist/neutral/index.d.cts +3 -0
  76. package/dist/neutral/index.d.cts.map +1 -0
  77. package/dist/neutral/index.d.mts +3 -0
  78. package/dist/neutral/index.d.mts.map +1 -0
  79. package/dist/neutral/index.d.ts +3 -0
  80. package/dist/neutral/index.d.ts.map +1 -0
  81. package/dist/neutral/index.js +285 -0
  82. package/dist/neutral/index.js.map +1 -0
  83. package/dist/node/HttpBridge.d.cts +43 -0
  84. package/dist/node/HttpBridge.d.cts.map +1 -0
  85. package/dist/node/HttpBridge.d.mts +43 -0
  86. package/dist/node/HttpBridge.d.mts.map +1 -0
  87. package/dist/node/HttpBridge.d.ts +43 -0
  88. package/dist/node/HttpBridge.d.ts.map +1 -0
  89. package/dist/node/HttpBridgeConfig.d.cts +13 -0
  90. package/dist/node/HttpBridgeConfig.d.cts.map +1 -0
  91. package/dist/node/HttpBridgeConfig.d.mts +13 -0
  92. package/dist/node/HttpBridgeConfig.d.mts.map +1 -0
  93. package/dist/node/HttpBridgeConfig.d.ts +13 -0
  94. package/dist/node/HttpBridgeConfig.d.ts.map +1 -0
  95. package/dist/node/HttpBridgeModuleResolver.d.cts +14 -0
  96. package/dist/node/HttpBridgeModuleResolver.d.cts.map +1 -0
  97. package/dist/node/HttpBridgeModuleResolver.d.mts +14 -0
  98. package/dist/node/HttpBridgeModuleResolver.d.mts.map +1 -0
  99. package/dist/node/HttpBridgeModuleResolver.d.ts +14 -0
  100. package/dist/node/HttpBridgeModuleResolver.d.ts.map +1 -0
  101. package/dist/node/ModuleProxy/ModuleProxy.d.cts +21 -0
  102. package/dist/node/ModuleProxy/ModuleProxy.d.cts.map +1 -0
  103. package/dist/node/ModuleProxy/ModuleProxy.d.mts +21 -0
  104. package/dist/node/ModuleProxy/ModuleProxy.d.mts.map +1 -0
  105. package/dist/node/ModuleProxy/ModuleProxy.d.ts +21 -0
  106. package/dist/node/ModuleProxy/ModuleProxy.d.ts.map +1 -0
  107. package/dist/node/ModuleProxy/index.d.cts +2 -0
  108. package/dist/node/ModuleProxy/index.d.cts.map +1 -0
  109. package/dist/node/ModuleProxy/index.d.mts +2 -0
  110. package/dist/node/ModuleProxy/index.d.mts.map +1 -0
  111. package/dist/node/ModuleProxy/index.d.ts +2 -0
  112. package/dist/node/ModuleProxy/index.d.ts.map +1 -0
  113. package/dist/node/index.cjs +324 -0
  114. package/dist/node/index.cjs.map +1 -0
  115. package/dist/node/index.d.cts +3 -0
  116. package/dist/node/index.d.cts.map +1 -0
  117. package/dist/node/index.d.mts +3 -0
  118. package/dist/node/index.d.mts.map +1 -0
  119. package/dist/node/index.d.ts +3 -0
  120. package/dist/node/index.d.ts.map +1 -0
  121. package/dist/node/index.js +298 -0
  122. package/dist/node/index.js.map +1 -0
  123. package/package.json +86 -0
  124. package/src/HttpBridge.ts +195 -0
  125. package/src/HttpBridgeConfig.ts +17 -0
  126. package/src/HttpBridgeModuleResolver.ts +88 -0
  127. package/src/ModuleProxy/ModuleProxy.ts +41 -0
  128. package/src/ModuleProxy/index.ts +1 -0
  129. package/src/index.ts +2 -0
  130. package/typedoc.json +5 -0
@@ -0,0 +1,298 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getProtoOf = Object.getPrototypeOf;
3
+ var __reflectGet = Reflect.get;
4
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
+ var __publicField = (obj, key, value) => {
7
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
8
+ return value;
9
+ };
10
+ var __superGet = (cls, obj, key) => __reflectGet(__getProtoOf(cls), key, obj);
11
+
12
+ // src/HttpBridge.ts
13
+ import { assertEx as assertEx2 } from "@xylabs/assert";
14
+ import { AxiosJson } from "@xylabs/axios";
15
+ import { exists } from "@xylabs/exists";
16
+ import { toJsonString } from "@xylabs/object";
17
+ import { AbstractBridge } from "@xyo-network/abstract-bridge";
18
+ import { NodeManifestPayloadSchema } from "@xyo-network/manifest-model";
19
+ import { creatableModule, ModuleStateQuerySchema } from "@xyo-network/module-model";
20
+ import { asAttachableNodeInstance } from "@xyo-network/node-model";
21
+ import { isPayloadOfSchemaType } from "@xyo-network/payload-model";
22
+ import { Mutex, Semaphore } from "async-mutex";
23
+ import { LRUCache } from "lru-cache";
24
+
25
+ // src/HttpBridgeConfig.ts
26
+ var HttpBridgeConfigSchema = "network.xyo.bridge.http.config";
27
+
28
+ // src/HttpBridgeModuleResolver.ts
29
+ import { assertEx } from "@xylabs/assert";
30
+ import { isAddress } from "@xylabs/hex";
31
+ import { AbstractBridgeModuleResolver, wrapModuleWithType } from "@xyo-network/abstract-bridge";
32
+ import { Account } from "@xyo-network/account";
33
+ import { ConfigSchema } from "@xyo-network/config-payload-plugin";
34
+ import { asModuleInstance, ModuleConfigSchema, ResolveHelper } from "@xyo-network/module-model";
35
+
36
+ // src/ModuleProxy/ModuleProxy.ts
37
+ import { AbstractModuleProxy } from "@xyo-network/abstract-bridge";
38
+ var _HttpModuleProxy = class _HttpModuleProxy extends AbstractModuleProxy {
39
+ constructor(params) {
40
+ _HttpModuleProxy.createCount = _HttpModuleProxy.createCount + 1;
41
+ if (Math.floor(_HttpModuleProxy.createCount / 10) === _HttpModuleProxy.createCount / 10) {
42
+ console.log(`HttpModuleProxy.createCount: ${_HttpModuleProxy.createCount}`);
43
+ }
44
+ super(params);
45
+ }
46
+ async proxyQueryHandler(query, payloads = []) {
47
+ return await this.params.querySender.sendBridgeQuery(this.params.moduleAddress, query, payloads);
48
+ }
49
+ };
50
+ __name(_HttpModuleProxy, "HttpModuleProxy");
51
+ __publicField(_HttpModuleProxy, "createCount", 0);
52
+ var HttpModuleProxy = _HttpModuleProxy;
53
+
54
+ // src/HttpBridgeModuleResolver.ts
55
+ var _HttpBridgeModuleResolver = class _HttpBridgeModuleResolver extends AbstractBridgeModuleResolver {
56
+ get querySender() {
57
+ return this.params.querySender;
58
+ }
59
+ moduleUrl(address) {
60
+ return new URL(address, this.params.rootUrl);
61
+ }
62
+ async resolveHandler(id, options) {
63
+ var _a, _b;
64
+ const parentResult = await super.resolveHandler(id, options);
65
+ if (parentResult.length > 0) {
66
+ return parentResult;
67
+ }
68
+ if (id === "*") {
69
+ return [];
70
+ }
71
+ const idParts = id.split(":");
72
+ const untransformedFirstPart = assertEx(idParts.shift(), () => `Invalid module identifier: ${id}`);
73
+ const firstPart = await ResolveHelper.transformModuleIdentifier(untransformedFirstPart);
74
+ const moduleAddress = firstPart;
75
+ assertEx(isAddress(firstPart), () => `Invalid module address: ${firstPart}`);
76
+ const remainderParts = idParts.join(":");
77
+ const params = {
78
+ account: Account.randomSync(),
79
+ archiving: this.params.archiving,
80
+ config: {
81
+ schema: ModuleConfigSchema
82
+ },
83
+ host: this,
84
+ moduleAddress,
85
+ querySender: this.querySender
86
+ };
87
+ (_a = this.logger) == null ? void 0 : _a.debug(`creating HttpProxy [${moduleAddress}] ${id}`);
88
+ const proxy = new HttpModuleProxy(params);
89
+ if (proxy) {
90
+ const state = await proxy.state();
91
+ if (state) {
92
+ const configSchema = (_b = state.find((payload) => payload.schema === ConfigSchema)) == null ? void 0 : _b.config;
93
+ const config = assertEx(state.find((payload) => payload.schema === configSchema), () => "Unable to locate config");
94
+ proxy.setConfig(config);
95
+ }
96
+ }
97
+ await proxy.start();
98
+ const wrapped = assertEx(wrapModuleWithType(proxy, Account.randomSync()), () => `Failed to wrapModuleWithType [${id}]`);
99
+ const instance = assertEx(asModuleInstance(wrapped, {}), () => `Failed to asModuleInstance [${id}]`);
100
+ proxy.upResolver.add(instance);
101
+ proxy.downResolver.add(instance);
102
+ if (remainderParts.length > 0) {
103
+ const result = await wrapped.resolve(remainderParts, options);
104
+ return result ? [
105
+ result
106
+ ] : [];
107
+ }
108
+ return [
109
+ instance
110
+ ];
111
+ }
112
+ };
113
+ __name(_HttpBridgeModuleResolver, "HttpBridgeModuleResolver");
114
+ var HttpBridgeModuleResolver = _HttpBridgeModuleResolver;
115
+
116
+ // src/HttpBridge.ts
117
+ function _ts_decorate(decorators, target, key, desc) {
118
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
119
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
120
+ r = Reflect.decorate(decorators, target, key, desc);
121
+ else
122
+ for (var i = decorators.length - 1; i >= 0; i--)
123
+ if (d = decorators[i])
124
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
125
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
126
+ }
127
+ __name(_ts_decorate, "_ts_decorate");
128
+ var _HttpBridge = class _HttpBridge extends AbstractBridge {
129
+ _axios;
130
+ _discoverRootsMutex = new Mutex();
131
+ _failureTimeCache = new LRUCache({
132
+ max: _HttpBridge.maxFailureCacheSize
133
+ });
134
+ _querySemaphore;
135
+ _resolver;
136
+ get axios() {
137
+ this._axios = this._axios ?? new AxiosJson();
138
+ return this._axios;
139
+ }
140
+ get failureRetryTime() {
141
+ return this.config.failureRetryTime ?? _HttpBridge.defaultFailureRetryTime;
142
+ }
143
+ get maxConnections() {
144
+ return this.config.maxConnections ?? _HttpBridge.defaultMaxConnections;
145
+ }
146
+ get maxPayloadSizeWarning() {
147
+ return this.config.maxPayloadSizeWarning ?? _HttpBridge.defaultMaxPayloadSizeWarning;
148
+ }
149
+ get nodeUrl() {
150
+ return assertEx2(this.config.nodeUrl, () => "No Url Set");
151
+ }
152
+ get querySemaphore() {
153
+ this._querySemaphore = this._querySemaphore ?? new Semaphore(this.maxConnections);
154
+ return this._querySemaphore;
155
+ }
156
+ get resolver() {
157
+ this._resolver = this._resolver ?? new HttpBridgeModuleResolver({
158
+ archiving: {
159
+ ...this.archiving,
160
+ resolveArchivists: this.resolveArchivingArchivists.bind(this)
161
+ },
162
+ bridge: this,
163
+ querySender: this,
164
+ root: this,
165
+ rootUrl: this.nodeUrl,
166
+ wrapperAccount: this.account
167
+ });
168
+ return this._resolver;
169
+ }
170
+ exposeHandler(_id, _options) {
171
+ throw new Error("Unsupported");
172
+ }
173
+ exposedHandler() {
174
+ throw new Error("Unsupported");
175
+ }
176
+ async getRoots(force) {
177
+ return await this._discoverRootsMutex.runExclusive(async () => {
178
+ var _a, _b;
179
+ if (this._roots === void 0 || force) {
180
+ const state = await this.getRootState();
181
+ (_a = this.logger) == null ? void 0 : _a.debug(`HttpBridge:discoverRoots.state [${state == null ? void 0 : state.length}]`);
182
+ const nodeManifest = state == null ? void 0 : state.find(isPayloadOfSchemaType(NodeManifestPayloadSchema));
183
+ if (nodeManifest) {
184
+ const mods = (await this.resolveRootNode(nodeManifest)).filter(exists);
185
+ (_b = this.logger) == null ? void 0 : _b.debug(`HttpBridge:discoverRoots [${mods.length}]`);
186
+ this._roots = mods;
187
+ } else {
188
+ this._roots = [];
189
+ }
190
+ }
191
+ return this._roots;
192
+ });
193
+ }
194
+ moduleUrl(address) {
195
+ return new URL(address, this.nodeUrl);
196
+ }
197
+ async sendBridgeQuery(targetAddress, query, payloads) {
198
+ var _a, _b, _c, _d;
199
+ const lastFailureTime = this._failureTimeCache.get(targetAddress);
200
+ if (lastFailureTime !== void 0) {
201
+ const now = Date.now();
202
+ const timeSincePreviousFailure = now - lastFailureTime;
203
+ if (timeSincePreviousFailure > this.failureRetryTime) {
204
+ throw new Error(`target module failed recently [${targetAddress}] [${timeSincePreviousFailure}ms ago]`);
205
+ }
206
+ this._failureTimeCache.delete(targetAddress);
207
+ }
208
+ try {
209
+ await this.querySemaphore.acquire();
210
+ const payloadSize = JSON.stringify([
211
+ query,
212
+ payloads
213
+ ]).length;
214
+ if (payloadSize > this.maxPayloadSizeWarning) {
215
+ (_a = this.logger) == null ? void 0 : _a.warn(`Large targetQuery being sent: ${payloadSize} bytes [${this.address}][${this.moduleAddress}] [${query.schema}] [${payloads == null ? void 0 : payloads.length}]`);
216
+ }
217
+ const moduleUrl = this.moduleUrl(targetAddress).href;
218
+ const result = await this.axios.post(moduleUrl, [
219
+ query,
220
+ payloads
221
+ ]);
222
+ if (result.status === 404) {
223
+ throw `target module not found [${moduleUrl}] [${result.status}]`;
224
+ }
225
+ if (result.status >= 400) {
226
+ (_b = this.logger) == null ? void 0 : _b.error(`targetQuery failed [${moduleUrl}]`);
227
+ throw `targetQuery failed [${moduleUrl}] [${result.status}]`;
228
+ }
229
+ return (_c = result.data) == null ? void 0 : _c.data;
230
+ } catch (ex) {
231
+ const error = ex;
232
+ (_d = this.logger) == null ? void 0 : _d.error(`Error: ${toJsonString(error)}`);
233
+ throw error;
234
+ } finally {
235
+ this.querySemaphore.release();
236
+ }
237
+ }
238
+ unexposeHandler(_id, _options) {
239
+ throw new Error("Unsupported");
240
+ }
241
+ async getRootState() {
242
+ var _a;
243
+ const queryPayload = {
244
+ schema: ModuleStateQuerySchema
245
+ };
246
+ const boundQuery = await this.bindQuery(queryPayload);
247
+ try {
248
+ const response = await this.axios.post(this.nodeUrl.toString(), boundQuery);
249
+ if (response.status === 404) {
250
+ return [];
251
+ }
252
+ const [, payloads, errors] = response.data.data;
253
+ if (errors.length > 0) {
254
+ throw new Error(`getRootState failed: ${JSON.stringify(errors, null, 2)}`);
255
+ }
256
+ return payloads;
257
+ } catch (ex) {
258
+ const error = ex;
259
+ (_a = this.logger) == null ? void 0 : _a.warn(`Unable to connect to remote node: ${error.message} [${this.nodeUrl}]`);
260
+ }
261
+ }
262
+ async resolveRootNode(nodeManifest) {
263
+ var _a;
264
+ const rootModule = assertEx2((await this.resolver.resolveHandler(assertEx2((_a = nodeManifest.status) == null ? void 0 : _a.address, () => "Root has no address"))).at(0), () => {
265
+ var _a2;
266
+ return `Root not found [${(_a2 = nodeManifest.status) == null ? void 0 : _a2.address}]`;
267
+ });
268
+ assertEx2(rootModule.constructor.name !== "HttpModuleProxy", () => "rootModule is not a Wrapper");
269
+ const rootNode = asAttachableNodeInstance(rootModule, "Root modules is not a node");
270
+ if (rootNode) {
271
+ this.logger.debug(`rootNode: ${rootNode.id}`);
272
+ this.downResolver.addResolver(rootNode);
273
+ return [
274
+ rootNode
275
+ ];
276
+ }
277
+ return [];
278
+ }
279
+ };
280
+ __name(_HttpBridge, "HttpBridge");
281
+ __publicField(_HttpBridge, "configSchemas", [
282
+ ...__superGet(_HttpBridge, _HttpBridge, "configSchemas"),
283
+ HttpBridgeConfigSchema
284
+ ]);
285
+ __publicField(_HttpBridge, "defaultConfigSchema", HttpBridgeConfigSchema);
286
+ __publicField(_HttpBridge, "defaultFailureRetryTime", 1e3 * 60);
287
+ __publicField(_HttpBridge, "defaultMaxConnections", 4);
288
+ __publicField(_HttpBridge, "defaultMaxPayloadSizeWarning", 256 * 256);
289
+ __publicField(_HttpBridge, "maxFailureCacheSize", 1e3);
290
+ var HttpBridge = _HttpBridge;
291
+ HttpBridge = _ts_decorate([
292
+ creatableModule()
293
+ ], HttpBridge);
294
+ export {
295
+ HttpBridge,
296
+ HttpBridgeConfigSchema
297
+ };
298
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/HttpBridge.ts","../../src/HttpBridgeConfig.ts","../../src/HttpBridgeModuleResolver.ts","../../src/ModuleProxy/ModuleProxy.ts"],"sourcesContent":["import { assertEx } from '@xylabs/assert'\nimport { AxiosError, AxiosJson } from '@xylabs/axios'\nimport { exists } from '@xylabs/exists'\nimport { Address } from '@xylabs/hex'\nimport { toJsonString } from '@xylabs/object'\nimport { Promisable } from '@xylabs/promise'\nimport { AbstractBridge } from '@xyo-network/abstract-bridge'\nimport { ApiEnvelope } from '@xyo-network/api-models'\nimport { QueryBoundWitness } from '@xyo-network/boundwitness-model'\nimport { BridgeExposeOptions, BridgeModule, BridgeParams, BridgeUnexposeOptions } from '@xyo-network/bridge-model'\nimport { NodeManifestPayload, NodeManifestPayloadSchema } from '@xyo-network/manifest-model'\nimport {\n AnyConfigSchema,\n creatableModule,\n ModuleInstance,\n ModuleQueryResult,\n ModuleResolverInstance,\n ModuleStateQuery,\n ModuleStateQuerySchema,\n} from '@xyo-network/module-model'\nimport { asAttachableNodeInstance } from '@xyo-network/node-model'\nimport { isPayloadOfSchemaType, Payload, Schema, WithMeta } from '@xyo-network/payload-model'\nimport { Mutex, Semaphore } from 'async-mutex'\nimport { LRUCache } from 'lru-cache'\n\nimport { HttpBridgeConfig, HttpBridgeConfigSchema } from './HttpBridgeConfig'\nimport { HttpBridgeModuleResolver } from './HttpBridgeModuleResolver'\nimport { BridgeQuerySender } from './ModuleProxy'\n\nexport interface HttpBridgeParams extends BridgeParams<AnyConfigSchema<HttpBridgeConfig>> {}\n\n@creatableModule()\nexport class HttpBridge<TParams extends HttpBridgeParams> extends AbstractBridge<TParams> implements BridgeModule<TParams>, BridgeQuerySender {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, HttpBridgeConfigSchema]\n static override readonly defaultConfigSchema: Schema = HttpBridgeConfigSchema\n static defaultFailureRetryTime = 1000 * 60\n static defaultMaxConnections = 4\n static defaultMaxPayloadSizeWarning = 256 * 256\n static maxFailureCacheSize = 1000\n\n private _axios?: AxiosJson\n private _discoverRootsMutex = new Mutex()\n private _failureTimeCache = new LRUCache<Address, number>({ max: HttpBridge.maxFailureCacheSize })\n private _querySemaphore?: Semaphore\n private _resolver?: HttpBridgeModuleResolver\n\n get axios() {\n this._axios = this._axios ?? new AxiosJson()\n return this._axios\n }\n\n get failureRetryTime() {\n return this.config.failureRetryTime ?? HttpBridge.defaultFailureRetryTime\n }\n\n get maxConnections() {\n return this.config.maxConnections ?? HttpBridge.defaultMaxConnections\n }\n\n get maxPayloadSizeWarning() {\n return this.config.maxPayloadSizeWarning ?? HttpBridge.defaultMaxPayloadSizeWarning\n }\n\n get nodeUrl() {\n return assertEx(this.config.nodeUrl, () => 'No Url Set')\n }\n\n get querySemaphore() {\n this._querySemaphore = this._querySemaphore ?? new Semaphore(this.maxConnections)\n return this._querySemaphore\n }\n\n override get resolver() {\n this._resolver =\n this._resolver ??\n new HttpBridgeModuleResolver({\n archiving: { ...this.archiving, resolveArchivists: this.resolveArchivingArchivists.bind(this) },\n bridge: this,\n querySender: this,\n root: this,\n rootUrl: this.nodeUrl,\n wrapperAccount: this.account,\n })\n return this._resolver\n }\n\n override exposeHandler(_id: string, _options?: BridgeExposeOptions | undefined): Promisable<ModuleInstance[]> {\n throw new Error('Unsupported')\n }\n\n override exposedHandler(): Promisable<Address[]> {\n throw new Error('Unsupported')\n }\n\n async getRoots(force?: boolean): Promise<ModuleInstance[]> {\n return await this._discoverRootsMutex.runExclusive(async () => {\n if (this._roots === undefined || force) {\n const state = await this.getRootState()\n this.logger?.debug(`HttpBridge:discoverRoots.state [${state?.length}]`)\n const nodeManifest = state?.find(isPayloadOfSchemaType<WithMeta<NodeManifestPayload>>(NodeManifestPayloadSchema))\n if (nodeManifest) {\n const mods = (await this.resolveRootNode(nodeManifest)).filter(exists)\n this.logger?.debug(`HttpBridge:discoverRoots [${mods.length}]`)\n this._roots = mods\n } else {\n this._roots = []\n }\n }\n return this._roots\n })\n }\n\n moduleUrl(address: Address) {\n return new URL(address, this.nodeUrl)\n }\n\n async sendBridgeQuery<TOut extends Payload = Payload, TQuery extends QueryBoundWitness = QueryBoundWitness, TIn extends Payload = Payload>(\n targetAddress: Address,\n query: TQuery,\n payloads?: TIn[],\n ): Promise<ModuleQueryResult<TOut>> {\n const lastFailureTime = this._failureTimeCache.get(targetAddress)\n if (lastFailureTime !== undefined) {\n const now = Date.now()\n const timeSincePreviousFailure = now - lastFailureTime\n if (timeSincePreviousFailure > this.failureRetryTime) {\n throw new Error(`target module failed recently [${targetAddress}] [${timeSincePreviousFailure}ms ago]`)\n }\n this._failureTimeCache.delete(targetAddress)\n }\n try {\n await this.querySemaphore.acquire()\n const payloadSize = JSON.stringify([query, payloads]).length\n if (payloadSize > this.maxPayloadSizeWarning) {\n this.logger?.warn(\n `Large targetQuery being sent: ${payloadSize} bytes [${this.address}][${this.moduleAddress}] [${query.schema}] [${payloads?.length}]`,\n )\n }\n const moduleUrl = this.moduleUrl(targetAddress).href\n const result = await this.axios.post<ApiEnvelope<ModuleQueryResult<TOut>>>(moduleUrl, [query, payloads])\n if (result.status === 404) {\n throw `target module not found [${moduleUrl}] [${result.status}]`\n }\n if (result.status >= 400) {\n this.logger?.error(`targetQuery failed [${moduleUrl}]`)\n throw `targetQuery failed [${moduleUrl}] [${result.status}]`\n }\n return result.data?.data\n } catch (ex) {\n const error = ex as AxiosError\n this.logger?.error(`Error: ${toJsonString(error)}`)\n throw error\n } finally {\n this.querySemaphore.release()\n }\n }\n\n override unexposeHandler(_id: string, _options?: BridgeUnexposeOptions | undefined): Promisable<ModuleInstance[]> {\n throw new Error('Unsupported')\n }\n\n private async getRootState() {\n const queryPayload: ModuleStateQuery = { schema: ModuleStateQuerySchema }\n const boundQuery = await this.bindQuery(queryPayload)\n try {\n const response = await this.axios.post<ApiEnvelope<ModuleQueryResult>>(this.nodeUrl.toString(), boundQuery)\n if (response.status === 404) {\n return []\n }\n const [, payloads, errors] = response.data.data\n if (errors.length > 0) {\n throw new Error(`getRootState failed: ${JSON.stringify(errors, null, 2)}`)\n }\n return payloads\n } catch (ex) {\n const error = ex as Error\n this.logger?.warn(`Unable to connect to remote node: ${error.message} [${this.nodeUrl}]`)\n }\n }\n\n private async resolveRootNode(nodeManifest: NodeManifestPayload): Promise<ModuleInstance[]> {\n const rootModule = assertEx(\n (await this.resolver.resolveHandler(assertEx(nodeManifest.status?.address, () => 'Root has no address'))).at(0),\n () => `Root not found [${nodeManifest.status?.address}]`,\n )\n assertEx(rootModule.constructor.name !== 'HttpModuleProxy', () => 'rootModule is not a Wrapper')\n const rootNode = asAttachableNodeInstance(rootModule, 'Root modules is not a node')\n if (rootNode) {\n this.logger.debug(`rootNode: ${rootNode.id}`)\n this.downResolver.addResolver(rootNode as unknown as ModuleResolverInstance)\n return [rootNode]\n }\n return []\n }\n}\n","import { EmptyObject } from '@xylabs/object'\nimport { BridgeConfig } from '@xyo-network/bridge-model'\n\nexport type HttpBridgeConfigSchema = 'network.xyo.bridge.http.config'\nexport const HttpBridgeConfigSchema: HttpBridgeConfigSchema = 'network.xyo.bridge.http.config'\n\nexport type HttpBridgeConfig<TConfig extends EmptyObject = EmptyObject, TSchema extends string | void = void> = BridgeConfig<\n {\n failureRetryTime?: number\n failureTimeCacheMax?: number\n maxConnections?: number\n maxPayloadSizeWarning?: number\n nodeUrl?: string\n schema: HttpBridgeConfigSchema\n } & TConfig,\n TSchema extends string ? TSchema : HttpBridgeConfigSchema\n>\n","import { assertEx } from '@xylabs/assert'\nimport { Address, isAddress } from '@xylabs/hex'\nimport { AbstractBridgeModuleResolver, BridgeModuleResolverParams, wrapModuleWithType } from '@xyo-network/abstract-bridge'\nimport { Account } from '@xyo-network/account'\nimport { ConfigPayload, ConfigSchema } from '@xyo-network/config-payload-plugin'\nimport {\n asModuleInstance,\n ModuleConfig,\n ModuleConfigSchema,\n ModuleFilterOptions,\n ModuleIdentifier,\n ModuleInstance,\n ResolveHelper,\n} from '@xyo-network/module-model'\n\nimport { BridgeQuerySender, HttpModuleProxy, HttpModuleProxyParams } from './ModuleProxy'\n\nexport interface HttpBridgeModuleResolverParams extends BridgeModuleResolverParams {\n querySender: BridgeQuerySender\n rootUrl: string\n}\n\nexport class HttpBridgeModuleResolver<\n T extends HttpBridgeModuleResolverParams = HttpBridgeModuleResolverParams,\n> extends AbstractBridgeModuleResolver<T> {\n get querySender() {\n return this.params.querySender\n }\n\n moduleUrl(address: Address) {\n return new URL(address, this.params.rootUrl)\n }\n\n override async resolveHandler<T extends ModuleInstance = ModuleInstance>(id: ModuleIdentifier, options?: ModuleFilterOptions<T>): Promise<T[]> {\n const parentResult = await super.resolveHandler(id, options)\n if (parentResult.length > 0) {\n return parentResult\n }\n if (id === '*') {\n return []\n }\n const idParts = id.split(':')\n const untransformedFirstPart = assertEx(idParts.shift(), () => `Invalid module identifier: ${id}`)\n const firstPart = await ResolveHelper.transformModuleIdentifier(untransformedFirstPart)\n const moduleAddress = firstPart as Address\n assertEx(isAddress(firstPart), () => `Invalid module address: ${firstPart}`)\n const remainderParts = idParts.join(':')\n const params: HttpModuleProxyParams = {\n account: Account.randomSync(),\n archiving: this.params.archiving,\n config: { schema: ModuleConfigSchema },\n host: this,\n moduleAddress,\n querySender: this.querySender,\n }\n\n this.logger?.debug(`creating HttpProxy [${moduleAddress}] ${id}`)\n\n const proxy = new HttpModuleProxy<T, HttpModuleProxyParams>(params)\n //calling state here to get the config\n if (proxy) {\n const state = await proxy.state()\n if (state) {\n const configSchema = (state.find((payload) => payload.schema === ConfigSchema) as ConfigPayload | undefined)?.config\n const config = assertEx(\n state.find((payload) => payload.schema === configSchema),\n () => 'Unable to locate config',\n ) as ModuleConfig\n proxy.setConfig(config)\n }\n }\n\n await proxy.start()\n\n const wrapped = assertEx(wrapModuleWithType(proxy, Account.randomSync()) as unknown as T, () => `Failed to wrapModuleWithType [${id}]`)\n const instance = assertEx(asModuleInstance<T>(wrapped, {}), () => `Failed to asModuleInstance [${id}]`)\n proxy.upResolver.add(instance)\n proxy.downResolver.add(instance)\n\n if (remainderParts.length > 0) {\n const result = await wrapped.resolve<T>(remainderParts, options)\n return result ? [result] : []\n }\n\n //console.log(`resolved: ${proxy.address} [${wrapped.constructor.name}] [${as.constructor.name}]`)\n return [instance]\n }\n}\n","import { Address } from '@xylabs/hex'\nimport { AbstractModuleProxy, ModuleProxyParams } from '@xyo-network/abstract-bridge'\nimport { QueryBoundWitness } from '@xyo-network/boundwitness-model'\nimport { AttachableModuleInstance, ModuleInstance, ModuleQueryResult } from '@xyo-network/module-model'\nimport { Payload } from '@xyo-network/payload-model'\n\nexport interface BridgeQuerySender {\n sendBridgeQuery: <TOut extends Payload = Payload, TQuery extends QueryBoundWitness = QueryBoundWitness, TIn extends Payload = Payload>(\n targetAddress: Address,\n query: TQuery,\n payloads?: TIn[],\n ) => Promise<ModuleQueryResult<TOut>>\n}\n\nexport type HttpModuleProxyParams = ModuleProxyParams & {\n querySender: BridgeQuerySender\n}\n\nexport class HttpModuleProxy<\n TWrappedModule extends ModuleInstance = ModuleInstance,\n TParams extends Omit<HttpModuleProxyParams, 'config'> & { config: TWrappedModule['config'] } = Omit<HttpModuleProxyParams, 'config'> & {\n config: TWrappedModule['config']\n },\n >\n extends AbstractModuleProxy<TWrappedModule, TParams>\n implements AttachableModuleInstance<TParams, TWrappedModule['eventData']>\n{\n static createCount = 0\n\n constructor(params: TParams) {\n HttpModuleProxy.createCount = HttpModuleProxy.createCount + 1\n if (Math.floor(HttpModuleProxy.createCount / 10) === HttpModuleProxy.createCount / 10) {\n console.log(`HttpModuleProxy.createCount: ${HttpModuleProxy.createCount}`)\n }\n super(params)\n }\n\n async proxyQueryHandler<T extends QueryBoundWitness = QueryBoundWitness>(query: T, payloads: Payload[] = []): Promise<ModuleQueryResult> {\n return await this.params.querySender.sendBridgeQuery(this.params.moduleAddress, query, payloads)\n }\n}\n"],"mappings":"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","names":["assertEx","AxiosJson","exists","toJsonString","AbstractBridge","NodeManifestPayloadSchema","creatableModule","ModuleStateQuerySchema","asAttachableNodeInstance","isPayloadOfSchemaType","Mutex","Semaphore","LRUCache","HttpBridgeConfigSchema","assertEx","isAddress","AbstractBridgeModuleResolver","wrapModuleWithType","Account","ConfigSchema","asModuleInstance","ModuleConfigSchema","ResolveHelper","AbstractModuleProxy","HttpModuleProxy","AbstractModuleProxy","constructor","params","createCount","Math","floor","console","log","proxyQueryHandler","query","payloads","querySender","sendBridgeQuery","moduleAddress","HttpBridgeModuleResolver","AbstractBridgeModuleResolver","querySender","params","moduleUrl","address","URL","rootUrl","resolveHandler","id","options","parentResult","length","idParts","split","untransformedFirstPart","assertEx","shift","firstPart","ResolveHelper","transformModuleIdentifier","moduleAddress","isAddress","remainderParts","join","account","Account","randomSync","archiving","config","schema","ModuleConfigSchema","host","logger","debug","proxy","HttpModuleProxy","state","configSchema","find","payload","ConfigSchema","setConfig","start","wrapped","wrapModuleWithType","instance","asModuleInstance","upResolver","add","downResolver","result","resolve","HttpBridge","AbstractBridge","_axios","_discoverRootsMutex","Mutex","_failureTimeCache","LRUCache","max","maxFailureCacheSize","_querySemaphore","_resolver","axios","AxiosJson","failureRetryTime","config","defaultFailureRetryTime","maxConnections","defaultMaxConnections","maxPayloadSizeWarning","defaultMaxPayloadSizeWarning","nodeUrl","assertEx","querySemaphore","Semaphore","resolver","HttpBridgeModuleResolver","archiving","resolveArchivists","resolveArchivingArchivists","bind","bridge","querySender","root","rootUrl","wrapperAccount","account","exposeHandler","_id","_options","Error","exposedHandler","getRoots","force","runExclusive","_roots","undefined","state","getRootState","logger","debug","length","nodeManifest","find","isPayloadOfSchemaType","NodeManifestPayloadSchema","mods","resolveRootNode","filter","exists","moduleUrl","address","URL","sendBridgeQuery","targetAddress","query","payloads","lastFailureTime","get","now","Date","timeSincePreviousFailure","delete","acquire","payloadSize","JSON","stringify","warn","moduleAddress","schema","href","result","post","status","error","data","ex","toJsonString","release","unexposeHandler","queryPayload","ModuleStateQuerySchema","boundQuery","bindQuery","response","toString","errors","message","rootModule","resolveHandler","at","constructor","name","rootNode","asAttachableNodeInstance","id","downResolver","addResolver","configSchemas","HttpBridgeConfigSchema","defaultConfigSchema","creatableModule"]}
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@xyo-network/bridge-http",
3
+ "author": {
4
+ "email": "support@xyo.network",
5
+ "name": "XYO Development Team",
6
+ "url": "https://xyo.network"
7
+ },
8
+ "bugs": {
9
+ "email": "support@xyo.network",
10
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js/issues"
11
+ },
12
+ "dependencies": {
13
+ "@xylabs/assert": "^3.3.3",
14
+ "@xylabs/axios": "^3.3.3",
15
+ "@xylabs/exists": "^3.3.3",
16
+ "@xylabs/hex": "^3.3.3",
17
+ "@xylabs/object": "^3.3.3",
18
+ "@xylabs/promise": "^3.3.3",
19
+ "@xyo-network/abstract-bridge": "~2.102.0",
20
+ "@xyo-network/account": "~2.102.0",
21
+ "@xyo-network/api-models": "~2.102.0",
22
+ "@xyo-network/boundwitness-model": "~2.102.0",
23
+ "@xyo-network/bridge-model": "~2.102.0",
24
+ "@xyo-network/config-payload-plugin": "~2.102.0",
25
+ "@xyo-network/manifest-model": "~2.102.0",
26
+ "@xyo-network/module-model": "~2.102.0",
27
+ "@xyo-network/node-model": "~2.102.0",
28
+ "@xyo-network/payload-model": "~2.102.0",
29
+ "async-mutex": "^0.5.0",
30
+ "lru-cache": "^10.2.2"
31
+ },
32
+ "devDependencies": {
33
+ "@xylabs/ts-scripts-yarn3": "^3.10.4",
34
+ "@xylabs/tsconfig": "^3.10.4",
35
+ "@xyo-network/account": "~2.102.0",
36
+ "@xyo-network/archivist-model": "~2.102.0",
37
+ "@xyo-network/diviner-model": "~2.102.0",
38
+ "@xyo-network/module-resolver": "~2.102.0",
39
+ "@xyo-network/node-memory": "~2.102.0",
40
+ "@xyo-network/node-model": "~2.102.0",
41
+ "@xyo-network/payload-builder": "~2.102.0",
42
+ "@xyo-network/payload-wrapper": "~2.102.0",
43
+ "typescript": "^5.4.5"
44
+ },
45
+ "description": "Primary SDK for using XYO Protocol 2.0",
46
+ "types": "dist/node/index.d.ts",
47
+ "exports": {
48
+ ".": {
49
+ "browser": {
50
+ "require": {
51
+ "types": "./dist/browser/index.d.cts",
52
+ "default": "./dist/browser/index.cjs"
53
+ },
54
+ "import": {
55
+ "types": "./dist/browser/index.d.mts",
56
+ "default": "./dist/browser/index.js"
57
+ }
58
+ },
59
+ "node": {
60
+ "require": {
61
+ "types": "./dist/node/index.d.cts",
62
+ "default": "./dist/node/index.cjs"
63
+ },
64
+ "import": {
65
+ "types": "./dist/node/index.d.mts",
66
+ "default": "./dist/node/index.js"
67
+ }
68
+ }
69
+ },
70
+ "./package.json": "./package.json"
71
+ },
72
+ "main": "dist/node/index.cjs",
73
+ "module": "dist/node/index.js",
74
+ "homepage": "https://xyo.network",
75
+ "license": "LGPL-3.0-only",
76
+ "publishConfig": {
77
+ "access": "public"
78
+ },
79
+ "repository": {
80
+ "type": "git",
81
+ "url": "https://github.com/XYOracleNetwork/sdk-xyo-client-js.git"
82
+ },
83
+ "sideEffects": false,
84
+ "version": "2.102.0",
85
+ "type": "module"
86
+ }
@@ -0,0 +1,195 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { AxiosError, AxiosJson } from '@xylabs/axios'
3
+ import { exists } from '@xylabs/exists'
4
+ import { Address } from '@xylabs/hex'
5
+ import { toJsonString } from '@xylabs/object'
6
+ import { Promisable } from '@xylabs/promise'
7
+ import { AbstractBridge } from '@xyo-network/abstract-bridge'
8
+ import { ApiEnvelope } from '@xyo-network/api-models'
9
+ import { QueryBoundWitness } from '@xyo-network/boundwitness-model'
10
+ import { BridgeExposeOptions, BridgeModule, BridgeParams, BridgeUnexposeOptions } from '@xyo-network/bridge-model'
11
+ import { NodeManifestPayload, NodeManifestPayloadSchema } from '@xyo-network/manifest-model'
12
+ import {
13
+ AnyConfigSchema,
14
+ creatableModule,
15
+ ModuleInstance,
16
+ ModuleQueryResult,
17
+ ModuleResolverInstance,
18
+ ModuleStateQuery,
19
+ ModuleStateQuerySchema,
20
+ } from '@xyo-network/module-model'
21
+ import { asAttachableNodeInstance } from '@xyo-network/node-model'
22
+ import { isPayloadOfSchemaType, Payload, Schema, WithMeta } from '@xyo-network/payload-model'
23
+ import { Mutex, Semaphore } from 'async-mutex'
24
+ import { LRUCache } from 'lru-cache'
25
+
26
+ import { HttpBridgeConfig, HttpBridgeConfigSchema } from './HttpBridgeConfig'
27
+ import { HttpBridgeModuleResolver } from './HttpBridgeModuleResolver'
28
+ import { BridgeQuerySender } from './ModuleProxy'
29
+
30
+ export interface HttpBridgeParams extends BridgeParams<AnyConfigSchema<HttpBridgeConfig>> {}
31
+
32
+ @creatableModule()
33
+ export class HttpBridge<TParams extends HttpBridgeParams> extends AbstractBridge<TParams> implements BridgeModule<TParams>, BridgeQuerySender {
34
+ static override readonly configSchemas: Schema[] = [...super.configSchemas, HttpBridgeConfigSchema]
35
+ static override readonly defaultConfigSchema: Schema = HttpBridgeConfigSchema
36
+ static defaultFailureRetryTime = 1000 * 60
37
+ static defaultMaxConnections = 4
38
+ static defaultMaxPayloadSizeWarning = 256 * 256
39
+ static maxFailureCacheSize = 1000
40
+
41
+ private _axios?: AxiosJson
42
+ private _discoverRootsMutex = new Mutex()
43
+ private _failureTimeCache = new LRUCache<Address, number>({ max: HttpBridge.maxFailureCacheSize })
44
+ private _querySemaphore?: Semaphore
45
+ private _resolver?: HttpBridgeModuleResolver
46
+
47
+ get axios() {
48
+ this._axios = this._axios ?? new AxiosJson()
49
+ return this._axios
50
+ }
51
+
52
+ get failureRetryTime() {
53
+ return this.config.failureRetryTime ?? HttpBridge.defaultFailureRetryTime
54
+ }
55
+
56
+ get maxConnections() {
57
+ return this.config.maxConnections ?? HttpBridge.defaultMaxConnections
58
+ }
59
+
60
+ get maxPayloadSizeWarning() {
61
+ return this.config.maxPayloadSizeWarning ?? HttpBridge.defaultMaxPayloadSizeWarning
62
+ }
63
+
64
+ get nodeUrl() {
65
+ return assertEx(this.config.nodeUrl, () => 'No Url Set')
66
+ }
67
+
68
+ get querySemaphore() {
69
+ this._querySemaphore = this._querySemaphore ?? new Semaphore(this.maxConnections)
70
+ return this._querySemaphore
71
+ }
72
+
73
+ override get resolver() {
74
+ this._resolver =
75
+ this._resolver ??
76
+ new HttpBridgeModuleResolver({
77
+ archiving: { ...this.archiving, resolveArchivists: this.resolveArchivingArchivists.bind(this) },
78
+ bridge: this,
79
+ querySender: this,
80
+ root: this,
81
+ rootUrl: this.nodeUrl,
82
+ wrapperAccount: this.account,
83
+ })
84
+ return this._resolver
85
+ }
86
+
87
+ override exposeHandler(_id: string, _options?: BridgeExposeOptions | undefined): Promisable<ModuleInstance[]> {
88
+ throw new Error('Unsupported')
89
+ }
90
+
91
+ override exposedHandler(): Promisable<Address[]> {
92
+ throw new Error('Unsupported')
93
+ }
94
+
95
+ async getRoots(force?: boolean): Promise<ModuleInstance[]> {
96
+ return await this._discoverRootsMutex.runExclusive(async () => {
97
+ if (this._roots === undefined || force) {
98
+ const state = await this.getRootState()
99
+ this.logger?.debug(`HttpBridge:discoverRoots.state [${state?.length}]`)
100
+ const nodeManifest = state?.find(isPayloadOfSchemaType<WithMeta<NodeManifestPayload>>(NodeManifestPayloadSchema))
101
+ if (nodeManifest) {
102
+ const mods = (await this.resolveRootNode(nodeManifest)).filter(exists)
103
+ this.logger?.debug(`HttpBridge:discoverRoots [${mods.length}]`)
104
+ this._roots = mods
105
+ } else {
106
+ this._roots = []
107
+ }
108
+ }
109
+ return this._roots
110
+ })
111
+ }
112
+
113
+ moduleUrl(address: Address) {
114
+ return new URL(address, this.nodeUrl)
115
+ }
116
+
117
+ async sendBridgeQuery<TOut extends Payload = Payload, TQuery extends QueryBoundWitness = QueryBoundWitness, TIn extends Payload = Payload>(
118
+ targetAddress: Address,
119
+ query: TQuery,
120
+ payloads?: TIn[],
121
+ ): Promise<ModuleQueryResult<TOut>> {
122
+ const lastFailureTime = this._failureTimeCache.get(targetAddress)
123
+ if (lastFailureTime !== undefined) {
124
+ const now = Date.now()
125
+ const timeSincePreviousFailure = now - lastFailureTime
126
+ if (timeSincePreviousFailure > this.failureRetryTime) {
127
+ throw new Error(`target module failed recently [${targetAddress}] [${timeSincePreviousFailure}ms ago]`)
128
+ }
129
+ this._failureTimeCache.delete(targetAddress)
130
+ }
131
+ try {
132
+ await this.querySemaphore.acquire()
133
+ const payloadSize = JSON.stringify([query, payloads]).length
134
+ if (payloadSize > this.maxPayloadSizeWarning) {
135
+ this.logger?.warn(
136
+ `Large targetQuery being sent: ${payloadSize} bytes [${this.address}][${this.moduleAddress}] [${query.schema}] [${payloads?.length}]`,
137
+ )
138
+ }
139
+ const moduleUrl = this.moduleUrl(targetAddress).href
140
+ const result = await this.axios.post<ApiEnvelope<ModuleQueryResult<TOut>>>(moduleUrl, [query, payloads])
141
+ if (result.status === 404) {
142
+ throw `target module not found [${moduleUrl}] [${result.status}]`
143
+ }
144
+ if (result.status >= 400) {
145
+ this.logger?.error(`targetQuery failed [${moduleUrl}]`)
146
+ throw `targetQuery failed [${moduleUrl}] [${result.status}]`
147
+ }
148
+ return result.data?.data
149
+ } catch (ex) {
150
+ const error = ex as AxiosError
151
+ this.logger?.error(`Error: ${toJsonString(error)}`)
152
+ throw error
153
+ } finally {
154
+ this.querySemaphore.release()
155
+ }
156
+ }
157
+
158
+ override unexposeHandler(_id: string, _options?: BridgeUnexposeOptions | undefined): Promisable<ModuleInstance[]> {
159
+ throw new Error('Unsupported')
160
+ }
161
+
162
+ private async getRootState() {
163
+ const queryPayload: ModuleStateQuery = { schema: ModuleStateQuerySchema }
164
+ const boundQuery = await this.bindQuery(queryPayload)
165
+ try {
166
+ const response = await this.axios.post<ApiEnvelope<ModuleQueryResult>>(this.nodeUrl.toString(), boundQuery)
167
+ if (response.status === 404) {
168
+ return []
169
+ }
170
+ const [, payloads, errors] = response.data.data
171
+ if (errors.length > 0) {
172
+ throw new Error(`getRootState failed: ${JSON.stringify(errors, null, 2)}`)
173
+ }
174
+ return payloads
175
+ } catch (ex) {
176
+ const error = ex as Error
177
+ this.logger?.warn(`Unable to connect to remote node: ${error.message} [${this.nodeUrl}]`)
178
+ }
179
+ }
180
+
181
+ private async resolveRootNode(nodeManifest: NodeManifestPayload): Promise<ModuleInstance[]> {
182
+ const rootModule = assertEx(
183
+ (await this.resolver.resolveHandler(assertEx(nodeManifest.status?.address, () => 'Root has no address'))).at(0),
184
+ () => `Root not found [${nodeManifest.status?.address}]`,
185
+ )
186
+ assertEx(rootModule.constructor.name !== 'HttpModuleProxy', () => 'rootModule is not a Wrapper')
187
+ const rootNode = asAttachableNodeInstance(rootModule, 'Root modules is not a node')
188
+ if (rootNode) {
189
+ this.logger.debug(`rootNode: ${rootNode.id}`)
190
+ this.downResolver.addResolver(rootNode as unknown as ModuleResolverInstance)
191
+ return [rootNode]
192
+ }
193
+ return []
194
+ }
195
+ }
@@ -0,0 +1,17 @@
1
+ import { EmptyObject } from '@xylabs/object'
2
+ import { BridgeConfig } from '@xyo-network/bridge-model'
3
+
4
+ export type HttpBridgeConfigSchema = 'network.xyo.bridge.http.config'
5
+ export const HttpBridgeConfigSchema: HttpBridgeConfigSchema = 'network.xyo.bridge.http.config'
6
+
7
+ export type HttpBridgeConfig<TConfig extends EmptyObject = EmptyObject, TSchema extends string | void = void> = BridgeConfig<
8
+ {
9
+ failureRetryTime?: number
10
+ failureTimeCacheMax?: number
11
+ maxConnections?: number
12
+ maxPayloadSizeWarning?: number
13
+ nodeUrl?: string
14
+ schema: HttpBridgeConfigSchema
15
+ } & TConfig,
16
+ TSchema extends string ? TSchema : HttpBridgeConfigSchema
17
+ >