@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.
Files changed (90) hide show
  1. package/package.json +5 -1
  2. package/.eslintrc.cjs +0 -37
  3. package/.vscode/launch.json +0 -12
  4. package/dist/crdt-helpers.browser.js +0 -4961
  5. package/dist/crdt-helpers.browser.js.map +0 -7
  6. package/dist/crdt-helpers.cjs.js +0 -4823
  7. package/dist/crdt-helpers.cjs.js.map +0 -7
  8. package/dist/crdt-helpers.esm.js +0 -4788
  9. package/dist/crdt-helpers.esm.js.map +0 -7
  10. package/dist/crdt.browser.js +0 -18214
  11. package/dist/crdt.browser.js.map +0 -7
  12. package/dist/crdt.cjs.js +0 -8692
  13. package/dist/crdt.cjs.js.map +0 -7
  14. package/dist/crdt.esm.js +0 -8682
  15. package/dist/crdt.esm.js.map +0 -7
  16. package/dist/database.browser.js +0 -18867
  17. package/dist/database.browser.js.map +0 -7
  18. package/dist/database.cjs.js +0 -9296
  19. package/dist/database.cjs.js.map +0 -7
  20. package/dist/database.esm.js +0 -9288
  21. package/dist/database.esm.js.map +0 -7
  22. package/dist/loader-helpers.browser.js +0 -6943
  23. package/dist/loader-helpers.browser.js.map +0 -7
  24. package/dist/loader-helpers.cjs.js +0 -4419
  25. package/dist/loader-helpers.cjs.js.map +0 -7
  26. package/dist/loader-helpers.esm.js +0 -4408
  27. package/dist/loader-helpers.esm.js.map +0 -7
  28. package/dist/loader.browser.js +0 -15968
  29. package/dist/loader.browser.js.map +0 -7
  30. package/dist/loader.cjs.js +0 -6667
  31. package/dist/loader.cjs.js.map +0 -7
  32. package/dist/loader.esm.js +0 -6657
  33. package/dist/loader.esm.js.map +0 -7
  34. package/dist/store-browser.browser.js +0 -1414
  35. package/dist/store-browser.browser.js.map +0 -7
  36. package/dist/store-browser.cjs.js +0 -1387
  37. package/dist/store-browser.cjs.js.map +0 -7
  38. package/dist/store-browser.esm.js +0 -1358
  39. package/dist/store-browser.esm.js.map +0 -7
  40. package/dist/store-fs.browser.js +0 -16142
  41. package/dist/store-fs.browser.js.map +0 -7
  42. package/dist/store-fs.cjs.js +0 -1171
  43. package/dist/store-fs.cjs.js.map +0 -7
  44. package/dist/store-fs.esm.js +0 -1143
  45. package/dist/store-fs.esm.js.map +0 -7
  46. package/dist/store.browser.js +0 -1113
  47. package/dist/store.browser.js.map +0 -7
  48. package/dist/store.cjs.js +0 -1126
  49. package/dist/store.cjs.js.map +0 -7
  50. package/dist/store.esm.js +0 -1097
  51. package/dist/store.esm.js.map +0 -7
  52. package/dist/transaction.browser.js +0 -17241
  53. package/dist/transaction.browser.js.map +0 -7
  54. package/dist/transaction.cjs.js +0 -7842
  55. package/dist/transaction.cjs.js.map +0 -7
  56. package/dist/transaction.esm.js +0 -7831
  57. package/dist/transaction.esm.js.map +0 -7
  58. package/dist/types.d.browser.js +0 -4
  59. package/dist/types.d.browser.js.map +0 -7
  60. package/dist/types.d.cjs.js +0 -19
  61. package/dist/types.d.cjs.js.map +0 -7
  62. package/dist/types.d.esm.js +0 -1
  63. package/dist/types.d.esm.js.map +0 -7
  64. package/scripts/analyze.js +0 -31
  65. package/scripts/build.js +0 -20
  66. package/scripts/serve.js +0 -20
  67. package/scripts/settings.js +0 -65
  68. package/scripts/test.js +0 -14
  69. package/src/crdt-helpers.ts +0 -89
  70. package/src/crdt.ts +0 -45
  71. package/src/database.ts +0 -61
  72. package/src/fireproof.ts +0 -6
  73. package/src/loader-helpers.ts +0 -53
  74. package/src/loader.ts +0 -66
  75. package/src/store-browser.ts +0 -76
  76. package/src/store-fs.ts +0 -51
  77. package/src/store.ts +0 -32
  78. package/src/transaction.ts +0 -68
  79. package/src/types.d.ts +0 -38
  80. package/test/crdt.test.js +0 -142
  81. package/test/database.test.js +0 -144
  82. package/test/fireproof.test.js +0 -50
  83. package/test/globals.d.ts +0 -4
  84. package/test/hello.test.js +0 -9
  85. package/test/helpers.js +0 -34
  86. package/test/loader.test.js +0 -112
  87. package/test/store-fs.test.js +0 -105
  88. package/test/transaction.test.js +0 -90
  89. package/tsconfig.json +0 -18
  90. package/webpack.config.cjs +0 -17
@@ -1,4 +0,0 @@
1
- "use strict";
2
- (() => {
3
- })();
4
- //# sourceMappingURL=types.d.browser.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -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
@@ -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
- }
@@ -1 +0,0 @@
1
- //# sourceMappingURL=types.d.esm.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
7
- }
@@ -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}.`)
@@ -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
- })
@@ -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
@@ -1,6 +0,0 @@
1
- import { Database } from './database'
2
- export class Fireproof {
3
- static storage(name: string): Database {
4
- return new Database(name)
5
- }
6
- }
@@ -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
- }
@@ -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
- }