diff --git a/apps/builder/app/dashboard/profile-menu.tsx b/apps/builder/app/dashboard/profile-menu.tsx index 2989e7dda162..32f29850cbf9 100644 --- a/apps/builder/app/dashboard/profile-menu.tsx +++ b/apps/builder/app/dashboard/profile-menu.tsx @@ -87,9 +87,11 @@ export const ProfileMenu = ({ purchase.subscriptionId ? ( - navigate(userPlanSubscriptionPath(purchase.subscriptionId)) - } + onSelect={() => { + window.location.href = userPlanSubscriptionPath( + purchase.subscriptionId + ); + }} > {purchase.planName} diff --git a/apps/builder/app/env/env.server.ts b/apps/builder/app/env/env.server.ts index 4ceaaa1777f8..a362cc291716 100644 --- a/apps/builder/app/env/env.server.ts +++ b/apps/builder/app/env/env.server.ts @@ -51,12 +51,6 @@ const env = { projectId.trim() ) ?? [], - N8N_WEBHOOK_URL: process.env.N8N_WEBHOOK_URL, - N8N_WEBHOOK_TOKEN: process.env.N8N_WEBHOOK_TOKEN, - - PAYMENT_WORKER_URL: process.env.PAYMENT_WORKER_URL, - PAYMENT_WORKER_TOKEN: process.env.PAYMENT_WORKER_TOKEN, - PUBLISHER_HOST: process.env.PUBLISHER_HOST || "wstd.work", STAGING_USERNAME: process.env.STAGING_USERNAME ?? "admin", diff --git a/apps/builder/app/routes/n8n.$.tsx b/apps/builder/app/routes/n8n.$.tsx deleted file mode 100644 index f6d81c803a63..000000000000 --- a/apps/builder/app/routes/n8n.$.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import { type LoaderFunctionArgs, json } from "@remix-run/server-runtime"; -import { isRouteErrorResponse, useRouteError } from "@remix-run/react"; -import { z } from "zod"; -import { findAuthenticatedUser } from "~/services/auth.server"; -import { isDashboard, loginPath } from "~/shared/router-utils"; -import env from "~/env/env.server"; -import cookie from "cookie"; -import { preventCrossOriginCookie } from "~/services/no-cross-origin-cookie"; -import { redirect } from "~/services/no-store-redirect"; -import { allowedDestinations } from "~/services/destinations.server"; - -const zN8NResponse = z.union([ - z.object({ - type: z.literal("error"), - error: z.string(), - }), - - z.object({ - type: z.literal("redirect"), - to: z.string(), - }), -]); -const zWebhookEnv = z.object({ - N8N_WEBHOOK_URL: z.string(), - N8N_WEBHOOK_TOKEN: z.string(), -}); - -export const loader = async ({ request, params }: LoaderFunctionArgs) => { - if (isDashboard(request) === false) { - throw new Response("Not Found", { - status: 404, - }); - } - - preventCrossOriginCookie(request); - allowedDestinations(request, ["document", "empty"]); - // CSRF token checks are not necessary for dashboard-only pages. - // All requests from the builder or canvas app are safeguarded either by preventCrossOriginCookie for fetch requests - // or by allowedDestinations for iframe requests. - - const user = await findAuthenticatedUser(request); - - if (user === null) { - const url = new URL(request.url); - throw redirect( - loginPath({ - returnTo: `${url.pathname}?${url.searchParams.toString()}`, - }) - ); - } - - const webhookEnvParsed = zWebhookEnv.safeParse(env); - if (webhookEnvParsed.success === false) { - throw new Response(webhookEnvParsed.error.message, { - status: 400, - }); - } - - const webhookEnv = webhookEnvParsed.data; - - const n8nWebhookUrl = new URL(webhookEnv.N8N_WEBHOOK_URL); - n8nWebhookUrl.pathname = `${n8nWebhookUrl.pathname}/${ - env.DEPLOYMENT_ENVIRONMENT ?? "local" - }/${params["*"]}` - .split("/") - .filter(Boolean) - .join("/"); - n8nWebhookUrl.search = new URL(request.url).search; - - const requestUrl = new URL(request.url); - - const response = await fetch(n8nWebhookUrl.href, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${webhookEnv.N8N_WEBHOOK_TOKEN}`, - }, - body: JSON.stringify({ - userId: user.id, - // For anonymous tracking like posthog - cookies: cookie.parse(request.headers.get("cookie") ?? ""), - requestUrl: requestUrl.href, - }), - }); - - if (response.ok === false) { - const text = await response.text(); - - throw new Response( - `Fetch error status="${response.status}"\nMessage:\n${text.slice( - 0, - 1000 - )}"`, - { - status: response.status, - } - ); - } - const responseJson = await response.json(); - const n8nResponseParsed = zN8NResponse.safeParse(responseJson); - - if (n8nResponseParsed.success === false) { - throw new Response(n8nResponseParsed.error.message, { - status: 400, - }); - } - - const n8nResponse = n8nResponseParsed.data; - - if (n8nResponse.type === "error") { - throw new Response(n8nResponse.error, { - status: 400, - }); - } - - if (n8nResponse.type === "redirect") { - throw redirect(n8nResponse.to); - } - - n8nResponse satisfies never; - - return json({}); -}; - -export const ErrorBoundary = () => { - const error = useRouteError(); - - if (isRouteErrorResponse(error)) { - return
{error.data}
; - } - - if (error instanceof Error) { - return
{error.message}
; - } - - return
{String(error)}
; -}; diff --git a/apps/builder/app/routes/payments.$.tsx b/apps/builder/app/routes/payments.$.tsx deleted file mode 100644 index a92e045117d5..000000000000 --- a/apps/builder/app/routes/payments.$.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { type LoaderFunctionArgs, json } from "@remix-run/server-runtime"; -import { isRouteErrorResponse, useRouteError } from "@remix-run/react"; -import { z } from "zod"; -import { findAuthenticatedUser } from "~/services/auth.server"; -import { isDashboard, loginPath } from "~/shared/router-utils"; -import env from "~/env/env.server"; -import cookie from "cookie"; -import { preventCrossOriginCookie } from "~/services/no-cross-origin-cookie"; -import { redirect } from "~/services/no-store-redirect"; -import { allowedDestinations } from "~/services/destinations.server"; - -const zWorkerResponse = z.union([ - z.object({ - type: z.literal("error"), - error: z.string(), - }), - z.object({ - type: z.literal("redirect"), - to: z.string(), - }), -]); - -const zWorkerEnv = z.object({ - PAYMENT_WORKER_URL: z.string(), - PAYMENT_WORKER_TOKEN: z.string(), -}); - -export const loader = async ({ request, params }: LoaderFunctionArgs) => { - if (isDashboard(request) === false) { - throw new Response("Not Found", { - status: 404, - }); - } - - preventCrossOriginCookie(request); - allowedDestinations(request, ["document", "empty"]); - - const user = await findAuthenticatedUser(request); - - if (user === null) { - const url = new URL(request.url); - throw redirect( - loginPath({ - returnTo: `${url.pathname}?${url.searchParams.toString()}`, - }) - ); - } - - const workerEnvParsed = zWorkerEnv.safeParse(env); - if (workerEnvParsed.success === false) { - throw new Response(workerEnvParsed.error.message, { - status: 400, - }); - } - - const workerEnv = workerEnvParsed.data; - - const workerUrl = new URL(workerEnv.PAYMENT_WORKER_URL); - workerUrl.pathname = `${workerUrl.pathname}/${params["*"]}` - .split("/") - .filter(Boolean) - .join("/"); - workerUrl.search = new URL(request.url).search; - - const requestUrl = new URL(request.url); - - const response = await fetch(workerUrl.href, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${workerEnv.PAYMENT_WORKER_TOKEN}`, - }, - body: JSON.stringify({ - userId: user.id, - cookies: cookie.parse(request.headers.get("cookie") ?? ""), - requestUrl: requestUrl.href, - }), - }); - - if (response.ok === false) { - const text = await response.text(); - - throw new Response( - `Fetch error status="${response.status}"\nMessage:\n${text.slice( - 0, - 1000 - )}"`, - { - status: response.status, - } - ); - } - - const responseJson = await response.json(); - const workerResponseParsed = zWorkerResponse.safeParse(responseJson); - - if (workerResponseParsed.success === false) { - throw new Response(workerResponseParsed.error.message, { - status: 400, - }); - } - - const workerResponse = workerResponseParsed.data; - - if (workerResponse.type === "error") { - throw new Response(workerResponse.error, { - status: 400, - }); - } - - if (workerResponse.type === "redirect") { - throw redirect(workerResponse.to); - } - - workerResponse satisfies never; - - return json({}); -}; - -export const ErrorBoundary = () => { - const error = useRouteError(); - - if (isRouteErrorResponse(error)) { - return
{error.data}
; - } - - return
Unexpected error
; -}; diff --git a/apps/builder/app/shared/router-utils/path-utils.ts b/apps/builder/app/shared/router-utils/path-utils.ts index 50453ab1e325..01c0515891f4 100644 --- a/apps/builder/app/shared/router-utils/path-utils.ts +++ b/apps/builder/app/shared/router-utils/path-utils.ts @@ -2,7 +2,6 @@ import type { AUTH_PROVIDERS } from "~/shared/session"; import { publicStaticEnv } from "~/env/env.static"; import { getAuthorizationServerOrigin } from "./origins"; import type { BuilderMode } from "../nano-states/misc"; -import { isFeatureEnabled } from "@webstudio-is/feature-flags"; const searchParams = (params: Record) => { const searchParams = new URLSearchParams(); @@ -116,11 +115,7 @@ export const userPlanSubscriptionPath = (subscriptionId?: string) => { urlSearchParams.set("subscription", subscriptionId); } - if (isFeatureEnabled("paymentWorker")) { - return `/payments/billing-portal/sessions?${urlSearchParams.toString()}`; - } - - return `/n8n/billing_portal/sessions?${urlSearchParams.toString()}`; + return `/builder-payments/billing-portal/sessions?${urlSearchParams.toString()}`; }; export const authCallbackPath = ({ diff --git a/packages/feature-flags/src/flags.ts b/packages/feature-flags/src/flags.ts index 0169eb1541b6..0a952b87c8df 100644 --- a/packages/feature-flags/src/flags.ts +++ b/packages/feature-flags/src/flags.ts @@ -3,4 +3,3 @@ export const internalComponents = false; export const unsupportedBrowsers = false; export const resourceProp = false; export const tailwind = false; -export const paymentWorker = false;