@xyo-network/bridge-abstract 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 (149) hide show
  1. package/LICENSE +165 -0
  2. package/README.md +13 -0
  3. package/dist/browser/AbstractBridge.d.cts +36 -0
  4. package/dist/browser/AbstractBridge.d.cts.map +1 -0
  5. package/dist/browser/AbstractBridge.d.mts +36 -0
  6. package/dist/browser/AbstractBridge.d.mts.map +1 -0
  7. package/dist/browser/AbstractBridge.d.ts +36 -0
  8. package/dist/browser/AbstractBridge.d.ts.map +1 -0
  9. package/dist/browser/AbstractBridgeModuleResolver.d.cts +21 -0
  10. package/dist/browser/AbstractBridgeModuleResolver.d.cts.map +1 -0
  11. package/dist/browser/AbstractBridgeModuleResolver.d.mts +21 -0
  12. package/dist/browser/AbstractBridgeModuleResolver.d.mts.map +1 -0
  13. package/dist/browser/AbstractBridgeModuleResolver.d.ts +21 -0
  14. package/dist/browser/AbstractBridgeModuleResolver.d.ts.map +1 -0
  15. package/dist/browser/AbstractModuleProxy/AbstractModuleProxy.d.cts +74 -0
  16. package/dist/browser/AbstractModuleProxy/AbstractModuleProxy.d.cts.map +1 -0
  17. package/dist/browser/AbstractModuleProxy/AbstractModuleProxy.d.mts +74 -0
  18. package/dist/browser/AbstractModuleProxy/AbstractModuleProxy.d.mts.map +1 -0
  19. package/dist/browser/AbstractModuleProxy/AbstractModuleProxy.d.ts +74 -0
  20. package/dist/browser/AbstractModuleProxy/AbstractModuleProxy.d.ts.map +1 -0
  21. package/dist/browser/AbstractModuleProxy/ModuleProxyResolver.d.cts +65 -0
  22. package/dist/browser/AbstractModuleProxy/ModuleProxyResolver.d.cts.map +1 -0
  23. package/dist/browser/AbstractModuleProxy/ModuleProxyResolver.d.mts +65 -0
  24. package/dist/browser/AbstractModuleProxy/ModuleProxyResolver.d.mts.map +1 -0
  25. package/dist/browser/AbstractModuleProxy/ModuleProxyResolver.d.ts +65 -0
  26. package/dist/browser/AbstractModuleProxy/ModuleProxyResolver.d.ts.map +1 -0
  27. package/dist/browser/AbstractModuleProxy/index.d.cts +3 -0
  28. package/dist/browser/AbstractModuleProxy/index.d.cts.map +1 -0
  29. package/dist/browser/AbstractModuleProxy/index.d.mts +3 -0
  30. package/dist/browser/AbstractModuleProxy/index.d.mts.map +1 -0
  31. package/dist/browser/AbstractModuleProxy/index.d.ts +3 -0
  32. package/dist/browser/AbstractModuleProxy/index.d.ts.map +1 -0
  33. package/dist/browser/index.cjs +585 -0
  34. package/dist/browser/index.cjs.map +1 -0
  35. package/dist/browser/index.d.cts +5 -0
  36. package/dist/browser/index.d.cts.map +1 -0
  37. package/dist/browser/index.d.mts +5 -0
  38. package/dist/browser/index.d.mts.map +1 -0
  39. package/dist/browser/index.d.ts +5 -0
  40. package/dist/browser/index.d.ts.map +1 -0
  41. package/dist/browser/index.js +564 -0
  42. package/dist/browser/index.js.map +1 -0
  43. package/dist/browser/wrapModuleWithType.d.cts +5 -0
  44. package/dist/browser/wrapModuleWithType.d.cts.map +1 -0
  45. package/dist/browser/wrapModuleWithType.d.mts +5 -0
  46. package/dist/browser/wrapModuleWithType.d.mts.map +1 -0
  47. package/dist/browser/wrapModuleWithType.d.ts +5 -0
  48. package/dist/browser/wrapModuleWithType.d.ts.map +1 -0
  49. package/dist/neutral/AbstractBridge.d.cts +36 -0
  50. package/dist/neutral/AbstractBridge.d.cts.map +1 -0
  51. package/dist/neutral/AbstractBridge.d.mts +36 -0
  52. package/dist/neutral/AbstractBridge.d.mts.map +1 -0
  53. package/dist/neutral/AbstractBridge.d.ts +36 -0
  54. package/dist/neutral/AbstractBridge.d.ts.map +1 -0
  55. package/dist/neutral/AbstractBridgeModuleResolver.d.cts +21 -0
  56. package/dist/neutral/AbstractBridgeModuleResolver.d.cts.map +1 -0
  57. package/dist/neutral/AbstractBridgeModuleResolver.d.mts +21 -0
  58. package/dist/neutral/AbstractBridgeModuleResolver.d.mts.map +1 -0
  59. package/dist/neutral/AbstractBridgeModuleResolver.d.ts +21 -0
  60. package/dist/neutral/AbstractBridgeModuleResolver.d.ts.map +1 -0
  61. package/dist/neutral/AbstractModuleProxy/AbstractModuleProxy.d.cts +74 -0
  62. package/dist/neutral/AbstractModuleProxy/AbstractModuleProxy.d.cts.map +1 -0
  63. package/dist/neutral/AbstractModuleProxy/AbstractModuleProxy.d.mts +74 -0
  64. package/dist/neutral/AbstractModuleProxy/AbstractModuleProxy.d.mts.map +1 -0
  65. package/dist/neutral/AbstractModuleProxy/AbstractModuleProxy.d.ts +74 -0
  66. package/dist/neutral/AbstractModuleProxy/AbstractModuleProxy.d.ts.map +1 -0
  67. package/dist/neutral/AbstractModuleProxy/ModuleProxyResolver.d.cts +65 -0
  68. package/dist/neutral/AbstractModuleProxy/ModuleProxyResolver.d.cts.map +1 -0
  69. package/dist/neutral/AbstractModuleProxy/ModuleProxyResolver.d.mts +65 -0
  70. package/dist/neutral/AbstractModuleProxy/ModuleProxyResolver.d.mts.map +1 -0
  71. package/dist/neutral/AbstractModuleProxy/ModuleProxyResolver.d.ts +65 -0
  72. package/dist/neutral/AbstractModuleProxy/ModuleProxyResolver.d.ts.map +1 -0
  73. package/dist/neutral/AbstractModuleProxy/index.d.cts +3 -0
  74. package/dist/neutral/AbstractModuleProxy/index.d.cts.map +1 -0
  75. package/dist/neutral/AbstractModuleProxy/index.d.mts +3 -0
  76. package/dist/neutral/AbstractModuleProxy/index.d.mts.map +1 -0
  77. package/dist/neutral/AbstractModuleProxy/index.d.ts +3 -0
  78. package/dist/neutral/AbstractModuleProxy/index.d.ts.map +1 -0
  79. package/dist/neutral/index.cjs +585 -0
  80. package/dist/neutral/index.cjs.map +1 -0
  81. package/dist/neutral/index.d.cts +5 -0
  82. package/dist/neutral/index.d.cts.map +1 -0
  83. package/dist/neutral/index.d.mts +5 -0
  84. package/dist/neutral/index.d.mts.map +1 -0
  85. package/dist/neutral/index.d.ts +5 -0
  86. package/dist/neutral/index.d.ts.map +1 -0
  87. package/dist/neutral/index.js +564 -0
  88. package/dist/neutral/index.js.map +1 -0
  89. package/dist/neutral/wrapModuleWithType.d.cts +5 -0
  90. package/dist/neutral/wrapModuleWithType.d.cts.map +1 -0
  91. package/dist/neutral/wrapModuleWithType.d.mts +5 -0
  92. package/dist/neutral/wrapModuleWithType.d.mts.map +1 -0
  93. package/dist/neutral/wrapModuleWithType.d.ts +5 -0
  94. package/dist/neutral/wrapModuleWithType.d.ts.map +1 -0
  95. package/dist/node/AbstractBridge.d.cts +36 -0
  96. package/dist/node/AbstractBridge.d.cts.map +1 -0
  97. package/dist/node/AbstractBridge.d.mts +36 -0
  98. package/dist/node/AbstractBridge.d.mts.map +1 -0
  99. package/dist/node/AbstractBridge.d.ts +36 -0
  100. package/dist/node/AbstractBridge.d.ts.map +1 -0
  101. package/dist/node/AbstractBridgeModuleResolver.d.cts +21 -0
  102. package/dist/node/AbstractBridgeModuleResolver.d.cts.map +1 -0
  103. package/dist/node/AbstractBridgeModuleResolver.d.mts +21 -0
  104. package/dist/node/AbstractBridgeModuleResolver.d.mts.map +1 -0
  105. package/dist/node/AbstractBridgeModuleResolver.d.ts +21 -0
  106. package/dist/node/AbstractBridgeModuleResolver.d.ts.map +1 -0
  107. package/dist/node/AbstractModuleProxy/AbstractModuleProxy.d.cts +74 -0
  108. package/dist/node/AbstractModuleProxy/AbstractModuleProxy.d.cts.map +1 -0
  109. package/dist/node/AbstractModuleProxy/AbstractModuleProxy.d.mts +74 -0
  110. package/dist/node/AbstractModuleProxy/AbstractModuleProxy.d.mts.map +1 -0
  111. package/dist/node/AbstractModuleProxy/AbstractModuleProxy.d.ts +74 -0
  112. package/dist/node/AbstractModuleProxy/AbstractModuleProxy.d.ts.map +1 -0
  113. package/dist/node/AbstractModuleProxy/ModuleProxyResolver.d.cts +65 -0
  114. package/dist/node/AbstractModuleProxy/ModuleProxyResolver.d.cts.map +1 -0
  115. package/dist/node/AbstractModuleProxy/ModuleProxyResolver.d.mts +65 -0
  116. package/dist/node/AbstractModuleProxy/ModuleProxyResolver.d.mts.map +1 -0
  117. package/dist/node/AbstractModuleProxy/ModuleProxyResolver.d.ts +65 -0
  118. package/dist/node/AbstractModuleProxy/ModuleProxyResolver.d.ts.map +1 -0
  119. package/dist/node/AbstractModuleProxy/index.d.cts +3 -0
  120. package/dist/node/AbstractModuleProxy/index.d.cts.map +1 -0
  121. package/dist/node/AbstractModuleProxy/index.d.mts +3 -0
  122. package/dist/node/AbstractModuleProxy/index.d.mts.map +1 -0
  123. package/dist/node/AbstractModuleProxy/index.d.ts +3 -0
  124. package/dist/node/AbstractModuleProxy/index.d.ts.map +1 -0
  125. package/dist/node/index.cjs +609 -0
  126. package/dist/node/index.cjs.map +1 -0
  127. package/dist/node/index.d.cts +5 -0
  128. package/dist/node/index.d.cts.map +1 -0
  129. package/dist/node/index.d.mts +5 -0
  130. package/dist/node/index.d.mts.map +1 -0
  131. package/dist/node/index.d.ts +5 -0
  132. package/dist/node/index.d.ts.map +1 -0
  133. package/dist/node/index.js +580 -0
  134. package/dist/node/index.js.map +1 -0
  135. package/dist/node/wrapModuleWithType.d.cts +5 -0
  136. package/dist/node/wrapModuleWithType.d.cts.map +1 -0
  137. package/dist/node/wrapModuleWithType.d.mts +5 -0
  138. package/dist/node/wrapModuleWithType.d.mts.map +1 -0
  139. package/dist/node/wrapModuleWithType.d.ts +5 -0
  140. package/dist/node/wrapModuleWithType.d.ts.map +1 -0
  141. package/package.json +92 -0
  142. package/src/AbstractBridge.ts +232 -0
  143. package/src/AbstractBridgeModuleResolver.ts +42 -0
  144. package/src/AbstractModuleProxy/AbstractModuleProxy.ts +268 -0
  145. package/src/AbstractModuleProxy/ModuleProxyResolver.ts +143 -0
  146. package/src/AbstractModuleProxy/index.ts +2 -0
  147. package/src/index.ts +4 -0
  148. package/src/wrapModuleWithType.ts +32 -0
  149. package/typedoc.json +5 -0
