mirror of
https://github.com/mempool/mempool.git
synced 2024-11-19 01:41:01 +01:00
Merge branch 'master' into natsoni/block-first-seen-audit
This commit is contained in:
commit
6884830da6
@ -27,6 +27,7 @@
|
|||||||
"AUTOMATIC_POOLS_UPDATE": false,
|
"AUTOMATIC_POOLS_UPDATE": false,
|
||||||
"POOLS_JSON_URL": "https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json",
|
"POOLS_JSON_URL": "https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json",
|
||||||
"POOLS_JSON_TREE_URL": "https://api.github.com/repos/mempool/mining-pools/git/trees/master",
|
"POOLS_JSON_TREE_URL": "https://api.github.com/repos/mempool/mining-pools/git/trees/master",
|
||||||
|
"POOLS_UPDATE_DELAY": 604800,
|
||||||
"AUDIT": false,
|
"AUDIT": false,
|
||||||
"RUST_GBT": true,
|
"RUST_GBT": true,
|
||||||
"LIMIT_GBT": false,
|
"LIMIT_GBT": false,
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"INDEXING_BLOCKS_AMOUNT": 14,
|
"INDEXING_BLOCKS_AMOUNT": 14,
|
||||||
"POOLS_JSON_TREE_URL": "__MEMPOOL_POOLS_JSON_TREE_URL__",
|
"POOLS_JSON_TREE_URL": "__MEMPOOL_POOLS_JSON_TREE_URL__",
|
||||||
"POOLS_JSON_URL": "__MEMPOOL_POOLS_JSON_URL__",
|
"POOLS_JSON_URL": "__MEMPOOL_POOLS_JSON_URL__",
|
||||||
|
"POOLS_UPDATE_DELAY": 604800,
|
||||||
"AUDIT": true,
|
"AUDIT": true,
|
||||||
"RUST_GBT": false,
|
"RUST_GBT": false,
|
||||||
"LIMIT_GBT": false,
|
"LIMIT_GBT": false,
|
||||||
|
@ -41,6 +41,7 @@ describe('Mempool Backend Config', () => {
|
|||||||
STDOUT_LOG_MIN_PRIORITY: 'debug',
|
STDOUT_LOG_MIN_PRIORITY: 'debug',
|
||||||
POOLS_JSON_TREE_URL: 'https://api.github.com/repos/mempool/mining-pools/git/trees/master',
|
POOLS_JSON_TREE_URL: 'https://api.github.com/repos/mempool/mining-pools/git/trees/master',
|
||||||
POOLS_JSON_URL: 'https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json',
|
POOLS_JSON_URL: 'https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json',
|
||||||
|
POOLS_UPDATE_DELAY: 604800,
|
||||||
AUDIT: false,
|
AUDIT: false,
|
||||||
RUST_GBT: true,
|
RUST_GBT: true,
|
||||||
LIMIT_GBT: false,
|
LIMIT_GBT: false,
|
||||||
|
@ -32,6 +32,7 @@ interface IConfig {
|
|||||||
AUTOMATIC_POOLS_UPDATE: boolean;
|
AUTOMATIC_POOLS_UPDATE: boolean;
|
||||||
POOLS_JSON_URL: string,
|
POOLS_JSON_URL: string,
|
||||||
POOLS_JSON_TREE_URL: string,
|
POOLS_JSON_TREE_URL: string,
|
||||||
|
POOLS_UPDATE_DELAY: number,
|
||||||
AUDIT: boolean;
|
AUDIT: boolean;
|
||||||
RUST_GBT: boolean;
|
RUST_GBT: boolean;
|
||||||
LIMIT_GBT: boolean;
|
LIMIT_GBT: boolean;
|
||||||
@ -193,6 +194,7 @@ const defaults: IConfig = {
|
|||||||
'AUTOMATIC_POOLS_UPDATE': false,
|
'AUTOMATIC_POOLS_UPDATE': false,
|
||||||
'POOLS_JSON_URL': 'https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json',
|
'POOLS_JSON_URL': 'https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json',
|
||||||
'POOLS_JSON_TREE_URL': 'https://api.github.com/repos/mempool/mining-pools/git/trees/master',
|
'POOLS_JSON_TREE_URL': 'https://api.github.com/repos/mempool/mining-pools/git/trees/master',
|
||||||
|
'POOLS_UPDATE_DELAY': 604800, // in seconds, default is one week
|
||||||
'AUDIT': false,
|
'AUDIT': false,
|
||||||
'RUST_GBT': true,
|
'RUST_GBT': true,
|
||||||
'LIMIT_GBT': false,
|
'LIMIT_GBT': false,
|
||||||
|
@ -211,6 +211,8 @@ class Server {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
poolsUpdater.$startService();
|
||||||
}
|
}
|
||||||
|
|
||||||
async runMainUpdateLoop(): Promise<void> {
|
async runMainUpdateLoop(): Promise<void> {
|
||||||
|
@ -6,16 +6,30 @@ import backendInfo from '../api/backend-info';
|
|||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
import { SocksProxyAgent } from 'socks-proxy-agent';
|
import { SocksProxyAgent } from 'socks-proxy-agent';
|
||||||
import * as https from 'https';
|
import * as https from 'https';
|
||||||
|
import { Common } from '../api/common';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintain the most recent version of pools-v2.json
|
* Maintain the most recent version of pools-v2.json
|
||||||
*/
|
*/
|
||||||
class PoolsUpdater {
|
class PoolsUpdater {
|
||||||
|
tag = 'PoolsUpdater';
|
||||||
|
|
||||||
lastRun: number = 0;
|
lastRun: number = 0;
|
||||||
currentSha: string | null = null;
|
currentSha: string | null = null;
|
||||||
poolsUrl: string = config.MEMPOOL.POOLS_JSON_URL;
|
poolsUrl: string = config.MEMPOOL.POOLS_JSON_URL;
|
||||||
treeUrl: string = config.MEMPOOL.POOLS_JSON_TREE_URL;
|
treeUrl: string = config.MEMPOOL.POOLS_JSON_TREE_URL;
|
||||||
|
|
||||||
|
public async $startService(): Promise<void> {
|
||||||
|
while ('Bitcoin is still alive') {
|
||||||
|
try {
|
||||||
|
await this.updatePoolsJson();
|
||||||
|
} catch (e: any) {
|
||||||
|
logger.info(`Exception ${e} in PoolsUpdater::$startService. Code: ${e.code}. Message: ${e.message}`, this.tag);
|
||||||
|
}
|
||||||
|
await Common.sleep$(10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async updatePoolsJson(): Promise<void> {
|
public async updatePoolsJson(): Promise<void> {
|
||||||
if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === false ||
|
if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === false ||
|
||||||
config.MEMPOOL.ENABLED === false
|
config.MEMPOOL.ENABLED === false
|
||||||
@ -23,11 +37,8 @@ class PoolsUpdater {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const oneWeek = 604800;
|
|
||||||
const oneDay = 86400;
|
|
||||||
|
|
||||||
const now = new Date().getTime() / 1000;
|
const now = new Date().getTime() / 1000;
|
||||||
if (now - this.lastRun < oneWeek) { // Execute the PoolsUpdate only once a week, or upon restart
|
if (now - this.lastRun < config.MEMPOOL.POOLS_UPDATE_DELAY) { // Execute the PoolsUpdate only once a week, or upon restart
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +54,7 @@ class PoolsUpdater {
|
|||||||
this.currentSha = await this.getShaFromDb();
|
this.currentSha = await this.getShaFromDb();
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(`pools-v2.json sha | Current: ${this.currentSha} | Github: ${githubSha}`);
|
logger.debug(`pools-v2.json sha | Current: ${this.currentSha} | Github: ${githubSha}`, this.tag);
|
||||||
if (this.currentSha !== null && this.currentSha === githubSha) {
|
if (this.currentSha !== null && this.currentSha === githubSha) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -53,16 +64,16 @@ class PoolsUpdater {
|
|||||||
config.MEMPOOL.AUTOMATIC_POOLS_UPDATE !== true && // Automatic pools update is disabled
|
config.MEMPOOL.AUTOMATIC_POOLS_UPDATE !== true && // Automatic pools update is disabled
|
||||||
!process.env.npm_config_update_pools // We're not manually updating mining pool
|
!process.env.npm_config_update_pools // We're not manually updating mining pool
|
||||||
) {
|
) {
|
||||||
logger.warn(`Updated mining pools data is available (${githubSha}) but AUTOMATIC_POOLS_UPDATE is disabled`);
|
logger.warn(`Updated mining pools data is available (${githubSha}) but AUTOMATIC_POOLS_UPDATE is disabled`, this.tag);
|
||||||
logger.info(`You can update your mining pools using the --update-pools command flag. You may want to clear your nginx cache as well if applicable`);
|
logger.info(`You can update your mining pools using the --update-pools command flag. You may want to clear your nginx cache as well if applicable`, this.tag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const network = config.SOCKS5PROXY.ENABLED ? 'tor' : 'clearnet';
|
const network = config.SOCKS5PROXY.ENABLED ? 'tor' : 'clearnet';
|
||||||
if (this.currentSha === null) {
|
if (this.currentSha === null) {
|
||||||
logger.info(`Downloading pools-v2.json for the first time from ${this.poolsUrl} over ${network}`, logger.tags.mining);
|
logger.info(`Downloading pools-v2.json for the first time from ${this.poolsUrl} over ${network}`, this.tag);
|
||||||
} else {
|
} else {
|
||||||
logger.warn(`pools-v2.json is outdated, fetching latest from ${this.poolsUrl} over ${network}`, logger.tags.mining);
|
logger.warn(`pools-v2.json is outdated, fetching latest from ${this.poolsUrl} over ${network}`, this.tag);
|
||||||
}
|
}
|
||||||
const poolsJson = await this.query(this.poolsUrl);
|
const poolsJson = await this.query(this.poolsUrl);
|
||||||
if (poolsJson === undefined) {
|
if (poolsJson === undefined) {
|
||||||
@ -71,7 +82,7 @@ class PoolsUpdater {
|
|||||||
poolsParser.setMiningPools(poolsJson);
|
poolsParser.setMiningPools(poolsJson);
|
||||||
|
|
||||||
if (config.DATABASE.ENABLED === false) { // Don't run db operations
|
if (config.DATABASE.ENABLED === false) { // Don't run db operations
|
||||||
logger.info(`Mining pools-v2.json (${githubSha}) import completed (no database)`);
|
logger.info(`Mining pools-v2.json (${githubSha}) import completed (no database)`, this.tag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,14 +92,14 @@ class PoolsUpdater {
|
|||||||
await this.updateDBSha(githubSha);
|
await this.updateDBSha(githubSha);
|
||||||
await DB.query('COMMIT;');
|
await DB.query('COMMIT;');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.err(`Could not migrate mining pools, rolling back. Exception: ${JSON.stringify(e)}`, logger.tags.mining);
|
logger.err(`Could not migrate mining pools, rolling back. Exception: ${JSON.stringify(e)}`, this.tag);
|
||||||
await DB.query('ROLLBACK;');
|
await DB.query('ROLLBACK;');
|
||||||
}
|
}
|
||||||
logger.info(`Mining pools-v2.json (${githubSha}) import completed`);
|
logger.info(`Mining pools-v2.json (${githubSha}) import completed`, this.tag);
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.lastRun = now - (oneWeek - oneDay); // Try again in 24h instead of waiting next week
|
this.lastRun = now - 600; // Try again in 10 minutes
|
||||||
logger.err(`PoolsUpdater failed. Will try again in 24h. Exception: ${JSON.stringify(e)}`, logger.tags.mining);
|
logger.err(`PoolsUpdater failed. Will try again in 10 minutes. Exception: ${JSON.stringify(e)}`, this.tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +113,7 @@ class PoolsUpdater {
|
|||||||
await DB.query('DELETE FROM state where name="pools_json_sha"');
|
await DB.query('DELETE FROM state where name="pools_json_sha"');
|
||||||
await DB.query(`INSERT INTO state VALUES('pools_json_sha', NULL, '${githubSha}')`);
|
await DB.query(`INSERT INTO state VALUES('pools_json_sha', NULL, '${githubSha}')`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.err('Cannot save github pools-v2.json sha into the db. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining);
|
logger.err('Cannot save github pools-v2.json sha into the db. Reason: ' + (e instanceof Error ? e.message : e), this.tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,7 +126,7 @@ class PoolsUpdater {
|
|||||||
const [rows]: any[] = await DB.query('SELECT string FROM state WHERE name="pools_json_sha"');
|
const [rows]: any[] = await DB.query('SELECT string FROM state WHERE name="pools_json_sha"');
|
||||||
return (rows.length > 0 ? rows[0].string : null);
|
return (rows.length > 0 ? rows[0].string : null);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.err('Cannot fetch pools-v2.json sha from db. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining);
|
logger.err('Cannot fetch pools-v2.json sha from db. Reason: ' + (e instanceof Error ? e.message : e), this.tag);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,7 +145,7 @@ class PoolsUpdater {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.err(`Cannot find "pools-v2.json" in git tree (${this.treeUrl})`, logger.tags.mining);
|
logger.err(`Cannot find "pools-v2.json" in git tree (${this.treeUrl})`, this.tag);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +197,7 @@ class PoolsUpdater {
|
|||||||
}
|
}
|
||||||
return data.data;
|
return data.data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.err('Could not connect to Github. Reason: ' + (e instanceof Error ? e.message : e));
|
logger.err('Could not connect to Github. Reason: ' + (e instanceof Error ? e.message : e), this.tag);
|
||||||
retry++;
|
retry++;
|
||||||
}
|
}
|
||||||
await setDelay(config.MEMPOOL.EXTERNAL_RETRY_INTERVAL);
|
await setDelay(config.MEMPOOL.EXTERNAL_RETRY_INTERVAL);
|
||||||
|
@ -109,6 +109,7 @@ Below we list all settings from `mempool-config.json` and the corresponding over
|
|||||||
"AUTOMATIC_POOLS_UPDATE": false,
|
"AUTOMATIC_POOLS_UPDATE": false,
|
||||||
"POOLS_JSON_URL": "https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json",
|
"POOLS_JSON_URL": "https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json",
|
||||||
"POOLS_JSON_TREE_URL": "https://api.github.com/repos/mempool/mining-pools/git/trees/master",
|
"POOLS_JSON_TREE_URL": "https://api.github.com/repos/mempool/mining-pools/git/trees/master",
|
||||||
|
"POOLS_UPDATE_DELAY": 604800,
|
||||||
"CPFP_INDEXING": false,
|
"CPFP_INDEXING": false,
|
||||||
"MAX_BLOCKS_BULK_QUERY": 0,
|
"MAX_BLOCKS_BULK_QUERY": 0,
|
||||||
"DISK_CACHE_BLOCK_INTERVAL": 6,
|
"DISK_CACHE_BLOCK_INTERVAL": 6,
|
||||||
@ -140,6 +141,7 @@ Corresponding `docker-compose.yml` overrides:
|
|||||||
MEMPOOL_AUTOMATIC_POOLS_UPDATE: ""
|
MEMPOOL_AUTOMATIC_POOLS_UPDATE: ""
|
||||||
MEMPOOL_POOLS_JSON_URL: ""
|
MEMPOOL_POOLS_JSON_URL: ""
|
||||||
MEMPOOL_POOLS_JSON_TREE_URL: ""
|
MEMPOOL_POOLS_JSON_TREE_URL: ""
|
||||||
|
MEMPOOL_POOLS_UPDATE_DELAY: ""
|
||||||
MEMPOOL_CPFP_INDEXING: ""
|
MEMPOOL_CPFP_INDEXING: ""
|
||||||
MEMPOOL_MAX_BLOCKS_BULK_QUERY: ""
|
MEMPOOL_MAX_BLOCKS_BULK_QUERY: ""
|
||||||
MEMPOOL_DISK_CACHE_BLOCK_INTERVAL: ""
|
MEMPOOL_DISK_CACHE_BLOCK_INTERVAL: ""
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
"ALLOW_UNREACHABLE": __MEMPOOL_ALLOW_UNREACHABLE__,
|
"ALLOW_UNREACHABLE": __MEMPOOL_ALLOW_UNREACHABLE__,
|
||||||
"POOLS_JSON_TREE_URL": "__MEMPOOL_POOLS_JSON_TREE_URL__",
|
"POOLS_JSON_TREE_URL": "__MEMPOOL_POOLS_JSON_TREE_URL__",
|
||||||
"POOLS_JSON_URL": "__MEMPOOL_POOLS_JSON_URL__",
|
"POOLS_JSON_URL": "__MEMPOOL_POOLS_JSON_URL__",
|
||||||
|
"POOLS_UPDATE_DELAY": __MEMPOOL_POOLS_UPDATE_DELAY__,
|
||||||
"PRICE_UPDATES_PER_HOUR": __MEMPOOL_PRICE_UPDATES_PER_HOUR__,
|
"PRICE_UPDATES_PER_HOUR": __MEMPOOL_PRICE_UPDATES_PER_HOUR__,
|
||||||
"MAX_TRACKED_ADDRESSES": __MEMPOOL_MAX_TRACKED_ADDRESSES__
|
"MAX_TRACKED_ADDRESSES": __MEMPOOL_MAX_TRACKED_ADDRESSES__
|
||||||
},
|
},
|
||||||
|
@ -29,6 +29,7 @@ __MEMPOOL_STDOUT_LOG_MIN_PRIORITY__=${MEMPOOL_STDOUT_LOG_MIN_PRIORITY:=info}
|
|||||||
__MEMPOOL_AUTOMATIC_POOLS_UPDATE__=${MEMPOOL_AUTOMATIC_POOLS_UPDATE:=false}
|
__MEMPOOL_AUTOMATIC_POOLS_UPDATE__=${MEMPOOL_AUTOMATIC_POOLS_UPDATE:=false}
|
||||||
__MEMPOOL_POOLS_JSON_URL__=${MEMPOOL_POOLS_JSON_URL:=https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json}
|
__MEMPOOL_POOLS_JSON_URL__=${MEMPOOL_POOLS_JSON_URL:=https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json}
|
||||||
__MEMPOOL_POOLS_JSON_TREE_URL__=${MEMPOOL_POOLS_JSON_TREE_URL:=https://api.github.com/repos/mempool/mining-pools/git/trees/master}
|
__MEMPOOL_POOLS_JSON_TREE_URL__=${MEMPOOL_POOLS_JSON_TREE_URL:=https://api.github.com/repos/mempool/mining-pools/git/trees/master}
|
||||||
|
__MEMPOOL_POOLS_UPDATE_DELAY__=${MEMPOOL_POOLS_UPDATE_DELAY:=604800}
|
||||||
__MEMPOOL_AUDIT__=${MEMPOOL_AUDIT:=false}
|
__MEMPOOL_AUDIT__=${MEMPOOL_AUDIT:=false}
|
||||||
__MEMPOOL_RUST_GBT__=${MEMPOOL_RUST_GBT:=true}
|
__MEMPOOL_RUST_GBT__=${MEMPOOL_RUST_GBT:=true}
|
||||||
__MEMPOOL_LIMIT_GBT__=${MEMPOOL_LIMIT_GBT:=false}
|
__MEMPOOL_LIMIT_GBT__=${MEMPOOL_LIMIT_GBT:=false}
|
||||||
@ -188,6 +189,7 @@ sed -i "s!__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__!${__MEMPOOL_STDOUT_LOG_MIN_PRIORIT
|
|||||||
sed -i "s!__MEMPOOL_AUTOMATIC_POOLS_UPDATE__!${__MEMPOOL_AUTOMATIC_POOLS_UPDATE__}!g" mempool-config.json
|
sed -i "s!__MEMPOOL_AUTOMATIC_POOLS_UPDATE__!${__MEMPOOL_AUTOMATIC_POOLS_UPDATE__}!g" mempool-config.json
|
||||||
sed -i "s!__MEMPOOL_POOLS_JSON_URL__!${__MEMPOOL_POOLS_JSON_URL__}!g" mempool-config.json
|
sed -i "s!__MEMPOOL_POOLS_JSON_URL__!${__MEMPOOL_POOLS_JSON_URL__}!g" mempool-config.json
|
||||||
sed -i "s!__MEMPOOL_POOLS_JSON_TREE_URL__!${__MEMPOOL_POOLS_JSON_TREE_URL__}!g" mempool-config.json
|
sed -i "s!__MEMPOOL_POOLS_JSON_TREE_URL__!${__MEMPOOL_POOLS_JSON_TREE_URL__}!g" mempool-config.json
|
||||||
|
sed -i "s!__MEMPOOL_POOLS_UPDATE_DELAY__!${__MEMPOOL_POOLS_UPDATE_DELAY__}!g" mempool-config.json
|
||||||
sed -i "s!__MEMPOOL_AUDIT__!${__MEMPOOL_AUDIT__}!g" mempool-config.json
|
sed -i "s!__MEMPOOL_AUDIT__!${__MEMPOOL_AUDIT__}!g" mempool-config.json
|
||||||
sed -i "s!__MEMPOOL_RUST_GBT__!${__MEMPOOL_RUST_GBT__}!g" mempool-config.json
|
sed -i "s!__MEMPOOL_RUST_GBT__!${__MEMPOOL_RUST_GBT__}!g" mempool-config.json
|
||||||
sed -i "s!__MEMPOOL_LIMIT_GBT__!${__MEMPOOL_LIMIT_GBT__}!g" mempool-config.json
|
sed -i "s!__MEMPOOL_LIMIT_GBT__!${__MEMPOOL_LIMIT_GBT__}!g" mempool-config.json
|
||||||
|
495
frontend/package-lock.json
generated
495
frontend/package-lock.json
generated
@ -62,7 +62,7 @@
|
|||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@cypress/schematic": "^2.5.0",
|
"@cypress/schematic": "^2.5.0",
|
||||||
"@types/cypress": "^1.1.3",
|
"@types/cypress": "^1.1.3",
|
||||||
"cypress": "^13.14.0",
|
"cypress": "^13.15.0",
|
||||||
"cypress-fail-on-console-error": "~5.1.0",
|
"cypress-fail-on-console-error": "~5.1.0",
|
||||||
"cypress-wait-until": "^2.0.1",
|
"cypress-wait-until": "^2.0.1",
|
||||||
"mock-socket": "~9.3.1",
|
"mock-socket": "~9.3.1",
|
||||||
@ -3113,9 +3113,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@cypress/request": {
|
"node_modules/@cypress/request": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.5.tgz",
|
||||||
"integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==",
|
"integrity": "sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aws-sign2": "~0.7.0",
|
"aws-sign2": "~0.7.0",
|
||||||
@ -3124,14 +3124,14 @@
|
|||||||
"combined-stream": "~1.0.6",
|
"combined-stream": "~1.0.6",
|
||||||
"extend": "~3.0.2",
|
"extend": "~3.0.2",
|
||||||
"forever-agent": "~0.6.1",
|
"forever-agent": "~0.6.1",
|
||||||
"form-data": "~2.3.2",
|
"form-data": "~4.0.0",
|
||||||
"http-signature": "~1.3.6",
|
"http-signature": "~1.4.0",
|
||||||
"is-typedarray": "~1.0.0",
|
"is-typedarray": "~1.0.0",
|
||||||
"isstream": "~0.1.2",
|
"isstream": "~0.1.2",
|
||||||
"json-stringify-safe": "~5.0.1",
|
"json-stringify-safe": "~5.0.1",
|
||||||
"mime-types": "~2.1.19",
|
"mime-types": "~2.1.19",
|
||||||
"performance-now": "^2.1.0",
|
"performance-now": "^2.1.0",
|
||||||
"qs": "6.10.4",
|
"qs": "6.13.0",
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"tough-cookie": "^4.1.3",
|
"tough-cookie": "^4.1.3",
|
||||||
"tunnel-agent": "^0.6.0",
|
"tunnel-agent": "^0.6.0",
|
||||||
@ -4313,9 +4313,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
|
||||||
"integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==",
|
"integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -4325,9 +4325,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm64": {
|
"node_modules/@rollup/rollup-android-arm64": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz",
|
||||||
"integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==",
|
"integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -4337,9 +4337,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz",
|
||||||
"integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==",
|
"integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -4349,9 +4349,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-x64": {
|
"node_modules/@rollup/rollup-darwin-x64": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz",
|
||||||
"integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==",
|
"integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -4361,9 +4361,21 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz",
|
||||||
"integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==",
|
"integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||||
|
"version": "4.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz",
|
||||||
|
"integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
@ -4373,9 +4385,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz",
|
||||||
"integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==",
|
"integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -4385,9 +4397,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz",
|
||||||
"integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==",
|
"integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -4396,10 +4408,22 @@
|
|||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||||
|
"version": "4.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz",
|
||||||
|
"integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==",
|
||||||
|
"cpu": [
|
||||||
|
"ppc64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz",
|
||||||
"integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==",
|
"integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
@ -4408,10 +4432,22 @@
|
|||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||||
|
"version": "4.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz",
|
||||||
|
"integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==",
|
||||||
|
"cpu": [
|
||||||
|
"s390x"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz",
|
||||||
"integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==",
|
"integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -4421,9 +4457,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz",
|
||||||
"integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==",
|
"integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -4433,9 +4469,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz",
|
||||||
"integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==",
|
"integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@ -4445,9 +4481,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz",
|
||||||
"integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==",
|
"integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
@ -4457,9 +4493,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz",
|
||||||
"integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==",
|
"integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@ -4801,9 +4837,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/express": {
|
"node_modules/@types/express": {
|
||||||
"version": "4.17.13",
|
"version": "4.17.13",
|
||||||
@ -5797,9 +5833,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/aws4": {
|
"node_modules/aws4": {
|
||||||
"version": "1.12.0",
|
"version": "1.13.2",
|
||||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
|
||||||
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==",
|
"integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
@ -6065,20 +6101,6 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/body-parser/node_modules/qs": {
|
|
||||||
"version": "6.13.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
|
||||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
|
||||||
"dependencies": {
|
|
||||||
"side-channel": "^1.0.6"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/bonjour-service": {
|
"node_modules/bonjour-service": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz",
|
||||||
@ -8045,13 +8067,13 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/cypress": {
|
"node_modules/cypress": {
|
||||||
"version": "13.14.0",
|
"version": "13.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/cypress/-/cypress-13.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.0.tgz",
|
||||||
"integrity": "sha512-r0+nhd033x883YL6068futewUsl02Q7rWiinyAAIBDW/OOTn+UMILWgNuCiY3vtJjd53efOqq5R9dctQk/rKiw==",
|
"integrity": "sha512-53aO7PwOfi604qzOkCSzNlWquCynLlKE/rmmpSPcziRH6LNfaDUAklQT6WJIsD8ywxlIy+uVZsnTMCCQVd2kTw==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cypress/request": "^3.0.1",
|
"@cypress/request": "^3.0.4",
|
||||||
"@cypress/xvfb": "^1.2.4",
|
"@cypress/xvfb": "^1.2.4",
|
||||||
"@types/sinonjs__fake-timers": "8.1.1",
|
"@types/sinonjs__fake-timers": "8.1.1",
|
||||||
"@types/sizzle": "^2.3.2",
|
"@types/sizzle": "^2.3.2",
|
||||||
@ -9896,20 +9918,6 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/express/node_modules/qs": {
|
|
||||||
"version": "6.13.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
|
||||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
|
||||||
"dependencies": {
|
|
||||||
"side-channel": "^1.0.6"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/express/node_modules/safe-buffer": {
|
"node_modules/express/node_modules/safe-buffer": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
@ -10305,17 +10313,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/form-data": {
|
"node_modules/form-data": {
|
||||||
"version": "2.3.3",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.6",
|
"combined-stream": "^1.0.8",
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.12"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/forwarded": {
|
"node_modules/forwarded": {
|
||||||
@ -10957,14 +10965,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/http-signature": {
|
"node_modules/http-signature": {
|
||||||
"version": "1.3.6",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz",
|
||||||
"integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==",
|
"integrity": "sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"assert-plus": "^1.0.0",
|
"assert-plus": "^1.0.0",
|
||||||
"jsprim": "^2.0.2",
|
"jsprim": "^2.0.2",
|
||||||
"sshpk": "^1.14.1"
|
"sshpk": "^1.18.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10"
|
"node": ">=0.10"
|
||||||
@ -14737,12 +14745,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/qs": {
|
"node_modules/qs": {
|
||||||
"version": "6.10.4",
|
"version": "6.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||||
"integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==",
|
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
@ -15198,11 +15205,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz",
|
||||||
"integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==",
|
"integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "1.0.5"
|
"@types/estree": "1.0.6"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
@ -15212,19 +15219,22 @@
|
|||||||
"npm": ">=8.0.0"
|
"npm": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-android-arm-eabi": "4.13.0",
|
"@rollup/rollup-android-arm-eabi": "4.24.0",
|
||||||
"@rollup/rollup-android-arm64": "4.13.0",
|
"@rollup/rollup-android-arm64": "4.24.0",
|
||||||
"@rollup/rollup-darwin-arm64": "4.13.0",
|
"@rollup/rollup-darwin-arm64": "4.24.0",
|
||||||
"@rollup/rollup-darwin-x64": "4.13.0",
|
"@rollup/rollup-darwin-x64": "4.24.0",
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": "4.13.0",
|
"@rollup/rollup-linux-arm-gnueabihf": "4.24.0",
|
||||||
"@rollup/rollup-linux-arm64-gnu": "4.13.0",
|
"@rollup/rollup-linux-arm-musleabihf": "4.24.0",
|
||||||
"@rollup/rollup-linux-arm64-musl": "4.13.0",
|
"@rollup/rollup-linux-arm64-gnu": "4.24.0",
|
||||||
"@rollup/rollup-linux-riscv64-gnu": "4.13.0",
|
"@rollup/rollup-linux-arm64-musl": "4.24.0",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.13.0",
|
"@rollup/rollup-linux-powerpc64le-gnu": "4.24.0",
|
||||||
"@rollup/rollup-linux-x64-musl": "4.13.0",
|
"@rollup/rollup-linux-riscv64-gnu": "4.24.0",
|
||||||
"@rollup/rollup-win32-arm64-msvc": "4.13.0",
|
"@rollup/rollup-linux-s390x-gnu": "4.24.0",
|
||||||
"@rollup/rollup-win32-ia32-msvc": "4.13.0",
|
"@rollup/rollup-linux-x64-gnu": "4.24.0",
|
||||||
"@rollup/rollup-win32-x64-msvc": "4.13.0",
|
"@rollup/rollup-linux-x64-musl": "4.24.0",
|
||||||
|
"@rollup/rollup-win32-arm64-msvc": "4.24.0",
|
||||||
|
"@rollup/rollup-win32-ia32-msvc": "4.24.0",
|
||||||
|
"@rollup/rollup-win32-x64-msvc": "4.24.0",
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -16129,9 +16139,9 @@
|
|||||||
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
|
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
|
||||||
},
|
},
|
||||||
"node_modules/sshpk": {
|
"node_modules/sshpk": {
|
||||||
"version": "1.17.0",
|
"version": "1.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz",
|
||||||
"integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
|
"integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asn1": "~0.2.3",
|
"asn1": "~0.2.3",
|
||||||
@ -16725,9 +16735,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tough-cookie": {
|
"node_modules/tough-cookie": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
|
||||||
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"psl": "^1.1.33",
|
"psl": "^1.1.33",
|
||||||
@ -17799,20 +17809,6 @@
|
|||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/wait-on/node_modules/form-data": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
|
||||||
"optional": true,
|
|
||||||
"dependencies": {
|
|
||||||
"asynckit": "^0.4.0",
|
|
||||||
"combined-stream": "^1.0.8",
|
|
||||||
"mime-types": "^2.1.12"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/wait-on/node_modules/proxy-from-env": {
|
"node_modules/wait-on/node_modules/proxy-from-env": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
@ -20466,9 +20462,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@cypress/request": {
|
"@cypress/request": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.5.tgz",
|
||||||
"integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==",
|
"integrity": "sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"aws-sign2": "~0.7.0",
|
"aws-sign2": "~0.7.0",
|
||||||
@ -20477,14 +20473,14 @@
|
|||||||
"combined-stream": "~1.0.6",
|
"combined-stream": "~1.0.6",
|
||||||
"extend": "~3.0.2",
|
"extend": "~3.0.2",
|
||||||
"forever-agent": "~0.6.1",
|
"forever-agent": "~0.6.1",
|
||||||
"form-data": "~2.3.2",
|
"form-data": "~4.0.0",
|
||||||
"http-signature": "~1.3.6",
|
"http-signature": "~1.4.0",
|
||||||
"is-typedarray": "~1.0.0",
|
"is-typedarray": "~1.0.0",
|
||||||
"isstream": "~0.1.2",
|
"isstream": "~0.1.2",
|
||||||
"json-stringify-safe": "~5.0.1",
|
"json-stringify-safe": "~5.0.1",
|
||||||
"mime-types": "~2.1.19",
|
"mime-types": "~2.1.19",
|
||||||
"performance-now": "^2.1.0",
|
"performance-now": "^2.1.0",
|
||||||
"qs": "6.10.4",
|
"qs": "6.13.0",
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"tough-cookie": "^4.1.3",
|
"tough-cookie": "^4.1.3",
|
||||||
"tunnel-agent": "^0.6.0",
|
"tunnel-agent": "^0.6.0",
|
||||||
@ -21229,81 +21225,99 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-android-arm-eabi": {
|
"@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
|
||||||
"integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==",
|
"integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-android-arm64": {
|
"@rollup/rollup-android-arm64": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz",
|
||||||
"integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==",
|
"integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-darwin-arm64": {
|
"@rollup/rollup-darwin-arm64": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz",
|
||||||
"integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==",
|
"integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-darwin-x64": {
|
"@rollup/rollup-darwin-x64": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz",
|
||||||
"integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==",
|
"integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": {
|
"@rollup/rollup-linux-arm-gnueabihf": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz",
|
||||||
"integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==",
|
"integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@rollup/rollup-linux-arm-musleabihf": {
|
||||||
|
"version": "4.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz",
|
||||||
|
"integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-linux-arm64-gnu": {
|
"@rollup/rollup-linux-arm64-gnu": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz",
|
||||||
"integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==",
|
"integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-linux-arm64-musl": {
|
"@rollup/rollup-linux-arm64-musl": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz",
|
||||||
"integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==",
|
"integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@rollup/rollup-linux-powerpc64le-gnu": {
|
||||||
|
"version": "4.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz",
|
||||||
|
"integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-linux-riscv64-gnu": {
|
"@rollup/rollup-linux-riscv64-gnu": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz",
|
||||||
"integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==",
|
"integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@rollup/rollup-linux-s390x-gnu": {
|
||||||
|
"version": "4.24.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz",
|
||||||
|
"integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-linux-x64-gnu": {
|
"@rollup/rollup-linux-x64-gnu": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz",
|
||||||
"integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==",
|
"integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-linux-x64-musl": {
|
"@rollup/rollup-linux-x64-musl": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz",
|
||||||
"integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==",
|
"integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-win32-arm64-msvc": {
|
"@rollup/rollup-win32-arm64-msvc": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz",
|
||||||
"integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==",
|
"integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-win32-ia32-msvc": {
|
"@rollup/rollup-win32-ia32-msvc": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz",
|
||||||
"integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==",
|
"integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@rollup/rollup-win32-x64-msvc": {
|
"@rollup/rollup-win32-x64-msvc": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz",
|
||||||
"integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==",
|
"integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@schematics/angular": {
|
"@schematics/angular": {
|
||||||
@ -21607,9 +21621,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/estree": {
|
"@types/estree": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
"integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="
|
||||||
},
|
},
|
||||||
"@types/express": {
|
"@types/express": {
|
||||||
"version": "4.17.13",
|
"version": "4.17.13",
|
||||||
@ -22369,9 +22383,9 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"aws4": {
|
"aws4": {
|
||||||
"version": "1.12.0",
|
"version": "1.13.2",
|
||||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
|
||||||
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==",
|
"integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
@ -22583,14 +22597,6 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"ee-first": "1.1.1"
|
"ee-first": "1.1.1"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"qs": {
|
|
||||||
"version": "6.13.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
|
||||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
|
||||||
"requires": {
|
|
||||||
"side-channel": "^1.0.6"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -24100,12 +24106,12 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"cypress": {
|
"cypress": {
|
||||||
"version": "13.14.0",
|
"version": "13.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/cypress/-/cypress-13.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/cypress/-/cypress-13.15.0.tgz",
|
||||||
"integrity": "sha512-r0+nhd033x883YL6068futewUsl02Q7rWiinyAAIBDW/OOTn+UMILWgNuCiY3vtJjd53efOqq5R9dctQk/rKiw==",
|
"integrity": "sha512-53aO7PwOfi604qzOkCSzNlWquCynLlKE/rmmpSPcziRH6LNfaDUAklQT6WJIsD8ywxlIy+uVZsnTMCCQVd2kTw==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@cypress/request": "^3.0.1",
|
"@cypress/request": "^3.0.4",
|
||||||
"@cypress/xvfb": "^1.2.4",
|
"@cypress/xvfb": "^1.2.4",
|
||||||
"@types/sinonjs__fake-timers": "8.1.1",
|
"@types/sinonjs__fake-timers": "8.1.1",
|
||||||
"@types/sizzle": "^2.3.2",
|
"@types/sizzle": "^2.3.2",
|
||||||
@ -25554,14 +25560,6 @@
|
|||||||
"ee-first": "1.1.1"
|
"ee-first": "1.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"qs": {
|
|
||||||
"version": "6.13.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
|
||||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
|
||||||
"requires": {
|
|
||||||
"side-channel": "^1.0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
@ -25853,13 +25851,13 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"form-data": {
|
"form-data": {
|
||||||
"version": "2.3.3",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.6",
|
"combined-stream": "^1.0.8",
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -26321,14 +26319,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"http-signature": {
|
"http-signature": {
|
||||||
"version": "1.3.6",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.4.0.tgz",
|
||||||
"integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==",
|
"integrity": "sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"assert-plus": "^1.0.0",
|
"assert-plus": "^1.0.0",
|
||||||
"jsprim": "^2.0.2",
|
"jsprim": "^2.0.2",
|
||||||
"sshpk": "^1.14.1"
|
"sshpk": "^1.18.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"https-browserify": {
|
"https-browserify": {
|
||||||
@ -29098,12 +29096,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"qs": {
|
"qs": {
|
||||||
"version": "6.10.4",
|
"version": "6.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||||
"integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==",
|
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"side-channel": "^1.0.4"
|
"side-channel": "^1.0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"querystring": {
|
"querystring": {
|
||||||
@ -29456,24 +29453,27 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rollup": {
|
"rollup": {
|
||||||
"version": "4.13.0",
|
"version": "4.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz",
|
||||||
"integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==",
|
"integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@rollup/rollup-android-arm-eabi": "4.13.0",
|
"@rollup/rollup-android-arm-eabi": "4.24.0",
|
||||||
"@rollup/rollup-android-arm64": "4.13.0",
|
"@rollup/rollup-android-arm64": "4.24.0",
|
||||||
"@rollup/rollup-darwin-arm64": "4.13.0",
|
"@rollup/rollup-darwin-arm64": "4.24.0",
|
||||||
"@rollup/rollup-darwin-x64": "4.13.0",
|
"@rollup/rollup-darwin-x64": "4.24.0",
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": "4.13.0",
|
"@rollup/rollup-linux-arm-gnueabihf": "4.24.0",
|
||||||
"@rollup/rollup-linux-arm64-gnu": "4.13.0",
|
"@rollup/rollup-linux-arm-musleabihf": "4.24.0",
|
||||||
"@rollup/rollup-linux-arm64-musl": "4.13.0",
|
"@rollup/rollup-linux-arm64-gnu": "4.24.0",
|
||||||
"@rollup/rollup-linux-riscv64-gnu": "4.13.0",
|
"@rollup/rollup-linux-arm64-musl": "4.24.0",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.13.0",
|
"@rollup/rollup-linux-powerpc64le-gnu": "4.24.0",
|
||||||
"@rollup/rollup-linux-x64-musl": "4.13.0",
|
"@rollup/rollup-linux-riscv64-gnu": "4.24.0",
|
||||||
"@rollup/rollup-win32-arm64-msvc": "4.13.0",
|
"@rollup/rollup-linux-s390x-gnu": "4.24.0",
|
||||||
"@rollup/rollup-win32-ia32-msvc": "4.13.0",
|
"@rollup/rollup-linux-x64-gnu": "4.24.0",
|
||||||
"@rollup/rollup-win32-x64-msvc": "4.13.0",
|
"@rollup/rollup-linux-x64-musl": "4.24.0",
|
||||||
"@types/estree": "1.0.5",
|
"@rollup/rollup-win32-arm64-msvc": "4.24.0",
|
||||||
|
"@rollup/rollup-win32-ia32-msvc": "4.24.0",
|
||||||
|
"@rollup/rollup-win32-x64-msvc": "4.24.0",
|
||||||
|
"@types/estree": "1.0.6",
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -30167,9 +30167,9 @@
|
|||||||
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
|
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
|
||||||
},
|
},
|
||||||
"sshpk": {
|
"sshpk": {
|
||||||
"version": "1.17.0",
|
"version": "1.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
|
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz",
|
||||||
"integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
|
"integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"asn1": "~0.2.3",
|
"asn1": "~0.2.3",
|
||||||
@ -30615,9 +30615,9 @@
|
|||||||
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
|
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
|
||||||
},
|
},
|
||||||
"tough-cookie": {
|
"tough-cookie": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
|
||||||
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"psl": "^1.1.33",
|
"psl": "^1.1.33",
|
||||||
@ -31248,17 +31248,6 @@
|
|||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"form-data": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
|
||||||
"asynckit": "^0.4.0",
|
|
||||||
"combined-stream": "^1.0.8",
|
|
||||||
"mime-types": "^2.1.12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"proxy-from-env": {
|
"proxy-from-env": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
@ -115,7 +115,7 @@
|
|||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@cypress/schematic": "^2.5.0",
|
"@cypress/schematic": "^2.5.0",
|
||||||
"@types/cypress": "^1.1.3",
|
"@types/cypress": "^1.1.3",
|
||||||
"cypress": "^13.14.0",
|
"cypress": "^13.15.0",
|
||||||
"cypress-fail-on-console-error": "~5.1.0",
|
"cypress-fail-on-console-error": "~5.1.0",
|
||||||
"cypress-wait-until": "^2.0.1",
|
"cypress-wait-until": "^2.0.1",
|
||||||
"mock-socket": "~9.3.1",
|
"mock-socket": "~9.3.1",
|
||||||
|
@ -6,6 +6,7 @@ import { ZONE_SERVICE } from './injection-tokens';
|
|||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
import { AppComponent } from './components/app/app.component';
|
import { AppComponent } from './components/app/app.component';
|
||||||
import { ElectrsApiService } from './services/electrs-api.service';
|
import { ElectrsApiService } from './services/electrs-api.service';
|
||||||
|
import { OrdApiService } from './services/ord-api.service';
|
||||||
import { StateService } from './services/state.service';
|
import { StateService } from './services/state.service';
|
||||||
import { CacheService } from './services/cache.service';
|
import { CacheService } from './services/cache.service';
|
||||||
import { PriceService } from './services/price.service';
|
import { PriceService } from './services/price.service';
|
||||||
@ -32,6 +33,7 @@ import { DatePipe } from '@angular/common';
|
|||||||
|
|
||||||
const providers = [
|
const providers = [
|
||||||
ElectrsApiService,
|
ElectrsApiService,
|
||||||
|
OrdApiService,
|
||||||
StateService,
|
StateService,
|
||||||
CacheService,
|
CacheService,
|
||||||
PriceService,
|
PriceService,
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
<span *ngIf="acceleration.status === 'accelerating'" class="badge badge-warning" i18n="accelerator.pending">Pending</span>
|
<span *ngIf="acceleration.status === 'accelerating'" class="badge badge-warning" i18n="accelerator.pending">Pending</span>
|
||||||
<span *ngIf="acceleration.status.includes('completed') && acceleration.minedByPoolUniqueId && pools[acceleration.minedByPoolUniqueId]" class="badge badge-success"><ng-container i18n="accelerator.completed">Completed</ng-container><span *ngIf="acceleration.status === 'completed_provisional'"> ⌛</span></span>
|
<span *ngIf="acceleration.status.includes('completed') && acceleration.minedByPoolUniqueId && pools[acceleration.minedByPoolUniqueId]" class="badge badge-success"><ng-container i18n="accelerator.completed">Completed</ng-container><span *ngIf="acceleration.status === 'completed_provisional'"> ⌛</span></span>
|
||||||
<span *ngIf="acceleration.status.includes('completed') && (!acceleration.minedByPoolUniqueId || !pools[acceleration.minedByPoolUniqueId])" class="badge badge-success"><ng-container i18n="transaction.rbf.mined">Mined</ng-container><span *ngIf="acceleration.status === 'completed_provisional'"> ⌛</span></span>
|
<span *ngIf="acceleration.status.includes('completed') && (!acceleration.minedByPoolUniqueId || !pools[acceleration.minedByPoolUniqueId])" class="badge badge-success"><ng-container i18n="transaction.rbf.mined">Mined</ng-container><span *ngIf="acceleration.status === 'completed_provisional'"> ⌛</span></span>
|
||||||
<span *ngIf="acceleration.status.includes('failed')" class="badge badge-danger"><ng-container i18n="accelerator.canceled">Failed</ng-container><span *ngIf="acceleration.status === 'failed_provisional'"> ⌛</span></span>
|
<span *ngIf="acceleration.status.includes('failed')" class="badge badge-danger"><ng-container i18n="accelerator.canceled">Canceled</ng-container><span *ngIf="acceleration.status === 'failed_provisional'"> ⌛</span></span>
|
||||||
</td>
|
</td>
|
||||||
<td class="date text-right" *ngIf="!this.widget">
|
<td class="date text-right" *ngIf="!this.widget">
|
||||||
<app-time kind="since" [time]="acceleration.added" [fastRender]="true" [showTooltip]="true"></app-time>
|
<app-time kind="since" [time]="acceleration.added" [fastRender]="true" [showTooltip]="true"></app-time>
|
||||||
|
@ -219,11 +219,11 @@ export class AddressComponent implements OnInit, OnDestroy {
|
|||||||
address.is_pubkey
|
address.is_pubkey
|
||||||
? this.electrsApiService.getScriptHashTransactions$((address.address.length === 66 ? '21' : '41') + address.address + 'ac')
|
? this.electrsApiService.getScriptHashTransactions$((address.address.length === 66 ? '21' : '41') + address.address + 'ac')
|
||||||
: this.electrsApiService.getAddressTransactions$(address.address),
|
: this.electrsApiService.getAddressTransactions$(address.address),
|
||||||
(utxoCount >= 2 && utxoCount <= 500 ? (address.is_pubkey
|
(utxoCount > 2 && utxoCount <= 500 ? (address.is_pubkey
|
||||||
? this.electrsApiService.getScriptHashUtxos$((address.address.length === 66 ? '21' : '41') + address.address + 'ac')
|
? this.electrsApiService.getScriptHashUtxos$((address.address.length === 66 ? '21' : '41') + address.address + 'ac')
|
||||||
: this.electrsApiService.getAddressUtxos$(address.address)) : of([])).pipe(
|
: this.electrsApiService.getAddressUtxos$(address.address)) : of(null)).pipe(
|
||||||
catchError(() => {
|
catchError(() => {
|
||||||
return of([]);
|
return of(null);
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
@ -350,27 +350,29 @@ export class AddressComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update utxos in-place
|
// update utxos in-place
|
||||||
let utxosChanged = false;
|
if (this.utxos != null) {
|
||||||
for (const vin of transaction.vin) {
|
let utxosChanged = false;
|
||||||
const utxoIndex = this.utxos.findIndex((utxo) => utxo.txid === vin.txid && utxo.vout === vin.vout);
|
for (const vin of transaction.vin) {
|
||||||
if (utxoIndex !== -1) {
|
const utxoIndex = this.utxos.findIndex((utxo) => utxo.txid === vin.txid && utxo.vout === vin.vout);
|
||||||
this.utxos.splice(utxoIndex, 1);
|
if (utxoIndex !== -1) {
|
||||||
utxosChanged = true;
|
this.utxos.splice(utxoIndex, 1);
|
||||||
|
utxosChanged = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
for (const [index, vout] of transaction.vout.entries()) {
|
||||||
for (const [index, vout] of transaction.vout.entries()) {
|
if (vout.scriptpubkey_address === this.address.address) {
|
||||||
if (vout.scriptpubkey_address === this.address.address) {
|
this.utxos.push({
|
||||||
this.utxos.push({
|
txid: transaction.txid,
|
||||||
txid: transaction.txid,
|
vout: index,
|
||||||
vout: index,
|
value: vout.value,
|
||||||
value: vout.value,
|
status: JSON.parse(JSON.stringify(transaction.status)),
|
||||||
status: JSON.parse(JSON.stringify(transaction.status)),
|
});
|
||||||
});
|
utxosChanged = true;
|
||||||
utxosChanged = true;
|
}
|
||||||
|
}
|
||||||
|
if (utxosChanged) {
|
||||||
|
this.utxos = this.utxos.slice();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (utxosChanged) {
|
|
||||||
this.utxos = this.utxos.slice();
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -385,29 +387,31 @@ export class AddressComponent implements OnInit, OnDestroy {
|
|||||||
this.transactions = this.transactions.slice();
|
this.transactions = this.transactions.slice();
|
||||||
|
|
||||||
// update utxos in-place
|
// update utxos in-place
|
||||||
let utxosChanged = false;
|
if (this.utxos != null) {
|
||||||
for (const vin of transaction.vin) {
|
let utxosChanged = false;
|
||||||
if (vin.prevout?.scriptpubkey_address === this.address.address) {
|
for (const vin of transaction.vin) {
|
||||||
this.utxos.push({
|
if (vin.prevout?.scriptpubkey_address === this.address.address) {
|
||||||
txid: vin.txid,
|
this.utxos.push({
|
||||||
vout: vin.vout,
|
txid: vin.txid,
|
||||||
value: vin.prevout.value,
|
vout: vin.vout,
|
||||||
status: { confirmed: true }, // Assuming the input was confirmed
|
value: vin.prevout.value,
|
||||||
});
|
status: { confirmed: true }, // Assuming the input was confirmed
|
||||||
utxosChanged = true;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const [index, vout] of transaction.vout.entries()) {
|
|
||||||
if (vout.scriptpubkey_address === this.address.address) {
|
|
||||||
const utxoIndex = this.utxos.findIndex((utxo) => utxo.txid === transaction.txid && utxo.vout === index);
|
|
||||||
if (utxoIndex !== -1) {
|
|
||||||
this.utxos.splice(utxoIndex, 1);
|
|
||||||
utxosChanged = true;
|
utxosChanged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
for (const [index, vout] of transaction.vout.entries()) {
|
||||||
if (utxosChanged) {
|
if (vout.scriptpubkey_address === this.address.address) {
|
||||||
this.utxos = this.utxos.slice();
|
const utxoIndex = this.utxos.findIndex((utxo) => utxo.txid === transaction.txid && utxo.vout === index);
|
||||||
|
if (utxoIndex !== -1) {
|
||||||
|
this.utxos.splice(utxoIndex, 1);
|
||||||
|
utxosChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (utxosChanged) {
|
||||||
|
this.utxos = this.utxos.slice();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -415,27 +419,29 @@ export class AddressComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
confirmTransaction(transaction: Transaction): void {
|
confirmTransaction(transaction: Transaction): void {
|
||||||
// update utxos in-place
|
// update utxos in-place
|
||||||
let utxosChanged = false;
|
if (this.utxos != null) {
|
||||||
for (const vin of transaction.vin) {
|
let utxosChanged = false;
|
||||||
if (vin.prevout?.scriptpubkey_address === this.address.address) {
|
for (const vin of transaction.vin) {
|
||||||
const utxoIndex = this.utxos.findIndex((utxo) => utxo.txid === vin.txid && utxo.vout === vin.vout);
|
if (vin.prevout?.scriptpubkey_address === this.address.address) {
|
||||||
if (utxoIndex !== -1) {
|
const utxoIndex = this.utxos.findIndex((utxo) => utxo.txid === vin.txid && utxo.vout === vin.vout);
|
||||||
this.utxos[utxoIndex].status = JSON.parse(JSON.stringify(transaction.status));
|
if (utxoIndex !== -1) {
|
||||||
utxosChanged = true;
|
this.utxos[utxoIndex].status = JSON.parse(JSON.stringify(transaction.status));
|
||||||
|
utxosChanged = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
for (const [index, vout] of transaction.vout.entries()) {
|
||||||
for (const [index, vout] of transaction.vout.entries()) {
|
if (vout.scriptpubkey_address === this.address.address) {
|
||||||
if (vout.scriptpubkey_address === this.address.address) {
|
const utxoIndex = this.utxos.findIndex((utxo) => utxo.txid === transaction.txid && utxo.vout === index);
|
||||||
const utxoIndex = this.utxos.findIndex((utxo) => utxo.txid === transaction.txid && utxo.vout === index);
|
if (utxoIndex !== -1) {
|
||||||
if (utxoIndex !== -1) {
|
this.utxos[utxoIndex].status = JSON.parse(JSON.stringify(transaction.status));
|
||||||
this.utxos[utxoIndex].status = JSON.parse(JSON.stringify(transaction.status));
|
utxosChanged = true;
|
||||||
utxosChanged = true;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (utxosChanged) {
|
||||||
if (utxosChanged) {
|
this.utxos = this.utxos.slice();
|
||||||
this.utxos = this.utxos.slice();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
@if (digitsInfo === '1.8-8') {
|
@if (digitsInfo === '1.8-8') {
|
||||||
‎{{ addPlus && satoshis >= 0 ? '+' : '' }}{{ satoshis | number }}
|
‎{{ addPlus && satoshis >= 0 ? '+' : '' }}{{ satoshis | number }}
|
||||||
} @else {
|
} @else {
|
||||||
‎{{ addPlus && satoshis >= 0 ? '+' : '' }}{{ satoshis | amountShortener : satoshis < 1000 && satoshis > -1000 ? 0 : 1 }}
|
‎{{ addPlus && satoshis >= 0 ? '+' : '' }}{{ satoshis | amountShortener : (satoshis < 1000 && satoshis > -1000 ? 0 : 1) : undefined : true }}
|
||||||
}
|
}
|
||||||
<span class="symbol">
|
<span class="symbol">
|
||||||
<ng-container *ngTemplateOutlet="prefix"></ng-container>sats
|
<ng-container *ngTemplateOutlet="prefix"></ng-container>sats
|
||||||
|
@ -66,10 +66,10 @@
|
|||||||
[class.badge-success]="blockAudit?.matchRate >= 99"
|
[class.badge-success]="blockAudit?.matchRate >= 99"
|
||||||
[class.badge-warning]="blockAudit?.matchRate >= 75 && blockAudit?.matchRate < 99"
|
[class.badge-warning]="blockAudit?.matchRate >= 75 && blockAudit?.matchRate < 99"
|
||||||
[class.badge-danger]="blockAudit?.matchRate < 75"
|
[class.badge-danger]="blockAudit?.matchRate < 75"
|
||||||
*ngIf="blockAudit?.matchRate != null; else nullHealth"
|
*ngIf="blockAudit?.matchRate != null && blockAudit?.id === block.id; else nullHealth"
|
||||||
>{{ blockAudit?.matchRate }}%</span>
|
>{{ blockAudit?.matchRate }}%</span>
|
||||||
<ng-template #nullHealth>
|
<ng-template #nullHealth>
|
||||||
<ng-container *ngIf="!isLoadingOverview; else loadingHealth">
|
<ng-container *ngIf="!isLoadingOverview && blockAudit?.id === block.id; else loadingHealth">
|
||||||
<span class="health-badge badge badge-secondary" i18n="unknown">Unknown</span>
|
<span class="health-badge badge badge-secondary" i18n="unknown">Unknown</span>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
<div *ngIf="!widget" class="float-left" style="display: flex; width: 100%; align-items: center;">
|
<div *ngIf="!widget" class="float-left" style="display: flex; width: 100%; align-items: center;">
|
||||||
<h1 i18n="master-page.blocks">Blocks</h1>
|
<h1 i18n="master-page.blocks">Blocks</h1>
|
||||||
<app-svg-images name="blocks-2-3" style="width: 275px; max-width: 90%; margin-top: -10px"></app-svg-images>
|
<app-svg-images name="blocks-2-3" style="width: 275px; max-width: 90%; margin-top: -10px"></app-svg-images>
|
||||||
|
<div *ngIf="!widget && isLoading" class="spinner-border" role="status"></div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!widget && isLoading" class="spinner-border ml-3" role="status"></div>
|
|
||||||
|
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
.spinner-border {
|
.spinner-border {
|
||||||
height: 25px;
|
height: 25px;
|
||||||
width: 25px;
|
width: 25px;
|
||||||
margin-top: 13px;
|
margin-top: -10px;
|
||||||
|
margin-left: -13px;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container-xl {
|
.container-xl {
|
||||||
|
@ -12,9 +12,15 @@
|
|||||||
<span class="badge mr-1 badge-og" *ngIf="user.ogRank">
|
<span class="badge mr-1 badge-og" *ngIf="user.ogRank">
|
||||||
OG #{{ user.ogRank }}
|
OG #{{ user.ogRank }}
|
||||||
</span>
|
</span>
|
||||||
<span class="badge mr-1 badge-default" [class]="'badge-' + user.subscription_tag" *ngIf="user.subscription_tag !== 'free'">
|
@if (user.subscription_tag !== 'free') {
|
||||||
{{ user.subscription_tag.toUpperCase() }}
|
<span class="badge mr-1 badge-default" [class]="'badge-' + user.subscription_tag">
|
||||||
</span>
|
{{ user.subscription_tag.toUpperCase() }}
|
||||||
|
</span>
|
||||||
|
} @else if (user.type === 'mining_pool') {
|
||||||
|
<span class="badge mr-1 badge-default" [class]="'badge-mining-pool'">
|
||||||
|
MINING POOL
|
||||||
|
</span>
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
<a *ngIf="!userAuth" class="d-flex justify-content-center align-items-center nav-link m-0 menu-click" routerLink="/login" role="tab" (click)="onLinkClick('/login')">
|
<a *ngIf="!userAuth" class="d-flex justify-content-center align-items-center nav-link m-0 menu-click" routerLink="/login" role="tab" (click)="onLinkClick('/login')">
|
||||||
<fa-icon class="menu-click" [icon]="['fas', 'user-circle']" [fixedWidth]="true" style="font-size: 25px;margin-right: 15px;"></fa-icon>
|
<fa-icon class="menu-click" [icon]="['fas', 'user-circle']" [fixedWidth]="true" style="font-size: 25px;margin-right: 15px;"></fa-icon>
|
||||||
|
65
frontend/src/app/components/ord-data/ord-data.component.html
Normal file
65
frontend/src/app/components/ord-data/ord-data.component.html
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
@if (minted) {
|
||||||
|
<ng-container i18n="ord.mint-n-runes">
|
||||||
|
<span>Mint</span>
|
||||||
|
<span class="amount"> {{ minted >= 100000 ? (minted | amountShortener:undefined:undefined:true) : minted }} </span>
|
||||||
|
<ng-container *ngTemplateOutlet="runeName; context: { $implicit: runestone.mint.toString() }"></ng-container>
|
||||||
|
</ng-container>
|
||||||
|
}
|
||||||
|
@if (runestone?.etching?.supply) {
|
||||||
|
@if (runestone?.etching.premine > 0) {
|
||||||
|
<ng-container i18n="ord.premine-n-runes">
|
||||||
|
<span>Premine</span>
|
||||||
|
<span class="amount"> {{ runestone.etching.premine >= 100000 ? (toNumber(runestone.etching.premine) | amountShortener:undefined:undefined:true) : runestone.etching.premine }} </span>
|
||||||
|
{{ runestone.etching.symbol }}
|
||||||
|
<span class="name">{{ runestone.etching.spacedName }}</span>
|
||||||
|
<span> ({{ toNumber(runestone.etching.premine) / toNumber(runestone.etching.supply) * 100 | amountShortener:0}}% of total supply)</span>
|
||||||
|
</ng-container>
|
||||||
|
} @else {
|
||||||
|
<ng-container i18n="ord.etch-rune">
|
||||||
|
<span>Etching of</span>
|
||||||
|
{{ runestone.etching.symbol }}
|
||||||
|
<span class="name">{{ runestone.etching.spacedName }}</span>
|
||||||
|
</ng-container>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if (transferredRunes?.length && type === 'vout') {
|
||||||
|
<div *ngFor="let rune of transferredRunes">
|
||||||
|
<ng-container i18n="ord.transfer-rune">
|
||||||
|
<span>Transfer</span>
|
||||||
|
<ng-container *ngTemplateOutlet="runeName; context: { $implicit: rune.key }"></ng-container>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (inscriptions?.length && type === 'vin') {
|
||||||
|
<div *ngFor="let contentType of inscriptionsData | keyvalue">
|
||||||
|
<div>
|
||||||
|
@if (contentType.key !== 'undefined') {
|
||||||
|
<span class="badge badge-ord mr-1">{{ contentType.value.count > 1 ? contentType.value.count + " " : "" }}{{ contentType.value?.tag || contentType.key }}</span>
|
||||||
|
} @else {
|
||||||
|
<span class="badge badge-ord mr-1" i18n="unknown">Unknown</span>
|
||||||
|
}
|
||||||
|
<span class="badge badge-ord" *ngIf="contentType.value.totalSize > 0">{{ contentType.value.totalSize | bytes:2:'B':undefined:true }}</span>
|
||||||
|
<a *ngIf="contentType.value.delegate" [routerLink]="['/tx' | relativeUrl, contentType.value.delegate]">
|
||||||
|
<span i18n="ord.source-inscription">Source inscription</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<pre *ngIf="contentType.value.json" class="name" style="white-space: pre-wrap; word-break: break-word;">{{ contentType.value.json | json }}</pre>
|
||||||
|
<pre *ngIf="contentType.value.text" class="name" style="white-space: pre-wrap; word-break: break-word;">{{ contentType.value.text }}</pre>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (!runestone && type === 'vout') {
|
||||||
|
<div class="skeleton-loader" style="width: 50%;"></div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if ((runestone && !minted && !runestone.etching?.supply && !transferredRunes?.length && type === 'vout') || (!inscriptions?.length && type === 'vin')) {
|
||||||
|
<i i18n="error.decoding-data">Error decoding data</i>
|
||||||
|
}
|
||||||
|
|
||||||
|
<ng-template #runeName let-id>
|
||||||
|
{{ runeInfo[id]?.etching.symbol || '' }}
|
||||||
|
<a [routerLink]="id !== '1:0' ? ['/tx' | relativeUrl, runeInfo[id]?.txid] : null" [class.rune-link]="id !== '1:0'" [class.disabled]="id === '1:0'">
|
||||||
|
<span class="name">{{ runeInfo[id]?.etching.spacedName }}</span>
|
||||||
|
</a>
|
||||||
|
</ng-template>
|
35
frontend/src/app/components/ord-data/ord-data.component.scss
Normal file
35
frontend/src/app/components/ord-data/ord-data.component.scss
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
.amount {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.rune-link {
|
||||||
|
color: inherit;
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: var(--transparent-fg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a.disabled {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
color: var(--transparent-fg);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-ord {
|
||||||
|
background-color: var(--grey);
|
||||||
|
position: relative;
|
||||||
|
top: -2px;
|
||||||
|
font-size: 81%;
|
||||||
|
&.primary {
|
||||||
|
background-color: var(--primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
margin-top: 5px;
|
||||||
|
max-height: 200px;
|
||||||
|
}
|
87
frontend/src/app/components/ord-data/ord-data.component.ts
Normal file
87
frontend/src/app/components/ord-data/ord-data.component.ts
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||||
|
import { Runestone, Etching } from '../../shared/ord/rune.utils';
|
||||||
|
import { Inscription } from '../../shared/ord/inscription.utils';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-ord-data',
|
||||||
|
templateUrl: './ord-data.component.html',
|
||||||
|
styleUrls: ['./ord-data.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
})
|
||||||
|
export class OrdDataComponent implements OnChanges {
|
||||||
|
@Input() inscriptions: Inscription[];
|
||||||
|
@Input() runestone: Runestone;
|
||||||
|
@Input() runeInfo: { [id: string]: { etching: Etching; txid: string } };
|
||||||
|
@Input() type: 'vin' | 'vout';
|
||||||
|
|
||||||
|
toNumber = (value: bigint): number => Number(value);
|
||||||
|
|
||||||
|
// Inscriptions
|
||||||
|
inscriptionsData: { [key: string]: { count: number, totalSize: number, text?: string; json?: JSON; tag?: string; delegate?: string } };
|
||||||
|
// Rune mints
|
||||||
|
minted: number;
|
||||||
|
// Rune transfers
|
||||||
|
transferredRunes: { key: string; etching: Etching; txid: string }[] = [];
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
if (changes.runestone && this.runestone) {
|
||||||
|
if (this.runestone.mint && this.runeInfo[this.runestone.mint.toString()]) {
|
||||||
|
const mint = this.runestone.mint.toString();
|
||||||
|
const terms = this.runeInfo[mint].etching.terms;
|
||||||
|
const amount = terms?.amount;
|
||||||
|
const divisibility = this.runeInfo[mint].etching.divisibility;
|
||||||
|
if (amount) {
|
||||||
|
this.minted = this.getAmount(amount, divisibility);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.runestone.edicts.forEach(edict => {
|
||||||
|
if (this.runeInfo[edict.id.toString()]) {
|
||||||
|
this.transferredRunes.push({ key: edict.id.toString(), ...this.runeInfo[edict.id.toString()] });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changes.inscriptions && this.inscriptions) {
|
||||||
|
|
||||||
|
if (this.inscriptions?.length) {
|
||||||
|
this.inscriptionsData = {};
|
||||||
|
this.inscriptions.forEach((inscription) => {
|
||||||
|
// General: count, total size, delegate
|
||||||
|
const key = inscription.content_type_str || 'undefined';
|
||||||
|
if (!this.inscriptionsData[key]) {
|
||||||
|
this.inscriptionsData[key] = { count: 0, totalSize: 0 };
|
||||||
|
}
|
||||||
|
this.inscriptionsData[key].count++;
|
||||||
|
this.inscriptionsData[key].totalSize += inscription.body_length;
|
||||||
|
if (inscription.delegate_txid && !this.inscriptionsData[key].delegate) {
|
||||||
|
this.inscriptionsData[key].delegate = inscription.delegate_txid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text / JSON data
|
||||||
|
if ((key.includes('text') || key.includes('json')) && !inscription.is_cropped && !this.inscriptionsData[key].text && !this.inscriptionsData[key].json) {
|
||||||
|
const decoder = new TextDecoder('utf-8');
|
||||||
|
const text = decoder.decode(inscription.body);
|
||||||
|
try {
|
||||||
|
this.inscriptionsData[key].json = JSON.parse(text);
|
||||||
|
if (this.inscriptionsData[key].json['p']) {
|
||||||
|
this.inscriptionsData[key].tag = this.inscriptionsData[key].json['p'].toUpperCase();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.inscriptionsData[key].text = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getAmount(amount: bigint, divisibility: number): number {
|
||||||
|
const divisor = BigInt(10) ** BigInt(divisibility);
|
||||||
|
const result = amount / divisor;
|
||||||
|
|
||||||
|
return result <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(result) : Number.MAX_SAFE_INTEGER;
|
||||||
|
}
|
||||||
|
}
|
@ -81,7 +81,8 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right nowrap amount" [class]="{large: vin?.prevout?.value > 1000000000}">
|
<td class="text-right nowrap amount" [class]="{large: vin?.prevout?.value > 1000000000 || vin.isInscription}">
|
||||||
|
<button *ngIf="vin.isInscription" (click)="toggleOrdData(tx.txid, 'vin', vindex)" type="button" class="btn btn-sm badge badge-ord primary" style="margin-right: 10px;">Inscription</button>
|
||||||
<ng-template [ngIf]="vin.prevout && vin.prevout.asset && vin.prevout.asset !== nativeAssetId" [ngIfElse]="defaultOutput">
|
<ng-template [ngIf]="vin.prevout && vin.prevout.asset && vin.prevout.asset !== nativeAssetId" [ngIfElse]="defaultOutput">
|
||||||
<div *ngIf="assetsMinimal && assetsMinimal[vin.prevout.asset] else assetVinNotFound">
|
<div *ngIf="assetsMinimal && assetsMinimal[vin.prevout.asset] else assetVinNotFound">
|
||||||
<ng-container *ngTemplateOutlet="assetBox; context:{ $implicit: vin.prevout }"></ng-container>
|
<ng-container *ngTemplateOutlet="assetBox; context:{ $implicit: vin.prevout }"></ng-container>
|
||||||
@ -96,6 +97,15 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr *ngIf="showOrdData[tx.txid + '-vin-' + vindex]?.show" [ngClass]="{
|
||||||
|
'assetBox': (assetsMinimal && vin.prevout && assetsMinimal[vin.prevout.asset] && !vin.is_coinbase && vin.prevout.scriptpubkey_address && tx._unblinded) || inputIndex === vindex,
|
||||||
|
'highlight': this.address !== '' && (vin.prevout?.scriptpubkey_address === this.address || (vin.prevout?.scriptpubkey_type === 'p2pk' && vin.prevout?.scriptpubkey.slice(2, -2) === this.address))
|
||||||
|
}">
|
||||||
|
<td></td>
|
||||||
|
<td colspan="2">
|
||||||
|
<app-ord-data [inscriptions]="showOrdData[tx.txid + '-vin-' + vindex]['inscriptions']" [type]="'vin'"></app-ord-data>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr *ngIf="(showDetails$ | async) === true">
|
<tr *ngIf="(showDetails$ | async) === true">
|
||||||
<td colspan="3" class="details-container" >
|
<td colspan="3" class="details-container" >
|
||||||
<table class="table table-striped table-fixed table-borderless details-table mb-3">
|
<table class="table table-striped table-fixed table-borderless details-table mb-3">
|
||||||
@ -236,7 +246,12 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template #defaultscriptpubkey_type>
|
<ng-template #defaultscriptpubkey_type>
|
||||||
<ng-template [ngIf]="vout.scriptpubkey_type === 'op_return'" [ngIfElse]="otherPubkeyType">
|
<ng-template [ngIf]="vout.scriptpubkey_type === 'op_return'" [ngIfElse]="otherPubkeyType">
|
||||||
OP_RETURN <a placement="bottom" [ngbTooltip]="vout.scriptpubkey_asm | hex2ascii"><span *ngIf="vout.scriptpubkey_asm !== 'OP_RETURN'" class="badge badge-secondary scriptmessage">{{ vout.scriptpubkey_asm | hex2ascii }}</span></a>
|
OP_RETURN
|
||||||
|
@if (vout.isRunestone) {
|
||||||
|
<button (click)="toggleOrdData(tx.txid, 'vout', vindex)" type="button" class="btn btn-sm badge badge-ord">Runestone</button>
|
||||||
|
} @else {
|
||||||
|
<a placement="bottom" [ngbTooltip]="vout.scriptpubkey_asm | hex2ascii"><span *ngIf="vout.scriptpubkey_asm !== 'OP_RETURN'" class="badge badge-secondary scriptmessage">{{ vout.scriptpubkey_asm | hex2ascii }}</span></a>
|
||||||
|
}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template #otherPubkeyType>{{ vout.scriptpubkey_type | scriptpubkeyType }}</ng-template>
|
<ng-template #otherPubkeyType>{{ vout.scriptpubkey_type | scriptpubkeyType }}</ng-template>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@ -276,6 +291,15 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr *ngIf="showOrdData[tx.txid + '-vout-' + vindex]?.show" [ngClass]="{
|
||||||
|
'assetBox': assetsMinimal && assetsMinimal[vout.asset] && vout.scriptpubkey_address && tx.vin && !tx.vin[0].is_coinbase && tx._unblinded || outputIndex === vindex,
|
||||||
|
'highlight': this.address !== '' && (vout.scriptpubkey_address === this.address || (vout.scriptpubkey_type === 'p2pk' && vout.scriptpubkey.slice(2, -2) === this.address))
|
||||||
|
}">
|
||||||
|
<td colspan="3">
|
||||||
|
<app-ord-data [runestone]="showOrdData[tx.txid + '-vout-' + vindex]['runestone']" [runeInfo]="showOrdData[tx.txid + '-vout-' + vindex]['runeInfo']" [type]="'vout'"></app-ord-data>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr *ngIf="(showDetails$ | async) === true">
|
<tr *ngIf="(showDetails$ | async) === true">
|
||||||
<td colspan="3" class=" details-container" >
|
<td colspan="3" class=" details-container" >
|
||||||
<table class="table table-striped table-borderless details-table mb-3">
|
<table class="table table-striped table-borderless details-table mb-3">
|
||||||
|
@ -175,4 +175,15 @@ h2 {
|
|||||||
.witness-item {
|
.witness-item {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge-ord {
|
||||||
|
background-color: var(--grey);
|
||||||
|
position: relative;
|
||||||
|
top: -2px;
|
||||||
|
font-size: 81%;
|
||||||
|
border: 0;
|
||||||
|
&.primary {
|
||||||
|
background-color: var(--primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,11 +6,14 @@ import { Outspend, Transaction, Vin, Vout } from '../../interfaces/electrs.inter
|
|||||||
import { ElectrsApiService } from '../../services/electrs-api.service';
|
import { ElectrsApiService } from '../../services/electrs-api.service';
|
||||||
import { environment } from '../../../environments/environment';
|
import { environment } from '../../../environments/environment';
|
||||||
import { AssetsService } from '../../services/assets.service';
|
import { AssetsService } from '../../services/assets.service';
|
||||||
import { filter, map, tap, switchMap, shareReplay, catchError } from 'rxjs/operators';
|
import { filter, map, tap, switchMap, catchError } from 'rxjs/operators';
|
||||||
import { BlockExtended } from '../../interfaces/node-api.interface';
|
import { BlockExtended } from '../../interfaces/node-api.interface';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { PriceService } from '../../services/price.service';
|
import { PriceService } from '../../services/price.service';
|
||||||
import { StorageService } from '../../services/storage.service';
|
import { StorageService } from '../../services/storage.service';
|
||||||
|
import { OrdApiService } from '../../services/ord-api.service';
|
||||||
|
import { Inscription } from '../../shared/ord/inscription.utils';
|
||||||
|
import { Etching, Runestone } from '../../shared/ord/rune.utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-transactions-list',
|
selector: 'app-transactions-list',
|
||||||
@ -50,12 +53,14 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
|||||||
outputRowLimit: number = 12;
|
outputRowLimit: number = 12;
|
||||||
showFullScript: { [vinIndex: number]: boolean } = {};
|
showFullScript: { [vinIndex: number]: boolean } = {};
|
||||||
showFullWitness: { [vinIndex: number]: { [witnessIndex: number]: boolean } } = {};
|
showFullWitness: { [vinIndex: number]: { [witnessIndex: number]: boolean } } = {};
|
||||||
|
showOrdData: { [key: string]: { show: boolean; inscriptions?: Inscription[]; runestone?: Runestone, runeInfo?: { [id: string]: { etching: Etching; txid: string; } }; } } = {};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public stateService: StateService,
|
public stateService: StateService,
|
||||||
private cacheService: CacheService,
|
private cacheService: CacheService,
|
||||||
private electrsApiService: ElectrsApiService,
|
private electrsApiService: ElectrsApiService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
|
private ordApiService: OrdApiService,
|
||||||
private assetsService: AssetsService,
|
private assetsService: AssetsService,
|
||||||
private ref: ChangeDetectorRef,
|
private ref: ChangeDetectorRef,
|
||||||
private priceService: PriceService,
|
private priceService: PriceService,
|
||||||
@ -239,6 +244,24 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
|||||||
tap((price) => tx['price'] = price),
|
tap((price) => tx['price'] = price),
|
||||||
).subscribe();
|
).subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for ord data fingerprints in inputs and outputs
|
||||||
|
if (this.stateService.network !== 'liquid' && this.stateService.network !== 'liquidtestnet') {
|
||||||
|
for (let i = 0; i < tx.vin.length; i++) {
|
||||||
|
if (tx.vin[i].prevout?.scriptpubkey_type === 'v1_p2tr' && tx.vin[i].witness?.length) {
|
||||||
|
const hasAnnex = tx.vin[i].witness?.[tx.vin[i].witness.length - 1].startsWith('50');
|
||||||
|
if (tx.vin[i].witness.length > (hasAnnex ? 2 : 1) && tx.vin[i].witness[tx.vin[i].witness.length - (hasAnnex ? 3 : 2)].includes('0063036f7264')) {
|
||||||
|
tx.vin[i].isInscription = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < tx.vout.length; i++) {
|
||||||
|
if (tx.vout[i]?.scriptpubkey?.startsWith('6a5d')) {
|
||||||
|
tx.vout[i].isRunestone = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.blockTime && this.transactions?.length && this.currency) {
|
if (this.blockTime && this.transactions?.length && this.currency) {
|
||||||
@ -372,6 +395,40 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
|||||||
this.showFullWitness[vinIndex][witnessIndex] = !this.showFullWitness[vinIndex][witnessIndex];
|
this.showFullWitness[vinIndex][witnessIndex] = !this.showFullWitness[vinIndex][witnessIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleOrdData(txid: string, type: 'vin' | 'vout', index: number) {
|
||||||
|
const tx = this.transactions.find((tx) => tx.txid === txid);
|
||||||
|
if (!tx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = tx.txid + '-' + type + '-' + index;
|
||||||
|
this.showOrdData[key] = this.showOrdData[key] || { show: false };
|
||||||
|
|
||||||
|
if (type === 'vin') {
|
||||||
|
|
||||||
|
if (!this.showOrdData[key].inscriptions) {
|
||||||
|
const hasAnnex = tx.vin[index].witness?.[tx.vin[index].witness.length - 1].startsWith('50');
|
||||||
|
this.showOrdData[key].inscriptions = this.ordApiService.decodeInscriptions(tx.vin[index].witness[tx.vin[index].witness.length - (hasAnnex ? 3 : 2)]);
|
||||||
|
}
|
||||||
|
this.showOrdData[key].show = !this.showOrdData[key].show;
|
||||||
|
|
||||||
|
} else if (type === 'vout') {
|
||||||
|
|
||||||
|
if (!this.showOrdData[key].runestone) {
|
||||||
|
this.ordApiService.decodeRunestone$(tx).pipe(
|
||||||
|
tap((runestone) => {
|
||||||
|
if (runestone) {
|
||||||
|
Object.assign(this.showOrdData[key], runestone);
|
||||||
|
this.ref.markForCheck();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
).subscribe();
|
||||||
|
}
|
||||||
|
this.showOrdData[key].show = !this.showOrdData[key].show;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.outspendsSubscription.unsubscribe();
|
this.outspendsSubscription.unsubscribe();
|
||||||
this.currencyChangeSubscription?.unsubscribe();
|
this.currencyChangeSubscription?.unsubscribe();
|
||||||
|
@ -9163,11 +9163,13 @@ export const restApiDocsData = [
|
|||||||
Filters can be applied:<ul>
|
Filters can be applied:<ul>
|
||||||
<li><code>status</code>: <code>all</code>, <code>requested</code>, <code>accelerating</code>, <code>mined</code>, <code>completed</code>, <code>failed</code></li>
|
<li><code>status</code>: <code>all</code>, <code>requested</code>, <code>accelerating</code>, <code>mined</code>, <code>completed</code>, <code>failed</code></li>
|
||||||
<li><code>timeframe</code>: <code>24h</code>, <code>3d</code>, <code>1w</code>, <code>1m</code>, <code>3m</code>, <code>6m</code>, <code>1y</code>, <code>2y</code>, <code>3y</code>, <code>4y</code>, <code>all</code></li>
|
<li><code>timeframe</code>: <code>24h</code>, <code>3d</code>, <code>1w</code>, <code>1m</code>, <code>3m</code>, <code>6m</code>, <code>1y</code>, <code>2y</code>, <code>3y</code>, <code>4y</code>, <code>all</code></li>
|
||||||
<li><code>poolUniqueId</code>: any id from <a target="_blank" href="https://github.com/mempool/mining-pools/blob/master/pools-v2.json">https://github.com/mempool/mining-pools/blob/master/pools-v2.json</a>. <i>Note: This will return all acceleration requests accepted by the pool but the the listed transactions may have been mined by another pool.</i>
|
<li><code>minedByPoolUniqueId</code>: any id from <a target="_blank" href="https://github.com/mempool/mining-pools/blob/master/pools-v2.json">pools-v2.json</a>
|
||||||
<li><code>blockHash</code>: a block hash</a>
|
<li><code>blockHash</code>: a block hash</a>
|
||||||
<li><code>blockHeight</code>: a block height</a>
|
<li><code>blockHeight</code>: a block height</a>
|
||||||
<li><code>page</code>: the requested page number if using pagination <i>(min: 1)</i></a>
|
<li><code>page</code>: the requested page number if using pagination <i>(min: 1)</i></a>
|
||||||
<li><code>pageLength</code>: the page lenght if using pagination <i>(min: 1, max: 50)</i></a>
|
<li><code>pageLength</code>: the page lenght if using pagination <i>(min: 1, max: 50)</i></a>
|
||||||
|
<li><code>from</code>: unix timestamp (<i>overrides <code>timeframe</code></i>)</a>
|
||||||
|
<li><code>to</code>: unix timestamp (<i>overrides <code>timeframe</code></i>)</a>
|
||||||
</ul></p>`
|
</ul></p>`
|
||||||
},
|
},
|
||||||
urlString: "/v1/services/accelerator/accelerations/history",
|
urlString: "/v1/services/accelerator/accelerations/history",
|
||||||
@ -9187,21 +9189,22 @@ export const restApiDocsData = [
|
|||||||
headers: '',
|
headers: '',
|
||||||
response: `[
|
response: `[
|
||||||
{
|
{
|
||||||
"txid": "d7e1796d8eb4a09d4e6c174e36cfd852f1e6e6c9f7df4496339933cd32cbdd1d",
|
"txid": "f829900985aad885c13fb90555d27514b05a338202c7ef5d694f4813ad474487",
|
||||||
"status": "completed",
|
"status": "completed_provisional",
|
||||||
"added": 1707421053,
|
"added": 1728111527,
|
||||||
"lastUpdated": 1719134667,
|
"lastUpdated": 1728112113,
|
||||||
"effectiveFee": 146,
|
"effectiveFee": 1385,
|
||||||
"effectiveVsize": 141,
|
"effectiveVsize": 276,
|
||||||
"feeDelta": 14000,
|
"feeDelta": 3000,
|
||||||
"blockHash": "00000000000000000000482f0746d62141694b9210a813b97eb8445780a32003",
|
"blockHash": "00000000000000000000cde89e34036ece454ca2d07ddd7f71ab46307ca87423",
|
||||||
"blockHeight": 829559,
|
"blockHeight": 864248,
|
||||||
"bidBoost": 3239,
|
"bidBoost": 65,
|
||||||
"boostVersion": "v1",
|
"boostVersion": "v2",
|
||||||
"pools": [
|
"pools": [
|
||||||
111
|
111,
|
||||||
|
115,
|
||||||
],
|
],
|
||||||
"minedByPoolUniqueId": 111
|
"minedByPoolUniqueId": 115
|
||||||
}
|
}
|
||||||
]`,
|
]`,
|
||||||
},
|
},
|
||||||
|
@ -74,6 +74,8 @@ export interface Vin {
|
|||||||
issuance?: Issuance;
|
issuance?: Issuance;
|
||||||
// Custom
|
// Custom
|
||||||
lazy?: boolean;
|
lazy?: boolean;
|
||||||
|
// Ord
|
||||||
|
isInscription?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Issuance {
|
interface Issuance {
|
||||||
@ -98,6 +100,8 @@ export interface Vout {
|
|||||||
valuecommitment?: number;
|
valuecommitment?: number;
|
||||||
asset?: string;
|
asset?: string;
|
||||||
pegout?: Pegout;
|
pegout?: Pegout;
|
||||||
|
// Ord
|
||||||
|
isRunestone?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Pegout {
|
interface Pegout {
|
||||||
|
@ -107,6 +107,10 @@ export class ElectrsApiService {
|
|||||||
return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/block-height/' + height, {responseType: 'text'});
|
return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/block-height/' + height, {responseType: 'text'});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBlockTxId$(hash: string, index: number): Observable<string> {
|
||||||
|
return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/block/' + hash + '/txid/' + index, { responseType: 'text' });
|
||||||
|
}
|
||||||
|
|
||||||
getAddress$(address: string): Observable<Address> {
|
getAddress$(address: string): Observable<Address> {
|
||||||
return this.httpClient.get<Address>(this.apiBaseUrl + this.apiBasePath + '/api/address/' + address);
|
return this.httpClient.get<Address>(this.apiBaseUrl + this.apiBasePath + '/api/address/' + address);
|
||||||
}
|
}
|
||||||
|
100
frontend/src/app/services/ord-api.service.ts
Normal file
100
frontend/src/app/services/ord-api.service.ts
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { catchError, forkJoin, map, Observable, of, switchMap, tap } from 'rxjs';
|
||||||
|
import { Inscription } from '../shared/ord/inscription.utils';
|
||||||
|
import { Transaction } from '../interfaces/electrs.interface';
|
||||||
|
import { getNextInscriptionMark, hexToBytes, extractInscriptionData } from '../shared/ord/inscription.utils';
|
||||||
|
import { decipherRunestone, Runestone, Etching, UNCOMMON_GOODS } from '../shared/ord/rune.utils';
|
||||||
|
import { ElectrsApiService } from './electrs-api.service';
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class OrdApiService {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private electrsApiService: ElectrsApiService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
decodeRunestone$(tx: Transaction): Observable<{ runestone: Runestone, runeInfo: { [id: string]: { etching: Etching; txid: string; } } }> {
|
||||||
|
const runestone = decipherRunestone(tx);
|
||||||
|
const runeInfo: { [id: string]: { etching: Etching; txid: string; } } = {};
|
||||||
|
|
||||||
|
if (runestone) {
|
||||||
|
const runesToFetch: Set<string> = new Set();
|
||||||
|
|
||||||
|
if (runestone.mint) {
|
||||||
|
runesToFetch.add(runestone.mint.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runestone.edicts.length) {
|
||||||
|
runestone.edicts.forEach(edict => {
|
||||||
|
runesToFetch.add(edict.id.toString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runesToFetch.size) {
|
||||||
|
const runeEtchingObservables = Array.from(runesToFetch).map(runeId => this.getEtchingFromRuneId$(runeId));
|
||||||
|
|
||||||
|
return forkJoin(runeEtchingObservables).pipe(
|
||||||
|
map((etchings) => {
|
||||||
|
etchings.forEach((el) => {
|
||||||
|
if (el) {
|
||||||
|
runeInfo[el.runeId] = { etching: el.etching, txid: el.txid };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { runestone: runestone, runeInfo };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return of({ runestone: runestone, runeInfo });
|
||||||
|
} else {
|
||||||
|
return of({ runestone: null, runeInfo: {} });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get etching from runeId by looking up the transaction that etched the rune
|
||||||
|
getEtchingFromRuneId$(runeId: string): Observable<{ runeId: string; etching: Etching; txid: string; }> {
|
||||||
|
if (runeId === '1:0') {
|
||||||
|
return of({ runeId, etching: UNCOMMON_GOODS, txid: '0000000000000000000000000000000000000000000000000000000000000000' });
|
||||||
|
} else {
|
||||||
|
const [blockNumber, txIndex] = runeId.split(':');
|
||||||
|
return this.electrsApiService.getBlockHashFromHeight$(parseInt(blockNumber)).pipe(
|
||||||
|
switchMap(blockHash => this.electrsApiService.getBlockTxId$(blockHash, parseInt(txIndex))),
|
||||||
|
switchMap(txId => this.electrsApiService.getTransaction$(txId)),
|
||||||
|
switchMap(tx => {
|
||||||
|
const runestone = decipherRunestone(tx);
|
||||||
|
if (runestone) {
|
||||||
|
const etching = runestone.etching;
|
||||||
|
if (etching) {
|
||||||
|
return of({ runeId, etching, txid: tx.txid });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return of(null);
|
||||||
|
}),
|
||||||
|
catchError(() => of(null))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decodeInscriptions(witness: string): Inscription[] | null {
|
||||||
|
|
||||||
|
const inscriptions: Inscription[] = [];
|
||||||
|
const raw = hexToBytes(witness);
|
||||||
|
let startPosition = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const pointer = getNextInscriptionMark(raw, startPosition);
|
||||||
|
if (pointer === -1) break;
|
||||||
|
|
||||||
|
const inscription = extractInscriptionData(raw, pointer);
|
||||||
|
if (inscription) {
|
||||||
|
inscriptions.push(inscription);
|
||||||
|
}
|
||||||
|
|
||||||
|
startPosition = pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
return inscriptions;
|
||||||
|
}
|
||||||
|
}
|
@ -9,13 +9,12 @@ import { IBackendInfo } from '../interfaces/websocket.interface';
|
|||||||
import { Acceleration, AccelerationHistoryParams } from '../interfaces/node-api.interface';
|
import { Acceleration, AccelerationHistoryParams } from '../interfaces/node-api.interface';
|
||||||
import { AccelerationStats } from '../components/acceleration/acceleration-stats/acceleration-stats.component';
|
import { AccelerationStats } from '../components/acceleration/acceleration-stats/acceleration-stats.component';
|
||||||
|
|
||||||
export type ProductType = 'enterprise' | 'community' | 'mining_pool' | 'custom';
|
|
||||||
export interface IUser {
|
export interface IUser {
|
||||||
username: string;
|
username: string;
|
||||||
email: string | null;
|
email: string | null;
|
||||||
passwordIsSet: boolean;
|
passwordIsSet: boolean;
|
||||||
snsId: string;
|
snsId: string;
|
||||||
type: ProductType;
|
type: 'enterprise' | 'community' | 'mining_pool';
|
||||||
subscription_tag: string;
|
subscription_tag: string;
|
||||||
status: 'pending' | 'verified' | 'disabled';
|
status: 'pending' | 'verified' | 'disabled';
|
||||||
features: string | null;
|
features: string | null;
|
||||||
|
409
frontend/src/app/shared/ord/inscription.utils.ts
Normal file
409
frontend/src/app/shared/ord/inscription.utils.ts
Normal file
@ -0,0 +1,409 @@
|
|||||||
|
// Adapted from https://github.com/ordpool-space/ordpool-parser/tree/ce04d7a5b6bb1cf37b9fdadd77ba430f5bd6e7d6/src
|
||||||
|
// Utils functions to decode ord inscriptions
|
||||||
|
|
||||||
|
export const OP_FALSE = 0x00;
|
||||||
|
export const OP_IF = 0x63;
|
||||||
|
export const OP_0 = 0x00;
|
||||||
|
|
||||||
|
export const OP_PUSHBYTES_3 = 0x03; // 3 -- not an actual opcode, but used in documentation --> pushes the next 3 bytes onto the stack.
|
||||||
|
export const OP_PUSHDATA1 = 0x4c; // 76 -- The next byte contains the number of bytes to be pushed onto the stack.
|
||||||
|
export const OP_PUSHDATA2 = 0x4d; // 77 -- The next two bytes contain the number of bytes to be pushed onto the stack in little endian order.
|
||||||
|
export const OP_PUSHDATA4 = 0x4e; // 78 -- The next four bytes contain the number of bytes to be pushed onto the stack in little endian order.
|
||||||
|
export const OP_ENDIF = 0x68; // 104 -- Ends an if/else block.
|
||||||
|
|
||||||
|
export const OP_1NEGATE = 0x4f; // 79 -- The number -1 is pushed onto the stack.
|
||||||
|
export const OP_RESERVED = 0x50; // 80 -- Transaction is invalid unless occuring in an unexecuted OP_IF branch
|
||||||
|
export const OP_PUSHNUM_1 = 0x51; // 81 -- also known as OP_1
|
||||||
|
export const OP_PUSHNUM_2 = 0x52; // 82 -- also known as OP_2
|
||||||
|
export const OP_PUSHNUM_3 = 0x53; // 83 -- also known as OP_3
|
||||||
|
export const OP_PUSHNUM_4 = 0x54; // 84 -- also known as OP_4
|
||||||
|
export const OP_PUSHNUM_5 = 0x55; // 85 -- also known as OP_5
|
||||||
|
export const OP_PUSHNUM_6 = 0x56; // 86 -- also known as OP_6
|
||||||
|
export const OP_PUSHNUM_7 = 0x57; // 87 -- also known as OP_7
|
||||||
|
export const OP_PUSHNUM_8 = 0x58; // 88 -- also known as OP_8
|
||||||
|
export const OP_PUSHNUM_9 = 0x59; // 89 -- also known as OP_9
|
||||||
|
export const OP_PUSHNUM_10 = 0x5a; // 90 -- also known as OP_10
|
||||||
|
export const OP_PUSHNUM_11 = 0x5b; // 91 -- also known as OP_11
|
||||||
|
export const OP_PUSHNUM_12 = 0x5c; // 92 -- also known as OP_12
|
||||||
|
export const OP_PUSHNUM_13 = 0x5d; // 93 -- also known as OP_13
|
||||||
|
export const OP_PUSHNUM_14 = 0x5e; // 94 -- also known as OP_14
|
||||||
|
export const OP_PUSHNUM_15 = 0x5f; // 95 -- also known as OP_15
|
||||||
|
export const OP_PUSHNUM_16 = 0x60; // 96 -- also known as OP_16
|
||||||
|
|
||||||
|
export const OP_RETURN = 0x6a; // 106 -- a standard way of attaching extra data to transactions is to add a zero-value output with a scriptPubKey consisting of OP_RETURN followed by data
|
||||||
|
|
||||||
|
//////////////////////////// Helper ///////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inscriptions may include fields before an optional body. Each field consists of two data pushes, a tag and a value.
|
||||||
|
* Currently, there are six defined fields:
|
||||||
|
*/
|
||||||
|
export const knownFields = {
|
||||||
|
// content_type, with a tag of 1, whose value is the MIME type of the body.
|
||||||
|
content_type: 0x01,
|
||||||
|
|
||||||
|
// pointer, with a tag of 2, see pointer docs: https://docs.ordinals.com/inscriptions/pointer.html
|
||||||
|
pointer: 0x02,
|
||||||
|
|
||||||
|
// parent, with a tag of 3, see provenance docs: https://docs.ordinals.com/inscriptions/provenance.html
|
||||||
|
parent: 0x03,
|
||||||
|
|
||||||
|
// metadata, with a tag of 5, see metadata docs: https://docs.ordinals.com/inscriptions/metadata.html
|
||||||
|
metadata: 0x05,
|
||||||
|
|
||||||
|
// metaprotocol, with a tag of 7, whose value is the metaprotocol identifier.
|
||||||
|
metaprotocol: 0x07,
|
||||||
|
|
||||||
|
// content_encoding, with a tag of 9, whose value is the encoding of the body.
|
||||||
|
content_encoding: 0x09,
|
||||||
|
|
||||||
|
// delegate, with a tag of 11, see delegate docs: https://docs.ordinals.com/inscriptions/delegate.html
|
||||||
|
delegate: 0xb
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the value for a given field from an array of field objects.
|
||||||
|
* It returns the value of the first object where the tag matches the specified field.
|
||||||
|
*
|
||||||
|
* @param fields - An array of objects containing tag and value properties.
|
||||||
|
* @param field - The field number to search for.
|
||||||
|
* @returns The value associated with the first matching field, or undefined if no match is found.
|
||||||
|
*/
|
||||||
|
export function getKnownFieldValue(fields: { tag: number; value: Uint8Array }[], field: number): Uint8Array | undefined {
|
||||||
|
const knownField = fields.find(x =>
|
||||||
|
x.tag === field);
|
||||||
|
|
||||||
|
if (knownField === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return knownField.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the values for a given field from an array of field objects.
|
||||||
|
* It returns the values of all objects where the tag matches the specified field.
|
||||||
|
*
|
||||||
|
* @param fields - An array of objects containing tag and value properties.
|
||||||
|
* @param field - The field number to search for.
|
||||||
|
* @returns An array of Uint8Array values associated with the matching fields. If no matches are found, an empty array is returned.
|
||||||
|
*/
|
||||||
|
export function getKnownFieldValues(fields: { tag: number; value: Uint8Array }[], field: number): Uint8Array[] {
|
||||||
|
const knownFields = fields.filter(x =>
|
||||||
|
x.tag === field
|
||||||
|
);
|
||||||
|
|
||||||
|
return knownFields.map(field => field.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for the next position of the ordinal inscription mark (0063036f7264)
|
||||||
|
* within the raw transaction data, starting from a given position.
|
||||||
|
*
|
||||||
|
* This function looks for a specific sequence of 6 bytes that represents the start of an ordinal inscription.
|
||||||
|
* If the sequence is found, the function returns the index immediately following the inscription mark.
|
||||||
|
* If the sequence is not found, the function returns -1, indicating no inscription mark was found.
|
||||||
|
*
|
||||||
|
* Note: This function uses a simple hardcoded approach based on the fixed length of the inscription mark.
|
||||||
|
*
|
||||||
|
* @returns The position immediately after the inscription mark, or -1 if not found.
|
||||||
|
*/
|
||||||
|
export function getNextInscriptionMark(raw: Uint8Array, startPosition: number): number {
|
||||||
|
|
||||||
|
// OP_FALSE
|
||||||
|
// OP_IF
|
||||||
|
// OP_PUSHBYTES_3: This pushes the next 3 bytes onto the stack.
|
||||||
|
// 0x6f, 0x72, 0x64: These bytes translate to the ASCII string "ord"
|
||||||
|
const inscriptionMark = new Uint8Array([OP_FALSE, OP_IF, OP_PUSHBYTES_3, 0x6f, 0x72, 0x64]);
|
||||||
|
|
||||||
|
for (let index = startPosition; index <= raw.length - 6; index++) {
|
||||||
|
if (raw[index] === inscriptionMark[0] &&
|
||||||
|
raw[index + 1] === inscriptionMark[1] &&
|
||||||
|
raw[index + 2] === inscriptionMark[2] &&
|
||||||
|
raw[index + 3] === inscriptionMark[3] &&
|
||||||
|
raw[index + 4] === inscriptionMark[4] &&
|
||||||
|
raw[index + 5] === inscriptionMark[5]) {
|
||||||
|
return index + 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////// Reader ///////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a specified number of bytes from a Uint8Array starting from a given pointer.
|
||||||
|
*
|
||||||
|
* @param raw - The Uint8Array from which bytes are to be read.
|
||||||
|
* @param pointer - The position in the array from where to start reading.
|
||||||
|
* @param n - The number of bytes to read.
|
||||||
|
* @returns A tuple containing the read bytes as Uint8Array and the updated pointer position.
|
||||||
|
*/
|
||||||
|
export function readBytes(raw: Uint8Array, pointer: number, n: number): [Uint8Array, number] {
|
||||||
|
const slice = raw.slice(pointer, pointer + n);
|
||||||
|
return [slice, pointer + n];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads data based on the Bitcoin script push opcode starting from a specified pointer in the raw data.
|
||||||
|
* Handles different opcodes and direct push (where the opcode itself signifies the number of bytes to push).
|
||||||
|
*
|
||||||
|
* @param raw - The raw transaction data as a Uint8Array.
|
||||||
|
* @param pointer - The current position in the raw data array.
|
||||||
|
* @returns A tuple containing the read data as Uint8Array and the updated pointer position.
|
||||||
|
*/
|
||||||
|
export function readPushdata(raw: Uint8Array, pointer: number): [Uint8Array, number] {
|
||||||
|
|
||||||
|
let [opcodeSlice, newPointer] = readBytes(raw, pointer, 1);
|
||||||
|
const opcode = opcodeSlice[0];
|
||||||
|
|
||||||
|
// Handle the special case of OP_0 (0x00) which pushes an empty array (interpreted as zero)
|
||||||
|
// fixes #18
|
||||||
|
if (opcode === OP_0) {
|
||||||
|
return [new Uint8Array(), newPointer];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the special case of OP_1NEGATE (-1)
|
||||||
|
if (opcode === OP_1NEGATE) {
|
||||||
|
// OP_1NEGATE pushes the value -1 onto the stack, represented as 0x81 in Bitcoin Script
|
||||||
|
return [new Uint8Array([0x81]), newPointer];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle minimal push numbers OP_PUSHNUM_1 (0x51) to OP_PUSHNUM_16 (0x60)
|
||||||
|
// which are used to push the values 0x01 (decimal 1) through 0x10 (decimal 16) onto the stack.
|
||||||
|
// To get the value, we can subtract OP_RESERVED (0x50) from the opcode to get the value to be pushed.
|
||||||
|
if (opcode >= OP_PUSHNUM_1 && opcode <= OP_PUSHNUM_16) {
|
||||||
|
// Convert opcode to corresponding byte value
|
||||||
|
const byteValue = opcode - OP_RESERVED;
|
||||||
|
return [Uint8Array.from([byteValue]), newPointer];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle direct push of 1 to 75 bytes (OP_PUSHBYTES_1 to OP_PUSHBYTES_75)
|
||||||
|
if (1 <= opcode && opcode <= 75) {
|
||||||
|
return readBytes(raw, newPointer, opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
let numBytes: number;
|
||||||
|
switch (opcode) {
|
||||||
|
case OP_PUSHDATA1: numBytes = 1; break;
|
||||||
|
case OP_PUSHDATA2: numBytes = 2; break;
|
||||||
|
case OP_PUSHDATA4: numBytes = 4; break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Invalid push opcode ${opcode} at position ${pointer}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let [dataSizeArray, nextPointer] = readBytes(raw, newPointer, numBytes);
|
||||||
|
let dataSize = littleEndianBytesToNumber(dataSizeArray);
|
||||||
|
return readBytes(raw, nextPointer, dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////// Conversion ////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a Uint8Array containing UTF-8 encoded data to a normal a UTF-16 encoded string.
|
||||||
|
*
|
||||||
|
* @param bytes - The Uint8Array containing UTF-8 encoded data.
|
||||||
|
* @returns The corresponding UTF-16 encoded JavaScript string.
|
||||||
|
*/
|
||||||
|
export function bytesToUnicodeString(bytes: Uint8Array): string {
|
||||||
|
const decoder = new TextDecoder('utf-8');
|
||||||
|
return decoder.decode(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Uint8Array to a string by treating each byte as a character code.
|
||||||
|
* It avoids interpreting bytes as UTF-8 encoded sequences.
|
||||||
|
* --> Again: it ignores UTF-8 encoding, which is necessary for binary content!
|
||||||
|
*
|
||||||
|
* Note: This method is different from just using `String.fromCharCode(...combinedData)` which can
|
||||||
|
* cause a "Maximum call stack size exceeded" error for large arrays due to the limitation of
|
||||||
|
* the spread operator in JavaScript. (previously the parser broke here, because of large content)
|
||||||
|
*
|
||||||
|
* @param bytes - The byte array to convert.
|
||||||
|
* @returns The resulting string where each byte value is treated as a direct character code.
|
||||||
|
*/
|
||||||
|
export function bytesToBinaryString(bytes: Uint8Array): string {
|
||||||
|
let resultStr = '';
|
||||||
|
for (let i = 0; i < bytes.length; i++) {
|
||||||
|
resultStr += String.fromCharCode(bytes[i]);
|
||||||
|
}
|
||||||
|
return resultStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a hexadecimal string to a Uint8Array.
|
||||||
|
*
|
||||||
|
* @param hex - A string of hexadecimal characters.
|
||||||
|
* @returns A Uint8Array representing the hex string.
|
||||||
|
*/
|
||||||
|
export function hexToBytes(hex: string): Uint8Array {
|
||||||
|
const bytes = new Uint8Array(hex.length / 2);
|
||||||
|
for (let i = 0, j = 0; i < hex.length; i += 2, j++) {
|
||||||
|
bytes[j] = parseInt(hex.slice(i, i + 2), 16);
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a Uint8Array to a hexadecimal string.
|
||||||
|
*
|
||||||
|
* @param bytes - A Uint8Array to convert.
|
||||||
|
* @returns A string of hexadecimal characters representing the byte array.
|
||||||
|
*/
|
||||||
|
export function bytesToHex(bytes: Uint8Array): string {
|
||||||
|
if (!bytes) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a little-endian byte array to a JavaScript number.
|
||||||
|
*
|
||||||
|
* This function interprets the provided bytes in little-endian format, where the least significant byte comes first.
|
||||||
|
* It constructs an integer value representing the number encoded by the bytes.
|
||||||
|
*
|
||||||
|
* @param byteArray - An array containing the bytes in little-endian format.
|
||||||
|
* @returns The number represented by the byte array.
|
||||||
|
*/
|
||||||
|
export function littleEndianBytesToNumber(byteArray: Uint8Array): number {
|
||||||
|
let number = 0;
|
||||||
|
for (let i = 0; i < byteArray.length; i++) {
|
||||||
|
// Extract each byte from byteArray, shift it to the left by 8 * i bits, and combine it with number.
|
||||||
|
// The shifting accounts for the little-endian format where the least significant byte comes first.
|
||||||
|
number |= byteArray[i] << (8 * i);
|
||||||
|
}
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenates multiple Uint8Array objects into a single Uint8Array.
|
||||||
|
*
|
||||||
|
* @param arrays - An array of Uint8Array objects to concatenate.
|
||||||
|
* @returns A new Uint8Array containing the concatenated results of the input arrays.
|
||||||
|
*/
|
||||||
|
export function concatUint8Arrays(arrays: Uint8Array[]): Uint8Array {
|
||||||
|
if (arrays.length === 0) {
|
||||||
|
return new Uint8Array();
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalLength = arrays.reduce((sum, arr) => sum + arr.length, 0);
|
||||||
|
const result = new Uint8Array(totalLength);
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
for (const array of arrays) {
|
||||||
|
result.set(array, offset);
|
||||||
|
offset += array.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////// Inscription ///////////////////////////
|
||||||
|
|
||||||
|
export interface Inscription {
|
||||||
|
body?: Uint8Array;
|
||||||
|
is_cropped?: boolean;
|
||||||
|
body_length?: number;
|
||||||
|
content_type?: Uint8Array;
|
||||||
|
content_type_str?: string;
|
||||||
|
delegate_txid?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts fields from the raw data until OP_0 is encountered.
|
||||||
|
*
|
||||||
|
* @param raw - The raw data to read.
|
||||||
|
* @param pointer - The current pointer where the reading starts.
|
||||||
|
* @returns An array of fields and the updated pointer position.
|
||||||
|
*/
|
||||||
|
export function extractFields(raw: Uint8Array, pointer: number): [{ tag: number; value: Uint8Array }[], number] {
|
||||||
|
|
||||||
|
const fields: { tag: number; value: Uint8Array }[] = [];
|
||||||
|
let newPointer = pointer;
|
||||||
|
let slice: Uint8Array;
|
||||||
|
|
||||||
|
while (newPointer < raw.length &&
|
||||||
|
// normal inscription - content follows now
|
||||||
|
(raw[newPointer] !== OP_0) &&
|
||||||
|
// delegate - inscription has no further content and ends directly here
|
||||||
|
(raw[newPointer] !== OP_ENDIF)
|
||||||
|
) {
|
||||||
|
|
||||||
|
// tags are encoded by ord as single-byte data pushes, but are accepted by ord as either single-byte pushes, or as OP_NUM data pushes.
|
||||||
|
// tags greater than or equal to 256 should be encoded as little endian integers with trailing zeros omitted.
|
||||||
|
// see: https://github.com/ordinals/ord/issues/2505
|
||||||
|
[slice, newPointer] = readPushdata(raw, newPointer);
|
||||||
|
const tag = slice.length === 1 ? slice[0] : littleEndianBytesToNumber(slice);
|
||||||
|
|
||||||
|
[slice, newPointer] = readPushdata(raw, newPointer);
|
||||||
|
const value = slice;
|
||||||
|
|
||||||
|
fields.push({ tag, value });
|
||||||
|
}
|
||||||
|
|
||||||
|
return [fields, newPointer];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts inscription data starting from the current pointer.
|
||||||
|
* @param raw - The raw data to read.
|
||||||
|
* @param pointer - The current pointer where the reading starts.
|
||||||
|
* @returns The parsed inscription or nullx
|
||||||
|
*/
|
||||||
|
export function extractInscriptionData(raw: Uint8Array, pointer: number): Inscription | null {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
let fields: { tag: number; value: Uint8Array }[];
|
||||||
|
let newPointer: number;
|
||||||
|
let slice: Uint8Array;
|
||||||
|
|
||||||
|
[fields, newPointer] = extractFields(raw, pointer);
|
||||||
|
|
||||||
|
// Now we are at the beginning of the body
|
||||||
|
// (or at the end of the raw data if there's no body)
|
||||||
|
if (newPointer < raw.length && raw[newPointer] === OP_0) {
|
||||||
|
newPointer++; // Skip OP_0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect body data until OP_ENDIF
|
||||||
|
const data: Uint8Array[] = [];
|
||||||
|
while (newPointer < raw.length && raw[newPointer] !== OP_ENDIF) {
|
||||||
|
[slice, newPointer] = readPushdata(raw, newPointer);
|
||||||
|
data.push(slice);
|
||||||
|
}
|
||||||
|
|
||||||
|
const combinedLengthOfAllArrays = data.reduce((acc, curr) => acc + curr.length, 0);
|
||||||
|
let combinedData = new Uint8Array(combinedLengthOfAllArrays);
|
||||||
|
|
||||||
|
// Copy all segments from data into combinedData, forming a single contiguous Uint8Array
|
||||||
|
let idx = 0;
|
||||||
|
for (const segment of data) {
|
||||||
|
combinedData.set(segment, idx);
|
||||||
|
idx += segment.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentTypeRaw = getKnownFieldValue(fields, knownFields.content_type);
|
||||||
|
let contentType: string;
|
||||||
|
|
||||||
|
if (!contentTypeRaw) {
|
||||||
|
contentType = 'undefined';
|
||||||
|
} else {
|
||||||
|
contentType = bytesToUnicodeString(contentTypeRaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
content_type_str: contentType,
|
||||||
|
body: combinedData.slice(0, 100_000), // Limit body to 100 kB for now
|
||||||
|
is_cropped: combinedData.length > 100_000,
|
||||||
|
body_length: combinedData.length,
|
||||||
|
delegate_txid: getKnownFieldValue(fields, knownFields.delegate) ? bytesToHex(getKnownFieldValue(fields, knownFields.delegate).reverse()) : null
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
255
frontend/src/app/shared/ord/rune.utils.ts
Normal file
255
frontend/src/app/shared/ord/rune.utils.ts
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
import { Transaction } from '../../interfaces/electrs.interface';
|
||||||
|
|
||||||
|
export const U128_MAX_BIGINT = 0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffffn;
|
||||||
|
|
||||||
|
export class RuneId {
|
||||||
|
block: number;
|
||||||
|
index: number;
|
||||||
|
|
||||||
|
constructor(block: number, index: number) {
|
||||||
|
this.block = block;
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
return `${this.block}:${this.index}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Etching = {
|
||||||
|
divisibility?: number;
|
||||||
|
premine?: bigint;
|
||||||
|
symbol?: string;
|
||||||
|
terms?: {
|
||||||
|
cap?: bigint;
|
||||||
|
amount?: bigint;
|
||||||
|
offset?: {
|
||||||
|
start?: bigint;
|
||||||
|
end?: bigint;
|
||||||
|
};
|
||||||
|
height?: {
|
||||||
|
start?: bigint;
|
||||||
|
end?: bigint;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
turbo?: boolean;
|
||||||
|
name?: string;
|
||||||
|
spacedName?: string;
|
||||||
|
supply?: bigint;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Edict = {
|
||||||
|
id: RuneId;
|
||||||
|
amount: bigint;
|
||||||
|
output: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Runestone = {
|
||||||
|
mint?: RuneId;
|
||||||
|
pointer?: number;
|
||||||
|
edicts?: Edict[];
|
||||||
|
etching?: Etching;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Message = {
|
||||||
|
fields: Record<number, bigint[]>;
|
||||||
|
edicts: Edict[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UNCOMMON_GOODS: Etching = {
|
||||||
|
divisibility: 0,
|
||||||
|
premine: 0n,
|
||||||
|
symbol: '⧉',
|
||||||
|
terms: {
|
||||||
|
cap: U128_MAX_BIGINT,
|
||||||
|
amount: 1n,
|
||||||
|
offset: {
|
||||||
|
start: 0n,
|
||||||
|
end: 0n,
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
start: 840000n,
|
||||||
|
end: 1050000n,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
turbo: false,
|
||||||
|
name: 'UNCOMMONGOODS',
|
||||||
|
spacedName: 'UNCOMMON•GOODS',
|
||||||
|
supply: U128_MAX_BIGINT,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Tag {
|
||||||
|
Body = 0,
|
||||||
|
Flags = 2,
|
||||||
|
Rune = 4,
|
||||||
|
Premine = 6,
|
||||||
|
Cap = 8,
|
||||||
|
Amount = 10,
|
||||||
|
HeightStart = 12,
|
||||||
|
HeightEnd = 14,
|
||||||
|
OffsetStart = 16,
|
||||||
|
OffsetEnd = 18,
|
||||||
|
Mint = 20,
|
||||||
|
Pointer = 22,
|
||||||
|
Cenotaph = 126,
|
||||||
|
|
||||||
|
Divisibility = 1,
|
||||||
|
Spacers = 3,
|
||||||
|
Symbol = 5,
|
||||||
|
Nop = 127,
|
||||||
|
}
|
||||||
|
|
||||||
|
const Flag = {
|
||||||
|
ETCHING: 1n,
|
||||||
|
TERMS: 1n << 1n,
|
||||||
|
TURBO: 1n << 2n,
|
||||||
|
CENOTAPH: 1n << 127n,
|
||||||
|
};
|
||||||
|
|
||||||
|
function hexToBytes(hex: string): Uint8Array {
|
||||||
|
return new Uint8Array(hex.match(/.{2}/g).map((byte) => parseInt(byte, 16)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function decodeLEB128(bytes: Uint8Array): bigint[] {
|
||||||
|
const integers: bigint[] = [];
|
||||||
|
let index = 0;
|
||||||
|
while (index < bytes.length) {
|
||||||
|
let value = BigInt(0);
|
||||||
|
let shift = 0;
|
||||||
|
let byte: number;
|
||||||
|
do {
|
||||||
|
byte = bytes[index++];
|
||||||
|
value |= BigInt(byte & 0x7f) << BigInt(shift);
|
||||||
|
shift += 7;
|
||||||
|
} while (byte & 0x80);
|
||||||
|
integers.push(value);
|
||||||
|
}
|
||||||
|
return integers;
|
||||||
|
}
|
||||||
|
|
||||||
|
function integersToMessage(integers: bigint[]): Message {
|
||||||
|
const message = {
|
||||||
|
fields: {},
|
||||||
|
edicts: [],
|
||||||
|
};
|
||||||
|
let inBody = false;
|
||||||
|
while (integers.length) {
|
||||||
|
if (!inBody) {
|
||||||
|
// The integers are interpreted as a sequence of tag/value pairs, with duplicate tags appending their value to the field value.
|
||||||
|
const tag: Tag = Number(integers.shift());
|
||||||
|
if (tag === Tag.Body) {
|
||||||
|
inBody = true;
|
||||||
|
} else {
|
||||||
|
const value = integers.shift();
|
||||||
|
if (message.fields[tag]) {
|
||||||
|
message.fields[tag].push(value);
|
||||||
|
} else {
|
||||||
|
message.fields[tag] = [value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If a tag with value zero is encountered, all following integers are interpreted as a series of four-integer edicts, each consisting of a rune ID block height, rune ID transaction index, amount, and output.
|
||||||
|
const height = integers.shift();
|
||||||
|
const txIndex = integers.shift();
|
||||||
|
const amount = integers.shift();
|
||||||
|
const output = integers.shift();
|
||||||
|
message.edicts.push({
|
||||||
|
id: new RuneId(Number(height), Number(txIndex)),
|
||||||
|
amount,
|
||||||
|
output,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseRuneName(rune: bigint): string {
|
||||||
|
let name = '';
|
||||||
|
rune += 1n;
|
||||||
|
while (rune > 0n) {
|
||||||
|
name = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[Number((rune - 1n) % 26n)] + name;
|
||||||
|
rune = (rune - 1n) / 26n;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function spaceRuneName(name: string, spacers: bigint): string {
|
||||||
|
let i = 0;
|
||||||
|
let spacedName = '';
|
||||||
|
while (spacers > 0n || i < name.length) {
|
||||||
|
spacedName += name[i];
|
||||||
|
if (spacers & 1n) {
|
||||||
|
spacedName += '•';
|
||||||
|
}
|
||||||
|
if (spacers > 0n) {
|
||||||
|
spacers >>= 1n;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return spacedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
function messageToRunestone(message: Message): Runestone {
|
||||||
|
let etching: Etching | undefined;
|
||||||
|
let mint: RuneId | undefined;
|
||||||
|
let pointer: number | undefined;
|
||||||
|
|
||||||
|
const flags = message.fields[Tag.Flags]?.[0] || 0n;
|
||||||
|
if (flags & Flag.ETCHING) {
|
||||||
|
const hasTerms = (flags & Flag.TERMS) > 0n;
|
||||||
|
const isTurbo = (flags & Flag.TURBO) > 0n;
|
||||||
|
const name = parseRuneName(message.fields[Tag.Rune]?.[0] ?? 0n);
|
||||||
|
etching = {
|
||||||
|
divisibility: Number(message.fields[Tag.Divisibility]?.[0] ?? 0n),
|
||||||
|
premine: message.fields[Tag.Premine]?.[0],
|
||||||
|
symbol: message.fields[Tag.Symbol]?.[0] ? String.fromCodePoint(Number(message.fields[Tag.Symbol][0])) : '¤',
|
||||||
|
terms: hasTerms ? {
|
||||||
|
cap: message.fields[Tag.Cap]?.[0],
|
||||||
|
amount: message.fields[Tag.Amount]?.[0],
|
||||||
|
offset: {
|
||||||
|
start: message.fields[Tag.OffsetStart]?.[0],
|
||||||
|
end: message.fields[Tag.OffsetEnd]?.[0],
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
start: message.fields[Tag.HeightStart]?.[0],
|
||||||
|
end: message.fields[Tag.HeightEnd]?.[0],
|
||||||
|
},
|
||||||
|
} : undefined,
|
||||||
|
turbo: isTurbo,
|
||||||
|
name,
|
||||||
|
spacedName: spaceRuneName(name, message.fields[Tag.Spacers]?.[0] ?? 0n),
|
||||||
|
};
|
||||||
|
etching.supply = (
|
||||||
|
(etching.terms?.cap ?? 0n) * (etching.terms?.amount ?? 0n)
|
||||||
|
) + (etching.premine ?? 0n);
|
||||||
|
}
|
||||||
|
const mintField = message.fields[Tag.Mint];
|
||||||
|
if (mintField) {
|
||||||
|
mint = new RuneId(Number(mintField[0]), Number(mintField[1]));
|
||||||
|
}
|
||||||
|
const pointerField = message.fields[Tag.Pointer];
|
||||||
|
if (pointerField) {
|
||||||
|
pointer = Number(pointerField[0]);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
mint,
|
||||||
|
pointer,
|
||||||
|
edicts: message.edicts,
|
||||||
|
etching,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decipherRunestone(tx: Transaction): Runestone | void {
|
||||||
|
const payload = tx.vout.find((vout) => vout.scriptpubkey.startsWith('6a5d'))?.scriptpubkey_asm.replace(/OP_\w+|\s/g, '');
|
||||||
|
if (!payload) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const integers = decodeLEB128(hexToBytes(payload));
|
||||||
|
const message = integersToMessage(integers);
|
||||||
|
return messageToRunestone(message);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
@ -102,6 +102,7 @@ import { AccelerationsListComponent } from '../components/acceleration/accelerat
|
|||||||
import { PendingStatsComponent } from '../components/acceleration/pending-stats/pending-stats.component';
|
import { PendingStatsComponent } from '../components/acceleration/pending-stats/pending-stats.component';
|
||||||
import { AccelerationStatsComponent } from '../components/acceleration/acceleration-stats/acceleration-stats.component';
|
import { AccelerationStatsComponent } from '../components/acceleration/acceleration-stats/acceleration-stats.component';
|
||||||
import { AccelerationSparklesComponent } from '../components/acceleration/sparkles/acceleration-sparkles.component';
|
import { AccelerationSparklesComponent } from '../components/acceleration/sparkles/acceleration-sparkles.component';
|
||||||
|
import { OrdDataComponent } from '../components/ord-data/ord-data.component';
|
||||||
|
|
||||||
import { BlockViewComponent } from '../components/block-view/block-view.component';
|
import { BlockViewComponent } from '../components/block-view/block-view.component';
|
||||||
import { EightBlocksComponent } from '../components/eight-blocks/eight-blocks.component';
|
import { EightBlocksComponent } from '../components/eight-blocks/eight-blocks.component';
|
||||||
@ -229,6 +230,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
|
|||||||
AccelerationStatsComponent,
|
AccelerationStatsComponent,
|
||||||
PendingStatsComponent,
|
PendingStatsComponent,
|
||||||
AccelerationSparklesComponent,
|
AccelerationSparklesComponent,
|
||||||
|
OrdDataComponent,
|
||||||
HttpErrorComponent,
|
HttpErrorComponent,
|
||||||
TwitterWidgetComponent,
|
TwitterWidgetComponent,
|
||||||
FaucetComponent,
|
FaucetComponent,
|
||||||
@ -361,6 +363,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
|
|||||||
AccelerationStatsComponent,
|
AccelerationStatsComponent,
|
||||||
PendingStatsComponent,
|
PendingStatsComponent,
|
||||||
AccelerationSparklesComponent,
|
AccelerationSparklesComponent,
|
||||||
|
OrdDataComponent,
|
||||||
HttpErrorComponent,
|
HttpErrorComponent,
|
||||||
TwitterWidgetComponent,
|
TwitterWidgetComponent,
|
||||||
TwitterLogin,
|
TwitterLogin,
|
||||||
|
Loading…
Reference in New Issue
Block a user