@web3-storage/pail 0.6.0-alpha.4 → 0.6.2

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 (111) hide show
  1. package/dist/cli.d.ts +3 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +208 -0
  4. package/dist/scripts/randomcid.d.ts +2 -0
  5. package/dist/scripts/randomcid.d.ts.map +1 -0
  6. package/dist/scripts/randomcid.js +10 -0
  7. package/dist/scripts/words/gen.d.ts +2 -0
  8. package/dist/scripts/words/gen.d.ts.map +1 -0
  9. package/dist/scripts/words/gen.js +51 -0
  10. package/dist/src/api.d.ts +4 -2
  11. package/dist/src/api.d.ts.map +1 -1
  12. package/dist/src/api.js +1 -0
  13. package/dist/src/batch/api.d.ts +2 -4
  14. package/dist/src/batch/api.d.ts.map +1 -1
  15. package/dist/src/batch/api.js +1 -0
  16. package/dist/src/batch/index.d.ts +2 -53
  17. package/dist/src/batch/index.d.ts.map +1 -1
  18. package/dist/src/batch/index.js +241 -0
  19. package/dist/src/batch/shard.d.ts +1 -1
  20. package/dist/src/batch/shard.d.ts.map +1 -1
  21. package/dist/src/batch/shard.js +12 -0
  22. package/dist/src/block.d.ts +3 -3
  23. package/dist/src/block.d.ts.map +1 -1
  24. package/dist/src/block.js +66 -0
  25. package/dist/src/clock/api.d.ts +1 -1
  26. package/dist/src/clock/api.d.ts.map +1 -1
  27. package/dist/src/clock/api.js +1 -0
  28. package/dist/src/clock/index.d.ts +2 -2
  29. package/dist/src/clock/index.d.ts.map +1 -1
  30. package/dist/src/clock/index.js +199 -0
  31. package/dist/src/crdt/api.d.ts +2 -2
  32. package/dist/src/crdt/api.d.ts.map +1 -1
  33. package/dist/src/crdt/api.js +1 -0
  34. package/dist/src/crdt/batch/api.d.ts +1 -1
  35. package/dist/src/crdt/batch/api.d.ts.map +1 -1
  36. package/dist/src/crdt/batch/api.js +1 -0
  37. package/dist/src/crdt/batch/index.d.ts.map +1 -1
  38. package/dist/src/crdt/batch/index.js +140 -0
  39. package/dist/src/crdt/index.d.ts +2 -4
  40. package/dist/src/crdt/index.d.ts.map +1 -1
  41. package/dist/src/crdt/index.js +344 -0
  42. package/dist/src/diff.d.ts +3 -3
  43. package/dist/src/diff.d.ts.map +1 -1
  44. package/dist/src/diff.js +151 -0
  45. package/dist/src/index.d.ts +1 -1
  46. package/dist/src/index.d.ts.map +1 -1
  47. package/dist/src/index.js +356 -0
  48. package/dist/src/merge.d.ts.map +1 -1
  49. package/dist/src/merge.js +42 -0
  50. package/dist/src/shard.d.ts +4 -4
  51. package/dist/src/shard.d.ts.map +1 -1
  52. package/dist/src/shard.js +166 -0
  53. package/dist/test/batch.test.d.ts +2 -0
  54. package/dist/test/batch.test.d.ts.map +1 -0
  55. package/dist/test/batch.test.js +126 -0
  56. package/dist/test/clock.test.d.ts +2 -0
  57. package/dist/test/clock.test.d.ts.map +1 -0
  58. package/dist/test/clock.test.js +244 -0
  59. package/dist/test/crdt.test.d.ts +2 -0
  60. package/dist/test/crdt.test.d.ts.map +1 -0
  61. package/dist/test/crdt.test.js +271 -0
  62. package/dist/test/del.test.d.ts +2 -0
  63. package/dist/test/del.test.d.ts.map +1 -0
  64. package/dist/test/del.test.js +21 -0
  65. package/dist/test/diff.test.d.ts +2 -0
  66. package/dist/test/diff.test.d.ts.map +1 -0
  67. package/dist/test/diff.test.js +38 -0
  68. package/dist/test/entries.test.d.ts +2 -0
  69. package/dist/test/entries.test.d.ts.map +1 -0
  70. package/dist/test/entries.test.js +210 -0
  71. package/dist/test/get.test.d.ts +2 -0
  72. package/dist/test/get.test.d.ts.map +1 -0
  73. package/dist/test/get.test.js +26 -0
  74. package/dist/test/helpers.d.ts +35 -0
  75. package/dist/test/helpers.d.ts.map +1 -0
  76. package/dist/test/helpers.js +168 -0
  77. package/dist/test/put.test.d.ts +2 -0
  78. package/dist/test/put.test.d.ts.map +1 -0
  79. package/dist/test/put.test.js +165 -0
  80. package/dist/tsconfig.tsbuildinfo +1 -1
  81. package/dist/vitest.config.d.ts +3 -0
  82. package/dist/vitest.config.d.ts.map +1 -0
  83. package/dist/vitest.config.js +13 -0
  84. package/package.json +47 -92
  85. package/scripts/propernames/gen.sh +3 -0
  86. package/cli.js +0 -260
  87. package/dist/src/batch.d.ts +0 -62
  88. package/dist/src/batch.d.ts.map +0 -1
  89. package/dist/src/crdt/batch.d.ts +0 -3
  90. package/dist/src/crdt/batch.d.ts.map +0 -1
  91. package/src/api.js +0 -1
  92. package/src/api.ts +0 -90
  93. package/src/batch/api.js +0 -1
  94. package/src/batch/api.ts +0 -59
  95. package/src/batch/index.js +0 -248
  96. package/src/batch/index2.js +0 -0
  97. package/src/batch/shard.js +0 -13
  98. package/src/block.js +0 -75
  99. package/src/clock/api.js +0 -1
  100. package/src/clock/api.ts +0 -12
  101. package/src/clock/index.js +0 -182
  102. package/src/crdt/api.js +0 -1
  103. package/src/crdt/api.ts +0 -33
  104. package/src/crdt/batch/api.js +0 -1
  105. package/src/crdt/batch/api.ts +0 -30
  106. package/src/crdt/batch/index.js +0 -156
  107. package/src/crdt/index.js +0 -355
  108. package/src/diff.js +0 -151
  109. package/src/index.js +0 -406
  110. package/src/merge.js +0 -43
  111. package/src/shard.js +0 -180
