Source: orbitdb.js

  1. /**
  2. * @module OrbitDB
  3. * @description Provides an interface for users to interact with OrbitDB.
  4. */
  5. import { getDatabaseType } from './databases/index.js'
  6. import KeyStore from './key-store.js'
  7. import { Identities } from './identities/index.js'
  8. import OrbitDBAddress, { isValidAddress } from './address.js'
  9. import ManifestStore from './manifest-store.js'
  10. import { createId } from './utils/index.js'
  11. import pathJoin from './utils/path-join.js'
  12. import { getAccessController } from './access-controllers/index.js'
  13. import IPFSAccessController from './access-controllers/ipfs.js'
  14. const DefaultDatabaseType = 'events'
  15. const DefaultAccessController = IPFSAccessController
  16. /**
  17. * Creates an instance of OrbitDB.
  18. * @function createOrbitDB
  19. * @param {Object} params One or more parameters for configuring OrbitDB.
  20. * @param {IPFS} params.ipfs An IPFS instance.
  21. * @param {string} [params.id] The id of the identity to use for this OrbitDB instance.
  22. * @param {module:Identity|Object} [params.identity] An identity instance or an object containing an Identity Provider instance and any additional params required to create the identity using the specified provider.
  23. * @param {Function} [params.identity.provider] An initialized identity provider.
  24. * @param {module:Identities} [params.identities] An Identities system instance.
  25. * @param {string} [params.directory] A location for storing OrbitDB data.
  26. * @return {module:OrbitDB~OrbitDB} An instance of OrbitDB.
  27. * @throws "IPFS instance is required argument" if no IPFS instance is provided.
  28. * @instance
  29. */
  30. const OrbitDB = async ({ ipfs, id, identity, identities, directory } = {}) => {
  31. /**
  32. * @namespace module:OrbitDB~OrbitDB
  33. * @description The instance returned by {@link module:OrbitDB}.
  34. */
  35. if (ipfs == null) {
  36. throw new Error('IPFS instance is a required argument.')
  37. }
  38. id = id || await createId()
  39. const peerId = ipfs.libp2p.peerId
  40. directory = directory || './orbitdb'
  41. let keystore
  42. if (identities) {
  43. keystore = identities.keystore
  44. } else {
  45. keystore = await KeyStore({ path: pathJoin(directory, './keystore') })
  46. identities = await Identities({ ipfs, keystore })
  47. }
  48. if (identity) {
  49. if (identity.provider) {
  50. identity = await identities.createIdentity({ ...identity })
  51. }
  52. } else {
  53. identity = await identities.createIdentity({ id })
  54. }
  55. const manifestStore = await ManifestStore({ ipfs })
  56. let databases = {}
  57. /**
  58. * Open a database or create one if it does not already exist.
  59. *
  60. * By default, OrbitDB will create a database of type [DefaultDatabaseType]{@link module:OrbitDB~DefaultDatabaseType}:
  61. * ```
  62. * const mydb = await orbitdb.open('mydb')
  63. * ```
  64. * To create a database of a different type, specify the type param:
  65. * ```
  66. * const mydb = await orbitdb.open('mydb', {type: 'documents'})
  67. * ```
  68. * The type must be listed in [databaseTypes]{@link module:OrbitDB.databaseTypes} or an error is thrown.
  69. * To open an existing database, pass its address to the `open` function:
  70. * ```
  71. * const existingDB = await orbitdb.open(dbAddress)
  72. * ```
  73. * The address of a newly created database can be retrieved using
  74. * `db.address`.
  75. * @function
  76. * @param {string} address The address of an existing database to open, or
  77. * the name of a new database.
  78. * @param {Object} params One or more database configuration parameters.
  79. * @param {string} [params.type=events] The database's type.
  80. * @param {*} [params.meta={}] The database's metadata. Only applies when
  81. * creating a database and is not used when opening an existing database.
  82. * @param {boolean} [params.sync=true] If true, sync databases automatically.
  83. * Otherwise, false.
  84. * @param {module:Database} [params.Database=[Events]{@link module:Database.Database-Events}] A Database-compatible
  85. * module.
  86. * @param {module:AccessControllers}
  87. * [params.AccessController=[IPFSAccessController]{@link module:AccessControllers.AccessControllers-IPFS}]
  88. * An AccessController-compatible module.
  89. * @param {module:Storage} [params.headsStorage=[ComposedStorage]{@link module:Storage.Storage-Composed}] A compatible storage instance for storing
  90. * log heads. Defaults to ComposedStorage(LRUStorage, LevelStorage).
  91. * @param {module:Storage} [params.entryStorage=[ComposedStorage]{@link module:Storage.Storage-Composed}] A compatible storage instance for storing
  92. * log entries. Defaults to ComposedStorage(LRUStorage, IPFSBlockStorage).
  93. * @param {module:Storage} [params.indexStorage=[ComposedStorage]{@link module:Storage.Storage-Composed}] A compatible storage instance for storing an " index of log entries. Defaults to ComposedStorage(LRUStorage, LevelStorage).
  94. * @param {number} [params.referencesCount] The number of references to
  95. * use for [Log]{@link module:Log} entries.
  96. * @memberof module:OrbitDB
  97. * @return {module:Database} A database instance.
  98. * @throws "Unsupported database type" if the type specified is not in the list
  99. * of known databaseTypes.
  100. * @memberof module:OrbitDB~OrbitDB
  101. * @instance
  102. * @async
  103. */
  104. const open = async (address, { type, meta, sync, Database, AccessController, headsStorage, entryStorage, indexStorage, referencesCount } = {}) => {
  105. let name, manifest, accessController
  106. if (databases[address]) {
  107. return databases[address]
  108. }
  109. if (isValidAddress(address)) {
  110. // If the address given was a valid OrbitDB address, eg. '/orbitdb/zdpuAuK3BHpS7NvMBivynypqciYCuy2UW77XYBPUYRnLjnw13'
  111. const addr = OrbitDBAddress(address)
  112. manifest = await manifestStore.get(addr.hash)
  113. const acType = manifest.accessController.split('/', 2).pop()
  114. AccessController = getAccessController(acType)()
  115. accessController = await AccessController({ orbitdb: { open, identity, ipfs }, identities, address: manifest.accessController })
  116. name = manifest.name
  117. type = type || manifest.type
  118. meta = manifest.meta
  119. } else {
  120. // If the address given was not valid, eg. just the name of the database
  121. type = type || DefaultDatabaseType
  122. AccessController = AccessController || DefaultAccessController()
  123. accessController = await AccessController({ orbitdb: { open, identity, ipfs }, identities, name: address })
  124. const m = await manifestStore.create({ name: address, type, accessController: accessController.address, meta })
  125. manifest = m.manifest
  126. address = OrbitDBAddress(m.hash)
  127. name = manifest.name
  128. meta = manifest.meta
  129. // Check if we already have the database open and return if it is
  130. if (databases[address]) {
  131. return databases[address]
  132. }
  133. }
  134. Database = Database || getDatabaseType(type)()
  135. if (!Database) {
  136. throw new Error(`Unsupported database type: '${type}'`)
  137. }
  138. address = address.toString()
  139. const db = await Database({ ipfs, identity, address, name, access: accessController, directory, meta, syncAutomatically: sync, headsStorage, entryStorage, indexStorage, referencesCount })
  140. db.events.on('close', onDatabaseClosed(address))
  141. databases[address] = db
  142. return db
  143. }
  144. const onDatabaseClosed = (address) => () => {
  145. delete databases[address]
  146. }
  147. /**
  148. * Stops OrbitDB, closing the underlying keystore and manifest store.
  149. * @function stop
  150. * @memberof module:OrbitDB~OrbitDB
  151. * @instance
  152. * @async
  153. */
  154. const stop = async () => {
  155. for (const db of Object.values(databases)) {
  156. await db.close()
  157. }
  158. if (keystore) {
  159. await keystore.close()
  160. }
  161. if (manifestStore) {
  162. await manifestStore.close()
  163. }
  164. databases = {}
  165. }
  166. return {
  167. id,
  168. open,
  169. stop,
  170. ipfs,
  171. directory,
  172. keystore,
  173. identities,
  174. identity,
  175. peerId
  176. }
  177. }
  178. export { OrbitDB as default, OrbitDBAddress }