@atcute/cid 2.2.6 → 2.4.0
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.
- package/README.md +75 -6
- package/dist/cid-link.d.ts.map +1 -1
- package/dist/cid-link.js.map +1 -1
- package/dist/codec.d.ts +65 -7
- package/dist/codec.d.ts.map +1 -1
- package/dist/codec.js +73 -40
- package/dist/codec.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/lib/codec.ts +74 -48
- package/lib/index.ts +2 -0
- package/package.json +9 -5
package/README.md
CHANGED
|
@@ -1,18 +1,87 @@
|
|
|
1
1
|
# @atcute/cid
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
content identifier (CID) codec for AT Protocol.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install @atcute/cid
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
this library implements DASL's [CID][dasl-cid] format used by AT Protocol to address resources by
|
|
10
|
+
their contents.
|
|
4
11
|
|
|
5
12
|
[dasl-cid]: https://dasl.ing/cid.html
|
|
6
13
|
|
|
14
|
+
## usage
|
|
15
|
+
|
|
16
|
+
### creating CIDs
|
|
17
|
+
|
|
7
18
|
```ts
|
|
8
19
|
import * as CID from '@atcute/cid';
|
|
9
20
|
|
|
21
|
+
// create a CID from DAG-CBOR data
|
|
22
|
+
const cid = await CID.create(0x71, cborBytes);
|
|
23
|
+
// -> { version: 1, codec: 113, digest: { ... }, bytes: Uint8Array(36) }
|
|
24
|
+
|
|
25
|
+
// create from raw data
|
|
26
|
+
const rawCid = await CID.create(0x55, rawBytes);
|
|
27
|
+
|
|
28
|
+
// create an empty CID (zero-length digest)
|
|
29
|
+
const empty = CID.createEmpty(0x71);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### parsing CIDs
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import * as CID from '@atcute/cid';
|
|
36
|
+
|
|
37
|
+
// parse from base32 string
|
|
10
38
|
const cid = CID.fromString('bafyreihffx5a2e7k5uwrmmgofbvzujc5cmw5h4espouwuxt3liqoflx3ee');
|
|
11
|
-
// ^? { version: 1, codec: 113, digest: { ... }, bytes: Uint8Array(36) }
|
|
12
39
|
|
|
13
|
-
//
|
|
14
|
-
const cid =
|
|
40
|
+
// parse from binary (with 0x00 prefix)
|
|
41
|
+
const cid = CID.fromBinary(bytes);
|
|
42
|
+
|
|
43
|
+
// parse from raw CID bytes
|
|
44
|
+
const cid = CID.decode(cidBytes);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### serializing CIDs
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import * as CID from '@atcute/cid';
|
|
51
|
+
|
|
52
|
+
// to base32 string
|
|
53
|
+
CID.toString(cid);
|
|
54
|
+
// -> "bafyreihffx5a2e7k5uwrmmgofbvzujc5cmw5h4espouwuxt3liqoflx3ee"
|
|
55
|
+
|
|
56
|
+
// to binary (with 0x00 prefix)
|
|
57
|
+
CID.toBinary(cid);
|
|
58
|
+
// -> Uint8Array(37)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### comparing CIDs
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import * as CID from '@atcute/cid';
|
|
65
|
+
|
|
66
|
+
CID.equals(cidA, cidB); // true if same content hash
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### CidLink wrapper
|
|
70
|
+
|
|
71
|
+
for JSON serialization compatible with atproto's data model:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { toCidLink, fromCidLink, isCidLink } from '@atcute/cid';
|
|
75
|
+
|
|
76
|
+
// convert Cid to CidLink (has $link property)
|
|
77
|
+
const link = toCidLink(cid);
|
|
78
|
+
// -> { $link: "bafyrei..." }
|
|
79
|
+
|
|
80
|
+
// convert back to Cid
|
|
81
|
+
const cid = fromCidLink(link);
|
|
15
82
|
|
|
16
|
-
//
|
|
17
|
-
|
|
83
|
+
// type guard
|
|
84
|
+
if (isCidLink(value)) {
|
|
85
|
+
console.log(value.$link);
|
|
86
|
+
}
|
|
18
87
|
```
|
package/dist/cid-link.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cid-link.d.ts","sourceRoot":"","sources":["../lib/cid-link.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2C,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAO/E,MAAM,WAAW,OAAO;IACvB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,cAAe,YAAW,OAAO;IAI7C,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"cid-link.d.ts","sourceRoot":"","sources":["../lib/cid-link.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2C,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAO/E,MAAM,WAAW,OAAO;IACvB,KAAK,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,cAAe,YAAW,OAAO;IAI7C,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAE3B,YAAY,KAAK,EAAE,UAAU,EAE5B;IAED,IAAI,KAAK,IAAI,MAAM,CASlB;IAED,MAAM,IAAI,OAAO,CAEhB;CACD;AAED,eAAO,MAAM,SAAS,sCAOrB,CAAC;AAEF,eAAO,MAAM,SAAS,uBASrB,CAAC;AAEF,eAAO,MAAM,WAAW,wBAMvB,CAAC"}
|
package/dist/cid-link.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cid-link.js","sourceRoot":"","sources":["../lib/cid-link.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,UAAU,EAAY,MAAM,YAAY,CAAC;AAE/E,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;AAE/D,gBAAgB;AAChB,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,OAAO,EAA0B,CAAC;AAM7E,MAAM,OAAO,cAAc;IAC1B,gBAAgB;IACP,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC;IAEzB,KAAK,CAAa;IAE3B,YAAY,KAAiB;
|
|
1
|
+
{"version":3,"file":"cid-link.js","sourceRoot":"","sources":["../lib/cid-link.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,UAAU,EAAY,MAAM,YAAY,CAAC;AAE/E,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;AAE/D,gBAAgB;AAChB,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,OAAO,EAA0B,CAAC;AAM7E,MAAM,OAAO,cAAc;IAC1B,gBAAgB;IACP,CAAC,eAAe,CAAC,GAAG,IAAI,CAAC;IAEzB,KAAK,CAAa;IAE3B,YAAY,KAAiB,EAAE;QAC9B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAAA,CACnB;IAED,IAAI,KAAK,GAAW;QACnB,IAAI,GAAG,GAAG,uBAAuB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACvB,GAAG,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAEjC,uBAAuB,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACxC,CAAC;QAED,OAAO,GAAG,CAAC;IAAA,CACX;IAED,MAAM,GAAY;QACjB,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IAAA,CAC7B;CACD;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAc,EAAoB,EAAE,CAAC;IAC9D,MAAM,GAAG,GAAG,KAAY,CAAC;IAEzB,OAAO,CACN,GAAG,YAAY,cAAc;QAC7B,CAAC,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAC1E,CAAC;AAAA,CACF,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAAQ,EAAW,EAAE,CAAC;IAC/C,MAAM,IAAI,GAAG,IAAI,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAEzC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACvB,uBAAuB,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,IAAI,CAAC;AAAA,CACZ,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAa,EAAO,EAAE,CAAC;IAClD,IAAI,IAAI,YAAY,cAAc,EAAE,CAAC;QACpC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAAA,CAC9B,CAAC"}
|
package/dist/codec.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
/** CID version, always `1` for CIDv1 */
|
|
1
2
|
export declare const CID_VERSION = 1;
|
|
3
|
+
/** multicodec for SHA-256 hash */
|
|
2
4
|
export declare const HASH_SHA256 = 18;
|
|
5
|
+
/** multicodec for raw binary data */
|
|
3
6
|
export declare const CODEC_RAW = 85;
|
|
7
|
+
/** multicodec for DAG-CBOR encoded data */
|
|
4
8
|
export declare const CODEC_DCBOR = 113;
|
|
5
9
|
/**
|
|
6
|
-
*
|
|
10
|
+
* represents a Content Identifier (CID), in particular, a limited subset of
|
|
7
11
|
* CIDv1 as described by DASL specifications.
|
|
8
12
|
* https://dasl.ing/cid.html
|
|
9
13
|
*/
|
|
@@ -22,13 +26,67 @@ export interface Cid {
|
|
|
22
26
|
/** Raw CID bytes */
|
|
23
27
|
readonly bytes: Uint8Array;
|
|
24
28
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
/**
|
|
30
|
+
* creates a CID from a pre-computed SHA-256 digest
|
|
31
|
+
* @param codec multicodec type for the data
|
|
32
|
+
* @param digest raw SHA-256 hash bytes (must be 32 bytes)
|
|
33
|
+
* @returns CID object
|
|
34
|
+
*/
|
|
35
|
+
export declare const fromDigest: (codec: 85 | 113, digest: Uint8Array<ArrayBufferLike>) => Cid;
|
|
36
|
+
/**
|
|
37
|
+
* creates a CID by hashing the provided data with SHA-256
|
|
38
|
+
* @param codec multicodec type for the data
|
|
39
|
+
* @param data raw data to hash
|
|
40
|
+
* @returns CID object
|
|
41
|
+
*/
|
|
42
|
+
export declare const create: (codec: 85 | 113, data: Uint8Array<ArrayBufferLike>) => Promise<Cid>;
|
|
43
|
+
/**
|
|
44
|
+
* decodes a CID from bytes, returning the CID and any remaining bytes
|
|
45
|
+
* @param bytes raw CID bytes
|
|
46
|
+
* @returns tuple of decoded CID and remainder bytes
|
|
47
|
+
* @throws {RangeError} if the bytes are too short or contain invalid values
|
|
48
|
+
*/
|
|
49
|
+
export declare const decodeFirst: (bytes: Uint8Array<ArrayBufferLike>) => [decoded: Cid, remainder: Uint8Array<ArrayBufferLike>];
|
|
50
|
+
/**
|
|
51
|
+
* decodes a CID from bytes, expecting no remainder
|
|
52
|
+
* @param bytes raw CID bytes
|
|
53
|
+
* @returns decoded CID
|
|
54
|
+
* @throws {RangeError} if the bytes are invalid or contain extra data
|
|
55
|
+
*/
|
|
56
|
+
export declare const decode: (bytes: Uint8Array<ArrayBufferLike>) => Cid;
|
|
57
|
+
/**
|
|
58
|
+
* parses a CID from a multibase base32 string
|
|
59
|
+
* @param input base32-encoded CID string (with 'b' prefix)
|
|
60
|
+
* @returns decoded CID
|
|
61
|
+
* @throws {SyntaxError} if the string is not a valid multibase base32 string
|
|
62
|
+
* @throws {RangeError} if the string length is invalid
|
|
63
|
+
*/
|
|
29
64
|
export declare const fromString: (input: string) => Cid;
|
|
65
|
+
/**
|
|
66
|
+
* encodes a CID to a multibase base32 string
|
|
67
|
+
* @param cid CID to encode
|
|
68
|
+
* @returns base32-encoded string with 'b' prefix
|
|
69
|
+
*/
|
|
30
70
|
export declare const toString: (cid: Cid) => string;
|
|
31
|
-
|
|
32
|
-
|
|
71
|
+
/**
|
|
72
|
+
* parses a CID from binary format (with 0x00 prefix)
|
|
73
|
+
* @param input binary CID bytes with 0x00 prefix
|
|
74
|
+
* @returns decoded CID
|
|
75
|
+
* @throws {RangeError} if the byte length is invalid
|
|
76
|
+
* @throws {SyntaxError} if the prefix byte is not 0x00
|
|
77
|
+
*/
|
|
78
|
+
export declare const fromBinary: (input: Uint8Array<ArrayBufferLike>) => Cid;
|
|
79
|
+
/**
|
|
80
|
+
* encodes a CID to binary format (with 0x00 prefix)
|
|
81
|
+
* @param cid CID to encode
|
|
82
|
+
* @returns binary CID bytes with 0x00 prefix
|
|
83
|
+
*/
|
|
84
|
+
export declare const toBinary: (cid: Cid) => Uint8Array<ArrayBufferLike>;
|
|
85
|
+
/**
|
|
86
|
+
* checks if two CIDs are equal
|
|
87
|
+
* @param a first CID
|
|
88
|
+
* @param b second CID
|
|
89
|
+
* @returns true if the CIDs have identical bytes
|
|
90
|
+
*/
|
|
33
91
|
export declare const equals: (a: Cid, b: Cid) => boolean;
|
|
34
92
|
//# sourceMappingURL=codec.d.ts.map
|
package/dist/codec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../lib/codec.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,WAAW,KAAO,CAAC;AAEhC,eAAO,MAAM,SAAS,KAAO,CAAC;AAC9B,eAAO,MAAM,WAAW,MAAO,CAAC;AAKhC;;;;GAIG;AACH,MAAM,WAAW,GAAG;IACnB,gDAAgD;IAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,sBAAsB;IACtB,QAAQ,CAAC,MAAM,EAAE;QAChB,wEAAwE;QACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,qBAAqB;QACrB,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;KAC9B,CAAC;IACF,oBAAoB;IACpB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC3B;AAKD,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../lib/codec.ts"],"names":[],"mappings":"AAGA,wCAAwC;AACxC,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,kCAAkC;AAClC,eAAO,MAAM,WAAW,KAAO,CAAC;AAEhC,qCAAqC;AACrC,eAAO,MAAM,SAAS,KAAO,CAAC;AAC9B,2CAA2C;AAC3C,eAAO,MAAM,WAAW,MAAO,CAAC;AAKhC;;;;GAIG;AACH,MAAM,WAAW,GAAG;IACnB,gDAAgD;IAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,sFAAsF;IACtF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,sBAAsB;IACtB,QAAQ,CAAC,MAAM,EAAE;QAChB,wEAAwE;QACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,qBAAqB;QACrB,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;KAC9B,CAAC;IACF,oBAAoB;IACpB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC3B;AAKD;;;;;GAKG;AACH,eAAO,MAAM,UAAU,+DAuBtB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,MAAM,sEAGlB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,gGAqCvB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,MAAM,6CAQlB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,wBAWtB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,sBASpB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,6CAOtB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,2CAMpB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,MAAM,6BAElB,CAAC"}
|
package/dist/codec.js
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import { fromBase32, toBase32 } from '@atcute/multibase';
|
|
2
2
|
import { allocUnsafe, toSha256, equals as isBufferEqual } from '@atcute/uint8array';
|
|
3
|
+
/** CID version, always `1` for CIDv1 */
|
|
3
4
|
export const CID_VERSION = 1;
|
|
5
|
+
/** multicodec for SHA-256 hash */
|
|
4
6
|
export const HASH_SHA256 = 0x12;
|
|
7
|
+
/** multicodec for raw binary data */
|
|
5
8
|
export const CODEC_RAW = 0x55;
|
|
9
|
+
/** multicodec for DAG-CBOR encoded data */
|
|
6
10
|
export const CODEC_DCBOR = 0x71;
|
|
7
11
|
/** @internal */
|
|
8
12
|
export const CID_STRINGIFY_CACHE = new WeakMap();
|
|
9
13
|
// a SHA-256 CIDv1 is always going to be 36 bytes, that's 4 bytes for the
|
|
10
14
|
// header, and 32 bytes for the digest itself.
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
/**
|
|
16
|
+
* creates a CID from a pre-computed SHA-256 digest
|
|
17
|
+
* @param codec multicodec type for the data
|
|
18
|
+
* @param digest raw SHA-256 hash bytes (must be 32 bytes)
|
|
19
|
+
* @returns CID object
|
|
20
|
+
*/
|
|
21
|
+
export const fromDigest = (codec, digest) => {
|
|
13
22
|
if (digest.length !== 32) {
|
|
14
23
|
throw new RangeError(`invalid digest length`);
|
|
15
24
|
}
|
|
@@ -19,7 +28,7 @@ export const create = async (codec, data) => {
|
|
|
19
28
|
bytes[2] = HASH_SHA256;
|
|
20
29
|
bytes[3] = 32;
|
|
21
30
|
bytes.set(digest, 4);
|
|
22
|
-
|
|
31
|
+
return {
|
|
23
32
|
version: CID_VERSION,
|
|
24
33
|
codec: codec,
|
|
25
34
|
digest: {
|
|
@@ -28,25 +37,25 @@ export const create = async (codec, data) => {
|
|
|
28
37
|
},
|
|
29
38
|
bytes: bytes,
|
|
30
39
|
};
|
|
31
|
-
return cid;
|
|
32
40
|
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
},
|
|
43
|
-
bytes: bytes,
|
|
44
|
-
};
|
|
45
|
-
return cid;
|
|
41
|
+
/**
|
|
42
|
+
* creates a CID by hashing the provided data with SHA-256
|
|
43
|
+
* @param codec multicodec type for the data
|
|
44
|
+
* @param data raw data to hash
|
|
45
|
+
* @returns CID object
|
|
46
|
+
*/
|
|
47
|
+
export const create = async (codec, data) => {
|
|
48
|
+
const digest = await toSha256(data);
|
|
49
|
+
return fromDigest(codec, digest);
|
|
46
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* decodes a CID from bytes, returning the CID and any remaining bytes
|
|
53
|
+
* @param bytes raw CID bytes
|
|
54
|
+
* @returns tuple of decoded CID and remainder bytes
|
|
55
|
+
* @throws {RangeError} if the bytes are too short or contain invalid values
|
|
56
|
+
*/
|
|
47
57
|
export const decodeFirst = (bytes) => {
|
|
48
|
-
|
|
49
|
-
if (length < 4) {
|
|
58
|
+
if (bytes.length < 36) {
|
|
50
59
|
throw new RangeError(`cid too short`);
|
|
51
60
|
}
|
|
52
61
|
const version = bytes[0];
|
|
@@ -62,23 +71,26 @@ export const decodeFirst = (bytes) => {
|
|
|
62
71
|
if (digestType !== HASH_SHA256) {
|
|
63
72
|
throw new RangeError(`incorrect cid digest codec (got 0x${digestType.toString(16)})`);
|
|
64
73
|
}
|
|
65
|
-
if (digestSize !== 32
|
|
74
|
+
if (digestSize !== 32) {
|
|
66
75
|
throw new RangeError(`incorrect cid digest size (got ${digestSize})`);
|
|
67
76
|
}
|
|
68
|
-
if (length < 4 + digestSize) {
|
|
69
|
-
throw new RangeError(`cid too short`);
|
|
70
|
-
}
|
|
71
77
|
const cid = {
|
|
72
78
|
version: CID_VERSION,
|
|
73
79
|
codec: codec,
|
|
74
80
|
digest: {
|
|
75
81
|
codec: digestType,
|
|
76
|
-
contents: bytes.subarray(4,
|
|
82
|
+
contents: bytes.subarray(4, 36),
|
|
77
83
|
},
|
|
78
|
-
bytes: bytes.subarray(0,
|
|
84
|
+
bytes: bytes.subarray(0, 36),
|
|
79
85
|
};
|
|
80
|
-
return [cid, bytes.subarray(
|
|
86
|
+
return [cid, bytes.subarray(36)];
|
|
81
87
|
};
|
|
88
|
+
/**
|
|
89
|
+
* decodes a CID from bytes, expecting no remainder
|
|
90
|
+
* @param bytes raw CID bytes
|
|
91
|
+
* @returns decoded CID
|
|
92
|
+
* @throws {RangeError} if the bytes are invalid or contain extra data
|
|
93
|
+
*/
|
|
82
94
|
export const decode = (bytes) => {
|
|
83
95
|
const [cid, remainder] = decodeFirst(bytes);
|
|
84
96
|
if (remainder.length !== 0) {
|
|
@@ -86,20 +98,28 @@ export const decode = (bytes) => {
|
|
|
86
98
|
}
|
|
87
99
|
return cid;
|
|
88
100
|
};
|
|
101
|
+
/**
|
|
102
|
+
* parses a CID from a multibase base32 string
|
|
103
|
+
* @param input base32-encoded CID string (with 'b' prefix)
|
|
104
|
+
* @returns decoded CID
|
|
105
|
+
* @throws {SyntaxError} if the string is not a valid multibase base32 string
|
|
106
|
+
* @throws {RangeError} if the string length is invalid
|
|
107
|
+
*/
|
|
89
108
|
export const fromString = (input) => {
|
|
90
|
-
if (input.length < 2 || input[0] !== 'b') {
|
|
91
|
-
throw new SyntaxError(`not a multibase base32 string`);
|
|
92
|
-
}
|
|
93
|
-
// 4 bytes in base32 = 7 characters + 1 character for the prefix
|
|
94
109
|
// 36 bytes in base32 = 58 characters + 1 character for the prefix
|
|
95
|
-
if (input.length !== 59
|
|
96
|
-
throw new
|
|
110
|
+
if (input.length !== 59 || input[0] !== 'b') {
|
|
111
|
+
throw new SyntaxError(`not a valid cid string`);
|
|
97
112
|
}
|
|
98
113
|
const bytes = fromBase32(input.slice(1));
|
|
99
114
|
const cid = decode(bytes);
|
|
100
115
|
CID_STRINGIFY_CACHE.set(cid, input);
|
|
101
116
|
return cid;
|
|
102
117
|
};
|
|
118
|
+
/**
|
|
119
|
+
* encodes a CID to a multibase base32 string
|
|
120
|
+
* @param cid CID to encode
|
|
121
|
+
* @returns base32-encoded string with 'b' prefix
|
|
122
|
+
*/
|
|
103
123
|
export const toString = (cid) => {
|
|
104
124
|
let str = CID_STRINGIFY_CACHE.get(cid);
|
|
105
125
|
if (str === undefined) {
|
|
@@ -108,24 +128,37 @@ export const toString = (cid) => {
|
|
|
108
128
|
}
|
|
109
129
|
return str;
|
|
110
130
|
};
|
|
131
|
+
/**
|
|
132
|
+
* parses a CID from binary format (with 0x00 prefix)
|
|
133
|
+
* @param input binary CID bytes with 0x00 prefix
|
|
134
|
+
* @returns decoded CID
|
|
135
|
+
* @throws {RangeError} if the byte length is invalid
|
|
136
|
+
* @throws {SyntaxError} if the prefix byte is not 0x00
|
|
137
|
+
*/
|
|
111
138
|
export const fromBinary = (input) => {
|
|
112
|
-
// 4 bytes + 1 byte for the 0x00 prefix
|
|
113
139
|
// 36 bytes + 1 byte for the 0x00 prefix
|
|
114
|
-
if (input.length !== 37
|
|
115
|
-
throw new
|
|
116
|
-
}
|
|
117
|
-
if (input[0] !== 0) {
|
|
118
|
-
throw new SyntaxError(`incorrect binary cid`);
|
|
140
|
+
if (input.length !== 37 || input[0] !== 0) {
|
|
141
|
+
throw new SyntaxError(`invalid binary cid`);
|
|
119
142
|
}
|
|
120
|
-
|
|
121
|
-
return decode(bytes);
|
|
143
|
+
return decode(input.subarray(1));
|
|
122
144
|
};
|
|
145
|
+
/**
|
|
146
|
+
* encodes a CID to binary format (with 0x00 prefix)
|
|
147
|
+
* @param cid CID to encode
|
|
148
|
+
* @returns binary CID bytes with 0x00 prefix
|
|
149
|
+
*/
|
|
123
150
|
export const toBinary = (cid) => {
|
|
124
151
|
const bytes = allocUnsafe(1 + cid.bytes.length);
|
|
125
152
|
bytes[0] = 0;
|
|
126
153
|
bytes.set(cid.bytes, 1);
|
|
127
154
|
return bytes;
|
|
128
155
|
};
|
|
156
|
+
/**
|
|
157
|
+
* checks if two CIDs are equal
|
|
158
|
+
* @param a first CID
|
|
159
|
+
* @param b second CID
|
|
160
|
+
* @returns true if the CIDs have identical bytes
|
|
161
|
+
*/
|
|
129
162
|
export const equals = (a, b) => {
|
|
130
163
|
return isBufferEqual(a.bytes, b.bytes);
|
|
131
164
|
};
|
package/dist/codec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../lib/codec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,IAAI,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEpF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAC7B,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC;AAEhC,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC;AAC9B,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC;AAEhC,gBAAgB;AAChB,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,OAAO,EAAe,CAAC;AAuB9D,yEAAyE;AACzE,8CAA8C;AAE9C,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../lib/codec.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAEA,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAE1D,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC"}
|
package/lib/codec.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { fromBase32, toBase32 } from '@atcute/multibase';
|
|
2
2
|
import { allocUnsafe, toSha256, equals as isBufferEqual } from '@atcute/uint8array';
|
|
3
3
|
|
|
4
|
+
/** CID version, always `1` for CIDv1 */
|
|
4
5
|
export const CID_VERSION = 1;
|
|
6
|
+
/** multicodec for SHA-256 hash */
|
|
5
7
|
export const HASH_SHA256 = 0x12;
|
|
6
8
|
|
|
9
|
+
/** multicodec for raw binary data */
|
|
7
10
|
export const CODEC_RAW = 0x55;
|
|
11
|
+
/** multicodec for DAG-CBOR encoded data */
|
|
8
12
|
export const CODEC_DCBOR = 0x71;
|
|
9
13
|
|
|
10
14
|
/** @internal */
|
|
11
15
|
export const CID_STRINGIFY_CACHE = new WeakMap<Cid, string>();
|
|
12
16
|
|
|
13
17
|
/**
|
|
14
|
-
*
|
|
18
|
+
* represents a Content Identifier (CID), in particular, a limited subset of
|
|
15
19
|
* CIDv1 as described by DASL specifications.
|
|
16
20
|
* https://dasl.ing/cid.html
|
|
17
21
|
*/
|
|
@@ -34,8 +38,13 @@ export interface Cid {
|
|
|
34
38
|
// a SHA-256 CIDv1 is always going to be 36 bytes, that's 4 bytes for the
|
|
35
39
|
// header, and 32 bytes for the digest itself.
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
/**
|
|
42
|
+
* creates a CID from a pre-computed SHA-256 digest
|
|
43
|
+
* @param codec multicodec type for the data
|
|
44
|
+
* @param digest raw SHA-256 hash bytes (must be 32 bytes)
|
|
45
|
+
* @returns CID object
|
|
46
|
+
*/
|
|
47
|
+
export const fromDigest = (codec: 0x55 | 0x71, digest: Uint8Array): Cid => {
|
|
39
48
|
if (digest.length !== 32) {
|
|
40
49
|
throw new RangeError(`invalid digest length`);
|
|
41
50
|
}
|
|
@@ -49,7 +58,7 @@ export const create = async (codec: 0x55 | 0x71, data: Uint8Array): Promise<Cid>
|
|
|
49
58
|
|
|
50
59
|
bytes.set(digest, 4);
|
|
51
60
|
|
|
52
|
-
|
|
61
|
+
return {
|
|
53
62
|
version: CID_VERSION,
|
|
54
63
|
codec: codec,
|
|
55
64
|
digest: {
|
|
@@ -58,31 +67,27 @@ export const create = async (codec: 0x55 | 0x71, data: Uint8Array): Promise<Cid>
|
|
|
58
67
|
},
|
|
59
68
|
bytes: bytes,
|
|
60
69
|
};
|
|
61
|
-
|
|
62
|
-
return cid;
|
|
63
70
|
};
|
|
64
71
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
contents: digest,
|
|
75
|
-
},
|
|
76
|
-
bytes: bytes,
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
return cid;
|
|
72
|
+
/**
|
|
73
|
+
* creates a CID by hashing the provided data with SHA-256
|
|
74
|
+
* @param codec multicodec type for the data
|
|
75
|
+
* @param data raw data to hash
|
|
76
|
+
* @returns CID object
|
|
77
|
+
*/
|
|
78
|
+
export const create = async (codec: 0x55 | 0x71, data: Uint8Array): Promise<Cid> => {
|
|
79
|
+
const digest = await toSha256(data);
|
|
80
|
+
return fromDigest(codec, digest);
|
|
80
81
|
};
|
|
81
82
|
|
|
83
|
+
/**
|
|
84
|
+
* decodes a CID from bytes, returning the CID and any remaining bytes
|
|
85
|
+
* @param bytes raw CID bytes
|
|
86
|
+
* @returns tuple of decoded CID and remainder bytes
|
|
87
|
+
* @throws {RangeError} if the bytes are too short or contain invalid values
|
|
88
|
+
*/
|
|
82
89
|
export const decodeFirst = (bytes: Uint8Array): [decoded: Cid, remainder: Uint8Array] => {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (length < 4) {
|
|
90
|
+
if (bytes.length < 36) {
|
|
86
91
|
throw new RangeError(`cid too short`);
|
|
87
92
|
}
|
|
88
93
|
|
|
@@ -103,27 +108,29 @@ export const decodeFirst = (bytes: Uint8Array): [decoded: Cid, remainder: Uint8A
|
|
|
103
108
|
throw new RangeError(`incorrect cid digest codec (got 0x${digestType.toString(16)})`);
|
|
104
109
|
}
|
|
105
110
|
|
|
106
|
-
if (digestSize !== 32
|
|
111
|
+
if (digestSize !== 32) {
|
|
107
112
|
throw new RangeError(`incorrect cid digest size (got ${digestSize})`);
|
|
108
113
|
}
|
|
109
114
|
|
|
110
|
-
if (length < 4 + digestSize) {
|
|
111
|
-
throw new RangeError(`cid too short`);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
115
|
const cid: Cid = {
|
|
115
116
|
version: CID_VERSION,
|
|
116
117
|
codec: codec,
|
|
117
118
|
digest: {
|
|
118
119
|
codec: digestType,
|
|
119
|
-
contents: bytes.subarray(4,
|
|
120
|
+
contents: bytes.subarray(4, 36),
|
|
120
121
|
},
|
|
121
|
-
bytes: bytes.subarray(0,
|
|
122
|
+
bytes: bytes.subarray(0, 36),
|
|
122
123
|
};
|
|
123
124
|
|
|
124
|
-
return [cid, bytes.subarray(
|
|
125
|
+
return [cid, bytes.subarray(36)];
|
|
125
126
|
};
|
|
126
127
|
|
|
128
|
+
/**
|
|
129
|
+
* decodes a CID from bytes, expecting no remainder
|
|
130
|
+
* @param bytes raw CID bytes
|
|
131
|
+
* @returns decoded CID
|
|
132
|
+
* @throws {RangeError} if the bytes are invalid or contain extra data
|
|
133
|
+
*/
|
|
127
134
|
export const decode = (bytes: Uint8Array): Cid => {
|
|
128
135
|
const [cid, remainder] = decodeFirst(bytes);
|
|
129
136
|
|
|
@@ -134,15 +141,17 @@ export const decode = (bytes: Uint8Array): Cid => {
|
|
|
134
141
|
return cid;
|
|
135
142
|
};
|
|
136
143
|
|
|
144
|
+
/**
|
|
145
|
+
* parses a CID from a multibase base32 string
|
|
146
|
+
* @param input base32-encoded CID string (with 'b' prefix)
|
|
147
|
+
* @returns decoded CID
|
|
148
|
+
* @throws {SyntaxError} if the string is not a valid multibase base32 string
|
|
149
|
+
* @throws {RangeError} if the string length is invalid
|
|
150
|
+
*/
|
|
137
151
|
export const fromString = (input: string): Cid => {
|
|
138
|
-
if (input.length < 2 || input[0] !== 'b') {
|
|
139
|
-
throw new SyntaxError(`not a multibase base32 string`);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// 4 bytes in base32 = 7 characters + 1 character for the prefix
|
|
143
152
|
// 36 bytes in base32 = 58 characters + 1 character for the prefix
|
|
144
|
-
if (input.length !== 59
|
|
145
|
-
throw new
|
|
153
|
+
if (input.length !== 59 || input[0] !== 'b') {
|
|
154
|
+
throw new SyntaxError(`not a valid cid string`);
|
|
146
155
|
}
|
|
147
156
|
|
|
148
157
|
const bytes = fromBase32(input.slice(1));
|
|
@@ -152,6 +161,11 @@ export const fromString = (input: string): Cid => {
|
|
|
152
161
|
return cid;
|
|
153
162
|
};
|
|
154
163
|
|
|
164
|
+
/**
|
|
165
|
+
* encodes a CID to a multibase base32 string
|
|
166
|
+
* @param cid CID to encode
|
|
167
|
+
* @returns base32-encoded string with 'b' prefix
|
|
168
|
+
*/
|
|
155
169
|
export const toString = (cid: Cid): string => {
|
|
156
170
|
let str = CID_STRINGIFY_CACHE.get(cid);
|
|
157
171
|
if (str === undefined) {
|
|
@@ -163,21 +177,27 @@ export const toString = (cid: Cid): string => {
|
|
|
163
177
|
return str;
|
|
164
178
|
};
|
|
165
179
|
|
|
180
|
+
/**
|
|
181
|
+
* parses a CID from binary format (with 0x00 prefix)
|
|
182
|
+
* @param input binary CID bytes with 0x00 prefix
|
|
183
|
+
* @returns decoded CID
|
|
184
|
+
* @throws {RangeError} if the byte length is invalid
|
|
185
|
+
* @throws {SyntaxError} if the prefix byte is not 0x00
|
|
186
|
+
*/
|
|
166
187
|
export const fromBinary = (input: Uint8Array): Cid => {
|
|
167
|
-
// 4 bytes + 1 byte for the 0x00 prefix
|
|
168
188
|
// 36 bytes + 1 byte for the 0x00 prefix
|
|
169
|
-
if (input.length !== 37
|
|
170
|
-
throw new
|
|
189
|
+
if (input.length !== 37 || input[0] !== 0) {
|
|
190
|
+
throw new SyntaxError(`invalid binary cid`);
|
|
171
191
|
}
|
|
172
192
|
|
|
173
|
-
|
|
174
|
-
throw new SyntaxError(`incorrect binary cid`);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const bytes = input.subarray(1);
|
|
178
|
-
return decode(bytes);
|
|
193
|
+
return decode(input.subarray(1));
|
|
179
194
|
};
|
|
180
195
|
|
|
196
|
+
/**
|
|
197
|
+
* encodes a CID to binary format (with 0x00 prefix)
|
|
198
|
+
* @param cid CID to encode
|
|
199
|
+
* @returns binary CID bytes with 0x00 prefix
|
|
200
|
+
*/
|
|
181
201
|
export const toBinary = (cid: Cid): Uint8Array => {
|
|
182
202
|
const bytes = allocUnsafe(1 + cid.bytes.length);
|
|
183
203
|
bytes[0] = 0;
|
|
@@ -186,6 +206,12 @@ export const toBinary = (cid: Cid): Uint8Array => {
|
|
|
186
206
|
return bytes;
|
|
187
207
|
};
|
|
188
208
|
|
|
209
|
+
/**
|
|
210
|
+
* checks if two CIDs are equal
|
|
211
|
+
* @param a first CID
|
|
212
|
+
* @param b second CID
|
|
213
|
+
* @returns true if the CIDs have identical bytes
|
|
214
|
+
*/
|
|
189
215
|
export const equals = (a: Cid, b: Cid): boolean => {
|
|
190
216
|
return isBufferEqual(a.bytes, b.bytes);
|
|
191
217
|
};
|
package/lib/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@atcute/cid",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.4.0",
|
|
5
5
|
"description": "lightweight DASL CID codec library for AT Protocol",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"atproto",
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
"url": "https://github.com/mary-ext/atcute",
|
|
14
14
|
"directory": "packages/utilities/cid"
|
|
15
15
|
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
16
19
|
"files": [
|
|
17
20
|
"dist/",
|
|
18
21
|
"lib/",
|
|
@@ -25,15 +28,16 @@
|
|
|
25
28
|
},
|
|
26
29
|
"sideEffects": false,
|
|
27
30
|
"devDependencies": {
|
|
28
|
-
"@
|
|
31
|
+
"@vitest/coverage-v8": "^4.0.16",
|
|
32
|
+
"vitest": "^4.0.16"
|
|
29
33
|
},
|
|
30
34
|
"dependencies": {
|
|
31
35
|
"@atcute/multibase": "^1.1.6",
|
|
32
|
-
"@atcute/uint8array": "^1.0.
|
|
36
|
+
"@atcute/uint8array": "^1.0.6"
|
|
33
37
|
},
|
|
34
38
|
"scripts": {
|
|
35
|
-
"build": "
|
|
36
|
-
"test": "
|
|
39
|
+
"build": "tsgo --project tsconfig.build.json",
|
|
40
|
+
"test": "vitest",
|
|
37
41
|
"prepublish": "rm -rf dist; pnpm run build"
|
|
38
42
|
}
|
|
39
43
|
}
|