@xyo-network/os-runtime 3.0.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 (132) hide show
  1. package/LICENSE +165 -0
  2. package/README.md +13 -0
  3. package/dist/neutral/index.d.ts +1656 -0
  4. package/dist/neutral/index.mjs +3432 -0
  5. package/dist/neutral/index.mjs.map +1 -0
  6. package/package.json +78 -0
  7. package/src/Caller.ts +221 -0
  8. package/src/DappCallerBase.ts +52 -0
  9. package/src/DefaultsQueries.ts +27 -0
  10. package/src/OsCallerBase.ts +55 -0
  11. package/src/PubSubBridgeCaller.ts +30 -0
  12. package/src/XyOs.ts +125 -0
  13. package/src/XyOsBase.ts +119 -0
  14. package/src/XyOsDapp.ts +90 -0
  15. package/src/access-interfaces/ValidDappAccessInterfaces.ts +8 -0
  16. package/src/access-interfaces/index.ts +2 -0
  17. package/src/access-interfaces/registered-names/helpers/AccessNodeQueries.ts +59 -0
  18. package/src/access-interfaces/registered-names/helpers/index.ts +2 -0
  19. package/src/access-interfaces/registered-names/helpers/resource/AbstractXnsCaller.ts +38 -0
  20. package/src/access-interfaces/registered-names/helpers/resource/RegistrationsResource.ts +54 -0
  21. package/src/access-interfaces/registered-names/helpers/resource/RegistrationsResourceQueries.ts +22 -0
  22. package/src/access-interfaces/registered-names/helpers/resource/index.ts +3 -0
  23. package/src/access-interfaces/registered-names/index.ts +1 -0
  24. package/src/adapter/Base.ts +96 -0
  25. package/src/adapter/Network.ts +31 -0
  26. package/src/adapter/Settings.ts +30 -0
  27. package/src/adapter/index.ts +2 -0
  28. package/src/adapters/OsPubSubBridgeNetwork.ts +10 -0
  29. package/src/adapters/OsSettings.ts +7 -0
  30. package/src/adapters/OsXyoPublicNetwork.ts +9 -0
  31. package/src/adapters/index.ts +3 -0
  32. package/src/classes/cache/RunningAccessDappCache.ts +21 -0
  33. package/src/classes/cache/RunningDappCache.ts +50 -0
  34. package/src/classes/cache/index.ts +2 -0
  35. package/src/classes/dapp/DefaultsResource.ts +65 -0
  36. package/src/classes/dapp/access/Caller.ts +73 -0
  37. package/src/classes/dapp/access/Queries.ts +38 -0
  38. package/src/classes/dapp/access/Resource.ts +63 -0
  39. package/src/classes/dapp/access/index.ts +3 -0
  40. package/src/classes/dapp/index.ts +2 -0
  41. package/src/classes/index.ts +8 -0
  42. package/src/classes/lib/DappCreatorParams.ts +16 -0
  43. package/src/classes/lib/Insertable.ts +14 -0
  44. package/src/classes/lib/index.ts +2 -0
  45. package/src/classes/menu/Caller.ts +76 -0
  46. package/src/classes/menu/Queries.ts +59 -0
  47. package/src/classes/menu/Resource.ts +103 -0
  48. package/src/classes/menu/index.ts +2 -0
  49. package/src/classes/node/Creator.ts +96 -0
  50. package/src/classes/node/DefaultPayloads/DappAccessPayloads.ts +17 -0
  51. package/src/classes/node/DefaultPayloads/DefaultPayloads.ts +33 -0
  52. package/src/classes/node/DefaultPayloads/NodeInfoPayload.ts +27 -0
  53. package/src/classes/node/DefaultPayloads/SigningKeyPayloads.ts +85 -0
  54. package/src/classes/node/DefaultPayloads/index.ts +1 -0
  55. package/src/classes/node/ExternalModulePermissions/ExternalModulePermissions.ts +47 -0
  56. package/src/classes/node/ExternalModulePermissions/index.ts +1 -0
  57. package/src/classes/node/createDappContext.ts +52 -0
  58. package/src/classes/node/index.ts +3 -0
  59. package/src/classes/registration/DappRegistrationService.ts +146 -0
  60. package/src/classes/registration/DappRegistry.ts +121 -0
  61. package/src/classes/registration/ValidateDappAccessDiviner/Config.ts +19 -0
  62. package/src/classes/registration/ValidateDappAccessDiviner/Diviner.ts +132 -0
  63. package/src/classes/registration/ValidateDappAccessDiviner/index.ts +2 -0
  64. package/src/classes/registration/index.ts +2 -0
  65. package/src/classes/settings/Caller.ts +76 -0
  66. package/src/classes/settings/CallerBase.ts +24 -0
  67. package/src/classes/settings/Resource.ts +79 -0
  68. package/src/classes/settings/SettingsQueries.ts +38 -0
  69. package/src/classes/settings/badge/Caller.ts +30 -0
  70. package/src/classes/settings/badge/Queries.ts +18 -0
  71. package/src/classes/settings/badge/Resource.ts +54 -0
  72. package/src/classes/settings/badge/index.ts +2 -0
  73. package/src/classes/settings/index.ts +5 -0
  74. package/src/classes/system/ManageSystemDapps.ts +131 -0
  75. package/src/classes/system/Queries.ts +69 -0
  76. package/src/classes/system/index.ts +1 -0
  77. package/src/event/bus/Connection.ts +31 -0
  78. package/src/event/bus/EventBus.ts +145 -0
  79. package/src/event/bus/PubSubConnection.ts +28 -0
  80. package/src/event/bus/index.ts +3 -0
  81. package/src/event/connections/DappAccessRequest.ts +11 -0
  82. package/src/event/connections/DappsReady.ts +9 -0
  83. package/src/event/connections/ExposeDappRequest.ts +11 -0
  84. package/src/event/connections/OsPubSubNetworkReady.ts +12 -0
  85. package/src/event/connections/OsSettingsReady.ts +12 -0
  86. package/src/event/connections/OsXyoPublicReady.ts +12 -0
  87. package/src/event/connections/index.ts +6 -0
  88. package/src/event/index.ts +2 -0
  89. package/src/helpers/index.ts +1 -0
  90. package/src/helpers/monitor/XyOsMonitor.ts +52 -0
  91. package/src/helpers/monitor/index.ts +2 -0
  92. package/src/helpers/monitor/types.ts +5 -0
  93. package/src/index.ts +22 -0
  94. package/src/intent/Caller.ts +72 -0
  95. package/src/intent/Resource.ts +66 -0
  96. package/src/intent/index.ts +2 -0
  97. package/src/lib/ExternalStore.ts +7 -0
  98. package/src/lib/Listener.ts +1 -0
  99. package/src/lib/ModuleAccountPaths.ts +29 -0
  100. package/src/lib/ModuleNames.ts +3 -0
  101. package/src/lib/NameTransforms.ts +31 -0
  102. package/src/lib/PayloadStore.ts +98 -0
  103. package/src/lib/ResourceStores.ts +7 -0
  104. package/src/lib/index.ts +10 -0
  105. package/src/lib/initializeXns.ts +16 -0
  106. package/src/lib/isPayload.ts +24 -0
  107. package/src/lib/tokenPlacesSplit.ts +17 -0
  108. package/src/loadOsNode.ts +43 -0
  109. package/src/manifest/ManifestReplaceableTokens.ts +17 -0
  110. package/src/manifest/index.ts +2 -0
  111. package/src/manifest/os-node.manifest.json +132 -0
  112. package/src/manifests/dapp-window.manifest.json +36 -0
  113. package/src/manifests/index.ts +1 -0
  114. package/src/profileModuleEvents.ts +43 -0
  115. package/src/stack/Base.ts +153 -0
  116. package/src/stack/Manager.ts +48 -0
  117. package/src/stack/Map.ts +20 -0
  118. package/src/stack/OsPubSubNetworkStack.ts +70 -0
  119. package/src/stack/OsSettingsStack.ts +24 -0
  120. package/src/stack/XyoPublicNetworkStack.ts +32 -0
  121. package/src/stack/index.ts +6 -0
  122. package/src/types/global.d.ts +9 -0
  123. package/src/types/images.d.ts +5 -0
  124. package/src/utils/buildWalletSeedPhrasePayload.ts +41 -0
  125. package/src/utils/getApiDomain.ts +14 -0
  126. package/src/utils/index.ts +3 -0
  127. package/src/utils/renameObjKey.ts +22 -0
  128. package/src/wallet/DappSeedPhraseRepository.ts +95 -0
  129. package/src/wallet/SeedPhraseRepository.ts +32 -0
  130. package/src/wallet/index.ts +2 -0
  131. package/typedoc.json +5 -0
  132. package/xy.config.ts +10 -0
