@fireproof/core 0.10.0-dev → 0.10.1-dev
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.
- package/package.json +5 -1
- package/.eslintrc.cjs +0 -37
- package/.vscode/launch.json +0 -12
- package/dist/crdt-helpers.browser.js +0 -4961
- package/dist/crdt-helpers.browser.js.map +0 -7
- package/dist/crdt-helpers.cjs.js +0 -4823
- package/dist/crdt-helpers.cjs.js.map +0 -7
- package/dist/crdt-helpers.esm.js +0 -4788
- package/dist/crdt-helpers.esm.js.map +0 -7
- package/dist/crdt.browser.js +0 -18214
- package/dist/crdt.browser.js.map +0 -7
- package/dist/crdt.cjs.js +0 -8692
- package/dist/crdt.cjs.js.map +0 -7
- package/dist/crdt.esm.js +0 -8682
- package/dist/crdt.esm.js.map +0 -7
- package/dist/database.browser.js +0 -18867
- package/dist/database.browser.js.map +0 -7
- package/dist/database.cjs.js +0 -9296
- package/dist/database.cjs.js.map +0 -7
- package/dist/database.esm.js +0 -9288
- package/dist/database.esm.js.map +0 -7
- package/dist/loader-helpers.browser.js +0 -6943
- package/dist/loader-helpers.browser.js.map +0 -7
- package/dist/loader-helpers.cjs.js +0 -4419
- package/dist/loader-helpers.cjs.js.map +0 -7
- package/dist/loader-helpers.esm.js +0 -4408
- package/dist/loader-helpers.esm.js.map +0 -7
- package/dist/loader.browser.js +0 -15968
- package/dist/loader.browser.js.map +0 -7
- package/dist/loader.cjs.js +0 -6667
- package/dist/loader.cjs.js.map +0 -7
- package/dist/loader.esm.js +0 -6657
- package/dist/loader.esm.js.map +0 -7
- package/dist/store-browser.browser.js +0 -1414
- package/dist/store-browser.browser.js.map +0 -7
- package/dist/store-browser.cjs.js +0 -1387
- package/dist/store-browser.cjs.js.map +0 -7
- package/dist/store-browser.esm.js +0 -1358
- package/dist/store-browser.esm.js.map +0 -7
- package/dist/store-fs.browser.js +0 -16142
- package/dist/store-fs.browser.js.map +0 -7
- package/dist/store-fs.cjs.js +0 -1171
- package/dist/store-fs.cjs.js.map +0 -7
- package/dist/store-fs.esm.js +0 -1143
- package/dist/store-fs.esm.js.map +0 -7
- package/dist/store.browser.js +0 -1113
- package/dist/store.browser.js.map +0 -7
- package/dist/store.cjs.js +0 -1126
- package/dist/store.cjs.js.map +0 -7
- package/dist/store.esm.js +0 -1097
- package/dist/store.esm.js.map +0 -7
- package/dist/transaction.browser.js +0 -17241
- package/dist/transaction.browser.js.map +0 -7
- package/dist/transaction.cjs.js +0 -7842
- package/dist/transaction.cjs.js.map +0 -7
- package/dist/transaction.esm.js +0 -7831
- package/dist/transaction.esm.js.map +0 -7
- package/dist/types.d.browser.js +0 -4
- package/dist/types.d.browser.js.map +0 -7
- package/dist/types.d.cjs.js +0 -19
- package/dist/types.d.cjs.js.map +0 -7
- package/dist/types.d.esm.js +0 -1
- package/dist/types.d.esm.js.map +0 -7
- package/scripts/analyze.js +0 -31
- package/scripts/build.js +0 -20
- package/scripts/serve.js +0 -20
- package/scripts/settings.js +0 -65
- package/scripts/test.js +0 -14
- package/src/crdt-helpers.ts +0 -89
- package/src/crdt.ts +0 -45
- package/src/database.ts +0 -61
- package/src/fireproof.ts +0 -6
- package/src/loader-helpers.ts +0 -53
- package/src/loader.ts +0 -66
- package/src/store-browser.ts +0 -76
- package/src/store-fs.ts +0 -51
- package/src/store.ts +0 -32
- package/src/transaction.ts +0 -68
- package/src/types.d.ts +0 -38
- package/test/crdt.test.js +0 -142
- package/test/database.test.js +0 -144
- package/test/fireproof.test.js +0 -50
- package/test/globals.d.ts +0 -4
- package/test/hello.test.js +0 -9
- package/test/helpers.js +0 -34
- package/test/loader.test.js +0 -112
- package/test/store-fs.test.js +0 -105
- package/test/transaction.test.js +0 -90
- package/tsconfig.json +0 -18
- package/webpack.config.cjs +0 -17
package/dist/types.d.browser.js
DELETED
package/dist/types.d.cjs.js
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
var __defProp = Object.defineProperty;
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
6
|
-
var __copyProps = (to, from, except, desc) => {
|
7
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
8
|
-
for (let key of __getOwnPropNames(from))
|
9
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
10
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
11
|
-
}
|
12
|
-
return to;
|
13
|
-
};
|
14
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
15
|
-
|
16
|
-
// src/types.d.ts
|
17
|
-
var types_d_exports = {};
|
18
|
-
module.exports = __toCommonJS(types_d_exports);
|
19
|
-
//# sourceMappingURL=types.d.cjs.js.map
|
package/dist/types.d.cjs.js.map
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
{
|
2
|
-
"version": 3,
|
3
|
-
"sources": ["../src/types.d.ts"],
|
4
|
-
"sourcesContent": ["import { Link } from 'multiformats'\nimport { EventLink } from '@alanshaw/pail/clock'\nimport { EventData } from '@alanshaw/pail/crdt'\n\nexport type ClockHead = EventLink<EventData>[]\n\nexport type BulkResult = {\n head: ClockHead\n car?: AnyLink\n}\n\ntype DocBody = {\n [key: string]: any\n}\n\nexport type Doc = DocBody & {\n _id: string\n}\n\nexport type DocUpdate = {\n key: string\n value?: DocBody\n del?: boolean\n}\n\nexport type DocValue = {\n doc?: DocBody\n del?: boolean\n}\n\nexport type AnyLink = Link<unknown, number, number, 1 | 0>\nexport type AnyBlock = { cid: AnyLink; bytes: Uint8Array }\nexport type BlockFetcher = { get: (link: AnyLink) => Promise<AnyBlock | undefined> }\n\nexport type DbResponse = {\n id: string\n clock: ClockHead\n}\n"],
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
|
6
|
-
"names": []
|
7
|
-
}
|
package/dist/types.d.esm.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
//# sourceMappingURL=types.d.esm.js.map
|
package/dist/types.d.esm.js.map
DELETED
package/scripts/analyze.js
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
import * as esbuild from 'esbuild'
|
2
|
-
import fs from 'node:fs'
|
3
|
-
import { createBuildSettings } from './settings.js'
|
4
|
-
|
5
|
-
const mode = process.env.npm_config_mode
|
6
|
-
|
7
|
-
async function analyzeProject() {
|
8
|
-
const buildConfigs = createBuildSettings({ minify: true, metafile: true })
|
9
|
-
|
10
|
-
for (const config of buildConfigs) {
|
11
|
-
if (!/fireproof/.test(config.outfile)) continue
|
12
|
-
try {
|
13
|
-
const result = await esbuild.build(config)
|
14
|
-
|
15
|
-
if (mode === 'write') {
|
16
|
-
fs.writeFileSync(`build-meta-${result.format}.json`, JSON.stringify(result.metafile))
|
17
|
-
} else {
|
18
|
-
console.log(await esbuild.analyzeMetafile(result.metafile, {
|
19
|
-
verbose: false
|
20
|
-
}))
|
21
|
-
}
|
22
|
-
} catch (err) {
|
23
|
-
console.error(err)
|
24
|
-
}
|
25
|
-
}
|
26
|
-
}
|
27
|
-
|
28
|
-
analyzeProject().catch((err) => {
|
29
|
-
console.error(err)
|
30
|
-
process.exit(1)
|
31
|
-
})
|
package/scripts/build.js
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
/* eslint-disable @typescript-eslint/require-await */
|
2
|
-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
3
|
-
import { build } from 'esbuild'
|
4
|
-
import { createBuildSettings } from './settings.js'
|
5
|
-
|
6
|
-
async function buildProject() {
|
7
|
-
const buildConfigs = createBuildSettings()
|
8
|
-
|
9
|
-
for (const config of buildConfigs) {
|
10
|
-
console.log('Building', config.outfile)
|
11
|
-
build(config).catch(() => {
|
12
|
-
console.log('Error', config.outfile)
|
13
|
-
})
|
14
|
-
}
|
15
|
-
}
|
16
|
-
|
17
|
-
buildProject().catch((err) => {
|
18
|
-
console.error(err)
|
19
|
-
process.exit(1)
|
20
|
-
})
|
package/scripts/serve.js
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
import esbuild from 'esbuild'
|
2
|
-
import { createBuildSettings } from './settings.js'
|
3
|
-
|
4
|
-
const settings = createBuildSettings({
|
5
|
-
sourcemap: true,
|
6
|
-
banner: {
|
7
|
-
js: 'new EventSource(\'/esbuild\').addEventListener(\'change\', () => location.reload())'
|
8
|
-
}
|
9
|
-
})
|
10
|
-
|
11
|
-
const ctx = await esbuild.context(settings)
|
12
|
-
|
13
|
-
await ctx.watch()
|
14
|
-
|
15
|
-
const { host, port } = await ctx.serve({
|
16
|
-
port: 5505,
|
17
|
-
servedir: 'www'
|
18
|
-
})
|
19
|
-
|
20
|
-
console.log(`Serving app at ${host}:${port}.`)
|
package/scripts/settings.js
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
2
|
-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
3
|
-
import esbuildPluginTsc from 'esbuild-plugin-tsc'
|
4
|
-
import fs from 'fs'
|
5
|
-
import path from 'path'
|
6
|
-
import { polyfillNode } from 'esbuild-plugin-polyfill-node'
|
7
|
-
|
8
|
-
// Obtain all .ts files in the src directory
|
9
|
-
const entryPoints = fs
|
10
|
-
.readdirSync('src')
|
11
|
-
.filter(file => path.extname(file) === '.ts')
|
12
|
-
.map(file => path.join('src', file))
|
13
|
-
|
14
|
-
export function createBuildSettings(options) {
|
15
|
-
const commonSettings = {
|
16
|
-
entryPoints,
|
17
|
-
bundle: true,
|
18
|
-
sourcemap: true,
|
19
|
-
plugins: [
|
20
|
-
esbuildPluginTsc({
|
21
|
-
force: true
|
22
|
-
})
|
23
|
-
],
|
24
|
-
...options
|
25
|
-
}
|
26
|
-
|
27
|
-
// Generate build configs for each entry point
|
28
|
-
const configs = entryPoints.map(entryPoint => {
|
29
|
-
const filename = path.basename(entryPoint, '.ts')
|
30
|
-
|
31
|
-
const cjsConfig = {
|
32
|
-
...commonSettings,
|
33
|
-
outfile: `dist/${filename}.cjs.js`,
|
34
|
-
format: 'cjs',
|
35
|
-
platform: 'node',
|
36
|
-
entryPoints: [entryPoint]
|
37
|
-
}
|
38
|
-
|
39
|
-
const esmConfig = {
|
40
|
-
...commonSettings,
|
41
|
-
outfile: `dist/${filename}.esm.js`,
|
42
|
-
format: 'esm',
|
43
|
-
platform: 'node',
|
44
|
-
entryPoints: [entryPoint]
|
45
|
-
}
|
46
|
-
|
47
|
-
const browserConfig = {
|
48
|
-
...commonSettings,
|
49
|
-
outfile: `dist/${filename}.browser.js`,
|
50
|
-
format: 'iife',
|
51
|
-
platform: 'browser',
|
52
|
-
target: 'es2015',
|
53
|
-
entryPoints: [entryPoint],
|
54
|
-
plugins: [
|
55
|
-
polyfillNode({}),
|
56
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
57
|
-
...commonSettings.plugins
|
58
|
-
]
|
59
|
-
}
|
60
|
-
|
61
|
-
return [cjsConfig, esmConfig, browserConfig]
|
62
|
-
})
|
63
|
-
|
64
|
-
return configs.flat()
|
65
|
-
}
|
package/scripts/test.js
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
import { spawn } from 'child_process'
|
2
|
-
const args = process.argv.slice(2)
|
3
|
-
|
4
|
-
let command = 'mocha test/*.js'
|
5
|
-
|
6
|
-
if (args.length > 0) {
|
7
|
-
command += ` --grep '${args.join(' ')}'`
|
8
|
-
}
|
9
|
-
|
10
|
-
const mocha = spawn(command, { stdio: 'inherit', shell: true })
|
11
|
-
|
12
|
-
mocha.on('close', (code) => {
|
13
|
-
process.exit(code)
|
14
|
-
})
|
package/src/crdt-helpers.ts
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
import { Link } from 'multiformats'
|
2
|
-
import { create, encode, decode } from 'multiformats/block'
|
3
|
-
import { sha256 as hasher } from 'multiformats/hashes/sha2'
|
4
|
-
import * as codec from '@ipld/dag-cbor'
|
5
|
-
import { put, get, EventData } from '@alanshaw/pail/crdt'
|
6
|
-
import { EventFetcher } from '@alanshaw/pail/clock'
|
7
|
-
|
8
|
-
import { TransactionBlockstore as Blockstore, Transaction } from './transaction'
|
9
|
-
import { DocUpdate, ClockHead, BlockFetcher, AnyLink, DocValue, BulkResult } from './types'
|
10
|
-
|
11
|
-
export function makeGetBlock(blocks: BlockFetcher) {
|
12
|
-
return async (address: Link) => {
|
13
|
-
const block = await blocks.get(address)
|
14
|
-
if (!block) throw new Error(`Missing block ${address.toString()}`)
|
15
|
-
const { cid, bytes } = block
|
16
|
-
return create({ cid, bytes, hasher, codec })
|
17
|
-
}
|
18
|
-
}
|
19
|
-
|
20
|
-
export async function applyBulkUpdateToCrdt(
|
21
|
-
tblocks: Transaction,
|
22
|
-
head: ClockHead,
|
23
|
-
updates: DocUpdate[],
|
24
|
-
options?: object
|
25
|
-
): Promise<BulkResult> {
|
26
|
-
for (const update of updates) {
|
27
|
-
const link = await makeLinkForDoc(tblocks, update)
|
28
|
-
const result = await put(tblocks, head, update.key, link, options)
|
29
|
-
for (const { cid, bytes } of [...result.additions, ...result.removals, result.event]) {
|
30
|
-
tblocks.putSync(cid, bytes)
|
31
|
-
}
|
32
|
-
head = result.head
|
33
|
-
}
|
34
|
-
return { head }
|
35
|
-
}
|
36
|
-
|
37
|
-
async function makeLinkForDoc(blocks: Transaction, update: DocUpdate): Promise<AnyLink> {
|
38
|
-
let value: DocValue
|
39
|
-
if (update.del) {
|
40
|
-
value = { del: true }
|
41
|
-
} else {
|
42
|
-
value = { doc: update.value }
|
43
|
-
}
|
44
|
-
const block = await encode({ value, hasher, codec })
|
45
|
-
blocks.putSync(block.cid, block.bytes)
|
46
|
-
return block.cid
|
47
|
-
}
|
48
|
-
|
49
|
-
export async function getValueFromCrdt(blocks: Blockstore, head: ClockHead, key: string): Promise<DocValue> {
|
50
|
-
const link = await get(blocks, head, key)
|
51
|
-
if (!link) throw new Error(`Missing key ${key}`)
|
52
|
-
return await getValueFromLink(blocks, link)
|
53
|
-
}
|
54
|
-
|
55
|
-
export async function getValueFromLink(blocks: Blockstore, link: AnyLink): Promise<DocValue> {
|
56
|
-
const block = await blocks.get(link)
|
57
|
-
if (!block) throw new Error(`Missing block ${link.toString()}`)
|
58
|
-
const { value } = (await decode({ bytes: block.bytes, hasher, codec })) as { value: DocValue }
|
59
|
-
return value
|
60
|
-
}
|
61
|
-
|
62
|
-
export async function clockChangesSince(
|
63
|
-
blocks: Blockstore,
|
64
|
-
_head: ClockHead,
|
65
|
-
_since: ClockHead
|
66
|
-
): Promise<{ result: DocUpdate[] }> {
|
67
|
-
const eventsFetcher = new EventFetcher<EventData>(blocks)
|
68
|
-
const updates = await gatherUpdates(blocks, eventsFetcher, _head, _since)
|
69
|
-
return { result: updates.reverse() }
|
70
|
-
}
|
71
|
-
|
72
|
-
async function gatherUpdates(blocks: Blockstore, eventsFetcher: EventFetcher<EventData>, head: ClockHead, since: ClockHead, updates: DocUpdate[] = []): Promise<DocUpdate[]> {
|
73
|
-
for (const link of since) {
|
74
|
-
if (head.includes(link)) {
|
75
|
-
throw new Error('found since in head, this is good, remove this error ' + updates.length)
|
76
|
-
return updates
|
77
|
-
}
|
78
|
-
}
|
79
|
-
for (const link of head) {
|
80
|
-
const { value: event } = await eventsFetcher.get(link)
|
81
|
-
const { key, value } = event.data
|
82
|
-
const docValue = await getValueFromLink(blocks, value)
|
83
|
-
updates.push({ key, value: docValue.doc, del: docValue.del })
|
84
|
-
if (event.parents) {
|
85
|
-
updates = await gatherUpdates(blocks, eventsFetcher, event.parents, since, updates)
|
86
|
-
}
|
87
|
-
}
|
88
|
-
return updates
|
89
|
-
}
|
package/src/crdt.ts
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
import { TransactionBlockstore as Blockstore } from './transaction'
|
2
|
-
import { DocUpdate, BulkResult, ClockHead } from './types'
|
3
|
-
import { clockChangesSince, applyBulkUpdateToCrdt, getValueFromCrdt } from './crdt-helpers'
|
4
|
-
|
5
|
-
export class CRDT {
|
6
|
-
name: string | null
|
7
|
-
ready: Promise<void>
|
8
|
-
|
9
|
-
private _blocks: Blockstore
|
10
|
-
private _head: ClockHead
|
11
|
-
|
12
|
-
constructor(name?: string, blocks?: Blockstore) {
|
13
|
-
this.name = name || null
|
14
|
-
this._blocks = blocks || new Blockstore(name)
|
15
|
-
this._head = []
|
16
|
-
this.ready = this._blocks.ready.then(({ head }: { head: ClockHead }) => {
|
17
|
-
this._head = head // todo multi head support here
|
18
|
-
})
|
19
|
-
}
|
20
|
-
|
21
|
-
async bulk(updates: DocUpdate[], options?: object): Promise<BulkResult> {
|
22
|
-
await this.ready
|
23
|
-
const tResult: BulkResult = await this._blocks.transaction(async tblocks => {
|
24
|
-
const { head } = await applyBulkUpdateToCrdt(tblocks, this._head, updates, options)
|
25
|
-
this._head = head // we want multi head support here if allowing calls to bulk in parallel
|
26
|
-
return { head }
|
27
|
-
})
|
28
|
-
return tResult
|
29
|
-
}
|
30
|
-
|
31
|
-
// async root(): Promise<any> {
|
32
|
-
// async eventsSince(since: EventLink<T>): Promise<{clockCIDs: CIDCounter, result: T[]}> {
|
33
|
-
// async getAll(rootCache: any = null): Promise<{root: any, cids: CIDCounter, clockCIDs: CIDCounter, result: T[]}> {
|
34
|
-
|
35
|
-
async get(key: string) {
|
36
|
-
await this.ready
|
37
|
-
const result = await getValueFromCrdt(this._blocks, this._head, key)
|
38
|
-
if (result.del) return null
|
39
|
-
return result
|
40
|
-
}
|
41
|
-
|
42
|
-
async changes(since: ClockHead) {
|
43
|
-
return await clockChangesSince(this._blocks, this._head, since)
|
44
|
-
}
|
45
|
-
}
|
package/src/database.ts
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
// @ts-ignore
|
2
|
-
import cargoQueue from 'async/cargoQueue'
|
3
|
-
import { CRDT } from './crdt'
|
4
|
-
import { Doc, BulkResult, DocUpdate, DbResponse, ClockHead } from './types'
|
5
|
-
|
6
|
-
export class Database {
|
7
|
-
name: string
|
8
|
-
config: object
|
9
|
-
_crdt: CRDT
|
10
|
-
_writeQueue: any
|
11
|
-
constructor(name: string, config = {}) {
|
12
|
-
this.name = name
|
13
|
-
this.config = config
|
14
|
-
this._crdt = new CRDT(name)
|
15
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
|
16
|
-
this._writeQueue = cargoQueue(async (updates: DocUpdate[]) => {
|
17
|
-
return await this._crdt.bulk(updates)
|
18
|
-
})
|
19
|
-
}
|
20
|
-
|
21
|
-
async put(doc: Doc): Promise<DbResponse> {
|
22
|
-
const { _id, ...value } = doc
|
23
|
-
return await new Promise<DbResponse>((resolve, reject) => {
|
24
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
25
|
-
this._writeQueue.push({ key: _id, value }, function (err: Error | null, result?: BulkResult) {
|
26
|
-
if (err) reject(err)
|
27
|
-
resolve({ id: doc._id, clock: result?.head } as DbResponse)
|
28
|
-
})
|
29
|
-
})
|
30
|
-
}
|
31
|
-
|
32
|
-
async get(id: string): Promise<Doc> {
|
33
|
-
const got = await this._crdt.get(id).catch(e => {
|
34
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
35
|
-
e.message = `Not found: ${id} - ` + e.message
|
36
|
-
throw e
|
37
|
-
})
|
38
|
-
if (!got) throw new Error(`Not found: ${id}`)
|
39
|
-
const { doc } = got
|
40
|
-
return { _id: id, ...doc }
|
41
|
-
}
|
42
|
-
|
43
|
-
async del(id: string): Promise<DbResponse> {
|
44
|
-
return await new Promise<DbResponse>((resolve, reject) => {
|
45
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
46
|
-
this._writeQueue.push({ key: id, del: true }, function (err: Error | null, result?: BulkResult) {
|
47
|
-
if (err) reject(err)
|
48
|
-
resolve({ id, clock: result?.head } as DbResponse)
|
49
|
-
})
|
50
|
-
})
|
51
|
-
}
|
52
|
-
|
53
|
-
async changes(since: ClockHead): Promise<{ rows: { key: string; value: Doc }[] }> {
|
54
|
-
const { result } = await this._crdt.changes(since)
|
55
|
-
const rows = result.map(({ key, value }) => ({
|
56
|
-
key,
|
57
|
-
value: { _id: key, ...value } as Doc
|
58
|
-
}))
|
59
|
-
return { rows }
|
60
|
-
}
|
61
|
-
}
|
package/src/fireproof.ts
DELETED
package/src/loader-helpers.ts
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
import { BlockView, CID } from 'multiformats'
|
2
|
-
import { Block, encode, decode } from 'multiformats/block'
|
3
|
-
import { sha256 as hasher } from 'multiformats/hashes/sha2'
|
4
|
-
import * as raw from 'multiformats/codecs/raw'
|
5
|
-
import * as CBW from '@ipld/car/buffer-writer'
|
6
|
-
import * as codec from '@ipld/dag-cbor'
|
7
|
-
import { CarReader } from '@ipld/car'
|
8
|
-
|
9
|
-
import { Transaction } from './transaction'
|
10
|
-
import { AnyBlock, BulkResult, ClockHead, AnyLink } from './types'
|
11
|
-
|
12
|
-
export async function makeCarFile(
|
13
|
-
t: Transaction,
|
14
|
-
{ head }: BulkResult,
|
15
|
-
cars: AnyLink[]
|
16
|
-
): Promise<BlockView<unknown, number, number, 1>> {
|
17
|
-
if (!head) throw new Error('no head')
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
|
19
|
-
const fpCarHeaderBlock = (await encode({
|
20
|
-
value: { fp: { head, cars } },
|
21
|
-
hasher,
|
22
|
-
codec
|
23
|
-
})) as AnyBlock
|
24
|
-
await t.put(fpCarHeaderBlock.cid, fpCarHeaderBlock.bytes)
|
25
|
-
|
26
|
-
let size = 0
|
27
|
-
const headerSize = CBW.headerLength({ roots: [fpCarHeaderBlock.cid as CID<unknown, number, number, 1>] })
|
28
|
-
size += headerSize
|
29
|
-
for (const { cid, bytes } of t.entries()) {
|
30
|
-
size += CBW.blockLength({ cid, bytes } as Block<unknown, number, number, 1>)
|
31
|
-
}
|
32
|
-
const buffer = new Uint8Array(size)
|
33
|
-
const writer = CBW.createWriter(buffer, { headerSize })
|
34
|
-
|
35
|
-
writer.addRoot(fpCarHeaderBlock.cid as CID<unknown, number, number, 1>)
|
36
|
-
|
37
|
-
for (const { cid, bytes } of t.entries()) {
|
38
|
-
writer.write({ cid, bytes } as Block<unknown, number, number, 1>)
|
39
|
-
}
|
40
|
-
writer.close()
|
41
|
-
return await encode({ value: writer.bytes, hasher, codec: raw })
|
42
|
-
}
|
43
|
-
|
44
|
-
export async function parseCarFile(reader: CarReader): Promise<{ head: ClockHead; cars: AnyLink[] }> {
|
45
|
-
const roots = await reader.getRoots()
|
46
|
-
const header = await reader.get(roots[0])
|
47
|
-
if (!header) throw new Error('missing header block')
|
48
|
-
const got = await decode({ bytes: header.bytes, hasher, codec })
|
49
|
-
const {
|
50
|
-
fp: { head, cars }
|
51
|
-
} = got.value as { fp: { head: ClockHead; cars: AnyLink[] } }
|
52
|
-
return { head, cars }
|
53
|
-
}
|
package/src/loader.ts
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
import { CarReader } from '@ipld/car'
|
2
|
-
|
3
|
-
// import { CarStoreFS, HeaderStoreFS } from './store-fs'
|
4
|
-
import { CarStoreIDB as CarStore, HeaderStoreLS as HeaderStore } from './store-browser'
|
5
|
-
import { makeCarFile, parseCarFile } from './loader-helpers'
|
6
|
-
import { Transaction } from './transaction'
|
7
|
-
import { AnyBlock, AnyLink, BulkResult, ClockHead } from './types'
|
8
|
-
import { CID } from 'multiformats'
|
9
|
-
|
10
|
-
export class Loader {
|
11
|
-
name: string
|
12
|
-
headerStore: HeaderStore
|
13
|
-
carStore: CarStore
|
14
|
-
carLog: AnyLink[] = []
|
15
|
-
carsReaders: Map<string, CarReader> = new Map()
|
16
|
-
ready: Promise<{ head: ClockHead}> // todo this will be a map of headers by branch name
|
17
|
-
constructor(name: string) {
|
18
|
-
this.name = name
|
19
|
-
this.headerStore = new HeaderStore(name)
|
20
|
-
this.carStore = new CarStore(name)
|
21
|
-
// todo config with multiple branches
|
22
|
-
this.ready = this.headerStore.load('main').then(async header => {
|
23
|
-
if (!header) return { head: [] }
|
24
|
-
const car = await this.carStore.load(header.car)
|
25
|
-
return await this.ingestCarHead(header.car, car)
|
26
|
-
})
|
27
|
-
}
|
28
|
-
|
29
|
-
async commit(t: Transaction, done: BulkResult): Promise<AnyLink> {
|
30
|
-
const car = await makeCarFile(t, done, this.carLog)
|
31
|
-
await this.carStore.save(car)
|
32
|
-
this.carLog.push(car.cid)
|
33
|
-
await this.headerStore.save(car.cid)
|
34
|
-
return car.cid
|
35
|
-
}
|
36
|
-
|
37
|
-
async loadCar(cid: AnyLink): Promise<CarReader> {
|
38
|
-
if (this.carsReaders.has(cid.toString())) return this.carsReaders.get(cid.toString()) as CarReader
|
39
|
-
const car = await this.carStore.load(cid)
|
40
|
-
if (!car) throw new Error(`missing car file ${cid.toString()}`)
|
41
|
-
const reader = await CarReader.fromBytes(car.bytes)
|
42
|
-
this.carsReaders.set(cid.toString(), reader)
|
43
|
-
return reader
|
44
|
-
}
|
45
|
-
|
46
|
-
async ingestCarHead(cid: AnyLink, car: AnyBlock): Promise<{ head: ClockHead, cars: AnyLink[]}> {
|
47
|
-
const reader = await CarReader.fromBytes(car.bytes)
|
48
|
-
this.carsReaders.set(cid.toString(), reader)
|
49
|
-
const { head, cars } = await parseCarFile(reader)
|
50
|
-
await this.getMoreReaders(cars)
|
51
|
-
return { head, cars }
|
52
|
-
}
|
53
|
-
|
54
|
-
async getMoreReaders(cids: AnyLink[]) {
|
55
|
-
for (const cid of cids) {
|
56
|
-
await this.loadCar(cid)
|
57
|
-
}
|
58
|
-
}
|
59
|
-
|
60
|
-
async getBlock(cid: CID): Promise<AnyBlock | undefined> {
|
61
|
-
for (const [, reader] of [...this.carsReaders].reverse()) { // reverse is faster
|
62
|
-
const block = await reader.get(cid)
|
63
|
-
if (block) return block
|
64
|
-
}
|
65
|
-
}
|
66
|
-
}
|
package/src/store-browser.ts
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
import { openDB, IDBPDatabase } from 'idb'
|
2
|
-
|
3
|
-
import { AnyBlock, AnyLink } from './types'
|
4
|
-
import { CarStore, HeaderStore, StoredHeader } from './store'
|
5
|
-
|
6
|
-
export const FORMAT = '0.9'
|
7
|
-
|
8
|
-
export class CarStoreIDB extends CarStore {
|
9
|
-
keyId: string = 'public'
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
|
11
|
-
idb: IDBPDatabase<unknown> | null = null
|
12
|
-
name: string = 'default'
|
13
|
-
async withDB(dbWorkFun: (arg0: any) => any) {
|
14
|
-
if (!this.idb) {
|
15
|
-
const dbName = `fp.${FORMAT}.${this.keyId}.${this.name}.valet`
|
16
|
-
const options = {
|
17
|
-
upgrade(db: IDBDatabase) {
|
18
|
-
db.createObjectStore('cars')
|
19
|
-
}
|
20
|
-
}
|
21
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
|
22
|
-
this.idb = await openDB(dbName, 0, options)
|
23
|
-
}
|
24
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
25
|
-
return await dbWorkFun(this.idb)
|
26
|
-
}
|
27
|
-
|
28
|
-
async load(cid: AnyLink): Promise<AnyBlock> {
|
29
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
30
|
-
return await this.withDB(async (db: IDBPDatabase<unknown>) => {
|
31
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
32
|
-
const tx = db.transaction(['cars'], 'readonly')
|
33
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
34
|
-
const bytes = (await tx.objectStore('cars').get(cid.toString())) as Uint8Array
|
35
|
-
if (!bytes) throw new Error(`missing block ${cid.toString()}`)
|
36
|
-
return { cid, bytes }
|
37
|
-
})
|
38
|
-
}
|
39
|
-
|
40
|
-
async save(car: AnyBlock): Promise<void> {
|
41
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
42
|
-
return await this.withDB(async (db: IDBPDatabase<unknown>) => {
|
43
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
44
|
-
const tx = db.transaction(['cars'], 'readwrite')
|
45
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
46
|
-
await tx.objectStore('cars').put(car.bytes, car.cid.toString())
|
47
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access
|
48
|
-
return await tx.done
|
49
|
-
})
|
50
|
-
}
|
51
|
-
}
|
52
|
-
|
53
|
-
export class HeaderStoreLS extends HeaderStore {
|
54
|
-
keyId: string = 'public'
|
55
|
-
name: string = 'default'
|
56
|
-
|
57
|
-
headerKey(branch: string) {
|
58
|
-
return `fp.${FORMAT}.${this.keyId}.${this.name}.${branch}`
|
59
|
-
}
|
60
|
-
|
61
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
62
|
-
async load(branch: string = 'main'): Promise<StoredHeader | null> {
|
63
|
-
// try {
|
64
|
-
const bytes = localStorage.getItem(this.headerKey(branch))
|
65
|
-
return bytes ? this.parseHeader(bytes.toString()) : null
|
66
|
-
// } catch (e) {}
|
67
|
-
}
|
68
|
-
|
69
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
70
|
-
async save(carCid: AnyLink, branch: string = 'main') {
|
71
|
-
// try {
|
72
|
-
const headerKey = this.headerKey(branch)
|
73
|
-
return localStorage.setItem(headerKey, this.makeHeader(carCid))
|
74
|
-
// } catch (e) {}
|
75
|
-
}
|
76
|
-
}
|
package/src/store-fs.ts
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
import { join, dirname } from 'node:path'
|
2
|
-
import { homedir } from 'node:os'
|
3
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
4
|
-
|
5
|
-
import { AnyBlock, AnyLink } from './types'
|
6
|
-
import { HeaderStore, CarStore, StoredHeader } from './store'
|
7
|
-
|
8
|
-
export const FORMAT = '0.9'
|
9
|
-
|
10
|
-
const encoder = new TextEncoder()
|
11
|
-
|
12
|
-
export const defaultConfig = {
|
13
|
-
dataDir: join(homedir(), '.fireproof', 'v' + FORMAT)
|
14
|
-
}
|
15
|
-
|
16
|
-
export class HeaderStoreFS extends HeaderStore {
|
17
|
-
async load(branch?: string): Promise<StoredHeader|null> {
|
18
|
-
branch = branch || 'main'
|
19
|
-
const filepath = join(defaultConfig.dataDir, this.name, branch + '.json')
|
20
|
-
const bytes = await readFile(filepath).catch((e: Error & { code: string}) => {
|
21
|
-
if (e.code === 'ENOENT') return null
|
22
|
-
throw e
|
23
|
-
})
|
24
|
-
return bytes ? this.parseHeader(bytes.toString()) : null
|
25
|
-
}
|
26
|
-
|
27
|
-
async save(carCid: AnyLink, branch?: string) {
|
28
|
-
branch = branch || 'main'
|
29
|
-
const filepath = join(defaultConfig.dataDir, this.name, branch + '.json')
|
30
|
-
const bytes = this.makeHeader(carCid)
|
31
|
-
await writePathFile(filepath, encoder.encode(bytes))
|
32
|
-
}
|
33
|
-
}
|
34
|
-
|
35
|
-
export class CarStoreFS extends CarStore {
|
36
|
-
async save(car: AnyBlock): Promise<void> {
|
37
|
-
const filepath = join(defaultConfig.dataDir, this.name, car.cid.toString() + '.car')
|
38
|
-
await writePathFile(filepath, car.bytes)
|
39
|
-
}
|
40
|
-
|
41
|
-
async load(cid: AnyLink): Promise<AnyBlock> {
|
42
|
-
const filepath = join(defaultConfig.dataDir, this.name, cid.toString() + '.car')
|
43
|
-
const bytes = await readFile(filepath)
|
44
|
-
return { cid, bytes: new Uint8Array(bytes) }
|
45
|
-
}
|
46
|
-
}
|
47
|
-
|
48
|
-
async function writePathFile(path: string, data: Uint8Array) {
|
49
|
-
await mkdir(dirname(path), { recursive: true })
|
50
|
-
return await writeFile(path, data)
|
51
|
-
}
|