package/src/batch/api.ts DELETED
@@ -1,59 +0,0 @@
1
- import {
2
- UnknownLink,
3
- ShardLink,
4
- ShardDiff,
5
- ShardEntry,
6
- ShardEntryValueValue,
7
- ShardEntryLinkValue,
8
- ShardEntryLinkAndValueValue,
9
- ShardConfig,
10
- ShardOptions,
11
- ShardBlockView,
12
- BlockFetcher
13
- } from '../api.js'
14
-
15
- export {
16
- UnknownLink,
17
- ShardLink,
18
- ShardDiff,
19
- ShardEntry,
20
- ShardEntryValueValue,
21
- ShardEntryLinkValue,
22
- ShardEntryLinkAndValueValue,
23
- ShardConfig,
24
- ShardOptions,
25
- ShardBlockView,
26
- BlockFetcher
27
- }
28
-
29
- export interface BatcherShard extends ShardConfig {
30
- base?: ShardBlockView
31
- entries: BatcherShardEntry[]
32
- }
33
-
34
- export interface BatcherShardInit extends ShardOptions {
35
- base?: ShardBlockView
36
- entries?: BatcherShardEntry[]
37
- }
38
-
39
- export type BatcherShardEntry = [
40
- key: string,
41
- value: ShardEntryValueValue | ShardEntryLinkValue | ShardEntryLinkAndValueValue | ShardEntryShardValue | ShardEntryShardAndValueValue
42
- ]
43
-
44
- export type ShardEntryShardValue = [BatcherShard]
45
-
46
- export type ShardEntryShardAndValueValue = [BatcherShard, UnknownLink]
47
-
48
- export interface Batcher {
49
- /**
50
- * Put a value (a CID) for the given key. If the key exists it's value is
51
- * overwritten.
52
- */
53
- put (key: string, value: UnknownLink): Promise<void>
54
- /**
55
- * Encode all altered shards in the batch and return the new root CID and
56
- * difference blocks.
57
- */
58
- commit (): Promise<{ root: ShardLink } & ShardDiff>
59
- }
@@ -1,248 +0,0 @@
1
- // eslint-disable-next-line no-unused-vars
2
- import * as API from './api.js'
3
- import { ShardFetcher } from '../shard.js'
4
- import * as Shard from '../shard.js'
5
- import * as BatcherShard from './shard.js'
6
-
7
- /** @implements {API.Batcher} */
8
- class Batcher {
9
- #committed = false
10
-
11
- /**
12
- * @param {object} init
13
- * @param {API.BlockFetcher} init.blocks Block storage.
14
- * @param {API.BatcherShardEntry[]} init.entries The entries in this shard.
15
- * @param {string} init.prefix Key prefix.
16
- * @param {number} init.version Shard compatibility version.
17
- * @param {string} init.keyChars Characters allowed in keys, referring to a known character set.
18
- * @param {number} init.maxKeySize Max key size in bytes.
19
- * @param {API.ShardBlockView} init.base Original shard this batcher is based on.
20
- */
21
- constructor ({ blocks, entries, prefix, version, keyChars, maxKeySize, base }) {
22
- this.blocks = blocks
23
- this.prefix = prefix
24
- this.entries = [...entries]
25
- this.base = base
26
- this.version = version
27
- this.keyChars = keyChars
28
- this.maxKeySize = maxKeySize
29
- }
30
-
31
- /**
32
- * @param {string} key The key of the value to put.
33
- * @param {API.UnknownLink} value The value to put.
34
- * @returns {Promise<void>}
35
- */
36
- async put (key, value) {
37
- if (this.#committed) throw new BatchCommittedError()
38
- return put(this.blocks, this, key, value)
39
- }
40
-
41
- async commit () {
42
- if (this.#committed) throw new BatchCommittedError()
43
- this.#committed = true
44
- return commit(this)
45
- }
46
-
47
- /**
48
- * @param {object} init
49
- * @param {API.BlockFetcher} init.blocks Block storage.
50
- * @param {API.ShardLink} init.link CID of the shard block.
51
- */
52
- static async create ({ blocks, link }) {
53
- const shards = new ShardFetcher(blocks)
54
- const base = await shards.get(link)
55
- return new Batcher({ blocks, base, ...base.value })
56
- }
57
- }
58
-
59
- /**
60
- * @param {API.BlockFetcher} blocks
61
- * @param {API.BatcherShard} shard
62
- * @param {string} key The key of the value to put.
63
- * @param {API.UnknownLink} value The value to put.
64
- * @returns {Promise<void>}
65
- */
66
- export const put = async (blocks, shard, key, value) => {
67
- const shards = new ShardFetcher(blocks)
68
- const dest = await traverse(shards, key, shard)
69
- if (dest.shard !== shard) {
70
- shard = dest.shard
71
- key = dest.key
72
- }
73
-
74
- /** @type {API.BatcherShardEntry} */
75
- let entry = [key, value]
76
- /** @type {API.BatcherShard|undefined} */
77
- let batcher
78
-
79
- // if the key in this shard is longer than allowed, then we need to make some
80
- // intermediate shards.
81
- if (key.length > shard.maxKeyLength) {
82
- const pfxskeys = Array.from(Array(Math.ceil(key.length / shard.maxKeyLength)), (_, i) => {
83
- const start = i * shard.maxKeyLength
84
- return {
85
- prefix: shard.prefix + key.slice(0, start),
86
- key: key.slice(start, start + shard.maxKeyLength)
87
- }
88
- })
89
-
90
- entry = [pfxskeys[pfxskeys.length - 1].key, value]
91
- batcher = BatcherShard.create({
92
- entries: [entry],
93
- prefix: pfxskeys[pfxskeys.length - 1].prefix,
94
- ...Shard.configure(shard)
95
- })
96
-
97
- for (let i = pfxskeys.length - 2; i > 0; i--) {
98
- entry = [pfxskeys[i].key, [batcher]]
99
- batcher = BatcherShard.create({
100
- entries: [entry],
101
- prefix: pfxskeys[i].prefix,
102
- ...Shard.configure(shard)
103
- })
104
- }
105
-
106
- entry = [pfxskeys[0].key, [batcher]]
107
- }
108
-
109
- shard.entries = Shard.putEntry(asShardEntries(shard.entries), asShardEntry(entry))
110
-
111
- // TODO: adjust size automatically
112
- const size = BatcherShard.encodedLength(shard)
113
- if (size > shard.maxSize) {
114
- const common = Shard.findCommonPrefix(
115
- asShardEntries(shard.entries),
116
- entry[0]
117
- )
118
- if (!common) throw new Error('shard limit reached')
119
- const { prefix } = common
120
- /** @type {API.BatcherShardEntry[]} */
121
- const matches = common.matches
122
-
123
- const entries = matches
124
- .filter(m => m[0] !== prefix)
125
- .map(m => {
126
- m = [...m]
127
- m[0] = m[0].slice(prefix.length)
128
- return m
129
- })
130
-
131
- const batcher = BatcherShard.create({
132
- entries,
133
- prefix: shard.prefix + prefix,
134
- ...Shard.configure(shard)
135
- })
136
-
137
- /** @type {API.ShardEntryShardValue | API.ShardEntryShardAndValueValue} */
138
- let value
139
- const pfxmatch = matches.find(m => m[0] === prefix)
140
- if (pfxmatch) {
141
- if (Array.isArray(pfxmatch[1])) {
142
- // should not happen! all entries with this prefix should have been
143
- // placed within this shard already.
144
- throw new Error(`expected "${prefix}" to be a shard value but found a shard link`)
145
- }
146
- value = [batcher, pfxmatch[1]]
147
- } else {
148
- value = [batcher]
149
- }
150
-
151
- shard.entries = Shard.putEntry(
152
- asShardEntries(shard.entries.filter(e => matches.every(m => e[0] !== m[0]))),
153
- asShardEntry([prefix, value])
154
- )
155
- }
156
- }
157
-
158
- /**
159
- * Traverse from the passed shard through to the correct shard for the passed
160
- * key.
161
- *
162
- * @param {ShardFetcher} shards
163
- * @param {string} key
164
- * @param {API.BatcherShard} shard
165
- * @returns {Promise<{ shard: API.BatcherShard, key: string }>}
166
- */
167
- export const traverse = async (shards, key, shard) => {
168
- for (let i = 0; i < shard.entries.length; i++) {
169
- const [k, v] = shard.entries[i]
170
- if (key <= k) break
171
- if (key.startsWith(k) && Array.isArray(v)) {
172
- if (Shard.isShardLink(v[0])) {
173
- const blk = await shards.get(v[0])
174
- const batcher = BatcherShard.create({ base: blk, ...blk.value })
175
- shard.entries[i] = [k, v[1] == null ? [batcher] : [batcher, v[1]]]
176
- return traverse(shards, key.slice(k.length), batcher)
177
- }
178
- return traverse(shards, key.slice(k.length), v[0])
179
- }
180
- }
181
- return { shard, key }
182
- }
183
-
184
- /**
185
- * Encode all altered shards in the batch and return the new root CID and
186
- * difference blocks.
187
- *
188
- * @param {API.BatcherShard} shard
189
- */
190
- export const commit = async shard => {
191
- /** @type {API.ShardBlockView[]} */
192
- const additions = []
193
- /** @type {API.ShardBlockView[]} */
194
- const removals = []
195
-
196
- /** @type {API.ShardEntry[]} */
197
- const entries = []
198
- for (const entry of shard.entries) {
199
- if (Array.isArray(entry[1]) && !Shard.isShardLink(entry[1][0])) {
200
- const result = await commit(entry[1][0])
201
- entries.push([
202
- entry[0],
203
- entry[1][1] == null ? [result.root] : [result.root, entry[1][1]]
204
- ])
205
- additions.push(...result.additions)
206
- removals.push(...result.removals)
207
- } else {
208
- entries.push(asShardEntry(entry))
209
- }
210
- }
211
-
212
- const block = await Shard.encodeBlock(Shard.withEntries(entries, shard))
213
- additions.push(block)
214
-
215
- if (shard.base && shard.base.cid.toString() === block.cid.toString()) {
216
- return { root: block.cid, additions: [], removals: [] }
217
- }
218
-
219
- if (shard.base) removals.push(shard.base)
220
-
221
- return { root: block.cid, additions, removals }
222
- }
223
-
224
- /** @param {API.BatcherShardEntry[]} entries */
225
- const asShardEntries = entries => /** @type {API.ShardEntry[]} */ (entries)
226
-
227
- /** @param {API.BatcherShardEntry} entry */
228
- const asShardEntry = entry => /** @type {API.ShardEntry} */ (entry)
229
-
230
- /**
231
- * @param {API.BlockFetcher} blocks Bucket block storage.
232
- * @param {API.ShardLink} root CID of the root shard block.
233
- * @returns {Promise<API.Batcher>}
234
- */
235
- export const create = (blocks, root) => Batcher.create({ blocks, link: root })
236
-
237
- export class BatchCommittedError extends Error {
238
- /**
239
- * @param {string} [message]
240
- * @param {ErrorOptions} [options]
241
- */
242
- constructor (message, options) {
243
- super(message ?? 'batch already committed', options)
244
- this.code = BatchCommittedError.code
245
- }
246
-
247
- static code = 'ERR_BATCH_COMMITTED'
248
- }
File without changes
@@ -1,13 +0,0 @@
1
- // eslint-disable-next-line no-unused-vars
2
- import * as API from './api.js'
3
- import { configure } from '../shard.js'
4
-
5
- /**
6
- * @param {API.BatcherShardInit} [init]
7
- * @returns {API.BatcherShard}
8
- */
9
- export const create = init => ({
10
- base: init?.base,
11
- entries: [...init?.entries ?? []],
12
- ...configure(init)
13
- })
package/src/block.js DELETED
@@ -1,75 +0,0 @@
1
- // eslint-disable-next-line no-unused-vars
2
- import * as API from './api.js'
3
- import { parse } from 'multiformats/link'
4
-
5
- /** @implements {API.BlockFetcher} */
6
- export class MemoryBlockstore {
7
- /** @type {Map<string, Uint8Array>} */
8
- #blocks = new Map()
9
-
10
- /**
11
- * @param {Array<import('multiformats').Block>} [blocks]
12
- */
13
- constructor (blocks) {
14
- if (blocks) {
15
- this.#blocks = new Map(blocks.map(b => [b.cid.toString(), b.bytes]))
16
- }
17
- }
18
-
19
- /** @type {API.BlockFetcher['get']} */
20
- async get (cid) {
21
- const bytes = this.#blocks.get(cid.toString())
22
- if (!bytes) return
23
- return { cid, bytes }
24
- }
25
-
26
- /**
27
- * @param {API.UnknownLink} cid
28
- * @param {Uint8Array} bytes
29
- */
30
- async put (cid, bytes) {
31
- this.#blocks.set(cid.toString(), bytes)
32
- }
33
-
34
- /**
35
- * @param {API.UnknownLink} cid
36
- * @param {Uint8Array} bytes
37
- */
38
- putSync (cid, bytes) {
39
- this.#blocks.set(cid.toString(), bytes)
40
- }
41
-
42
- /** @param {API.UnknownLink} cid */
43
- async delete (cid) {
44
- this.#blocks.delete(cid.toString())
45
- }
46
-
47
- /** @param {API.UnknownLink} cid */
48
- deleteSync (cid) {
49
- this.#blocks.delete(cid.toString())
50
- }
51
-
52
- * entries () {
53
- for (const [str, bytes] of this.#blocks) {
54
- yield { cid: parse(str), bytes }
55
- }
56
- }
57
- }
58
-
59
- export class MultiBlockFetcher {
60
- /** @type {API.BlockFetcher[]} */
61
- #fetchers
62
-
63
- /** @param {API.BlockFetcher[]} fetchers */
64
- constructor (...fetchers) {
65
- this.#fetchers = fetchers
66
- }
67
-
68
- /** @type {API.BlockFetcher['get']} */
69
- async get (link) {
70
- for (const f of this.#fetchers) {
71
- const v = await f.get(link)
72
- if (v) return v
73
- }
74
- }
75
- }
package/src/clock/api.js DELETED
@@ -1 +0,0 @@
1
- export {}
package/src/clock/api.ts DELETED
@@ -1,12 +0,0 @@
1
- import { Link, BlockView } from 'multiformats'
2
-
3
- export { BlockFetcher } from '../api.js'
4
-
5
- export type EventLink<T> = Link<EventView<T>>
6
-
7
- export interface EventView<T> {
8
- parents: EventLink<T>[]
9
- data: T
10
- }
11
-
12
- export interface EventBlockView<T> extends BlockView<EventView<T>> {}
@@ -1,182 +0,0 @@
1
- import { Block, encode, decode } from 'multiformats/block'
2
- import { sha256 } from 'multiformats/hashes/sha2'
3
- import * as cbor from '@ipld/dag-cbor'
4
- // eslint-disable-next-line no-unused-vars
5
- import * as API from './api.js'
6
-
7
- /**
8
- * Advance the clock by adding an event.
9
- *
10
- * @template T
11
- * @param {API.BlockFetcher} blocks Block storage.
12
- * @param {API.EventLink<T>[]} head The head of the clock.
13
- * @param {API.EventLink<T>} event The event to add.
14
- */
15
- export const advance = async (blocks, head, event) => {
16
- const events = new EventFetcher(blocks)
17
- const headmap = new Map(head.map(cid => [cid.toString(), cid]))
18
- if (headmap.has(event.toString())) return head
19
-
20
- // does event contain the clock?
21
- let changed = false
22
- for (const cid of head) {
23
- if (await contains(events, event, cid)) {
24
- headmap.delete(cid.toString())
25
- headmap.set(event.toString(), event)
26
- changed = true
27
- }
28
- }
29
- if (changed) {
30
- return [...headmap.values()]
31
- }
32
-
33
- // does clock contain the event?
34
- for (const p of head) {
35
- if (await contains(events, p, event)) {
36
- return head
37
- }
38
- }
39
-
40
- return head.concat(event)
41
- }
42
-
43
- /**
44
- * @template T
45
- * @extends {Block<API.EventView<T>, typeof cbor.code, typeof sha256.code, 1>}
46
- * @implements {API.EventBlockView<T>}
47
- */
48
- export class EventBlock extends Block {
49
- /**
50
- * @param {object} config
51
- * @param {API.EventLink<T>} config.cid
52
- * @param {Event} config.value
53
- * @param {Uint8Array} config.bytes
54
- * @param {string} config.prefix
55
- */
56
- constructor ({ cid, value, bytes, prefix }) {
57
- // @ts-expect-error
58
- super({ cid, value, bytes })
59
- this.prefix = prefix
60
- }
61
-
62
- /**
63
- * @template T
64
- * @param {T} data
65
- * @param {API.EventLink<T>[]} [parents]
66
- */
67
- static create (data, parents) {
68
- return encodeEventBlock({ data, parents: parents ?? [] })
69
- }
70
- }
71
-
72
- /** @template T */
73
- export class EventFetcher {
74
- /** @param {API.BlockFetcher} blocks */
75
- constructor (blocks) {
76
- /** @private */
77
- this._blocks = blocks
78
- }
79
-
80
- /**
81
- * @param {API.EventLink<T>} link
82
- * @returns {Promise<API.EventBlockView<T>>}
83
- */
84
- async get (link) {
85
- const block = await this._blocks.get(link)
86
- if (!block) throw new Error(`missing block: ${link}`)
87
- return decodeEventBlock(block.bytes)
88
- }
89
- }
90
-
91
- /**
92
- * @template T
93
- * @param {API.EventView<T>} value
94
- * @returns {Promise<API.EventBlockView<T>>}
95
- */
96
- export const encodeEventBlock = async (value) => {
97
- // TODO: sort parents
98
- const { cid, bytes } = await encode({ value, codec: cbor, hasher: sha256 })
99
- // @ts-expect-error
100
- return new Block({ cid, value, bytes })
101
- }
102
-
103
- /**
104
- * @template T
105
- * @param {Uint8Array} bytes
106
- * @returns {Promise<API.EventBlockView<T>>}
107
- */
108
- export const decodeEventBlock = async (bytes) => {
109
- const { cid, value } = await decode({ bytes, codec: cbor, hasher: sha256 })
110
- // @ts-expect-error
111
- return new Block({ cid, value, bytes })
112
- }
113
-
114
- /**
115
- * Returns true if event "a" contains event "b". Breadth first search.
116
- * @template T
117
- * @param {EventFetcher<T>} events
118
- * @param {API.EventLink<T>} a
119
- * @param {API.EventLink<T>} b
120
- */
121
- const contains = async (events, a, b) => {
122
- if (a.toString() === b.toString()) return true
123
- const [{ value: aevent }, { value: bevent }] = await Promise.all([events.get(a), events.get(b)])
124
- const links = [...aevent.parents]
125
- const seen = new Set()
126
- while (links.length) {
127
- const link = links.shift()
128
- if (!link) break
129
- if (link.toString() === b.toString()) return true
130
- // if any of b's parents are this link, then b cannot exist in any of the
131
- // tree below, since that would create a cycle.
132
- if (bevent.parents.some(p => link.toString() === p.toString())) continue
133
- if (seen.has(link.toString())) continue
134
- seen.add(link.toString())
135
- const { value: event } = await events.get(link)
136
- links.push(...event.parents)
137
- }
138
- return false
139
- }
140
-
141
- /**
142
- * @template T
143
- * @param {API.BlockFetcher} blocks Block storage.
144
- * @param {API.EventLink<T>[]} head
145
- * @param {object} [options]
146
- * @param {(b: API.EventBlockView<T>) => string} [options.renderNodeLabel]
147
- */
148
- export const vis = async function * (blocks, head, options = {}) {
149
- const renderNodeLabel = options.renderNodeLabel ?? (b => shortLink(b.cid))
150
- const events = new EventFetcher(blocks)
151
- yield 'digraph clock {'
152
- yield ' node [shape=point fontname="Courier"]; head;'
153
- const hevents = await Promise.all(head.map(link => events.get(link)))
154
- /** @type {import('multiformats').Link<API.EventView<any>>[]} */
155
- const links = []
156
- const nodes = new Set()
157
- for (const e of hevents) {
158
- nodes.add(e.cid.toString())
159
- yield ` node [shape=oval fontname="Courier"]; ${e.cid} [label="${renderNodeLabel(e)}"];`
160
- yield ` head -> ${e.cid};`
161
- for (const p of e.value.parents) {
162
- yield ` ${e.cid} -> ${p};`
163
- }
164
- links.push(...e.value.parents)
165
- }
166
- while (links.length) {
167
- const link = links.shift()
168
- if (!link) break
169
- if (nodes.has(link.toString())) continue
170
- nodes.add(link.toString())
171
- const block = await events.get(link)
172
- yield ` node [shape=oval]; ${link} [label="${renderNodeLabel(block)}" fontname="Courier"];`
173
- for (const p of block.value.parents) {
174
- yield ` ${link} -> ${p};`
175
- }
176
- links.push(...block.value.parents)
177
- }
178
- yield '}'
179
- }
180
-
181
- /** @param {import('multiformats').UnknownLink} l */
182
- const shortLink = l => `${String(l).slice(0, 4)}..${String(l).slice(-4)}`
package/src/crdt/api.js DELETED
@@ -1 +0,0 @@
1
- export {}
package/src/crdt/api.ts DELETED
@@ -1,33 +0,0 @@
1
- import { ShardDiff, ShardLink, UnknownLink } from '../api.js'
2
- import { EventLink, EventBlockView } from '../clock/api.js'
3
-
4
- export { BlockFetcher, UnknownLink, ShardBlockView, ShardDiff, ShardLink } from '../api.js'
5
- export { EventBlockView, EventLink } from '../clock/api.js'
6
-
7
- export interface Result extends ShardDiff {
8
- root: ShardLink
9
- head: EventLink<Operation>[]
10
- event?: EventBlockView<Operation>
11
- }
12
-
13
- export type Operation = (
14
- | PutOperation
15
- | DeleteOperation
16
- | BatchOperation
17
- ) & { root: ShardLink }
18
-
19
- export interface PutOperation {
20
- type: 'put',
21
- key: string
22
- value: UnknownLink
23
- }
24
-
25
- export interface DeleteOperation {
26
- type: 'del',
27
- key: string
28
- }
29
-
30
- export interface BatchOperation {
31
- type: 'batch',
32
- ops: Array<PutOperation|DeleteOperation>
33
- }
@@ -1 +0,0 @@
1
- export {}
@@ -1,30 +0,0 @@
1
- import {
2
- Batcher,
3
- BatcherShardEntry,
4
- ShardBlockView,
5
- BlockFetcher,
6
- ShardLink,
7
- UnknownLink
8
- } from '../../batch/api.js'
9
- import { Operation, BatchOperation, EventLink, Result } from '../api.js'
10
-
11
- export {
12
- Batcher,
13
- BatcherShardEntry,
14
- ShardBlockView,
15
- BlockFetcher,
16
- ShardLink,
17
- UnknownLink,
18
- Operation,
19
- BatchOperation,
20
- EventLink,
21
- Result
22
- }
23
-
24
- export interface CRDTBatcher extends Batcher {
25
- /**
26
- * Encode all altered shards in the batch and return the new root CID, new
27
- * clock head, the new clock event and the difference blocks.
28
- */
29
- commit (): Promise<Result>
30
- }