- Add GETTING_STARTED.md with quick start guide and development modes - Add INSTALL.sh automated installation script - Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md - Add QUICK_REFERENCE.md for common commands - Add SETUP_GUIDE.md with detailed setup instructions - Update README.md with improved project overview - Add did-wallet app dependencies and node_modules
2433 lines
76 KiB
JavaScript
2433 lines
76 KiB
JavaScript
"use strict";
|
|
var __create = Object.create;
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __getProtoOf = Object.getPrototypeOf;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __export = (target, all) => {
|
|
for (var name in all)
|
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
};
|
|
var __copyProps = (to, from2, except, desc) => {
|
|
if (from2 && typeof from2 === "object" || typeof from2 === "function") {
|
|
for (let key of __getOwnPropNames(from2))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from2[key], enumerable: !(desc = __getOwnPropDesc(from2, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
// If the importer is in node compatibility mode or this is not an ESM
|
|
// file that has been converted to a CommonJS file using a Babel-
|
|
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
mod
|
|
));
|
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
|
|
// src/index.ts
|
|
var src_exports = {};
|
|
__export(src_exports, {
|
|
Convert: () => Convert,
|
|
LevelStore: () => LevelStore,
|
|
MemoryStore: () => MemoryStore,
|
|
Multicodec: () => Multicodec,
|
|
NodeStream: () => NodeStream,
|
|
Readable: () => import_readable_stream2.Readable,
|
|
Stream: () => Stream,
|
|
TtlCache: () => import_ttlcache.default,
|
|
isArrayBufferSlice: () => isArrayBufferSlice,
|
|
isAsyncIterable: () => isAsyncIterable,
|
|
isDefined: () => isDefined,
|
|
isEmptyObject: () => isEmptyObject,
|
|
removeEmptyObjects: () => removeEmptyObjects,
|
|
removeUndefinedProperties: () => removeUndefinedProperties,
|
|
universalTypeOf: () => universalTypeOf
|
|
});
|
|
module.exports = __toCommonJS(src_exports);
|
|
|
|
// src/cache.ts
|
|
var import_ttlcache = __toESM(require("@isaacs/ttlcache"), 1);
|
|
|
|
// ../../node_modules/.pnpm/multiformats@11.0.2/node_modules/multiformats/vendor/base-x.js
|
|
function base(ALPHABET, name) {
|
|
if (ALPHABET.length >= 255) {
|
|
throw new TypeError("Alphabet too long");
|
|
}
|
|
var BASE_MAP = new Uint8Array(256);
|
|
for (var j = 0; j < BASE_MAP.length; j++) {
|
|
BASE_MAP[j] = 255;
|
|
}
|
|
for (var i = 0; i < ALPHABET.length; i++) {
|
|
var x = ALPHABET.charAt(i);
|
|
var xc = x.charCodeAt(0);
|
|
if (BASE_MAP[xc] !== 255) {
|
|
throw new TypeError(x + " is ambiguous");
|
|
}
|
|
BASE_MAP[xc] = i;
|
|
}
|
|
var BASE = ALPHABET.length;
|
|
var LEADER = ALPHABET.charAt(0);
|
|
var FACTOR = Math.log(BASE) / Math.log(256);
|
|
var iFACTOR = Math.log(256) / Math.log(BASE);
|
|
function encode3(source) {
|
|
if (source instanceof Uint8Array)
|
|
;
|
|
else if (ArrayBuffer.isView(source)) {
|
|
source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
|
|
} else if (Array.isArray(source)) {
|
|
source = Uint8Array.from(source);
|
|
}
|
|
if (!(source instanceof Uint8Array)) {
|
|
throw new TypeError("Expected Uint8Array");
|
|
}
|
|
if (source.length === 0) {
|
|
return "";
|
|
}
|
|
var zeroes = 0;
|
|
var length2 = 0;
|
|
var pbegin = 0;
|
|
var pend = source.length;
|
|
while (pbegin !== pend && source[pbegin] === 0) {
|
|
pbegin++;
|
|
zeroes++;
|
|
}
|
|
var size = (pend - pbegin) * iFACTOR + 1 >>> 0;
|
|
var b58 = new Uint8Array(size);
|
|
while (pbegin !== pend) {
|
|
var carry = source[pbegin];
|
|
var i2 = 0;
|
|
for (var it1 = size - 1; (carry !== 0 || i2 < length2) && it1 !== -1; it1--, i2++) {
|
|
carry += 256 * b58[it1] >>> 0;
|
|
b58[it1] = carry % BASE >>> 0;
|
|
carry = carry / BASE >>> 0;
|
|
}
|
|
if (carry !== 0) {
|
|
throw new Error("Non-zero carry");
|
|
}
|
|
length2 = i2;
|
|
pbegin++;
|
|
}
|
|
var it2 = size - length2;
|
|
while (it2 !== size && b58[it2] === 0) {
|
|
it2++;
|
|
}
|
|
var str = LEADER.repeat(zeroes);
|
|
for (; it2 < size; ++it2) {
|
|
str += ALPHABET.charAt(b58[it2]);
|
|
}
|
|
return str;
|
|
}
|
|
function decodeUnsafe(source) {
|
|
if (typeof source !== "string") {
|
|
throw new TypeError("Expected String");
|
|
}
|
|
if (source.length === 0) {
|
|
return new Uint8Array();
|
|
}
|
|
var psz = 0;
|
|
if (source[psz] === " ") {
|
|
return;
|
|
}
|
|
var zeroes = 0;
|
|
var length2 = 0;
|
|
while (source[psz] === LEADER) {
|
|
zeroes++;
|
|
psz++;
|
|
}
|
|
var size = (source.length - psz) * FACTOR + 1 >>> 0;
|
|
var b256 = new Uint8Array(size);
|
|
while (source[psz]) {
|
|
var carry = BASE_MAP[source.charCodeAt(psz)];
|
|
if (carry === 255) {
|
|
return;
|
|
}
|
|
var i2 = 0;
|
|
for (var it3 = size - 1; (carry !== 0 || i2 < length2) && it3 !== -1; it3--, i2++) {
|
|
carry += BASE * b256[it3] >>> 0;
|
|
b256[it3] = carry % 256 >>> 0;
|
|
carry = carry / 256 >>> 0;
|
|
}
|
|
if (carry !== 0) {
|
|
throw new Error("Non-zero carry");
|
|
}
|
|
length2 = i2;
|
|
psz++;
|
|
}
|
|
if (source[psz] === " ") {
|
|
return;
|
|
}
|
|
var it4 = size - length2;
|
|
while (it4 !== size && b256[it4] === 0) {
|
|
it4++;
|
|
}
|
|
var vch = new Uint8Array(zeroes + (size - it4));
|
|
var j2 = zeroes;
|
|
while (it4 !== size) {
|
|
vch[j2++] = b256[it4++];
|
|
}
|
|
return vch;
|
|
}
|
|
function decode5(string) {
|
|
var buffer = decodeUnsafe(string);
|
|
if (buffer) {
|
|
return buffer;
|
|
}
|
|
throw new Error(`Non-${name} character`);
|
|
}
|
|
return {
|
|
encode: encode3,
|
|
decodeUnsafe,
|
|
decode: decode5
|
|
};
|
|
}
|
|
var src = base;
|
|
var _brrp__multiformats_scope_baseX = src;
|
|
var base_x_default = _brrp__multiformats_scope_baseX;
|
|
|
|
// ../../node_modules/.pnpm/multiformats@11.0.2/node_modules/multiformats/src/bytes.js
|
|
var empty = new Uint8Array(0);
|
|
var equals = (aa, bb) => {
|
|
if (aa === bb)
|
|
return true;
|
|
if (aa.byteLength !== bb.byteLength) {
|
|
return false;
|
|
}
|
|
for (let ii = 0; ii < aa.byteLength; ii++) {
|
|
if (aa[ii] !== bb[ii]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
var coerce = (o) => {
|
|
if (o instanceof Uint8Array && o.constructor.name === "Uint8Array")
|
|
return o;
|
|
if (o instanceof ArrayBuffer)
|
|
return new Uint8Array(o);
|
|
if (ArrayBuffer.isView(o)) {
|
|
return new Uint8Array(o.buffer, o.byteOffset, o.byteLength);
|
|
}
|
|
throw new Error("Unknown type, must be binary type");
|
|
};
|
|
|
|
// ../../node_modules/.pnpm/multiformats@11.0.2/node_modules/multiformats/src/bases/base.js
|
|
var Encoder = class {
|
|
/**
|
|
* @param {Base} name
|
|
* @param {Prefix} prefix
|
|
* @param {(bytes:Uint8Array) => string} baseEncode
|
|
*/
|
|
constructor(name, prefix, baseEncode) {
|
|
this.name = name;
|
|
this.prefix = prefix;
|
|
this.baseEncode = baseEncode;
|
|
}
|
|
/**
|
|
* @param {Uint8Array} bytes
|
|
* @returns {API.Multibase<Prefix>}
|
|
*/
|
|
encode(bytes) {
|
|
if (bytes instanceof Uint8Array) {
|
|
return `${this.prefix}${this.baseEncode(bytes)}`;
|
|
} else {
|
|
throw Error("Unknown type, must be binary type");
|
|
}
|
|
}
|
|
};
|
|
var Decoder = class {
|
|
/**
|
|
* @param {Base} name
|
|
* @param {Prefix} prefix
|
|
* @param {(text:string) => Uint8Array} baseDecode
|
|
*/
|
|
constructor(name, prefix, baseDecode) {
|
|
this.name = name;
|
|
this.prefix = prefix;
|
|
if (prefix.codePointAt(0) === void 0) {
|
|
throw new Error("Invalid prefix character");
|
|
}
|
|
this.prefixCodePoint = /** @type {number} */
|
|
prefix.codePointAt(0);
|
|
this.baseDecode = baseDecode;
|
|
}
|
|
/**
|
|
* @param {string} text
|
|
*/
|
|
decode(text) {
|
|
if (typeof text === "string") {
|
|
if (text.codePointAt(0) !== this.prefixCodePoint) {
|
|
throw Error(`Unable to decode multibase string ${JSON.stringify(text)}, ${this.name} decoder only supports inputs prefixed with ${this.prefix}`);
|
|
}
|
|
return this.baseDecode(text.slice(this.prefix.length));
|
|
} else {
|
|
throw Error("Can only multibase decode strings");
|
|
}
|
|
}
|
|
/**
|
|
* @template {string} OtherPrefix
|
|
* @param {API.UnibaseDecoder<OtherPrefix>|ComposedDecoder<OtherPrefix>} decoder
|
|
* @returns {ComposedDecoder<Prefix|OtherPrefix>}
|
|
*/
|
|
or(decoder) {
|
|
return or(this, decoder);
|
|
}
|
|
};
|
|
var ComposedDecoder = class {
|
|
/**
|
|
* @param {Decoders<Prefix>} decoders
|
|
*/
|
|
constructor(decoders) {
|
|
this.decoders = decoders;
|
|
}
|
|
/**
|
|
* @template {string} OtherPrefix
|
|
* @param {API.UnibaseDecoder<OtherPrefix>|ComposedDecoder<OtherPrefix>} decoder
|
|
* @returns {ComposedDecoder<Prefix|OtherPrefix>}
|
|
*/
|
|
or(decoder) {
|
|
return or(this, decoder);
|
|
}
|
|
/**
|
|
* @param {string} input
|
|
* @returns {Uint8Array}
|
|
*/
|
|
decode(input) {
|
|
const prefix = (
|
|
/** @type {Prefix} */
|
|
input[0]
|
|
);
|
|
const decoder = this.decoders[prefix];
|
|
if (decoder) {
|
|
return decoder.decode(input);
|
|
} else {
|
|
throw RangeError(`Unable to decode multibase string ${JSON.stringify(input)}, only inputs prefixed with ${Object.keys(this.decoders)} are supported`);
|
|
}
|
|
}
|
|
};
|
|
var or = (left, right) => new ComposedDecoder(
|
|
/** @type {Decoders<L|R>} */
|
|
{
|
|
...left.decoders || { [
|
|
/** @type API.UnibaseDecoder<L> */
|
|
left.prefix
|
|
]: left },
|
|
...right.decoders || { [
|
|
/** @type API.UnibaseDecoder<R> */
|
|
right.prefix
|
|
]: right }
|
|
}
|
|
);
|
|
var Codec = class {
|
|
/**
|
|
* @param {Base} name
|
|
* @param {Prefix} prefix
|
|
* @param {(bytes:Uint8Array) => string} baseEncode
|
|
* @param {(text:string) => Uint8Array} baseDecode
|
|
*/
|
|
constructor(name, prefix, baseEncode, baseDecode) {
|
|
this.name = name;
|
|
this.prefix = prefix;
|
|
this.baseEncode = baseEncode;
|
|
this.baseDecode = baseDecode;
|
|
this.encoder = new Encoder(name, prefix, baseEncode);
|
|
this.decoder = new Decoder(name, prefix, baseDecode);
|
|
}
|
|
/**
|
|
* @param {Uint8Array} input
|
|
*/
|
|
encode(input) {
|
|
return this.encoder.encode(input);
|
|
}
|
|
/**
|
|
* @param {string} input
|
|
*/
|
|
decode(input) {
|
|
return this.decoder.decode(input);
|
|
}
|
|
};
|
|
var from = ({ name, prefix, encode: encode3, decode: decode5 }) => new Codec(name, prefix, encode3, decode5);
|
|
var baseX = ({ prefix, name, alphabet }) => {
|
|
const { encode: encode3, decode: decode5 } = base_x_default(alphabet, name);
|
|
return from({
|
|
prefix,
|
|
name,
|
|
encode: encode3,
|
|
/**
|
|
* @param {string} text
|
|
*/
|
|
decode: (text) => coerce(decode5(text))
|
|
});
|
|
};
|
|
var decode = (string, alphabet, bitsPerChar, name) => {
|
|
const codes = {};
|
|
for (let i = 0; i < alphabet.length; ++i) {
|
|
codes[alphabet[i]] = i;
|
|
}
|
|
let end = string.length;
|
|
while (string[end - 1] === "=") {
|
|
--end;
|
|
}
|
|
const out = new Uint8Array(end * bitsPerChar / 8 | 0);
|
|
let bits = 0;
|
|
let buffer = 0;
|
|
let written = 0;
|
|
for (let i = 0; i < end; ++i) {
|
|
const value = codes[string[i]];
|
|
if (value === void 0) {
|
|
throw new SyntaxError(`Non-${name} character`);
|
|
}
|
|
buffer = buffer << bitsPerChar | value;
|
|
bits += bitsPerChar;
|
|
if (bits >= 8) {
|
|
bits -= 8;
|
|
out[written++] = 255 & buffer >> bits;
|
|
}
|
|
}
|
|
if (bits >= bitsPerChar || 255 & buffer << 8 - bits) {
|
|
throw new SyntaxError("Unexpected end of data");
|
|
}
|
|
return out;
|
|
};
|
|
var encode = (data, alphabet, bitsPerChar) => {
|
|
const pad = alphabet[alphabet.length - 1] === "=";
|
|
const mask = (1 << bitsPerChar) - 1;
|
|
let out = "";
|
|
let bits = 0;
|
|
let buffer = 0;
|
|
for (let i = 0; i < data.length; ++i) {
|
|
buffer = buffer << 8 | data[i];
|
|
bits += 8;
|
|
while (bits > bitsPerChar) {
|
|
bits -= bitsPerChar;
|
|
out += alphabet[mask & buffer >> bits];
|
|
}
|
|
}
|
|
if (bits) {
|
|
out += alphabet[mask & buffer << bitsPerChar - bits];
|
|
}
|
|
if (pad) {
|
|
while (out.length * bitsPerChar & 7) {
|
|
out += "=";
|
|
}
|
|
}
|
|
return out;
|
|
};
|
|
var rfc4648 = ({ name, prefix, bitsPerChar, alphabet }) => {
|
|
return from({
|
|
prefix,
|
|
name,
|
|
encode(input) {
|
|
return encode(input, alphabet, bitsPerChar);
|
|
},
|
|
decode(input) {
|
|
return decode(input, alphabet, bitsPerChar, name);
|
|
}
|
|
});
|
|
};
|
|
|
|
// ../../node_modules/.pnpm/multiformats@11.0.2/node_modules/multiformats/src/bases/base32.js
|
|
var base32 = rfc4648({
|
|
prefix: "b",
|
|
name: "base32",
|
|
alphabet: "abcdefghijklmnopqrstuvwxyz234567",
|
|
bitsPerChar: 5
|
|
});
|
|
var base32upper = rfc4648({
|
|
prefix: "B",
|
|
name: "base32upper",
|
|
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
|
|
bitsPerChar: 5
|
|
});
|
|
var base32pad = rfc4648({
|
|
prefix: "c",
|
|
name: "base32pad",
|
|
alphabet: "abcdefghijklmnopqrstuvwxyz234567=",
|
|
bitsPerChar: 5
|
|
});
|
|
var base32padupper = rfc4648({
|
|
prefix: "C",
|
|
name: "base32padupper",
|
|
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
|
|
bitsPerChar: 5
|
|
});
|
|
var base32hex = rfc4648({
|
|
prefix: "v",
|
|
name: "base32hex",
|
|
alphabet: "0123456789abcdefghijklmnopqrstuv",
|
|
bitsPerChar: 5
|
|
});
|
|
var base32hexupper = rfc4648({
|
|
prefix: "V",
|
|
name: "base32hexupper",
|
|
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV",
|
|
bitsPerChar: 5
|
|
});
|
|
var base32hexpad = rfc4648({
|
|
prefix: "t",
|
|
name: "base32hexpad",
|
|
alphabet: "0123456789abcdefghijklmnopqrstuv=",
|
|
bitsPerChar: 5
|
|
});
|
|
var base32hexpadupper = rfc4648({
|
|
prefix: "T",
|
|
name: "base32hexpadupper",
|
|
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUV=",
|
|
bitsPerChar: 5
|
|
});
|
|
var base32z = rfc4648({
|
|
prefix: "h",
|
|
name: "base32z",
|
|
alphabet: "ybndrfg8ejkmcpqxot1uwisza345h769",
|
|
bitsPerChar: 5
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/multiformats@11.0.2/node_modules/multiformats/src/bases/base58.js
|
|
var base58btc = baseX({
|
|
name: "base58btc",
|
|
prefix: "z",
|
|
alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
|
});
|
|
var base58flickr = baseX({
|
|
name: "base58flickr",
|
|
prefix: "Z",
|
|
alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/multiformats@11.0.2/node_modules/multiformats/src/bases/base64.js
|
|
var base64 = rfc4648({
|
|
prefix: "m",
|
|
name: "base64",
|
|
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
|
bitsPerChar: 6
|
|
});
|
|
var base64pad = rfc4648({
|
|
prefix: "M",
|
|
name: "base64pad",
|
|
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
|
|
bitsPerChar: 6
|
|
});
|
|
var base64url = rfc4648({
|
|
prefix: "u",
|
|
name: "base64url",
|
|
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
|
|
bitsPerChar: 6
|
|
});
|
|
var base64urlpad = rfc4648({
|
|
prefix: "U",
|
|
name: "base64urlpad",
|
|
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",
|
|
bitsPerChar: 6
|
|
});
|
|
|
|
// src/type-utils.ts
|
|
function isArrayBufferSlice(arrayBufferView) {
|
|
return arrayBufferView.byteOffset !== 0 || arrayBufferView.byteLength !== arrayBufferView.buffer.byteLength;
|
|
}
|
|
function isAsyncIterable(obj) {
|
|
if (typeof obj !== "object" || obj === null) {
|
|
return false;
|
|
}
|
|
return typeof obj[Symbol.asyncIterator] === "function";
|
|
}
|
|
function isDefined(arg) {
|
|
return arg !== null && typeof arg !== "undefined";
|
|
}
|
|
function universalTypeOf(value) {
|
|
const typeString = Object.prototype.toString.call(value);
|
|
const match = typeString.match(/\s([a-zA-Z0-9]+)/);
|
|
const [_, type] = match;
|
|
return type;
|
|
}
|
|
|
|
// src/convert.ts
|
|
var textEncoder = new TextEncoder();
|
|
var textDecoder = new TextDecoder();
|
|
var Convert = class _Convert {
|
|
constructor(data, format2) {
|
|
this.data = data;
|
|
this.format = format2;
|
|
}
|
|
static arrayBuffer(data) {
|
|
return new _Convert(data, "ArrayBuffer");
|
|
}
|
|
static asyncIterable(data) {
|
|
if (!isAsyncIterable(data)) {
|
|
throw new TypeError("Input must be of type AsyncIterable.");
|
|
}
|
|
return new _Convert(data, "AsyncIterable");
|
|
}
|
|
static base32Z(data) {
|
|
return new _Convert(data, "Base32Z");
|
|
}
|
|
static base58Btc(data) {
|
|
return new _Convert(data, "Base58Btc");
|
|
}
|
|
static base64Url(data) {
|
|
return new _Convert(data, "Base64Url");
|
|
}
|
|
/**
|
|
* Reference:
|
|
* The BufferSource type is a TypeScript type that represents an ArrayBuffer
|
|
* or one of the ArrayBufferView types, such a TypedArray (e.g., Uint8Array)
|
|
* or a DataView.
|
|
*/
|
|
static bufferSource(data) {
|
|
return new _Convert(data, "BufferSource");
|
|
}
|
|
static hex(data) {
|
|
if (typeof data !== "string") {
|
|
throw new TypeError("Hex input must be a string.");
|
|
}
|
|
if (data.length % 2 !== 0) {
|
|
throw new TypeError("Hex input must have an even number of characters.");
|
|
}
|
|
return new _Convert(data, "Hex");
|
|
}
|
|
static multibase(data) {
|
|
return new _Convert(data, "Multibase");
|
|
}
|
|
static object(data) {
|
|
return new _Convert(data, "Object");
|
|
}
|
|
static string(data) {
|
|
return new _Convert(data, "String");
|
|
}
|
|
static uint8Array(data) {
|
|
return new _Convert(data, "Uint8Array");
|
|
}
|
|
toArrayBuffer() {
|
|
switch (this.format) {
|
|
case "Base58Btc": {
|
|
return base58btc.baseDecode(this.data).buffer;
|
|
}
|
|
case "Base64Url": {
|
|
return base64url.baseDecode(this.data).buffer;
|
|
}
|
|
case "BufferSource": {
|
|
const dataType = universalTypeOf(this.data);
|
|
if (dataType === "ArrayBuffer") {
|
|
return this.data;
|
|
} else if (ArrayBuffer.isView(this.data)) {
|
|
if (isArrayBufferSlice(this.data)) {
|
|
return this.data.buffer.slice(this.data.byteOffset, this.data.byteOffset + this.data.byteLength);
|
|
} else {
|
|
return this.data.buffer;
|
|
}
|
|
} else {
|
|
throw new TypeError(`${this.format} value is not of type: ArrayBuffer, DataView, or TypedArray.`);
|
|
}
|
|
}
|
|
case "Hex": {
|
|
return this.toUint8Array().buffer;
|
|
}
|
|
case "String": {
|
|
return this.toUint8Array().buffer;
|
|
}
|
|
case "Uint8Array": {
|
|
return this.data.buffer;
|
|
}
|
|
default:
|
|
throw new TypeError(`Conversion from ${this.format} to ArrayBuffer is not supported.`);
|
|
}
|
|
}
|
|
async toArrayBufferAsync() {
|
|
switch (this.format) {
|
|
case "AsyncIterable": {
|
|
const blob = await this.toBlobAsync();
|
|
return await blob.arrayBuffer();
|
|
}
|
|
default:
|
|
throw new TypeError(`Asynchronous conversion from ${this.format} to ArrayBuffer is not supported.`);
|
|
}
|
|
}
|
|
toBase32Z() {
|
|
switch (this.format) {
|
|
case "Uint8Array": {
|
|
return base32z.baseEncode(this.data);
|
|
}
|
|
default:
|
|
throw new TypeError(`Conversion from ${this.format} to Base64Z is not supported.`);
|
|
}
|
|
}
|
|
toBase58Btc() {
|
|
switch (this.format) {
|
|
case "ArrayBuffer": {
|
|
const u8a = new Uint8Array(this.data);
|
|
return base58btc.baseEncode(u8a);
|
|
}
|
|
case "Multibase": {
|
|
return this.data.substring(1);
|
|
}
|
|
case "Uint8Array": {
|
|
return base58btc.baseEncode(this.data);
|
|
}
|
|
default:
|
|
throw new TypeError(`Conversion from ${this.format} to Base58Btc is not supported.`);
|
|
}
|
|
}
|
|
toBase64Url() {
|
|
switch (this.format) {
|
|
case "ArrayBuffer": {
|
|
const u8a = new Uint8Array(this.data);
|
|
return base64url.baseEncode(u8a);
|
|
}
|
|
case "BufferSource": {
|
|
const u8a = this.toUint8Array();
|
|
return base64url.baseEncode(u8a);
|
|
}
|
|
case "Object": {
|
|
const string = JSON.stringify(this.data);
|
|
const u8a = textEncoder.encode(string);
|
|
return base64url.baseEncode(u8a);
|
|
}
|
|
case "String": {
|
|
const u8a = textEncoder.encode(this.data);
|
|
return base64url.baseEncode(u8a);
|
|
}
|
|
case "Uint8Array": {
|
|
return base64url.baseEncode(this.data);
|
|
}
|
|
default:
|
|
throw new TypeError(`Conversion from ${this.format} to Base64Url is not supported.`);
|
|
}
|
|
}
|
|
async toBlobAsync() {
|
|
switch (this.format) {
|
|
case "AsyncIterable": {
|
|
const chunks = [];
|
|
for await (const chunk of this.data) {
|
|
chunks.push(chunk);
|
|
}
|
|
const blob = new Blob(chunks);
|
|
return blob;
|
|
}
|
|
default:
|
|
throw new TypeError(`Asynchronous conversion from ${this.format} to Blob is not supported.`);
|
|
}
|
|
}
|
|
toHex() {
|
|
const hexes = Array.from({ length: 256 }, (v, i) => i.toString(16).padStart(2, "0"));
|
|
switch (this.format) {
|
|
case "ArrayBuffer": {
|
|
const u8a = this.toUint8Array();
|
|
return _Convert.uint8Array(u8a).toHex();
|
|
}
|
|
case "Base64Url": {
|
|
const u8a = this.toUint8Array();
|
|
return _Convert.uint8Array(u8a).toHex();
|
|
}
|
|
case "Uint8Array": {
|
|
let hex = "";
|
|
for (let i = 0; i < this.data.length; i++) {
|
|
hex += hexes[this.data[i]];
|
|
}
|
|
return hex;
|
|
}
|
|
default:
|
|
throw new TypeError(`Conversion from ${this.format} to Hex is not supported.`);
|
|
}
|
|
}
|
|
toMultibase() {
|
|
switch (this.format) {
|
|
case "Base58Btc": {
|
|
return `z${this.data}`;
|
|
}
|
|
default:
|
|
throw new TypeError(`Conversion from ${this.format} to Multibase is not supported.`);
|
|
}
|
|
}
|
|
toObject() {
|
|
switch (this.format) {
|
|
case "Base64Url": {
|
|
const u8a = base64url.baseDecode(this.data);
|
|
const text = textDecoder.decode(u8a);
|
|
return JSON.parse(text);
|
|
}
|
|
case "String": {
|
|
return JSON.parse(this.data);
|
|
}
|
|
case "Uint8Array": {
|
|
const text = textDecoder.decode(this.data);
|
|
return JSON.parse(text);
|
|
}
|
|
default:
|
|
throw new TypeError(`Conversion from ${this.format} to Object is not supported.`);
|
|
}
|
|
}
|
|
async toObjectAsync() {
|
|
switch (this.format) {
|
|
case "AsyncIterable": {
|
|
const text = await this.toStringAsync();
|
|
const json = JSON.parse(text);
|
|
return json;
|
|
}
|
|
default:
|
|
throw new TypeError(`Asynchronous conversion from ${this.format} to Object is not supported.`);
|
|
}
|
|
}
|
|
toString() {
|
|
switch (this.format) {
|
|
case "ArrayBuffer": {
|
|
return textDecoder.decode(this.data);
|
|
}
|
|
case "Base64Url": {
|
|
const u8a = base64url.baseDecode(this.data);
|
|
return textDecoder.decode(u8a);
|
|
}
|
|
case "Object": {
|
|
return JSON.stringify(this.data);
|
|
}
|
|
case "Uint8Array": {
|
|
return textDecoder.decode(this.data);
|
|
}
|
|
default:
|
|
throw new TypeError(`Conversion from ${this.format} to String is not supported.`);
|
|
}
|
|
}
|
|
async toStringAsync() {
|
|
switch (this.format) {
|
|
case "AsyncIterable": {
|
|
let str = "";
|
|
for await (const chunk of this.data) {
|
|
if (typeof chunk === "string")
|
|
str += chunk;
|
|
else
|
|
str += textDecoder.decode(chunk, { stream: true });
|
|
}
|
|
str += textDecoder.decode(void 0, { stream: false });
|
|
return str;
|
|
}
|
|
default:
|
|
throw new TypeError(`Asynchronous conversion from ${this.format} to String is not supported.`);
|
|
}
|
|
}
|
|
toUint8Array() {
|
|
switch (this.format) {
|
|
case "ArrayBuffer": {
|
|
return new Uint8Array(this.data);
|
|
}
|
|
case "Base32Z": {
|
|
return base32z.baseDecode(this.data);
|
|
}
|
|
case "Base58Btc": {
|
|
return base58btc.baseDecode(this.data);
|
|
}
|
|
case "Base64Url": {
|
|
return base64url.baseDecode(this.data);
|
|
}
|
|
case "BufferSource": {
|
|
const dataType = universalTypeOf(this.data);
|
|
if (dataType === "Uint8Array") {
|
|
return this.data;
|
|
} else if (dataType === "ArrayBuffer") {
|
|
return new Uint8Array(this.data);
|
|
} else if (ArrayBuffer.isView(this.data)) {
|
|
return new Uint8Array(this.data.buffer, this.data.byteOffset, this.data.byteLength);
|
|
} else {
|
|
throw new TypeError(`${this.format} value is not of type: ArrayBuffer, DataView, or TypedArray.`);
|
|
}
|
|
}
|
|
case "Hex": {
|
|
const u8a = new Uint8Array(this.data.length / 2);
|
|
for (let i = 0; i < this.data.length; i += 2) {
|
|
const byteValue = parseInt(this.data.substring(i, i + 2), 16);
|
|
if (isNaN(byteValue)) {
|
|
throw new TypeError("Input is not a valid hexadecimal string.");
|
|
}
|
|
u8a[i / 2] = byteValue;
|
|
}
|
|
return u8a;
|
|
}
|
|
case "Object": {
|
|
const string = JSON.stringify(this.data);
|
|
return textEncoder.encode(string);
|
|
}
|
|
case "String": {
|
|
return textEncoder.encode(this.data);
|
|
}
|
|
default:
|
|
throw new TypeError(`Conversion from ${this.format} to Uint8Array is not supported.`);
|
|
}
|
|
}
|
|
async toUint8ArrayAsync() {
|
|
switch (this.format) {
|
|
case "AsyncIterable": {
|
|
const arrayBuffer = await this.toArrayBufferAsync();
|
|
return new Uint8Array(arrayBuffer);
|
|
}
|
|
default:
|
|
throw new TypeError(`Asynchronous conversion from ${this.format} to Uint8Array is not supported.`);
|
|
}
|
|
}
|
|
};
|
|
|
|
// ../../node_modules/.pnpm/multiformats@11.0.2/node_modules/multiformats/src/varint.js
|
|
var varint_exports = {};
|
|
__export(varint_exports, {
|
|
decode: () => decode3,
|
|
encodeTo: () => encodeTo,
|
|
encodingLength: () => encodingLength
|
|
});
|
|
|
|
// ../../node_modules/.pnpm/multiformats@11.0.2/node_modules/multiformats/vendor/varint.js
|
|
var encode_1 = encode2;
|
|
var MSB = 128;
|
|
var REST = 127;
|
|
var MSBALL = ~REST;
|
|
var INT = Math.pow(2, 31);
|
|
function encode2(num, out, offset) {
|
|
out = out || [];
|
|
offset = offset || 0;
|
|
var oldOffset = offset;
|
|
while (num >= INT) {
|
|
out[offset++] = num & 255 | MSB;
|
|
num /= 128;
|
|
}
|
|
while (num & MSBALL) {
|
|
out[offset++] = num & 255 | MSB;
|
|
num >>>= 7;
|
|
}
|
|
out[offset] = num | 0;
|
|
encode2.bytes = offset - oldOffset + 1;
|
|
return out;
|
|
}
|
|
var decode2 = read;
|
|
var MSB$1 = 128;
|
|
var REST$1 = 127;
|
|
function read(buf, offset) {
|
|
var res = 0, offset = offset || 0, shift = 0, counter = offset, b, l = buf.length;
|
|
do {
|
|
if (counter >= l) {
|
|
read.bytes = 0;
|
|
throw new RangeError("Could not decode varint");
|
|
}
|
|
b = buf[counter++];
|
|
res += shift < 28 ? (b & REST$1) << shift : (b & REST$1) * Math.pow(2, shift);
|
|
shift += 7;
|
|
} while (b >= MSB$1);
|
|
read.bytes = counter - offset;
|
|
return res;
|
|
}
|
|
var N1 = Math.pow(2, 7);
|
|
var N2 = Math.pow(2, 14);
|
|
var N3 = Math.pow(2, 21);
|
|
var N4 = Math.pow(2, 28);
|
|
var N5 = Math.pow(2, 35);
|
|
var N6 = Math.pow(2, 42);
|
|
var N7 = Math.pow(2, 49);
|
|
var N8 = Math.pow(2, 56);
|
|
var N9 = Math.pow(2, 63);
|
|
var length = function(value) {
|
|
return value < N1 ? 1 : value < N2 ? 2 : value < N3 ? 3 : value < N4 ? 4 : value < N5 ? 5 : value < N6 ? 6 : value < N7 ? 7 : value < N8 ? 8 : value < N9 ? 9 : 10;
|
|
};
|
|
var varint = {
|
|
encode: encode_1,
|
|
decode: decode2,
|
|
encodingLength: length
|
|
};
|
|
var _brrp_varint = varint;
|
|
var varint_default = _brrp_varint;
|
|
|
|
// ../../node_modules/.pnpm/multiformats@11.0.2/node_modules/multiformats/src/varint.js
|
|
var decode3 = (data, offset = 0) => {
|
|
const code = varint_default.decode(data, offset);
|
|
return [code, varint_default.decode.bytes];
|
|
};
|
|
var encodeTo = (int, target, offset = 0) => {
|
|
varint_default.encode(int, target, offset);
|
|
return target;
|
|
};
|
|
var encodingLength = (int) => {
|
|
return varint_default.encodingLength(int);
|
|
};
|
|
|
|
// ../../node_modules/.pnpm/multiformats@11.0.2/node_modules/multiformats/src/hashes/digest.js
|
|
var create = (code, digest) => {
|
|
const size = digest.byteLength;
|
|
const sizeOffset = encodingLength(code);
|
|
const digestOffset = sizeOffset + encodingLength(size);
|
|
const bytes = new Uint8Array(digestOffset + size);
|
|
encodeTo(code, bytes, 0);
|
|
encodeTo(size, bytes, sizeOffset);
|
|
bytes.set(digest, digestOffset);
|
|
return new Digest(code, size, digest, bytes);
|
|
};
|
|
var decode4 = (multihash) => {
|
|
const bytes = coerce(multihash);
|
|
const [code, sizeOffset] = decode3(bytes);
|
|
const [size, digestOffset] = decode3(bytes.subarray(sizeOffset));
|
|
const digest = bytes.subarray(sizeOffset + digestOffset);
|
|
if (digest.byteLength !== size) {
|
|
throw new Error("Incorrect length");
|
|
}
|
|
return new Digest(code, size, digest, bytes);
|
|
};
|
|
var equals2 = (a, b) => {
|
|
if (a === b) {
|
|
return true;
|
|
} else {
|
|
const data = (
|
|
/** @type {{code?:unknown, size?:unknown, bytes?:unknown}} */
|
|
b
|
|
);
|
|
return a.code === data.code && a.size === data.size && data.bytes instanceof Uint8Array && equals(a.bytes, data.bytes);
|
|
}
|
|
};
|
|
var Digest = class {
|
|
/**
|
|
* Creates a multihash digest.
|
|
*
|
|
* @param {Code} code
|
|
* @param {Size} size
|
|
* @param {Uint8Array} digest
|
|
* @param {Uint8Array} bytes
|
|
*/
|
|
constructor(code, size, digest, bytes) {
|
|
this.code = code;
|
|
this.size = size;
|
|
this.digest = digest;
|
|
this.bytes = bytes;
|
|
}
|
|
};
|
|
|
|
// ../../node_modules/.pnpm/multiformats@11.0.2/node_modules/multiformats/src/cid.js
|
|
var format = (link, base2) => {
|
|
const { bytes, version } = link;
|
|
switch (version) {
|
|
case 0:
|
|
return toStringV0(
|
|
bytes,
|
|
baseCache(link),
|
|
/** @type {API.MultibaseEncoder<"z">} */
|
|
base2 || base58btc.encoder
|
|
);
|
|
default:
|
|
return toStringV1(
|
|
bytes,
|
|
baseCache(link),
|
|
/** @type {API.MultibaseEncoder<Prefix>} */
|
|
base2 || base32.encoder
|
|
);
|
|
}
|
|
};
|
|
var cache = /* @__PURE__ */ new WeakMap();
|
|
var baseCache = (cid) => {
|
|
const baseCache2 = cache.get(cid);
|
|
if (baseCache2 == null) {
|
|
const baseCache3 = /* @__PURE__ */ new Map();
|
|
cache.set(cid, baseCache3);
|
|
return baseCache3;
|
|
}
|
|
return baseCache2;
|
|
};
|
|
var CID = class _CID {
|
|
/**
|
|
* @param {Version} version - Version of the CID
|
|
* @param {Format} code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
|
|
* @param {API.MultihashDigest<Alg>} multihash - (Multi)hash of the of the content.
|
|
* @param {Uint8Array} bytes
|
|
*
|
|
*/
|
|
constructor(version, code, multihash, bytes) {
|
|
this.code = code;
|
|
this.version = version;
|
|
this.multihash = multihash;
|
|
this.bytes = bytes;
|
|
this["/"] = bytes;
|
|
}
|
|
/**
|
|
* Signalling `cid.asCID === cid` has been replaced with `cid['/'] === cid.bytes`
|
|
* please either use `CID.asCID(cid)` or switch to new signalling mechanism
|
|
*
|
|
* @deprecated
|
|
*/
|
|
get asCID() {
|
|
return this;
|
|
}
|
|
// ArrayBufferView
|
|
get byteOffset() {
|
|
return this.bytes.byteOffset;
|
|
}
|
|
// ArrayBufferView
|
|
get byteLength() {
|
|
return this.bytes.byteLength;
|
|
}
|
|
/**
|
|
* @returns {CID<Data, API.DAG_PB, API.SHA_256, 0>}
|
|
*/
|
|
toV0() {
|
|
switch (this.version) {
|
|
case 0: {
|
|
return (
|
|
/** @type {CID<Data, API.DAG_PB, API.SHA_256, 0>} */
|
|
this
|
|
);
|
|
}
|
|
case 1: {
|
|
const { code, multihash } = this;
|
|
if (code !== DAG_PB_CODE) {
|
|
throw new Error("Cannot convert a non dag-pb CID to CIDv0");
|
|
}
|
|
if (multihash.code !== SHA_256_CODE) {
|
|
throw new Error("Cannot convert non sha2-256 multihash CID to CIDv0");
|
|
}
|
|
return (
|
|
/** @type {CID<Data, API.DAG_PB, API.SHA_256, 0>} */
|
|
_CID.createV0(
|
|
/** @type {API.MultihashDigest<API.SHA_256>} */
|
|
multihash
|
|
)
|
|
);
|
|
}
|
|
default: {
|
|
throw Error(
|
|
`Can not convert CID version ${this.version} to version 0. This is a bug please report`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* @returns {CID<Data, Format, Alg, 1>}
|
|
*/
|
|
toV1() {
|
|
switch (this.version) {
|
|
case 0: {
|
|
const { code, digest } = this.multihash;
|
|
const multihash = create(code, digest);
|
|
return (
|
|
/** @type {CID<Data, Format, Alg, 1>} */
|
|
_CID.createV1(this.code, multihash)
|
|
);
|
|
}
|
|
case 1: {
|
|
return (
|
|
/** @type {CID<Data, Format, Alg, 1>} */
|
|
this
|
|
);
|
|
}
|
|
default: {
|
|
throw Error(
|
|
`Can not convert CID version ${this.version} to version 1. This is a bug please report`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* @param {unknown} other
|
|
* @returns {other is CID<Data, Format, Alg, Version>}
|
|
*/
|
|
equals(other) {
|
|
return _CID.equals(this, other);
|
|
}
|
|
/**
|
|
* @template {unknown} Data
|
|
* @template {number} Format
|
|
* @template {number} Alg
|
|
* @template {API.Version} Version
|
|
* @param {API.Link<Data, Format, Alg, Version>} self
|
|
* @param {unknown} other
|
|
* @returns {other is CID}
|
|
*/
|
|
static equals(self, other) {
|
|
const unknown = (
|
|
/** @type {{code?:unknown, version?:unknown, multihash?:unknown}} */
|
|
other
|
|
);
|
|
return unknown && self.code === unknown.code && self.version === unknown.version && equals2(self.multihash, unknown.multihash);
|
|
}
|
|
/**
|
|
* @param {API.MultibaseEncoder<string>} [base]
|
|
* @returns {string}
|
|
*/
|
|
toString(base2) {
|
|
return format(this, base2);
|
|
}
|
|
toJSON() {
|
|
return { "/": format(this) };
|
|
}
|
|
link() {
|
|
return this;
|
|
}
|
|
get [Symbol.toStringTag]() {
|
|
return "CID";
|
|
}
|
|
// Legacy
|
|
[Symbol.for("nodejs.util.inspect.custom")]() {
|
|
return `CID(${this.toString()})`;
|
|
}
|
|
/**
|
|
* Takes any input `value` and returns a `CID` instance if it was
|
|
* a `CID` otherwise returns `null`. If `value` is instanceof `CID`
|
|
* it will return value back. If `value` is not instance of this CID
|
|
* class, but is compatible CID it will return new instance of this
|
|
* `CID` class. Otherwise returns null.
|
|
*
|
|
* This allows two different incompatible versions of CID library to
|
|
* co-exist and interop as long as binary interface is compatible.
|
|
*
|
|
* @template {unknown} Data
|
|
* @template {number} Format
|
|
* @template {number} Alg
|
|
* @template {API.Version} Version
|
|
* @template {unknown} U
|
|
* @param {API.Link<Data, Format, Alg, Version>|U} input
|
|
* @returns {CID<Data, Format, Alg, Version>|null}
|
|
*/
|
|
static asCID(input) {
|
|
if (input == null) {
|
|
return null;
|
|
}
|
|
const value = (
|
|
/** @type {any} */
|
|
input
|
|
);
|
|
if (value instanceof _CID) {
|
|
return value;
|
|
} else if (value["/"] != null && value["/"] === value.bytes || value.asCID === value) {
|
|
const { version, code, multihash, bytes } = value;
|
|
return new _CID(
|
|
version,
|
|
code,
|
|
/** @type {API.MultihashDigest<Alg>} */
|
|
multihash,
|
|
bytes || encodeCID(version, code, multihash.bytes)
|
|
);
|
|
} else if (value[cidSymbol] === true) {
|
|
const { version, multihash, code } = value;
|
|
const digest = (
|
|
/** @type {API.MultihashDigest<Alg>} */
|
|
decode4(multihash)
|
|
);
|
|
return _CID.create(version, code, digest);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
/**
|
|
*
|
|
* @template {unknown} Data
|
|
* @template {number} Format
|
|
* @template {number} Alg
|
|
* @template {API.Version} Version
|
|
* @param {Version} version - Version of the CID
|
|
* @param {Format} code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
|
|
* @param {API.MultihashDigest<Alg>} digest - (Multi)hash of the of the content.
|
|
* @returns {CID<Data, Format, Alg, Version>}
|
|
*/
|
|
static create(version, code, digest) {
|
|
if (typeof code !== "number") {
|
|
throw new Error("String codecs are no longer supported");
|
|
}
|
|
if (!(digest.bytes instanceof Uint8Array)) {
|
|
throw new Error("Invalid digest");
|
|
}
|
|
switch (version) {
|
|
case 0: {
|
|
if (code !== DAG_PB_CODE) {
|
|
throw new Error(
|
|
`Version 0 CID must use dag-pb (code: ${DAG_PB_CODE}) block encoding`
|
|
);
|
|
} else {
|
|
return new _CID(version, code, digest, digest.bytes);
|
|
}
|
|
}
|
|
case 1: {
|
|
const bytes = encodeCID(version, code, digest.bytes);
|
|
return new _CID(version, code, digest, bytes);
|
|
}
|
|
default: {
|
|
throw new Error("Invalid version");
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Simplified version of `create` for CIDv0.
|
|
*
|
|
* @template {unknown} [T=unknown]
|
|
* @param {API.MultihashDigest<typeof SHA_256_CODE>} digest - Multihash.
|
|
* @returns {CID<T, typeof DAG_PB_CODE, typeof SHA_256_CODE, 0>}
|
|
*/
|
|
static createV0(digest) {
|
|
return _CID.create(0, DAG_PB_CODE, digest);
|
|
}
|
|
/**
|
|
* Simplified version of `create` for CIDv1.
|
|
*
|
|
* @template {unknown} Data
|
|
* @template {number} Code
|
|
* @template {number} Alg
|
|
* @param {Code} code - Content encoding format code.
|
|
* @param {API.MultihashDigest<Alg>} digest - Miltihash of the content.
|
|
* @returns {CID<Data, Code, Alg, 1>}
|
|
*/
|
|
static createV1(code, digest) {
|
|
return _CID.create(1, code, digest);
|
|
}
|
|
/**
|
|
* Decoded a CID from its binary representation. The byte array must contain
|
|
* only the CID with no additional bytes.
|
|
*
|
|
* An error will be thrown if the bytes provided do not contain a valid
|
|
* binary representation of a CID.
|
|
*
|
|
* @template {unknown} Data
|
|
* @template {number} Code
|
|
* @template {number} Alg
|
|
* @template {API.Version} Ver
|
|
* @param {API.ByteView<API.Link<Data, Code, Alg, Ver>>} bytes
|
|
* @returns {CID<Data, Code, Alg, Ver>}
|
|
*/
|
|
static decode(bytes) {
|
|
const [cid, remainder] = _CID.decodeFirst(bytes);
|
|
if (remainder.length) {
|
|
throw new Error("Incorrect length");
|
|
}
|
|
return cid;
|
|
}
|
|
/**
|
|
* Decoded a CID from its binary representation at the beginning of a byte
|
|
* array.
|
|
*
|
|
* Returns an array with the first element containing the CID and the second
|
|
* element containing the remainder of the original byte array. The remainder
|
|
* will be a zero-length byte array if the provided bytes only contained a
|
|
* binary CID representation.
|
|
*
|
|
* @template {unknown} T
|
|
* @template {number} C
|
|
* @template {number} A
|
|
* @template {API.Version} V
|
|
* @param {API.ByteView<API.Link<T, C, A, V>>} bytes
|
|
* @returns {[CID<T, C, A, V>, Uint8Array]}
|
|
*/
|
|
static decodeFirst(bytes) {
|
|
const specs = _CID.inspectBytes(bytes);
|
|
const prefixSize = specs.size - specs.multihashSize;
|
|
const multihashBytes = coerce(
|
|
bytes.subarray(prefixSize, prefixSize + specs.multihashSize)
|
|
);
|
|
if (multihashBytes.byteLength !== specs.multihashSize) {
|
|
throw new Error("Incorrect length");
|
|
}
|
|
const digestBytes = multihashBytes.subarray(
|
|
specs.multihashSize - specs.digestSize
|
|
);
|
|
const digest = new Digest(
|
|
specs.multihashCode,
|
|
specs.digestSize,
|
|
digestBytes,
|
|
multihashBytes
|
|
);
|
|
const cid = specs.version === 0 ? _CID.createV0(
|
|
/** @type {API.MultihashDigest<API.SHA_256>} */
|
|
digest
|
|
) : _CID.createV1(specs.codec, digest);
|
|
return [
|
|
/** @type {CID<T, C, A, V>} */
|
|
cid,
|
|
bytes.subarray(specs.size)
|
|
];
|
|
}
|
|
/**
|
|
* Inspect the initial bytes of a CID to determine its properties.
|
|
*
|
|
* Involves decoding up to 4 varints. Typically this will require only 4 to 6
|
|
* bytes but for larger multicodec code values and larger multihash digest
|
|
* lengths these varints can be quite large. It is recommended that at least
|
|
* 10 bytes be made available in the `initialBytes` argument for a complete
|
|
* inspection.
|
|
*
|
|
* @template {unknown} T
|
|
* @template {number} C
|
|
* @template {number} A
|
|
* @template {API.Version} V
|
|
* @param {API.ByteView<API.Link<T, C, A, V>>} initialBytes
|
|
* @returns {{ version:V, codec:C, multihashCode:A, digestSize:number, multihashSize:number, size:number }}
|
|
*/
|
|
static inspectBytes(initialBytes) {
|
|
let offset = 0;
|
|
const next = () => {
|
|
const [i, length2] = decode3(initialBytes.subarray(offset));
|
|
offset += length2;
|
|
return i;
|
|
};
|
|
let version = (
|
|
/** @type {V} */
|
|
next()
|
|
);
|
|
let codec = (
|
|
/** @type {C} */
|
|
DAG_PB_CODE
|
|
);
|
|
if (
|
|
/** @type {number} */
|
|
version === 18
|
|
) {
|
|
version = /** @type {V} */
|
|
0;
|
|
offset = 0;
|
|
} else {
|
|
codec = /** @type {C} */
|
|
next();
|
|
}
|
|
if (version !== 0 && version !== 1) {
|
|
throw new RangeError(`Invalid CID version ${version}`);
|
|
}
|
|
const prefixSize = offset;
|
|
const multihashCode = (
|
|
/** @type {A} */
|
|
next()
|
|
);
|
|
const digestSize = next();
|
|
const size = offset + digestSize;
|
|
const multihashSize = size - prefixSize;
|
|
return { version, codec, multihashCode, digestSize, multihashSize, size };
|
|
}
|
|
/**
|
|
* Takes cid in a string representation and creates an instance. If `base`
|
|
* decoder is not provided will use a default from the configuration. It will
|
|
* throw an error if encoding of the CID is not compatible with supplied (or
|
|
* a default decoder).
|
|
*
|
|
* @template {string} Prefix
|
|
* @template {unknown} Data
|
|
* @template {number} Code
|
|
* @template {number} Alg
|
|
* @template {API.Version} Ver
|
|
* @param {API.ToString<API.Link<Data, Code, Alg, Ver>, Prefix>} source
|
|
* @param {API.MultibaseDecoder<Prefix>} [base]
|
|
* @returns {CID<Data, Code, Alg, Ver>}
|
|
*/
|
|
static parse(source, base2) {
|
|
const [prefix, bytes] = parseCIDtoBytes(source, base2);
|
|
const cid = _CID.decode(bytes);
|
|
if (cid.version === 0 && source[0] !== "Q") {
|
|
throw Error("Version 0 CID string must not include multibase prefix");
|
|
}
|
|
baseCache(cid).set(prefix, source);
|
|
return cid;
|
|
}
|
|
};
|
|
var parseCIDtoBytes = (source, base2) => {
|
|
switch (source[0]) {
|
|
case "Q": {
|
|
const decoder = base2 || base58btc;
|
|
return [
|
|
/** @type {Prefix} */
|
|
base58btc.prefix,
|
|
decoder.decode(`${base58btc.prefix}${source}`)
|
|
];
|
|
}
|
|
case base58btc.prefix: {
|
|
const decoder = base2 || base58btc;
|
|
return [
|
|
/** @type {Prefix} */
|
|
base58btc.prefix,
|
|
decoder.decode(source)
|
|
];
|
|
}
|
|
case base32.prefix: {
|
|
const decoder = base2 || base32;
|
|
return [
|
|
/** @type {Prefix} */
|
|
base32.prefix,
|
|
decoder.decode(source)
|
|
];
|
|
}
|
|
default: {
|
|
if (base2 == null) {
|
|
throw Error(
|
|
"To parse non base32 or base58btc encoded CID multibase decoder must be provided"
|
|
);
|
|
}
|
|
return [
|
|
/** @type {Prefix} */
|
|
source[0],
|
|
base2.decode(source)
|
|
];
|
|
}
|
|
}
|
|
};
|
|
var toStringV0 = (bytes, cache2, base2) => {
|
|
const { prefix } = base2;
|
|
if (prefix !== base58btc.prefix) {
|
|
throw Error(`Cannot string encode V0 in ${base2.name} encoding`);
|
|
}
|
|
const cid = cache2.get(prefix);
|
|
if (cid == null) {
|
|
const cid2 = base2.encode(bytes).slice(1);
|
|
cache2.set(prefix, cid2);
|
|
return cid2;
|
|
} else {
|
|
return cid;
|
|
}
|
|
};
|
|
var toStringV1 = (bytes, cache2, base2) => {
|
|
const { prefix } = base2;
|
|
const cid = cache2.get(prefix);
|
|
if (cid == null) {
|
|
const cid2 = base2.encode(bytes);
|
|
cache2.set(prefix, cid2);
|
|
return cid2;
|
|
} else {
|
|
return cid;
|
|
}
|
|
};
|
|
var DAG_PB_CODE = 112;
|
|
var SHA_256_CODE = 18;
|
|
var encodeCID = (version, code, multihash) => {
|
|
const codeOffset = encodingLength(version);
|
|
const hashOffset = codeOffset + encodingLength(code);
|
|
const bytes = new Uint8Array(hashOffset + multihash.byteLength);
|
|
encodeTo(version, bytes, 0);
|
|
encodeTo(code, bytes, codeOffset);
|
|
bytes.set(multihash, hashOffset);
|
|
return bytes;
|
|
};
|
|
var cidSymbol = Symbol.for("@ipld/js-cid/CID");
|
|
|
|
// src/multicodec.ts
|
|
var Multicodec = class _Multicodec {
|
|
static {
|
|
/**
|
|
* A static field containing a map of codec codes to their corresponding names.
|
|
*/
|
|
this.codeToName = /* @__PURE__ */ new Map();
|
|
}
|
|
static {
|
|
/**
|
|
* A static field containing a map of codec names to their corresponding codes.
|
|
*/
|
|
this.nameToCode = /* @__PURE__ */ new Map();
|
|
}
|
|
/**
|
|
* Adds a multicodec prefix to input data.
|
|
*
|
|
* @param options - The options for adding a prefix.
|
|
* @param options.code - The codec code. Either the code or name must be provided.
|
|
* @param options.name - The codec name. Either the code or name must be provided.
|
|
* @param options.data - The data to be prefixed.
|
|
* @returns The data with the added prefix as a Uint8Array.
|
|
*/
|
|
static addPrefix(options) {
|
|
let { code, data, name } = options;
|
|
if (!(name ? !code : code)) {
|
|
throw new Error(`Either 'name' or 'code' must be defined, but not both.`);
|
|
}
|
|
code = _Multicodec.codeToName.has(code) ? code : _Multicodec.nameToCode.get(name);
|
|
if (code === void 0) {
|
|
throw new Error(`Unsupported multicodec: ${options.name ?? options.code}`);
|
|
}
|
|
const prefixLength = varint_exports.encodingLength(code);
|
|
const dataWithPrefix = new Uint8Array(prefixLength + data.byteLength);
|
|
dataWithPrefix.set(data, prefixLength);
|
|
varint_exports.encodeTo(code, dataWithPrefix);
|
|
return dataWithPrefix;
|
|
}
|
|
/**
|
|
* Get the Multicodec code from given prefixed data.
|
|
*
|
|
* @param options - The options for getting the codec code.
|
|
* @param options.prefixedData - The data to extract the codec code from.
|
|
* @returns - The Multicodec code as a number.
|
|
*/
|
|
static getCodeFromData(options) {
|
|
const { prefixedData } = options;
|
|
const [code, _] = varint_exports.decode(prefixedData);
|
|
return code;
|
|
}
|
|
/**
|
|
* Get the Multicodec code from given Multicodec name.
|
|
*
|
|
* @param options - The options for getting the codec code.
|
|
* @param options.name - The name to lookup.
|
|
* @returns - The Multicodec code as a number.
|
|
*/
|
|
static getCodeFromName(options) {
|
|
const { name } = options;
|
|
const code = _Multicodec.nameToCode.get(name);
|
|
if (code === void 0) {
|
|
throw new Error(`Unsupported multicodec: ${name}`);
|
|
}
|
|
return code;
|
|
}
|
|
/**
|
|
* Get the Multicodec name from given Multicodec code.
|
|
*
|
|
* @param options - The options for getting the codec name.
|
|
* @param options.name - The code to lookup.
|
|
* @returns - The Multicodec name as a string.
|
|
*/
|
|
static getNameFromCode(options) {
|
|
const { code } = options;
|
|
const name = _Multicodec.codeToName.get(code);
|
|
if (name === void 0) {
|
|
throw new Error(`Unsupported multicodec: ${code}`);
|
|
}
|
|
return name;
|
|
}
|
|
/**
|
|
* Registers a new codec in the Multicodec class.
|
|
*
|
|
* @param codec - The codec to be registered.
|
|
*/
|
|
static registerCodec(codec) {
|
|
_Multicodec.codeToName.set(codec.code, codec.name);
|
|
_Multicodec.nameToCode.set(codec.name, codec.code);
|
|
}
|
|
/**
|
|
* Returns the data with the Multicodec prefix removed.
|
|
*
|
|
* @param refixedData - The data to extract the codec code from.
|
|
* @returns {Uint8Array}
|
|
*/
|
|
static removePrefix(options) {
|
|
const { prefixedData } = options;
|
|
const [code, codeByteLength] = varint_exports.decode(prefixedData);
|
|
const name = _Multicodec.codeToName.get(code);
|
|
if (name === void 0) {
|
|
throw new Error(`Unsupported multicodec: ${code}`);
|
|
}
|
|
return { code, data: prefixedData.slice(codeByteLength), name };
|
|
}
|
|
};
|
|
Multicodec.registerCodec({ code: 237, name: "ed25519-pub" });
|
|
Multicodec.registerCodec({ code: 4864, name: "ed25519-priv" });
|
|
Multicodec.registerCodec({ code: 236, name: "x25519-pub" });
|
|
Multicodec.registerCodec({ code: 4866, name: "x25519-priv" });
|
|
Multicodec.registerCodec({ code: 231, name: "secp256k1-pub" });
|
|
Multicodec.registerCodec({ code: 4865, name: "secp256k1-priv" });
|
|
|
|
// src/object.ts
|
|
function isEmptyObject(obj) {
|
|
if (typeof obj !== "object" || obj === null) {
|
|
return false;
|
|
}
|
|
if (Object.getOwnPropertySymbols(obj).length > 0) {
|
|
return false;
|
|
}
|
|
return Object.keys(obj).length === 0;
|
|
}
|
|
function removeEmptyObjects(obj) {
|
|
Object.keys(obj).forEach((key) => {
|
|
if (typeof obj[key] === "object") {
|
|
removeEmptyObjects(obj[key]);
|
|
}
|
|
if (isEmptyObject(obj[key])) {
|
|
delete obj[key];
|
|
}
|
|
});
|
|
}
|
|
function removeUndefinedProperties(obj) {
|
|
Object.keys(obj).forEach((key) => {
|
|
if (obj[key] === void 0) {
|
|
delete obj[key];
|
|
} else if (typeof obj[key] === "object") {
|
|
removeUndefinedProperties(obj[key]);
|
|
}
|
|
});
|
|
}
|
|
|
|
// src/stores.ts
|
|
var import_level = require("level");
|
|
var LevelStore = class {
|
|
constructor({ db, location = "DATASTORE" } = {}) {
|
|
this.store = db ?? new import_level.Level(location);
|
|
}
|
|
async clear() {
|
|
await this.store.clear();
|
|
}
|
|
async close() {
|
|
await this.store.close();
|
|
}
|
|
async delete(key) {
|
|
await this.store.del(key);
|
|
}
|
|
async get(key) {
|
|
try {
|
|
return await this.store.get(key);
|
|
} catch (error) {
|
|
if (error.notFound)
|
|
return void 0;
|
|
throw error;
|
|
}
|
|
}
|
|
async set(key, value) {
|
|
await this.store.put(key, value);
|
|
}
|
|
};
|
|
var MemoryStore = class {
|
|
constructor() {
|
|
/**
|
|
* A private field that contains the Map used as the key-value store.
|
|
*/
|
|
this.store = /* @__PURE__ */ new Map();
|
|
}
|
|
/**
|
|
* Clears all entries in the key-value store.
|
|
*
|
|
* @returns A Promise that resolves when the operation is complete.
|
|
*/
|
|
async clear() {
|
|
this.store.clear();
|
|
}
|
|
/**
|
|
* This operation is no-op for `MemoryStore`
|
|
* and will log a warning if called.
|
|
*/
|
|
async close() {
|
|
}
|
|
/**
|
|
* Deletes an entry from the key-value store by its key.
|
|
*
|
|
* @param id - The key of the entry to delete.
|
|
* @returns A Promise that resolves to a boolean indicating whether the entry was successfully deleted.
|
|
*/
|
|
async delete(id) {
|
|
return this.store.delete(id);
|
|
}
|
|
/**
|
|
* Retrieves the value of an entry by its key.
|
|
*
|
|
* @param id - The key of the entry to retrieve.
|
|
* @returns A Promise that resolves to the value of the entry, or `undefined` if the entry does not exist.
|
|
*/
|
|
async get(id) {
|
|
return this.store.get(id);
|
|
}
|
|
/**
|
|
* Checks for the presence of an entry by key.
|
|
*
|
|
* @param id - The key to check for the existence of.
|
|
* @returns A Promise that resolves to a boolean indicating whether an element with the specified key exists or not.
|
|
*/
|
|
async has(id) {
|
|
return this.store.has(id);
|
|
}
|
|
/**
|
|
* Retrieves all values in the key-value store.
|
|
*
|
|
* @returns A Promise that resolves to an array of all values in the store.
|
|
*/
|
|
async list() {
|
|
return Array.from(this.store.values());
|
|
}
|
|
/**
|
|
* Sets the value of an entry in the key-value store.
|
|
*
|
|
* @param id - The key of the entry to set.
|
|
* @param key - The new value for the entry.
|
|
* @returns A Promise that resolves when the operation is complete.
|
|
*/
|
|
async set(id, key) {
|
|
this.store.set(id, key);
|
|
}
|
|
};
|
|
|
|
// src/stream.ts
|
|
var Stream = class _Stream {
|
|
/**
|
|
* Transforms a `ReadableStream` into an `AsyncIterable`. This allows for the asynchronous
|
|
* iteration over the stream's data chunks.
|
|
*
|
|
* This method creates an async iterator from a `ReadableStream`, enabling the use of
|
|
* `for await...of` loops to process stream data. It reads from the stream until it's closed or
|
|
* errored, yielding each chunk as it becomes available.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const readableStream = new ReadableStream({ ... });
|
|
* for await (const chunk of Stream.asAsyncIterator(readableStream)) {
|
|
* // process each chunk
|
|
* }
|
|
* ```
|
|
*
|
|
* @remarks
|
|
* - The method ensures proper cleanup by releasing the reader lock when iteration is completed or
|
|
* if an error occurs.
|
|
*
|
|
* @param readableStream - The Web `ReadableStream` to be transformed into an `AsyncIterable`.
|
|
* @returns An `AsyncIterable` that yields data chunks from the `ReadableStream`.
|
|
*/
|
|
static async *asAsyncIterator(readableStream) {
|
|
const reader = readableStream.getReader();
|
|
try {
|
|
while (true) {
|
|
const { done, value } = await reader.read();
|
|
if (done)
|
|
break;
|
|
yield value;
|
|
}
|
|
} finally {
|
|
reader.releaseLock();
|
|
}
|
|
}
|
|
/**
|
|
* Consumes a `ReadableStream` and returns its contents as an `ArrayBuffer`.
|
|
*
|
|
* This method reads all data from a `ReadableStream`, collects it, and converts it into an
|
|
* `ArrayBuffer`.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const readableStream = new ReadableStream({ ... });
|
|
* const arrayBuffer = await Stream.consumeToArrayBuffer({ readableStream });
|
|
* ```
|
|
*
|
|
* @param readableStream - The Web `ReadableStream` whose data will be consumed.
|
|
* @returns A Promise that resolves to an `ArrayBuffer` containing all the data from the stream.
|
|
*/
|
|
static async consumeToArrayBuffer({ readableStream }) {
|
|
const iterableStream = _Stream.asAsyncIterator(readableStream);
|
|
const arrayBuffer = await Convert.asyncIterable(iterableStream).toArrayBufferAsync();
|
|
return arrayBuffer;
|
|
}
|
|
/**
|
|
* Consumes a `ReadableStream` and returns its contents as a `Blob`.
|
|
*
|
|
* This method reads all data from a `ReadableStream`, collects it, and converts it into a `Blob`.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const readableStream = new ReadableStream({ ... });
|
|
* const blob = await Stream.consumeToBlob({ readableStream });
|
|
* ```
|
|
*
|
|
* @param readableStream - The Web `ReadableStream` whose data will be consumed.
|
|
* @returns A Promise that resolves to a `Blob` containing all the data from the stream.
|
|
*/
|
|
static async consumeToBlob({ readableStream }) {
|
|
const iterableStream = _Stream.asAsyncIterator(readableStream);
|
|
const blob = await Convert.asyncIterable(iterableStream).toBlobAsync();
|
|
return blob;
|
|
}
|
|
/**
|
|
* Consumes a `ReadableStream` and returns its contents as a `Uint8Array`.
|
|
*
|
|
* This method reads all data from a `ReadableStream`, collects it, and converts it into a
|
|
* `Uint8Array`.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const readableStream = new ReadableStream({ ... });
|
|
* const bytes = await Stream.consumeToBytes({ readableStream });
|
|
* ```
|
|
*
|
|
* @param readableStream - The Web `ReadableStream` whose data will be consumed.
|
|
* @returns A Promise that resolves to a `Uint8Array` containing all the data from the stream.
|
|
*/
|
|
static async consumeToBytes({ readableStream }) {
|
|
const iterableStream = _Stream.asAsyncIterator(readableStream);
|
|
const bytes = await Convert.asyncIterable(iterableStream).toUint8ArrayAsync();
|
|
return bytes;
|
|
}
|
|
/**
|
|
* Consumes a `ReadableStream` and parses its contents as JSON.
|
|
*
|
|
* This method reads all the data from the stream, converts it to a text string, and then parses
|
|
* it as JSON, returning the resulting object.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const readableStream = new ReadableStream({ ... });
|
|
* const jsonData = await Stream.consumeToJson({ readableStream });
|
|
* ```
|
|
*
|
|
* @param readableStream - The Web `ReadableStream` whose JSON content will be consumed.
|
|
* @returns A Promise that resolves to the parsed JSON object from the stream's data.
|
|
*/
|
|
static async consumeToJson({ readableStream }) {
|
|
const iterableStream = _Stream.asAsyncIterator(readableStream);
|
|
const object = await Convert.asyncIterable(iterableStream).toObjectAsync();
|
|
return object;
|
|
}
|
|
/**
|
|
* Consumes a `ReadableStream` and returns its contents as a text string.
|
|
*
|
|
* This method reads all the data from the stream, converting it into a single string.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const readableStream = new ReadableStream({ ... });
|
|
* const text = await Stream.consumeToText({ readableStream });
|
|
* ```
|
|
*
|
|
* @param readableStream - The Web `ReadableStream` whose text content will be consumed.
|
|
* @returns A Promise that resolves to a string containing all the data from the stream.
|
|
*/
|
|
static async consumeToText({ readableStream }) {
|
|
const iterableStream = _Stream.asAsyncIterator(readableStream);
|
|
const text = await Convert.asyncIterable(iterableStream).toStringAsync();
|
|
return text;
|
|
}
|
|
/**
|
|
* Generates a `ReadableStream` of `Uint8Array` chunks with customizable length and fill value.
|
|
*
|
|
* This method creates a `ReadableStream` that emits `Uint8Array` chunks. You can specify the
|
|
* total length of the stream, the length of individual chunks, and a fill value or range for the
|
|
* chunks. It's useful for testing or when specific binary data streams are required.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* // Create a stream of 1000 bytes with 100-byte chunks filled with 0xAA.
|
|
* const byteStream = Stream.generateByteStream({
|
|
* streamLength: 1000,
|
|
* chunkLength: 100,
|
|
* fillValue: 0xAA
|
|
* });
|
|
*
|
|
* // Create an unending stream of 100KB chunks filled with values that range from 1 to 99.
|
|
* const byteStream = Stream.generateByteStream({
|
|
* chunkLength: 100 * 1024,
|
|
* fillValue: [1, 99]
|
|
* });
|
|
* ```
|
|
*
|
|
* @param streamLength - The total length of the stream in bytes. If omitted, the stream is infinite.
|
|
* @param chunkLength - The length of each chunk. If omitted, each chunk is the size of `streamLength`.
|
|
* @param fillValue - A value or range to fill the chunks with. Can be a single number or a tuple [min, max].
|
|
* @returns A `ReadableStream` that emits `Uint8Array` chunks.
|
|
*/
|
|
static generateByteStream({ streamLength, chunkLength, fillValue }) {
|
|
let bytesRemaining = streamLength ?? Infinity;
|
|
let controller;
|
|
function enqueueChunk() {
|
|
const currentChunkLength = Math.min(bytesRemaining, chunkLength ?? Infinity);
|
|
bytesRemaining -= currentChunkLength;
|
|
let chunk;
|
|
if (typeof fillValue === "number") {
|
|
chunk = new Uint8Array(currentChunkLength).fill(fillValue);
|
|
} else if (Array.isArray(fillValue)) {
|
|
chunk = new Uint8Array(currentChunkLength);
|
|
const [min, max] = fillValue;
|
|
const range = max - min + 1;
|
|
for (let i = 0; i < currentChunkLength; i++) {
|
|
chunk[i] = Math.floor(Math.random() * range) + min;
|
|
}
|
|
} else {
|
|
chunk = new Uint8Array(currentChunkLength);
|
|
}
|
|
controller.enqueue(chunk);
|
|
if (bytesRemaining <= 0) {
|
|
controller.close();
|
|
}
|
|
}
|
|
return new ReadableStream({
|
|
start(c) {
|
|
controller = c;
|
|
enqueueChunk();
|
|
},
|
|
pull() {
|
|
enqueueChunk();
|
|
}
|
|
});
|
|
}
|
|
/**
|
|
* Checks if the provided Web `ReadableStream` is in a readable state.
|
|
*
|
|
* After verifying that the stream is a Web {@link https://streams.spec.whatwg.org/#rs-model | ReadableStream},
|
|
* this method checks the {@link https://streams.spec.whatwg.org/#readablestream-locked | locked}
|
|
* property of the ReadableStream. The `locked` property is `true` if a reader is currently
|
|
* active, meaning the stream is either being read or has already been read (and hence is not in a
|
|
* readable state). If `locked` is `false`, it means the stream is still in a state where it can
|
|
* be read.
|
|
*
|
|
* In the case where a `ReadableStream` has been unlocked but is no longer readable (for example,
|
|
* if it has been fully read or cancelled), additional checks are needed beyond just examining the
|
|
* locked property. The ReadableStream API does not provide a direct way to check if the stream
|
|
* has data left or if it's in a readable state once it's been unlocked.
|
|
*
|
|
* Per {@link https://streams.spec.whatwg.org/#other-specs-rs-introspect | WHATWG Streams, Section 9.1.3. Introspection}:
|
|
*
|
|
* > ...note that apart from checking whether or not the stream is locked, this direct
|
|
* > introspection is not possible via the public JavaScript API, and so specifications should
|
|
* > instead use the algorithms in §9.1.2 Reading. (For example, instead of testing if the stream
|
|
* > is readable, attempt to get a reader and handle any exception.)
|
|
*
|
|
* This implementation employs the technique suggested by the WHATWG Streams standard by
|
|
* attempting to acquire a reader and checking the state of the reader. If acquiring a reader
|
|
* succeeds, it immediately releases the lock and returns `true`, indicating the stream is
|
|
* readable. If an error occurs while trying to get a reader (which can happen if the stream is
|
|
* already closed or errored), it catches the error and returns `false`, indicating the stream is
|
|
* not readable.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const readableStream = new ReadableStream({ ... });
|
|
* const isStreamReadable = Stream.isReadable({ readableStream });
|
|
* console.log(isStreamReadable); // Output: true or false
|
|
* ```
|
|
*
|
|
* @remarks
|
|
* - This method does not check whether the stream has data left to read; it only checks if the
|
|
* stream is in a state that allows reading. It is possible for a stream to be unlocked but
|
|
* still have no data left if it has never been locked to a reader.
|
|
*
|
|
* @param readableStream - The Web `ReadableStream` to be checked for readability.
|
|
*
|
|
* @returns `true` if the stream is a `ReadableStream` and is in a readable state (not locked and
|
|
* no error on getting a reader); otherwise, `false`.
|
|
*/
|
|
static isReadable({ readableStream }) {
|
|
if (!_Stream.isReadableStream(readableStream)) {
|
|
return false;
|
|
}
|
|
if (readableStream.locked) {
|
|
return false;
|
|
}
|
|
try {
|
|
const reader = readableStream.getReader();
|
|
reader.releaseLock();
|
|
return true;
|
|
} catch (error) {
|
|
return false;
|
|
}
|
|
}
|
|
/**
|
|
* Checks if an object is a Web `ReadableStream`.
|
|
*
|
|
* This method verifies whether the given object is a `ReadableStream` by checking its type and
|
|
* the presence of the `getReader` function.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const obj = getSomeObject();
|
|
* if (Stream.isReadableStream(obj)) {
|
|
* // obj is a ReadableStream
|
|
* }
|
|
* ```
|
|
*
|
|
* @param obj - The object to be checked.
|
|
* @returns `true` if `obj` is a `ReadableStream`; otherwise, `false`.
|
|
*/
|
|
static isReadableStream(obj) {
|
|
return typeof obj === "object" && obj !== null && "getReader" in obj && typeof obj.getReader === "function";
|
|
}
|
|
/**
|
|
* Checks if an object is a Web `ReadableStream`, `WritableStream`, or `TransformStream`.
|
|
*
|
|
* This method verifies the type of a given object to determine if it is one of the standard
|
|
* stream types in the Web Streams API: `ReadableStream`, `WritableStream`, or `TransformStream`.
|
|
* It employs type-checking strategies that are specific to each stream type.
|
|
*
|
|
* The method checks for the specific functions and properties associated with each stream type:
|
|
* - `ReadableStream`: Identified by the presence of a `getReader` method.
|
|
* - `WritableStream`: Identified by the presence of a `getWriter` and `abort` methods.
|
|
* - `TransformStream`: Identified by having both `readable` and `writable` properties.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const readableStream = new ReadableStream();
|
|
* console.log(Stream.isStream(readableStream)); // Output: true
|
|
*
|
|
* const writableStream = new WritableStream();
|
|
* console.log(Stream.isStream(writableStream)); // Output: true
|
|
*
|
|
* const transformStream = new TransformStream();
|
|
* console.log(Stream.isStream(transformStream)); // Output: true
|
|
*
|
|
* const nonStreamObject = {};
|
|
* console.log(Stream.isStream(nonStreamObject)); // Output: false
|
|
* ```
|
|
*
|
|
* @remarks
|
|
* - This method does not differentiate between `ReadableStream`, `WritableStream`, and
|
|
* `TransformStream`. It checks if the object conforms to any of these types.
|
|
* - This method is specific to the Web Streams API and may not recognize non-standard or custom
|
|
* stream-like objects that do not adhere to the Web Streams API specifications.
|
|
*
|
|
* @param obj - The object to be checked for being a Web `ReadableStream`, `WritableStream`, or `TransformStream`.
|
|
* @returns `true` if the object is a `ReadableStream`, `WritableStream`, or `TransformStream`; otherwise, `false`.
|
|
*/
|
|
static isStream(obj) {
|
|
return _Stream.isReadableStream(obj) || _Stream.isWritableStream(obj) || _Stream.isTransformStream(obj);
|
|
}
|
|
/**
|
|
* Checks if an object is a `TransformStream`.
|
|
*
|
|
* This method verifies whether the given object is a `TransformStream` by checking its type and
|
|
* the presence of `readable` and `writable` properties.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const obj = getSomeObject();
|
|
* if (Stream.isTransformStream(obj)) {
|
|
* // obj is a TransformStream
|
|
* }
|
|
* ```
|
|
*
|
|
* @param obj - The object to be checked.
|
|
* @returns `true` if `obj` is a `TransformStream`; otherwise, `false`.
|
|
*/
|
|
static isTransformStream(obj) {
|
|
return typeof obj === "object" && obj !== null && "readable" in obj && typeof obj.readable === "object" && "writable" in obj && typeof obj.writable === "object";
|
|
}
|
|
/**
|
|
* Checks if an object is a `WritableStream`.
|
|
*
|
|
* This method determines whether the given object is a `WritableStream` by verifying its type and
|
|
* the presence of the `getWriter` and `abort` functions.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const obj = getSomeObject();
|
|
* if (Stream.isWritableStream(obj)) {
|
|
* // obj is a WritableStream
|
|
* }
|
|
* ```
|
|
*
|
|
* @param obj - The object to be checked.
|
|
* @returns `true` if `obj` is a `TransformStream`; otherwise, `false`.
|
|
*/
|
|
static isWritableStream(obj) {
|
|
return typeof obj === "object" && obj !== null && "getWriter" in obj && typeof obj.getWriter === "function" && "abort" in obj && typeof obj.abort === "function";
|
|
}
|
|
};
|
|
|
|
// src/stream-node.ts
|
|
var import_readable_stream = require("readable-stream");
|
|
var import_readable_stream2 = require("readable-stream");
|
|
var NodeStream = class _NodeStream {
|
|
/**
|
|
* Consumes a `Readable` stream and returns its contents as an `ArrayBuffer`.
|
|
*
|
|
* This method reads all data from a Node.js `Readable` stream, collects it, and converts it into
|
|
* an `ArrayBuffer`.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const nodeReadable = getReadableStreamSomehow();
|
|
* const arrayBuffer = await NodeStream.consumeToArrayBuffer({ readable: nodeReadable });
|
|
* ```
|
|
*
|
|
* @param readable - The Node.js Readable stream whose data will be consumed.
|
|
* @returns A Promise that resolves to an `ArrayBuffer` containing all the data from the stream.
|
|
*/
|
|
static async consumeToArrayBuffer({ readable }) {
|
|
const arrayBuffer = await Convert.asyncIterable(readable).toArrayBufferAsync();
|
|
return arrayBuffer;
|
|
}
|
|
/**
|
|
* Consumes a `Readable` stream and returns its contents as a `Blob`.
|
|
*
|
|
* This method reads all data from a Node.js `Readable` stream, collects it, and converts it into
|
|
* a `Blob`.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const nodeReadable = getReadableStreamSomehow();
|
|
* const blob = await NodeStream.consumeToBlob({ readable: nodeReadable });
|
|
* ```
|
|
*
|
|
* @param readableStream - The Node.js `Readable` stream whose data will be consumed.
|
|
* @returns A Promise that resolves to a `Blob` containing all the data from the stream.
|
|
*/
|
|
static async consumeToBlob({ readable }) {
|
|
const blob = await Convert.asyncIterable(readable).toBlobAsync();
|
|
return blob;
|
|
}
|
|
/**
|
|
* Consumes a `Readable` stream and returns its contents as a `Uint8Array`.
|
|
*
|
|
* This method reads all data from a Node.js `Readable`, collects it, and converts it into a
|
|
* `Uint8Array`.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const nodeReadable = getReadableStreamSomehow();
|
|
* const bytes = await NodeStream.consumeToBytes({ readable: nodeReadable });
|
|
* ```
|
|
*
|
|
* @param readableStream - The Node.js `Readable` stream whose data will be consumed.
|
|
* @returns A Promise that resolves to a `Uint8Array` containing all the data from the stream.
|
|
*/
|
|
static async consumeToBytes({ readable }) {
|
|
const bytes = await Convert.asyncIterable(readable).toUint8ArrayAsync();
|
|
return bytes;
|
|
}
|
|
/**
|
|
* Consumes a `Readable` stream and parses its contents as JSON.
|
|
*
|
|
* This method reads all the data from the stream, converts it to a text string, and then parses
|
|
* it as JSON, returning the resulting object.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const nodeReadable = getReadableStreamSomehow();
|
|
* const jsonData = await NodeStream.consumeToJson({ readable: nodeReadable });
|
|
* ```
|
|
*
|
|
* @param readableStream - The Node.js `Readable` stream whose JSON content will be consumed.
|
|
* @returns A Promise that resolves to the parsed JSON object from the stream's data.
|
|
*/
|
|
static async consumeToJson({ readable }) {
|
|
const object = await Convert.asyncIterable(readable).toObjectAsync();
|
|
return object;
|
|
}
|
|
/**
|
|
* Consumes a `Readable` stream and returns its contents as a text string.
|
|
*
|
|
* This method reads all the data from the stream, converting it into a single string.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const nodeReadable = getReadableStreamSomehow();
|
|
* const text = await NodeStream.consumeToText({ readable: nodeReadable });
|
|
* ```
|
|
*
|
|
* @param readableStream - The Node.js `Readable` stream whose text content will be consumed.
|
|
* @returns A Promise that resolves to a string containing all the data from the stream.
|
|
*/
|
|
static async consumeToText({ readable }) {
|
|
const text = await Convert.asyncIterable(readable).toStringAsync();
|
|
return text;
|
|
}
|
|
/**
|
|
* Converts a Web `ReadableStream` to a Node.js `Readable` stream.
|
|
*
|
|
* This method takes a Web `ReadableStream` and converts it to a Node.js `Readable` stream.
|
|
* The conversion is done by reading chunks from the Web `ReadableStream` and pushing them
|
|
* into the Node.js `Readable` stream.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const webReadableStream = getWebReadableStreamSomehow();
|
|
* const nodeReadableStream = NodeStream.fromWebReadable({ readableStream: webReadableStream });
|
|
* ```
|
|
*
|
|
* @param readableStream - The Web `ReadableStream` to be converted.
|
|
* @param readableOptions - Optional `Readable` stream options for the Node.js stream.
|
|
* @returns The Node.js `Readable` stream.
|
|
*/
|
|
static fromWebReadable({ readableStream, readableOptions }) {
|
|
if (!Stream.isReadableStream(readableStream)) {
|
|
throw new TypeError(`NodeStream.fromWebReadable: 'readableStream' is not a Web ReadableStream.`);
|
|
}
|
|
const reader = readableStream.getReader();
|
|
let closed = false;
|
|
const nodeReadable = new import_readable_stream.Readable({
|
|
...readableOptions,
|
|
read: function() {
|
|
reader.read().then(({ done, value }) => {
|
|
if (done) {
|
|
this.push(null);
|
|
} else {
|
|
if (!this.push(value)) {
|
|
return;
|
|
}
|
|
}
|
|
}).catch((error) => {
|
|
this.destroy(error);
|
|
});
|
|
},
|
|
destroy: function(error, callback) {
|
|
function done() {
|
|
callback(error);
|
|
}
|
|
if (!closed) {
|
|
reader.cancel(error).then(done).catch(done);
|
|
return;
|
|
}
|
|
done();
|
|
}
|
|
});
|
|
reader.closed.then(() => {
|
|
closed = true;
|
|
}).catch((error) => {
|
|
closed = true;
|
|
nodeReadable.destroy(error);
|
|
});
|
|
return nodeReadable;
|
|
}
|
|
/**
|
|
* Checks if a Node.js stream (`Readable`, `Writable`, `Duplex`, or `Transform`) has been destroyed.
|
|
*
|
|
* This method determines whether the provided Node.js stream has been destroyed. A stream
|
|
* is considered destroyed if its 'destroyed' property is set to true or if its internal state
|
|
* indicates it has been destroyed.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const stream = getStreamSomehow();
|
|
* stream.destroy(); // Destroy the stream.
|
|
* const isDestroyed = NodeStream.isDestroyed({ stream });
|
|
* console.log(isDestroyed); // Output: true
|
|
* ```
|
|
*
|
|
* @param stream - The Node.js stream to check.
|
|
* @returns `true` if the stream has been destroyed; otherwise, `false`.
|
|
*/
|
|
static isDestroyed({ stream }) {
|
|
if (!_NodeStream.isStream(stream)) {
|
|
throw new TypeError(`NodeStream.isDestroyed: 'stream' is not a Node stream.`);
|
|
}
|
|
const writableState = "_writableState" in stream ? stream._writableState : void 0;
|
|
const readableState = stream._readableState;
|
|
const state = writableState || readableState;
|
|
return !!(stream.destroyed || state.destroyed);
|
|
}
|
|
/**
|
|
* Checks if a Node.js `Readable` stream is still readable.
|
|
*
|
|
* This method checks if a Node.js `Readable` stream is still in a state that allows reading from
|
|
* it. A stream is considered readable if it has not ended, has not been destroyed, and is not
|
|
* currently paused.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const readableStream = new Readable();
|
|
* const isReadable = NodeStream.isReadable({ readable: readableStream });
|
|
* console.log(isReadable); // Output: true or false
|
|
* ```
|
|
*
|
|
* @param readable - The Node.js `Readable` stream to be checked.
|
|
* @returns `true` if the stream is still readable; otherwise, `false`.
|
|
*/
|
|
static isReadable({ readable }) {
|
|
if (!_NodeStream.isReadableStream(readable)) {
|
|
return false;
|
|
}
|
|
return readable.readable && // Is the stream readable?
|
|
(typeof readable._readableState.ended === "boolean" && !readable._readableState.ended) && // Has the 'end' method been called?
|
|
(typeof readable._readableState.endEmitted === "boolean" && !readable._readableState.endEmitted) && // Has the 'end' event been emitted?
|
|
!readable.destroyed && // Has the 'destroy' method been called?
|
|
!readable.isPaused();
|
|
}
|
|
/**
|
|
* Checks if an object is a Node.js `Readable` stream.
|
|
*
|
|
* This method verifies if the provided object is a Node.js `Readable` stream by checking for
|
|
* specific properties and methods typical of a `Readable` stream in Node.js.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const obj = getSomeObject();
|
|
* if (NodeStream.isReadableStream(obj)) {
|
|
* // obj is a Node.js Readable stream
|
|
* }
|
|
* ```
|
|
*
|
|
* @param obj - The object to be checked.
|
|
* @returns `true` if `obj` is a Node.js `Readable` stream; otherwise, `false`.
|
|
*/
|
|
static isReadableStream(obj) {
|
|
return typeof obj === "object" && obj !== null && ("pipe" in obj && typeof obj.pipe === "function") && ("on" in obj && typeof obj.on === "function") && (!("_writableState" in obj) && "_readableState" in obj);
|
|
}
|
|
/**
|
|
* Checks if the provided object is a Node.js stream (`Duplex`, `Readable`, `Writable`, or `Transform`).
|
|
*
|
|
* This method checks for the presence of internal properties specific to Node.js streams:
|
|
* `_readableState` and `_writableState`. These properties are present in Node.js stream
|
|
* instances, allowing identification of the stream type.
|
|
*
|
|
* The `_readableState` property is found in `Readable` and `Duplex` streams (including
|
|
* `Transform` streams, which are a type of `Duplex` stream), indicating that the stream can be
|
|
* read from. The `_writableState` property is found in `Writable` and `Duplex` streams,
|
|
* indicating that the stream can be written to.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const { Readable, Writable, Duplex, Transform } = require('stream');
|
|
*
|
|
* const readableStream = new Readable();
|
|
* console.log(NodeStream.isStream(readableStream)); // Output: true
|
|
*
|
|
* const writableStream = new Writable();
|
|
* console.log(NodeStream.isStream(writableStream)); // Output: true
|
|
*
|
|
* const duplexStream = new Duplex();
|
|
* console.log(NodeStream.isStream(duplexStream)); // Output: true
|
|
*
|
|
* const transformStream = new Transform();
|
|
* console.log(NodeStream.isStream(transformStream)); // Output: true
|
|
*
|
|
* const nonStreamObject = {};
|
|
* console.log(NodeStream.isStream(nonStreamObject)); // Output: false
|
|
* ```
|
|
*
|
|
* @remarks
|
|
* - This method does not differentiate between the different types of streams (Readable,
|
|
* Writable, Duplex, Transform). It simply checks if the object is any kind of Node.js stream.
|
|
* - While this method can identify standard Node.js streams, it may not recognize custom or
|
|
* third-party stream-like objects that do not inherit directly from Node.js's stream classes
|
|
* or do not have these internal state properties. This is intentional as many of the methods
|
|
* in this library are designed to work with standard Node.js streams.
|
|
*
|
|
* @param obj - The object to be checked for being a Node.js stream.
|
|
* @returns `true` if the object is a Node.js stream (`Duplex`, `Readable`, `Writable`, or `Transform`); otherwise, `false`.
|
|
*/
|
|
static isStream(obj) {
|
|
return typeof obj === "object" && obj !== null && ("_readableState" in obj || "_writableState" in obj);
|
|
}
|
|
/**
|
|
* Converts a Node.js `Readable` stream to a Web `ReadableStream`.
|
|
*
|
|
* This method provides a bridge between Node.js streams and the Web Streams API by converting a
|
|
* Node.js `Readable` stream into a Web `ReadableStream`. It listens for 'data', 'end', and 'error'
|
|
* events on the Node.js stream and appropriately enqueues data, closes, or errors the Web
|
|
* `ReadableStream`.
|
|
*
|
|
* If the Node.js stream is already destroyed, the method returns an immediately cancelled
|
|
* Web `ReadableStream`.
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const nodeReadable = getNodeReadableStreamSomehow();
|
|
* const webReadableStream = NodeStream.toWebReadable({ readable: nodeReadable });
|
|
* ```
|
|
*
|
|
* @param readable - The Node.js `Readable` stream to be converted.
|
|
* @returns A Web `ReadableStream` corresponding to the provided Node.js `Readable` stream.
|
|
* @throws TypeError if `readable` is not a Node.js `Readable` stream.
|
|
* @throws Error if the Node.js `Readable` stream is already destroyed.
|
|
*/
|
|
static toWebReadable({ readable }) {
|
|
if (!_NodeStream.isReadableStream(readable)) {
|
|
throw new TypeError(`NodeStream.toWebReadable: 'readable' is not a Node Readable stream.`);
|
|
}
|
|
if (_NodeStream.isDestroyed({ stream: readable })) {
|
|
const readable2 = new ReadableStream();
|
|
readable2.cancel();
|
|
return readable2;
|
|
}
|
|
return new ReadableStream({
|
|
start(controller) {
|
|
readable.on("data", (chunk) => {
|
|
controller.enqueue(chunk);
|
|
});
|
|
readable.on("end", () => {
|
|
controller.close();
|
|
});
|
|
readable.on("error", (err) => {
|
|
controller.error(err);
|
|
});
|
|
},
|
|
cancel() {
|
|
readable.destroy();
|
|
}
|
|
});
|
|
}
|
|
};
|
|
// Annotate the CommonJS export names for ESM import in node:
|
|
0 && (module.exports = {
|
|
Convert,
|
|
LevelStore,
|
|
MemoryStore,
|
|
Multicodec,
|
|
NodeStream,
|
|
Readable,
|
|
Stream,
|
|
TtlCache,
|
|
isArrayBufferSlice,
|
|
isAsyncIterable,
|
|
isDefined,
|
|
isEmptyObject,
|
|
removeEmptyObjects,
|
|
removeUndefinedProperties,
|
|
universalTypeOf
|
|
});
|
|
//# sourceMappingURL=index.js.map
|