mirror of
https://github.com/orbitdb/orbitdb.git
synced 2025-03-30 15:08:28 +00:00
Merge branch 'main' into HEAD
This commit is contained in:
commit
7975ac42b9
38
conf/jsdoc/layout.tmpl
Normal file
38
conf/jsdoc/layout.tmpl
Normal file
@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>OrbitDB API</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">OrbitDB API</h1>
|
||||
|
||||
<?js= content ?>
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<?js= this.nav ?>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc <?js= env.version.number ?></a><?js if(env.conf.templates && env.conf.templates.default && env.conf.templates.default.includeDate !== false) { ?> on <?js= (new Date()) ?><?js } ?>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
@ -1,3 +1,8 @@
|
||||
{
|
||||
"plugins": ["plugins/markdown"]
|
||||
"plugins": ["plugins/markdown"],
|
||||
"templates" : {
|
||||
"default": {
|
||||
"layoutFile": "conf/jsdoc/layout.tmpl"
|
||||
}
|
||||
}
|
||||
}
|
@ -21,12 +21,12 @@ import IPFSAccessController from './ipfs.js'
|
||||
import OrbitDBAccessController from './orbitdb.js'
|
||||
|
||||
/**
|
||||
* An array of available access controller types.
|
||||
* @name types
|
||||
* An array of available access controllers.
|
||||
* @name accessControllers
|
||||
* @†ype []
|
||||
* @return [] An array of access controller types.
|
||||
* @return [] An array of access controllers.
|
||||
*/
|
||||
const types = {
|
||||
const accessControllers = {
|
||||
ipfs: IPFSAccessController,
|
||||
orbitdb: OrbitDBAccessController
|
||||
}
|
||||
@ -36,25 +36,15 @@ const types = {
|
||||
* @param {string} type A valid access controller type.
|
||||
* @return {AccessController} The access controller module.
|
||||
*/
|
||||
const get = (type) => {
|
||||
if (!isSupported(type)) {
|
||||
const getAccessController = (type) => {
|
||||
if (!Object.keys(accessControllers).includes(type)) {
|
||||
throw new Error(`AccessController type '${type}' is not supported`)
|
||||
}
|
||||
return types[type]
|
||||
return accessControllers[type]
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the access controller exists.
|
||||
* @param {string} type A valid access controller type.
|
||||
* @return {boolean} True if the access controller exists, false otherwise.
|
||||
*/
|
||||
const isSupported = type => {
|
||||
return Object.keys(types).includes(type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an access controller module to the list of supported access controller
|
||||
* types.
|
||||
* Adds an access controller module to the list of supported access controller.
|
||||
* @param {AccessController} accessController A compatible access controller
|
||||
* module.
|
||||
* @throws Access controller `type` already added if the access controller is
|
||||
@ -62,8 +52,8 @@ const isSupported = type => {
|
||||
* @throws Given AccessController class needs to implement: type if the access
|
||||
* controller module does not implement a type property.
|
||||
*/
|
||||
const add = (accessController) => {
|
||||
if (types[accessController.type]) {
|
||||
const addAccessController = (accessController) => {
|
||||
if (accessControllers[accessController.type]) {
|
||||
throw new Error(`Access controller '${accessController.type}' already added.`)
|
||||
}
|
||||
|
||||
@ -71,21 +61,20 @@ const add = (accessController) => {
|
||||
throw new Error('Given AccessController class needs to implement: type.')
|
||||
}
|
||||
|
||||
types[accessController.type] = accessController
|
||||
accessControllers[accessController.type] = accessController
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an access controller from the types list.
|
||||
* Removes an access controller from the list.
|
||||
* @param {string} type A valid access controller type.
|
||||
*/
|
||||
const remove = type => {
|
||||
delete types[type]
|
||||
const removeAccessController = type => {
|
||||
delete accessControllers[type]
|
||||
}
|
||||
|
||||
export {
|
||||
types,
|
||||
get,
|
||||
isSupported,
|
||||
add,
|
||||
remove
|
||||
accessControllers,
|
||||
getAccessController,
|
||||
addAccessController,
|
||||
removeAccessController
|
||||
}
|
||||
|
@ -4,9 +4,8 @@
|
||||
* Identities provides a framework for generating and managing identity
|
||||
* details and providers.
|
||||
*/
|
||||
|
||||
import Identity, { isIdentity, isEqual, decodeIdentity } from './identity.js'
|
||||
import { PublicKeyIdentityProvider } from './providers/index.js'
|
||||
import { getProviderFor } from './providers/index.js'
|
||||
// import DIDIdentityProvider from './identity-providers/did.js'
|
||||
// import EthIdentityProvider from './identity-providers/ethereum.js'
|
||||
import KeyStore, { signMessage, verifyMessage } from '../key-store.js'
|
||||
@ -14,13 +13,8 @@ import { LRUStorage, IPFSBlockStorage, MemoryStorage, ComposedStorage } from '..
|
||||
import pathJoin from '../utils/path-join.js'
|
||||
|
||||
const DefaultProviderType = 'publickey'
|
||||
const DefaultIdentityKeysPath = pathJoin('./orbitdb', 'identities')
|
||||
|
||||
const supportedTypes = {
|
||||
publickey: PublicKeyIdentityProvider
|
||||
// [DIDIdentityProvider.type]: DIDIdentityProvider,
|
||||
// [EthIdentityProvider.type]: EthIdentityProvider
|
||||
}
|
||||
const DefaultIdentityKeysPath = pathJoin('./orbitdb', 'identities')
|
||||
|
||||
/**
|
||||
* Creates an instance of Identities.
|
||||
@ -167,68 +161,6 @@ const Identities = async ({ keystore, path, storage, ipfs } = {}) => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an identity provider is supported.
|
||||
* @param {string} type The identity provider type.
|
||||
* @return {boolean} True if the identity provider is supported, false
|
||||
* otherwise.
|
||||
* @static
|
||||
*/
|
||||
const isProviderSupported = (type) => {
|
||||
return Object.keys(supportedTypes).includes(type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an identity provider.
|
||||
* @param {string} type The identity provider type.
|
||||
* @return {IdentityProvider} The IdentityProvider module corresponding to
|
||||
* type.
|
||||
* @throws IdentityProvider type is not supported if the identity provider is
|
||||
* not supported.
|
||||
* @static
|
||||
*/
|
||||
const getProviderFor = (type) => {
|
||||
if (!isProviderSupported(type)) {
|
||||
throw new Error(`IdentityProvider type '${type}' is not supported`)
|
||||
}
|
||||
|
||||
return supportedTypes[type]
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an identity provider.
|
||||
* @param {IdentityProvider} IdentityProvider The identity provider to add.
|
||||
* @throws IdentityProvider must be given as an argument if no module is
|
||||
* provided.
|
||||
* @throws 'Given IdentityProvider doesn't have a field 'type' if the
|
||||
* IdentityProvider does not include a type property.
|
||||
* @static
|
||||
*/
|
||||
const addIdentityProvider = (IdentityProvider) => {
|
||||
if (!IdentityProvider) {
|
||||
throw new Error('IdentityProvider must be given as an argument')
|
||||
}
|
||||
|
||||
if (!IdentityProvider.type ||
|
||||
typeof IdentityProvider.type !== 'string') {
|
||||
throw new Error('Given IdentityProvider doesn\'t have a field \'type\'')
|
||||
}
|
||||
|
||||
supportedTypes[IdentityProvider.type] = IdentityProvider
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an identity provider.
|
||||
* @param {string} type The identity provider type.
|
||||
* @static
|
||||
*/
|
||||
const removeIdentityProvider = (type) => {
|
||||
delete supportedTypes[type]
|
||||
}
|
||||
|
||||
export {
|
||||
Identities as default,
|
||||
isProviderSupported,
|
||||
addIdentityProvider,
|
||||
removeIdentityProvider
|
||||
Identities as default
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
* @description
|
||||
* An identity.
|
||||
*/
|
||||
|
||||
import * as Block from 'multiformats/block'
|
||||
import * as dagCbor from '@ipld/dag-cbor'
|
||||
import { sha256 } from 'multiformats/hashes/sha2'
|
||||
|
@ -1,9 +1,4 @@
|
||||
export {
|
||||
default as Identities,
|
||||
addIdentityProvider,
|
||||
removeIdentityProvider,
|
||||
isProviderSupported
|
||||
} from './identities.js'
|
||||
export { default as Identities } from './identities.js'
|
||||
|
||||
export {
|
||||
default as Identity,
|
||||
@ -11,4 +6,8 @@ export {
|
||||
isEqual
|
||||
} from './identity.js'
|
||||
|
||||
export { PublicKeyIdentityProvider } from './providers/index.js'
|
||||
export {
|
||||
PublicKeyIdentityProvider,
|
||||
addIdentityProvider,
|
||||
identityProviders
|
||||
} from './providers/index.js'
|
||||
|
@ -46,7 +46,68 @@
|
||||
*
|
||||
* where my-custom-identity-provider is the custom module.
|
||||
*/
|
||||
import * as PublicKeyIdentityProvider from './publickey.js'
|
||||
|
||||
const identityProviders = {
|
||||
publickey: PublicKeyIdentityProvider
|
||||
// [DIDIdentityProvider.type]: DIDIdentityProvider,
|
||||
// [EthIdentityProvider.type]: EthIdentityProvider
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an identity provider is supported.
|
||||
* @param {string} type The identity provider type.
|
||||
* @return {boolean} True if the identity provider is supported, false
|
||||
* otherwise.
|
||||
* @static
|
||||
*/
|
||||
const isProviderSupported = (type) => {
|
||||
return Object.keys(identityProviders).includes(type)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an identity provider.
|
||||
* @param {string} type The identity provider type.
|
||||
* @return {IdentityProvider} The IdentityProvider module corresponding to
|
||||
* type.
|
||||
* @throws IdentityProvider type is not supported if the identity provider is
|
||||
* not supported.
|
||||
* @static
|
||||
*/
|
||||
const getProviderFor = (type) => {
|
||||
if (!isProviderSupported(type)) {
|
||||
throw new Error(`IdentityProvider type '${type}' is not supported`)
|
||||
}
|
||||
|
||||
return identityProviders[type]
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an identity provider.
|
||||
* @param {IdentityProvider} IdentityProvider The identity provider to add.
|
||||
* @throws IdentityProvider must be given as an argument if no module is
|
||||
* provided.
|
||||
* @throws 'Given IdentityProvider doesn't have a field 'type' if the
|
||||
* IdentityProvider does not include a type property.
|
||||
* @static
|
||||
*/
|
||||
const addIdentityProvider = (IdentityProvider) => {
|
||||
if (!IdentityProvider) {
|
||||
throw new Error('IdentityProvider must be given as an argument')
|
||||
}
|
||||
|
||||
if (!IdentityProvider.type ||
|
||||
typeof IdentityProvider.type !== 'string') {
|
||||
throw new Error('Given IdentityProvider doesn\'t have a field \'type\'')
|
||||
}
|
||||
|
||||
if (identityProviders[IdentityProvider.type]) {
|
||||
throw new Error(`Type already added: ${IdentityProvider.type}`)
|
||||
}
|
||||
|
||||
identityProviders[IdentityProvider.type] = IdentityProvider
|
||||
}
|
||||
|
||||
// export { default as DIDIdentityProvider } from './did.js'
|
||||
// export { default as EthIdentityProvider } from './ethereum.js'
|
||||
export * as PublicKeyIdentityProvider from './publickey.js'
|
||||
export { identityProviders, addIdentityProvider, getProviderFor, PublicKeyIdentityProvider }
|
||||
|
@ -44,8 +44,8 @@ const PublicKeyIdentityProvider = ({ keystore }) => {
|
||||
/**
|
||||
* Gets the id.
|
||||
* @memberof module:IdentityProviders.IdentityProvider-PublicKey
|
||||
* @param {String} id The id to retrieve.
|
||||
* @return {String} The identity's id.
|
||||
* @param {string} id The id to retrieve.
|
||||
* @return {string} The identity's id.
|
||||
* @instance
|
||||
*/
|
||||
const getId = async ({ id } = {}) => {
|
||||
|
41
src/index.js
41
src/index.js
@ -1,8 +1,39 @@
|
||||
export { default as OrbitDB } from './orbitdb.js'
|
||||
export { databaseTypes, addDatabaseType } from './orbitdb.js'
|
||||
export { default as OrbitDBAddress, isValidAddress, parseAddress } from './address.js'
|
||||
export {
|
||||
default as OrbitDB,
|
||||
databaseTypes,
|
||||
addDatabaseType
|
||||
} from './orbitdb.js'
|
||||
|
||||
export {
|
||||
default as OrbitDBAddress,
|
||||
isValidAddress,
|
||||
parseAddress
|
||||
} from './address.js'
|
||||
|
||||
export { Log, Entry, DefaultAccessController } from './oplog/index.js'
|
||||
|
||||
export { default as Database } from './database.js'
|
||||
|
||||
export { default as KeyStore } from './key-store.js'
|
||||
export { Identities, isIdentity } from './identities/index.js'
|
||||
export { IPFSBlockStorage, LevelStorage, LRUStorage, MemoryStorage, ComposedStorage } from './storage/index.js'
|
||||
|
||||
export {
|
||||
addAccessController,
|
||||
removeAccessController,
|
||||
getAccessController,
|
||||
accessControllers
|
||||
} from './access-controllers/index.js'
|
||||
|
||||
export {
|
||||
Identities,
|
||||
isIdentity,
|
||||
identityProviders,
|
||||
addIdentityProvider
|
||||
} from './identities/index.js'
|
||||
|
||||
export {
|
||||
IPFSBlockStorage,
|
||||
LevelStorage,
|
||||
LRUStorage,
|
||||
MemoryStorage,
|
||||
ComposedStorage
|
||||
} from './storage/index.js'
|
||||
|
@ -1,4 +1,19 @@
|
||||
/* Lamport Clock */
|
||||
/**
|
||||
* @module Clock
|
||||
* @description
|
||||
* The lamport clock.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compares two clocks by time and then, time is the same, by id.
|
||||
*
|
||||
* compareClocks should never return zero (0). If it does, a and b refer to the
|
||||
* same clock.
|
||||
* @param {module:Clock} a The first clock.
|
||||
* @param {module:Clock} b The second clock.
|
||||
* @return {number} Returns a negative integer if clock a is less than clock b
|
||||
* otherwise a positive integer is returned.
|
||||
*/
|
||||
const compareClocks = (a, b) => {
|
||||
// Calculate the "distance" based on the clock, ie. lower or greater
|
||||
const dist = a.time - b.time
|
||||
@ -10,10 +25,22 @@ const compareClocks = (a, b) => {
|
||||
return dist
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances a clock's time by 1, returning a new instance of Clock.
|
||||
* @param {module:Clock} clock The clock to advance.
|
||||
* @return {module:Clock} A new instance of clock with time advanced by 1.
|
||||
*/
|
||||
const tickClock = (clock) => {
|
||||
return Clock(clock.id, ++clock.time)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of Clock.
|
||||
* @function
|
||||
* @param {string} id A unique identifier.
|
||||
* @param {number} [time=0] A natural number (including 0).
|
||||
* @instance
|
||||
*/
|
||||
const Clock = (id, time) => {
|
||||
time = time || 0
|
||||
|
||||
|
@ -26,7 +26,10 @@ function LastWriteWins (a, b) {
|
||||
* Sort two entries by their clock time.
|
||||
* @param {Entry} a First entry to compare
|
||||
* @param {Entry} b Second entry to compare
|
||||
* @param {function(a, b)} resolveConflict A function to call if entries are concurrent (happened at the same time). The function should take in two entries and return 1 if the first entry should be chosen and -1 if the second entry should be chosen.
|
||||
* @param {function(a, b)} resolveConflict A function to call if entries are
|
||||
* concurrent (happened at the same time). The function should take in two
|
||||
* entries and return 1 if the first entry should be chosen and -1 if the
|
||||
* second entry should be chosen.
|
||||
* @return {number} 1 if a is greater, -1 if b is greater
|
||||
*/
|
||||
function SortByClocks (a, b, resolveConflict) {
|
||||
@ -41,7 +44,9 @@ function SortByClocks (a, b, resolveConflict) {
|
||||
* Sort two entries by their clock id.
|
||||
* @param {Entry} a First entry to compare
|
||||
* @param {Entry} b Second entry to compare
|
||||
* @param {function(a, b)} resolveConflict A function to call if the clocks ids are the same. The function should take in two entries and return 1 if the first entry should be chosen and -1 if the second entry should be chosen.
|
||||
* @param {function(a, b)} resolveConflict A function to call if the clocks ids
|
||||
* are the same. The function should take in two entries and return 1 if the
|
||||
* first entry should be chosen and -1 if the second entry should be chosen.
|
||||
* @return {number} 1 if a is greater, -1 if b is greater
|
||||
*/
|
||||
function SortByClockId (a, b, resolveConflict) {
|
||||
@ -53,7 +58,8 @@ function SortByClockId (a, b, resolveConflict) {
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper function to throw an error if the results of a passed function return zero
|
||||
* A wrapper function to throw an error if the results of a passed function
|
||||
* return zero
|
||||
* @param {function(a, b)} [tiebreaker] The tiebreaker function to validate.
|
||||
* @return {function(a, b)} 1 if a is greater, -1 if b is greater
|
||||
* @throws {Error} if func ever returns 0
|
||||
|
@ -17,10 +17,13 @@ const hashStringEncoding = base58btc
|
||||
* Create an Entry
|
||||
* @param {Identity} identity The identity instance
|
||||
* @param {string} logId The unique identifier for this log
|
||||
* @param {*} data Data of the entry to be added. Can be any JSON.stringifyable data
|
||||
* @param {Clock} [clock] The clock
|
||||
* @param {Array<string|Entry>} [next=[]] An array of CIDs as base58btc encoded strings
|
||||
* @param {Array<string|Entry>} [refs=[]] An array of CIDs as base58btc encoded strings
|
||||
* @param {*} data Data of the entry to be added. Can be any JSON.stringifyable
|
||||
* data.
|
||||
* @param {module:Clock} [clock] The clock
|
||||
* @param {Array<string|Entry>} [next=[]] An array of CIDs as base58btc encoded
|
||||
* strings.
|
||||
* @param {Array<string|Entry>} [refs=[]] An array of CIDs as base58btc encoded
|
||||
* strings.
|
||||
* @return {Promise<Entry>}
|
||||
* @example
|
||||
* const entry = await Entry.create(identity, 'log1', 'hello')
|
||||
@ -59,7 +62,8 @@ const create = async (identity, id, payload, clock = null, next = [], refs = [])
|
||||
*
|
||||
* @param {Identities} identities Identities system to use
|
||||
* @param {Entry} entry The entry being verified
|
||||
* @return {Promise} A promise that resolves to a boolean value indicating if the signature is valid
|
||||
* @return {Promise} A promise that resolves to a boolean value indicating if
|
||||
* the signature is valid.
|
||||
*/
|
||||
const verify = async (identities, entry) => {
|
||||
if (!identities) throw new Error('Identities is required, cannot verify entry')
|
||||
|
@ -45,7 +45,7 @@ const DefaultAccessController = async () => {
|
||||
* @param {Object} options.access AccessController (./default-access-controller)
|
||||
* @param {Array<Entry>} options.entries An Array of Entries from which to create the log
|
||||
* @param {Array<Entry>} options.heads Set the heads of the log
|
||||
* @param {Clock} options.clock Set the clock of the log
|
||||
* @param {module:Clock} options.clock Set the clock of the log
|
||||
* @param {Function} options.sortFn The sort function - by default LastWriteWins
|
||||
* @return {module:Log~Log} sync An instance of Log
|
||||
* @memberof module:Log
|
||||
@ -80,7 +80,7 @@ const Log = async (identity, { logId, logHeads, access, entryStorage, headsStora
|
||||
|
||||
/**
|
||||
* Returns the clock of the log.
|
||||
* @return {Clock}
|
||||
* @return {module:Clock}
|
||||
* @memberof module:Log~Log
|
||||
* @instance
|
||||
*/
|
||||
|
@ -35,7 +35,7 @@ import OrbitDBAddress, { isValidAddress } from './address.js'
|
||||
import Manifests from './manifest.js'
|
||||
import { createId } from './utils/index.js'
|
||||
import pathJoin from './utils/path-join.js'
|
||||
import * as AccessControllers from './access-controllers/index.js'
|
||||
import { getAccessController } from './access-controllers/index.js'
|
||||
import IPFSAccessController from './access-controllers/ipfs.js'
|
||||
|
||||
/**
|
||||
@ -168,7 +168,7 @@ const OrbitDB = async ({ ipfs, id, identity, keystore, directory } = {}) => {
|
||||
manifest = await manifests.get(addr.path)
|
||||
const acType = manifest.accessController.split('/', 2).pop()
|
||||
const acAddress = manifest.accessController.replaceAll(`/${acType}/`, '')
|
||||
AccessController = AccessControllers.get(acType)()
|
||||
AccessController = getAccessController(acType)()
|
||||
accessController = await AccessController({ orbitdb: { open, identity, ipfs }, identities, address: acAddress })
|
||||
name = manifest.name
|
||||
type = type || manifest.type
|
||||
@ -234,4 +234,4 @@ const OrbitDB = async ({ ipfs, id, identity, keystore, directory } = {}) => {
|
||||
}
|
||||
}
|
||||
|
||||
export { OrbitDB as default, OrbitDBAddress, addDatabaseType, databaseTypes, AccessControllers }
|
||||
export { OrbitDB as default, OrbitDBAddress, addDatabaseType, databaseTypes }
|
||||
|
47
src/sync.js
47
src/sync.js
@ -18,26 +18,29 @@ const DefaultTimeout = 30000 // 30 seconds
|
||||
* When Sync is started, a peer subscribes to a pubsub topic of the log's id.
|
||||
* Upon subscribing to the topic, peers already connected to the topic receive
|
||||
* the subscription message and "dial" the subscribing peer using a libp2p
|
||||
* custom protocol. Once connected to the subscribing peer on a direct peer-to-peer
|
||||
* connection, the dialing peer and the subscribing peer exchange the heads of the Log
|
||||
* each peer currently has. Once completed, the peers have the same "local state".
|
||||
* custom protocol. Once connected to the subscribing peer on a direct
|
||||
* peer-to-peer connection, the dialing peer and the subscribing peer exchange * the heads of the Log each peer currently has. Once completed, the peers have * the same "local state".
|
||||
*
|
||||
* Once the initial sync has completed, peers notify one another of updates to the
|
||||
* log, ie. updates to the database, using the initially opened pubsub topic subscription.
|
||||
* A peer with new heads broadcasts changes to other peers by publishing the updated heads
|
||||
* to the pubsub topic. Peers subscribed to the same topic will then receive the update and
|
||||
* Once the initial sync has completed, peers notify one another of updates to
|
||||
* the log, ie. updates to the database, using the initially opened pubsub
|
||||
* topic subscription.
|
||||
* A peer with new heads broadcasts changes to other peers by publishing the
|
||||
* updated heads
|
||||
* to the pubsub topic. Peers subscribed to the same topic will then receive
|
||||
* the update and
|
||||
* will update their log's state, the heads, accordingly.
|
||||
*
|
||||
* The Sync Protocol is eventually consistent. It guarantees that once all messages
|
||||
* have been sent and received, peers will observe the same log state and values.
|
||||
* The Sync Protocol does not guarantee the order in which messages are received or
|
||||
* even that a message is recieved at all, nor any timing on when messages are received.
|
||||
* The Sync Protocol is eventually consistent. It guarantees that once all
|
||||
* messages have been sent and received, peers will observe the same log state
|
||||
* and values. The Sync Protocol does not guarantee the order in which messages
|
||||
* are received or even that a message is recieved at all, nor any timing on
|
||||
* when messages are received.
|
||||
*
|
||||
* Note that the Sync Protocol does not retrieve the full log when synchronizing the
|
||||
* heads. Rather only the "latest entries" in the log, the heads, are exchanged. In order
|
||||
* to retrieve the full log and each entry, the user would call the log.traverse() or
|
||||
* log.iterator() functions, which go through the log and retrieve each missing
|
||||
* log entry from IPFS.
|
||||
* Note that the Sync Protocol does not retrieve the full log when
|
||||
* synchronizing the heads. Rather only the "latest entries" in the log, the
|
||||
* heads, are exchanged. In order to retrieve the full log and each entry, the
|
||||
* user would call the log.traverse() or log.iterator() functions, which go
|
||||
* through the log and retrieve each missing log entry from IPFS.
|
||||
*
|
||||
* @example
|
||||
* // Using defaults
|
||||
@ -59,11 +62,13 @@ const DefaultTimeout = 30000 // 30 seconds
|
||||
* @param {Object} params One or more parameters for configuring Sync.
|
||||
* @param {IPFS} params.ipfs An IPFS instance.
|
||||
* @param {Log} params.log The log instance to sync.
|
||||
* @param {EventEmitter} [params.events] An event emitter to use. Events emitted are 'join', 'leave' and 'error'. If the parameter is not provided, an EventEmitter will be created.
|
||||
* @param {onSynced} [params.onSynced] A callback function that is called after the peer
|
||||
* has received heads from another peer.
|
||||
* @param {Boolean} [params.start] True if sync should start automatically, false
|
||||
* otherwise. Defaults to true.
|
||||
* @param {EventEmitter} [params.events] An event emitter to use. Events
|
||||
* emitted are 'join', 'leave' and 'error'. If the parameter is not provided,
|
||||
* an EventEmitter will be created.
|
||||
* @param {onSynced} [params.onSynced] A callback function that is called after
|
||||
* the peer has received heads from another peer.
|
||||
* @param {Boolean} [params.start] True if sync should start automatically,
|
||||
* false otherwise. Defaults to true.
|
||||
* @return {module:Sync~Sync} sync An instance of the Sync Protocol.
|
||||
* @memberof module:Sync
|
||||
* @instance
|
||||
|
48
test/fixtures/providers.js
vendored
Normal file
48
test/fixtures/providers.js
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
const customIdentityProvider = () => {
|
||||
const verifyIdentity = async (data) => { return true }
|
||||
|
||||
const CustomIdentityProvider = () => {
|
||||
const getId = () => { return 'custom' }
|
||||
|
||||
const signIdentity = (data) => { return `signature '${data}'` }
|
||||
|
||||
return {
|
||||
getId,
|
||||
signIdentity,
|
||||
type: 'custom'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
default: CustomIdentityProvider,
|
||||
type: 'custom',
|
||||
verifyIdentity
|
||||
}
|
||||
}
|
||||
|
||||
const fakeIdentityProvider = () => {
|
||||
const verifyIdentity = async (data) => { return false }
|
||||
|
||||
const FakeIdentityProvider = () => {
|
||||
const getId = () => { return 'pubKey' }
|
||||
|
||||
const signIdentity = (data) => { return `false signature '${data}'` }
|
||||
|
||||
return {
|
||||
getId,
|
||||
signIdentity,
|
||||
type: 'fake'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
default: FakeIdentityProvider,
|
||||
verifyIdentity,
|
||||
type: 'fake'
|
||||
}
|
||||
}
|
||||
|
||||
const CustomIdentityProvider = customIdentityProvider()
|
||||
const FakeIdentityProvider = fakeIdentityProvider()
|
||||
|
||||
export { CustomIdentityProvider, FakeIdentityProvider }
|
@ -3,8 +3,9 @@ import rmrf from 'rimraf'
|
||||
import { copy } from 'fs-extra'
|
||||
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
||||
import KeyStore, { signMessage, verifyMessage } from '../../src/key-store.js'
|
||||
import { Identities, addIdentityProvider, Identity, PublicKeyIdentityProvider } from '../../src/identities/index.js'
|
||||
import { Identities, identityProviders, addIdentityProvider, Identity, PublicKeyIdentityProvider } from '../../src/identities/index.js'
|
||||
import testKeysPath from '../fixtures/test-keys-path.js'
|
||||
import { CustomIdentityProvider, FakeIdentityProvider } from '../fixtures/providers.js'
|
||||
|
||||
const type = PublicKeyIdentityProvider.type
|
||||
const keysPath = './testkeys'
|
||||
@ -14,6 +15,15 @@ describe('Identities', function () {
|
||||
await copy(testKeysPath, keysPath)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
// reset the identityProviders.
|
||||
for (const [key] of Object.entries(identityProviders)) {
|
||||
if (key !== 'publickey') {
|
||||
delete identityProviders[key]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
await rmrf(keysPath)
|
||||
})
|
||||
@ -213,30 +223,8 @@ describe('Identities', function () {
|
||||
})
|
||||
|
||||
it('false signature doesn\'t verify', async () => {
|
||||
const IP = () => {
|
||||
const verifyIdentity = async (data) => { return false }
|
||||
|
||||
const FakeIdentityProvider = () => {
|
||||
const getId = () => { return 'pubKey' }
|
||||
|
||||
const signIdentity = (data) => { return `false signature '${data}'` }
|
||||
|
||||
return {
|
||||
getId,
|
||||
signIdentity,
|
||||
type: 'fake'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
default: FakeIdentityProvider,
|
||||
verifyIdentity,
|
||||
type: 'fake'
|
||||
}
|
||||
}
|
||||
|
||||
addIdentityProvider(IP())
|
||||
identity = await identities.createIdentity({ type: IP().type })
|
||||
addIdentityProvider(FakeIdentityProvider)
|
||||
identity = await identities.createIdentity({ type: FakeIdentityProvider.type })
|
||||
const verified = await identities.verifyIdentity(identity)
|
||||
assert.strictEqual(verified, false)
|
||||
})
|
||||
@ -345,4 +333,16 @@ describe('Identities', function () {
|
||||
assert.strictEqual(verified, false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('manage identity providers', () => {
|
||||
it('has default identity providers', () => {
|
||||
assert.deepStrictEqual(identityProviders, { publickey: PublicKeyIdentityProvider })
|
||||
})
|
||||
|
||||
it('can add an identity provider', () => {
|
||||
addIdentityProvider(CustomIdentityProvider)
|
||||
|
||||
assert.deepStrictEqual(identityProviders, { publickey: PublicKeyIdentityProvider, custom: CustomIdentityProvider })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { strictEqual, deepStrictEqual, notStrictEqual } from 'assert'
|
||||
import rmrf from 'rimraf'
|
||||
import * as IPFS from 'ipfs-core'
|
||||
import OrbitDB, { AccessControllers } from '../src/orbitdb.js'
|
||||
import OrbitDB from '../src/orbitdb.js'
|
||||
import { accessControllers, addAccessController, removeAccessController } from '../src/access-controllers/index.js'
|
||||
import config from './config.js'
|
||||
import pathJoin from '../src/utils/path-join.js'
|
||||
|
||||
@ -38,7 +39,7 @@ describe('Add a custom access controller', function () {
|
||||
}
|
||||
|
||||
// Remove the added custom database type from OrbitDB import
|
||||
AccessControllers.remove(type)
|
||||
removeAccessController(type)
|
||||
|
||||
await rmrf('./orbitdb')
|
||||
await rmrf('./ipfs1')
|
||||
@ -51,7 +52,7 @@ describe('Add a custom access controller', function () {
|
||||
'orbitdb'
|
||||
]
|
||||
|
||||
deepStrictEqual(Object.keys(AccessControllers.types), expected)
|
||||
deepStrictEqual(Object.keys(accessControllers), expected)
|
||||
})
|
||||
|
||||
it('throws and error if custom access controller hasn\'t been added', async () => {
|
||||
@ -71,7 +72,7 @@ describe('Add a custom access controller', function () {
|
||||
|
||||
describe('Custom access controller', function () {
|
||||
before(() => {
|
||||
AccessControllers.add(CustomAccessController)
|
||||
addAccessController(CustomAccessController)
|
||||
})
|
||||
|
||||
it('create a database with the custom access controller', async () => {
|
||||
@ -83,7 +84,7 @@ describe('Add a custom access controller', function () {
|
||||
it('throws and error if custom access controller already exists', async () => {
|
||||
let err
|
||||
try {
|
||||
AccessControllers.add(CustomAccessController)
|
||||
addAccessController(CustomAccessController)
|
||||
} catch (e) {
|
||||
err = e.toString()
|
||||
}
|
||||
@ -98,7 +99,7 @@ describe('Add a custom access controller', function () {
|
||||
type
|
||||
]
|
||||
|
||||
deepStrictEqual(Object.keys(AccessControllers.types), expected)
|
||||
deepStrictEqual(Object.keys(accessControllers), expected)
|
||||
})
|
||||
|
||||
it('can be removed from supported access controllers', async () => {
|
||||
@ -107,9 +108,9 @@ describe('Add a custom access controller', function () {
|
||||
'orbitdb'
|
||||
]
|
||||
|
||||
AccessControllers.remove(type)
|
||||
removeAccessController(type)
|
||||
|
||||
deepStrictEqual(Object.keys(AccessControllers.types), expected)
|
||||
deepStrictEqual(Object.keys(accessControllers), expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user