diff --git a/apps/pay/app/lnurlp/[username]/callback/route.ts b/apps/pay/app/lnurlp/[username]/callback/route.ts index 7a00fd1c74..bf06760e39 100644 --- a/apps/pay/app/lnurlp/[username]/callback/route.ts +++ b/apps/pay/app/lnurlp/[username]/callback/route.ts @@ -116,7 +116,7 @@ export async function GET( const metadata = JSON.stringify([ ["text/plain", `Payment to ${username}`], - ["text/identifier", `${username}@${env.NEXT_PUBLIC_PAY_DOMAIN}`], + ["text/identifier", `${username}@${env.PAY_DOMAIN}`], ]) // lnurl generate invoice diff --git a/apps/pay/app/lnurlp/[username]/route.ts b/apps/pay/app/lnurlp/[username]/route.ts index 293d7523b7..c29d9411a3 100644 --- a/apps/pay/app/lnurlp/[username]/route.ts +++ b/apps/pay/app/lnurlp/[username]/route.ts @@ -70,7 +70,7 @@ export async function GET( const metadata = JSON.stringify([ ["text/plain", `Payment to ${username}`], - ["text/identifier", `${username}@${env.NEXT_PUBLIC_PAY_DOMAIN}`], + ["text/identifier", `${username}@${env.PAY_DOMAIN}`], ]) const callback = `${env.PAY_URL}/lnurlp/${username}/callback` diff --git a/apps/pay/components/Layouts/AppLayout.tsx b/apps/pay/components/Layouts/AppLayout.tsx index 47519b8701..d8c7535b5b 100644 --- a/apps/pay/components/Layouts/AppLayout.tsx +++ b/apps/pay/components/Layouts/AppLayout.tsx @@ -4,7 +4,7 @@ import { useRouter } from "next/router" import React from "react" import { Image, OverlayTrigger, Tooltip } from "react-bootstrap" -import { env } from "../../env" +import { getClientSidePayDomain } from "../../config/config" import styles from "./app-layout.module.css" @@ -19,7 +19,7 @@ const AppLayout = ({ children, username }: Props) => { const [openSideBar, setOpenSideBar] = React.useState(false) const [copied, setCopied] = React.useState(false) const lightningAddr = username - ? `${username?.toString().toLowerCase()}@${env.NEXT_PUBLIC_PAY_DOMAIN}` + ? `${username?.toString().toLowerCase()}@${getClientSidePayDomain()}` : "" const cashRegisterLink = username ? `/${username}` : "#" diff --git a/apps/pay/components/ParsePOSPayment/Receive-Invoice.tsx b/apps/pay/components/ParsePOSPayment/Receive-Invoice.tsx index 8be66b27d7..0032427d47 100644 --- a/apps/pay/components/ParsePOSPayment/Receive-Invoice.tsx +++ b/apps/pay/components/ParsePOSPayment/Receive-Invoice.tsx @@ -9,8 +9,7 @@ import Tooltip from "react-bootstrap/Tooltip" import { QRCode } from "react-qrcode-logo" import { useScreenshot } from "use-react-screenshot" -import { USD_INVOICE_EXPIRE_INTERVAL } from "../../config/config" -import { env } from "../../env" +import { USD_INVOICE_EXPIRE_INTERVAL, getClientSidePayDomain } from "../../config/config" import useCreateInvoice from "../../hooks/use-Create-Invoice" import { LnInvoiceObject } from "../../lib/graphql/index.types.d" import useSatPrice from "../../lib/use-sat-price" @@ -53,7 +52,7 @@ function ReceiveInvoice({ recipientWalletCurrency, walletId, state, dispatch }: const shareUrl = !amount && !unit && !memo - ? `https://${env.NEXT_PUBLIC_PAY_DOMAIN}/${username}?amount=${ + ? `https://${getClientSidePayDomain()}/${username}?amount=${ state.currentAmount }&sats=${usdToSats( state.currentAmount, diff --git a/apps/pay/config/config.ts b/apps/pay/config/config.ts index 66095752d7..7e4ba9edbd 100644 --- a/apps/pay/config/config.ts +++ b/apps/pay/config/config.ts @@ -1,3 +1,44 @@ +import { env } from "../env" export const USD_INVOICE_EXPIRE_INTERVAL = 60 * 5 export const MAX_INPUT_VALUE_LENGTH = 14 export const APP_DESCRIPTION = "Blink official lightning network node" + +// TODO get rid of this by removing the use of build time env vars in the client +export const getClientSideGqlConfig = () => { + const hostname = new URL(window.location.href).hostname + + let coreGqlUrl + + // Allow overriding the coreGqlUrl for local development, otherwise use the default in the URL + if (env.NEXT_PUBLIC_CORE_GQL_URL || typeof window === "undefined") { + coreGqlUrl = env.NEXT_PUBLIC_CORE_GQL_URL + } else { + const hostPartsApi = hostname.split(".") + hostPartsApi[0] = "api" + coreGqlUrl = `https://${hostPartsApi.join(".")}/graphql` + } + + let coreGqlWebSocketUrl + + // Allow overriding the coreGqlWebSocketUrl for local development, otherwise use the default in the URL + if (env.NEXT_PUBLIC_CORE_GQL_WEB_SOCKET_URL || typeof window === "undefined") { + coreGqlWebSocketUrl = env.NEXT_PUBLIC_CORE_GQL_WEB_SOCKET_URL + } else { + const hostPartsWs = hostname.split(".") + hostPartsWs[0] = "ws" + coreGqlWebSocketUrl = `wss://${hostPartsWs.join(".")}/graphql` + } + + return { + coreGqlUrl: coreGqlUrl || "", + coreGqlWebSocketUrl: coreGqlWebSocketUrl || "", + } +} + +export const getClientSidePayDomain = () => { + if (env.NEXT_PUBLIC_PAY_DOMAIN || typeof window === "undefined") { + return env.NEXT_PUBLIC_PAY_DOMAIN + } else { + return new URL(window.location.href).hostname.split(".").slice(-2).join(".") // Return the last two parts of the hostname (e.g. "blink.sv") + } +} diff --git a/apps/pay/env.ts b/apps/pay/env.ts index ca8e06f8cf..02b8c5fbb7 100644 --- a/apps/pay/env.ts +++ b/apps/pay/env.ts @@ -5,6 +5,7 @@ export const env = createEnv({ server: { CORE_GQL_URL_INTRANET: z.string().default("http://localhost:4455/graphql"), // Use intranet URL to preserve tracing headers PAY_URL: z.string().default("http://localhost:3002"), + PAY_DOMAIN: z.string().default("localhost:3002"), NOSTR_PUBKEY: z.string().optional(), REDIS_PASSWORD: z.string().optional(), REDIS_MASTER_NAME: z.string().optional(), @@ -12,19 +13,19 @@ export const env = createEnv({ REDIS_1_DNS: z.string().optional(), REDIS_2_DNS: z.string().optional(), }, + // DO NOT USE THESE, EXCEPT FOR LOCAL DEVELOPMENT client: { - NEXT_PUBLIC_CORE_GQL_URL: z.string().default("http://localhost:4455/graphql"), - NEXT_PUBLIC_CORE_GQL_WEB_SOCKET_URL: z - .string() - .default("ws://localhost:4455/graphql"), - NEXT_PUBLIC_PAY_DOMAIN: z.string().default("localhost:3002"), + NEXT_PUBLIC_CORE_GQL_URL: z.string().optional(), + NEXT_PUBLIC_CORE_GQL_WEB_SOCKET_URL: z.string().optional(), + NEXT_PUBLIC_PAY_DOMAIN: z.string().optional(), }, runtimeEnv: { CORE_GQL_URL_INTRANET: process.env.CORE_GQL_URL_INTRANET, NEXT_PUBLIC_CORE_GQL_URL: process.env.NEXT_PUBLIC_CORE_GQL_URL, NEXT_PUBLIC_CORE_GQL_WEB_SOCKET_URL: process.env.NEXT_PUBLIC_CORE_GQL_WEB_SOCKET_URL, - PAY_URL: process.env.PAY_URL, NEXT_PUBLIC_PAY_DOMAIN: process.env.NEXT_PUBLIC_PAY_DOMAIN, + PAY_URL: process.env.PAY_URL, + PAY_DOMAIN: process.env.PAY_DOMAIN, NOSTR_PUBKEY: process.env.NOSTR_PUBKEY, // Optional but required for Nostr Zaps REDIS_PASSWORD: process.env.REDIS_PASSWORD, // Optional but required for Nostr Zaps REDIS_MASTER_NAME: process.env.REDIS_MASTER_NAME, // Optional but required for Nostr Zaps diff --git a/apps/pay/lib/graphql.tsx b/apps/pay/lib/graphql.tsx index 5b446d57ee..f45fd6e444 100644 --- a/apps/pay/lib/graphql.tsx +++ b/apps/pay/lib/graphql.tsx @@ -14,15 +14,15 @@ import { onError } from "@apollo/client/link/error" import { createClient } from "graphql-ws" -import { env } from "../env" +import { getClientSideGqlConfig } from "../config/config" const httpLink = new HttpLink({ - uri: env.NEXT_PUBLIC_CORE_GQL_URL, + uri: getClientSideGqlConfig().coreGqlUrl, }) const wsLink = new GraphQLWsLink( createClient({ - url: env.NEXT_PUBLIC_CORE_GQL_WEB_SOCKET_URL, + url: getClientSideGqlConfig().coreGqlWebSocketUrl, retryAttempts: 12, connectionParams: {}, shouldRetry: (errOrCloseEvent) => { diff --git a/apps/pay/pages/[username]/print.tsx b/apps/pay/pages/[username]/print.tsx index 0d62f35f79..d021121382 100644 --- a/apps/pay/pages/[username]/print.tsx +++ b/apps/pay/pages/[username]/print.tsx @@ -43,7 +43,7 @@ export async function getServerSideProps({ props: { qrCodeURL, username, - userHeader: `Pay ${username}@${env.NEXT_PUBLIC_PAY_DOMAIN}`, + userHeader: `Pay ${username}@${env.PAY_DOMAIN}`, }, } } diff --git a/apps/pay/pages/index.tsx b/apps/pay/pages/index.tsx index 4ea4f593cb..57cc09661d 100644 --- a/apps/pay/pages/index.tsx +++ b/apps/pay/pages/index.tsx @@ -9,8 +9,8 @@ import { gql, useQuery } from "@apollo/client" import { useRouter } from "next/router" -import { env } from "../env" import CurrencyDropdown from "../components/Currency/currency-dropdown" +import { getClientSideGqlConfig } from "../config/config" const GET_NODE_STATS = gql` query nodeIds { @@ -21,7 +21,7 @@ const GET_NODE_STATS = gql` ` function Home() { - const nodeUrl = env.NEXT_PUBLIC_CORE_GQL_URL.includes("staging") + const nodeUrl = getClientSideGqlConfig().coreGqlUrl.includes("staging") ? `https://mempool.space/signet/lightning/node/` : `https://mempool.space/lightning/node/` const { loading, error, data } = useQuery(GET_NODE_STATS) diff --git a/dev/Tiltfile b/dev/Tiltfile index 0527db3bb9..3b385041c1 100644 --- a/dev/Tiltfile +++ b/dev/Tiltfile @@ -76,10 +76,11 @@ local_resource( serve_env = { "PORT": "3002", "CORE_GQL_URL_INTRANET": "http://localhost:4455/graphql", + "PAY_URL": "http://localhost:3002", + "PAY_DOMAIN": "localhost:3002", "NEXT_PUBLIC_CORE_GQL_URL": "http://localhost:4455/graphql", "NEXT_PUBLIC_CORE_GQL_WEB_SOCKET_URL": "wss://localhost:4455/graphql", - "PAY_URL":"http://localhost:3002", - "NEXT_PUBLIC_PAY_DOMAIN":"http://localhost:3002", + "NEXT_PUBLIC_PAY_DOMAIN": "localhost:3002", }, deps = _buck2_dep_inputs(pay_target), allow_parallel = True,