From f551d614e4121a3e8dd7cbf551fd84da03d0f207 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Thu, 16 Apr 2026 02:54:38 +0100 Subject: [PATCH 01/34] chore: simplify seat update call (#5703) --- apps/builder/.env | 2 +- .../app/services/workspace-router.server.ts | 30 ++----------------- apps/builder/app/shared/permissions.test.ts | 4 +-- packages/plans/src/plan-features.ts | 4 +-- 4 files changed, 8 insertions(+), 32 deletions(-) diff --git a/apps/builder/.env b/apps/builder/.env index 53c8d18477c2..1f68cabc83f9 100644 --- a/apps/builder/.env +++ b/apps/builder/.env @@ -74,7 +74,7 @@ PLANS='[ "extends": "Pro", "features": { "maxWorkspaces": 20, - "minSeats": 4, + "seatsIncluded": 4, "maxSeatsPerWorkspace": 20 } } diff --git a/apps/builder/app/services/workspace-router.server.ts b/apps/builder/app/services/workspace-router.server.ts index 9966d036e6d5..5989894542d6 100644 --- a/apps/builder/app/services/workspace-router.server.ts +++ b/apps/builder/app/services/workspace-router.server.ts @@ -6,8 +6,7 @@ import { } from "@webstudio-is/trpc-interface/index.server"; import { workspace as workspaceApi } from "@webstudio-is/project/index.server"; import { roles } from "@webstudio-is/trpc-interface/authorize"; -import { getPlanInfo, getPaidSeats } from "@webstudio-is/plans/index.server"; -import { defaultPlanFeatures } from "@webstudio-is/plans"; +import { getPaidSeats } from "@webstudio-is/plans/index.server"; import env from "~/env/env.server"; const Name = z.string().min(2).max(100); @@ -19,16 +18,10 @@ type UpdateSeatsResult = const updateSeats = async ({ userId, - subscriptionId, newQuantity, - minSeats, - maxSeats, }: { userId: string; - subscriptionId: string; newQuantity: number; - minSeats: number; - maxSeats: number; }): Promise => { if (!env.PAYMENT_WORKER_URL || !env.PAYMENT_WORKER_TOKEN) { return null; @@ -44,10 +37,7 @@ const updateSeats = async ({ }, body: JSON.stringify({ userId, - subscriptionId, newQuantity, - minSeats, - maxSeats, }), }); @@ -86,25 +76,11 @@ const syncOwnerSeats = async ( } const ownerId = workspaceResult.data.userId; - const planResults = await getPlanInfo([ownerId], ctx); - const { planFeatures, purchases } = planResults.get(ownerId) ?? { - planFeatures: defaultPlanFeatures, - purchases: [], - }; - - const subscription = purchases.find((p) => p.subscriptionId !== undefined); - if (subscription?.subscriptionId === undefined) { - return; - } - const memberCount = await workspaceApi.countAllMembers(ownerId, ctx); const result = await updateSeats({ userId: ownerId, - subscriptionId: subscription.subscriptionId, newQuantity: memberCount + countDelta, - minSeats: planFeatures.minSeats, - maxSeats: planFeatures.maxSeatsPerWorkspace, }); if (result === null) { @@ -336,9 +312,9 @@ export const workspaceRouter = router({ success: true as const, data: { ...members, - // Falls back to minSeats (seats included in the plan) when no + // Falls back to seatsIncluded (seats included in the plan) when no // subscription event exists yet (free plan, AppSumo, etc.). - maxSeats: paidSeats ?? ctx.planFeatures.minSeats, + maxSeats: paidSeats ?? ctx.planFeatures.seatsIncluded, }, }; } catch (error) { diff --git a/apps/builder/app/shared/permissions.test.ts b/apps/builder/app/shared/permissions.test.ts index 66b375547e91..1e6429653311 100644 --- a/apps/builder/app/shared/permissions.test.ts +++ b/apps/builder/app/shared/permissions.test.ts @@ -30,7 +30,7 @@ const proPlan = { maxWorkspaces: 0, maxProjectsAllowedPerUser: 100, maxAssetsPerProject: 500, - minSeats: 0, + seatsIncluded: 0, maxSeatsPerWorkspace: 0, }; @@ -47,7 +47,7 @@ const freePlan = { maxWorkspaces: 0, maxProjectsAllowedPerUser: 2, maxAssetsPerProject: 50, - minSeats: 0, + seatsIncluded: 0, maxSeatsPerWorkspace: 0, }; diff --git a/packages/plans/src/plan-features.ts b/packages/plans/src/plan-features.ts index 1438154258e9..ef06b01c8d36 100644 --- a/packages/plans/src/plan-features.ts +++ b/packages/plans/src/plan-features.ts @@ -18,7 +18,7 @@ export const PlanFeaturesSchema = z.object({ maxWorkspaces: z.number().nonnegative(), maxProjectsAllowedPerUser: z.number().nonnegative(), maxAssetsPerProject: z.number().nonnegative(), - minSeats: z.number().nonnegative(), + seatsIncluded: z.number().nonnegative(), maxSeatsPerWorkspace: z.number().nonnegative(), }); @@ -45,7 +45,7 @@ export const defaultPlanFeatures: PlanFeatures = { maxWorkspaces: 1, maxProjectsAllowedPerUser: 100, maxAssetsPerProject: 50, - minSeats: 0, + seatsIncluded: 0, maxSeatsPerWorkspace: 0, }; From 3099ba045c6bfa934e8407a8e528182c35fa272b Mon Sep 17 00:00:00 2001 From: Ivan Starkov Date: Fri, 5 Dec 2025 18:45:51 +0700 Subject: [PATCH 02/34] Try prod release again --- .github/actions/vercel/action.yaml | 12 +++++++++++- .github/workflows/vercel-deploy-staging.yml | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/.github/actions/vercel/action.yaml b/.github/actions/vercel/action.yaml index 9b0119f54184..6ba96844c1ea 100644 --- a/.github/actions/vercel/action.yaml +++ b/.github/actions/vercel/action.yaml @@ -76,7 +76,11 @@ runs: export GITHUB_SHA=${{ inputs.sha }} export GITHUB_REF_NAME=${{ inputs.ref-name }} - pnpx vercel build + if [ "${{ inputs.environment }}" = "production" ]; then + pnpx vercel build --prod + else + pnpx vercel build + fi shell: bash - name: Patch @@ -103,8 +107,14 @@ runs: - name: Deploy id: deploy run: | + PROD_FLAGS="" + if [ "${{ inputs.environment }}" = "production" ]; then + PROD_FLAGS="--prod --skip-domain" + fi + pnpx vercel deploy \ --prebuilt \ + $PROD_FLAGS \ --token ${{ inputs.vercel-token }} \ 2> >(tee info.txt >&2) | tee domain.txt diff --git a/.github/workflows/vercel-deploy-staging.yml b/.github/workflows/vercel-deploy-staging.yml index a96527e72bfb..51e6d23bf227 100644 --- a/.github/workflows/vercel-deploy-staging.yml +++ b/.github/workflows/vercel-deploy-staging.yml @@ -87,6 +87,18 @@ jobs: sha: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }} environment: ${{ matrix.environment }} + - uses: ./.github/actions/vercel + if: matrix.environment == 'staging' + id: vercel-prod + name: Deploy to Vercel + with: + vercel-token: ${{ secrets.VERCEL_TOKEN }} + vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} + vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} + ref-name: ${{ github.ref_name }} + sha: ${{ github.sha }} + environment: "production" + - name: Debug Vercel Outputs run: | echo "domain=${{ steps.vercel.outputs.domain }}" @@ -99,6 +111,13 @@ jobs: description: "[${{ matrix.environment }}] Vercel logs" url: "${{ steps.vercel.outputs.inspect-url }}" + - uses: ./.github/actions/add-status + if: matrix.environment == 'staging' + with: + title: "⏰ [${{ matrix.environment }}] Vercel Production Inspection" + description: "[${{ matrix.environment }}] Vercel production logs" + url: "${{ steps.vercel-prod.outputs.inspect-url }}" + - uses: ./.github/actions/add-status with: title: "⭐ [${{ matrix.environment }}] Apps Webstudio URL" From ea280b1984cceaec0ed2e14c819d1afc8f41f485 Mon Sep 17 00:00:00 2001 From: Ivan Starkov Date: Fri, 5 Dec 2025 18:52:54 +0700 Subject: [PATCH 03/34] Try fix --- .github/actions/vercel/action.yaml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/.github/actions/vercel/action.yaml b/.github/actions/vercel/action.yaml index 6ba96844c1ea..b1f2c20e72f8 100644 --- a/.github/actions/vercel/action.yaml +++ b/.github/actions/vercel/action.yaml @@ -107,23 +107,27 @@ runs: - name: Deploy id: deploy run: | - PROD_FLAGS="" if [ "${{ inputs.environment }}" = "production" ]; then - PROD_FLAGS="--prod --skip-domain" + pnpx vercel deploy \ + --prebuilt \ + --prod \ + --skip-domain \ + --token ${{ inputs.vercel-token }} \ + 2> >(tee info.txt >&2) | tee domain.txt + else + pnpx vercel deploy \ + --prebuilt \ + --token ${{ inputs.vercel-token }} \ + 2> >(tee info.txt >&2) | tee domain.txt fi - pnpx vercel deploy \ - --prebuilt \ - $PROD_FLAGS \ - --token ${{ inputs.vercel-token }} \ - 2> >(tee info.txt >&2) | tee domain.txt - echo "domain=$(cat ./domain.txt)" >> $GITHUB_OUTPUT echo "inspect-url=$(cat info.txt | grep 'Inspect:' | awk '{print $2}')" >> $GITHUB_OUTPUT shell: bash - name: Set Alias + if: ${{ inputs.environment != 'production' }} id: alias run: | ALIAS="${{ steps.branch.outputs.value }}" From 9f65a12baf58cf2cea4f99b9a403592a4b12a4f5 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Mon, 8 Dec 2025 21:30:06 +0000 Subject: [PATCH 04/34] test From 4ed940cd31771b793ccce8b12a567d81cdf24f36 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Tue, 9 Dec 2025 23:27:22 +0000 Subject: [PATCH 05/34] test From 3e8454c08c965ee301607bca16f40f0c427c5994 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Fri, 12 Dec 2025 12:36:45 +0000 Subject: [PATCH 06/34] test From a0889daeded0785a85431ca12205a5d13c365db9 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Mon, 15 Dec 2025 16:39:46 +0000 Subject: [PATCH 07/34] context menu From 78fe5af44bdc4bd0d3a9ca2603737d129f55768b Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Tue, 16 Dec 2025 13:12:47 +0000 Subject: [PATCH 08/34] fix paste and settings permissions From 385ede4e68e8f9ce59b4c741317e8959132c144e Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Wed, 17 Dec 2025 00:44:37 +0000 Subject: [PATCH 09/34] convert instance From daf1bfa926d06a441e8165dcbdbf328391df7893 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Thu, 18 Dec 2025 16:39:57 +0000 Subject: [PATCH 10/34] tokens conflict management From 292ce9116f28a2e3823c5da1385c6de491e52b9e Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Thu, 18 Dec 2025 23:19:53 +0000 Subject: [PATCH 11/34] publish enh, commands panel enh, instances search From 2de857990c77cc5c4ddd7188561be4f696b64412 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Thu, 18 Dec 2025 23:40:58 +0000 Subject: [PATCH 12/34] publish enh, commands panel enh, instances search From e4d19ce4176fee2c0ebf36f29348ced69302abf1 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Sat, 27 Dec 2025 15:55:31 +0000 Subject: [PATCH 13/34] fix svg upload From 79dc4eac4215d68beb7b2f2ff3bd69f56a6fc177 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Sun, 4 Jan 2026 17:56:10 +0000 Subject: [PATCH 14/34] media conditions From d5dc525f67a474ee948f79aec69c3eab7c7020a0 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Mon, 8 Dec 2025 21:30:06 +0000 Subject: [PATCH 15/34] test From d3049137799ab7a8eb807994bbf5b7d288909405 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Tue, 9 Dec 2025 23:27:22 +0000 Subject: [PATCH 16/34] test From 69c8c01eb8355f69d412d7f2684585aedf3b3386 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Fri, 12 Dec 2025 12:36:45 +0000 Subject: [PATCH 17/34] test From 3d325a4ac0cff17c0c28308e6a4e92ef1c811c69 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Mon, 15 Dec 2025 16:39:46 +0000 Subject: [PATCH 18/34] context menu From 23de241dc4210ac8aa8079d0c416ee37f0766e17 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Tue, 16 Dec 2025 13:12:47 +0000 Subject: [PATCH 19/34] fix paste and settings permissions From 3034268253503daf25023f9eeeaf274c264575c2 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Wed, 17 Dec 2025 00:44:37 +0000 Subject: [PATCH 20/34] convert instance From 0528d67583c4bf88d648548c07f08332a9c598ae Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Thu, 18 Dec 2025 16:39:57 +0000 Subject: [PATCH 21/34] tokens conflict management From 4f3255a9db48656f156cab9397bf974fff89b44a Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Thu, 18 Dec 2025 23:19:53 +0000 Subject: [PATCH 22/34] publish enh, commands panel enh, instances search From b44845987153c7d36ac5cb9f4bc49dad83808d9e Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Thu, 18 Dec 2025 23:40:58 +0000 Subject: [PATCH 23/34] publish enh, commands panel enh, instances search From aa2201486c29ee09057e9496bcb66da1e20b50ca Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Sat, 27 Dec 2025 15:55:31 +0000 Subject: [PATCH 24/34] fix svg upload From 4df4aeaca5ee79223cfd3bf7eeb82db29972eaf9 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Sun, 4 Jan 2026 17:56:10 +0000 Subject: [PATCH 25/34] media conditions From 17934ed6d94dc9dc91a7bdc732e6d9e5d9315aa2 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Mon, 12 Jan 2026 16:48:33 +0000 Subject: [PATCH 26/34] 0.248.0 From 04787de57cba1c3f731181c902f72db89da0f613 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Thu, 5 Feb 2026 22:44:55 +0000 Subject: [PATCH 27/34] 0.253.0 From 490abaed7bb84f2a1a9eee7e672e1a1f520d0a32 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Thu, 19 Feb 2026 10:45:15 +0000 Subject: [PATCH 28/34] redirects From f66dd3ed3375fc1a61215f44fad02fb8fd357a3d Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Tue, 24 Mar 2026 14:58:08 +0000 Subject: [PATCH 29/34] fix: use valid CSS color space names in toValue() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit colorjs uses internal short names (p3, a98rgb, prophoto) that don't match the CSS predefined color space identifiers required by the spec: - p3 → display-p3 - a98rgb → a98-rgb - prophoto → prophoto-rgb This caused toValue() to emit invalid CSS like `color(p3 ...)`, which the css-tree lexer rejects when re-validating the value in the CSS value input (e.g. after a round-trip through the style panel). --- packages/css-engine/src/core/to-value.test.ts | 1 - packages/css-engine/src/core/to-value.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/css-engine/src/core/to-value.test.ts b/packages/css-engine/src/core/to-value.test.ts index 8319ed53f59b..cf84b7f5e193 100644 --- a/packages/css-engine/src/core/to-value.test.ts +++ b/packages/css-engine/src/core/to-value.test.ts @@ -446,7 +446,6 @@ describe("Convert WS CSS Values to native CSS strings", () => { expect(value).toBe(expected); }); } - }); test("color in tuple", () => { const value = toValue({ diff --git a/packages/css-engine/src/core/to-value.ts b/packages/css-engine/src/core/to-value.ts index cd4dec85b07e..16c83dc8661e 100644 --- a/packages/css-engine/src/core/to-value.ts +++ b/packages/css-engine/src/core/to-value.ts @@ -122,7 +122,7 @@ export const toValue = ( case "oklch": return `oklch(${c1} ${c2} ${c3} / ${alpha})`; // Fall back to color() function for less common color spaces. - // colorjs uses internal short names that differ from CSS predefined color space identifiers. + // Webstudio uses colorjs internal names; map to CSS predefined color space names. case "p3": return `color(display-p3 ${c1} ${c2} ${c3} / ${alpha})`; case "a98rgb": From a66239fa3c759b8de635001b1fd6b93dc9033a00 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Tue, 31 Mar 2026 14:47:31 +0000 Subject: [PATCH 30/34] lostpixel trigger From 512cc4b1b4de61b9449582dcf2b8cf8eb3438a8d Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Wed, 1 Apr 2026 10:41:44 +0000 Subject: [PATCH 31/34] redepploy From 9a2822a20921bb619c96c57f2f5bda539d0fa1b3 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Wed, 8 Apr 2026 20:03:09 +0000 Subject: [PATCH 32/34] ::migrate:: From efe0b534ded8fc184889c196e66edc041d352022 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Mon, 13 Apr 2026 18:51:45 +0000 Subject: [PATCH 33/34] wip workspaces ::migrate:: From 9552e0d8d214e027168d06efe632a0961876fe86 Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Wed, 15 Apr 2026 22:30:13 +0000 Subject: [PATCH 34/34] test