@xyo-network/chain-mempool 1.16.3

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 (95) hide show
  1. package/LICENSE +165 -0
  2. package/README.md +96 -0
  3. package/dist/node/helpers/index.d.ts +2 -0
  4. package/dist/node/helpers/index.d.ts.map +1 -0
  5. package/dist/node/helpers/initChainId.d.ts +4 -0
  6. package/dist/node/helpers/initChainId.d.ts.map +1 -0
  7. package/dist/node/index.d.ts +2 -0
  8. package/dist/node/index.d.ts.map +1 -0
  9. package/dist/node/index.mjs +618 -0
  10. package/dist/node/index.mjs.map +1 -0
  11. package/dist/node/manifest/getLocator.d.ts +14 -0
  12. package/dist/node/manifest/getLocator.d.ts.map +1 -0
  13. package/dist/node/manifest/getNode.d.ts +15 -0
  14. package/dist/node/manifest/getNode.d.ts.map +1 -0
  15. package/dist/node/manifest/index.d.ts +6 -0
  16. package/dist/node/manifest/index.d.ts.map +1 -0
  17. package/dist/node/manifest/nodeManifest.d.ts +6 -0
  18. package/dist/node/manifest/nodeManifest.d.ts.map +1 -0
  19. package/dist/node/manifest/private/index.d.ts +5 -0
  20. package/dist/node/manifest/private/index.d.ts.map +1 -0
  21. package/dist/node/manifest/public/index.d.ts +14 -0
  22. package/dist/node/manifest/public/index.d.ts.map +1 -0
  23. package/dist/node/manifest/public/spec/Node.spec.d.ts +2 -0
  24. package/dist/node/manifest/public/spec/Node.spec.d.ts.map +1 -0
  25. package/dist/node/server/app.d.ts +4 -0
  26. package/dist/node/server/app.d.ts.map +1 -0
  27. package/dist/node/server/index.d.ts +11 -0
  28. package/dist/node/server/index.d.ts.map +1 -0
  29. package/dist/node/server/instrumentation.d.ts +9 -0
  30. package/dist/node/server/instrumentation.d.ts.map +1 -0
  31. package/dist/node/server/routes/addRoutes.d.ts +3 -0
  32. package/dist/node/server/routes/addRoutes.d.ts.map +1 -0
  33. package/dist/node/server/routes/address/AddressPathParams.d.ts +4 -0
  34. package/dist/node/server/routes/address/AddressPathParams.d.ts.map +1 -0
  35. package/dist/node/server/routes/address/addNodeRoutes.d.ts +3 -0
  36. package/dist/node/server/routes/address/addNodeRoutes.d.ts.map +1 -0
  37. package/dist/node/server/routes/address/get/get.d.ts +4 -0
  38. package/dist/node/server/routes/address/get/get.d.ts.map +1 -0
  39. package/dist/node/server/routes/address/get/index.d.ts +2 -0
  40. package/dist/node/server/routes/address/get/index.d.ts.map +1 -0
  41. package/dist/node/server/routes/address/index.d.ts +2 -0
  42. package/dist/node/server/routes/address/index.d.ts.map +1 -0
  43. package/dist/node/server/routes/address/post/getQueryConfig.d.ts +6 -0
  44. package/dist/node/server/routes/address/post/getQueryConfig.d.ts.map +1 -0
  45. package/dist/node/server/routes/address/post/index.d.ts +2 -0
  46. package/dist/node/server/routes/address/post/index.d.ts.map +1 -0
  47. package/dist/node/server/routes/address/post/post.d.ts +8 -0
  48. package/dist/node/server/routes/address/post/post.d.ts.map +1 -0
  49. package/dist/node/server/routes/dataLake/addDataLakeRoutes.d.ts +3 -0
  50. package/dist/node/server/routes/dataLake/addDataLakeRoutes.d.ts.map +1 -0
  51. package/dist/node/server/routes/dataLake/archivistMiddleware.d.ts +10 -0
  52. package/dist/node/server/routes/dataLake/archivistMiddleware.d.ts.map +1 -0
  53. package/dist/node/server/routes/dataLake/index.d.ts +2 -0
  54. package/dist/node/server/routes/dataLake/index.d.ts.map +1 -0
  55. package/dist/node/server/routes/healthz/addHealthRoutes.d.ts +3 -0
  56. package/dist/node/server/routes/healthz/addHealthRoutes.d.ts.map +1 -0
  57. package/dist/node/server/routes/healthz/index.d.ts +2 -0
  58. package/dist/node/server/routes/healthz/index.d.ts.map +1 -0
  59. package/dist/node/server/routes/index.d.ts +4 -0
  60. package/dist/node/server/routes/index.d.ts.map +1 -0
  61. package/dist/node/server/server.d.ts +11 -0
  62. package/dist/node/server/server.d.ts.map +1 -0
  63. package/package.json +118 -0
  64. package/src/helpers/index.ts +1 -0
  65. package/src/helpers/initChainId.ts +20 -0
  66. package/src/index.ts +1 -0
  67. package/src/manifest/getLocator.ts +85 -0
  68. package/src/manifest/getNode.ts +32 -0
  69. package/src/manifest/index.ts +5 -0
  70. package/src/manifest/node.json +17 -0
  71. package/src/manifest/nodeManifest.ts +8 -0
  72. package/src/manifest/private/index.ts +4 -0
  73. package/src/manifest/public/Chain.json +101 -0
  74. package/src/manifest/public/Pending.json +35 -0
  75. package/src/manifest/public/index.ts +20 -0
  76. package/src/manifest/public/spec/Node.spec.ts +32 -0
  77. package/src/server/app.ts +36 -0
  78. package/src/server/index.ts +13 -0
  79. package/src/server/instrumentation.ts +15 -0
  80. package/src/server/routes/addRoutes.ts +11 -0
  81. package/src/server/routes/address/AddressPathParams.ts +3 -0
  82. package/src/server/routes/address/addNodeRoutes.ts +21 -0
  83. package/src/server/routes/address/get/get.ts +31 -0
  84. package/src/server/routes/address/get/index.ts +1 -0
  85. package/src/server/routes/address/index.ts +1 -0
  86. package/src/server/routes/address/post/getQueryConfig.ts +23 -0
  87. package/src/server/routes/address/post/index.ts +1 -0
  88. package/src/server/routes/address/post/post.ts +77 -0
  89. package/src/server/routes/dataLake/addDataLakeRoutes.ts +9 -0
  90. package/src/server/routes/dataLake/archivistMiddleware.ts +86 -0
  91. package/src/server/routes/dataLake/index.ts +1 -0
  92. package/src/server/routes/healthz/addHealthRoutes.ts +14 -0
  93. package/src/server/routes/healthz/index.ts +1 -0
  94. package/src/server/routes/index.ts +3 -0
  95. package/src/server/server.ts +63 -0
