UNPKG

near-sdk-js

Version:

High Level JavaScript SDK for building smart contracts on NEAR

283 lines (282 loc) 10.6 kB
import { cloneDeep } from "lodash-es"; const TYPE_KEY = "typeInfo"; var TypeBrand; (function (TypeBrand) { TypeBrand["BIGINT"] = "bigint"; TypeBrand["DATE"] = "date"; })(TypeBrand || (TypeBrand = {})); export const ERR_INCONSISTENT_STATE = "The collection is an inconsistent state. Did previous smart contract execution terminate unexpectedly?"; export const ERR_INDEX_OUT_OF_BOUNDS = "Index out of bounds"; const ACCOUNT_ID_REGEX = /^(([a-z\d]+[-_])*[a-z\d]+\.)*([a-z\d]+[-_])*[a-z\d]+$/; /** * Concat two Uint8Array * @param array1 * @param array2 * @returns the concatenation of two array */ export function concat(array1, array2) { const mergedArray = new Uint8Array(array1.length + array2.length); mergedArray.set(array1); mergedArray.set(array2, array1.length); return mergedArray; } /** * Asserts that the expression passed to the function is truthy, otherwise throws a new Error with the provided message. * * @param expression - The expression to be asserted. * @param message - The error message to be printed. */ export function assert(expression, message) { if (!expression) { throw new Error("assertion failed: " + message); } } export function getValueWithOptions(subDatatype, value, options = { deserializer: deserialize, }) { if (value === null) { return options?.defaultValue ?? null; } // here is an obj let deserialized = deserialize(value); if (deserialized === undefined || deserialized === null) { return options?.defaultValue ?? null; } if (options?.reconstructor) { // example: // { collection: {reconstructor: LookupMap.reconstruct, value: 'string'}} const collection = options.reconstructor(deserialized); if (subDatatype !== undefined && // eslint-disable-next-line no-prototype-builtins subDatatype.hasOwnProperty("class") && // eslint-disable-next-line no-prototype-builtins subDatatype["class"].hasOwnProperty("value")) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore collection.subtype = function () { // example: {class: UnorderedMap, value: UnorderedMap} return subDatatype["class"]["value"]; }; } return collection; } // example: { collection: {reconstructor: LookupMap.reconstruct, value: 'string'}} if (subDatatype !== undefined) { // subtype info is a class constructor, Such as Car if (typeof subDatatype === "function") { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore deserialized = decodeObj2class(new subDatatype(), deserialized); } else if (typeof subDatatype === "object") { // normal collections of array, map; subtype will be: // {map: { key: 'string', value: 'string' }} or {array: {value: 'string'}} .. // eslint-disable-next-line no-prototype-builtins if (subDatatype.hasOwnProperty("map")) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore for (const mkey in deserialized) { if (subDatatype["map"]["value"] !== "string") { deserialized[mkey] = decodeObj2class(new subDatatype["map"]["value"](), value[mkey]); } } // eslint-disable-next-line no-prototype-builtins } else if (subDatatype.hasOwnProperty("array")) { const new_vec = []; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore for (const k in deserialized) { if (subDatatype["array"]["value"] !== "string") { new_vec.push(decodeObj2class(new subDatatype["array"]["value"](), value[k])); } } deserialized = new_vec; // eslint-disable-next-line no-prototype-builtins } } } return deserialized; } export function serializeValueWithOptions(value, { serializer } = { serializer: serialize, }) { return serializer(value); } export function serialize(valueToSerialize) { return encode(JSON.stringify(valueToSerialize, function (key, value) { if (typeof value === "bigint") { return { value: value.toString(), [TYPE_KEY]: TypeBrand.BIGINT, }; } if (typeof this[key] === "object" && this[key] !== null && this[key] instanceof Date) { return { value: this[key].toISOString(), [TYPE_KEY]: TypeBrand.DATE, }; } return value; })); } export function deserialize(valueToDeserialize) { return JSON.parse(decode(valueToDeserialize), (_, value) => { if (value !== null && typeof value === "object" && Object.keys(value).length === 2 && Object.keys(value).every((key) => ["value", TYPE_KEY].includes(key))) { switch (value[TYPE_KEY]) { case TypeBrand.BIGINT: return BigInt(value["value"]); case TypeBrand.DATE: return new Date(value["value"]); } } return value; }); } export function decodeObj2class(class_instance, obj) { if (typeof obj != "object" || typeof obj === "bigint" || obj instanceof Date || class_instance.constructor.schema === undefined) { return obj; } let key; for (key in obj) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const value = obj[key]; if (typeof value == "object") { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const ty = class_instance.constructor.schema[key]; // eslint-disable-next-line no-prototype-builtins if (ty !== undefined && ty.hasOwnProperty("map")) { for (const mkey in value) { if (ty["map"]["value"] === "string") { class_instance[key][mkey] = value[mkey]; } else { class_instance[key][mkey] = decodeObj2class(new ty["map"]["value"](), value[mkey]); } } // eslint-disable-next-line no-prototype-builtins } else if (ty !== undefined && ty.hasOwnProperty("array")) { for (const k in value) { if (ty["array"]["value"] === "string") { class_instance[key].push(value[k]); } else { class_instance[key].push(decodeObj2class(new ty["array"]["value"](), value[k])); } } // eslint-disable-next-line no-prototype-builtins } else if (ty !== undefined && ty.hasOwnProperty("class")) { // => nested_lookup_recordes: {class: UnorderedMap, value: {class: LookupMap }}, class_instance[key] = ty["class"].reconstruct(obj[key]); // eslint-disable-next-line no-prototype-builtins if (ty.hasOwnProperty("value")) { const subtype_value = ty["value"]; class_instance[key].subtype = function () { // example: { collection: {reconstructor: LookupMap.reconstruct, value: 'string'}} // example: UnorderedMap or {class: UnorderedMap, value: 'string'} return subtype_value; }; } } else if (ty !== undefined && typeof ty.reconstruct === "function") { class_instance[key] = ty.reconstruct(obj[key]); } else { // normal case with nested Class, such as field is truck: Truck, class_instance[key] = decodeObj2class(class_instance[key], obj[key]); } } else { class_instance[key] = obj[key]; } } const instance_tmp = cloneDeep(class_instance); for (key in obj) { if (typeof class_instance[key] == "object" && !(class_instance[key] instanceof Date)) { class_instance[key] = instance_tmp[key]; } } return class_instance; } /** * Validates the Account ID according to the NEAR protocol * [Account ID rules](https://nomicon.io/DataStructures/Account#account-id-rules). * * @param accountId - The Account ID string you want to validate. */ export function validateAccountId(accountId) { return (accountId.length >= 2 && accountId.length <= 64 && ACCOUNT_ID_REGEX.test(accountId)); } /** * A subset of NodeJS TextEncoder API */ export class TextEncoder { encode(s) { return env.utf8_string_to_uint8array(s); } } /** * A subset of NodeJS TextDecoder API. Only support utf-8 and latin1 encoding. */ export class TextDecoder { constructor(encoding = "utf-8") { this.encoding = encoding; } decode(a) { if (this.encoding == "utf-8") { return env.uint8array_to_utf8_string(a); } else if (this.encoding == "latin1") { return env.uint8array_to_latin1_string(a); } else { throw new Error("unsupported encoding: " + this.encoding); } } } /** * Convert a string to Uint8Array, each character must have a char code between 0-255. * @param s - string that with only Latin1 character to convert * @returns result Uint8Array */ export function bytes(s) { return env.latin1_string_to_uint8array(s); } /** * Convert a Uint8Array to string, each uint8 to the single character of that char code * @param a - Uint8Array to convert * @returns result string */ export function str(a) { return env.uint8array_to_latin1_string(a); } /** * Encode the string to Uint8Array with UTF-8 encoding * @param s - String to encode * @returns result Uint8Array */ export function encode(s) { return env.utf8_string_to_uint8array(s); } /** * Decode the Uint8Array to string in UTF-8 encoding * @param a - array to decode * @returns result string */ export function decode(a) { return env.uint8array_to_utf8_string(a); }