mirror of
https://github.com/placeholder-soft/web.git
synced 2026-01-12 22:45:00 +08:00
* Add datadog rum instrumentation * use node_env * Remove non-null assertion * Fixes * Fix envs
476 lines
13 KiB
JavaScript
476 lines
13 KiB
JavaScript
const express = require('express');
|
|
const path = require('path');
|
|
const basicAuth = require('express-basic-auth');
|
|
const fs = require('fs');
|
|
const notFound = require('./404.js');
|
|
const bodyParser = require('body-parser');
|
|
const fetch = require('node-fetch');
|
|
const dotenv = require('dotenv');
|
|
|
|
dotenv.config();
|
|
|
|
const unless = function (path, middleware) {
|
|
return function (req, res, next) {
|
|
if (path === req.baseUrl) {
|
|
return next();
|
|
} else {
|
|
return middleware(req, res, next);
|
|
}
|
|
};
|
|
};
|
|
|
|
const app = express();
|
|
|
|
app.use(express.static('static'));
|
|
|
|
app.use(bodyParser.json());
|
|
|
|
app.get('/api/_health', (_, res) => {
|
|
res.sendStatus(200);
|
|
});
|
|
|
|
app.post('/api/rateMessage', (req, res) => {
|
|
const { message_id, rating_value } = req.body;
|
|
|
|
const data = {
|
|
api_key: process.env.MENDABLE_SERVER_API_KEY,
|
|
message_id,
|
|
rating_value,
|
|
};
|
|
|
|
fetch('https://api.mendable.ai/v1/rateMessage', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(data),
|
|
})
|
|
.then((response) => res.json(response))
|
|
.catch((error) => res.status(400));
|
|
});
|
|
|
|
app.get('/base-camp', (req, res) => {
|
|
res.redirect('/base-learn/docs/welcome');
|
|
});
|
|
|
|
app.get('/base-learn', (req, res) => {
|
|
res.redirect('/base-learn/docs/welcome');
|
|
});
|
|
|
|
app.get('/basecamp', (req, res) => {
|
|
res.redirect('/base-learn/docs/welcome');
|
|
});
|
|
|
|
app.get('/baselearn', (req, res) => {
|
|
res.redirect('/base-learn/docs/welcome');
|
|
});
|
|
|
|
app.get('/using-base', (req, res) => {
|
|
res.redirect('/docs/using-base');
|
|
});
|
|
|
|
app.get('/network-information', (req, res) => {
|
|
res.redirect('/docs/network-information');
|
|
});
|
|
|
|
app.get('/base-contracts', (req, res) => {
|
|
res.redirect('/docs/base-contracts');
|
|
});
|
|
|
|
app.get('/fees', (req, res) => {
|
|
res.redirect('/docs/fees');
|
|
});
|
|
|
|
app.get('/differences', (req, res) => {
|
|
res.redirect('/docs/differences');
|
|
});
|
|
|
|
app.get('/contracts', (req, res) => {
|
|
res.redirect('/docs/contracts');
|
|
});
|
|
|
|
app.get('/security', (req, res) => {
|
|
res.redirect('/docs/security');
|
|
});
|
|
|
|
app.get('/terms-of-service', (req, res) => {
|
|
res.redirect('/docs/terms-of-service');
|
|
});
|
|
|
|
app.get('/privacy-policy', (req, res) => {
|
|
res.redirect('/docs/privacy-policy');
|
|
});
|
|
|
|
app.get('/cookie-policy', (req, res) => {
|
|
res.redirect('/docs/cookie-policy');
|
|
});
|
|
|
|
app.get('/tools/node-providers', (req, res) => {
|
|
res.redirect('/docs/tools/node-providers');
|
|
});
|
|
|
|
app.get('/tools/block-explorers', (req, res) => {
|
|
res.redirect('/docs/tools/block-explorers');
|
|
});
|
|
|
|
app.get('/tools/network-faucets', (req, res) => {
|
|
res.redirect('/docs/tools/network-faucets');
|
|
});
|
|
|
|
app.get('/tools/oracles', (req, res) => {
|
|
res.redirect('/docs/tools/oracles');
|
|
});
|
|
|
|
app.get('/tools/data-indexers', (req, res) => {
|
|
res.redirect('/docs/tools/data-indexers');
|
|
});
|
|
|
|
app.get('/tools/cross-chain', (req, res) => {
|
|
res.redirect('/docs/tools/cross-chain');
|
|
});
|
|
|
|
app.get('/tools/account-abstraction', (req, res) => {
|
|
res.redirect('/docs/tools/account-abstraction');
|
|
});
|
|
|
|
app.get('/tools/nft-checkout', (req, res) => {
|
|
res.redirect('/docs/tools/nft-checkout');
|
|
});
|
|
|
|
app.get('/tools/onramps', (req, res) => {
|
|
res.redirect('/docs/tools/onramps');
|
|
});
|
|
|
|
app.get('/tools/onboarding', (req, res) => {
|
|
res.redirect('/docs/tools/onboarding');
|
|
});
|
|
|
|
app.get('/tools/bridges', (req, res) => {
|
|
res.redirect('/docs/tools/bridges');
|
|
});
|
|
|
|
app.get('/docs/tools/bridges-testnet', (req, res) => {
|
|
res.redirect('/docs/tools/bridges');
|
|
});
|
|
|
|
app.get('docs/tools/bridge-faq', (req, res) => {
|
|
res.redirect('/docs/tools/bridges');
|
|
});
|
|
|
|
app.get('/tools/foundry', (req, res) => {
|
|
res.redirect('/docs/tools/foundry');
|
|
});
|
|
|
|
app.get('/tools/hardhat', (req, res) => {
|
|
res.redirect('/docs/tools/hardhat');
|
|
});
|
|
|
|
app.get('/tools/thirdweb-cli', (req, res) => {
|
|
res.redirect('/docs/tools/thirdweb-cli');
|
|
});
|
|
|
|
app.get('/tools/ethers', (req, res) => {
|
|
res.redirect('/docs/tools/ethers');
|
|
});
|
|
|
|
app.get('/tools/thirdweb-sdk', (req, res) => {
|
|
res.redirect('/docs/tools/thirdweb-sdk');
|
|
});
|
|
|
|
app.get('/tools/viem', (req, res) => {
|
|
res.redirect('/docs/tools/viem');
|
|
});
|
|
|
|
app.get('/tools/web3', (req, res) => {
|
|
res.redirect('/docs/tools/web3');
|
|
});
|
|
|
|
app.get('/tokens/list', (req, res) => {
|
|
res.redirect('/docs/tokens/list');
|
|
});
|
|
|
|
app.get('/tokens/wallet', (req, res) => {
|
|
res.redirect('/docs/tokens/wallet');
|
|
});
|
|
|
|
app.get('/guides/run-a-base-goerli-node/', (req, res) => {
|
|
res.redirect('/tutorials/run-a-base-node/');
|
|
});
|
|
|
|
app.get('/guides/deploy-smart-contracts', (req, res) => {
|
|
res.redirect('/tutorials/deploy-with-hardhat');
|
|
});
|
|
|
|
app.get('/guides/deploy-with-foundry', (req, res) => {
|
|
res.redirect('/tutorials/deploy-with-foundry');
|
|
});
|
|
|
|
app.get('/guides/deploy-with-remix', (req, res) => {
|
|
res.redirect('/tutorials/deploy-with-remix');
|
|
});
|
|
|
|
app.get('/guides/deploy-with-tenderly', (req, res) => {
|
|
res.redirect('/tutorials/deploy-with-tenderly');
|
|
});
|
|
|
|
app.get('/guides/deploy-with-thirdweb', (req, res) => {
|
|
res.redirect('/tutorials/deploy-with-thirdweb');
|
|
});
|
|
|
|
app.get('/guides/build-with-thirdweb', (req, res) => {
|
|
res.redirect('/tutorials/build-with-thirdweb');
|
|
});
|
|
|
|
app.get('/guides/run-a-base-node', (req, res) => {
|
|
res.redirect('/tutorials/run-a-base-node');
|
|
});
|
|
|
|
app.get('/guides/using-chainlink-price-feeds', (req, res) => {
|
|
res.redirect('/tutorials/oracles-chainlink-price-feeds');
|
|
});
|
|
|
|
app.get('/guides/using-pyth-price-feeds', (req, res) => {
|
|
res.redirect('/tutorials/oracles-pyth-price-feeds');
|
|
});
|
|
|
|
app.get('/guides/using-supra-vrf', (req, res) => {
|
|
res.redirect('/tutorials/oracles-supra-vrf');
|
|
});
|
|
|
|
app.get('/guides/cross-chain-with-ccip', (req, res) => {
|
|
res.redirect('/tutorials/cross-chain-with-ccip');
|
|
});
|
|
|
|
app.get('/guides/cross-chain-with-layerzero', (req, res) => {
|
|
res.redirect('/tutorials/cross-chain-with-layerzero');
|
|
});
|
|
|
|
app.get('/guides/account-abstraction-with-biconomy', (req, res) => {
|
|
res.redirect('/tutorials/account-abstraction-with-biconomy');
|
|
});
|
|
|
|
app.get('/guides/building-with-base-and-foundry/introduction', (req, res) => {
|
|
res.redirect('/tutorials/intro-to-foundry-setup');
|
|
});
|
|
|
|
app.get('/guides/building-with-base-and-foundry/testing', (req, res) => {
|
|
res.redirect('/tutorials/intro-to-foundry-testing');
|
|
});
|
|
|
|
app.get('/guides/complex-onchain-nfts', (req, res) => {
|
|
res.redirect('/tutorials/onchain-nfts');
|
|
});
|
|
|
|
app.get('/guides/linked-minting-frame', (req, res) => {
|
|
res.redirect('/tutorials/farcaster-frames-nocode-minting');
|
|
});
|
|
|
|
app.get('/guides/nft-minting-frame', (req, res) => {
|
|
res.redirect('/tutorials/farcaster-frames-nft-minting');
|
|
});
|
|
|
|
app.get('/guides/deploy-frame-on-vercel', (req, res) => {
|
|
res.redirect('/tutorials/farcaster-frames-deploy-to-vercel');
|
|
});
|
|
|
|
app.get('/guides/advanced-frame-behavior', (req, res) => {
|
|
res.redirect('/tutorials/farcaster-frames-gating-and-redirects');
|
|
});
|
|
|
|
app.get('/guides/hyperframes', (req, res) => {
|
|
res.redirect('/tutorials/farcaster-frames-hyperframes');
|
|
});
|
|
|
|
app.get('/guides/frame-transactions', (req, res) => {
|
|
res.redirect('/tutorials/farcaster-frames-transactions');
|
|
});
|
|
|
|
app.get('/hardhat-tools-and-testing/overview', (req, res) => {
|
|
res.redirect('');
|
|
});
|
|
|
|
app.get(
|
|
'/hardhat-tools-and-testing/hardhat-profiling-size/contract-sizer-setup-vid',
|
|
(req, res) => {
|
|
res.redirect('/tutorials/hardhat-profiling-size');
|
|
},
|
|
);
|
|
|
|
app.get(
|
|
'/hardhat-tools-and-testing/hardhat-profiling-size/manual-contract-optimizations-vid',
|
|
(req, res) => {
|
|
res.redirect('/tutorials/hardhat-profiling-size');
|
|
},
|
|
);
|
|
|
|
app.get('/hardhat-tools-and-testing/hardhat-profiling-size/using-the-optimizer-vid', (req, res) => {
|
|
res.redirect('/tutorials/hardhat-profiling-size');
|
|
});
|
|
|
|
app.get('/hardhat-tools-and-testing/hardhat-profiling-size/hardhat-profiling-size', (req, res) => {
|
|
res.redirect('/tutorials/hardhat-profiling-size');
|
|
});
|
|
|
|
app.get(
|
|
'/hardhat-tools-and-testing/hardhat-profiling-gas/installing-the-gas-analyzer-vid',
|
|
(req, res) => {
|
|
res.redirect('/tutorials/hardhat-profiling-gas');
|
|
},
|
|
);
|
|
|
|
app.get('/hardhat-tools-and-testing/hardhat-profiling-gas/improving-gas-usage-vid', (req, res) => {
|
|
res.redirect('/tutorials/hardhat-profiling-gas');
|
|
});
|
|
|
|
app.get('/hardhat-tools-and-testing/hardhat-profiling-gas/hardhat-profiling-gas', (req, res) => {
|
|
res.redirect('/tutorials/hardhat-profiling-gas');
|
|
});
|
|
|
|
app.get('/hardhat-tools-and-testing/hardhat-debugging/debugging-with-hardhat-sbs', (req, res) => {
|
|
res.redirect('/tutorials/hardhat-debugging');
|
|
});
|
|
|
|
app.get(
|
|
'/hardhat-tools-and-testing/hardhat-test-coverage/hardhat-test-coverage-sbs',
|
|
(req, res) => {
|
|
res.redirect('/tutorials/hardhat-test-coverage');
|
|
},
|
|
);
|
|
|
|
app.get('/connecting-to-the-blockchain/overview', (req, res) => {
|
|
res.redirect('/tutorials/intro-to-providers');
|
|
});
|
|
|
|
app.get('/connecting-to-the-blockchain/blockchain-providers', (req, res) => {
|
|
res.redirect('/tutorials/intro-to-providers');
|
|
});
|
|
|
|
app.get('/connecting-to-the-blockchain/connecting-with-a-provider', (req, res) => {
|
|
res.redirect('/tutorials/intro-to-providers');
|
|
});
|
|
|
|
app.get('/guides/account-abstraction/overview', (req, res) => {
|
|
res.redirect('/tutorials/account-abstraction-with-privy-and-base-paymaster');
|
|
});
|
|
|
|
app.get('/guides/account-abstraction/intro-to-account-abstraction', (req, res) => {
|
|
res.redirect('/tutorials/account-abstraction-with-privy-and-base-paymaster');
|
|
});
|
|
|
|
app.get('/guides/account-abstraction/intro-to-privy', (req, res) => {
|
|
res.redirect('/tutorials/account-abstraction-with-privy-and-base-paymaster');
|
|
});
|
|
|
|
app.get('/guides/account-abstraction/implementing-the-paymaster', (req, res) => {
|
|
res.redirect('/tutorials/account-abstraction-with-privy-and-base-paymaster');
|
|
});
|
|
|
|
app.get('/building-with-base/guides/account-abstraction/overview', (req, res) => {
|
|
res.redirect('/tutorials/account-abstraction-with-privy-and-base-paymaster');
|
|
});
|
|
|
|
app.get(
|
|
'/building-with-base/guides/account-abstraction/intro-to-account-abstraction',
|
|
(req, res) => {
|
|
res.redirect('/tutorials/account-abstraction-with-privy-and-base-paymaster');
|
|
},
|
|
);
|
|
|
|
app.get('/building-with-base/guides/account-abstraction/intro-to-privy', (req, res) => {
|
|
res.redirect('/tutorials/account-abstraction-with-privy-and-base-paymaster');
|
|
});
|
|
|
|
app.get('/building-with-base/guides/account-abstraction/implementing-the-paymaster', (req, res) => {
|
|
res.redirect('/tutorials/account-abstraction-with-privy-and-base-paymaster');
|
|
});
|
|
|
|
if (process.env.APP_STAGE === 'production' && process.env.AUTH_ENABLED !== 'false') {
|
|
const auth = basicAuth({
|
|
challenge: true,
|
|
realm: 'This is a private site',
|
|
// expected in the format: "user1:pass user2:pass" (same as the Base public router)
|
|
users: process.env.BASIC_AUTH_CREDENTIALS.split(' ').reduce((o, e) => {
|
|
let s = e.split(':');
|
|
o[s[0]] = s[1];
|
|
return o;
|
|
}, {}),
|
|
});
|
|
|
|
app.use(unless('/api/_health', auth));
|
|
}
|
|
|
|
app.set('port', 3000);
|
|
|
|
const contentSecurityPolicy = {
|
|
'default-src': ["'self'"],
|
|
'frame-ancestors': ["'self'"],
|
|
'form-action': ["'self'"],
|
|
'script-src': [
|
|
"'self'",
|
|
"'unsafe-inline'",
|
|
'https://static-assets.coinbase.com/js/cca/v0.0.1.js', // CCA Lite
|
|
'https://cca-lite.coinbase.com', // CCA Lite
|
|
],
|
|
'style-src': ["'self'", "'unsafe-inline'"],
|
|
'img-src': ["'self'", 'data:'],
|
|
'connect-src': [
|
|
"'self'",
|
|
'wss://www.walletlink.org/rpc', // Coinbase Wallet SDK
|
|
'wss://relay.walletconnect.com', // WalletConnect
|
|
'wss://relay.walletconnect.org',
|
|
'https://goerli.base.org', // Base Goerli RPC
|
|
'https://sepolia.base.org', // Base Sepolia RPC
|
|
'https://cca-lite.coinbase.com', // CCA Lite
|
|
'https://*.algolia.net', // Algolia Search
|
|
'https://*.algolianet.com', // Algolia Search
|
|
'https://api.mendable.ai/v1/newConversation', // Mendable API
|
|
'https://api.mendable.ai/v1/mendableChat', // Mendable API
|
|
'https://api.mendable.ai/v1/rateMessage', // Mendable API
|
|
'https://api.sprig.com', // Sprig API
|
|
'https://cdn.sprig.com', // Sprig API
|
|
'https://flag.lab.amplitude.com/sdk/v2/flags',
|
|
'https://api.lab.amplitude.com/sdk/v2/vardata',
|
|
'https://browser-intake-datadoghq.com', // datadog
|
|
'https://*.datadoghq.com'
|
|
],
|
|
'frame-src': ["'self'", 'https://player.vimeo.com', 'https://verify.walletconnect.org'],
|
|
};
|
|
|
|
const cspObjectToString = Object.entries(contentSecurityPolicy).reduce((acc, [key, value]) => {
|
|
return `${acc}${key} ${value.join(' ')};`;
|
|
}, '');
|
|
|
|
app.use(
|
|
express.static(path.join(__dirname, '../../out/base-docs'), {
|
|
setHeaders: function (res) {
|
|
res.setHeader('cache-control', 'no-store');
|
|
res.setHeader('content-security-policy', cspObjectToString);
|
|
res.setHeader('cross-origin-opener-policy', 'same-origin-allow-popups');
|
|
res.setHeader('referrer-policy', 'strict-origin-when-cross-origin');
|
|
res.setHeader('strict-transport-security', 'max-age=63072000; includeSubDomains; preload');
|
|
res.setHeader('x-content-type-options', 'nosniff');
|
|
res.setHeader('x-frame-options', 'SAMEORIGIN');
|
|
res.setHeader('x-xss-protection', '1; mode=block');
|
|
},
|
|
}),
|
|
);
|
|
|
|
app.use(function (req, res, next) {
|
|
const filePath = path.resolve(__dirname, req.originalUrl.slice(1));
|
|
const rootDir = path.resolve(__dirname, 'public');
|
|
|
|
if (!filePath.startsWith(rootDir)) {
|
|
res.status(404).send(notFound.html);
|
|
return;
|
|
}
|
|
|
|
if (!fs.existsSync(filePath)) {
|
|
res.status(404).send(notFound.html);
|
|
return;
|
|
}
|
|
|
|
next();
|
|
});
|
|
|
|
app.listen(app.get('port'));
|