@fireproof/core 0.8.0 → 0.10.1-dev

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. package/README.md +5 -184
  2. package/dist/fireproof.browser.js +18879 -0
  3. package/dist/fireproof.browser.js.map +7 -0
  4. package/dist/fireproof.cjs.js +9305 -0
  5. package/dist/fireproof.cjs.js.map +7 -0
  6. package/dist/fireproof.esm.js +9295 -0
  7. package/dist/fireproof.esm.js.map +7 -0
  8. package/package.json +57 -105
  9. package/dist/blockstore.js +0 -268
  10. package/dist/clock.js +0 -459
  11. package/dist/crypto.js +0 -63
  12. package/dist/database.js +0 -434
  13. package/dist/db-index.js +0 -403
  14. package/dist/encrypted-block.js +0 -48
  15. package/dist/fireproof.js +0 -84
  16. package/dist/import.js +0 -29
  17. package/dist/listener.js +0 -111
  18. package/dist/loader.js +0 -13
  19. package/dist/prolly.js +0 -405
  20. package/dist/remote.js +0 -102
  21. package/dist/sha1.js +0 -74
  22. package/dist/src/fireproof.d.ts +0 -472
  23. package/dist/src/fireproof.js +0 -81191
  24. package/dist/src/fireproof.js.map +0 -1
  25. package/dist/src/fireproof.mjs +0 -81186
  26. package/dist/src/fireproof.mjs.map +0 -1
  27. package/dist/storage/base.js +0 -426
  28. package/dist/storage/blocksToEncryptedCarBlock.js +0 -144
  29. package/dist/storage/browser.js +0 -62
  30. package/dist/storage/filesystem.js +0 -67
  31. package/dist/storage/rest.js +0 -57
  32. package/dist/storage/ucan.js +0 -0
  33. package/dist/storage/utils.js +0 -144
  34. package/dist/sync.js +0 -218
  35. package/dist/utils.js +0 -16
  36. package/dist/valet.js +0 -102
  37. package/src/blockstore.js +0 -283
  38. package/src/clock.js +0 -486
  39. package/src/crypto.js +0 -70
  40. package/src/database.js +0 -469
  41. package/src/db-index.js +0 -426
  42. package/src/encrypted-block.js +0 -57
  43. package/src/fireproof.js +0 -98
  44. package/src/import.js +0 -34
  45. package/src/link.d.ts +0 -3
  46. package/src/loader.js +0 -16
  47. package/src/prolly.js +0 -445
  48. package/src/remote.js +0 -113
  49. package/src/sha1.js +0 -83
  50. package/src/storage/base.js +0 -463
  51. package/src/storage/browser.js +0 -67
  52. package/src/storage/filesystem.js +0 -73
  53. package/src/storage/rest.js +0 -59
  54. package/src/storage/ucan.js +0 -0
  55. package/src/storage/utils.js +0 -152
  56. package/src/sync.js +0 -237
  57. package/src/valet.js +0 -105
