helia 0.0.0-031ca73

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.
@@ -0,0 +1,169 @@
1
+ /* eslint max-depth: ["error", 7] */
2
+
3
+ import * as dagPb from '@ipld/dag-pb'
4
+ import * as cborg from 'cborg'
5
+ import { Type, Token } from 'cborg'
6
+ import * as cborgJson from 'cborg/json'
7
+ import type { DAGWalker } from '../index.js'
8
+ import * as raw from 'multiformats/codecs/raw'
9
+ import { CID } from 'multiformats'
10
+ import { base64 } from 'multiformats/bases/base64'
11
+
12
+ /**
13
+ * Dag walker for dag-pb CIDs
14
+ */
15
+ export const dagPbWalker: DAGWalker = {
16
+ codec: dagPb.code,
17
+ async * walk (block) {
18
+ const node = dagPb.decode(block)
19
+
20
+ yield * node.Links.map(l => l.Hash)
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Dag walker for raw CIDs
26
+ */
27
+ export const rawWalker: DAGWalker = {
28
+ codec: raw.code,
29
+ async * walk () {
30
+ // no embedded CIDs in a raw block
31
+ }
32
+ }
33
+
34
+ // https://github.com/ipfs/go-ipfs/issues/3570#issuecomment-273931692
35
+ const CID_TAG = 42
36
+
37
+ /**
38
+ * Dag walker for dag-cbor CIDs. Does not actually use dag-cbor since
39
+ * all we are interested in is extracting the the CIDs from the block
40
+ * so we can just use cborg for that.
41
+ */
42
+ export const cborWalker: DAGWalker = {
43
+ codec: 0x71,
44
+ async * walk (block) {
45
+ const cids: CID[] = []
46
+ const tags: cborg.TagDecoder[] = []
47
+ tags[CID_TAG] = (bytes) => {
48
+ if (bytes[0] !== 0) {
49
+ throw new Error('Invalid CID for CBOR tag 42; expected leading 0x00')
50
+ }
51
+
52
+ const cid = CID.decode(bytes.subarray(1)) // ignore leading 0x00
53
+
54
+ cids.push(cid)
55
+
56
+ return cid
57
+ }
58
+
59
+ cborg.decode(block, {
60
+ tags
61
+ })
62
+
63
+ yield * cids
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Borrowed from @ipld/dag-json
69
+ */
70
+ class DagJsonTokenizer extends cborgJson.Tokenizer {
71
+ private readonly tokenBuffer: cborg.Token[]
72
+
73
+ constructor (data: Uint8Array, options?: cborg.DecodeOptions) {
74
+ super(data, options)
75
+
76
+ this.tokenBuffer = []
77
+ }
78
+
79
+ done (): boolean {
80
+ return this.tokenBuffer.length === 0 && super.done()
81
+ }
82
+
83
+ _next (): cborg.Token {
84
+ if (this.tokenBuffer.length > 0) {
85
+ // @ts-expect-error https://github.com/Microsoft/TypeScript/issues/30406
86
+ return this.tokenBuffer.pop()
87
+ }
88
+ return super.next()
89
+ }
90
+
91
+ /**
92
+ * Implements rules outlined in https://github.com/ipld/specs/pull/356
93
+ */
94
+ next (): cborg.Token {
95
+ const token = this._next()
96
+
97
+ if (token.type === Type.map) {
98
+ const keyToken = this._next()
99
+ if (keyToken.type === Type.string && keyToken.value === '/') {
100
+ const valueToken = this._next()
101
+ if (valueToken.type === Type.string) { // *must* be a CID
102
+ const breakToken = this._next() // swallow the end-of-map token
103
+ if (breakToken.type !== Type.break) {
104
+ throw new Error('Invalid encoded CID form')
105
+ }
106
+ this.tokenBuffer.push(valueToken) // CID.parse will pick this up after our tag token
107
+ return new Token(Type.tag, 42, 0)
108
+ }
109
+ if (valueToken.type === Type.map) {
110
+ const innerKeyToken = this._next()
111
+ if (innerKeyToken.type === Type.string && innerKeyToken.value === 'bytes') {
112
+ const innerValueToken = this._next()
113
+ if (innerValueToken.type === Type.string) { // *must* be Bytes
114
+ for (let i = 0; i < 2; i++) {
115
+ const breakToken = this._next() // swallow two end-of-map tokens
116
+ if (breakToken.type !== Type.break) {
117
+ throw new Error('Invalid encoded Bytes form')
118
+ }
119
+ }
120
+ const bytes = base64.decode(`m${innerValueToken.value}`)
121
+ return new Token(Type.bytes, bytes, innerValueToken.value.length)
122
+ }
123
+ this.tokenBuffer.push(innerValueToken) // bail
124
+ }
125
+ this.tokenBuffer.push(innerKeyToken) // bail
126
+ }
127
+ this.tokenBuffer.push(valueToken) // bail
128
+ }
129
+ this.tokenBuffer.push(keyToken) // bail
130
+ }
131
+ return token
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Dag walker for dag-json CIDs. Does not actually use dag-json since
137
+ * all we are interested in is extracting the the CIDs from the block
138
+ * so we can just use cborg/json for that.
139
+ */
140
+ export const jsonWalker: DAGWalker = {
141
+ codec: 0x0129,
142
+ async * walk (block) {
143
+ const cids: CID[] = []
144
+ const tags: cborg.TagDecoder[] = []
145
+ tags[CID_TAG] = (string) => {
146
+ const cid = CID.parse(string)
147
+
148
+ cids.push(cid)
149
+
150
+ return cid
151
+ }
152
+
153
+ cborgJson.decode(block, {
154
+ tags,
155
+ tokenizer: new DagJsonTokenizer(block, {
156
+ tags,
157
+ allowIndefinite: true,
158
+ allowUndefined: true,
159
+ allowNaN: true,
160
+ allowInfinity: true,
161
+ allowBigInt: true,
162
+ strict: false,
163
+ rejectDuplicateMapKeys: false
164
+ })
165
+ })
166
+
167
+ yield * cids
168
+ }
169
+ }
@@ -0,0 +1,23 @@
1
+ import { Datastore, Key } from 'interface-datastore'
2
+ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
3
+ import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
4
+
5
+ const DS_VERSION_KEY = new Key('/version')
6
+ const CURRENT_VERSION = 1
7
+
8
+ export async function assertDatastoreVersionIsCurrent (datastore: Datastore): Promise<void> {
9
+ if (!(await datastore.has(DS_VERSION_KEY))) {
10
+ await datastore.put(DS_VERSION_KEY, uint8ArrayFromString(`${CURRENT_VERSION}`))
11
+
12
+ return
13
+ }
14
+
15
+ const buf = await datastore.get(DS_VERSION_KEY)
16
+ const str = uint8ArrayToString(buf)
17
+ const version = parseInt(str, 10)
18
+
19
+ if (version !== CURRENT_VERSION) {
20
+ // TODO: write migrations when we break compatibility - for an example, see https://github.com/ipfs/js-ipfs-repo/tree/master/packages/ipfs-repo-migrations
21
+ throw new Error('Unknown datastore version, a datastore migration may be required')
22
+ }
23
+ }