@atcute/cid 2.2.5 → 2.3.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 +1 -1
- package/dist/cid-link.d.ts.map +1 -1
- package/dist/cid-link.js +16 -7
- package/dist/cid-link.js.map +1 -1
- package/dist/codec.d.ts +69 -5
- package/dist/codec.d.ts.map +1 -1
- package/dist/codec.js +78 -12
- package/dist/codec.js.map +1 -1
- package/lib/cid-link.ts +21 -7
- package/lib/codec.ts +81 -16
- 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
CHANGED
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,
|
|
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
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import { toBase32 } from '@atcute/multibase';
|
|
2
|
-
import { decode, fromString } from './codec.js';
|
|
2
|
+
import { CID_STRINGIFY_CACHE, decode, fromString } from './codec.js';
|
|
3
3
|
const CID_LINK_SYMBOL = Symbol.for('@atcute/cid-link-wrapper');
|
|
4
|
+
/** @internal */
|
|
5
|
+
export const CIDLINK_STRINGIFY_CACHE = new WeakMap();
|
|
4
6
|
export class CidLinkWrapper {
|
|
5
7
|
/** @internal */
|
|
6
8
|
[CID_LINK_SYMBOL] = true;
|
|
7
|
-
/** @internal */
|
|
8
|
-
_str;
|
|
9
9
|
bytes;
|
|
10
|
-
constructor(bytes
|
|
10
|
+
constructor(bytes) {
|
|
11
11
|
this.bytes = bytes;
|
|
12
|
-
this._str = str;
|
|
13
12
|
}
|
|
14
13
|
get $link() {
|
|
15
|
-
|
|
14
|
+
let str = CIDLINK_STRINGIFY_CACHE.get(this);
|
|
15
|
+
if (str === undefined) {
|
|
16
|
+
str = `b${toBase32(this.bytes)}`;
|
|
17
|
+
CIDLINK_STRINGIFY_CACHE.set(this, str);
|
|
18
|
+
}
|
|
19
|
+
return str;
|
|
16
20
|
}
|
|
17
21
|
toJSON() {
|
|
18
22
|
return { $link: this.$link };
|
|
@@ -24,7 +28,12 @@ export const isCidLink = (value) => {
|
|
|
24
28
|
(val !== null && typeof val === 'object' && typeof val.$link === 'string'));
|
|
25
29
|
};
|
|
26
30
|
export const toCidLink = (cid) => {
|
|
27
|
-
|
|
31
|
+
const inst = new CidLinkWrapper(cid.bytes);
|
|
32
|
+
const str = CID_STRINGIFY_CACHE.get(cid);
|
|
33
|
+
if (str !== undefined) {
|
|
34
|
+
CIDLINK_STRINGIFY_CACHE.set(inst, str);
|
|
35
|
+
}
|
|
36
|
+
return inst;
|
|
28
37
|
};
|
|
29
38
|
export const fromCidLink = (link) => {
|
|
30
39
|
if (link instanceof CidLinkWrapper) {
|
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,MAAM,EAAE,UAAU,EAAY,MAAM,YAAY,CAAC;
|
|
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,6 +1,10 @@
|
|
|
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
|
|
@@ -22,13 +26,73 @@ export interface Cid {
|
|
|
22
26
|
/** Raw CID bytes */
|
|
23
27
|
readonly bytes: Uint8Array;
|
|
24
28
|
}
|
|
25
|
-
|
|
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
|
+
* creates an empty CID with a zero-length digest
|
|
45
|
+
* @param codec multicodec type for the data
|
|
46
|
+
* @returns CID object with empty digest
|
|
47
|
+
*/
|
|
26
48
|
export declare const createEmpty: (codec: 85 | 113) => Cid;
|
|
27
|
-
|
|
28
|
-
|
|
49
|
+
/**
|
|
50
|
+
* decodes a CID from bytes, returning the CID and any remaining bytes
|
|
51
|
+
* @param bytes raw CID bytes
|
|
52
|
+
* @returns tuple of decoded CID and remainder bytes
|
|
53
|
+
* @throws {RangeError} if the bytes are too short or contain invalid values
|
|
54
|
+
*/
|
|
55
|
+
export declare const decodeFirst: (bytes: Uint8Array<ArrayBufferLike>) => [decoded: Cid, remainder: Uint8Array<ArrayBufferLike>];
|
|
56
|
+
/**
|
|
57
|
+
* decodes a CID from bytes, expecting no remainder
|
|
58
|
+
* @param bytes raw CID bytes
|
|
59
|
+
* @returns decoded CID
|
|
60
|
+
* @throws {RangeError} if the bytes are invalid or contain extra data
|
|
61
|
+
*/
|
|
62
|
+
export declare const decode: (bytes: Uint8Array<ArrayBufferLike>) => Cid;
|
|
63
|
+
/**
|
|
64
|
+
* parses a CID from a multibase base32 string
|
|
65
|
+
* @param input base32-encoded CID string (with 'b' prefix)
|
|
66
|
+
* @returns decoded CID
|
|
67
|
+
* @throws {SyntaxError} if the string is not a valid multibase base32 string
|
|
68
|
+
* @throws {RangeError} if the string length is invalid
|
|
69
|
+
*/
|
|
29
70
|
export declare const fromString: (input: string) => Cid;
|
|
71
|
+
/**
|
|
72
|
+
* encodes a CID to a multibase base32 string
|
|
73
|
+
* @param cid CID to encode
|
|
74
|
+
* @returns base32-encoded string with 'b' prefix
|
|
75
|
+
*/
|
|
30
76
|
export declare const toString: (cid: Cid) => string;
|
|
31
|
-
|
|
32
|
-
|
|
77
|
+
/**
|
|
78
|
+
* parses a CID from binary format (with 0x00 prefix)
|
|
79
|
+
* @param input binary CID bytes with 0x00 prefix
|
|
80
|
+
* @returns decoded CID
|
|
81
|
+
* @throws {RangeError} if the byte length is invalid
|
|
82
|
+
* @throws {SyntaxError} if the prefix byte is not 0x00
|
|
83
|
+
*/
|
|
84
|
+
export declare const fromBinary: (input: Uint8Array<ArrayBufferLike>) => Cid;
|
|
85
|
+
/**
|
|
86
|
+
* encodes a CID to binary format (with 0x00 prefix)
|
|
87
|
+
* @param cid CID to encode
|
|
88
|
+
* @returns binary CID bytes with 0x00 prefix
|
|
89
|
+
*/
|
|
90
|
+
export declare const toBinary: (cid: Cid) => Uint8Array<ArrayBufferLike>;
|
|
91
|
+
/**
|
|
92
|
+
* checks if two CIDs are equal
|
|
93
|
+
* @param a first CID
|
|
94
|
+
* @param b second CID
|
|
95
|
+
* @returns true if the CIDs have identical bytes
|
|
96
|
+
*/
|
|
33
97
|
export declare const equals: (a: Cid, b: Cid) => boolean;
|
|
34
98
|
//# 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;
|
|
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;;;;GAIG;AACH,eAAO,MAAM,WAAW,0BAevB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,gGA2CvB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,MAAM,6CAQlB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,wBAgBtB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,sBASpB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,6CAatB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,2CAMpB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,MAAM,6BAElB,CAAC"}
|
package/dist/codec.js
CHANGED
|
@@ -1,13 +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;
|
|
11
|
+
/** @internal */
|
|
12
|
+
export const CID_STRINGIFY_CACHE = new WeakMap();
|
|
7
13
|
// a SHA-256 CIDv1 is always going to be 36 bytes, that's 4 bytes for the
|
|
8
14
|
// header, and 32 bytes for the digest itself.
|
|
9
|
-
|
|
10
|
-
|
|
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) => {
|
|
11
22
|
if (digest.length !== 32) {
|
|
12
23
|
throw new RangeError(`invalid digest length`);
|
|
13
24
|
}
|
|
@@ -17,7 +28,7 @@ export const create = async (codec, data) => {
|
|
|
17
28
|
bytes[2] = HASH_SHA256;
|
|
18
29
|
bytes[3] = 32;
|
|
19
30
|
bytes.set(digest, 4);
|
|
20
|
-
|
|
31
|
+
return {
|
|
21
32
|
version: CID_VERSION,
|
|
22
33
|
codec: codec,
|
|
23
34
|
digest: {
|
|
@@ -25,10 +36,23 @@ export const create = async (codec, data) => {
|
|
|
25
36
|
contents: bytes.subarray(4, 36),
|
|
26
37
|
},
|
|
27
38
|
bytes: bytes,
|
|
28
|
-
_str: undefined,
|
|
29
39
|
};
|
|
30
|
-
return cid;
|
|
31
40
|
};
|
|
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);
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* creates an empty CID with a zero-length digest
|
|
53
|
+
* @param codec multicodec type for the data
|
|
54
|
+
* @returns CID object with empty digest
|
|
55
|
+
*/
|
|
32
56
|
export const createEmpty = (codec) => {
|
|
33
57
|
const bytes = Uint8Array.from([CID_VERSION, codec, HASH_SHA256, 0]);
|
|
34
58
|
const digest = bytes.subarray(4);
|
|
@@ -40,10 +64,15 @@ export const createEmpty = (codec) => {
|
|
|
40
64
|
contents: digest,
|
|
41
65
|
},
|
|
42
66
|
bytes: bytes,
|
|
43
|
-
_str: undefined,
|
|
44
67
|
};
|
|
45
68
|
return cid;
|
|
46
69
|
};
|
|
70
|
+
/**
|
|
71
|
+
* decodes a CID from bytes, returning the CID and any remaining bytes
|
|
72
|
+
* @param bytes raw CID bytes
|
|
73
|
+
* @returns tuple of decoded CID and remainder bytes
|
|
74
|
+
* @throws {RangeError} if the bytes are too short or contain invalid values
|
|
75
|
+
*/
|
|
47
76
|
export const decodeFirst = (bytes) => {
|
|
48
77
|
const length = bytes.length;
|
|
49
78
|
if (length < 4) {
|
|
@@ -76,10 +105,15 @@ export const decodeFirst = (bytes) => {
|
|
|
76
105
|
contents: bytes.subarray(4, 4 + digestSize),
|
|
77
106
|
},
|
|
78
107
|
bytes: bytes.subarray(0, 4 + digestSize),
|
|
79
|
-
_str: undefined,
|
|
80
108
|
};
|
|
81
109
|
return [cid, bytes.subarray(4 + digestSize)];
|
|
82
110
|
};
|
|
111
|
+
/**
|
|
112
|
+
* decodes a CID from bytes, expecting no remainder
|
|
113
|
+
* @param bytes raw CID bytes
|
|
114
|
+
* @returns decoded CID
|
|
115
|
+
* @throws {RangeError} if the bytes are invalid or contain extra data
|
|
116
|
+
*/
|
|
83
117
|
export const decode = (bytes) => {
|
|
84
118
|
const [cid, remainder] = decodeFirst(bytes);
|
|
85
119
|
if (remainder.length !== 0) {
|
|
@@ -87,6 +121,13 @@ export const decode = (bytes) => {
|
|
|
87
121
|
}
|
|
88
122
|
return cid;
|
|
89
123
|
};
|
|
124
|
+
/**
|
|
125
|
+
* parses a CID from a multibase base32 string
|
|
126
|
+
* @param input base32-encoded CID string (with 'b' prefix)
|
|
127
|
+
* @returns decoded CID
|
|
128
|
+
* @throws {SyntaxError} if the string is not a valid multibase base32 string
|
|
129
|
+
* @throws {RangeError} if the string length is invalid
|
|
130
|
+
*/
|
|
90
131
|
export const fromString = (input) => {
|
|
91
132
|
if (input.length < 2 || input[0] !== 'b') {
|
|
92
133
|
throw new SyntaxError(`not a multibase base32 string`);
|
|
@@ -98,12 +139,29 @@ export const fromString = (input) => {
|
|
|
98
139
|
}
|
|
99
140
|
const bytes = fromBase32(input.slice(1));
|
|
100
141
|
const cid = decode(bytes);
|
|
101
|
-
cid
|
|
142
|
+
CID_STRINGIFY_CACHE.set(cid, input);
|
|
102
143
|
return cid;
|
|
103
144
|
};
|
|
145
|
+
/**
|
|
146
|
+
* encodes a CID to a multibase base32 string
|
|
147
|
+
* @param cid CID to encode
|
|
148
|
+
* @returns base32-encoded string with 'b' prefix
|
|
149
|
+
*/
|
|
104
150
|
export const toString = (cid) => {
|
|
105
|
-
|
|
151
|
+
let str = CID_STRINGIFY_CACHE.get(cid);
|
|
152
|
+
if (str === undefined) {
|
|
153
|
+
str = `b${toBase32(cid.bytes)}`;
|
|
154
|
+
CID_STRINGIFY_CACHE.set(cid, str);
|
|
155
|
+
}
|
|
156
|
+
return str;
|
|
106
157
|
};
|
|
158
|
+
/**
|
|
159
|
+
* parses a CID from binary format (with 0x00 prefix)
|
|
160
|
+
* @param input binary CID bytes with 0x00 prefix
|
|
161
|
+
* @returns decoded CID
|
|
162
|
+
* @throws {RangeError} if the byte length is invalid
|
|
163
|
+
* @throws {SyntaxError} if the prefix byte is not 0x00
|
|
164
|
+
*/
|
|
107
165
|
export const fromBinary = (input) => {
|
|
108
166
|
// 4 bytes + 1 byte for the 0x00 prefix
|
|
109
167
|
// 36 bytes + 1 byte for the 0x00 prefix
|
|
@@ -116,16 +174,24 @@ export const fromBinary = (input) => {
|
|
|
116
174
|
const bytes = input.subarray(1);
|
|
117
175
|
return decode(bytes);
|
|
118
176
|
};
|
|
177
|
+
/**
|
|
178
|
+
* encodes a CID to binary format (with 0x00 prefix)
|
|
179
|
+
* @param cid CID to encode
|
|
180
|
+
* @returns binary CID bytes with 0x00 prefix
|
|
181
|
+
*/
|
|
119
182
|
export const toBinary = (cid) => {
|
|
120
183
|
const bytes = allocUnsafe(1 + cid.bytes.length);
|
|
121
184
|
bytes[0] = 0;
|
|
122
185
|
bytes.set(cid.bytes, 1);
|
|
123
186
|
return bytes;
|
|
124
187
|
};
|
|
188
|
+
/**
|
|
189
|
+
* checks if two CIDs are equal
|
|
190
|
+
* @param a first CID
|
|
191
|
+
* @param b second CID
|
|
192
|
+
* @returns true if the CIDs have identical bytes
|
|
193
|
+
*/
|
|
125
194
|
export const equals = (a, b) => {
|
|
126
|
-
if (a._str !== undefined && b._str !== undefined) {
|
|
127
|
-
return a._str === b._str;
|
|
128
|
-
}
|
|
129
195
|
return isBufferEqual(a.bytes, b.bytes);
|
|
130
196
|
};
|
|
131
197
|
//# sourceMappingURL=codec.js.map
|
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;
|
|
1
|
+
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../lib/codec.ts"],"names":[],"mappings":"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"}
|
package/lib/cid-link.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { toBase32 } from '@atcute/multibase';
|
|
2
2
|
|
|
3
|
-
import { decode, fromString, type Cid } from './codec.js';
|
|
3
|
+
import { CID_STRINGIFY_CACHE, decode, fromString, type Cid } from './codec.js';
|
|
4
4
|
|
|
5
5
|
const CID_LINK_SYMBOL = Symbol.for('@atcute/cid-link-wrapper');
|
|
6
6
|
|
|
7
|
+
/** @internal */
|
|
8
|
+
export const CIDLINK_STRINGIFY_CACHE = new WeakMap<CidLinkWrapper, string>();
|
|
9
|
+
|
|
7
10
|
export interface CidLink {
|
|
8
11
|
$link: string;
|
|
9
12
|
}
|
|
@@ -11,18 +14,22 @@ export interface CidLink {
|
|
|
11
14
|
export class CidLinkWrapper implements CidLink {
|
|
12
15
|
/** @internal */
|
|
13
16
|
readonly [CID_LINK_SYMBOL] = true;
|
|
14
|
-
/** @internal */
|
|
15
|
-
_str: string | undefined;
|
|
16
17
|
|
|
17
18
|
readonly bytes: Uint8Array;
|
|
18
19
|
|
|
19
|
-
constructor(bytes: Uint8Array
|
|
20
|
+
constructor(bytes: Uint8Array) {
|
|
20
21
|
this.bytes = bytes;
|
|
21
|
-
this._str = str;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
get $link(): string {
|
|
25
|
-
|
|
25
|
+
let str = CIDLINK_STRINGIFY_CACHE.get(this);
|
|
26
|
+
if (str === undefined) {
|
|
27
|
+
str = `b${toBase32(this.bytes)}`;
|
|
28
|
+
|
|
29
|
+
CIDLINK_STRINGIFY_CACHE.set(this, str);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return str;
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
toJSON(): CidLink {
|
|
@@ -40,7 +47,14 @@ export const isCidLink = (value: unknown): value is CidLink => {
|
|
|
40
47
|
};
|
|
41
48
|
|
|
42
49
|
export const toCidLink = (cid: Cid): CidLink => {
|
|
43
|
-
|
|
50
|
+
const inst = new CidLinkWrapper(cid.bytes);
|
|
51
|
+
const str = CID_STRINGIFY_CACHE.get(cid);
|
|
52
|
+
|
|
53
|
+
if (str !== undefined) {
|
|
54
|
+
CIDLINK_STRINGIFY_CACHE.set(inst, str);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return inst;
|
|
44
58
|
};
|
|
45
59
|
|
|
46
60
|
export const fromCidLink = (link: CidLink): Cid => {
|
package/lib/codec.ts
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
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
|
|
|
14
|
+
/** @internal */
|
|
15
|
+
export const CID_STRINGIFY_CACHE = new WeakMap<Cid, string>();
|
|
16
|
+
|
|
10
17
|
/**
|
|
11
18
|
* Represents a Content Identifier (CID), in particular, a limited subset of
|
|
12
19
|
* CIDv1 as described by DASL specifications.
|
|
@@ -26,16 +33,18 @@ export interface Cid {
|
|
|
26
33
|
};
|
|
27
34
|
/** Raw CID bytes */
|
|
28
35
|
readonly bytes: Uint8Array;
|
|
29
|
-
|
|
30
|
-
/** @internal */
|
|
31
|
-
_str: string | undefined;
|
|
32
36
|
}
|
|
33
37
|
|
|
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: {
|
|
@@ -57,12 +66,25 @@ export const create = async (codec: 0x55 | 0x71, data: Uint8Array): Promise<Cid>
|
|
|
57
66
|
contents: bytes.subarray(4, 36),
|
|
58
67
|
},
|
|
59
68
|
bytes: bytes,
|
|
60
|
-
_str: undefined,
|
|
61
69
|
};
|
|
70
|
+
};
|
|
62
71
|
|
|
63
|
-
|
|
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);
|
|
64
81
|
};
|
|
65
82
|
|
|
83
|
+
/**
|
|
84
|
+
* creates an empty CID with a zero-length digest
|
|
85
|
+
* @param codec multicodec type for the data
|
|
86
|
+
* @returns CID object with empty digest
|
|
87
|
+
*/
|
|
66
88
|
export const createEmpty = (codec: 0x55 | 0x71): Cid => {
|
|
67
89
|
const bytes = Uint8Array.from([CID_VERSION, codec, HASH_SHA256, 0]);
|
|
68
90
|
const digest = bytes.subarray(4);
|
|
@@ -75,12 +97,17 @@ export const createEmpty = (codec: 0x55 | 0x71): Cid => {
|
|
|
75
97
|
contents: digest,
|
|
76
98
|
},
|
|
77
99
|
bytes: bytes,
|
|
78
|
-
_str: undefined,
|
|
79
100
|
};
|
|
80
101
|
|
|
81
102
|
return cid;
|
|
82
103
|
};
|
|
83
104
|
|
|
105
|
+
/**
|
|
106
|
+
* decodes a CID from bytes, returning the CID and any remaining bytes
|
|
107
|
+
* @param bytes raw CID bytes
|
|
108
|
+
* @returns tuple of decoded CID and remainder bytes
|
|
109
|
+
* @throws {RangeError} if the bytes are too short or contain invalid values
|
|
110
|
+
*/
|
|
84
111
|
export const decodeFirst = (bytes: Uint8Array): [decoded: Cid, remainder: Uint8Array] => {
|
|
85
112
|
const length = bytes.length;
|
|
86
113
|
|
|
@@ -121,12 +148,17 @@ export const decodeFirst = (bytes: Uint8Array): [decoded: Cid, remainder: Uint8A
|
|
|
121
148
|
contents: bytes.subarray(4, 4 + digestSize),
|
|
122
149
|
},
|
|
123
150
|
bytes: bytes.subarray(0, 4 + digestSize),
|
|
124
|
-
_str: undefined,
|
|
125
151
|
};
|
|
126
152
|
|
|
127
153
|
return [cid, bytes.subarray(4 + digestSize)];
|
|
128
154
|
};
|
|
129
155
|
|
|
156
|
+
/**
|
|
157
|
+
* decodes a CID from bytes, expecting no remainder
|
|
158
|
+
* @param bytes raw CID bytes
|
|
159
|
+
* @returns decoded CID
|
|
160
|
+
* @throws {RangeError} if the bytes are invalid or contain extra data
|
|
161
|
+
*/
|
|
130
162
|
export const decode = (bytes: Uint8Array): Cid => {
|
|
131
163
|
const [cid, remainder] = decodeFirst(bytes);
|
|
132
164
|
|
|
@@ -137,6 +169,13 @@ export const decode = (bytes: Uint8Array): Cid => {
|
|
|
137
169
|
return cid;
|
|
138
170
|
};
|
|
139
171
|
|
|
172
|
+
/**
|
|
173
|
+
* parses a CID from a multibase base32 string
|
|
174
|
+
* @param input base32-encoded CID string (with 'b' prefix)
|
|
175
|
+
* @returns decoded CID
|
|
176
|
+
* @throws {SyntaxError} if the string is not a valid multibase base32 string
|
|
177
|
+
* @throws {RangeError} if the string length is invalid
|
|
178
|
+
*/
|
|
140
179
|
export const fromString = (input: string): Cid => {
|
|
141
180
|
if (input.length < 2 || input[0] !== 'b') {
|
|
142
181
|
throw new SyntaxError(`not a multibase base32 string`);
|
|
@@ -151,14 +190,33 @@ export const fromString = (input: string): Cid => {
|
|
|
151
190
|
const bytes = fromBase32(input.slice(1));
|
|
152
191
|
const cid = decode(bytes);
|
|
153
192
|
|
|
154
|
-
cid
|
|
193
|
+
CID_STRINGIFY_CACHE.set(cid, input);
|
|
155
194
|
return cid;
|
|
156
195
|
};
|
|
157
196
|
|
|
197
|
+
/**
|
|
198
|
+
* encodes a CID to a multibase base32 string
|
|
199
|
+
* @param cid CID to encode
|
|
200
|
+
* @returns base32-encoded string with 'b' prefix
|
|
201
|
+
*/
|
|
158
202
|
export const toString = (cid: Cid): string => {
|
|
159
|
-
|
|
203
|
+
let str = CID_STRINGIFY_CACHE.get(cid);
|
|
204
|
+
if (str === undefined) {
|
|
205
|
+
str = `b${toBase32(cid.bytes)}`;
|
|
206
|
+
|
|
207
|
+
CID_STRINGIFY_CACHE.set(cid, str);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return str;
|
|
160
211
|
};
|
|
161
212
|
|
|
213
|
+
/**
|
|
214
|
+
* parses a CID from binary format (with 0x00 prefix)
|
|
215
|
+
* @param input binary CID bytes with 0x00 prefix
|
|
216
|
+
* @returns decoded CID
|
|
217
|
+
* @throws {RangeError} if the byte length is invalid
|
|
218
|
+
* @throws {SyntaxError} if the prefix byte is not 0x00
|
|
219
|
+
*/
|
|
162
220
|
export const fromBinary = (input: Uint8Array): Cid => {
|
|
163
221
|
// 4 bytes + 1 byte for the 0x00 prefix
|
|
164
222
|
// 36 bytes + 1 byte for the 0x00 prefix
|
|
@@ -174,6 +232,11 @@ export const fromBinary = (input: Uint8Array): Cid => {
|
|
|
174
232
|
return decode(bytes);
|
|
175
233
|
};
|
|
176
234
|
|
|
235
|
+
/**
|
|
236
|
+
* encodes a CID to binary format (with 0x00 prefix)
|
|
237
|
+
* @param cid CID to encode
|
|
238
|
+
* @returns binary CID bytes with 0x00 prefix
|
|
239
|
+
*/
|
|
177
240
|
export const toBinary = (cid: Cid): Uint8Array => {
|
|
178
241
|
const bytes = allocUnsafe(1 + cid.bytes.length);
|
|
179
242
|
bytes[0] = 0;
|
|
@@ -182,10 +245,12 @@ export const toBinary = (cid: Cid): Uint8Array => {
|
|
|
182
245
|
return bytes;
|
|
183
246
|
};
|
|
184
247
|
|
|
248
|
+
/**
|
|
249
|
+
* checks if two CIDs are equal
|
|
250
|
+
* @param a first CID
|
|
251
|
+
* @param b second CID
|
|
252
|
+
* @returns true if the CIDs have identical bytes
|
|
253
|
+
*/
|
|
185
254
|
export const equals = (a: Cid, b: Cid): boolean => {
|
|
186
|
-
if (a._str !== undefined && b._str !== undefined) {
|
|
187
|
-
return a._str === b._str;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
255
|
return isBufferEqual(a.bytes, b.bytes);
|
|
191
256
|
};
|
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.3.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
|
}
|