Browse Source

Major updates to many files.

pull/1/head
Qortal Dev 2 months ago
parent
commit
715a25e582
  1. 2
      index.d.ts
  2. 12
      index.ts
  3. 2
      package.json
  4. 51
      src/QortalRequest/Profile.ts
  5. 62
      src/QortalRequest/Qapps/Qfund.ts
  6. 28
      src/QortalRequest/Search.ts
  7. 30
      src/QortalRequest/SendCoin.ts
  8. 29
      src/QortalRequest/Utils/Interfaces/Responses.ts
  9. 22
      src/QortalRequest/Utils/Types.ts
  10. 57
      src/QortalRequest/general.ts
  11. 4
      src/QortalRequest/getFromAddress.ts
  12. 8
      src/QortalRequest/getFromName.ts
  13. 42
      src/QortalRequest/getFromSelf.ts
  14. 12
      src/QortalRequest/setFromSelf.ts
  15. 0
      src/Utils/Numbers/Colors.ts
  16. 0
      src/Utils/Numbers/NumberConversion.ts
  17. 4
      src/Utils/Numbers/Numbers.ts
  18. 0
      src/Utils/Numbers/StringNumbers.ts
  19. 184
      src/Utils/PublishFormatter.ts
  20. 0
      src/Utils/Strings/printFunctions.ts
  21. 13
      src/Utils/Strings/stringFunctions.ts
  22. 3
      src/global.d.ts

2
index.d.ts vendored

@ -10,7 +10,7 @@ export * from "./dist/src/QortalRequest/Utils/Types";
export * from "./dist/src/QortalRequest/getFromAddress"; export * from "./dist/src/QortalRequest/getFromAddress";
export * from "./dist/src/QortalRequest/getFromSelf"; export * from "./dist/src/QortalRequest/getFromSelf";
export * from "./dist/src/QortalRequest/setFromSelf"; export * from "./dist/src/QortalRequest/profile";
export * from "./dist/src/QortalRequest/SendCoin"; export * from "./dist/src/QortalRequest/SendCoin";
export * from "./dist/src/QortalRequest/Transactions"; export * from "./dist/src/QortalRequest/Transactions";
export * from "./dist/src/QortalRequest/general" export * from "./dist/src/QortalRequest/general"

12
index.ts

@ -1,8 +1,8 @@
export * from "./src/TypescriptUtils/Numbers/Colors"; export * from "./src/Utils/Numbers/Colors";
export * from "./src/TypescriptUtils/Numbers/NumberConversion"; export * from "./src/Utils/Numbers/NumberConversion";
export * from "./src/TypescriptUtils/Numbers/Numbers"; export * from "./src/Utils/Numbers/Numbers";
export * from "./src/TypescriptUtils/Numbers/StringNumbers"; export * from "./src/Utils/Numbers/StringNumbers";
export * from "./src/TypescriptUtils/Strings/printFunctions"; export * from "./src/Utils/Strings/printFunctions";
export * from "./src/QortalRequest/Utils/Interfaces/Responses"; export * from "./src/QortalRequest/Utils/Interfaces/Responses";
export * from "./src/QortalRequest/Utils/Interfaces/Parameters"; export * from "./src/QortalRequest/Utils/Interfaces/Parameters";
@ -10,7 +10,7 @@ export * from "./src/QortalRequest/Utils/Types";
export * from "./src/QortalRequest/getFromAddress"; export * from "./src/QortalRequest/getFromAddress";
export * from "./src/QortalRequest/getFromSelf"; export * from "./src/QortalRequest/getFromSelf";
export * from "./src/QortalRequest/setFromSelf"; export * from "./src/QortalRequest/profile";
export * from "./src/QortalRequest/SendCoin"; export * from "./src/QortalRequest/SendCoin";
export * from "./src/QortalRequest/Transactions"; export * from "./src/QortalRequest/Transactions";
export * from "./src/QortalRequest/general"; export * from "./src/QortalRequest/general";

2
package.json