@@ -1,152 +0,0 @@
1
- import * as CBW from '@ipld/car/buffer-writer'
2
- import * as raw from 'multiformats/codecs/raw'
3
- import { encrypt, decrypt } from '../crypto.js'
4
- import { parse } from 'multiformats/link'
5
- import { sha256 } from 'multiformats/hashes/sha2'
6
- import * as Block from 'multiformats/block'
7
- import { Buffer } from 'buffer'
8
- // @ts-ignore
9
- import { bf } from 'prolly-trees/utils'
10
- // @ts-ignore
11
- import { nocache as cache } from 'prolly-trees/cache'
12
- const chunker = bf(30)
13
-
14
- export async function getEmptyLoader () { // unused?
15
- const theseWriteableBlocks = new VMemoryBlockstore()
16
- return {
17
- blocks: theseWriteableBlocks,
18
- put: async (cid, bytes) => {
19
- return await theseWriteableBlocks.put(cid, bytes)
20
- },
21
- get: async (cid) => {
22
- const got = await theseWriteableBlocks.get(cid)
23
- return got.bytes
24
- }
25
- }
26
- }
27
-
28
- export class VMemoryBlockstore {
29
- /** @type {Map<string, Uint8Array>} */
30
- blocks = new Map()
31
- instanceId = Math.random().toString(36).slice(2)
32
-
33
- async get (cid) {
34
- const bytes = this.blocks.get(cid.toString())
35
- if (!bytes) throw new Error('block not found ' + cid.toString())
36
- return { cid, bytes }
37
- }
38
-
39
- /**
40
- * @param {any} cid
41
- * @param {Uint8Array} bytes
42
- */
43
- async put (cid, bytes) {
44
- this.blocks.set(cid.toString(), bytes)
45
- }
46
-
47
- * entries () {
48
- for (const [str, bytes] of this.blocks) {
49
- yield { cid: parse(str), bytes }
50
- }
51
- }
52
- }
53
-
54
- export const blocksToCarBlock = async (rootCids, blocks) => {
55
- // console.log('blocksToCarBlock', rootCids, blocks.constructor.name)
56
- let size = 0
57
- if (!Array.isArray(rootCids)) {
58
- rootCids = [rootCids]
59
- }
60
- const headerSize = CBW.headerLength({ roots: rootCids })
61
- size += headerSize
62
- if (!Array.isArray(blocks)) {
63
- blocks = Array.from(blocks.entries())
64
- }
65
- for (const { cid, bytes } of blocks) {
66
- // console.log(cid, bytes)
67
- size += CBW.blockLength({ cid, bytes })
68
- }
69
- const buffer = new Uint8Array(size)
70
- const writer = await CBW.createWriter(buffer, { headerSize })
71
-
72
- for (const cid of rootCids) {
73
- writer.addRoot(cid)
74
- }
75
-
76
- for (const { cid, bytes } of blocks) {
77
- writer.write({ cid, bytes })
78
- }
79
- await writer.close()
80
- return await Block.encode({ value: writer.bytes, hasher: sha256, codec: raw })
81
- }
82
-
83
- export const blocksToEncryptedCarBlock = async (innerBlockStoreClockRootCid, blocks, keyMaterial, cids) => {
84
- const encryptionKey = Buffer.from(keyMaterial, 'hex')
85
- const encryptedBlocks = []
86
- const theCids = cids
87
- // console.trace('blocksToEncryptedCarBlock', blocks)
88
- // for (const { cid } of blocks.entries()) {
89
- // theCids.push(cid.toString())
90
- // }
91
- // console.log(
92
- // 'encrypting',
93
- // theCids.length,
94
- // 'blocks',
95
- // theCids.includes(innerBlockStoreClockRootCid.toString()),
96
- // keyMaterial
97
- // )
98
- // console.log('cids', theCids, innerBlockStoreClockRootCid.toString())
99
- let last
100
- for await (const block of encrypt({
101
- cids: theCids,
102
- get: async (cid) => {
103
- // console.log('getencrypt', cid)
104
- const got = blocks.get(cid)
105
- // console.log('got', got)
106
- return got.block ? ({ cid, bytes: got.block }) : got
107
- },
108
- key: encryptionKey,
109
- hasher: sha256,
110
- chunker,
111
- cache,
112
- // codec: dagcbor, // should be crypto?
113
- root: innerBlockStoreClockRootCid
114
- })) {
115
- encryptedBlocks.push(block)
116
- last = block
117
- }
118
- // console.log('last', last.cid.toString(), 'for clock', innerBlockStoreClockRootCid.toString())
119
- const encryptedCar = await blocksToCarBlock(last.cid, encryptedBlocks)
120
- return encryptedCar
121
- }
122
-
123
- // { root, get, key, cache, chunker, hasher }
124
- const memoizeDecryptedCarBlocks = new Map()
125
- export const blocksFromEncryptedCarBlock = async (cid, get, keyMaterial) => {
126
- if (memoizeDecryptedCarBlocks.has(cid.toString())) {
127
- return memoizeDecryptedCarBlocks.get(cid.toString())
128
- } else {
129
- const blocksPromise = (async () => {
130
- const decryptionKey = Buffer.from(keyMaterial, 'hex')
131
- // console.log('decrypting', keyMaterial, cid.toString())
132
- const cids = new Set()
133
- const decryptedBlocks = []
134
- for await (const block of decrypt({
135
- root: cid,
136
- get,
137
- key: decryptionKey,
138
- chunker,
139
- hasher: sha256,
140
- cache
141
- // codec: dagcbor
142
- })) {
143
- // console.log('decrypted', block.cid.toString())
144
- decryptedBlocks.push(block)
145
- cids.add(block.cid.toString())
146
- }
147
- return { blocks: decryptedBlocks, cids }
148
- })()
149
- memoizeDecryptedCarBlocks.set(cid.toString(), blocksPromise)
150
- return blocksPromise
151
- }
152
- }
package/src/sync.js DELETED
@@ -1,237 +0,0 @@
1
- import SimplePeer from 'simple-peer'
2
- import { parseCID } from './database.js'
3
- import { decodeEventBlock } from './clock.js'
4
- import { blocksToCarBlock, blocksToEncryptedCarBlock } from './storage/utils.js'
5
- import { CarReader } from '@ipld/car'
6
-
7
- /**
8
- * @typedef {import('./database.js').Database} Database
9
- */
10
- export class Sync {
11
- /**
12
- * @param {Database} database
13
- * @param {typeof SimplePeer} [PeerClass]
14
- * @memberof Sync
15
- * @static
16
- */
17
- status = 'new'
18
- constructor (database, PeerClass = SimplePeer) {
19
- this.database = database
20
- this.database.blocks.syncs.add(this) // should this happen during setup?
21
- this.PeerClass = PeerClass
22
- this.pushBacklog = new Promise((resolve, reject) => {
23
- this.pushBacklogResolve = resolve
24
- this.pushBacklogReject = reject
25
- })
26
- this.isReady = false
27
- // this.pushBacklog.then(() => {
28
- // // console.log('sync backlog resolved')
29
- // this.database.notifyReset()
30
- // })
31
- // this.connected = new Promise((resolve, reject) => {
32
- // this.readyResolve = resolve
33
- // this.readyReject = reject
34
- // })
35
- }
36
-
37
- async offer () {
38
- this.status = 'offering'
39
- return this.setupPeer(true)
40
- }
41
-
42
- async accept (base64offer) {
43
- const offer = JSON.parse(atob(base64offer))
44
- const p = this.setupPeer(false)
45
- this.peer.signal(offer)
46
- this.status = 'accepting'
47
- return p
48
- }
49
-
50
- connect (base64accept) {
51
- const accept = JSON.parse(atob(base64accept))
52
- this.status = 'connecting'
53
- this.peer.signal(accept)
54
- }
55
-
56
- async setupPeer (initiator = false) {
57
- this.peer = new this.PeerClass({
58
- initiator,
59
- trickle: false
60
- })
61
- this.peer.on('connect', () => this.startSync())
62
- this.peer.on('data', data => this.gotData(data))
63
- const p = new Promise((resolve, reject) => {
64
- this.peer.on('signal', resolve)
65
- this.peer.on('error', reject)
66
- })
67
- return p.then(signal => btoa(JSON.stringify(signal)))
68
- }
69
-
70
- async backlog () {
71
- return this.pushBacklog
72
- }
73
-
74
- async gotData (data) {
75
- // console.log('got data', data.toString())
76
- let reader = null
77
- try {
78
- reader = await CarReader.fromBytes(data)
79
- } catch (e) {
80
- // console.log('not a car', data.toString())
81
- }
82
- if (reader) {
83
- // console.log('got car')
84
- this.status = 'parking car'
85
- const blz = new Set()
86
- for await (const block of reader.blocks()) {
87
- blz.add(block)
88
- }
89
- const roots = await reader.getRoots()
90
- // console.log(
91
- // 'got car',
92
- // roots.map(c => c.toString()),
93
- // this.database.clock.map(c => c.toString())
94
- // )
95
- // console.log(
96
- // 'got blocks!',
97
- // [...blz].map(({ cid }) => cid.toString())
98
- // )
99
- // @ts-ignore
100
- reader.entries = reader.blocks
101
- await this.database.blocks.commit(
102
- {
103
- label: 'sync',
104
- entries: () => [...blz],
105
- get: async cid => await reader.get(cid),
106
- lastCid: [...blz][0].cid // doesn't matter
107
- },
108
- false
109
- )
110
- // first arg could be the roots parents?
111
- // get the roots parents
112
- const parents = await Promise.all(
113
- roots.map(async cid => {
114
- const rbl = await reader.get(cid)
115
- if (!rbl) {
116
- console.log('missing root block', cid.toString(), reader)
117
- throw new Error('missing root block')
118
- }
119
- const block = await decodeEventBlock(rbl.bytes)
120
- return block.value.parents
121
- })
122
- )
123
- this.database.applyClock(parents.flat(), roots)
124
- this.database.notifyReset()
125
- // console.log('after', this.database.clockToJSON())
126
- this.pushBacklogResolve({ ok: true })
127
- } else {
128
- // data is a json string, parse it
129
- const message = JSON.parse(data.toString())
130
- // console.log('got message', message)
131
- if (message.ok) {
132
- this.status = 'ok'
133
- this.pushBacklogResolve({ ok: true })
134
- } else if (message.clock) {
135
- const reqCidDiff = message
136
- // this might be a CID diff
137
- // console.log('got diff', reqCidDiff)
138
- const carBlock = await Sync.makeCar(this.database, null, reqCidDiff.cids)
139
- if (!carBlock) {
140
- // we are full synced
141
- // console.log('we are full synced')
142
- this.status = 'full synced'
143
- this.peer.send(JSON.stringify({ ok: true }))
144
- // this.pushBacklogResolve({ ok: true })
145
- } else {
146
- // console.log('do send diff', carBlock.bytes.length)
147
- this.status = 'sending diff car'
148
- this.peer.send(carBlock.bytes)
149
- // console.log('sent diff car')
150
- // this.pushBacklogResolve({ ok: true })
151
- }
152
- }
153
- }
154
- }
155
-
156
- destroy () {
157
- this.database.blocks.syncs.delete(this)
158
- this.status = 'destroyed'
159
- // this.peer.destroy() todo
160
- }
161
-
162
- async sendUpdate (blockstore) {
163
- if (!this.peer || !this.isReady) return
164
- // console.log('send update from', this.database.instanceId)
165
- // todo should send updates since last sync (currently sends each transaction)
166
- const newCar = await blocksToCarBlock(blockstore.lastCid, blockstore)
167
- this.status = 'sending update car'
168
- this.peer.send(newCar.bytes)
169
- }
170
-
171
- async startSync () {
172
- // console.log('start sync', this.peer.initiator)
173
- this.isReady = true
174
- const allCIDs = await this.database.allStoredCIDs()
175
- // console.log('allCIDs', allCIDs)
176
- const reqCidDiff = {
177
- clock: this.database.clockToJSON(),
178
- cids: allCIDs.map(cid => cid.toString())
179
- }
180
- // console.log('send diff', reqCidDiff)
181
- this.status = 'sending cid diff'
182
- this.peer.send(JSON.stringify(reqCidDiff))
183
- }
184
-
185
- // get all the cids
186
- // tell valet to make a file
187
- /**
188
- * @param {import("./database.js").Database} database
189
- * @param {string} key
190
- */
191
- static async makeCar (database, key, skip = []) {
192
- const allCIDs = await database.allCIDs()
193
- const blocks = database.blocks
194
- const rootCIDs = database.clock
195
-
196
- const newCIDs = [...new Set([...rootCIDs, ...allCIDs])].filter(cid => !skip.includes(cid.toString()))
197
- const syncCIDs = [...new Set([...rootCIDs, ...allCIDs.filter(cid => !skip.includes(cid.toString()))])]
198
- // console.log(
199
- // 'makeCar',
200
- // rootCIDs.map(c => c.toString()),
201
- // syncCIDs.map(c => c.toString()),
202
- // allCIDs.map(c => c.toString())
203
- // )
204
- if (newCIDs.length === 0) {
205
- return null
206
- }
207
-
208
- if (typeof key === 'undefined') {
209
- key = blocks.valet?.primary.keyMaterial
210
- }
211
- if (key) {
212
- return blocksToEncryptedCarBlock(
213
- rootCIDs,
214
- {
215
- entries: () => syncCIDs.map(cid => ({ cid })),
216
- get: async cid => await blocks.get(cid)
217
- },
218
- key,
219
- syncCIDs.map(c => c.toString())
220
- )
221
- } else {
222
- const carBlocks = await Promise.all(
223
- syncCIDs.map(async c => {
224
- const b = await blocks.get(c)
225
- if (typeof b.cid === 'string') {
226
- b.cid = parseCID(b.cid)
227
- }
228
- return b
229
- })
230
- )
231
- // console.log('carblock')
232
- return blocksToCarBlock(rootCIDs, {
233
- entries: () => carBlocks
234
- })
235
- }
236
- }
237
- }
package/src/valet.js DELETED
@@ -1,105 +0,0 @@
1
-
2
- import { Loader } from './loader.js'
3
-
4
- export class Valet {
5
- idb = null
6
- name = null
7
- uploadQueue = null
8
- alreadyEnqueued = new Set()
9
-
10
- instanceId = Math.random().toString(36).slice(2)
11
-
12
- constructor (name = 'default', config = {}) {
13
- this.name = name
14
- // console.log('new Valet', name, config.primary)
15
- this.primary = Loader.appropriate(name, config.primary)
16
- this.secondary = config.secondary ? Loader.appropriate(name, config.secondary) : null
17
- // set up a promise listener that applies all the headers to the clock
18
- // when they resolve
19
- const readyP = [this.primary.ready]
20
- if (this.secondary) readyP.push(this.secondary.ready)
21
-
22
- this.ready = Promise.all(readyP).then((blocksReady) => {
23
- // console.log('blocksReady valet', this.name, blocksReady)
24
- return blocksReady
25
- })
26
- }
27
-
28
- async saveHeader (header) {
29
- // each storage needs to add its own carCidMapCarCid to the header
30
- if (this.secondary) { this.secondary.saveHeader(header) } // todo: await?
31
- return await this.primary.saveHeader(header)
32
- }
33
-
34
- async compact (clock) {
35
- await this.primary.compact(clock)
36
- if (this.secondary) await this.secondary.compact(clock)
37
- }
38
-
39
- /**
40
- * Group the blocks into a car and write it to the valet.
41
- * @param {import('./blockstore.js').InnerBlockstore} innerBlockstore
42
- * @param {Set<string>} cids
43
- * @returns {Promise<void>}
44
- * @memberof Valet
45
- */
46
- async writeTransaction (innerBlockstore, cids) {
47
- if (innerBlockstore.lastCid) {
48
- await this.primary.parkCar(innerBlockstore, cids)
49
- if (this.secondary) await this.secondary.parkCar(innerBlockstore, cids)
50
- } else {
51
- throw new Error('missing lastCid for car header')
52
- }
53
- }
54
-
55
- /**
56
- * Iterate over all blocks in the store.
57
- *
58
- * @yields {{cid: string, value: Uint8Array}}
59
- * @returns {AsyncGenerator<any, any, any>}
60
- */
61
- async * cids () {
62
- // console.log('valet cids')
63
- // todo use cidMap
64
- // while (cursor) {
65
- // yield { cid: cursor.key, car: cursor.value.car }
66
- // cursor = await cursor.continue()
67
- // }
68
- }
69
-
70
- remoteBlockFunction = null
71
-
72
- async getValetBlock (dataCID) {
73
- // console.log('getValetBlock primary', dataCID)
74
- try {
75
- const { block } = await this.primary.getLoaderBlock(dataCID)
76
- return block
77
- } catch (e) {
78
- // console.log('getValetBlock error', e)
79
- if (this.secondary) {
80
- // console.log('getValetBlock secondary', dataCID)
81
- try {
82
- // eslint-disable-next-line
83
- const { block, reader } = await this.secondary.getLoaderBlock(dataCID)
84
- const writeableCarReader = await this.primary.getWriteableCarReader(reader)
85
- // console.log('getValetBlock secondary', dataCID, block.length)
86
- // eslint-disable-next-line
87
- const cids = new Set()
88
- for await (const { cid } of reader.entries()) {
89
- // console.log(cid, bytes)
90
- cids.add(cid.toString())
91
- }
92
- // reader.get = reader.gat // some consumers prefer get
93
- // console.log('replicating', reader.root)
94
- writeableCarReader.lastCid = reader.root.cid
95
- writeableCarReader.head = []
96
- await this.primary.parkCar(writeableCarReader, cids).catch(e => console.error('parkCar error', e))
97
- // console.log('FIX THIS', did)
98
- return block
99
- } catch (e) {
100
- // console.log('getValetBlock secondary error', e)
101
- }
102
- }
103
- }
104
- }
105
- }