From 2d29f1e8ecc79deb42177e0b2093f1afff7e56e5 Mon Sep 17 00:00:00 2001 From: ekzyis Date: Mon, 3 Nov 2025 16:35:57 +0100 Subject: [PATCH] Refactor process.env.NODE_ENV checks --- api/lnd/index.js | 4 ++-- api/models/index.js | 3 ++- api/s3/index.js | 8 ++++---- capture/media-check.js | 3 ++- lib/apollo.js | 4 ++-- lib/auth.js | 3 ++- lib/cln.js | 4 ++-- lib/constants.js | 6 ++++++ lib/lnurl.js | 4 ++-- lib/proxy.js | 3 ++- lib/sndev.js | 4 +++- lib/validate.js | 5 +++-- lib/webPush.js | 4 ++-- middleware.js | 9 ++++----- next.config.js | 12 ++++++------ pages/api/lnurlp/[username]/index.js | 4 ++-- scripts/imgproxy.js | 3 ++- wallets/lib/validate.js | 3 ++- wallets/server/protocols/lnbits.js | 4 ++-- worker/imgproxy.js | 5 +++-- worker/loadenv.js | 3 +++ worker/socialPoster.js | 6 +++--- 22 files changed, 61 insertions(+), 43 deletions(-) diff --git a/api/lnd/index.js b/api/lnd/index.js index e55d43d1a5..10960ec14f 100644 --- a/api/lnd/index.js +++ b/api/lnd/index.js @@ -3,7 +3,7 @@ import { toPositiveNumber } from '@/lib/format' import { authenticatedLndGrpc } from '@/lib/lnd' import { getIdentity, getHeight, getWalletInfo, getNode, getPayment, parsePaymentRequest } from 'ln-service' import { datePivot } from '@/lib/time' -import { LND_PATHFINDING_TIMEOUT_MS } from '@/lib/constants' +import { LND_PATHFINDING_TIMEOUT_MS, __DEV__ } from '@/lib/constants' const lnd = global.lnd || authenticatedLndGrpc({ cert: process.env.LND_CERT, @@ -11,7 +11,7 @@ const lnd = global.lnd || authenticatedLndGrpc({ socket: process.env.LND_SOCKET }).lnd -if (process.env.NODE_ENV === 'development') global.lnd = lnd +if (__DEV__) global.lnd = lnd // Check LND GRPC connection getWalletInfo({ lnd }, (err, result) => { diff --git a/api/models/index.js b/api/models/index.js index d050e0a2da..ca7ae8ae58 100644 --- a/api/models/index.js +++ b/api/models/index.js @@ -1,4 +1,5 @@ import createPrisma from '@/lib/create-prisma' +import { __DEV__ } from '@/lib/constants' const prisma = global.prisma || (() => { console.log('initing prisma') @@ -9,6 +10,6 @@ const prisma = global.prisma || (() => { }) })() -if (process.env.NODE_ENV === 'development') global.prisma = prisma +if (__DEV__) global.prisma = prisma export default prisma diff --git a/api/s3/index.js b/api/s3/index.js index b31fc470b4..0e7248adf8 100644 --- a/api/s3/index.js +++ b/api/s3/index.js @@ -1,5 +1,5 @@ import AWS from 'aws-sdk' -import { MEDIA_URL } from '@/lib/constants' +import { __DEV__, MEDIA_URL } from '@/lib/constants' const bucketRegion = 'us-east-1' const Bucket = process.env.NEXT_PUBLIC_AWS_UPLOAD_BUCKET @@ -10,13 +10,13 @@ AWS.config.update({ const config = { apiVersion: '2006-03-01', - s3ForcePathStyle: process.env.NODE_ENV === 'development' + s3ForcePathStyle: __DEV__ } export function createPresignedPost ({ key, type, size }) { // for local development, we use the NEXT_PUBLIC_MEDIA_URL which // is reachable from the host machine - if (process.env.NODE_ENV === 'development') { + if (__DEV__) { config.endpoint = process.env.NEXT_PUBLIC_MEDIA_URL } @@ -39,7 +39,7 @@ export function createPresignedPost ({ key, type, size }) { export async function deleteObjects (keys) { // for local development, we use the MEDIA_URL which // is reachable from the container network - if (process.env.NODE_ENV === 'development') { + if (__DEV__) { config.endpoint = MEDIA_URL } diff --git a/capture/media-check.js b/capture/media-check.js index 1384d62c5f..42017d4c8e 100644 --- a/capture/media-check.js +++ b/capture/media-check.js @@ -1,4 +1,5 @@ import { filetypemime } from 'magic-bytes.js' +import { __DEV__ } from '@/lib/constants' const TIMEOUT_HEAD = 2000 const TIMEOUT_GET = 10000 @@ -81,7 +82,7 @@ export default async function mediaCheck (req, res) { try { // in development, the capture container can't reach the public media url, // so we need to replace it with its docker equivalent, e.g. http://s3:4566/uploads - if (url.startsWith(process.env.NEXT_PUBLIC_MEDIA_URL) && process.env.NODE_ENV === 'development') { + if (url.startsWith(process.env.NEXT_PUBLIC_MEDIA_URL) && __DEV__) { url = url.replace(process.env.NEXT_PUBLIC_MEDIA_URL, process.env.MEDIA_URL_DOCKER) } diff --git a/lib/apollo.js b/lib/apollo.js index 9a67a80a51..c193a41549 100644 --- a/lib/apollo.js +++ b/lib/apollo.js @@ -1,7 +1,7 @@ import { ApolloClient, InMemoryCache, HttpLink, makeVar, split, from } from '@apollo/client' import { BatchHttpLink } from '@apollo/client/link/batch-http' import { decodeCursor, LIMIT } from './cursor' -import { COMMENTS_LIMIT, SSR } from './constants' +import { COMMENTS_LIMIT, SSR, __DEV__ } from './constants' import { RetryLink } from '@apollo/client/link/retry' import { isMutationOperation, isQueryOperation } from '@apollo/client/utilities' @@ -59,7 +59,7 @@ function getClient (uri) { return new ApolloClient({ link, ssrMode: SSR, - connectToDevTools: process.env.NODE_ENV !== 'production', + connectToDevTools: __DEV__, cache: new InMemoryCache({ freezeResults: true, // https://github.com/apollographql/apollo-client/issues/7648 diff --git a/lib/auth.js b/lib/auth.js index 70dec13abf..b2ec5ac8ad 100644 --- a/lib/auth.js +++ b/lib/auth.js @@ -2,11 +2,12 @@ import { datePivot } from '@/lib/time' import * as cookie from 'cookie' import { NodeNextRequest } from 'next/dist/server/base-http/node' import { encode as encodeJWT, decode as decodeJWT } from 'next-auth/jwt' +import { __PROD__ } from '@/lib/constants' const b64Encode = obj => Buffer.from(JSON.stringify(obj)).toString('base64') const b64Decode = s => JSON.parse(Buffer.from(s, 'base64')) -export const HTTPS = process.env.NODE_ENV === 'production' +export const HTTPS = __PROD__ const secureCookie = (name) => HTTPS diff --git a/lib/cln.js b/lib/cln.js index adeb01f081..d8699344f4 100644 --- a/lib/cln.js +++ b/lib/cln.js @@ -3,7 +3,7 @@ import crypto from 'crypto' import { getAgent } from '@/lib/proxy' import { assertContentTypeJson, assertResponseOk } from './url' import { fetchWithTimeout, FetchTimeoutError } from './fetch' -import { WALLET_CREATE_INVOICE_TIMEOUT_MS } from './constants' +import { WALLET_CREATE_INVOICE_TIMEOUT_MS, __DEV__ } from './constants' export const createInvoice = async ({ msats, description, expiry }, { socket, rune, cert }, { signal }) => { const agent = getAgent({ hostname: socket, cert }) @@ -54,7 +54,7 @@ export const sendPayment = async (bolt11, { socket, rune }, { signal }) => { // https://docs.corelightning.org/reference/pay const url = new URL( '/v1/pay', - process.env.NODE_ENV === 'development' ? `http://${socket}` : `https://${socket}`) + __DEV__ ? `http://${socket}` : `https://${socket}`) const method = 'POST' const res = await fetchWithTimeout(url, { method, diff --git a/lib/constants.js b/lib/constants.js index 05115c5baa..05471a6fe3 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -217,3 +217,9 @@ export const BECH32_CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l' export const HALLOWEEN_IMMUNITY_HOURS = 8 export const HALLOWEEN_INACTIVITY_TIMEOUT_HOURS = 36 + +/** true if `process.env.NODE_ENV` is set to `development` */ +export const __DEV__ = process.env.NODE_ENV === 'development' + +/** true if `process.env.NODE_ENV` is set to `production` */ +export const __PROD__ = process.env.NODE_ENV === 'production' diff --git a/lib/lnurl.js b/lib/lnurl.js index fff51b9789..9335d2c4d9 100644 --- a/lib/lnurl.js +++ b/lib/lnurl.js @@ -2,7 +2,7 @@ import { createHash } from 'crypto' import { bech32 } from 'bech32' import { lnAddrSchema } from './validate' import { FetchTimeoutError } from '@/lib/fetch' -import { WALLET_CREATE_INVOICE_TIMEOUT_MS } from './constants' +import { WALLET_CREATE_INVOICE_TIMEOUT_MS, __DEV__ } from './constants' import { assertContentTypeJson, assertResponseOk, ResponseAssertError } from '@/lib/url' export function encodeLNUrl (url) { @@ -32,7 +32,7 @@ export async function lnAddrOptions (addr, { signal } = {}) { await lnAddrSchema().fields.addr.validate(addr) const [name, domain] = addr.split('@') let protocol = 'https' - if (process.env.NODE_ENV === 'development') { + if (__DEV__) { // support HTTP and HTTPS during development protocol = process.env.NEXT_PUBLIC_URL.split('://')[0] } diff --git a/lib/proxy.js b/lib/proxy.js index ea8c0a87d1..a03d4df055 100644 --- a/lib/proxy.js +++ b/lib/proxy.js @@ -1,6 +1,7 @@ import http from 'http' import https from 'https' import { TOR_REGEXP } from '@/lib/url' +import { __DEV__ } from '@/lib/constants' // from https://github.com/delvedor/hpagent @@ -137,7 +138,7 @@ export function getAgent ({ hostname, cert }) { return agent } - if (process.env.NODE_ENV === 'development' && !cert) { + if (__DEV__ && !cert) { return new http.Agent() } diff --git a/lib/sndev.js b/lib/sndev.js index b2d74b77cb..03bed418cc 100644 --- a/lib/sndev.js +++ b/lib/sndev.js @@ -1,5 +1,7 @@ +import { __PROD__ } from '@/lib/constants' + export function isServiceEnabled (service) { - if (process.env.NODE_ENV !== 'development') return true + if (__PROD__) return true const services = (process.env.COMPOSE_PROFILES ?? '').split(',') return services.includes(service) diff --git a/lib/validate.js b/lib/validate.js index ea1fa25c8f..bcd25b5b72 100644 --- a/lib/validate.js +++ b/lib/validate.js @@ -4,7 +4,8 @@ import { MIN_POLL_NUM_CHOICES, MAX_FORWARDS, BOOST_MULT, MAX_TERRITORY_DESC_LENGTH, POST_TYPES, TERRITORY_BILLING_TYPES, MAX_COMMENT_TEXT_LENGTH, MAX_POST_TEXT_LENGTH, MIN_TITLE_LENGTH, BOUNTY_MIN, BOUNTY_MAX, RESERVED_SUB_NAMES, - BOOST_MAX + BOOST_MAX, + __DEV__ } from './constants' import { SUPPORTED_CURRENCIES } from './currency' import { NOSTR_MAX_RELAY_NUM, NOSTR_PUBKEY_BECH32, NOSTR_PUBKEY_HEX } from './nostr' @@ -45,7 +46,7 @@ const nameValidator = string() const intValidator = number().typeError('must be a number').integer('must be whole') const floatValidator = number().typeError('must be a number') -export const lightningAddressValidator = process.env.NODE_ENV === 'development' +export const lightningAddressValidator = __DEV__ ? string().or( [string().matches(/^[\w_]+@localhost:\d+$/), string().matches(/^[\w_]+@app:\d+$/), string().email()], 'address is no good') diff --git a/lib/webPush.js b/lib/webPush.js index 5b59a5dfff..f992ed38e2 100644 --- a/lib/webPush.js +++ b/lib/webPush.js @@ -1,12 +1,12 @@ import webPush from 'web-push' import removeMd from 'remove-markdown' -import { COMMENT_DEPTH_LIMIT, FOUND_BLURBS, LOST_BLURBS } from './constants' +import { COMMENT_DEPTH_LIMIT, FOUND_BLURBS, LOST_BLURBS, __PROD__ } from './constants' import { msatsToSats, numWithUnits } from './format' import models from '@/api/models' import { isMuted } from '@/lib/user' import { Prisma } from '@prisma/client' -const webPushEnabled = process.env.NODE_ENV === 'production' || +const webPushEnabled = __PROD__ || (process.env.VAPID_MAILTO && process.env.NEXT_PUBLIC_VAPID_PUBKEY && process.env.VAPID_PRIVKEY) function log (...args) { diff --git a/middleware.js b/middleware.js index 926ba496a6..ad1546fabe 100644 --- a/middleware.js +++ b/middleware.js @@ -1,4 +1,5 @@ import { NextResponse, URLPattern } from 'next/server' +import { __DEV__ } from '@/lib/constants' const referrerPattern = new URLPattern({ pathname: ':pathname(*)/r/:referrer([\\w_]+)' }) const itemPattern = new URLPattern({ pathname: '/items/:id(\\d+){/:other(\\w+)}?' }) @@ -87,14 +88,12 @@ function referrerMiddleware (request) { export function middleware (request) { const resp = referrerMiddleware(request) - const isDev = process.env.NODE_ENV === 'development' - const nonce = Buffer.from(crypto.randomUUID()).toString('base64') // we want to load media from other localhost ports during development - const devSrc = isDev ? ' localhost:* http: ws:' : '' + const devSrc = __DEV__ ? ' localhost:* http: ws:' : '' // unsafe-eval is required during development due to react-refresh.js // see https://github.com/vercel/next.js/issues/14221 - const devScriptSrc = isDev ? " 'unsafe-eval'" : '' + const devScriptSrc = __DEV__ ? " 'unsafe-eval'" : '' const cspHeader = [ // if something is not explicitly allowed, we don't allow it. @@ -117,7 +116,7 @@ export function middleware (request) { // blocks injection of tags "base-uri 'none'", // tell user agents to replace HTTP with HTTPS - isDev ? '' : 'upgrade-insecure-requests', + __DEV__ ? '' : 'upgrade-insecure-requests', // prevents any domain from framing the content (defense against clickjacking attacks) "frame-ancestors 'none'" ].join('; ') diff --git a/next.config.js b/next.config.js index 1cc0b0668f..cac5bcd095 100644 --- a/next.config.js +++ b/next.config.js @@ -3,7 +3,7 @@ const { InjectManifest } = require('workbox-webpack-plugin') const CopyPlugin = require('copy-webpack-plugin') const webpack = require('webpack') -let isProd = process.env.NODE_ENV === 'production' +let __PROD__ = process.env.NODE_ENV === 'production' const corsHeaders = [ { key: 'Access-Control-Allow-Origin', @@ -29,14 +29,14 @@ const getGitCommit = (env) => { let commitHash try { - if (isProd) { + if (__PROD__) { try { commitHash = getGitCommit('aws') } catch (e) { // maybe we're running prod build locally commitHash = getGitCommit() // if above line worked, we're running locally and should not use prod config which configurates CDN - isProd = false + __PROD__ = false } } else { commitHash = getGitCommit() @@ -50,7 +50,7 @@ module.exports = withPlausibleProxy()({ env: { NEXT_PUBLIC_COMMIT_HASH: commitHash, NEXT_PUBLIC_LND_CONNECT_ADDRESS: process.env.LND_CONNECT_ADDRESS, - NEXT_PUBLIC_ASSET_PREFIX: isProd ? 'https://a.stacker.news' : '', + NEXT_PUBLIC_ASSET_PREFIX: __PROD__ ? 'https://a.stacker.news' : '', // in prod, we build in /var/app/staging and then cp and deploy in /var/app/current // so we need to resolve the relative path to the lightning module LIGHTNING_MODULE_PATH: require('path').relative(process.cwd(), require.resolve('lightning')) @@ -64,8 +64,8 @@ module.exports = withPlausibleProxy()({ productionBrowserSourceMaps: true, generateBuildId: commitHash ? async () => commitHash : undefined, // Use the CDN in production and localhost for development. - assetPrefix: isProd ? 'https://a.stacker.news' : undefined, - crossOrigin: isProd ? 'anonymous' : undefined, + assetPrefix: __PROD__ ? 'https://a.stacker.news' : undefined, + crossOrigin: __PROD__ ? 'anonymous' : undefined, async headers () { return [ { diff --git a/pages/api/lnurlp/[username]/index.js b/pages/api/lnurlp/[username]/index.js index 68626eb03f..61c7b4e6a1 100644 --- a/pages/api/lnurlp/[username]/index.js +++ b/pages/api/lnurlp/[username]/index.js @@ -1,7 +1,7 @@ import { getPublicKey } from 'nostr' import models from '@/api/models' import { lnurlPayMetadataString } from '@/lib/lnurl' -import { LNURLP_COMMENT_MAX_LENGTH, PROXY_RECEIVE_FEE_PERCENT } from '@/lib/constants' +import { LNURLP_COMMENT_MAX_LENGTH, PROXY_RECEIVE_FEE_PERCENT, __DEV__ } from '@/lib/constants' export default async ({ query: { username } }, res) => { const user = await models.user.findUnique({ where: { name: username } }) @@ -14,7 +14,7 @@ export default async ({ query: { username } }, res) => { minSendable += minSendable * PROXY_RECEIVE_FEE_PERCENT / 100n } - const url = process.env.NODE_ENV === 'development' ? process.env.SELF_URL : process.env.NEXT_PUBLIC_URL + const url = __DEV__ ? process.env.SELF_URL : process.env.NEXT_PUBLIC_URL return res.status(200).json({ callback: `${url}/api/lnurlp/${username}/pay`, // The URL from LN SERVICE which will accept the pay request parameters minSendable: Number(minSendable), // Min amount LN SERVICE is willing to receive, can not be less than 1 or more than `maxSendable` diff --git a/scripts/imgproxy.js b/scripts/imgproxy.js index 02b1611382..7b330b1206 100644 --- a/scripts/imgproxy.js +++ b/scripts/imgproxy.js @@ -1,8 +1,9 @@ +const { __PROD__ } = require('@/lib/constants') const { PrismaClient, Prisma } = require('@prisma/client') const prisma = new PrismaClient() -const imgProxyEnabled = process.env.NODE_ENV === 'production' || +const imgProxyEnabled = __PROD__ || (process.env.NEXT_PUBLIC_IMGPROXY_URL && process.env.IMGPROXY_SALT && process.env.IMGPROXY_KEY) if (!imgProxyEnabled) { diff --git a/wallets/lib/validate.js b/wallets/lib/validate.js index 9c3945749d..803724ca01 100644 --- a/wallets/lib/validate.js +++ b/wallets/lib/validate.js @@ -7,6 +7,7 @@ import { TOR_REGEXP } from '@/lib/url' import { lightningAddressValidator } from '@/lib/validate' import { decodeBech32 as clinkDecodeBech32, OfferPriceType } from '@shocknet/clink-sdk' import { string, array } from 'yup' +import { __DEV__ } from '@/lib/constants' export const externalLightningAddressValidator = lightningAddressValidator .test({ @@ -168,7 +169,7 @@ export const bip39Validator = ({ min = 12, max = 24 } = {}) => export const certValidator = () => string().hexOrBase64() export const urlValidator = (...args) => - process.env.NODE_ENV === 'development' + __DEV__ ? string() .or([ string().matches(/^(http:\/\/)?localhost:\d+$/), diff --git a/wallets/server/protocols/lnbits.js b/wallets/server/protocols/lnbits.js index cdf3b6c157..2dc59bc8e8 100644 --- a/wallets/server/protocols/lnbits.js +++ b/wallets/server/protocols/lnbits.js @@ -1,4 +1,4 @@ -import { WALLET_CREATE_INVOICE_TIMEOUT_MS } from '@/lib/constants' +import { __DEV__, WALLET_CREATE_INVOICE_TIMEOUT_MS } from '@/lib/constants' import { FetchTimeoutError } from '@/lib/fetch' import { msatsToSats } from '@/lib/format' import { getAgent } from '@/lib/proxy' @@ -32,7 +32,7 @@ export async function createInvoice ( let hostname = url.replace(/^https?:\/\//, '').replace(/\/+$/, '') const agent = getAgent({ hostname }) - if (process.env.NODE_ENV !== 'production' && hostname.startsWith('localhost:')) { + if (__DEV__ && hostname.startsWith('localhost:')) { // to make it possible to attach LNbits for receives during local dev hostname = hostname === `localhost:${process.env.LNBITS_WEB_PORT}` ? 'lnbits:5000' : 'lnbits-v1:5000' } diff --git a/worker/imgproxy.js b/worker/imgproxy.js index c0fae9b970..103ffe24b7 100644 --- a/worker/imgproxy.js +++ b/worker/imgproxy.js @@ -4,8 +4,9 @@ import { isJob } from '@/lib/item' import path from 'node:path' import { decodeProxyUrl } from '@/lib/url' import { fetchWithTimeout } from '@/lib/fetch' +import { __PROD__ } from '@/lib/constants' -const imgProxyEnabled = process.env.NODE_ENV === 'production' || +const imgProxyEnabled = __PROD__ || (process.env.NEXT_PUBLIC_IMGPROXY_URL && process.env.IMGPROXY_SALT && process.env.IMGPROXY_KEY) if (!imgProxyEnabled) { @@ -32,7 +33,7 @@ const imageUrlMatchers = [ u => u.host === 'i.imgur.com' ] const exclude = [ - u => process.env.NODE_ENV === 'production' && u.protocol !== 'https:', + u => __PROD__ && u.protocol !== 'https:', u => u.host.endsWith('.onion') || u.host.endsWith('.b32.ip') || u.host.endsWith('.loki'), u => ['twitter.com', 'x.com', 'nitter.it', 'nitter.at', 'xcancel.com'].some(h => h === u.host), u => u.host === 'stacker.news', diff --git a/worker/loadenv.js b/worker/loadenv.js index 4d93e99139..bca74ec1f7 100644 --- a/worker/loadenv.js +++ b/worker/loadenv.js @@ -1,2 +1,5 @@ import { loadEnvConfig } from '@next/env' + +// this should probably not import __DEV__ from @/lib/constants +// because we are initializing the environment variables for the worker here loadEnvConfig('.', process.env.NODE_ENV === 'development') diff --git a/worker/socialPoster.js b/worker/socialPoster.js index 65be7daed0..6e4abef68b 100644 --- a/worker/socialPoster.js +++ b/worker/socialPoster.js @@ -1,12 +1,12 @@ import Nostr, { getNostrProfile } from '@/lib/nostr' import { TwitterApi } from 'twitter-api-v2' import { msatsToSats, numWithUnits } from '@/lib/format' +import { __PROD__ } from '@/lib/constants' -const isProd = process.env.NODE_ENV === 'production' const WEIGHTED_VOTE_THRESHOLD = 3 async function postToTwitter ({ message }) { - if (!isProd || + if (!__PROD__ || !process.env.TWITTER_POSTER_API_KEY || !process.env.TWITTER_POSTER_API_KEY_SECRET || !process.env.TWITTER_POSTER_ACCESS_TOKEN || @@ -42,7 +42,7 @@ const RELAYS = [ ] async function postToNostr ({ message }) { - if (!isProd || !process.env.NOSTR_PRIVATE_KEY) { + if (!__PROD__ || !process.env.NOSTR_PRIVATE_KEY) { console.log('Nostr poster not configured') return }