@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,96 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { asArchivistInstance } from '@xyo-network/archivist-model'
3
+ import type { PackageManifestPayload } from '@xyo-network/manifest'
4
+ import { PackageManifestPayloadSchema } from '@xyo-network/manifest'
5
+ import type { ManifestWrapper } from '@xyo-network/manifest-wrapper'
6
+ import type { ModuleFactoryLocator } from '@xyo-network/module-factory-locator'
7
+ import type { NodeInstance } from '@xyo-network/node-model'
8
+ import type { DappId, DappPackageManifestPayload, ExternalModule, XyOsContext } from '@xyo-network/os-model'
9
+ import type { WalletInstance } from '@xyo-network/wallet-model'
10
+
11
+ import { DappCallerBase } from '../../DappCallerBase.ts'
12
+ import { ReplaceManifestTokens } from '../../manifest/index.ts'
13
+ import type { DappNodesCreatorParams } from '../lib/index.ts'
14
+ import { DefaultPayloads } from './DefaultPayloads/index.ts'
15
+ import { ExternalModulePermissions } from './ExternalModulePermissions/index.ts'
16
+
17
+ export type TargetDappManifestParams = ConstructorParameters<typeof ManifestWrapper<DappPackageManifestPayload>>
18
+
19
+ export class DappContextCreator {
20
+ // Designated offset path for the wallet used by windowed dapps. In the future, other offsets could be used for other dapp modes
21
+ private static DAPP_WINDOW_WALLET_PATH = '1'
22
+
23
+ constructor(
24
+ private targetDappManifestParams: TargetDappManifestParams,
25
+ private dappId: DappId,
26
+ private context: XyOsContext,
27
+ private rootWallet: WalletInstance,
28
+ private externalPermissions?: ExternalModule[],
29
+ private sharedLocator?: ModuleFactoryLocator,
30
+ ) {}
31
+
32
+ static async create(params: DappNodesCreatorParams, xnsNodeUrl: string | undefined, xnsNetwork: string | undefined) {
33
+ const { config, locator, context, wallet } = params
34
+ const { payload, dappName, publicChildren, privateChildren } = config
35
+
36
+ const { external, manifestPayload } = this.parseDappPackageManifestPayload(payload, xnsNodeUrl, xnsNetwork)
37
+ console.debug('[DEBUG] dApp manifest', manifestPayload)
38
+
39
+ // derive a wallet for the dapp to use from the root wallet
40
+ const dappWallet = await wallet.derivePath(DappContextCreator.DAPP_WINDOW_WALLET_PATH)
41
+ const targetDappManifestParams: TargetDappManifestParams = [manifestPayload, dappWallet, locator, publicChildren, privateChildren]
42
+
43
+ const instance = new this(targetDappManifestParams, dappName, context, wallet, external?.modules, locator)
44
+ return instance
45
+ }
46
+
47
+ // Add default payloads to the archivist shared between the os and the dapp
48
+ static async primeDappArchivist(dappContext: XyOsContext, osContext: XyOsContext, dappName: DappId) {
49
+ const dappCaller = new DappCallerBase(dappContext)
50
+ const dappArchivist = await dappCaller.getDappArchivist()
51
+ const defaultPayloads = new DefaultPayloads(dappArchivist, osContext, dappName)
52
+
53
+ await defaultPayloads.insert()
54
+ }
55
+
56
+ // Reset the dapp archivist to remove all payloads
57
+ static async resetDappArchivist(context: XyOsContext) {
58
+ const dappModule = await context.root.resolve('DappArchivist')
59
+ const dappArchivist = assertEx(asArchivistInstance(dappModule), () => 'DappArchivist not found')
60
+
61
+ await dappArchivist.clear()
62
+ }
63
+
64
+ private static parseDappPackageManifestPayload(payload: DappPackageManifestPayload, xnsNodeUrl: string | undefined, xnsNetwork: string | undefined) {
65
+ // extract external permissions from package manifest payload
66
+ const { external, ...manifestWithoutExternals } = payload
67
+ const manifestPayloadRaw: PackageManifestPayload = {
68
+ ...manifestWithoutExternals,
69
+ schema: PackageManifestPayloadSchema,
70
+ }
71
+ const manifestPayload = ReplaceManifestTokens(manifestPayloadRaw, xnsNodeUrl, xnsNetwork)
72
+ return { external, manifestPayload }
73
+ }
74
+
75
+ async loadDappContext(context: XyOsContext): Promise<XyOsContext> {
76
+ console.log('DappNodesCreator:loadDappContext', this.dappId)
77
+ // build nodes and attach to dappNodes to dappWindowNode
78
+ const dapp
79
+ = (await context.dappByName(this.dappId))
80
+ ?? (await (async () => {
81
+ const dapp = await context.buildDapp(this.targetDappManifestParams[0], this.dappId)
82
+ await dapp.boot(this.rootWallet, this.sharedLocator)
83
+ return dapp
84
+ })())
85
+ await this.handleExternalModulePermissions(dapp.root)
86
+ await DappContextCreator.primeDappArchivist(dapp, this.context, this.dappId)
87
+
88
+ return dapp
89
+ }
90
+
91
+ // try to satisfy the external permissions requested by a dapp
92
+ private async handleExternalModulePermissions(dappWindowNode: NodeInstance) {
93
+ const externalModulePermissions = new ExternalModulePermissions(this.context, dappWindowNode, this.dappId, this.externalPermissions)
94
+ await externalModulePermissions.permit()
95
+ }
96
+ }
@@ -0,0 +1,17 @@
1
+ import type { DappName, XyOsContext } from '@xyo-network/os-model'
2
+
3
+ import { OsCallerBase } from '../../../OsCallerBase.ts'
4
+ import type { DefaultPayloadsInsertable } from '../../lib/index.ts'
5
+
6
+ export class DappAccessPayloads implements DefaultPayloadsInsertable {
7
+ constructor(
8
+ private context: XyOsContext,
9
+ _dappName: DappName,
10
+ ) {}
11
+
12
+ async payloads() {
13
+ const osCaller = new OsCallerBase(this.context)
14
+ const archivist = await osCaller.getRegisteredDappInterfacesArchivist()
15
+ return await archivist.all()
16
+ }
17
+ }
@@ -0,0 +1,33 @@
1
+ import type { ArchivistInstance } from '@xyo-network/archivist-model'
2
+ import type { DappName, XyOsContext } from '@xyo-network/os-model'
3
+ import { PayloadBuilder } from '@xyo-network/payload-builder'
4
+ import type { Payload } from '@xyo-network/payload-model'
5
+
6
+ import type { InsertableConstructor } from '../../lib/index.ts'
7
+ import { createInsertable } from '../../lib/index.ts'
8
+ import { DappAccessPayloads } from './DappAccessPayloads.ts'
9
+ import { NodeInfoPayload } from './NodeInfoPayload.ts'
10
+ import { SigningKeyPayloads } from './SigningKeyPayloads.ts'
11
+
12
+ export class DefaultPayloads {
13
+ constructor(
14
+ private dappArchivist: ArchivistInstance,
15
+ private xyOs: XyOsContext,
16
+ private dappName: DappName,
17
+ ) {}
18
+
19
+ async insert() {
20
+ const insertables: InsertableConstructor[] = [NodeInfoPayload, SigningKeyPayloads, DappAccessPayloads]
21
+ const insertPayloads: Payload[] = []
22
+ for (const insertable of insertables) {
23
+ const classInstance = createInsertable(insertable, this.xyOs, this.dappName)
24
+ const payloads = await classInstance.payloads()
25
+ insertPayloads.push(...payloads)
26
+ }
27
+ for (const payload of insertPayloads) {
28
+ const [existing] = await this.dappArchivist.get([await PayloadBuilder.dataHash(payload)])
29
+ if (existing) continue
30
+ await this.dappArchivist.insert([payload])
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,27 @@
1
+ import type { DappName, NodeOsInfo, XyOsContext } from '@xyo-network/os-model'
2
+ import { NodeOsInfoSchema } from '@xyo-network/os-model'
3
+
4
+ import type { DefaultPayloadsInsertable } from '../../lib/index.ts'
5
+
6
+ export class NodeInfoPayload implements DefaultPayloadsInsertable {
7
+ constructor(
8
+ private _context: XyOsContext,
9
+ _dappName: DappName,
10
+ ) {}
11
+
12
+ async payloads() {
13
+ const exposedNode = this._context.exposedNode
14
+ if (exposedNode) {
15
+ console.debug('[DEBUG]', 'Found Exposed Node Address', exposedNode?.address)
16
+ } else {
17
+ console.error('exposedNode not found')
18
+ }
19
+
20
+ await Promise.resolve()
21
+ const nodeOsInfo: NodeOsInfo = {
22
+ publicAddress: exposedNode?.address ?? '',
23
+ schema: NodeOsInfoSchema,
24
+ }
25
+ return [nodeOsInfo]
26
+ }
27
+ }
@@ -0,0 +1,85 @@
1
+ import { assertEx } from '@xylabs/assert'
2
+ import { hexFrom } from '@xylabs/hex'
3
+ import { HDWallet } from '@xyo-network/account'
4
+ import type { DappName, XyOsContext } from '@xyo-network/os-model'
5
+ import { mnemonicArrayToString, SigningKeySchema } from '@xyo-network/os-model'
6
+ import type { Payload } from '@xyo-network/payload-model'
7
+ import { isAnyPayload } from '@xyo-network/payload-model'
8
+ import type { WalletInstance } from '@xyo-network/wallet-model'
9
+
10
+ import type { DefaultPayloadsInsertable } from '../../lib/index.ts'
11
+ import { OsSettingsCaller } from '../../settings/index.ts'
12
+
13
+ const DappsWithAdditionalPayloads = new Set(['Profile'])
14
+
15
+ const DefaultName: DappName = 'Name Service' as const
16
+
17
+ const DEFAULT_DAPP_ACCOUNT_PATHS: Record<string, string> = {
18
+ [DefaultName]: "1'/1",
19
+ } as const
20
+
21
+ // WIP - for now, dApps listed here can gain access to the signing key for other dapps
22
+ // In the future, this will be controlled by the user
23
+ const ADDITIONAL_DAPP_ACCOUNT_PATHS: Record<string, Record<string, string>> = {
24
+ ['Profile']: {
25
+ [DefaultName]: DEFAULT_DAPP_ACCOUNT_PATHS[DefaultName],
26
+ },
27
+ } as const
28
+
29
+ export class SigningKeyPayloads implements DefaultPayloadsInsertable {
30
+ constructor(
31
+ private context: XyOsContext,
32
+ private dappName: DappName,
33
+ ) {}
34
+
35
+ async payloads() {
36
+ const wallet = await this.resolveXyoWallet()
37
+
38
+ // get the signing key payloads for the default dapp account
39
+ const defaultDappAccountSigningKeyPayloads = await this.signingKeyPayload(wallet, this.dappName, DEFAULT_DAPP_ACCOUNT_PATHS[this.dappName])
40
+
41
+ // and any additional dapp accounts
42
+ const additionalDappAccountSigningKeyPayloads: (Payload | undefined)[] = []
43
+ for (const [dappName, accountPaths] of Object.entries(ADDITIONAL_DAPP_ACCOUNT_PATHS)) {
44
+ if (dappName !== this.dappName || !DappsWithAdditionalPayloads.has(dappName)) continue
45
+
46
+ for (const additionalDappAccountName of Object.keys(accountPaths)) {
47
+ const signingKeyPayload = await this.signingKeyPayload(wallet, additionalDappAccountName, accountPaths[additionalDappAccountName])
48
+ additionalDappAccountSigningKeyPayloads.push(signingKeyPayload)
49
+ }
50
+ }
51
+
52
+ // filter so we only return valid payloads
53
+ return [...additionalDappAccountSigningKeyPayloads, defaultDappAccountSigningKeyPayloads].filter(isAnyPayload) as Payload[]
54
+ }
55
+
56
+ private async resolveXyoWallet() {
57
+ // get the user's wallet
58
+ const settingsCaller = new OsSettingsCaller(this.context)
59
+ const latestWallet = await settingsCaller.getLatestUserWallet()
60
+
61
+ // find the phrase
62
+ const phrase = mnemonicArrayToString(latestWallet.mnemonic.mnemonic)
63
+ const assertedPhrase = assertEx(phrase, () => 'No phrase found in latest wallet')
64
+
65
+ // create a wallet instance
66
+ return await HDWallet.fromPhrase(assertedPhrase)
67
+ }
68
+
69
+ private async signingKeyPayload(wallet: WalletInstance, name: string, path?: string) {
70
+ if (path) {
71
+ // derive the sub account
72
+ const subAccount = await wallet.derivePath(path)
73
+
74
+ // get the private key
75
+ const privateKey = hexFrom(subAccount.privateKey, { prefix: false })
76
+
77
+ // return the payload
78
+ return {
79
+ dappName: name,
80
+ privateKey,
81
+ schema: SigningKeySchema,
82
+ }
83
+ }
84
+ }
85
+ }
@@ -0,0 +1 @@
1
+ export * from './DefaultPayloads.ts'
@@ -0,0 +1,47 @@
1
+ import type { AttachableModuleInstance, ModuleIdentifier } from '@xyo-network/module-model'
2
+ import type { NodeInstance } from '@xyo-network/node-model'
3
+ import type { DappName, ExternalModule, XyOsContext } from '@xyo-network/os-model'
4
+
5
+ // Dapps can only request specific modules from the parent node
6
+ const ALLOWED_MODULES_FROM_PARENT = ['IntentArchivist', 'OsSettingsNode', 'OsPubSubNetworkStackNode', 'OsXyoPublicNetworkStackNode'] as const
7
+
8
+ export class ExternalModulePermissions {
9
+ constructor(
10
+ private context: XyOsContext,
11
+ private dappWindowNode: NodeInstance,
12
+ private dappName: DappName,
13
+ private externalPermissions?: ExternalModule[],
14
+ ) {}
15
+
16
+ async permit() {
17
+ for (const permission of this.externalPermissions ?? []) {
18
+ await this.permitExternalModule(permission)
19
+ }
20
+ }
21
+
22
+ private getExternalModuleName(permission: ExternalModule) {
23
+ return permission.name as (typeof ALLOWED_MODULES_FROM_PARENT)[number]
24
+ }
25
+
26
+ private async permitExternalModule(externalPermission: ExternalModule) {
27
+ const externalModuleName = this.getExternalModuleName(externalPermission)
28
+
29
+ if (ALLOWED_MODULES_FROM_PARENT.includes(externalModuleName)) {
30
+ const mod = await this.resolveExternalModule(externalModuleName)
31
+ await this.registerAndAttachModule(mod)
32
+ } else {
33
+ console.warn(`${this.dappName} requested ${externalModuleName} but it was not fulfilled`)
34
+ }
35
+ }
36
+
37
+ private async registerAndAttachModule(mod?: AttachableModuleInstance) {
38
+ if (mod) {
39
+ await this.dappWindowNode.register?.(mod)
40
+ await this.dappWindowNode.attach(mod.address, true)
41
+ }
42
+ }
43
+
44
+ private async resolveExternalModule(id: ModuleIdentifier): Promise<AttachableModuleInstance | undefined> {
45
+ return await this.context.root.resolve(id)
46
+ }
47
+ }
@@ -0,0 +1 @@
1
+ export * from './ExternalModulePermissions.ts'
@@ -0,0 +1,52 @@
1
+ import { HDWallet } from '@xyo-network/account'
2
+ import { GenericPayloadDiviner } from '@xyo-network/diviner-payload-generic'
3
+ import { ModuleFactoryLocator } from '@xyo-network/module-factory-locator'
4
+ import type { RegisteredDapp, WindowDappNodeSet, XyOsContext } from '@xyo-network/os-model'
5
+
6
+ import { DappSeedPhraseRepository } from '../../wallet/index.ts'
7
+ import type { DappNodesCreatorParams } from '../lib/index.ts'
8
+ import { DappContextCreator } from './Creator.ts'
9
+
10
+ const GenericPayloadDivinerTags = { 'network.xyo.generic.payload.diviner': 'GenericPayloadDiviner' }
11
+
12
+ const resolveLocator = (existingLocator?: ModuleFactoryLocator) => {
13
+ const locator = existingLocator ?? new ModuleFactoryLocator()
14
+ locator.register(GenericPayloadDiviner, GenericPayloadDivinerTags)
15
+ return locator
16
+ }
17
+
18
+ export const createDappContext = async (dapp: RegisteredDapp, context: XyOsContext, allowedNames: string[], xnsNodeUrl: string | undefined, xnsNetwork: string | undefined): Promise<WindowDappNodeSet> => {
19
+ console.log('createNodes')
20
+ try {
21
+ const dappSeedPhraseRepository = new DappSeedPhraseRepository(context, allowedNames)
22
+ const seedPhrase = await dappSeedPhraseRepository.request(dapp.config.walletId)
23
+ if (!seedPhrase) {
24
+ throw new Error(`unable to find seed phrase for walletId: ${JSON.stringify(dapp.config, null, 2)}`)
25
+ }
26
+ const wallet = await HDWallet.fromPhrase(seedPhrase)
27
+ const dappName = dapp.config.name
28
+ const { config: dappConfig, params: dappParams } = dapp
29
+
30
+ const locator = resolveLocator((dappParams.locator ?? new ModuleFactoryLocator()).merge(context.platformLocator))
31
+
32
+ const params: DappNodesCreatorParams = {
33
+ config: { dappName, payload: dappConfig.manifest },
34
+ context,
35
+ locator,
36
+ wallet,
37
+ }
38
+ const dappContextCreator = await DappContextCreator.create(params, xnsNodeUrl, xnsNetwork)
39
+
40
+ const dappContext = await dappContextCreator.loadDappContext(context)
41
+
42
+ return {
43
+ context: dappContext,
44
+ dappWallet: wallet,
45
+ }
46
+ } catch (e) {
47
+ const error = e as Error
48
+ console.error(`Error creating dappWindow node: ${error.message}`)
49
+ console.error(`Error creating dappWindow node: ${error.stack}`)
50
+ throw new Error(`Error creating dappWindow node: ${error.message}`)
51
+ }
52
+ }
@@ -0,0 +1,3 @@
1
+ export * from './createDappContext.ts'
2
+ export * from './Creator.ts'
3
+ export * from './ExternalModulePermissions/index.ts'
@@ -0,0 +1,146 @@
1
+ import { forget } from '@xylabs/forget'
2
+ import type { Promisable } from '@xylabs/promise'
3
+ import { fulfilled, rejected } from '@xylabs/promise'
4
+ import { ModuleFactoryLocator } from '@xyo-network/module-factory-locator'
5
+ import type {
6
+ DappPackageManifestPayload,
7
+ DappParams,
8
+ DappRegistrationResults,
9
+ PayloadWithVersion,
10
+ RegisteredDappSetResult,
11
+ XyOsContext,
12
+ XyOsDappContext } from '@xyo-network/os-model'
13
+ import {
14
+ DappIntentTypes,
15
+ DappMode,
16
+ isRegisteredDappAccessDappSet,
17
+ isRegisteredDappExposedDappSet,
18
+ } from '@xyo-network/os-model'
19
+
20
+ import { dappAccessRequestConnection, DappAccessRequestEvent, exposeDappRequestConnection, ExposeDappRequestEvent } from '../../event/index.ts'
21
+ import { DappIntentCaller } from '../../intent/index.ts'
22
+ import { NameTransforms } from '../../lib/index.ts'
23
+ import { DappSeedPhraseRepository } from '../../wallet/index.ts'
24
+ import { XyOsDapp } from '../../XyOsDapp.ts'
25
+ import { ManageSystemDapps } from '../system/index.ts'
26
+ import { DappRegistry } from './DappRegistry.ts'
27
+
28
+ export interface DappRegistrationServiceParams {
29
+ dappNames: string[]
30
+ dappParams: Record<string, DappParams>
31
+ dappPayloads: PayloadWithVersion[]
32
+ }
33
+
34
+ export class DappRegistrationService {
35
+ // Dapps that have been built with their own context
36
+ builtDapps: Record<string, XyOsDappContext> = {}
37
+
38
+ dappRegistry: DappRegistry
39
+ dappSeedPhraseRepository: DappSeedPhraseRepository
40
+ manageSystemDapps: ManageSystemDapps
41
+
42
+ // Dapps that have been registered with dappAccessRequests
43
+ registeredAccessDappSets: Set<RegisteredDappSetResult> = new Set()
44
+
45
+ // Dapps that have been registered with the dapp registry
46
+ registeredDappSets: Set<RegisteredDappSetResult> = new Set()
47
+
48
+ // Dapps that have been registered with exposeDappRequests
49
+ registeredExposedDappSets: Set<RegisteredDappSetResult> = new Set()
50
+
51
+ private dappAccessRequestConnection = dappAccessRequestConnection()
52
+ private exposeDappRequestConnection = exposeDappRequestConnection()
53
+
54
+ constructor(
55
+ private context: XyOsContext,
56
+ private params: DappRegistrationServiceParams = { dappNames: [], dappParams: {}, dappPayloads: [] },
57
+ private locator = new ModuleFactoryLocator(),
58
+ private developmentMode?: boolean,
59
+ ) {
60
+ this.manageSystemDapps = new ManageSystemDapps(
61
+ context,
62
+ this.params?.dappNames ?? [],
63
+ this.params?.dappPayloads ?? [],
64
+ this.params?.dappParams ?? {},
65
+ this.locator,
66
+ this.developmentMode,
67
+ )
68
+ this.dappSeedPhraseRepository = new DappSeedPhraseRepository(context, this.params?.dappNames ?? [])
69
+ this.dappRegistry = new DappRegistry(this.dappSeedPhraseRepository)
70
+
71
+ this.addConnectionRequests()
72
+ }
73
+
74
+ buildDapp(
75
+ manifest: DappPackageManifestPayload,
76
+ dappId = NameTransforms.slug(manifest.nodes[0]?.config.name),
77
+ name = NameTransforms.moduleName(manifest.nodes[0]?.config.name),
78
+ ): Promisable<XyOsDappContext> {
79
+ const dapp = new XyOsDapp({ dapp: { id: dappId, name }, locator: this.locator, manifest, parent: this.context }) as XyOsDappContext
80
+ this.builtDapps[dappId] = dapp
81
+ return dapp
82
+ }
83
+
84
+ getParamsForRegisteredDapp(dappId: string) {
85
+ return this.params?.dappParams[dappId]
86
+ }
87
+
88
+ async start(): Promise<DappRegistrationResults> {
89
+ const systemDapps = await this.context.monitor(async () => await this.manageSystemDapps.install(), { name: 'Install System dApps' })
90
+ const activeDapps = systemDapps.filter(({ dapp }) => dapp.icon.active === true)
91
+ const results = await Promise.allSettled(
92
+ activeDapps.map(async (dappSet) => {
93
+ const { dapp } = dappSet
94
+ const registeredDapp = await this.dappRegistry.registerDapp(dapp)
95
+ const result: RegisteredDappSetResult = { dapp: registeredDapp, dappIcon: dapp.icon }
96
+
97
+ // Start post registration process in the background
98
+ const forgetHandlers = async () => {
99
+ try {
100
+ await this.postRegistrationHandlers(result)
101
+ } catch (e) {
102
+ console.error('Error in post registration handlers', e)
103
+ }
104
+ }
105
+ forget(forgetHandlers())
106
+
107
+ return result
108
+ }),
109
+ )
110
+ const failed = results.filter(rejected).map(result => result.reason)
111
+ const succeeded = results.filter(fulfilled).map(result => result.value)
112
+
113
+ for (const registeredDapp of succeeded) this.registeredDappSets.add(registeredDapp)
114
+
115
+ return { failed, succeeded }
116
+ }
117
+
118
+ private addConnectionRequests() {
119
+ this.context.eventBus.addConnection(this.dappAccessRequestConnection)
120
+ this.context.eventBus.addConnection(this.exposeDappRequestConnection)
121
+ }
122
+
123
+ private async postRegistrationHandlers(registeredDapp: RegisteredDappSetResult) {
124
+ if (registeredDapp.dapp) {
125
+ if (isRegisteredDappExposedDappSet(registeredDapp)) {
126
+ // add to exposed dapp set
127
+ this.registeredExposedDappSets.add(registeredDapp)
128
+ // craft intent
129
+ const exposeIntent = DappIntentCaller.buildIntent(
130
+ DappIntentCaller.OsDappName,
131
+ DappIntentTypes.Launch,
132
+ registeredDapp.dapp.config.name,
133
+ DappMode.Exposed,
134
+ )
135
+ // emit to bus
136
+ await this.exposeDappRequestConnection.emit(ExposeDappRequestEvent, { payloads: [registeredDapp.dapp.config, exposeIntent] })
137
+ }
138
+ if (isRegisteredDappAccessDappSet(registeredDapp)) {
139
+ // add to access dapp set
140
+ this.registeredAccessDappSets.add(registeredDapp)
141
+ // emit to bus
142
+ await this.dappAccessRequestConnection.emit(DappAccessRequestEvent, { payloads: registeredDapp.dapp.accessors })
143
+ }
144
+ }
145
+ }
146
+ }
@@ -0,0 +1,121 @@
1
+ import type { Hash } from '@xylabs/hex'
2
+ import { HDWallet } from '@xyo-network/account'
3
+ import type {
4
+ DappPackageManifestPayload,
5
+ DappParams,
6
+ RegisteredDapp,
7
+ RegisteredDappAccess,
8
+ UnregisteredDapp,
9
+ UnregisteredDappAccess } from '@xyo-network/os-model'
10
+ import {
11
+ DappRegisteredSchema,
12
+ DappRegisteredState,
13
+ isRegisteredDappAccess,
14
+ } from '@xyo-network/os-model'
15
+ import type { WithMeta } from '@xyo-network/payload-model'
16
+
17
+ import type { DappSeedPhraseRepository } from '../../wallet/index.ts'
18
+ import type {
19
+ FailedAccessor } from './ValidateDappAccessDiviner/index.ts'
20
+ import {
21
+ isFailedAccessor,
22
+ ValidateDappAccessDiviner,
23
+ ValidateDappAccessDivinerConfigSchema,
24
+ } from './ValidateDappAccessDiviner/index.ts'
25
+
26
+ export type DappRegisteredId = string
27
+
28
+ /**
29
+ * Manage Dapp Registration
30
+ */
31
+ export class DappRegistry {
32
+ private dappRegistry: Map<DappRegisteredId, RegisteredDapp> = new Map()
33
+
34
+ constructor(private dappSeedPhraseRepository: DappSeedPhraseRepository) {}
35
+
36
+ /**
37
+ * Register a Dapp with window manager and if successful, return its id
38
+ *
39
+ * @param {UnregisteredDapp} dapp Manifest and UI of the Dapp to register
40
+ * @returns {RegisteredDapp} dapp with registration fields
41
+ **/
42
+ async registerDapp(dapp?: UnregisteredDapp): Promise<RegisteredDapp | null> {
43
+ if (dapp) {
44
+ const { exposedModuleIds, manifest, modes, name, version, params, widgetConfigs } = this.extractDappProperties(dapp)
45
+
46
+ try {
47
+ /**
48
+ * TODO: More validation from sources is needed for third-party dapps. A name needs some form of verification
49
+ * before trusting it with a seed phrase at that given name.
50
+ */
51
+
52
+ // get a seed phrase for the given dapp id
53
+ const walletId = await this.dappSeedPhraseRepository.findOrCreate(name)
54
+
55
+ const registeredAccessors = await this.validateDappAccessPayloads(manifest, dapp.accessors, params)
56
+
57
+ const registeredDapp: RegisteredDapp = {
58
+ accessors: registeredAccessors,
59
+ config: {
60
+ exposedModuleIds,
61
+ manifest,
62
+ modes,
63
+ name,
64
+ schema: DappRegisteredSchema,
65
+ state: DappRegisteredState.Registered,
66
+ version,
67
+ // attach the walletId to a registered dapp so it can request it back in the future
68
+ walletId,
69
+ },
70
+ params,
71
+ widgetConfigs,
72
+ }
73
+
74
+ if (this.dappRegistry.get(name)) {
75
+ console.warn('tried to register two dapps with the same name', name)
76
+ return null
77
+ }
78
+ this.dappRegistry.set(name, registeredDapp)
79
+ return registeredDapp
80
+ } catch (e) {
81
+ console.error('Error registeringDapp', e)
82
+ return null
83
+ }
84
+ } else {
85
+ return null
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Unregister a dapp so it can no longer be launched
91
+ *
92
+ * @param dappId
93
+ */
94
+ unregisterDapp(dappId: Hash) {
95
+ this.dappRegistry.delete(dappId)
96
+ }
97
+
98
+ private extractDappProperties(dapp: UnregisteredDapp) {
99
+ const { params, config, widgetConfigs } = dapp
100
+ const { exposedModuleIds, manifest, modes, name, sources, version } = config
101
+
102
+ return { exposedModuleIds, manifest, modes, name, params, sources, version, widgetConfigs }
103
+ }
104
+
105
+ private async validateDappAccessPayloads(manifest: DappPackageManifestPayload, accessors: UnregisteredDappAccess[] = [], params: DappParams) {
106
+ const validateDappAccess = await ValidateDappAccessDiviner.create({
107
+ account: await HDWallet.random(),
108
+ config: { schema: ValidateDappAccessDivinerConfigSchema },
109
+ dappParams: params,
110
+ })
111
+ const payloads = await validateDappAccess.divine([manifest, ...accessors])
112
+ const failedAccessors = payloads.filter(isFailedAccessor) as WithMeta<FailedAccessor>[]
113
+ const registeredAccessors = payloads.filter(isRegisteredDappAccess) as WithMeta<RegisteredDappAccess>[]
114
+
115
+ if (failedAccessors.length > 0) {
116
+ console.error('Failed to register all dapp accessors', failedAccessors)
117
+ }
118
+
119
+ return registeredAccessors
120
+ }
121
+ }
@@ -0,0 +1,19 @@
1
+ import type { DivinerParams } from '@xyo-network/diviner-model'
2
+ import type { PackageManifestPayload } from '@xyo-network/manifest'
3
+ import type { DappPackageManifestPayload, DappParams, RegisteredDappAccess, UnregisteredDappAccess } from '@xyo-network/os-model'
4
+ import type { Payload, WithMeta } from '@xyo-network/payload-model'
5
+ import { isPayloadOfSchemaTypeWithMeta } from '@xyo-network/payload-model'
6
+
7
+ export const FailedAccessorSchema = 'network.xyo.os.failed.accessor.registration' as const
8
+ export type FailedAccessorSchema = typeof FailedAccessorSchema
9
+
10
+ export type FailedAccessor = Payload<{ accessor: UnregisteredDappAccess; errorMessage: string }, FailedAccessorSchema>
11
+
12
+ export const isFailedAccessor = isPayloadOfSchemaTypeWithMeta<FailedAccessor>(FailedAccessorSchema)
13
+
14
+ export type ValidateDappAccessDivinerParams = DivinerParams & { dappParams: DappParams }
15
+ export type ValidateDappAccessDivinerIn = DappPackageManifestPayload | PackageManifestPayload | UnregisteredDappAccess
16
+ export type ValidateDappAccessDivinerOut = WithMeta<RegisteredDappAccess> | WithMeta<FailedAccessor>
17
+
18
+ export const ValidateDappAccessDivinerConfigSchema = 'network.xyo.os.dapp.access.registration.validate' as const
19
+ export type ValidateDappAccessDivinerConfigSchema = typeof ValidateDappAccessDivinerConfigSchema