Merge branch 'master' into hunicus/docs-links-alignment

This commit is contained in:
hunicus
2024-04-01 19:06:18 +09:00
committed by GitHub
51 changed files with 7271 additions and 7325 deletions

View File

@@ -19,6 +19,7 @@
"@typescript-eslint/no-this-alias": 1,
"@typescript-eslint/no-var-requires": 1,
"@typescript-eslint/explicit-function-return-type": 1,
"@typescript-eslint/no-unused-vars": 1,
"no-case-declarations": 1,
"no-console": 1,
"no-constant-condition": 1,

View File

@@ -223,11 +223,11 @@
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "mempool:build"
"buildTarget": "mempool:build"
},
"configurations": {
"production": {
"browserTarget": "mempool:build:production"
"buildTarget": "mempool:build:production"
},
"local": {
"proxyConfig": "proxy.conf.local.js",
@@ -264,7 +264,7 @@
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "mempool:build"
"buildTarget": "mempool:build"
}
},
"e2e": {
@@ -303,7 +303,7 @@
}
},
"serve-ssr": {
"builder": "@nguniversal/builders:ssr-dev-server",
"builder": "@angular-devkit/build-angular:ssr-dev-server",
"options": {
"browserTarget": "mempool:build",
"serverTarget": "mempool:server"
@@ -318,7 +318,7 @@
}
},
"prerender": {
"builder": "@nguniversal/builders:prerender",
"builder": "@angular-devkit/build-angular:prerender",
"options": {
"browserTarget": "mempool:build:production",
"serverTarget": "mempool:server:production",

File diff suppressed because it is too large Load Diff

View File

@@ -38,7 +38,13 @@ export const mockWebSocket = () => {
win.mockServer = server;
win.mockServer.on('connection', (socket) => {
win.mockSocket = socket;
win.mockSocket.send('{"action":"init"}');
win.mockSocket.send('{"conversions":{"USD":32365.338815782445}}');
cy.readFile('cypress/fixtures/mainnet_live2hchart.json', 'ascii').then((fixture) => {
win.mockSocket.send(JSON.stringify(fixture));
});
cy.readFile('cypress/fixtures/mainnet_mempoolInfo.json', 'ascii').then((fixture) => {
win.mockSocket.send(JSON.stringify(fixture));
});
});
win.mockServer.on('message', (message) => {
@@ -75,8 +81,6 @@ export const emitMempoolInfo = ({
switch (params.command) {
case "init": {
win.mockSocket.send('{"action":"init"}');
win.mockSocket.send('{"action":"want","data":["blocks","stats","mempool-blocks","live-2h-chart"]}');
win.mockSocket.send('{"conversions":{"USD":32365.338815782445}}');
cy.readFile('cypress/fixtures/mainnet_live2hchart.json', 'ascii').then((fixture) => {
win.mockSocket.send(JSON.stringify(fixture));

11999
frontend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -64,24 +64,25 @@
"cypress:run:ci:staging": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-staging 4200 cypress:run:record"
},
"dependencies": {
"@angular-devkit/build-angular": "^16.1.1",
"@angular/animations": "^16.1.1",
"@angular/cli": "^16.1.1",
"@angular/common": "^16.1.1",
"@angular/compiler": "^16.1.1",
"@angular/core": "^16.1.1",
"@angular/forms": "^16.1.1",
"@angular/localize": "^16.1.1",
"@angular/platform-browser": "^16.1.1",
"@angular/platform-browser-dynamic": "^16.1.1",
"@angular/platform-server": "^16.1.1",
"@angular/router": "^16.1.1",
"@fortawesome/angular-fontawesome": "~0.13.0",
"@angular-devkit/build-angular": "^17.3.1",
"@angular/animations": "^17.3.1",
"@angular/cli": "^17.3.1",
"@angular/common": "^17.3.1",
"@angular/compiler": "^17.3.1",
"@angular/core": "^17.3.1",
"@angular/forms": "^17.3.1",
"@angular/localize": "^17.3.1",
"@angular/platform-browser": "^17.3.1",
"@angular/platform-browser-dynamic": "^17.3.1",
"@angular/platform-server": "^17.3.1",
"@angular/router": "^17.3.1",
"@angular/ssr": "^17.3.1",
"@fortawesome/angular-fontawesome": "~0.14.1",
"@fortawesome/fontawesome-common-types": "~6.5.1",
"@fortawesome/fontawesome-svg-core": "~6.5.1",
"@fortawesome/free-solid-svg-icons": "~6.5.1",
"@mempool/mempool.js": "2.3.0",
"@ng-bootstrap/ng-bootstrap": "^15.1.0",
"@ng-bootstrap/ng-bootstrap": "^16.0.0",
"@types/qrcode": "~1.5.0",
"bootstrap": "~4.6.2",
"browserify": "^17.0.0",
@@ -89,29 +90,29 @@
"domino": "^2.1.6",
"echarts": "~5.5.0",
"lightweight-charts": "~3.8.0",
"ngx-echarts": "~16.2.0",
"ngx-infinite-scroll": "^16.0.0",
"ngx-echarts": "~17.1.0",
"ngx-infinite-scroll": "^17.0.0",
"qrcode": "1.5.1",
"rxjs": "~7.8.1",
"tinyify": "^3.1.0",
"esbuild": "^0.20.2",
"tinyify": "^4.0.0",
"tlite": "^0.1.9",
"tslib": "~2.6.0",
"zone.js": "~0.13.1"
"zone.js": "~0.14.4"
},
"devDependencies": {
"@angular/compiler-cli": "^16.1.1",
"@angular/language-service": "^16.1.1",
"@nguniversal/builders": "16.1.1",
"@nguniversal/express-engine": "16.1.1",
"@angular/compiler-cli": "^17.3.1",
"@angular/language-service": "^17.3.1",
"@types/node": "^18.11.9",
"@typescript-eslint/eslint-plugin": "^5.48.1",
"@typescript-eslint/parser": "^5.48.1",
"eslint": "^8.31.0",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@typescript-eslint/parser": "^7.4.0",
"eslint": "^8.57.0",
"browser-sync": "^3.0.0",
"http-proxy-middleware": "~2.0.6",
"prettier": "^3.0.0",
"source-map-support": "^0.5.21",
"ts-node": "~10.9.1",
"typescript": "~4.9.3"
"typescript": "~5.4.3"
},
"optionalDependencies": {
"@cypress/schematic": "^2.5.0",

View File

@@ -1,4 +1,3 @@
import 'zone.js/dist/zone-node';
import './src/resources/config.js';
import * as domino from 'domino';

View File

@@ -1,12 +1,11 @@
import 'zone.js/dist/zone-node';
import 'zone.js';
import './src/resources/config.js';
import { ngExpressEngine } from '@nguniversal/express-engine';
import { CommonEngine } from '@angular/ssr';
import * as express from 'express';
import * as fs from 'fs';
import * as path from 'path';
import * as domino from 'domino';
import { createProxyMiddleware } from 'http-proxy-middleware';
import { join } from 'path';
import { AppServerModule } from './src/main.server';
@@ -15,6 +14,8 @@ import { existsSync } from 'fs';
import { ResizeObserver } from './shims';
const commonEngine = new CommonEngine();
const template = fs.readFileSync(path.join(process.cwd(), 'dist/mempool/browser/en-US/', 'index.html')).toString();
const win = domino.createWindow(template);
@@ -58,35 +59,32 @@ global['localStorage'] = {
export function app(locale: string): express.Express {
const server = express();
const distFolder = join(process.cwd(), `dist/mempool/browser/${locale}`);
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
const indexHtml = join(distFolder, 'index.html');
server.set('view engine', 'html');
server.set('views', distFolder);
// static file handler so we send HTTP 404 to nginx
server.get('/**.(css|js|json|ico|webmanifest|png|jpg|jpeg|svg|mp4)*', express.static(distFolder, { maxAge: '1y', fallthrough: false }));
// handle page routes
server.get('/**', getLocalizedSSR(indexHtml));
server.get('*', (req, res, next) => {
const { protocol, originalUrl, baseUrl, headers } = req;
commonEngine
.render({
bootstrap: AppServerModule,
documentFilePath: indexHtml,
url: `${protocol}://${headers.host}${originalUrl}`,
publicPath: distFolder,
providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
})
.then((html) => res.send(html))
.catch((err) => next(err));
});
return server;
}
function getLocalizedSSR(indexHtml) {
return (req, res) => {
res.render(indexHtml, {
req,
providers: [
{ provide: APP_BASE_HREF, useValue: req.baseUrl }
]
});
}
}
// only used for development mode
function run(): void {
@@ -107,6 +105,4 @@ const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';
}

View File

@@ -1,5 +1,5 @@
<div class="grid-align" [style.gridTemplateColumns]="'repeat(auto-fit, ' + resolution + 'px)'">
<div class="graph-alignment" [class.grid-align]="!autofit" [style.gridTemplateColumns]="'repeat(auto-fit, ' + resolution + 'px)'">
<div class="block-overview-graph">
<canvas *browserOnly class="block-overview-canvas" [class.clickable]="!!hoverTx" #blockCanvas></canvas>
<div class="loader-wrapper" [class.hidden]="(!isLoading || disableSpinner) && !unavailable">

View File

@@ -22,9 +22,12 @@
}
}
.grid-align {
.graph-alignment {
position: relative;
width: 100%;
}
.grid-align {
display: grid;
grid-template-columns: repeat(auto-fit, 75px);
justify-content: center;

View File

@@ -32,6 +32,7 @@ const unmatchedAuditColors = {
export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, OnChanges {
@Input() isLoading: boolean;
@Input() resolution: number;
@Input() autofit: boolean = false;
@Input() blockLimit: number;
@Input() orientation = 'left';
@Input() flip = true;
@@ -206,6 +207,10 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left', resetLayout: boolean = false): void {
if (this.scene) {
add = add.filter(tx => !this.scene.txs[tx.txid]);
remove = remove.filter(txid => this.scene.txs[txid]);
change = change.filter(tx => this.scene.txs[tx.txid]);
this.scene.update(add, remove, change, direction, resetLayout);
this.start();
this.updateSearchHighlight();

View File

@@ -70,8 +70,9 @@
<div class="col-sm chart-container">
<app-block-overview-graph
#blockGraph
[autofit]="true"
[isLoading]="false"
[resolution]="80"
[resolution]="86"
[blockLimit]="stateService.blockVSize"
[orientation]="'top'"
[flip]="false"

View File

@@ -97,7 +97,7 @@
<div class="difficulty-stats">
<div class="item">
<div class="card-text bigger">
<app-btc [satoshis]="312500000"></app-btc>
<app-btc [satoshis]="nextSubsidy"></app-btc>
</div>
<div class="symbol">
<span i18n="difficulty-box.new-subsidy">New subsidy</span>

View File

@@ -62,6 +62,7 @@ export class DifficultyComponent implements OnInit {
expectedIndex: number;
difference: number;
shapes: DiffShape[];
nextSubsidy: number;
tooltipPosition = { x: 0, y: 0 };
hoverSection: DiffShape | void;
@@ -106,6 +107,7 @@ export class DifficultyComponent implements OnInit {
const newEpochStart = Math.floor(this.stateService.latestBlockHeight / EPOCH_BLOCK_LENGTH) * EPOCH_BLOCK_LENGTH;
const newExpectedHeight = Math.floor(newEpochStart + da.expectedBlocks);
this.now = new Date().getTime();
this.nextSubsidy = getNextBlockSubsidy(maxHeight);
if (blocksUntilHalving < da.remainingBlocks && !this.userSelectedMode) {
this.mode = 'halving';
@@ -233,3 +235,16 @@ export class DifficultyComponent implements OnInit {
this.hoverSection = null;
}
}
function getNextBlockSubsidy(height: number): number {
const halvings = Math.floor(height / 210_000) + 1;
// Force block reward to zero when right shift is undefined.
if (halvings >= 64) {
return 0;
}
let subsidy = BigInt(50 * 100_000_000);
// Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
subsidy >>= BigInt(halvings);
return Number(subsidy);
}

View File

@@ -66,7 +66,7 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
return;
}
const samples = [];
const txs = this.transactions.filter(tx => !tx.acc).map(tx => { return { vsize: tx.vsize, rate: tx.rate || (tx.fee / tx.vsize) }; }).sort((a, b) => { return b.rate - a.rate; });
const txs = this.transactions.map(tx => { return { vsize: tx.vsize, rate: tx.rate || (tx.fee / tx.vsize) }; }).sort((a, b) => { return b.rate - a.rate; });
const maxBlockVSize = this.stateService.env.BLOCK_WEIGHT_UNITS / 4;
const sampleInterval = maxBlockVSize / this.numSamples;
let cumVSize = 0;

View File

@@ -265,8 +265,8 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges, On
type: 'value',
axisLabel: {
fontSize: 11,
formatter: (value) => {
return this.weightMode ? value * 4 : value;
formatter: (value): string => {
return this.weightMode ? (value * 4).toString() : value.toString();
}
},
splitLine: {

View File

@@ -20,10 +20,12 @@
-
<app-fee-rate [fee]="projectedBlock.feeRange[projectedBlock.feeRange.length - 1]" rounding="1.0-0" unitClass=""></app-fee-rate>
</div>
<div *ngIf="showMiningInfo" class="block-size">
<div *ngIf="showMiningInfo$ | async; else noMiningInfo" class="block-size">
<app-amount [attr.data-cy]="'mempool-block-' + i + '-total-fees'" [satoshis]="projectedBlock.totalFees" digitsInfo="1.2-3" [noFiat]="true"></app-amount>
</div>
<div *ngIf="!showMiningInfo" class="block-size" [innerHTML]="'&lrm;' + (projectedBlock.blockSize | bytes: 2)"></div>
<ng-template #noMiningInfo>
<div class="block-size" [innerHTML]="'&lrm;' + (projectedBlock.blockSize | bytes: 2)"></div>
</ng-template>
<div [attr.data-cy]="'mempool-block-' + i + '-transaction-count'" class="transaction-count">
<ng-container *ngTemplateOutlet="projectedBlock.nTx === 1 ? transactionsSingular : transactionsPlural; context: {$implicit: projectedBlock.nTx | number}"></ng-container>
<ng-template #transactionsSingular let-i i18n="shared.transaction-count.singular">{{ i }} transaction</ng-template>

View File

@@ -1,5 +1,5 @@
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, HostListener, Input, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core';
import { Subscription, Observable, of, combineLatest } from 'rxjs';
import { Subscription, Observable, of, combineLatest, BehaviorSubject } from 'rxjs';
import { MempoolBlock } from '../../interfaces/websocket.interface';
import { StateService } from '../../services/state.service';
import { Router } from '@angular/router';
@@ -42,6 +42,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
mempoolBlocks$: Observable<MempoolBlock[]>;
difficultyAdjustments$: Observable<DifficultyAdjustment>;
loadingBlocks$: Observable<boolean>;
showMiningInfo$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
blocksSubscription: Subscription;
mempoolBlocksFull: MempoolBlock[] = [];
@@ -57,10 +58,8 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
network = '';
now = new Date().getTime();
timeOffset = 0;
showMiningInfo = false;
timeLtrSubscription: Subscription;
timeLtr: boolean;
showMiningInfoSubscription: Subscription;
animateEntry: boolean = false;
blockOffset: number = 155;
@@ -98,10 +97,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
this.widthChange.emit(this.mempoolWidth);
if (['', 'testnet', 'signet'].includes(this.stateService.network)) {
this.showMiningInfoSubscription = this.stateService.showMiningInfo$.subscribe((showMiningInfo) => {
this.showMiningInfo = showMiningInfo;
this.cd.markForCheck();
});
this.showMiningInfo$ = this.stateService.showMiningInfo$;
}
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
@@ -267,7 +263,6 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
this.chainTipSubscription.unsubscribe();
this.keySubscription.unsubscribe();
this.isTabHiddenSubscription.unsubscribe();
this.showMiningInfoSubscription.unsubscribe();
clearTimeout(this.resetTransitionTimeout);
}

View File

@@ -411,7 +411,6 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
padding: [20, 0, 0, 0],
},
type: 'time',
boundaryGap: false,
axisLine: { onZero: true },
axisLabel: {
margin: 20,

View File

@@ -6,7 +6,7 @@
<span class="menu-click text-nowrap ellipsis">
<strong>
<span *ngIf="user.username.includes('@'); else usernamenospace">{{ user.username }}</span>
<ng-template #usernamenospace>@{{ user.username }}</ng-template>
<ng-template #usernamenospace>&#64;{{ user.username }}</ng-template>
</strong>
</span>
<span class="badge mr-1 badge-og" *ngIf="user.ogRank">

View File

@@ -24,7 +24,7 @@ export class StartComponent implements OnInit, AfterViewChecked, OnDestroy {
timeLtrSubscription: Subscription;
timeLtr: boolean = this.stateService.timeLtr.value;
chainTipSubscription: Subscription;
chainTip: number = 100;
chainTip: number = -1;
tipIsSet: boolean = false;
lastMark: MarkBlockState;
markBlockSubscription: Subscription;

View File

@@ -326,7 +326,7 @@
<br>
<p>If you have any questions about this Policy, would like to speak with us about the use of our Marks in ways not described in the Policy, or see any abuse of our Marks, please email us at &lt;legal@mempool.space&gt;</p>
<p>If you have any questions about this Policy, would like to speak with us about the use of our Marks in ways not described in the Policy, or see any abuse of our Marks, please email us at &lt;legal&#64;mempool.space&gt;</p>
</ol>

View File

@@ -1,13 +1,16 @@
import { ChangeDetectionStrategy, Component, Input, Output, EventEmitter, NgZone, OnInit } from '@angular/core';
import { SeoService } from '../../services/seo.service';
import { ApiService } from '../../services/api.service';
import { delay, Observable, switchMap, tap, zip } from 'rxjs';
import { delay, Observable, of, switchMap, tap, zip } from 'rxjs';
import { AssetsService } from '../../services/assets.service';
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
import { StateService } from '../../services/state.service';
import { EChartsOption, echarts } from '../../graphs/echarts';
import { isMobile } from '../../shared/common.utils';
import { AmountShortenerPipe } from '../../shared/pipes/amount-shortener.pipe';
import { getFlagEmoji } from '../../shared/common.utils';
import { lerpColor } from '../../shared/graphs.utils';
@Component({
selector: 'app-nodes-channels-map',
@@ -50,6 +53,7 @@ export class NodesChannelsMap implements OnInit {
private router: Router,
private zone: NgZone,
private activatedRoute: ActivatedRoute,
private amountShortenerPipe: AmountShortenerPipe,
) {
}
@@ -86,10 +90,12 @@ export class NodesChannelsMap implements OnInit {
return zip(
this.assetsService.getWorldMapJson$,
this.style !== 'channelpage' ? this.apiService.getChannelsGeo$(params.get('public_key') ?? undefined, this.style) : [''],
[params.get('public_key') ?? undefined]
[params.get('public_key') ?? undefined],
this.style === 'widget' ? of(undefined) : this.apiService.getWorldNodes$(),
).pipe(tap((data) => {
echarts.registerMap('world', data[0]);
let maxLiquidity = data[3]?.maxLiquidity;
const channelsLoc = [];
const nodes = [];
const nodesPubkeys = {};
@@ -197,13 +203,24 @@ export class NodesChannelsMap implements OnInit {
this.zoom = -0.05 * distance + 8;
}
this.prepareChartOptions(nodes, channelsLoc);
if (data[3]) {
for (const node of nodes) {
const foundNode = data[3].nodes.find((n) => n[2] === node[3]);
if (foundNode) {
node.push(foundNode[4], foundNode[5], foundNode[6]?.en, foundNode[7]);
maxLiquidity = Math.max(maxLiquidity ?? 0, foundNode[4]);
}
}
}
maxLiquidity = Math.max(1, maxLiquidity);
this.prepareChartOptions(nodes, channelsLoc, maxLiquidity);
}));
})
);
}
prepareChartOptions(nodes, channels) {
prepareChartOptions(nodes, channels, maxLiquidity) {
let title: object;
if (channels.length === 0) {
if (!this.placeholder) {
@@ -267,7 +284,12 @@ export class NodesChannelsMap implements OnInit {
data: nodes,
coordinateSystem: 'geo',
geoIndex: 0,
symbolSize: this.nodeSize,
symbolSize: (params) => {
if (maxLiquidity) {
return 10 * Math.pow(params[5] / maxLiquidity, 0.2) + 3;
}
return this.nodeSize;
},
tooltip: {
show: true,
backgroundColor: 'rgba(17, 19, 31, 1)',
@@ -281,11 +303,25 @@ export class NodesChannelsMap implements OnInit {
formatter: (value) => {
const data = value.data;
const alias = data[4].length > 0 ? data[4] : data[3].slice(0, 20);
return `<b style="color: white">${alias}</b>`;
}
const liquidity = data[5] >= 100000000 ?
`${this.amountShortenerPipe.transform(data[5] / 100000000)} BTC` :
`${this.amountShortenerPipe.transform(data[5], 2)} sats`;
return `
<b style="color: white">${alias}</b><br>
${liquidity}<br>` +
$localize`:@@205c1b86ac1cc419c4d0cca51fdde418c4ffdc20:${data[6]}:INTERPOLATION: channels` + `<br>
${getFlagEmoji(data[8])} ${data[7]}
`;
},
},
itemStyle: {
color: 'white',
color: (params) => {
if (!maxLiquidity) {
return 'white';
}
return `${lerpColor('#1E88E5', '#D81B60', Math.pow(params.data[5] / maxLiquidity, 0.2))}`;
},
opacity: 1,
borderColor: 'black',
borderWidth: 0,
@@ -361,8 +397,6 @@ export class NodesChannelsMap implements OnInit {
}
chartOptions.series[0].itemStyle.borderWidth = nodeBorder;
chartOptions.series[0].symbolSize += e.zoom > 1 ? speed * 15 : -speed * 15;
chartOptions.series[0].symbolSize = Math.max(4, Math.min(7, chartOptions.series[0].symbolSize));
chartOptions.series[1].lineStyle.opacity += e.zoom > 1 ? speed : -speed;
chartOptions.series[1].lineStyle.width += e.zoom > 1 ? speed : -speed;

View File

@@ -1,8 +1,8 @@
import { Inject, Injectable, PLATFORM_ID } from '@angular/core';
import { Inject, Injectable, PLATFORM_ID, makeStateKey, TransferState } from '@angular/core';
import { HttpInterceptor, HttpEvent, HttpRequest, HttpHandler, HttpResponse, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
import { TransferState, makeStateKey } from '@angular/platform-browser';
import { isPlatformBrowser } from '@angular/common';
@Injectable()

View File

@@ -7,5 +7,5 @@ if (environment.production) {
enableProdMode();
}
export { AppServerModule } from './app/app.server.module';
export { AppServerModule } from './app/app.module.server';
export { renderModule } from '@angular/platform-server';

View File

@@ -32,19 +32,19 @@ const githubSecret = process.env.GITHUB_TOKEN;
const CONFIG_FILE_NAME = 'mempool-frontend-config.json';
let configContent = {};
var PATH;
var ASSETS_PATH;
if (process.argv[2]) {
PATH = process.argv[2];
PATH += PATH.endsWith("/") ? "" : "/"
PATH = path.resolve(path.normalize(PATH));
console.log(`[sync-assets] using PATH ${PATH}`);
if (!fs.existsSync(PATH)){
console.log(`${LOG_TAG} ${PATH} does not exist, creating`);
fs.mkdirSync(PATH, { recursive: true });
ASSETS_PATH = process.argv[2];
ASSETS_PATH += ASSETS_PATH.endsWith("/") ? "" : "/"
ASSETS_PATH = path.resolve(path.normalize(ASSETS_PATH));
console.log(`[sync-assets] using ASSETS_PATH ${ASSETS_PATH}`);
if (!fs.existsSync(ASSETS_PATH)){
console.log(`${LOG_TAG} ${ASSETS_PATH} does not exist, creating`);
fs.mkdirSync(ASSETS_PATH, { recursive: true });
}
}
if (!PATH) {
if (!ASSETS_PATH) {
throw new Error('Resource path argument is not set');
}
@@ -125,7 +125,8 @@ function downloadMiningPoolLogos$() {
if (verbose) {
console.log(`${LOG_TAG} Processing ${poolLogo.name}`);
}
const filePath = `${PATH}/mining-pools/${poolLogo.name}`;
console.log(`${ASSETS_PATH}/mining-pools/${poolLogo.name}`);
const filePath = `${ASSETS_PATH}/mining-pools/${poolLogo.name}`;
if (fs.existsSync(filePath)) {
const localHash = getLocalHash(filePath);
if (verbose) {
@@ -152,7 +153,7 @@ function downloadMiningPoolLogos$() {
}
} else {
console.log(`${LOG_TAG} \t\t${poolLogo.name} is missing, downloading...`);
const miningPoolsDir = `${PATH}/mining-pools/`;
const miningPoolsDir = `${ASSETS_PATH}/mining-pools/`;
if (!fs.existsSync(miningPoolsDir)){
fs.mkdirSync(miningPoolsDir, { recursive: true });
}
@@ -219,7 +220,7 @@ function downloadPromoVideoSubtiles$() {
if (verbose) {
console.log(`${LOG_TAG} Processing ${language.name}`);
}
const filePath = `${PATH}/promo-video/${language.name}`;
const filePath = `${ASSETS_PATH}/promo-video/${language.name}`;
if (fs.existsSync(filePath)) {
if (verbose) {
console.log(`${LOG_TAG} \t${language.name} remote promo video hash ${language.sha}`);
@@ -245,7 +246,7 @@ function downloadPromoVideoSubtiles$() {
}
} else {
console.log(`${LOG_TAG} \t\t${language.name} is missing, downloading`);
const promoVideosDir = `${PATH}/promo-video/`;
const promoVideosDir = `${ASSETS_PATH}/promo-video/`;
if (!fs.existsSync(promoVideosDir)){
fs.mkdirSync(promoVideosDir, { recursive: true });
}
@@ -313,7 +314,7 @@ function downloadPromoVideo$() {
if (item.name !== 'promo.mp4') {
continue;
}
const filePath = `${PATH}/promo-video/mempool-promo.mp4`;
const filePath = `${ASSETS_PATH}/promo-video/mempool-promo.mp4`;
if (fs.existsSync(filePath)) {
const localHash = getLocalHash(filePath);
@@ -373,16 +374,16 @@ if (configContent.BASE_MODULE && configContent.BASE_MODULE === 'liquid') {
const testnetAssetsMinimalJsonUrl = 'https://raw.githubusercontent.com/Blockstream/asset_registry_testnet_db/master/index.minimal.json';
console.log(`${LOG_TAG} Downloading assets`);
download(`${PATH}/assets.json`, assetsJsonUrl);
download(`${ASSETS_PATH}/assets.json`, assetsJsonUrl);
console.log(`${LOG_TAG} Downloading assets minimal`);
download(`${PATH}/assets.minimal.json`, assetsMinimalJsonUrl);
download(`${ASSETS_PATH}/assets.minimal.json`, assetsMinimalJsonUrl);
console.log(`${LOG_TAG} Downloading testnet assets`);
download(`${PATH}/assets-testnet.json`, testnetAssetsJsonUrl);
download(`${ASSETS_PATH}/assets-testnet.json`, testnetAssetsJsonUrl);
console.log(`${LOG_TAG} Downloading testnet assets minimal`);
download(`${PATH}/assets-testnet.minimal.json`, testnetAssetsMinimalJsonUrl);
download(`${ASSETS_PATH}/assets-testnet.minimal.json`, testnetAssetsMinimalJsonUrl);
} else {
if (verbose) {
console.log(`${LOG_TAG} BASE_MODULE is not set to Liquid (currently ${configContent.BASE_MODULE}), skipping downloading assets`);

View File

@@ -7,7 +7,7 @@
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"module": "ES2020",
"module": "ES2022",
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
@@ -15,7 +15,7 @@
"node_modules/@types"
],
"lib": [
"ES2018",
"ES2022",
"dom",
"dom.iterable"
]