From 954f97b44c8a98519a9c9f4019a3929b693c6fc2 Mon Sep 17 00:00:00 2001 From: vimtor Date: Mon, 18 May 2026 20:08:43 +0200 Subject: [PATCH] core: copy Go referral links from current site Users should share the actual site they are visiting, and the reward dialog should only close once credit is applied. Keep Drizzle tooling on the same beta snapshot as runtime ORM so schema commands avoid version drift. --- bun.lock | 4 +- package.json | 2 +- .../console/app/src/component/go-referral.tsx | 69 +++++-------------- 3 files changed, 21 insertions(+), 54 deletions(-) diff --git a/bun.lock b/bun.lock index aa87c959df..2a79552b9e 100644 --- a/bun.lock +++ b/bun.lock @@ -745,7 +745,7 @@ "cross-spawn": "7.0.6", "diff": "8.0.2", "dompurify": "3.3.1", - "drizzle-kit": "1.0.0-beta.22", + "drizzle-kit": "1.0.0-beta.19-d95b7a4", "drizzle-orm": "1.0.0-beta.19-d95b7a4", "effect": "4.0.0-beta.65", "fuzzysort": "3.1.0", @@ -2972,7 +2972,7 @@ "dotenv-expand": ["dotenv-expand@11.0.7", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA=="], - "drizzle-kit": ["drizzle-kit@1.0.0-beta.22", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "get-tsconfig": "^4.13.6", "jiti": "^2.6.1" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-9HTZuQRljQKTgCx4UhiGn8KYYfHGk4+B/bRR1714W67kz0qgJvdrG527i8rQD8uUyET9UTGR1u8syySJD4znGw=="], + "drizzle-kit": ["drizzle-kit@1.0.0-beta.19-d95b7a4", "", { "dependencies": { "@drizzle-team/brocli": "^0.11.0", "@js-temporal/polyfill": "^0.5.1", "esbuild": "^0.25.10", "get-tsconfig": "^4.13.6", "jiti": "^2.6.1" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-M0sqc+42TYBod6kEZ3AsW6+JWe3+76gR1aDFbHH5DmuLKEwewmbzlhBG6qnvV6YA1cIIbkuam3dC7r6PREOCXw=="], "drizzle-orm": ["drizzle-orm@1.0.0-beta.19-d95b7a4", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@effect/sql": "^0.48.5", "@effect/sql-pg": "^0.49.7", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@sinclair/typebox": ">=0.34.8", "@sqlitecloud/drivers": ">=1.0.653", "@tidbcloud/serverless": "*", "@tursodatabase/database": ">=0.2.1", "@tursodatabase/database-common": ">=0.2.1", "@tursodatabase/database-wasm": ">=0.2.1", "@types/better-sqlite3": "*", "@types/mssql": "^9.1.4", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "arktype": ">=2.0.0", "better-sqlite3": ">=9.3.0", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "mssql": "^11.0.1", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5", "typebox": ">=1.0.0", "valibot": ">=1.0.0-beta.7", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@effect/sql", "@effect/sql-pg", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@sinclair/typebox", "@sqlitecloud/drivers", "@tidbcloud/serverless", "@tursodatabase/database", "@tursodatabase/database-common", "@tursodatabase/database-wasm", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "arktype", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "mysql2", "pg", "postgres", "sql.js", "sqlite3", "typebox", "valibot", "zod"] }, "sha512-bZZKKeoRKrMVU6zKTscjrSH0+WNb1WEi3N0Jl4wEyQ7aQpTgHzdYY6IJQ1P0M74HuSJVeX4UpkFB/S6dtqLEJg=="], diff --git a/package.json b/package.json index 6205d8773b..f1cc7da5c3 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@tailwindcss/vite": "4.1.11", "diff": "8.0.2", "dompurify": "3.3.1", - "drizzle-kit": "1.0.0-beta.22", + "drizzle-kit": "1.0.0-beta.19-d95b7a4", "drizzle-orm": "1.0.0-beta.19-d95b7a4", "effect": "4.0.0-beta.65", "ai": "6.0.168", diff --git a/packages/console/app/src/component/go-referral.tsx b/packages/console/app/src/component/go-referral.tsx index 6f0b305bb8..22aaa5976c 100644 --- a/packages/console/app/src/component/go-referral.tsx +++ b/packages/console/app/src/component/go-referral.tsx @@ -1,6 +1,5 @@ import { action, createAsync, json, query, useAction, useSubmission } from "@solidjs/router" -import { createEffect, createMemo, createSignal, For, onCleanup, Show } from "solid-js" -import { getRequestEvent } from "solid-js/web" +import { createEffect, createMemo, createSignal, For, onCleanup, onMount, Show } from "solid-js" import { Referral } from "@opencode-ai/console-core/referral.js" import { withActor } from "~/context/auth.withActor" import { Modal } from "~/component/modal" @@ -11,38 +10,10 @@ import { formatResetTime, liteResetTimeKeys } from "~/lib/format-reset-time" import { queryLiteSubscription } from "~/routes/workspace/[id]/go/lite-section" import "./go-referral.css" -type GoReferralReward = { - id: string - amount: number - email: string - source: "inviter" | "invitee" - status: "pending" | "available" | "applied" - timeCreated: string | Date - timeApplied: string | Date | null -} - -type GoReferralSummary = { - inviteCode: string - inviteUrl: string - validInviteCount: number - hasActiveGo: boolean - rewardAmount: number - totalEarned: number - totalApplied: number - rewards: GoReferralReward[] -} - -type GoReferralUsagePreview = { - rollingUsage: GoReferralUsagePreviewItem - weeklyUsage: GoReferralUsagePreviewItem - monthlyUsage: GoReferralUsagePreviewItem -} - -type GoReferralUsagePreviewItem = { - beforePercent: number - afterPercent: number - resetInSec: number -} +type GoReferralSummary = Awaited> +type GoReferralReward = GoReferralSummary["rewards"][number] +type GoReferralUsagePreview = NonNullable>> +type GoReferralUsagePreviewItem = GoReferralUsagePreview["rollingUsage"] const emptyUsagePreview = { rollingUsage: { beforePercent: 0, afterPercent: 0, resetInSec: 0 }, @@ -52,13 +23,7 @@ const emptyUsagePreview = { export const queryGoReferral = query(async (workspaceID: string) => { "use server" - return withActor(async () => { - const summary = await Referral.summary() - return { - ...summary, - inviteUrl: new URL(`/go?invite=${summary.inviteCode}`, getRequestEvent()!.request.url).toString(), - } satisfies GoReferralSummary - }, workspaceID) + return withActor(() => Referral.summary(), workspaceID) }, "go.referral.get") export const queryGoReferralUsagePreview = query(async (workspaceID: string, referralID?: string) => { @@ -70,13 +35,7 @@ export const queryGoReferralUsagePreview = query(async (workspaceID: string, ref export const applyGoReferralReward = action(async (workspaceID: string, referralID: string) => { "use server" return json( - await withActor( - () => - Referral.applyReward({ referralID }) - .then((data) => ({ error: undefined, data })) - .catch((e) => ({ error: e.message as string, data: undefined })), - workspaceID, - ), + await withActor(() => Referral.applyReward({ referralID }), workspaceID), { revalidate: [queryGoReferral.key, queryGoReferralUsagePreview.key, queryLiteSubscription.key] }, ) }, "go.referral.reward.apply") @@ -114,10 +73,18 @@ function rewardPendingStatusKey(source: GoReferralReward["source"]) { function CopyInviteLink(props: { summary: GoReferralSummary }) { const i18n = useI18n() const [copied, setCopied] = createSignal(false) + const [origin, setOrigin] = createSignal("") + const inviteUrl = createMemo(() => { + const path = `/go?invite=${props.summary.inviteCode}` + if (!origin()) return path + return new URL(path, origin()).toString() + }) + + onMount(() => setOrigin(window.location.origin)) async function copy() { if (typeof navigator !== "object") return - await navigator.clipboard.writeText(props.summary.inviteUrl) + await navigator.clipboard.writeText(inviteUrl()) setCopied(true) window.setTimeout(() => setCopied(false), 1600) } @@ -125,7 +92,7 @@ function CopyInviteLink(props: { summary: GoReferralSummary }) { return (
- {props.summary.inviteUrl} + {inviteUrl()}