@ -1,6 +1,6 @@
{ {
"name": "qortal-app-utils", "name": "qortal-app-utils",
"version": "1.4.0", "version": "1.5.0",
"description": "A series of convenience functions that perform common tasks, especially those that interact with the Qortal blockchain", "description": "A series of convenience functions that perform common tasks, especially those that interact with the Qortal blockchain",
"keywords": [ "keywords": [
"Qortal", "Qortal",

51
src/QortalRequest/Profile.ts

@ -0,0 +1,51 @@
// returns {error: "Cannot find requested data"} if data isn't found
import { ProfileCoinType } from "./Utils/Types.ts";
export const getProfileData = async (property: string) => {
return (await qortalRequest({
action: "GET_PROFILE_DATA",
property,
})) as string | object;
};
export const setProfileData = async (
property: string,
data: object,
encrypt = false
) => {
if (encrypt) property += "-private";
return (await qortalRequest({
action: "SET_PROFILE_DATA",
property,
data: { customData: data },
})) as string;
};
export const setDefaultProfileData = async (
property: string,
data: object,
encrypt = false
) => {
if (encrypt) property += "-private";
return (await qortalRequest({
action: "SET_PROFILE_DATA",
property,
data,
})) as string;
};
export const getProfileWallet = async (coin: ProfileCoinType) => {
return await getProfileData("wallets")[coin];
};
export const setProfileWallet = async (wallet: object) => {
return await setProfileData("wallets", wallet);
};
export const summonProfileModal = async () => {
return (await qortalRequest({
action: "SET_PROFILE_DATA",
property: "wallets",
data: {},
})) as string;
};

62
src/QortalRequest/Qapps/Qfund.ts

@ -0,0 +1,62 @@
export const hasQFundEnded = async (atAddress: string) => {
try {
const url = `/at/${atAddress}`;
const response = await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
if (response.status === 200) {
const responseDataSearch = await response.json();
if (
Object.keys(responseDataSearch).length > 0 &&
responseDataSearch?.isFinished
) {
return true;
} else {
return false;
}
}
} catch (error) {
console.log(error);
}
};
export const getATAmount = async crowdfundLink => {
const crowdfund = await getCrowdfund(crowdfundLink);
const atAddress = crowdfund?.deployedAT?.aTAddress;
if (!atAddress) return 0;
try {
const res = await qortalRequest({
action: "SEARCH_TRANSACTIONS",
txType: ["PAYMENT"],
confirmationStatus: "CONFIRMED",
address: atAddress,
limit: 0,
reverse: true,
});
if (res?.length > 0) {
const totalAmount: number = res.reduce(
(total: number, transaction) => total + parseFloat(transaction.amount),
0
);
return totalAmount;
}
} catch (e) {
console.log(e);
return 0;
}
};
export const getCrowdfund = async (crowdfundLink: string) => {
const splitLink = crowdfundLink.split("/");
const name = splitLink[5];
const identifier = splitLink[6];
return await qortalRequest({
action: "FETCH_QDN_RESOURCE",
service: "DOCUMENT",
name,
identifier,
});
};

28
src/QortalRequest/Search.ts

@ -0,0 +1,28 @@
import { SearchResourcesResponse } from "./Utils/Interfaces/Responses.ts";
export const fetchResourcesByIdentifier = async <T>(
service: string,
identifier: string
) => {
const names: SearchResourcesResponse[] = await qortalRequest({
action: "SEARCH_QDN_RESOURCES",
service,
identifier,
includeMetadata: false,
});
const distinctNames = names.filter(
(searchResponse, index) => names.indexOf(searchResponse) === index
);
const promises: Promise<T>[] = [];
distinctNames.map(response => {
const resource: Promise<T> = qortalRequest({
action: "FETCH_QDN_RESOURCE",
name: response.name,
service,
identifier,
});
promises.push(resource);
});
return (await Promise.all(promises)) as T[];
};

30
src/QortalRequest/SendCoin.ts

@ -1,22 +1,48 @@
import { CoinType } from "./Utils/Types"; import { CoinType } from "./Utils/Types";
import { SendCoinResponse } from "./Utils/Interfaces/Responses.ts";
export const sendCoin = async ( export const sendCoin = async (
address: string, address: string,
amount: number, amount: number,
coin: CoinType coin: CoinType
) => { ) => {
return qortalRequest({ try {
return (await qortalRequest({
action: "SEND_COIN", action: "SEND_COIN",
coin, coin,
destinationAddress: address, destinationAddress: address,
amount, amount,
}); })) as SendCoinResponse;
} catch (e) {
console.log("sendCoin refused", e);
}
}; };
export const sendQORT = async (address: string, amount: number) => { export const sendQORT = async (address: string, amount: number) => {
return await sendCoin(address, amount, "QORT"); return await sendCoin(address, amount, "QORT");
}; };
export interface NameData {
name: string;
reducedName: string;
owner: string;
data: string;
registered: number;
isForSale: boolean;
}
export const getNameData = async (name: string) => {
return qortalRequest({
action: "GET_NAME_DATA",
name: name,
}) as Promise<NameData>;
};
export const sendQORTtoName = async (name: string, amount: number) => {
const address = await getNameData(name);
if (address) return await sendQORT(address.owner, amount);
else throw Error("Name Not Found");
};
export const sendBitCoin = async (address: string, amount: number) => { export const sendBitCoin = async (address: string, amount: number) => {
return await sendCoin(address, amount, "BTC"); return await sendCoin(address, amount, "BTC");
}; };

29
src/QortalRequest/Utils/Interfaces/Responses.ts

@ -33,3 +33,32 @@ export interface DaySummaryResponse {
totalTransactionCount: number; totalTransactionCount: number;
transactionCountByType: SummaryTransactionCounts; transactionCountByType: SummaryTransactionCounts;
} }
export interface MetaData {
title: string;
description: string;
tags: string[];
mimeType: string;
}
export interface SearchResourcesResponse {
name: string;
service: string;
identifier: string;
metadata?: MetaData;
size: number;
created: number;
updated: number;
}
export interface SendCoinResponse {
amount: number;
approvalStatus: string;
fee: string;
recipient: string;
reference: string;
senderPublicKey: string;
signature: string;
timestamp: number;
txGroupId: number;
type: string;
}

22
src/QortalRequest/Utils/Types.ts

@ -42,12 +42,18 @@ export type TransactionType =
| "TRANSFER_PRIVS" | "TRANSFER_PRIVS"
| "PRESENCE"; | "PRESENCE";
export type CoinType = "QORT" | "BTC" | "LTC" | "DOGE" | "DGB" | "RVN" | "ARRR"; export const Coins = ["QORT", "BTC", "LTC", "DOGE", "DGB", "RVN", "ARRR"];
export type CoinType = (typeof Coins)[number];
export type BlockchainType = export const ProfileCoins = ["btc", "ltc", "doge", "dgb", "rvn", "arrr"];
| "BITCOIN" export type ProfileCoinType = (typeof ProfileCoins)[number];
| "LITECOIN" export const Blockchains = [
| "DODGECOIN" "BITCOIN",
| "DIGIBYTE" "LITECOIN",
| "RAVENCOIN" "DOGECOIN",
| "PIRATECHAIN"; "DIGIBYTE",
"RAVENCOIN",
"PIRATECHAIN",
];
export type BlockchainType = (typeof Blockchains)[number];

57
src/QortalRequest/general.ts

@ -1,6 +1,8 @@
import { DaySummaryResponse } from "./Utils/Interfaces/Responses.ts"; import { DaySummaryResponse } from "./Utils/Interfaces/Responses.ts";
import { BlockchainType } from "./Utils/Types.ts"; import { Blockchains, BlockchainType } from "./Utils/Types.ts";
import { truncateNumber } from "../TypescriptUtils/Numbers/StringNumbers.ts"; import { truncateNumber } from "../Utils/Numbers/StringNumbers.ts";
import { getNameData } from "./SendCoin.ts";
import { getUserAccountNames } from "./getFromSelf.ts";
export const getDaySummary = async () => { export const getDaySummary = async () => {
return (await qortalRequest({ return (await qortalRequest({
@ -32,16 +34,59 @@ export const getDurationFromBlocks = async (blocks: number) => {
}); });
}; };
export const getPrice = async ( export const getPriceAsNumber = async (
blockchainName: BlockchainType, blockchainName: BlockchainType,
tradesToInclude = 10, tradesToInclude = 10
isQortRatio = true
) => { ) => {
const response = (await qortalRequest({ const response = (await qortalRequest({
action: "GET_PRICE", action: "GET_PRICE",
blockchain: blockchainName, blockchain: blockchainName,
maxTrades: tradesToInclude, maxTrades: tradesToInclude,
inverse: isQortRatio, inverse: true,
})) as number; })) as number;
return response / 1e8; return response / 1e8;
}; };
type BlockchainPrice = { name: BlockchainType; price: number };
const getPriceAsObject = async (
chain: BlockchainType,
tradesToInclude: number
) => {
return { name: chain, price: await getPriceAsNumber(chain, tradesToInclude) };
};
export const getPricesAsObject = async (
chains: BlockchainType[],
tradesToInclude = 10
) => {
return await Promise.all(
chains.map(async (chain: BlockchainType) => {
return getPriceAsObject(chain, tradesToInclude);
})
);
};
export const sendQchatDM = async (
recipientName: string,
message: string,
allowSelfAsRecipient = false
) => {
if (!allowSelfAsRecipient) {
const userAccountNames = await getUserAccountNames();
const userNames = userAccountNames.map(name => name.name);
if (userNames.includes(recipientName)) return;
}
const address = await getNameData(recipientName);
try {
return await qortalRequest({
action: "SEND_CHAT_MESSAGE",
destinationAddress: address.owner,
message,
});
} catch (e) {
console.log(e);
return false;
}
};

4
src/QortalRequest/getFromAddress.ts

@ -1,4 +1,4 @@
import { stringIsEmpty } from "../TypescriptUtils/Numbers/StringNumbers"; import { stringIsEmpty } from "../Utils/Numbers/StringNumbers";
import { GetRequestData } from "./Utils/Interfaces/Parameters.ts"; import { GetRequestData } from "./Utils/Interfaces/Parameters.ts";
type AccountName = { name: string; owner: string }; type AccountName = { name: string; owner: string };
@ -8,7 +8,7 @@ export const getAccountNames = async (
) => { ) => {
const names = (await qortalRequest({ const names = (await qortalRequest({
action: "GET_ACCOUNT_NAMES", action: "GET_ACCOUNT_NAMES",
address, address: address,
...params, ...params,
})) as AccountName[]; })) as AccountName[];

8
src/QortalRequest/getFromName.ts

@ -0,0 +1,8 @@
export const getAvatarFromName = async (name: string) => {
return await qortalRequest({
action: "GET_QDN_RESOURCE_URL",
name,
service: "THUMBNAIL",
identifier: "qortal_avatar",
});
};

42
src/QortalRequest/getFromSelf.ts

@ -1,5 +1,6 @@
import { getBalance } from "./getFromAddress"; import { getBalance } from "./getFromAddress";
import { CoinType } from "./Utils/Types"; import { CoinType } from "./Utils/Types";
import { GetRequestData } from "./Utils/Interfaces/Parameters.ts";
export const getWalletBalance = async (coin: CoinType) => { export const getWalletBalance = async (coin: CoinType) => {
return (await qortalRequest({ return (await qortalRequest({
@ -21,16 +22,45 @@ export const getForeignWallet = async (coin: CoinType) => {
coin, coin,
})) as AccountInfo; })) as AccountInfo;
}; };
export const stringIsEmpty = (value: string) => {
return value === "";
};
export type AccountName = { name: string; owner: string };
export const getAccountNames = async (
address: string,
params?: GetRequestData
) => {
const names = (await qortalRequest({
action: "GET_ACCOUNT_NAMES",
address: address,
...params,
})) as AccountName[];
const namelessAddress = { name: "", owner: address };
const emptyNamesFilled = names.map(({ name, owner }) => {
return stringIsEmpty(name) ? namelessAddress : { name, owner };
});
const returnValue =
emptyNamesFilled.length > 0 ? emptyNamesFilled : [namelessAddress];
return returnValue as AccountName[];
};
export const getUserAccount = async () => { export const getUserAccount = async () => {
return (await qortalRequest({ return (await qortalRequest({
action: "GET_USER_ACCOUNT", action: "GET_USER_ACCOUNT",
})) as AccountInfo; })) as AccountInfo;
}; };
// returns {error: "Cannot find requested data"} if data isn't found export const getUserAccountNames = async () => {
export const getProfileData = async (property: string) => { const account = await getUserAccount();
return (await qortalRequest({ return await getAccountNames(account.address);
action: "GET_PROFILE_DATA", };
property,
})) as string | object; export const userHasName = async (name: string) => {
const userAccountNames = await getUserAccountNames();
const userNames = userAccountNames.map(userName => userName.name);
return userNames.includes(name);
}; };

12
src/QortalRequest/setFromSelf.ts

@ -1,12 +0,0 @@
export const setProfileData = async (
property: string,
data: object,
encrypt = false
) => {
if (encrypt) property += "-private";
return (await qortalRequest({
action: "SET_PROFILE_DATA",
property,
data: { customData: data },
})) as string;
};

0
src/TypescriptUtils/Numbers/Colors.ts → src/Utils/Numbers/Colors.ts

0
src/TypescriptUtils/Numbers/NumberConversion.ts → src/Utils/Numbers/NumberConversion.ts

4
src/TypescriptUtils/Numbers/Numbers.ts → src/Utils/Numbers/Numbers.ts

@ -7,3 +7,7 @@ export const setNumberWithinBounds = (
if (num < minValue) return minValue; if (num < minValue) return minValue;
return num; return num;
}; };
export const numberToInt = (num: number) => {
return Math.floor(num);
};

0
src/TypescriptUtils/Numbers/StringNumbers.ts → src/Utils/Numbers/StringNumbers.ts

184
src/Utils/PublishFormatter.ts

@ -0,0 +1,184 @@
export const publishFormatter = (
file: File
): Promise<string | ArrayBuffer | null> =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
const result = reader.result;
reader.onload = null; // remove onload handler
reader.onerror = null; // remove onerror handler
resolve(result);
};
reader.onerror = error => {
reader.onload = null; // remove onload handler
reader.onerror = null; // remove onerror handler
reject(error);
};
});
export function objectToBase64(obj: any) {
// Step 1: Convert the object to a JSON string
const jsonString = JSON.stringify(obj);
// Step 2: Create a Blob from the JSON string
const blob = new Blob([jsonString], { type: "application/json" });
// Step 3: Create a FileReader to read the Blob as a base64-encoded string
return new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => {
if (typeof reader.result === "string") {
// Remove 'data:application/json;base64,' prefix
const base64 = reader.result.replace(
"data:application/json;base64,",
""
);
resolve(base64);
} else {
reject(new Error("Failed to read the Blob as a base64-encoded string"));
}
};
reader.onerror = () => {
reject(reader.error);
};
reader.readAsDataURL(blob);
});
}
export function objectToFile(obj: any) {
// Step 1: Convert the object to a JSON string
const jsonString = JSON.stringify(obj);
// Step 2: Create a Blob from the JSON string
return new Blob([jsonString], { type: "application/json" });
}
export function objectToUint8Array(obj: any) {
// Convert the object to a JSON string
const jsonString = JSON.stringify(obj);
// Encode the JSON string as a byte array using TextEncoder
const encoder = new TextEncoder();
const byteArray = encoder.encode(jsonString);
// Create a new Uint8Array and set its content to the encoded byte array
const uint8Array = new Uint8Array(byteArray);
return uint8Array;
}
export function uint8ArrayToBase64(uint8Array: Uint8Array): string {
const length = uint8Array.length;
let binaryString = "";
const chunkSize = 1024 * 1024; // Process 1MB at a time
for (let i = 0; i < length; i += chunkSize) {
const chunkEnd = Math.min(i + chunkSize, length);
const chunk = uint8Array.subarray(i, chunkEnd);
binaryString += Array.from(chunk, byte => String.fromCharCode(byte)).join(
""
);
}
return btoa(binaryString);
}
export function objectToUint8ArrayFromResponse(obj: any) {
const len = Object.keys(obj).length;
const result = new Uint8Array(len);
for (let i = 0; i < len; i++) {
result[i] = obj[i];
}
return result;
}
// export function uint8ArrayToBase64(arrayBuffer: Uint8Array): string {
// let binary = ''
// const bytes = new Uint8Array(arrayBuffer)
// const len = bytes.length
// for (let i = 0; i < len; i++) {
// binary += String.fromCharCode(bytes[i])
// }
// return btoa(binary)
// }
export function base64ToUint8Array(base64: string) {
const binaryString = atob(base64);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes;
}
export function uint8ArrayToObject(uint8Array: Uint8Array) {
// Decode the byte array using TextDecoder
const decoder = new TextDecoder();
const jsonString = decoder.decode(uint8Array);
// Convert the JSON string back into an object
const obj = JSON.parse(jsonString);
return obj;
}
export function processFileInChunks(file: File): Promise<Uint8Array> {
return new Promise(
(resolve: (value: Uint8Array) => void, reject: (reason?: any) => void) => {
const reader = new FileReader();
reader.onload = function (event: ProgressEvent<FileReader>) {
const arrayBuffer = event.target?.result as ArrayBuffer;
const uint8Array = new Uint8Array(arrayBuffer);
resolve(uint8Array);
};
reader.onerror = function (error: ProgressEvent<FileReader>) {
reject(error);
};
reader.readAsArrayBuffer(file);
}
);
}
// export async function processFileInChunks(file: File, chunkSize = 1024 * 1024): Promise<Uint8Array> {
// const fileStream = file.stream();
// const reader = fileStream.getReader();
// const totalLength = file.size;
// if (totalLength <= 0 || isNaN(totalLength)) {
// throw new Error('Invalid file size');
// }
// const combinedArray = new Uint8Array(totalLength);
// let offset = 0;
// while (offset < totalLength) {
// const { value, done } = await reader.read();
// if (done) {
// break;
// }
// const chunk = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
// // Set elements one by one instead of using combinedArray.set(chunk, offset)
// for (let i = 0; i < chunk.length; i++) {
// combinedArray[offset + i] = chunk[i];
// }
// offset += chunk.length;
// }
// return combinedArray;
// }

0
src/TypescriptUtils/Strings/printFunctions.ts → src/Utils/Strings/printFunctions.ts

13
src/Utils/Strings/stringFunctions.ts

@ -0,0 +1,13 @@
export const getFileExtensionIndex = (s: string) => {
const lastIndex = s.lastIndexOf(".");
return lastIndex > 0 ? lastIndex : s.length - 1;
};
export const getFileName = (s: string) => {
return s.substring(0, getFileExtensionIndex(s));
};
export const isNumber = (input: string) => {
const num = Number(input);
return !isNaN(num);
};

3
src/global.d.ts vendored

@ -99,6 +99,7 @@ interface QortalRequestOptions {
maxTrades?: number; maxTrades?: number;
inverse?: boolean; inverse?: boolean;
property?: string; property?: string;
data?: { customData: object }; data?: { customData?: object };
message?: string;
} }
declare function qortalRequest(options: QortalRequestOptions): Promise<any>; declare function qortalRequest(options: QortalRequestOptions): Promise<any>;

Loading…
Cancel
Save