Files
boris/node_modules/@cashu/cashu-ts/dist/lib/es5/utils.js
Gigi 5d53a827e0 feat: initialize markr nostr bookmark client
- Add project structure with TypeScript, React, and Vite
- Implement nostr authentication using browser extension (NIP-07)
- Add NIP-51 compliant bookmark fetching and display
- Create minimal UI with login and bookmark components
- Integrate applesauce-core and applesauce-react libraries
- Add responsive styling with dark/light mode support
- Include comprehensive README with setup instructions

This is a minimal MVP for a nostr bookmark client that allows users to
view their bookmarks according to NIP-51 specification.
2025-10-02 07:17:07 +02:00

345 lines
12 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodePaymentRequest = exports.sumProofs = exports.sanitizeUrl = exports.joinUrls = exports.checkResponse = exports.isObj = exports.sortProofsById = exports.mergeUInt8Arrays = exports.deriveKeysetId = exports.handleTokens = exports.getDecodedToken = exports.getEncodedTokenV4 = exports.getEncodedToken = exports.getEncodedTokenV3 = exports.bigIntStringify = exports.hasNonHexId = exports.hexToNumber = exports.bytesToNumber = exports.hasCorrespondingKey = exports.getKeysetAmounts = exports.getKeepAmounts = exports.splitAmount = void 0;
var base64_js_1 = require("./base64.js");
var Constants_js_1 = require("./utils/Constants.js");
var utils_1 = require("@noble/curves/abstract/utils");
var sha256_1 = require("@noble/hashes/sha256");
var cbor_js_1 = require("./cbor.js");
var PaymentRequest_js_1 = require("./model/PaymentRequest.js");
/**
* Splits the amount into denominations of the provided @param keyset
* @param value amount to split
* @param keyset keys to look up split amounts
* @param split? optional custom split amounts
* @param order? optional order for split amounts (default: "asc")
* @returns Array of split amounts
* @throws Error if @param split amount is greater than @param value amount
*/
function splitAmount(value, keyset, split, order) {
if (split) {
if (split.reduce(function (a, b) { return a + b; }, 0) > value) {
throw new Error("Split is greater than total amount: ".concat(split.reduce(function (a, b) { return a + b; }, 0), " > ").concat(value));
}
split.forEach(function (amt) {
if (!hasCorrespondingKey(amt, keyset)) {
throw new Error('Provided amount preferences do not match the amounts of the mint keyset.');
}
});
value =
value -
split.reduce(function (curr, acc) {
return curr + acc;
}, 0);
}
else {
split = [];
}
var sortedKeyAmounts = getKeysetAmounts(keyset);
sortedKeyAmounts.forEach(function (amt) {
var q = Math.floor(value / amt);
for (var i = 0; i < q; ++i)
split === null || split === void 0 ? void 0 : split.push(amt);
value %= amt;
});
return split.sort(function (a, b) { return (order === 'desc' ? b - a : a - b); });
}
exports.splitAmount = splitAmount;
/**
* Creates a list of amounts to keep based on the proofs we have and the proofs we want to reach.
* @param proofsWeHave complete set of proofs stored (from current mint)
* @param amountToKeep amount to keep
* @param keys keys of current keyset
* @param targetCount the target number of proofs to reach
* @returns an array of amounts to keep
*/
function getKeepAmounts(proofsWeHave, amountToKeep, keys, targetCount) {
// determines amounts we need to reach the targetCount for each amount based on the amounts of the proofs we have
// it tries to select amounts so that the proofs we have and the proofs we want reach the targetCount
var amountsWeWant = [];
var amountsWeHave = proofsWeHave.map(function (p) { return p.amount; });
var sortedKeyAmounts = getKeysetAmounts(keys, 'asc');
sortedKeyAmounts.forEach(function (amt) {
var countWeHave = amountsWeHave.filter(function (a) { return a === amt; }).length;
var countWeWant = Math.max(targetCount - countWeHave, 0);
for (var i = 0; i < countWeWant; ++i) {
if (amountsWeWant.reduce(function (a, b) { return a + b; }, 0) + amt > amountToKeep) {
break;
}
amountsWeWant.push(amt);
}
});
// use splitAmount to fill the rest between the sum of amountsWeHave and amountToKeep
var amountDiff = amountToKeep - amountsWeWant.reduce(function (a, b) { return a + b; }, 0);
if (amountDiff) {
var remainingAmounts = splitAmount(amountDiff, keys);
remainingAmounts.forEach(function (amt) {
amountsWeWant.push(amt);
});
}
var sortedAmountsWeWant = amountsWeWant.sort(function (a, b) { return a - b; });
return sortedAmountsWeWant;
}
exports.getKeepAmounts = getKeepAmounts;
/**
* returns the amounts in the keyset sorted by the order specified
* @param keyset to search in
* @param order order to sort the amounts in
* @returns the amounts in the keyset sorted by the order specified
*/
function getKeysetAmounts(keyset, order) {
if (order === void 0) { order = 'desc'; }
if (order == 'desc') {
return Object.keys(keyset)
.map(function (k) { return parseInt(k); })
.sort(function (a, b) { return b - a; });
}
return Object.keys(keyset)
.map(function (k) { return parseInt(k); })
.sort(function (a, b) { return a - b; });
}
exports.getKeysetAmounts = getKeysetAmounts;
/**
* Checks if the provided amount is in the keyset.
* @param amount amount to check
* @param keyset to search in
* @returns true if the amount is in the keyset, false otherwise
*/
function hasCorrespondingKey(amount, keyset) {
return amount in keyset;
}
exports.hasCorrespondingKey = hasCorrespondingKey;
/**
* Converts a bytes array to a number.
* @param bytes to convert to number
* @returns number
*/
function bytesToNumber(bytes) {
return hexToNumber((0, utils_1.bytesToHex)(bytes));
}
exports.bytesToNumber = bytesToNumber;
/**
* Converts a hex string to a number.
* @param hex to convert to number
* @returns number
*/
function hexToNumber(hex) {
return BigInt("0x".concat(hex));
}
exports.hexToNumber = hexToNumber;
function isValidHex(str) {
return /^[a-f0-9]*$/i.test(str);
}
/**
* Checks wether a proof or a list of proofs contains a non-hex id
* @param p Proof or list of proofs
* @returns boolean
*/
function hasNonHexId(p) {
if (Array.isArray(p)) {
return p.some(function (proof) { return !isValidHex(proof.id); });
}
return isValidHex(p.id);
}
exports.hasNonHexId = hasNonHexId;
//used for json serialization
function bigIntStringify(_key, value) {
return typeof value === 'bigint' ? value.toString() : value;
}
exports.bigIntStringify = bigIntStringify;
/**
* Helper function to encode a v3 cashu token
* @param token to encode
* @returns encoded token
*/
function getEncodedTokenV3(token) {
var v3TokenObj = { token: [{ mint: token.mint, proofs: token.proofs }] };
if (token.unit) {
v3TokenObj.unit = token.unit;
}
if (token.memo) {
v3TokenObj.memo = token.memo;
}
return Constants_js_1.TOKEN_PREFIX + Constants_js_1.TOKEN_VERSION + (0, base64_js_1.encodeJsonToBase64)(v3TokenObj);
}
exports.getEncodedTokenV3 = getEncodedTokenV3;
/**
* Helper function to encode a cashu token (defaults to v4 if keyset id allows it)
* @param token
* @param [opts]
*/
function getEncodedToken(token, opts) {
var nonHex = hasNonHexId(token.proofs);
if (nonHex || (opts === null || opts === void 0 ? void 0 : opts.version) === 3) {
if ((opts === null || opts === void 0 ? void 0 : opts.version) === 4) {
throw new Error('can not encode to v4 token if proofs contain non-hex keyset id');
}
return getEncodedTokenV3(token);
}
return getEncodedTokenV4(token);
}
exports.getEncodedToken = getEncodedToken;
function getEncodedTokenV4(token) {
var nonHex = hasNonHexId(token.proofs);
if (nonHex) {
throw new Error('can not encode to v4 token if proofs contain non-hex keyset id');
}
var idMap = {};
var mint = token.mint;
for (var i = 0; i < token.proofs.length; i++) {
var proof = token.proofs[i];
if (idMap[proof.id]) {
idMap[proof.id].push(proof);
}
else {
idMap[proof.id] = [proof];
}
}
var tokenTemplate = {
m: mint,
u: token.unit || 'sat',
t: Object.keys(idMap).map(function (id) { return ({
i: (0, utils_1.hexToBytes)(id),
p: idMap[id].map(function (p) { return ({ a: p.amount, s: p.secret, c: (0, utils_1.hexToBytes)(p.C) }); })
}); })
};
if (token.memo) {
tokenTemplate.d = token.memo;
}
var encodedData = (0, cbor_js_1.encodeCBOR)(tokenTemplate);
var prefix = 'cashu';
var version = 'B';
var base64Data = (0, base64_js_1.encodeUint8toBase64Url)(encodedData);
return prefix + version + base64Data;
}
exports.getEncodedTokenV4 = getEncodedTokenV4;
/**
* Helper function to decode cashu tokens into object
* @param token an encoded cashu token (cashuAey...)
* @returns cashu token object
*/
function getDecodedToken(token) {
// remove prefixes
var uriPrefixes = ['web+cashu://', 'cashu://', 'cashu:', 'cashu'];
uriPrefixes.forEach(function (prefix) {
if (!token.startsWith(prefix)) {
return;
}
token = token.slice(prefix.length);
});
return handleTokens(token);
}
exports.getDecodedToken = getDecodedToken;
/**
* Helper function to decode different versions of cashu tokens into an object
* @param token an encoded cashu token (cashuAey...)
* @returns cashu Token object
*/
function handleTokens(token) {
var version = token.slice(0, 1);
var encodedToken = token.slice(1);
if (version === 'A') {
var parsedV3Token = (0, base64_js_1.encodeBase64ToJson)(encodedToken);
if (parsedV3Token.token.length > 1) {
throw new Error('Multi entry token are not supported');
}
var entry = parsedV3Token.token[0];
var tokenObj = {
mint: entry.mint,
proofs: entry.proofs,
unit: parsedV3Token.unit || 'sat'
};
if (parsedV3Token.memo) {
tokenObj.memo = parsedV3Token.memo;
}
return tokenObj;
}
else if (version === 'B') {
var uInt8Token = (0, base64_js_1.encodeBase64toUint8)(encodedToken);
var tokenData = (0, cbor_js_1.decodeCBOR)(uInt8Token);
var proofs_1 = [];
tokenData.t.forEach(function (t) {
return t.p.forEach(function (p) {
proofs_1.push({
secret: p.s,
C: (0, utils_1.bytesToHex)(p.c),
amount: p.a,
id: (0, utils_1.bytesToHex)(t.i)
});
});
});
var decodedToken = { mint: tokenData.m, proofs: proofs_1, unit: tokenData.u || 'sat' };
if (tokenData.d) {
decodedToken.memo = tokenData.d;
}
return decodedToken;
}
throw new Error('Token version is not supported');
}
exports.handleTokens = handleTokens;
/**
* Returns the keyset id of a set of keys
* @param keys keys object to derive keyset id from
* @returns
*/
function deriveKeysetId(keys) {
var pubkeysConcat = Object.entries(keys)
.sort(function (a, b) { return +a[0] - +b[0]; })
.map(function (_a) {
var pubKey = _a[1];
return (0, utils_1.hexToBytes)(pubKey);
})
.reduce(function (prev, curr) { return mergeUInt8Arrays(prev, curr); }, new Uint8Array());
var hash = (0, sha256_1.sha256)(pubkeysConcat);
var hashHex = Buffer.from(hash).toString('hex').slice(0, 14);
return '00' + hashHex;
}
exports.deriveKeysetId = deriveKeysetId;
function mergeUInt8Arrays(a1, a2) {
// sum of individual array lengths
var mergedArray = new Uint8Array(a1.length + a2.length);
mergedArray.set(a1);
mergedArray.set(a2, a1.length);
return mergedArray;
}
exports.mergeUInt8Arrays = mergeUInt8Arrays;
function sortProofsById(proofs) {
return proofs.sort(function (a, b) { return a.id.localeCompare(b.id); });
}
exports.sortProofsById = sortProofsById;
function isObj(v) {
return typeof v === 'object';
}
exports.isObj = isObj;
function checkResponse(data) {
if (!isObj(data))
return;
if ('error' in data && data.error) {
throw new Error(data.error);
}
if ('detail' in data && data.detail) {
throw new Error(data.detail);
}
}
exports.checkResponse = checkResponse;
function joinUrls() {
var parts = [];
for (var _i = 0; _i < arguments.length; _i++) {
parts[_i] = arguments[_i];
}
return parts.map(function (part) { return part.replace(/(^\/+|\/+$)/g, ''); }).join('/');
}
exports.joinUrls = joinUrls;
function sanitizeUrl(url) {
return url.replace(/\/$/, '');
}
exports.sanitizeUrl = sanitizeUrl;
function sumProofs(proofs) {
return proofs.reduce(function (acc, proof) { return acc + proof.amount; }, 0);
}
exports.sumProofs = sumProofs;
function decodePaymentRequest(paymentRequest) {
return PaymentRequest_js_1.PaymentRequest.fromEncodedRequest(paymentRequest);
}
exports.decodePaymentRequest = decodePaymentRequest;