@@ -0,0 +1,98 @@
1
+ import type { ArchivistInstance, ArchivistModuleEventData } from '@xyo-network/archivist'
2
+ import type { Payload, WithMeta, WithSources } from '@xyo-network/payload-model'
3
+
4
+ import type { ExternalStore } from './ExternalStore.ts'
5
+ import type { Listener } from './Listener.ts'
6
+
7
+ export interface PayloadStoreConfig<T extends Payload = Payload> {
8
+ archivist: ArchivistInstance
9
+ getLatest: () => Promise<WithMeta<WithSources<T>>[]>
10
+ idFunction: (schema: Payload) => boolean
11
+ }
12
+
13
+ export class PayloadStore<T extends Payload = Payload> implements ExternalStore {
14
+ latest: WithMeta<T>[] = []
15
+ private deleteListeners: WeakRef<(args: ArchivistModuleEventData['deleted']) => void>[] = []
16
+ private insertListeners: WeakRef<(args: ArchivistModuleEventData['inserted']) => void>[] = []
17
+ private listeners: Listener[] = []
18
+
19
+ private constructor(private archivist: ArchivistInstance) {}
20
+
21
+ /**
22
+ * Initialize listeners on the archivist that update class member variables when new payloads are inserted
23
+ */
24
+ static async create<T extends Payload = Payload>({ archivist, getLatest, idFunction }: PayloadStoreConfig<T>) {
25
+ const instance = new this<T>(archivist)
26
+
27
+ const insertListener = async ({ payloads }: ArchivistModuleEventData['inserted']) => {
28
+ // if any of the newly inserted payloads pass the idFunction check, rerun the query
29
+ if (payloads.some(idFunction)) {
30
+ instance.latest = await getLatest()
31
+ instance.emitChange()
32
+ }
33
+ }
34
+
35
+ // when payloads are deleted, rerun the diviner query
36
+ const deleteListener = async () => {
37
+ instance.latest = await getLatest()
38
+ instance.emitChange()
39
+ }
40
+
41
+ const weakRefInsertListener = new WeakRef(insertListener)
42
+ const weakRefDeleteListener = new WeakRef(deleteListener)
43
+ const insertListenerRef = weakRefInsertListener.deref()
44
+ const deleteListenerRef = weakRefDeleteListener.deref()
45
+
46
+ if (insertListenerRef) instance.archivist.on('inserted', insertListenerRef)
47
+ if (deleteListenerRef) instance.archivist.on('deleted', deleteListenerRef)
48
+
49
+ instance.insertListeners.push(weakRefInsertListener)
50
+ instance.deleteListeners.push(weakRefDeleteListener)
51
+
52
+ instance.latest = await getLatest()
53
+ return instance
54
+ }
55
+
56
+ /**
57
+ * Remove all listeners and reset their class members
58
+ */
59
+ cleanupListeners() {
60
+ this.removeListeners(this.insertListeners, 'inserted')
61
+ this.removeListeners(this.deleteListeners, 'deleted')
62
+ this.insertListeners = []
63
+ this.deleteListeners = []
64
+ }
65
+
66
+ /**
67
+ * Get the current value of the store
68
+ */
69
+ getSnapshot(): WithMeta<WithSources<T>>[] {
70
+ return this.latest
71
+ }
72
+
73
+ /**
74
+ * Add a call back function that is invoked when new Payloads are inserted
75
+ *
76
+ * @param {PayloadListener} onStoreChange
77
+ */
78
+ subscribe(onStoreChange: Listener) {
79
+ this.listeners.push(onStoreChange)
80
+ return () => {
81
+ this.listeners = this.listeners.filter(l => l !== onStoreChange)
82
+ }
83
+ }
84
+
85
+ private emitChange() {
86
+ for (const listener of this.listeners) {
87
+ listener()
88
+ }
89
+ }
90
+
91
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
92
+ private removeListeners(listeners: WeakRef<(args: any) => void>[], eventName: string) {
93
+ for (const listener of listeners) {
94
+ const listenerRef = listener.deref()
95
+ if (listenerRef) this.archivist.off(eventName, listenerRef)
96
+ }
97
+ }
98
+ }
@@ -0,0 +1,7 @@
1
+ import type { ExternalStore } from './ExternalStore.ts'
2
+
3
+ export interface ResourceStore<Name extends string = string> {
4
+ cleanupListeners: () => void
5
+ subscriptions: Record<Name, ExternalStore['subscribe']>
6
+ views: Record<Name, ExternalStore['getSnapshot']>
7
+ }
@@ -0,0 +1,10 @@
1
+ export * from './ExternalStore.ts'
2
+ export * from './initializeXns.ts'
3
+ export * from './isPayload.ts'
4
+ export * from './Listener.ts'
5
+ export * from './ModuleAccountPaths.ts'
6
+ export * from './ModuleNames.ts'
7
+ export * from './NameTransforms.ts'
8
+ export * from './PayloadStore.ts'
9
+ export * from './ResourceStores.ts'
10
+ export * from './tokenPlacesSplit.ts'
@@ -0,0 +1,16 @@
1
+ import { asDivinerInstance } from '@xyo-network/diviner-model'
2
+ import { ResolveHelper } from '@xyo-network/module-model'
3
+ import { NameRegistrarTransformer } from '@xyo-network/module-resolver'
4
+ import type { NodeInstance } from '@xyo-network/node-model'
5
+
6
+ export const initializeXns = async (xnsNode: NodeInstance) => {
7
+ if (ResolveHelper.transformers.length === 0) {
8
+ const registrarDiviner = asDivinerInstance(await xnsNode?.resolve('AddressRecords:AddressRecordIndexDiviner'))
9
+ if (registrarDiviner) {
10
+ const transformer = new NameRegistrarTransformer(registrarDiviner, 'xyo')
11
+ ResolveHelper.transformers = [transformer]
12
+ return true
13
+ }
14
+ }
15
+ return false
16
+ }
@@ -0,0 +1,24 @@
1
+ import { AsObjectFactory } from '@xylabs/object'
2
+ import type { Payload, Schema } from '@xyo-network/payload-model'
3
+
4
+ export const isObject = (x: unknown): x is Record<string | symbol | number, unknown> => {
5
+ return typeof x === 'object' && !Array.isArray(x)
6
+ }
7
+
8
+ export const isAnyPayload = (obj: unknown): obj is Payload => {
9
+ if (isObject(obj)) {
10
+ return typeof obj.schema === 'string'
11
+ }
12
+ return false
13
+ }
14
+
15
+ export const isPayload
16
+ = <T extends Payload>(schema: Schema[]) =>
17
+ (obj: unknown): obj is T => {
18
+ if (isAnyPayload(obj)) {
19
+ return schema.includes(obj.schema)
20
+ }
21
+ return false
22
+ }
23
+
24
+ export const asPayload = <T extends Payload>(schema: Schema[]) => AsObjectFactory.create(isPayload<T>(schema))
@@ -0,0 +1,17 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+
3
+ export const tokenPlacesSplit = (value: bigint, places: number): [bigint, bigint] => {
4
+ assertEx(places >= 0, () => 'Places has to be >= 0')
5
+ const factor = BigInt(10 ** Math.abs(places))
6
+ const remainder = value % factor
7
+ const wholeValue = value / factor
8
+ return [wholeValue, remainder]
9
+ }
10
+
11
+ export const tokenPlacesSplitString = (value: bigint | undefined, places: number): string => {
12
+ if (value === undefined) {
13
+ return '-'
14
+ }
15
+ const [wholeValue, remainder] = tokenPlacesSplit(value, places)
16
+ return `${wholeValue}.${remainder.toString().padStart(Math.abs(places), '0')}`
17
+ }
@@ -0,0 +1,43 @@
1
+ import type { WalletInstance } from '@xyo-network/account'
2
+ import { IndexedDbArchivist } from '@xyo-network/archivist-indexeddb'
3
+ import { IndexedDbPayloadDiviner } from '@xyo-network/diviner-payload-indexeddb'
4
+ import type { PackageManifestPayload } from '@xyo-network/manifest'
5
+ import { ManifestWrapper } from '@xyo-network/manifest-wrapper'
6
+ import { ModuleFactoryLocator } from '@xyo-network/module-factory-locator'
7
+ import type { AttachableNodeInstance } from '@xyo-network/node-model'
8
+
9
+ import { osNodeManifest } from './manifest/index.ts'
10
+
11
+ // NOTE: Path "0'" is reserved for the exposed node in the kernel
12
+ const OS_NODE_PATH = "1'"
13
+
14
+ const getDefaultOsNodeLocator = (): ModuleFactoryLocator => {
15
+ const locator = new ModuleFactoryLocator()
16
+ locator.register(IndexedDbArchivist, { 'network.xyo.archivist.persistence.scope': 'device' })
17
+ locator.register(IndexedDbPayloadDiviner, { 'network.xyo.archivist.persistence.scope': 'device' })
18
+ return locator
19
+ }
20
+
21
+ export const loadOsNode = async (
22
+ osWallet: WalletInstance,
23
+ locator?: ModuleFactoryLocator,
24
+ ): Promise<[AttachableNodeInstance]> => {
25
+ try {
26
+ // Create wallets for the OS & kernel nodes
27
+ const osNodeWallet = await osWallet.derivePath(OS_NODE_PATH)
28
+
29
+ // Create the OS node manifest
30
+ const osNodeLocator: ModuleFactoryLocator = locator ?? getDefaultOsNodeLocator()
31
+ const manifestWrapper = new ManifestWrapper(osNodeManifest as PackageManifestPayload, osNodeWallet, osNodeLocator)
32
+
33
+ // Create the OS & kernel nodes
34
+ const osNode = (await manifestWrapper.loadNodes())[0]
35
+
36
+ return [osNode]
37
+ } catch (e) {
38
+ const error = e as Error
39
+ console.error(`Error creating os node: ${error.message}`)
40
+ console.error(`Error creating os node: ${error.stack}`)
41
+ throw new Error(`Error creating os node: ${error.message}`)
42
+ }
43
+ }
@@ -0,0 +1,17 @@
1
+ import { getXnsDomain } from '@xyo-network/kernel'
2
+ import type { Payload } from '@xyo-network/payload-model'
3
+
4
+ export const ManifestReplaceableTokens = (xnsNodeUrl: string | undefined, xnsNetwork: string | undefined) => ({
5
+ '[REPLACE_WITH_NS_NODE_URL]': getXnsDomain(xnsNodeUrl, xnsNetwork),
6
+ })
7
+
8
+ export const ReplaceManifestTokens = (manifest: Payload, xnsNodeUrl: string | undefined, xnsNetwork: string | undefined) => {
9
+ // Replace ReplaceableTokens in the manifest
10
+ let stringifiedManifestReplaced = JSON.stringify(manifest)
11
+
12
+ for (const [token, value] of Object.entries(ManifestReplaceableTokens(xnsNodeUrl, xnsNetwork))) {
13
+ stringifiedManifestReplaced = stringifiedManifestReplaced.replaceAll(token, value)
14
+ }
15
+
16
+ return JSON.parse(stringifiedManifestReplaced)
17
+ }
@@ -0,0 +1,2 @@
1
+ export * from './ManifestReplaceableTokens.ts'
2
+ export { default as osNodeManifest } from './os-node.manifest.json'
@@ -0,0 +1,132 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/XYOracleNetwork/sdk-xyo-client-js/main/packages/manifest/src/compilations/dapp-package-manifest-schema.json",
3
+ "nodes": [
4
+ {
5
+ "config": {
6
+ "accountPath": "0'",
7
+ "name": "OsNode",
8
+ "schema": "network.xyo.node.config"
9
+ },
10
+ "modules": {
11
+ "private": [],
12
+ "public": [
13
+ {
14
+ "config": {
15
+ "accountPath": "1'",
16
+ "name": "OSArchivist",
17
+ "dbName": "OSArchivist",
18
+ "labels": {
19
+ "network.xyo.archivist.persistence.scope": "device"
20
+ },
21
+ "storeName": "payloads",
22
+ "parents": {
23
+ "read": [
24
+ "Archivist"
25
+ ]
26
+ },
27
+ "schema": "network.xyo.archivist.config"
28
+ }
29
+ },
30
+ {
31
+ "config": {
32
+ "accountPath": "3'",
33
+ "name": "DappsArchivist",
34
+ "dbName": "DappsArchivist",
35
+ "labels": {
36
+ "network.xyo.archivist.persistence.scope": "device"
37
+ },
38
+ "storeName": "payloads",
39
+ "schema": "network.xyo.archivist.config"
40
+ }
41
+ },
42
+ {
43
+ "config": {
44
+ "archivist": "DappsArchivist",
45
+ "dbVersion": 1,
46
+ "name": "DappsArchivistPayloadDiviner",
47
+ "labels": {
48
+ "network.xyo.archivist.persistence.scope": "device"
49
+ },
50
+ "schema": "network.xyo.diviner.payload.config"
51
+ }
52
+ },
53
+ {
54
+ "config": {
55
+ "accountPath": "4'",
56
+ "dbName": "IntentArchivist",
57
+ "name": "IntentArchivist",
58
+ "storeName": "payloads",
59
+ "labels": {
60
+ "network.xyo.archivist.persistence.scope": "device"
61
+ },
62
+ "schema": "network.xyo.archivist.config"
63
+ }
64
+ },
65
+ {
66
+ "config": {
67
+ "accountPath": "7",
68
+ "archivist": "IntentArchivist",
69
+ "dbVersion": 1,
70
+ "name": "IntentArchivistPayloadDiviner",
71
+ "labels": {
72
+ "network.xyo.archivist.persistence.scope": "device"
73
+ },
74
+ "schema": "network.xyo.diviner.payload.config",
75
+ "storeName": "payloads"
76
+ }
77
+ },
78
+ {
79
+ "config": {
80
+ "accountPath": "8",
81
+ "name": "RegisteredDappInterfacesArchivist",
82
+ "schema": "network.xyo.archivist.memory.config"
83
+ }
84
+ },
85
+ {
86
+ "config": {
87
+ "accountPath": "9'",
88
+ "name": "DappsArchivistDevelopment",
89
+ "parents": {
90
+ "write": [
91
+ "DappsArchivist"
92
+ ]
93
+ },
94
+ "schema": "network.xyo.archivist.memory.config"
95
+ }
96
+ },
97
+ {
98
+ "config": {
99
+ "accountPath": "10",
100
+ "archivist": "DappsArchivistDevelopment",
101
+ "dbVersion": 1,
102
+ "name": "DappsArchivistPayloadDivinerDevelopment",
103
+ "labels": {
104
+ "network.xyo.generic.payload.diviner": "GenericPayloadDiviner"
105
+ },
106
+ "schema": "network.xyo.diviner.payload.generic.config"
107
+ }
108
+ },
109
+ {
110
+ "config": {
111
+ "name": "OsPubSubNetworkStackNode",
112
+ "schema": "network.xyo.node.config"
113
+ }
114
+ },
115
+ {
116
+ "config": {
117
+ "name": "OsSettingsStackNode",
118
+ "schema": "network.xyo.node.config"
119
+ }
120
+ },
121
+ {
122
+ "config": {
123
+ "name": "OsXyoPublicNetworkStackNode",
124
+ "schema": "network.xyo.node.config"
125
+ }
126
+ }
127
+ ]
128
+ }
129
+ }
130
+ ],
131
+ "schema": "network.xyo.manifest.package.dapp"
132
+ }
@@ -0,0 +1,36 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/XYOracleNetwork/sdk-xyo-client-js/main/packages/manifest/src/compilations/dapp-package-manifest-schema.json",
3
+ "nodes": [
4
+ {
5
+ "config": {
6
+ "accountPath": "0'",
7
+ "name": "Dapp",
8
+ "schema": "network.xyo.node.config"
9
+ },
10
+ "modules": {
11
+ "private": [],
12
+ "public": [
13
+ {
14
+ "config": {
15
+ "accountPath": "0'/0'",
16
+ "name": "DappArchivist",
17
+ "schema": "network.xyo.archivist.memory.config"
18
+ }
19
+ },
20
+ {
21
+ "config": {
22
+ "accountPath": "0'/1'",
23
+ "archivist": "DappArchivist",
24
+ "labels": {
25
+ "network.xyo.generic.payload.diviner": "GenericPayloadDiviner"
26
+ },
27
+ "name": "DappArchivistPayloadDiviner",
28
+ "schema": "network.xyo.diviner.payload.config"
29
+ }
30
+ }
31
+ ]
32
+ }
33
+ }
34
+ ],
35
+ "schema": "network.xyo.manifest.package.dapp"
36
+ }
@@ -0,0 +1 @@
1
+ export { default as DappWindowManifest } from './dapp-window.manifest.json'
@@ -0,0 +1,43 @@
1
+ import type { Address } from '@xylabs/hex'
2
+ import type { QuerySendStartedEventArgs } from '@xyo-network/bridge-model'
3
+ import type { ModuleInstance } from '@xyo-network/module-model'
4
+ import { PayloadBuilder } from '@xyo-network/payload-builder'
5
+
6
+ const DISPLAY_EVENT_COUNT_FREQUENCY = 100 as const
7
+
8
+ export interface ProfileEventsData {
9
+ allEventCount: number
10
+ eventCounts: { [key: string | number | symbol]: number }
11
+ }
12
+
13
+ export const profileData: Record<Address, ProfileEventsData> = {}
14
+
15
+ export const profileModuleEvents = (mod: ModuleInstance) => {
16
+ const modRef = new WeakRef(mod) // prevent memory leak
17
+ mod.onAny(async (eventName, args) => {
18
+ const mod = modRef.deref()
19
+ if (mod) {
20
+ const data = profileData[mod.address] ?? { allEventCount: 0, eventCounts: {} }
21
+ profileData[mod.address] = data
22
+ data.allEventCount += 1
23
+ data.eventCounts[eventName] = (data.eventCounts[eventName] ?? 0) + 1
24
+ if (eventName === 'querySendStarted') {
25
+ const { query, payloads = [] } = args as QuerySendStartedEventArgs
26
+ const pairs = await PayloadBuilder.dataHashPairs(payloads)
27
+ const foundPair = pairs.find(([, hash]) => hash === query.query)
28
+ if (foundPair) {
29
+ const [payload] = foundPair
30
+ console.log(`querySendStarted: ${payload.schema}`)
31
+ }
32
+ }
33
+ if (eventName === 'querySendFinished') {
34
+ const { query } = args as QuerySendStartedEventArgs
35
+ console.log(`querySendFinished: ${query.query}`)
36
+ }
37
+ if (data.allEventCount % DISPLAY_EVENT_COUNT_FREQUENCY === 0) {
38
+ console.log(`[PROFILE] - ${mod.id} Event Counts:`)
39
+ console.log(data.eventCounts)
40
+ }
41
+ }
42
+ })
43
+ }
@@ -0,0 +1,153 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { forget } from '@xylabs/forget'
3
+ import type { BaseParams } from '@xylabs/object'
4
+ import { BaseEmitter } from '@xyo-network/module-abstract'
5
+ import type { ModuleIdentifier } from '@xyo-network/module-model'
6
+ import { isModuleInstance } from '@xyo-network/module-model'
7
+ import type { AttachableNodeInstance } from '@xyo-network/node-model'
8
+ import { asAttachableNodeInstance } from '@xyo-network/node-model'
9
+ import type { AdapterSetCreator, NodeAdapter, NodeAdapterBaseEvents, StackBaseEvents, StackInitializer, XyOsContext } from '@xyo-network/os-model'
10
+
11
+ /**
12
+ * Stack Base Class
13
+ *
14
+ * Listens for changes in adapter connections, update the stack node, and emits events when the stack is ready
15
+ */
16
+ export class StackBase extends BaseEmitter<BaseParams, StackBaseEvents> implements StackInitializer {
17
+ // flag to check that all adapters are initialized
18
+ initialized = false
19
+
20
+ // adapters to initialize into the stack
21
+ private _adapterSet: NodeAdapter[]
22
+
23
+ private _context: XyOsContext
24
+
25
+ // stack node
26
+ private _stack: AttachableNodeInstance | undefined
27
+
28
+ // stack node module identifier for the stack
29
+ private _stackNodeModuleId: ModuleIdentifier
30
+
31
+ // list of initialized nodes
32
+ private initializedNodes: AttachableNodeInstance[] = []
33
+
34
+ // list of listeners - lister type not important since its only recalled to stop listening
35
+
36
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
+ private listeners: { adapter: NodeAdapter; eventName: string; listener: (args: any) => void }[] = []
38
+
39
+ constructor(context: XyOsContext, adapterSet: AdapterSetCreator, stackNodeModuleId: ModuleIdentifier) {
40
+ super({})
41
+ this._context = context
42
+ this._adapterSet = adapterSet(assertEx(this.context.kernel, 'Kernel access required'))
43
+ this._stackNodeModuleId = stackNodeModuleId
44
+ }
45
+
46
+ get adapterSet(): NodeAdapter[] {
47
+ return assertEx(this._adapterSet, () => `${this.stackNodeModuleId} adapters not initialized`)
48
+ }
49
+
50
+ get context(): XyOsContext {
51
+ return assertEx(this._context, () => `${this.stackNodeModuleId} stack context not initialized`)
52
+ }
53
+
54
+ get stack(): AttachableNodeInstance {
55
+ return assertEx(this._stack, () => `${this.stackNodeModuleId} stack node not initialized`)
56
+ }
57
+
58
+ get stackNodeModuleId(): ModuleIdentifier {
59
+ return assertEx(this._stackNodeModuleId, () => 'Stack node module identifier not initialized')
60
+ }
61
+
62
+ initialize() {
63
+ this.assignStack()
64
+ // watch for adapter connection changes
65
+ for (const adapter of this.adapterSet) {
66
+ // listen for driver ready events
67
+ const driverReadyListener = async ({ node }: NodeAdapterBaseEvents['driverReady']) => await this.handleDriverReady(node)
68
+ adapter.on('driverReady', driverReadyListener)
69
+ this.listeners.push({ adapter: adapter, eventName: 'driverReady', listener: driverReadyListener })
70
+
71
+ // listen for driver error events
72
+ const driverErrorListener = async ({ error }: NodeAdapterBaseEvents['driverError']) => {
73
+ console.error(`Error updating ${this.stackNodeModuleId} stack node`, error)
74
+ await this.emit('driverError', { error })
75
+ }
76
+ adapter.on('driverError', driverErrorListener)
77
+ this.listeners.push({ adapter: adapter, eventName: 'driverError', listener: driverErrorListener })
78
+
79
+ // start the adapter
80
+ const startAdapter = async () => await adapter.start()
81
+ forget(startAdapter())
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Stops the stack
87
+ */
88
+ stop() {
89
+ for (const { eventName, listener, adapter } of this.listeners) {
90
+ // stop the adapter
91
+ adapter.off(eventName, listener)
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Adds a node to the stack. Idempotent to avoid adding the
97
+ * same node multiple times
98
+ * @param node The node to add to the stack
99
+ * @returns
100
+ */
101
+ private async addNodeToStackNode(node: AttachableNodeInstance) {
102
+ // Locate the stack node
103
+ const stackNode = await this.getStackNode()
104
+
105
+ // If the node is already attached as there's no need to re-attach
106
+ const existingModule = await stackNode.resolve(node.address, { direction: 'down' })
107
+ if (isModuleInstance(existingModule)) return
108
+
109
+ // Register & attach the new node
110
+ await stackNode.register?.(node)
111
+ await stackNode.attach?.(node.address, true)
112
+ }
113
+
114
+ private assignStack() {
115
+ const assign = async () => {
116
+ const stackNode = await this.getStackNode()
117
+ this._stack = stackNode
118
+ }
119
+ forget(assign())
120
+ }
121
+
122
+ private async getStackNode() {
123
+ const mod = assertEx(await this.context.root.resolve(this.stackNodeModuleId), () => `${this.stackNodeModuleId} not found`)
124
+ return asAttachableNodeInstance(mod, () => `${this.stackNodeModuleId} not a NodeInstance`)
125
+ }
126
+
127
+ private async handleDriverReady(node: AttachableNodeInstance) {
128
+ try {
129
+ // eagerly emit that the driver is ready
130
+ await this.emit('driverReady', { node })
131
+
132
+ await this.addNodeToStackNode(node)
133
+
134
+ await this.updateInitializationState(node)
135
+ } catch (error) {
136
+ console.error(`Error updating ${this.stackNodeModuleId} stack node`, node.id, error)
137
+ await this.emit('stackError', { error: error as Error })
138
+ }
139
+ }
140
+
141
+ private async updateInitializationState(node: AttachableNodeInstance) {
142
+ // update the initialized nodes list
143
+ this.initializedNodes.push(node)
144
+
145
+ // update the initialized flag
146
+ this.initialized = this.adapterSet.every(n => n.initialized)
147
+
148
+ // notify all initialized listeners
149
+ if (this.initialized) {
150
+ await this.emit('initialized', { stack: await this.getStackNode() })
151
+ }
152
+ }
153
+ }
@@ -0,0 +1,48 @@
1
+ import type { AdapterSetCreator, StackInitializer, XyOsContext } from '@xyo-network/os-model'
2
+
3
+ import type { StackBase } from './Base.ts'
4
+
5
+ export interface StackConstructor {
6
+ new (context: XyOsContext, adapters: AdapterSetCreator): StackBase
7
+ }
8
+
9
+ export interface UninitializedStackSet {
10
+ adapters: AdapterSetCreator
11
+ stack: StackConstructor
12
+ }
13
+
14
+ export interface UninitializedStackMap {
15
+ [key: string]: UninitializedStackSet
16
+ }
17
+
18
+ export class StackManager {
19
+ private initializedStacksMap: Map<string, StackInitializer> = new Map()
20
+ private stackMap: UninitializedStackMap
21
+
22
+ constructor(stackMap: UninitializedStackMap) {
23
+ this.stackMap = stackMap
24
+ }
25
+
26
+ private get stacks() {
27
+ return this.initializedStacksMap
28
+ }
29
+
30
+ getStack<TStack = StackBase>(key: string) {
31
+ return this.initializedStacksMap.get(key) as TStack | undefined
32
+ }
33
+
34
+ initialize(context: XyOsContext) {
35
+ for (const [key, stackSet] of Object.entries(this.stackMap)) {
36
+ const { stack: Stack, adapters: stackNodeModuleId } = stackSet
37
+ const initializedStack = new Stack(context, stackNodeModuleId)
38
+ initializedStack.initialize()
39
+ this.stacks.set(key, initializedStack)
40
+ }
41
+ }
42
+
43
+ stop() {
44
+ for (const stack of this.stacks.values()) {
45
+ stack.stop()
46
+ }
47
+ }
48
+ }