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;