@@ -0,0 +1,268 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { forget } from '@xylabs/forget'
3
+ import { Address, asAddress } from '@xylabs/hex'
4
+ import { compact } from '@xylabs/lodash'
5
+ import { toJsonString } from '@xylabs/object'
6
+ import { AccountInstance } from '@xyo-network/account-model'
7
+ import { ArchivistInstance } from '@xyo-network/archivist-model'
8
+ import { QueryBoundWitness } from '@xyo-network/boundwitness-model'
9
+ import { BoundWitnessWrapper, QueryBoundWitnessWrapper } from '@xyo-network/boundwitness-wrapper'
10
+ import { QuerySendFinishedEventArgs, QuerySendStartedEventArgs } from '@xyo-network/bridge-model'
11
+ import { ModuleManifestPayload, ModuleManifestPayloadSchema, NodeManifestPayload, NodeManifestPayloadSchema } from '@xyo-network/manifest-model'
12
+ import { AbstractModuleInstance } from '@xyo-network/module-abstract'
13
+ import {
14
+ AddressPreviousHashPayload,
15
+ AddressPreviousHashSchema,
16
+ ArchivingModuleConfig,
17
+ DeadModuleError,
18
+ Module,
19
+ ModuleAddressQuery,
20
+ ModuleAddressQuerySchema,
21
+ ModuleConfigSchema,
22
+ ModuleInstance,
23
+ ModuleManifestQuery,
24
+ ModuleManifestQuerySchema,
25
+ ModuleName,
26
+ ModuleParams,
27
+ ModuleQueryHandlerResult,
28
+ ModuleQueryResult,
29
+ ModuleResolver,
30
+ ModuleStateQuerySchema,
31
+ } from '@xyo-network/module-model'
32
+ import { ModuleWrapper } from '@xyo-network/module-wrapper'
33
+ import { PayloadBuilder } from '@xyo-network/payload-builder'
34
+ import { isPayloadOfSchemaType, ModuleError, ModuleErrorSchema, Payload, WithMeta } from '@xyo-network/payload-model'
35
+ import { QueryPayload, QuerySchema } from '@xyo-network/query-payload-plugin'
36
+ import { LRUCache } from 'lru-cache'
37
+
38
+ import { ModuleProxyResolver } from './ModuleProxyResolver'
39
+
40
+ export type ModuleProxyParams = ModuleParams<
41
+ {
42
+ schema: ModuleConfigSchema
43
+ },
44
+ {
45
+ account: AccountInstance
46
+ archiving?: ArchivingModuleConfig['archiving'] & { resolveArchivists: () => Promise<ArchivistInstance[]> }
47
+ host: ModuleResolver
48
+ moduleAddress: Address
49
+ onQuerySendFinished?: (args: Omit<QuerySendFinishedEventArgs, 'module'>) => void
50
+ onQuerySendStarted?: (args: Omit<QuerySendStartedEventArgs, 'module'>) => void
51
+ }
52
+ >
53
+
54
+ export abstract class AbstractModuleProxy<
55
+ TWrappedModule extends ModuleInstance = ModuleInstance,
56
+ TParams extends Omit<ModuleProxyParams, 'config'> & { config: TWrappedModule['config'] } = Omit<ModuleProxyParams, 'config'> & {
57
+ config: TWrappedModule['config']
58
+ },
59
+ >
60
+ extends AbstractModuleInstance<TParams, TWrappedModule['eventData']>
61
+ implements ModuleInstance<TParams, TWrappedModule['eventData']>
62
+ {
63
+ static requiredQueries: string[] = [ModuleStateQuerySchema]
64
+
65
+ protected _config?: ModuleInstance['config']
66
+ protected _publicChildren?: ModuleInstance[]
67
+ protected _state: Payload[] | undefined = undefined
68
+ protected _stateInProcess = false
69
+
70
+ private _spamTrap = new LRUCache<string, number>({ max: 1000, ttl: 1000 * 60, ttlAutopurge: true })
71
+
72
+ constructor(params: TParams) {
73
+ params.addToResolvers = false
74
+ super(AbstractModuleProxy.privateConstructorKey, params, params.account)
75
+ }
76
+
77
+ override get address() {
78
+ return this.params.moduleAddress
79
+ }
80
+
81
+ override get archiving(): ArchivingModuleConfig['archiving'] | undefined {
82
+ return this.params?.archiving
83
+ }
84
+
85
+ override get config() {
86
+ return assertEx(this._config, () => 'Config not set')
87
+ }
88
+
89
+ override get queries(): string[] {
90
+ const queryPayloads = assertEx(this._state, () => 'Module state not found. Make sure proxy has been started').filter((item) =>
91
+ isPayloadOfSchemaType<QueryPayload>(QuerySchema)(item),
92
+ ) as QueryPayload[]
93
+ return queryPayloads.map((payload) => payload.query)
94
+ }
95
+
96
+ protected override get _queryAccountPaths() {
97
+ return this._baseModuleQueryAccountPaths
98
+ }
99
+
100
+ static hasRequiredQueries(module: Module) {
101
+ return this.missingRequiredQueries(module).length === 0
102
+ }
103
+
104
+ static missingRequiredQueries(module: Module): string[] {
105
+ const moduleQueries = module.queries
106
+ return compact(
107
+ this.requiredQueries.map((query) => {
108
+ return moduleQueries.includes(query) ? null : query
109
+ }),
110
+ )
111
+ }
112
+
113
+ async addressPreviousHash(): Promise<AddressPreviousHashPayload> {
114
+ const queryPayload: ModuleAddressQuery = { schema: ModuleAddressQuerySchema }
115
+ const result: AddressPreviousHashPayload = assertEx(
116
+ (await this.sendQuery(queryPayload, undefined, this.account)).find(
117
+ isPayloadOfSchemaType<AddressPreviousHashPayload>(AddressPreviousHashSchema),
118
+ ) as WithMeta<AddressPreviousHashPayload>,
119
+ () => 'Result did not include correct payload',
120
+ )
121
+ return result
122
+ }
123
+
124
+ childAddressByName(name: ModuleName): Address | undefined {
125
+ const nodeManifests = this._state?.filter(isPayloadOfSchemaType<NodeManifestPayload>(NodeManifestPayloadSchema))
126
+ const childPairs = nodeManifests?.flatMap((nodeManifest) => Object.entries(nodeManifest.status?.children ?? {}) as [Address, ModuleName | null][])
127
+ return asAddress(childPairs?.find(([_, childName]) => childName === name)?.[0])
128
+ }
129
+
130
+ async childAddressMap(): Promise<Record<Address, ModuleName | null>> {
131
+ const state = await this.state()
132
+ const result: Record<Address, ModuleName | null> = {}
133
+ const nodeManifests = state.filter(isPayloadOfSchemaType<NodeManifestPayload>(NodeManifestPayloadSchema))
134
+ for (const manifest of nodeManifests) {
135
+ const children = manifest.modules?.public ?? []
136
+ for (const child of children) {
137
+ if (typeof child === 'object') {
138
+ const address = child.status?.address
139
+ if (address) {
140
+ result[address] = child.config.name ?? null
141
+ }
142
+ }
143
+ }
144
+ }
145
+ return result
146
+ }
147
+
148
+ override async manifest(maxDepth?: number): Promise<ModuleManifestPayload> {
149
+ const queryPayload: ModuleManifestQuery = { schema: ModuleManifestQuerySchema, ...(maxDepth === undefined ? {} : { maxDepth }) }
150
+ return (await this.sendQuery(queryPayload))[0] as WithMeta<ModuleManifestPayload>
151
+ }
152
+
153
+ override async moduleAddress(): Promise<AddressPreviousHashPayload[]> {
154
+ const queryPayload: ModuleAddressQuery = { schema: ModuleAddressQuerySchema }
155
+ return (await this.sendQuery(queryPayload)) as WithMeta<AddressPreviousHashPayload>[]
156
+ }
157
+
158
+ override async previousHash(): Promise<string | undefined> {
159
+ const queryPayload: ModuleAddressQuery = { schema: ModuleAddressQuerySchema }
160
+ return ((await this.sendQuery(queryPayload)).pop() as WithMeta<AddressPreviousHashPayload>).previousHash
161
+ }
162
+
163
+ override async publicChildren() {
164
+ this._publicChildren = this._publicChildren ?? (await super.publicChildren())
165
+ return this._publicChildren
166
+ }
167
+
168
+ override async query<T extends QueryBoundWitness = QueryBoundWitness>(query: T, payloads?: Payload[]): Promise<ModuleQueryResult> {
169
+ this._checkDead()
170
+ return await this.busy(async () => {
171
+ try {
172
+ await this.checkSpam(query)
173
+ this.params.onQuerySendStarted?.({ payloads, query })
174
+ const result = await this.proxyQueryHandler<T>(query, payloads)
175
+ this.params.onQuerySendFinished?.({ payloads, query, result, status: 'success' })
176
+ if (this.archiving && this.isAllowedArchivingQuery(query.schema)) {
177
+ forget(this.storeToArchivists(result.flat()))
178
+ }
179
+ forget(this.emit('moduleQueried', { module: this, payloads, query, result }))
180
+ return result
181
+ } catch (ex) {
182
+ this.params.onQuerySendFinished?.({ payloads, query, status: 'failure' })
183
+ const error = ex as Error
184
+ this._lastError = error
185
+ //this.status = 'dead'
186
+ const deadError = new DeadModuleError(this.address, error)
187
+ const errorPayload: ModuleError = {
188
+ message: deadError.message,
189
+ name: deadError.name,
190
+ schema: ModuleErrorSchema,
191
+ }
192
+ const sourceQuery = await PayloadBuilder.build(assertEx(QueryBoundWitnessWrapper.unwrap(query), () => 'Invalid query'))
193
+ return await this.bindQueryResult(sourceQuery, [], undefined, [errorPayload])
194
+ }
195
+ })
196
+ }
197
+
198
+ override queryHandler<T extends QueryBoundWitness = QueryBoundWitness>(
199
+ _query: T,
200
+ _payloads?: Payload[],
201
+ _queryConfig?: TWrappedModule['params']['config'],
202
+ ): Promise<ModuleQueryHandlerResult> {
203
+ throw new Error('queryHandler should never be called')
204
+ }
205
+
206
+ override async queryable<T extends QueryBoundWitness = QueryBoundWitness>(
207
+ _query: T,
208
+ _payloads?: Payload[],
209
+ _queryConfig?: TWrappedModule['params']['config'],
210
+ ): Promise<boolean> {
211
+ return await Promise.resolve(true)
212
+ }
213
+
214
+ override async resolveArchivingArchivists(): Promise<ArchivistInstance[]> {
215
+ return (await this.params.archiving?.resolveArchivists()) ?? []
216
+ }
217
+
218
+ setConfig(config: TWrappedModule['params']['config']) {
219
+ this._config = config
220
+ }
221
+
222
+ override async startHandler(): Promise<boolean> {
223
+ const state = await this.state()
224
+ const manifestPayload = state.find(
225
+ (payload) => isPayloadOfSchemaType(NodeManifestPayloadSchema)(payload) || isPayloadOfSchemaType(ModuleManifestPayloadSchema)(payload),
226
+ ) as ModuleManifestPayload
227
+ const manifest = assertEx(manifestPayload, () => "Can't find manifest payload")
228
+ this.setConfig({ ...manifest.config })
229
+ this.downResolver.addResolver(
230
+ new ModuleProxyResolver({
231
+ childAddressMap: await this.childAddressMap(),
232
+ host: this.params.host,
233
+ module: this,
234
+ moduleIdentifierTransformers: this.params.moduleIdentifierTransformers,
235
+ }),
236
+ )
237
+ return await super.startHandler()
238
+ }
239
+
240
+ override async state(): Promise<Payload[]> {
241
+ if (this._state === undefined) {
242
+ //temporarily add ModuleStateQuerySchema to the schema list so we can wrap it and get the real query list
243
+ const stateQueryPayload: QueryPayload = { query: ModuleStateQuerySchema, schema: QuerySchema }
244
+ const manifestQueryPayload: QueryPayload = { query: ModuleManifestQuerySchema, schema: QuerySchema }
245
+ this._state = [stateQueryPayload, manifestQueryPayload]
246
+ const wrapper = ModuleWrapper.wrap(this, this.account)
247
+ this._state = await wrapper.state()
248
+ }
249
+ return this._state
250
+ }
251
+
252
+ protected async filterErrors(result: ModuleQueryResult): Promise<ModuleError[]> {
253
+ const wrapper = await BoundWitnessWrapper.wrap(result[0], result[1])
254
+ return wrapper.payloadsBySchema<WithMeta<ModuleError>>(ModuleErrorSchema)
255
+ }
256
+
257
+ //this checks and warns if we are getting spammed by the same query
258
+ private async checkSpam(query: QueryBoundWitness) {
259
+ const hash = await PayloadBuilder.hash(query)
260
+ const previousCount = this._spamTrap.get(hash) ?? 0
261
+ if (previousCount > 0) {
262
+ this.logger?.warn(`Spam trap triggered for query: ${hash} from ${toJsonString(query.addresses)}`)
263
+ }
264
+ this._spamTrap.set(hash, previousCount + 1)
265
+ }
266
+
267
+ abstract proxyQueryHandler<T extends QueryBoundWitness = QueryBoundWitness>(query: T, payloads?: Payload[]): Promise<ModuleQueryResult>
268
+ }
@@ -0,0 +1,143 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { exists } from '@xylabs/exists'
3
+ import { Address } from '@xylabs/hex'
4
+ import { Promisable } from '@xylabs/promise'
5
+ import { Account } from '@xyo-network/account'
6
+ import {
7
+ isAddressModuleFilter,
8
+ isNameModuleFilter,
9
+ ModuleFilter,
10
+ ModuleFilterOptions,
11
+ ModuleIdentifier,
12
+ ModuleIdentifierTransformer,
13
+ ModuleInstance,
14
+ ModuleName,
15
+ ModuleResolver,
16
+ ModuleResolverInstance,
17
+ ObjectFilterOptions,
18
+ ObjectResolverPriority,
19
+ } from '@xyo-network/module-model'
20
+ import { CompositeModuleResolver } from '@xyo-network/module-resolver'
21
+
22
+ import { wrapModuleWithType } from '../wrapModuleWithType'
23
+
24
+ export interface ModuleProxyResolverOptions {
25
+ childAddressMap: Record<Address, ModuleName | null>
26
+ host: ModuleResolver
27
+ module: ModuleInstance
28
+ moduleIdentifierTransformers?: ModuleIdentifierTransformer[]
29
+ }
30
+
31
+ export class ModuleProxyResolver<T extends ModuleProxyResolverOptions = ModuleProxyResolverOptions> implements ModuleResolverInstance {
32
+ private downResolver: CompositeModuleResolver
33
+
34
+ constructor(private options: T) {
35
+ this.downResolver = new CompositeModuleResolver({ moduleIdentifierTransformers: options.moduleIdentifierTransformers, root: this.root })
36
+ }
37
+
38
+ get priority() {
39
+ return ObjectResolverPriority.VeryLow
40
+ }
41
+
42
+ get root() {
43
+ return this.options.module
44
+ }
45
+
46
+ protected get childAddressMap() {
47
+ return this.options.childAddressMap
48
+ }
49
+
50
+ protected get host() {
51
+ return this.options.host
52
+ }
53
+
54
+ protected get module() {
55
+ return this.options.module
56
+ }
57
+
58
+ addResolver(_resolver: ModuleResolver): this {
59
+ throw new Error('Not supported')
60
+ }
61
+
62
+ removeResolver(_resolver: ModuleResolver): this {
63
+ throw new Error('Not supported')
64
+ }
65
+
66
+ /** @deprecated do not pass undefined. If trying to get all, pass '*' */
67
+ async resolve(): Promise<ModuleInstance[]>
68
+ async resolve<T extends ModuleInstance = ModuleInstance>(all: '*', options?: ModuleFilterOptions<T>): Promise<T[]>
69
+ async resolve<T extends ModuleInstance = ModuleInstance>(filter: ModuleFilter<T>, options?: ModuleFilterOptions<T>): Promise<T[]>
70
+ async resolve<T extends ModuleInstance = ModuleInstance>(id: ModuleIdentifier, options?: ModuleFilterOptions<T>): Promise<T | undefined>
71
+ /** @deprecated use '*' if trying to resolve all */
72
+ async resolve<T extends ModuleInstance = ModuleInstance>(filter?: ModuleFilter<T>, options?: ModuleFilterOptions<T>): Promise<T[]>
73
+ async resolve<T extends ModuleInstance = ModuleInstance>(
74
+ idOrFilter: ModuleFilter<T> | ModuleIdentifier = '*',
75
+ options?: ModuleFilterOptions<T>,
76
+ ): Promise<T | T[] | undefined> {
77
+ //console.log(`childAddressMap: ${toJsonString(this.childAddressMap, 10)}`)
78
+ const direction = options?.direction ?? 'all'
79
+ if (idOrFilter === '*') {
80
+ //get all the child addresses. if they have been resolved before, they should be in downResolver
81
+ const childAddresses = Object.keys(this.childAddressMap)
82
+ const resolvedChildren = await Promise.all(childAddresses.map<Promise<T | undefined>>((address) => this.resolve<T>(address, options)))
83
+ return resolvedChildren.filter(exists)
84
+ } else if (typeof idOrFilter === 'string') {
85
+ const idParts = idOrFilter.split(':')
86
+ const firstPart: ModuleIdentifier = assertEx(idParts.shift(), () => 'Invalid module identifier at first position')
87
+ const firstPartAddress = await this.resolveIdentifier(firstPart)
88
+ if (firstPartAddress) {
89
+ const remainingParts = idParts.length > 0 ? idParts.join(':') : undefined
90
+ if (direction === 'down' || direction === 'all') {
91
+ const downResolverModule = await this.downResolver.resolve<T>(firstPartAddress)
92
+ if (downResolverModule) {
93
+ return remainingParts ? downResolverModule.resolve(remainingParts, options) : downResolverModule
94
+ }
95
+ //if it is a known child, create a proxy
96
+ const addressToProxy =
97
+ Object.keys(this.childAddressMap).includes(firstPartAddress as Address) ?
98
+ (firstPartAddress as Address)
99
+ : (Object.entries(this.childAddressMap).find(([_, value]) => value === firstPartAddress)?.[0] as Address | undefined)
100
+ if (addressToProxy) {
101
+ const proxy = await this.host.resolve(addressToProxy, { ...options, direction: 'down' })
102
+ if (proxy) {
103
+ const wrapped = wrapModuleWithType(proxy, Account.randomSync()) as unknown as T
104
+ return remainingParts ? wrapped?.resolve(remainingParts, options) : wrapped
105
+ }
106
+ return
107
+ }
108
+ }
109
+ }
110
+ return
111
+ } else {
112
+ const filter = idOrFilter
113
+ if (isAddressModuleFilter(filter)) {
114
+ const results = (await Promise.all(filter.address.map((item) => this.resolve(item, options)))).filter(exists)
115
+ return results
116
+ } else if (isNameModuleFilter(filter)) {
117
+ return (await Promise.all(filter.name.map((item) => this.resolve(item, options)))).filter(exists)
118
+ }
119
+ }
120
+ }
121
+
122
+ resolveIdentifier(id: ModuleIdentifier, _options?: ObjectFilterOptions): Promisable<Address | undefined> {
123
+ //check if any of the modules have the id as an address
124
+ if (this.childAddressMap[id as Address]) {
125
+ return id as Address
126
+ }
127
+
128
+ //check if id is a name of one of modules in the resolver
129
+ const addressFromName = Object.entries(this.childAddressMap).find(([, name]) => name === id)?.[0] as Address | undefined
130
+ if (addressFromName) {
131
+ return addressFromName
132
+ }
133
+ }
134
+
135
+ async resolvePrivate<T extends ModuleInstance = ModuleInstance>(all: '*', options?: ObjectFilterOptions<T>): Promise<T[]>
136
+ async resolvePrivate<T extends ModuleInstance = ModuleInstance>(id: ModuleIdentifier, options?: ObjectFilterOptions<T>): Promise<T | undefined>
137
+ async resolvePrivate<T extends ModuleInstance = ModuleInstance>(
138
+ id: ModuleIdentifier,
139
+ _options?: ObjectFilterOptions<T>,
140
+ ): Promise<T | T[] | undefined> {
141
+ if (id === '*') return await Promise.resolve([])
142
+ }
143
+ }
@@ -0,0 +1,2 @@
1
+ export * from './AbstractModuleProxy'
2
+ export * from './ModuleProxyResolver'
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './AbstractBridge'
2
+ export * from './AbstractBridgeModuleResolver'
3
+ export * from './AbstractModuleProxy'
4
+ export * from './wrapModuleWithType'
@@ -0,0 +1,32 @@
1
+ import { AccountInstance } from '@xyo-network/account-model'
2
+ import { isArchivistModule } from '@xyo-network/archivist-model'
3
+ import { ArchivistWrapper } from '@xyo-network/archivist-wrapper'
4
+ import { isDivinerModule } from '@xyo-network/diviner-model'
5
+ import { DivinerWrapper } from '@xyo-network/diviner-wrapper'
6
+ import { Module } from '@xyo-network/module-model'
7
+ import { ModuleWrapper } from '@xyo-network/module-wrapper'
8
+ import { isNodeModule } from '@xyo-network/node-model'
9
+ import { NodeWrapper } from '@xyo-network/node-wrapper'
10
+ import { isSentinelModule } from '@xyo-network/sentinel-model'
11
+ import { SentinelWrapper } from '@xyo-network/sentinel-wrapper'
12
+ import { isWitnessModule } from '@xyo-network/witness-model'
13
+ import { WitnessWrapper } from '@xyo-network/witness-wrapper'
14
+
15
+ export const wrapModuleWithType = (module: Module, account: AccountInstance): ModuleWrapper => {
16
+ if (isArchivistModule(module)) {
17
+ return ArchivistWrapper.wrap(module, account)
18
+ }
19
+ if (isDivinerModule(module)) {
20
+ return DivinerWrapper.wrap(module, account)
21
+ }
22
+ if (isNodeModule(module)) {
23
+ return NodeWrapper.wrap(module, account)
24
+ }
25
+ if (isSentinelModule(module)) {
26
+ return SentinelWrapper.wrap(module, account)
27
+ }
28
+ if (isWitnessModule(module)) {
29
+ return WitnessWrapper.wrap(module, account)
30
+ }
31
+ throw 'Failed to wrap'
32
+ }
package/typedoc.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "$schema": "https://typedoc.org/schema.json",
3
+ "entryPoints": ["src/index.ts"],
4
+ "tsconfig": "./tsconfig.typedoc.json"
5
+ }