@fireproof/core 0.10.0-dev → 0.10.2-dev

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. package/dist/fireproof.browser.js +2 -3
  2. package/dist/fireproof.browser.js.map +2 -2
  3. package/dist/fireproof.cjs.js +2 -3
  4. package/dist/fireproof.cjs.js.map +2 -2
  5. package/dist/fireproof.esm.js +2 -3
  6. package/dist/fireproof.esm.js.map +2 -2
  7. package/package.json +5 -1
  8. package/.eslintrc.cjs +0 -37
  9. package/.vscode/launch.json +0 -12
  10. package/dist/crdt-helpers.browser.js +0 -4961
  11. package/dist/crdt-helpers.browser.js.map +0 -7
  12. package/dist/crdt-helpers.cjs.js +0 -4823
  13. package/dist/crdt-helpers.cjs.js.map +0 -7
  14. package/dist/crdt-helpers.esm.js +0 -4788
  15. package/dist/crdt-helpers.esm.js.map +0 -7
  16. package/dist/crdt.browser.js +0 -18214
  17. package/dist/crdt.browser.js.map +0 -7
  18. package/dist/crdt.cjs.js +0 -8692
  19. package/dist/crdt.cjs.js.map +0 -7
  20. package/dist/crdt.esm.js +0 -8682
  21. package/dist/crdt.esm.js.map +0 -7
  22. package/dist/database.browser.js +0 -18867
  23. package/dist/database.browser.js.map +0 -7
  24. package/dist/database.cjs.js +0 -9296
  25. package/dist/database.cjs.js.map +0 -7
  26. package/dist/database.esm.js +0 -9288
  27. package/dist/database.esm.js.map +0 -7
  28. package/dist/loader-helpers.browser.js +0 -6943
  29. package/dist/loader-helpers.browser.js.map +0 -7
  30. package/dist/loader-helpers.cjs.js +0 -4419
  31. package/dist/loader-helpers.cjs.js.map +0 -7
  32. package/dist/loader-helpers.esm.js +0 -4408
  33. package/dist/loader-helpers.esm.js.map +0 -7
  34. package/dist/loader.browser.js +0 -15968
  35. package/dist/loader.browser.js.map +0 -7
  36. package/dist/loader.cjs.js +0 -6667
  37. package/dist/loader.cjs.js.map +0 -7
  38. package/dist/loader.esm.js +0 -6657
  39. package/dist/loader.esm.js.map +0 -7
  40. package/dist/store-browser.browser.js +0 -1414
  41. package/dist/store-browser.browser.js.map +0 -7
  42. package/dist/store-browser.cjs.js +0 -1387
  43. package/dist/store-browser.cjs.js.map +0 -7
  44. package/dist/store-browser.esm.js +0 -1358
  45. package/dist/store-browser.esm.js.map +0 -7
  46. package/dist/store-fs.browser.js +0 -16142
  47. package/dist/store-fs.browser.js.map +0 -7
  48. package/dist/store-fs.cjs.js +0 -1171
  49. package/dist/store-fs.cjs.js.map +0 -7
  50. package/dist/store-fs.esm.js +0 -1143
  51. package/dist/store-fs.esm.js.map +0 -7
  52. package/dist/store.browser.js +0 -1113
  53. package/dist/store.browser.js.map +0 -7
  54. package/dist/store.cjs.js +0 -1126
  55. package/dist/store.cjs.js.map +0 -7
  56. package/dist/store.esm.js +0 -1097
  57. package/dist/store.esm.js.map +0 -7
  58. package/dist/transaction.browser.js +0 -17241
  59. package/dist/transaction.browser.js.map +0 -7
  60. package/dist/transaction.cjs.js +0 -7842
  61. package/dist/transaction.cjs.js.map +0 -7
  62. package/dist/transaction.esm.js +0 -7831
  63. package/dist/transaction.esm.js.map +0 -7
  64. package/dist/types.d.browser.js +0 -4
  65. package/dist/types.d.browser.js.map +0 -7
  66. package/dist/types.d.cjs.js +0 -19
  67. package/dist/types.d.cjs.js.map +0 -7
  68. package/dist/types.d.esm.js +0 -1
  69. package/dist/types.d.esm.js.map +0 -7
  70. package/scripts/analyze.js +0 -31
  71. package/scripts/build.js +0 -20
  72. package/scripts/serve.js +0 -20
  73. package/scripts/settings.js +0 -65
  74. package/scripts/test.js +0 -14
  75. package/src/crdt-helpers.ts +0 -89
  76. package/src/crdt.ts +0 -45
  77. package/src/database.ts +0 -61
  78. package/src/fireproof.ts +0 -6
  79. package/src/loader-helpers.ts +0 -53
  80. package/src/loader.ts +0 -66
  81. package/src/store-browser.ts +0 -76
  82. package/src/store-fs.ts +0 -51
  83. package/src/store.ts +0 -32
  84. package/src/transaction.ts +0 -68
  85. package/src/types.d.ts +0 -38
  86. package/test/crdt.test.js +0 -142
  87. package/test/database.test.js +0 -144
  88. package/test/fireproof.test.js +0 -50
  89. package/test/globals.d.ts +0 -4
  90. package/test/hello.test.js +0 -9
  91. package/test/helpers.js +0 -34
  92. package/test/loader.test.js +0 -112
  93. package/test/store-fs.test.js +0 -105
  94. package/test/transaction.test.js +0 -90
  95. package/tsconfig.json +0 -18
  96. 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
- }