@@ -0,0 +1,85 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { asAddress, ZERO_ADDRESS } from '@xylabs/hex'
3
+ import type { Logger } from '@xylabs/logger'
4
+ import { type BaseMongoSdkPrivateConfig } from '@xylabs/mongo'
5
+ import { isDefined } from '@xylabs/typeof'
6
+ import { MemoryArchivist } from '@xyo-network/archivist-memory'
7
+ import { MongoDBArchivistV2 } from '@xyo-network/archivist-mongodb'
8
+ import { ViewArchivist } from '@xyo-network/archivist-view'
9
+ import { HeadValidationDiviner } from '@xyo-network/chain-modules'
10
+ import { initTelemetry } from '@xyo-network/chain-telemetry'
11
+ import { AbstractModule, LoggerModuleStatusReporter } from '@xyo-network/module-abstract'
12
+ import { ModuleFactoryLocator } from '@xyo-network/module-factory-locator'
13
+ import type { MongoDBModuleParamsV2 } from '@xyo-network/module-model-mongodb'
14
+ import { MemorySentinel } from '@xyo-network/sentinel-memory'
15
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
16
+ import { hasMongoConfig } from '@xyo-network/xl1-protocol-sdk'
17
+
18
+ export interface GetLocatorContext {
19
+ config: Config
20
+ logger?: Logger
21
+ }
22
+
23
+ /**
24
+ * Used for retrieving a locator with the necessary modules registered for testing
25
+ * operation of the node (entirely in memory)
26
+ * @returns A locator with the necessary modules registered
27
+ */
28
+ export const getLocator = async (context: GetLocatorContext) => {
29
+ const { config, logger } = context
30
+ const { otlpEndpoint } = config.telemetry?.otel ?? {}
31
+ const { traceProvider, meterProvider } = await initTelemetry({
32
+ attributes: {
33
+ serviceName: 'xl1-api',
34
+ serviceVersion: '1.0.0',
35
+ },
36
+ otlpEndpoint,
37
+ metricsConfig: {
38
+ endpoint: '/metrics',
39
+ port: 9465,
40
+ },
41
+ })
42
+
43
+ if (isDefined(logger)) AbstractModule.defaultLogger = logger
44
+ const statusReporter = logger ? new LoggerModuleStatusReporter(logger) : undefined
45
+
46
+ const locator = new ModuleFactoryLocator()
47
+
48
+ // If there's a MongoDB configuration
49
+ const mongoConfig = config.storage?.mongo
50
+ if (hasMongoConfig(mongoConfig)) {
51
+ // Create the MongoDB SDK from the configuration
52
+ const {
53
+ connectionString: dbConnectionString, database: dbName, domain: dbDomain, password: dbPassword, username: dbUserName,
54
+ } = mongoConfig
55
+ const payloadSdkConfig: BaseMongoSdkPrivateConfig = {
56
+ dbConnectionString, dbDomain, dbName, dbPassword, dbUserName,
57
+ }
58
+ const params: Partial<MongoDBModuleParamsV2> = {
59
+ meterProvider, payloadSdkConfig, statusReporter, traceProvider,
60
+ }
61
+ // Register the MongoDB Archivist as the default
62
+ locator.register(MongoDBArchivistV2.factory(params), undefined, true)
63
+ }
64
+
65
+ const chainId = isDefined(config.chain.id)
66
+ ? assertEx(asAddress(config.chain.id), () => 'chain.id must be an Address')
67
+ : ZERO_ADDRESS
68
+ locator.register(HeadValidationDiviner.factory<HeadValidationDiviner>({
69
+ traceProvider,
70
+ meterProvider,
71
+ statusReporter,
72
+ chainId,
73
+ allowedProducers: config.producer.allowlist,
74
+ }))
75
+ locator.register(MemoryArchivist.factory({
76
+ traceProvider, meterProvider, statusReporter,
77
+ }))
78
+ locator.register(MemorySentinel.factory({
79
+ traceProvider, meterProvider, statusReporter,
80
+ }))
81
+ locator.register(ViewArchivist.factory({
82
+ traceProvider, meterProvider, statusReporter,
83
+ }))
84
+ return locator
85
+ }
@@ -0,0 +1,32 @@
1
+ import type { Logger } from '@xylabs/logger'
2
+ import { ManifestWrapper } from '@xyo-network/manifest-wrapper'
3
+ import type { WalletInstance } from '@xyo-network/wallet-model'
4
+ import type { Config } from '@xyo-network/xl1-protocol-sdk'
5
+
6
+ import { getLocator } from './getLocator.ts'
7
+ import { NodeManifest } from './nodeManifest.ts'
8
+ import { PrivateChildManifests } from './private/index.ts'
9
+ import { PublicChildManifests } from './public/index.ts'
10
+
11
+ export interface GetNodeContext {
12
+ config: Config
13
+ logger?: Logger
14
+ wallet: WalletInstance
15
+ }
16
+
17
+ /**
18
+ * Creates a node with the xyo-chain modules registered
19
+ * @param context The context to use for the node
20
+ * @returns A node with the xyo-chain modules registered
21
+ */
22
+ export const getNode = async (context: GetNodeContext) => {
23
+ const { wallet } = context
24
+ const locator = await getLocator(context)
25
+ const wrapper = new ManifestWrapper(NodeManifest, wallet, locator, PublicChildManifests, PrivateChildManifests)
26
+ const [node, ...childNodes] = await wrapper.loadNodes()
27
+ if (childNodes?.length > 0) {
28
+ await Promise.all(childNodes.map(childNode => node.register(childNode)))
29
+ await Promise.all(childNodes.map(childNode => node.attach(childNode.address, true)))
30
+ }
31
+ return node
32
+ }
@@ -0,0 +1,5 @@
1
+ export * from './getLocator.ts'
2
+ export * from './getNode.ts'
3
+ export * from './nodeManifest.ts'
4
+ export * from './private/index.ts'
5
+ export * from './public/index.ts'
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/XYOracleNetwork/sdk-xyo-client-js/main/packages/manifest/src/schema.json",
3
+ "nodes": [
4
+ {
5
+ "config": {
6
+ "accountPath": "44'/60'/1",
7
+ "name": "XYOChain",
8
+ "schema": "network.xyo.node.config"
9
+ },
10
+ "modules": {
11
+ "private": [],
12
+ "public": []
13
+ }
14
+ }
15
+ ],
16
+ "schema": "network.xyo.manifest"
17
+ }
@@ -0,0 +1,8 @@
1
+ import type { PackageManifestPayload } from '@xyo-network/manifest-model'
2
+
3
+ import node from './node.json' with { type: 'json' }
4
+
5
+ /**
6
+ * Root Node Manifest
7
+ */
8
+ export const NodeManifest = node as PackageManifestPayload
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Private Child Manifests
3
+ */
4
+ export const PrivateChildManifests = []
@@ -0,0 +1,101 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/XYOracleNetwork/sdk-xyo-client-js/main/packages/manifest/src/schema.json",
3
+ "nodes": [
4
+ {
5
+ "config": {
6
+ "accountPath": "1",
7
+ "name": "Chain",
8
+ "schema": "network.xyo.node.config"
9
+ },
10
+ "modules": {
11
+ "private": [
12
+ {
13
+ "config": {
14
+ "accountPath": "1/1'/1'",
15
+ "name": "Validated",
16
+ "getCache": {
17
+ "enabled": true,
18
+ "maxEntries": 5000
19
+ },
20
+ "payloadSdkConfig": {
21
+ "collection": "chain_validated"
22
+ },
23
+ "schema": "network.xyo.archivist.config"
24
+ }
25
+ },
26
+ {
27
+ "config": {
28
+ "accountPath": "1/1'/2'",
29
+ "schema": "network.xyo.diviner.chain.head.validation.config",
30
+ "eventSubscriptions": [
31
+ {
32
+ "sourceEvent": "inserted",
33
+ "sourceModule": "Submissions",
34
+ "targetModuleFunction": "divine"
35
+ }
36
+ ],
37
+ "inArchivist": "Submissions",
38
+ "outArchivist": "Validated",
39
+ "name": "HeadValidationDiviner"
40
+ }
41
+ },
42
+ {
43
+ "config": {
44
+ "accountPath": "1/1'/3'",
45
+ "automations": [
46
+ {
47
+ "frequency": 1000,
48
+ "frequencyUnits": "millis",
49
+ "schema": "network.xyo.automation.interval",
50
+ "type": "interval"
51
+ }
52
+ ],
53
+ "name": "ChainValidationSentinel",
54
+ "schema": "network.xyo.sentinel.config",
55
+ "synchronous": true,
56
+ "tasks": [
57
+ {
58
+ "mod": "HeadValidationDiviner",
59
+ "endPoint": "divine"
60
+ }
61
+ ]
62
+ }
63
+ }
64
+ ],
65
+ "public": [
66
+ {
67
+ "config": {
68
+ "accountPath": "1/1/1",
69
+ "name": "Submissions",
70
+ "getCache": {
71
+ "enabled": true,
72
+ "maxEntries": 5000
73
+ },
74
+ "payloadSdkConfig": {
75
+ "collection": "chain_submissions"
76
+ },
77
+ "schema": "network.xyo.archivist.config"
78
+ }
79
+ },
80
+ {
81
+ "config": {
82
+ "accountPath": "1/1/2",
83
+ "name": "Finalized",
84
+ "allowedQueries": [
85
+ "network.xyo.query.archivist.get",
86
+ "network.xyo.query.archivist.next"
87
+ ],
88
+ "getCache": {
89
+ "enabled": true,
90
+ "maxEntries": 50000
91
+ },
92
+ "originArchivist": "Validated",
93
+ "schema": "network.xyo.archivist.view.config"
94
+ }
95
+ }
96
+ ]
97
+ }
98
+ }
99
+ ],
100
+ "schema": "network.xyo.manifest"
101
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/XYOracleNetwork/sdk-xyo-client-js/main/packages/manifest/src/schema.json",
3
+ "nodes": [
4
+ {
5
+ "config": {
6
+ "accountPath": "2",
7
+ "name": "Pending",
8
+ "schema": "network.xyo.node.config"
9
+ },
10
+ "modules": {
11
+ "private": [],
12
+ "public": [
13
+ {
14
+ "config": {
15
+ "accountPath": "2/1/1",
16
+ "name": "PendingTransactions",
17
+ "getCache": {
18
+ "enabled": true,
19
+ "maxEntries": 5000
20
+ },
21
+ "labels": {
22
+ "network.xyo.storage.class": "mongodb"
23
+ },
24
+ "payloadSdkConfig": {
25
+ "collection": "pending_bundles"
26
+ },
27
+ "schema": "network.xyo.archivist.config"
28
+ }
29
+ }
30
+ ]
31
+ }
32
+ }
33
+ ],
34
+ "schema": "network.xyo.manifest"
35
+ }
@@ -0,0 +1,20 @@
1
+ import type { ModuleManifest, PackageManifestPayload } from '@xyo-network/manifest-model'
2
+
3
+ import Chain from './Chain.json' with { type: 'json' }
4
+ import Pending from './Pending.json' with { type: 'json' }
5
+
6
+ /**
7
+ * Chain Node Manifest
8
+ */
9
+ export const ChainNodeManifest = Chain as PackageManifestPayload
10
+ /**
11
+ * Pending Node Manifest
12
+ */
13
+ export const PendingNodeManifest = Pending as PackageManifestPayload
14
+ /**
15
+ * Public Child Manifests
16
+ */
17
+ export const PublicChildManifests: ModuleManifest[] = [
18
+ ...ChainNodeManifest.nodes,
19
+ ...PendingNodeManifest.nodes,
20
+ ]
@@ -0,0 +1,32 @@
1
+ import type { MemoryNode } from '@xyo-network/node-memory'
2
+ import { HDWallet } from '@xyo-network/wallet'
3
+ import { getDefaultConfig } from '@xyo-network/xl1-protocol-sdk'
4
+ import {
5
+ beforeAll, describe, expect,
6
+ it,
7
+ } from 'vitest'
8
+
9
+ import { getNode, GetNodeContext } from '../../getNode.ts'
10
+ import { SilentLogger } from '@xylabs/logger'
11
+
12
+ /**
13
+ * @group manifest
14
+ */
15
+ describe('Node', () => {
16
+ let node: MemoryNode
17
+ let context: GetNodeContext
18
+
19
+ beforeAll(async () => {
20
+ const config = getDefaultConfig()
21
+ const logger = new SilentLogger()
22
+ const wallet = await HDWallet.random()
23
+ context = {
24
+ config, logger, wallet,
25
+ }
26
+ // Create a node with the default configuration
27
+ node = await getNode(context)
28
+ })
29
+ it('should return node', () => {
30
+ expect(node).toBeDefined()
31
+ })
32
+ })
@@ -0,0 +1,36 @@
1
+ import {
2
+ customPoweredByHeader,
3
+ disableCaseSensitiveRouting,
4
+ disableExpressDefaultPoweredByHeader,
5
+ getJsonBodyParser,
6
+ getJsonBodyParserOptions,
7
+ responseProfiler,
8
+ standardErrors,
9
+ standardResponses,
10
+ } from '@xylabs/express'
11
+ import type { NodeInstance } from '@xyo-network/node-model'
12
+ import compression from 'compression'
13
+ import cors from 'cors'
14
+ import type { Express } from 'express'
15
+ import express from 'express'
16
+
17
+ import { addInstrumentation } from './instrumentation.ts'
18
+ import { addRoutes } from './routes/index.ts'
19
+
20
+ export const getApp = (node: NodeInstance): Express => {
21
+ addInstrumentation()
22
+ const app = express()
23
+ app.set('etag', false)
24
+ app.use(cors())
25
+ app.use(compression())
26
+ app.use(responseProfiler)
27
+ app.use(getJsonBodyParser(getJsonBodyParserOptions({ limit: '1mb' })))
28
+ app.use(standardResponses)
29
+ disableExpressDefaultPoweredByHeader(app)
30
+ app.use(customPoweredByHeader)
31
+ disableCaseSensitiveRouting(app)
32
+ app.node = node
33
+ addRoutes(app)
34
+ app.use(standardErrors)
35
+ return app
36
+ }
@@ -0,0 +1,13 @@
1
+ export * from './app.ts'
2
+ export * from './server.ts'
3
+
4
+ import type { NodeInstance } from '@xyo-network/node-model'
5
+
6
+ declare global {
7
+ // eslint-disable-next-line @typescript-eslint/no-namespace
8
+ namespace Express {
9
+ interface Application {
10
+ node: NodeInstance
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,15 @@
1
+ import { registerInstrumentations } from '@opentelemetry/instrumentation'
2
+ import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express'
3
+ import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'
4
+
5
+ /**
6
+ * Registers OpenTelemetry instrumentations for HTTP and Express.
7
+ * This function is used to set up the necessary instrumentations for monitoring
8
+ * HTTP requests and Express applications. Since it monkey patches the Express
9
+ * router & middleware system, it should be called before any Express applications
10
+ * are defined.
11
+ */
12
+ export const addInstrumentation = () => {
13
+ const instrumentations = [new HttpInstrumentation(), new ExpressInstrumentation()]
14
+ registerInstrumentations({ instrumentations })
15
+ }
@@ -0,0 +1,11 @@
1
+ import type { Express } from 'express'
2
+
3
+ import { addNodeRoutes } from './address/index.ts'
4
+ import { addDataLakeRoutes } from './dataLake/index.ts'
5
+ import { addHealthRoutes } from './healthz/index.ts'
6
+
7
+ export const addRoutes = (app: Express) => {
8
+ addHealthRoutes(app)
9
+ addDataLakeRoutes(app)
10
+ addNodeRoutes(app)
11
+ }
@@ -0,0 +1,3 @@
1
+ export type AddressPathParams = {
2
+ address: string
3
+ }
@@ -0,0 +1,21 @@
1
+ import type { Express } from 'express'
2
+ import { StatusCodes } from 'http-status-codes'
3
+
4
+ import { getAddress } from './get/index.ts'
5
+ import { postAddress } from './post/index.ts'
6
+
7
+ export const addNodeRoutes = (app: Express) => {
8
+ const defaultModule = app.node
9
+ const address = defaultModule.address
10
+ const defaultModuleEndpoint = `/${address}`
11
+ app.get('/', (_req, res) => res.redirect(StatusCodes.MOVED_TEMPORARILY, defaultModuleEndpoint))
12
+ app.post('/', (_req, res) => res.redirect(StatusCodes.TEMPORARY_REDIRECT, defaultModuleEndpoint))
13
+ app.get('/:address', getAddress)
14
+ app.post('/:address', postAddress)
15
+ app.get('/:hash', (_req, res) => {
16
+ res.sendStatus(StatusCodes.NOT_FOUND)
17
+ })
18
+ app.post('/:hash', (_req, res) => {
19
+ res.sendStatus(StatusCodes.NOT_FOUND)
20
+ })
21
+ }
@@ -0,0 +1,31 @@
1
+ import { asyncHandler } from '@xylabs/express'
2
+ import { asAddress } from '@xylabs/hex'
3
+ import { isDefined } from '@xylabs/typeof'
4
+ import { isModuleName } from '@xyo-network/module-model'
5
+ import type { Payload } from '@xyo-network/payload-model'
6
+ import type { RequestHandler } from 'express'
7
+ import { StatusCodes } from 'http-status-codes'
8
+
9
+ import type { AddressPathParams } from '../AddressPathParams.ts'
10
+
11
+ const handler: RequestHandler<AddressPathParams, Payload[]> = async (req, res, next) => {
12
+ const { address: moduleIdentifier } = req.params
13
+ const { node } = req.app
14
+ const address = asAddress(moduleIdentifier)
15
+ if (isDefined(address)) {
16
+ let mod = node.address === address ? node : (await node.resolve(address, { direction: 'down' }))
17
+ if (mod) {
18
+ res.json(await mod.state())
19
+ return
20
+ }
21
+ }
22
+ if (isModuleName(moduleIdentifier)) {
23
+ const mod = await node.resolve(moduleIdentifier, { direction: 'down' })
24
+ if (mod) {
25
+ res.redirect(StatusCodes.MOVED_TEMPORARILY, `/${mod.address}`)
26
+ return
27
+ }
28
+ }
29
+ next('route')
30
+ }
31
+ export const getAddress = asyncHandler(handler)
@@ -0,0 +1 @@
1
+ export * from './get.ts'
@@ -0,0 +1 @@
1
+ export * from './addNodeRoutes.ts'
@@ -0,0 +1,23 @@
1
+ import type { BoundWitness, QueryBoundWitness } from '@xyo-network/boundwitness-model'
2
+ import { BoundWitnessSchema } from '@xyo-network/boundwitness-model'
3
+ import type { ModuleConfig, ModuleInstance } from '@xyo-network/module-model'
4
+ import { ModuleConfigSchema } from '@xyo-network/module-model'
5
+ import type { Payload } from '@xyo-network/payload-model'
6
+ import type { Request } from 'express'
7
+
8
+ const DEFAULT_DEPTH = 5 as const
9
+
10
+ export const getQueryConfig = (mod: ModuleInstance, req: Request, bw: QueryBoundWitness, payloads?: Payload[]): ModuleConfig | undefined => {
11
+ // TODO: Filter based on query addresses?
12
+ // Recurse through payloads for nested BWs
13
+ const nestedBwAddresses
14
+ = payloads
15
+ ?.flat(DEFAULT_DEPTH)
16
+ .filter<BoundWitness>((payload): payload is BoundWitness => payload?.schema === BoundWitnessSchema)
17
+ .map(bw => bw.addresses) ?? []
18
+ // TODO: Do we want to end up with a list of addresses or a list of address lists?
19
+ const addresses = [bw.addresses, ...nestedBwAddresses].filter(address => address.length > 0)
20
+ const allowed = addresses.length > 0 ? Object.fromEntries(mod.queries.map(schema => [schema, addresses])) : {}
21
+ const security = { allowed }
22
+ return { schema: ModuleConfigSchema, security }
23
+ }
@@ -0,0 +1 @@
1
+ export * from './post.ts'
@@ -0,0 +1,77 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { asyncHandler } from '@xylabs/express'
3
+ import {
4
+ asAddress, isAddress,
5
+ toAddress,
6
+ } from '@xylabs/hex'
7
+ import type { JsonObject } from '@xylabs/object'
8
+ import { isQueryBoundWitness, type QueryBoundWitness } from '@xyo-network/boundwitness-model'
9
+ import { ModuleErrorBuilder } from '@xyo-network/module-abstract'
10
+ import type { ModuleInstance, ModuleQueryResult } from '@xyo-network/module-model'
11
+ import type { ModuleError, Payload } from '@xyo-network/payload-model'
12
+ import type { RequestHandler } from 'express'
13
+ import { StatusCodes } from 'http-status-codes'
14
+
15
+ import type { AddressPathParams } from '../AddressPathParams.ts'
16
+ import { getQueryConfig } from './getQueryConfig.ts'
17
+
18
+ type PostAddressRequestBody = [QueryBoundWitness, undefined | Payload[]]
19
+
20
+ const handler: RequestHandler<AddressPathParams, ModuleQueryResult | ModuleError, PostAddressRequestBody> = async (req, res, next) => {
21
+ const returnError = (code: number, message = 'An error occurred', details?: JsonObject) => {
22
+ const error = new ModuleErrorBuilder().message(message).details(details).build()
23
+ res.locals.rawResponse = false
24
+ res.status(code).json(error)
25
+ next()
26
+ }
27
+
28
+ const { address } = req.params
29
+ const { node } = req.app
30
+ const [bw, payloads] = Array.isArray(req.body) ? req.body : []
31
+ if (!isAddress(address)) {
32
+ return returnError(StatusCodes.BAD_REQUEST, 'Missing address')
33
+ }
34
+
35
+ if (!bw) {
36
+ return returnError(StatusCodes.BAD_REQUEST, 'Missing boundwitness')
37
+ }
38
+
39
+ if (!isQueryBoundWitness(bw)) {
40
+ return returnError(StatusCodes.BAD_REQUEST, 'Invalid query boundwitness')
41
+ }
42
+
43
+ let modules: ModuleInstance[] = []
44
+ const normalizedAddress = toAddress(address)
45
+ if (node.address === normalizedAddress) modules = [node]
46
+ else {
47
+ const typedAddress = asAddress(address)
48
+ const byAddress = (typedAddress === undefined) ? undefined : await node.resolve(typedAddress, { maxDepth: 10 })
49
+
50
+ if (byAddress) modules = [byAddress]
51
+ else {
52
+ const byName = await node.resolve(address, { direction: 'down' })
53
+ if (byName) {
54
+ const moduleAddress = assertEx(byName?.address, () => 'Error redirecting to module by address')
55
+ res.redirect(StatusCodes.TEMPORARY_REDIRECT, `/${moduleAddress}`)
56
+ return
57
+ } else {
58
+ return returnError(StatusCodes.NOT_FOUND, 'Module not found', { address })
59
+ }
60
+ }
61
+ }
62
+
63
+ if (modules.length > 0) {
64
+ const mod = modules[0]
65
+ const queryConfig = getQueryConfig(mod, req, bw, payloads)
66
+ try {
67
+ const queryResult = await mod.query(bw, payloads, queryConfig)
68
+ res.json(queryResult)
69
+ } catch (ex) {
70
+ return returnError(StatusCodes.INTERNAL_SERVER_ERROR, 'Query Failed', { message: (ex as Error)?.message ?? 'Unknown Error' })
71
+ }
72
+ } else {
73
+ return returnError(StatusCodes.NOT_FOUND, 'Module not found', { address })
74
+ }
75
+ }
76
+
77
+ export const postAddress = asyncHandler(handler)
@@ -0,0 +1,9 @@
1
+ import type { Express } from 'express'
2
+
3
+ import { archivistMiddleware } from './archivistMiddleware.ts'
4
+
5
+ export const addDataLakeRoutes = (app: Express) => {
6
+ const { node } = app
7
+ const archivistModuleIdentifier = 'Chain:Finalized'
8
+ app.use('/chain', archivistMiddleware({ node, archivistModuleIdentifier }))
9
+ }