@fireproof/core 0.10.0-dev → 0.10.1-dev
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
}
|