npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

datoms

v1.3.0

Published

datom is the {smallest, accountable, tradable} data assets block

Downloads

9

Readme

datoms协议

Datoms是个人数据资产化协议堆栈中的最底层协议。

datom是最小的可交易数据资产单元

  • 数据资产的最小单元是datom。
  • 每一个datom都采用append-only log结构,具备很好的底层数据资产治理结构。
  • 每一个datom都可以设置对应的权限、隐私保护以及其他安全使用要求。
  • 每一个datom都是可交易的。
  • 每一个datom都可以单独确权。
  • 每一个datom都可以单独计量。
  • 每一个datom都可以单独进行权限设置、访问控制。

1. datom的结构

一个datom是具有如下标准结构的文件集合。通常包括六个文件(datoms v1.3.0版本):

  • 1.1 [bitfield][bitefield]

    采用bitfield对datom的一些状态进行二进制编码(es6标准,前缀为0b)。

    state:
    		{
          var1: fales,
          var2: true,
          var3: false,
        }
    //上述状态用es6的bitfield表示:
    const state = 0b010 
  • 1.2 data

​ 采用wc3 VCs数据模型 的数据资产。一般包括原始数据,metadata以及(数据控制者)数字签名,可验证。VCs数据模型的结构示意图示例如下:

示例: Alice在JD的消费数据。
1. Alice的请求JD,复制其在JD在【2018/1/1-2019/1/1】的个人全部消费数据;
2. JD根据Alice的请求,按照peopledata的规范或行业规范,提供Alice上述数据。
3. 为保证复制到Alice后的数据可信,JD需要生成的数据格式示例如下:
{
  "@context": [         
    "https://www.peopledata.org.cn/2022/data/cusmerdata/v1"   //peopledata拟定的电子商务消费数据规范
  ],   
  
  "id": "metachain DID",  //由metachain分配给Alice的DID.
  
  //metadata
  
  "type": ["cusumer e-commerce data"],   //数据类型
  
  "issuer": "https://www.jd.com/xxxxxxxx",  //数据发布者:JD给Alice在JD的消费数据发布
  
  "issuanceDate": "2022-01-01T19:23:24Z",    //数据发布日期
  
  "rawdata": {                                   //原始数据
    
    "id": "did:jd:ebfeb1f712ebc6f1c276e12ec21",    // 原始数据的DID。
    
    "cusumerdata": {
      "startDate":2018/1/1 ,
      "endDate"": 2019/1/1 ,
      records:{
     //JD 自定义的个人消费数据规范格式的数据。
      	
      “时间”:xxxxx;
      .....
    		
    		
    	 }
    
     }
  
  
  "proof": {  //JD提供的签名proof,证明1)Alice的消费数据以及metadata是JD提供的;2)验证的方法;
    
    "type": "RsaSignature2018",
    
    "created": "2022-01-18T21:19:10Z",
    
    "proofPurpose": "assertionMethod",
    
    "verificationMethod": "https://www.jd.com/issuers/#key-1",
    
    "jws": "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..TCYt5X
      sITJX1CxPCT8yAV-TVkIEq_PbChOMqsLfRoPsnsgw5WEuts01mq-pQy7UJiN5mgRxD-WUc
      X16dUEMGlv50aqzpqh4Qktb3rk-BuQy72IFLOqV0G_zS245-kronKb78cPN25DGlcTwLtj
      PAYuNzVBAh4vGHSrQyHUdBBPM"
  }

//为防止中间传输过程中出现攻击/泄漏,提供的证明。
"proof": {
    "type": "RsaSignature2018",
    "created": "2022-01-18T21:19:10Z",
    "proofPurpose": "authentication",
    "verificationMethod": "did:JD:ebfeb1f712ebc6f1c276e12ec21#keys-1",
    
    "challenge": "1f44d55f-f161-4938-a659-f8026467f126",
    "domain": "4jt78h47fh47",
    "jws": "eyJhbGciOiJSUzI1NiIsImI2NCI6ZmFsc2UsImNyaXQiOlsiYjY0Il19..kTCYt5
      XsITJX1CxPCT8yAV-TVIw5WEuts01mq-pQy7UJiN5mgREEMGlv50aqzpqh4Qq_PbChOMqs
      LfRoPsnsgxD-WUcX16dUOqV0G_zS245-kronKb78cPktb3rk-BuQy72IFLN25DYuNzVBAh
      4vGHSrQyHUGlcTwLtjPAnKb78"
  }
}

对于dataom来说,这个[data]项是其“有效载荷”。

metadata主要来自数据发布者(控制者),提供metadata主要是对发布的个人数据提供可溯源、可验证的凭证。

proof主要有几种形式:

  • 数据发布者数字签名;
数据发布者用自己专用的私钥进行数字签名。并提供验证的方法(methold)。
验证者可以参考数据发布者公开的url,对此签名进行验证。
  • 中间人数字签名;
流通链条上经过的任何设备、实体的数字签名。
为溯源提供可验证的凭证。
  • Witness 方签名;
witeness方对任何需要见证的事件进行签名。
  • 交易签名;
对任何更新、更改事项(状态改变)的签名。
谁做的修改、更新。
  • ZKP零知识证明【可选】
采用ZKP-SNACK进行的non-interactive的零知识证明。
针对特定场景,需要非交互式的ZKP。
  • 1.3 key
由一个masterkey生成的private-key.
拥有此key,才能访问datom。
  • 1.4 secret_key 右crypto.keyPair()生成的key。
const crypto = require('datom-crypto')

//生成一对新的keyPair: {keyPair.PublicKey, keyPair.secretKey}

const keyPair = crypto.keyPair()
  
console.log('publicKey is ',keyPair.publicKey.toString('hex'))
console.log('secretKey is',keyPair.secretKey.toString('hex'))
  • 1.5 signatures
对数据块的签名。
signature = crypto.sign(data_block, secretKey)
  • 1.6 tree 该datom对应的merkle tree的hash(root_node).
对datom的数据块计算merkle tree。并把root hash存储在此。以作为后续审计和验证。
hash = crypto.data(data) 
hash = crypto.parent(left,right) 
{
  index: treeIndex,
  hash: hashOfThisNode,
  size: byteSizeOfThisTree
}
hash = crypto.tree(peaks) 
  • 1.7 [可选项] (后续版本可以根据数据类型增加一些自定义添加项)。

    可自定义的添加项。

2. datoms

若干个datom(最小数据资产块)组合构成datoms。 datoms按照数据资产类别进行分类。可以是同一种类的数据,也可以不是同一类的。

每一个datom的结构如下:

datom:
- bitfield
- data
- key
- name
- sign
- tree

不同datom在一个space中。一个示例:

开始使用

  1. 安装软件包 系统配置要求:
  1. node 14.0以上

npm i datoms

  1. 编写代码(示例)
const datoms = require('datoms')

const datom = toPromises(datoms('存储地址', {
    valueEncoding: 'json' // 数据采用json。也支持binary和其他函数对象。
  }))

//添加一个datom。可以添加任意多个。
await datom.append({
      name: 'name',
      Company: 'company',
      jobTitle: 'jobTitle',
      Tel: 'phoneNumbe',
      City: 'city',
      Address: 'streetAddress',
      emal: 'email',
      zipcode: 'zipCode'
})

//读取datom
datom.createReadStream()
        .on('data', console.log)
        .on('end', console.log.bind(console, '\n(end)'))

API

var datom = datoms(storage, [key],[options])

创建一个新的datom. [storage]为存储数据或metadata的目录。

var datom = datoms('./dir')   //数据存储到./dir目录中

[key]是datom的public key。如果不设置[key],则默认从存储目录中的key文件中读取。如果没有[key],则系统自动生成一个密钥对。

[options]包括:

{
  createIfMissing: true, // 如果在存储中没有key pair,则创建一个新的。
  overwrite: false, // 是否覆盖任何已经存在的datom
  valueEncoding: 'json' | 'utf-8' | 'binary', // data的类型
  sparse: false, // 不需要下载全部datom
  eagerUpdate: true, // 始终更新
  secretKey: buffer, // 自己传递secret key
  storeSecretKey: true, // 是否存secret key
  storageCacheSize: 65536, // 存储缓存最大entry的数量
  onwrite: (index, data, peer, cb) // 在数据验证后写入(选项) 
                                   // 
  stats: true // 收集网络统计信息
  // 自定义加密签名(可选)
  crypto: {
    sign (data, secretKey, cb(err, signature)),
    verify (signature, data, key, cb(err, valid))
  }
  noiseKeyPair: { publicKey, secretKey } // 设置noise通信协议需要的key pair
}

注意: [key]和[secretkey]是node.js的buffer instances,而非浏览器的arraybuffer instance。在浏览器中使用,需要用Feross's buffer模式。

const storage = someRandomAccessStorage
const myPublicKey = someUint8Array

const Buffer = require('buffer').Buffer
const PublicKeyBuffer = Buffer.from(myPublicKey.buffer)

const datom = datoms(storage, PublicKeyBuffer)

datom.append(data,[callback])

添加一个数据块到datom。 [callback]回调(err,seq)。[seq]是数据添加后返回的序列号。

const id = datom.get(index, [options], callback)

从datom调取一个数据块。 [options]包括:

{
  wait: true, // 等待索引下载完毕
  onwait: () => {}, //  如果等待下载,则hook
  timeout: 0, // 
  valueEncoding: 'json' | 'utf-8' | 'binary' // 
}

datom.getBatch(start, end, [options], callback)

读取一个区间范围内的数据块。 [options]包括:

{
  wait: sameAsAbove,
  timeout: sameAsAbove,
  valueEncoding: sameAsAbove
}

datom.cancel(getId)

取消一个正在pending的get操作。

datom.head([options], callback)

读取一个数据块的最新更新的。

const id = datom.download([range], [callback])

下载一个区间的数据。 [range]包含以下选项:

{
  start: startIndex,
  end: nonInclusiveEndIndex,
  linear: false // download range linearly and not randomly
}

如果不指定区间,则下载全部数据。

也可以指定特点的区块。

{
  blocks: [0, 1, 4, 10] // will download those 4 blocks as fast as possible
}

datom.undownload(downloadId)

取消一个正在penging的下载请求。

datom.signature([index], callback)

得到某个[index]数据块的签名,或整个[stream]的签名。

{
  index: lastSignedBlock,
  signature: Buffer
}

datom.verify(index, signature, callback)

验证一个[index]数据块的签名。

datom.rootHashes(index, callback)

取回一个[index]数据块的roothash。 回调返回(err,roots)。[roots]是merkle tree中的一组node。

Node {
  index: merkle tree的根节点的index.
  size: 这个root下的子node的总字节数
  hash: root下的子node的hash(32-byte buffer)
}

var number = datom.downloaded([start], [end])

返回从[start]到[end]下载的数量。

var bool = datom.has(index)

查询是否存在[index]的数据块。

var bool = datom.has(start, end)

查询是否存在[start]到[end]区间的数据块。

var stream = datom.createReadStream([options])

创建一个可以读取数据的stream[js]。

{
  start: 0, // 开始的index
  end: datom.length, // 得到结尾为止
  snapshot: true, // 每次是否都读到结尾为止
  tail: false, // 设定 `start` 到 `datom.length`
  live: false, // 设定保持读状态
  timeout: 0, // 每次事件的timeout (0 means no timeout)
  wait: true, // 当数据下载是等待
  batch: 1 // 每批次读取的message的数量
}

var stream = datom.replicate(isInitiator, [options])

创建一个replicate的stream。

// 假设有两个datoms, localdatom + remotedatom, 使用相同的key。
var net = require('net')
var server = net.createServer(function (socket) {
  socket.pipe(remotedatom.replicate(false)).pipe(socket)
})

// 在客户端
var socket = net.connect(...)
socket.pipe(localdatom.replicate(true)).pipe(socket)

Options include:

{
  live: false, // 当所有数据下载完后,是否保持replicate
  ack: false, // 当设定为true时:一个peer写操作时,会被告知。
  download: true, // 从peer下载数据吗?
  upload: true, // 从peer上传数据吗?
  encrypted: true, // 用key pair加密数据
  noise: true, // 是否采用noise加密通信p2p协议
  keyPair: { publicKey, secretKey }, // 用这个key pair为noise加密
  onauthenticate (remotePublicKey, done) //当远程主机认证时,hook这个key
}

datom.close([callback])

关闭一个datom。

datom.destroyStorage([callback])

删除全部datom并关闭。

datom.audit([callback])

审计datom中的所有数据。与merkle tree中的hash比较,如果不一致,则clear bitfield。

{
  valid: 10, // 有多少数据满足hash。
  invalid: 0, // 有多少数据不满足hash。
}

datom.writable

datom是否可写?

datom.readable

datom是否可读?

datom.key

datom的publiic key

datom.discoveryKey

datom的discoverykey

datom.length

datom的长度

datom.byteLength

datom的子节长度

datom.stats

datom的统计信息。

{
  totals: {
    uploadedBytes: 100,
    uploadedBlocks: 1,
    downloadedBytes: 0,
    downloadedBlocks: 0
  },
  peers: [
    {
      uploadedBytes: 100,
      uploadedBlocks: 1,
      downloadedBytes: 0,
      downloadedBlocks: 0
    },
    ...
  ]
}

datom.on('peer-add', peer)

当有新的peer加入时emmitted。

datom.on('peer-remove', peer)

当有peer退出时emmitted。

datom.on('peer-open', peer)

当有一个peer channel打开时emmitted。

datom.peers

所有peers的列表。

ext = datom.registerExtension(name, handlers)

注册一个replication extension。

{
  encoding: 'json' | 'binary' | 'utf-8' | anyAbstractEncoding,
  onmessage (message, peer) { //called 当收到peer发出的信息。
  },
  onerror (err) {
  }
}

ext.send(message, peer)

发出一个extension message给一个特点的peer。

ext.broadcast(message)

广播一个extension message个所有链接的peer.

peer.publicKey

peer的key.

datom.on('ready')

当datom就绪emitted。

datom.on('error', err)

当遇到错误emitted.

datom.on('download', index, data)

下载[index]的数据emitted。

datom.on('upload', index, data)

当数据上传时emitted.

datom.on('append')

当有新的数据appned时emitted。

datom.on('sync')

当数据从0到datom.length全部下载完后emitted。

datom.on('close')

当datom全部关闭时emitted。

附录:

License

@jerry.zhang[email protected]

MIT