Frank 2 месяцев назад
Родитель
Сommit
eaf18d9915

+ 2 - 0
infra/console.ts

@@ -122,6 +122,7 @@ const ZEN_MODELS = [
 ]
 ]
 const ZEN_BLACK = new sst.Secret("ZEN_BLACK")
 const ZEN_BLACK = new sst.Secret("ZEN_BLACK")
 const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY")
 const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY")
+const STRIPE_PUBLISHABLE_KEY = new sst.Secret("STRIPE_PUBLISHABLE_KEY")
 const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", {
 const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", {
   properties: { value: auth.url.apply((url) => url!) },
   properties: { value: auth.url.apply((url) => url!) },
 })
 })
@@ -177,6 +178,7 @@ new sst.cloudflare.x.SolidStart("Console", {
     //VITE_DOCS_URL: web.url.apply((url) => url!),
     //VITE_DOCS_URL: web.url.apply((url) => url!),
     //VITE_API_URL: gateway.url.apply((url) => url!),
     //VITE_API_URL: gateway.url.apply((url) => url!),
     VITE_AUTH_URL: auth.url.apply((url) => url!),
     VITE_AUTH_URL: auth.url.apply((url) => url!),
+    VITE_STRIPE_PUBLISHABLE_KEY: STRIPE_PUBLISHABLE_KEY.value,
   },
   },
   transform: {
   transform: {
     server: {
     server: {

+ 1 - 1
packages/console/app/package.json

@@ -6,7 +6,7 @@
   "scripts": {
   "scripts": {
     "typecheck": "tsgo --noEmit",
     "typecheck": "tsgo --noEmit",
     "dev": "vite dev --host 0.0.0.0",
     "dev": "vite dev --host 0.0.0.0",
-    "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev",
+    "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai VITE_STRIPE_PUBLISHABLE_KEY=pk_test_51RtuLNE7fOCwHSD4mewwzFejyytjdGoSDK7CAvhbffwaZnPbNb2rwJICw6LTOXCmWO320fSNXvb5NzI08RZVkAxd00syfqrW7t bun sst shell --stage=dev bun dev",
     "build": "./script/generate-sitemap.ts && vite build && ../../opencode/script/schema.ts ./.output/public/config.json",
     "build": "./script/generate-sitemap.ts && vite build && ../../opencode/script/schema.ts ./.output/public/config.json",
     "start": "vite start"
     "start": "vite start"
   },
   },

+ 0 - 6
packages/console/app/src/config.ts

@@ -26,10 +26,4 @@ export const config = {
     commits: "6,500",
     commits: "6,500",
     monthlyUsers: "650,000",
     monthlyUsers: "650,000",
   },
   },
-
-  // Stripe
-  stripe: {
-    publishableKey:
-      "pk_live_51OhXSKEclFNgdHcR9dDfYGwQeKuPfKo0IjA5kWBQIXKMFhE8QFd9bYLdPZC6klRKEgEkxJYSKuZg9U3FKHdLnF4300F9qLqMgP",
-  },
 } as const
 } as const

+ 0 - 30
packages/console/app/src/routes/api/black/setup-intent.ts

@@ -1,30 +0,0 @@
-import type { APIEvent } from "@solidjs/start/server"
-import { Billing } from "@opencode-ai/console-core/billing.js"
-
-export async function POST(event: APIEvent) {
-  try {
-    const body = (await event.request.json()) as { plan: string }
-    const plan = body.plan
-
-    if (!plan || !["20", "100", "200"].includes(plan)) {
-      return Response.json({ error: "Invalid plan" }, { status: 400 })
-    }
-
-    const amount = parseInt(plan) * 100
-
-    const intent = await Billing.stripe().setupIntents.create({
-      payment_method_types: ["card"],
-      metadata: {
-        plan,
-        amount: amount.toString(),
-      },
-    })
-
-    return Response.json({
-      clientSecret: intent.client_secret,
-    })
-  } catch (error) {
-    console.error("Error creating setup intent:", error)
-    return Response.json({ error: "Internal server error" }, { status: 500 })
-  }
-}

+ 2 - 1
packages/console/app/src/routes/auth/callback.ts → packages/console/app/src/routes/auth/[...callback].ts

@@ -5,6 +5,7 @@ import { useAuthSession } from "~/context/auth"
 
 
 export async function GET(input: APIEvent) {
 export async function GET(input: APIEvent) {
   const url = new URL(input.request.url)
   const url = new URL(input.request.url)
+
   try {
   try {
     const code = url.searchParams.get("code")
     const code = url.searchParams.get("code")
     if (!code) throw new Error("No code found")
     if (!code) throw new Error("No code found")
@@ -27,7 +28,7 @@ export async function GET(input: APIEvent) {
         current: id,
         current: id,
       }
       }
     })
     })
-    return redirect("/auth")
+    return redirect(url.pathname === "/auth/callback" ? "/auth" : url.pathname.replace("/auth/callback", ""))
   } catch (e: any) {
   } catch (e: any) {
     return new Response(
     return new Response(
       JSON.stringify({
       JSON.stringify({

+ 4 - 8
packages/console/app/src/routes/auth/authorize.ts

@@ -3,12 +3,8 @@ import { AuthClient } from "~/context/auth"
 
 
 export async function GET(input: APIEvent) {
 export async function GET(input: APIEvent) {
   const url = new URL(input.request.url)
   const url = new URL(input.request.url)
-  // TODO
-  // input.request.url http://localhost:3001/auth/authorize?continue=/black/subscribe
-  const result = await AuthClient.authorize(
-    new URL("/callback/subscribe?foo=bar", input.request.url).toString(),
-    "code",
-  )
-  // result.url https://auth.frank.dev.opencode.ai/authorize?client_id=app&redirect_uri=http%3A%2F%2Flocalhost%3A3001%2Fauth%2Fcallback&response_type=code&state=0d3fc834-bcbc-42dc-83ab-c25c2c43c7e3
-  return Response.redirect(result.url + "&continue=" + url.searchParams.get("continue"), 302)
+  const cont = url.searchParams.get("continue") ?? ""
+  const callbackUrl = new URL(`./callback${cont}`, input.request.url)
+  const result = await AuthClient.authorize(callbackUrl.toString(), "code")
+  return Response.redirect(result.url, 302)
 }
 }

+ 79 - 0
packages/console/app/src/routes/black.css

@@ -460,6 +460,39 @@
         font-weight: 400;
         font-weight: 400;
       }
       }
 
 
+      [data-slot="tax-id-section"] {
+        display: flex;
+        flex-direction: column;
+        gap: 8px;
+
+        [data-slot="label"] {
+          color: rgba(255, 255, 255, 0.59);
+          font-size: 14px;
+        }
+
+        [data-slot="input"] {
+          width: 100%;
+          height: 44px;
+          padding: 0 12px;
+          background: #1a1a1a;
+          border: 1px solid rgba(255, 255, 255, 0.17);
+          border-radius: 4px;
+          color: #ffffff;
+          font-family: var(--font-mono);
+          font-size: 14px;
+          outline: none;
+          transition: border-color 0.15s ease;
+
+          &::placeholder {
+            color: rgba(255, 255, 255, 0.39);
+          }
+
+          &:focus {
+            border-color: rgba(255, 255, 255, 0.35);
+          }
+        }
+      }
+
       [data-slot="checkout-form"] {
       [data-slot="checkout-form"] {
         display: flex;
         display: flex;
         flex-direction: column;
         flex-direction: column;
@@ -500,6 +533,52 @@
         text-align: center;
         text-align: center;
       }
       }
 
 
+      [data-slot="success"] {
+        display: flex;
+        flex-direction: column;
+        gap: 24px;
+
+        [data-slot="title"] {
+          color: rgba(255, 255, 255, 0.92);
+          font-size: 18px;
+          font-weight: 400;
+          margin: 0;
+        }
+
+        [data-slot="details"] {
+          display: flex;
+          flex-direction: column;
+          gap: 16px;
+
+          > div {
+            display: flex;
+            justify-content: space-between;
+            align-items: baseline;
+            gap: 16px;
+          }
+
+          dt {
+            color: rgba(255, 255, 255, 0.59);
+            font-size: 14px;
+            font-weight: 400;
+          }
+
+          dd {
+            color: rgba(255, 255, 255, 0.92);
+            font-size: 14px;
+            font-weight: 400;
+            margin: 0;
+            text-align: right;
+          }
+        }
+
+        [data-slot="charge-notice"] {
+          color: #d4a500;
+          font-size: 14px;
+          text-align: left;
+        }
+      }
+
       [data-slot="loading"] {
       [data-slot="loading"] {
         display: flex;
         display: flex;
         justify-content: center;
         justify-content: center;

+ 3 - 3
packages/console/app/src/routes/black/common.tsx

@@ -1,9 +1,9 @@
 import { Match, Switch } from "solid-js"
 import { Match, Switch } from "solid-js"
 
 
 export const plans = [
 export const plans = [
-  { id: "20", amount: 20, multiplier: null },
-  { id: "100", amount: 100, multiplier: "6x more usage than Black 20" },
-  { id: "200", amount: 200, multiplier: "21x more usage than Black 20" },
+  { id: "20", multiplier: null },
+  { id: "100", multiplier: "6x more usage than Black 20" },
+  { id: "200", multiplier: "21x more usage than Black 20" },
 ] as const
 ] as const
 
 
 export type Plan = (typeof plans)[number]
 export type Plan = (typeof plans)[number]

+ 1 - 1
packages/console/app/src/routes/black/index.tsx

@@ -62,7 +62,7 @@ export default function Black() {
                     <button type="button" onClick={() => setSelected(null)} data-slot="cancel">
                     <button type="button" onClick={() => setSelected(null)} data-slot="cancel">
                       Cancel
                       Cancel
                     </button>
                     </button>
-                    <a href={`/black/subscribe?plan=${plan().id}`} data-slot="continue">
+                    <a href={`/black/subscribe/${plan().id}`} data-slot="continue">
                       Continue
                       Continue
                     </a>
                     </a>
                   </div>
                   </div>

+ 0 - 244
packages/console/app/src/routes/black/subscribe.tsx

@@ -1,244 +0,0 @@
-import { A, createAsync, query, redirect, useSearchParams } from "@solidjs/router"
-import { Title } from "@solidjs/meta"
-import { createEffect, createSignal, For, onMount, Show } from "solid-js"
-import { loadStripe } from "@stripe/stripe-js"
-import { Elements, PaymentElement, useStripe, useElements } from "solid-stripe"
-import { config } from "~/config"
-import { PlanIcon, plans } from "./common"
-import { getActor } from "~/context/auth"
-import { withActor } from "~/context/auth.withActor"
-import { Actor } from "@opencode-ai/console-core/actor.js"
-import { and, Database, eq, isNull } from "@opencode-ai/console-core/drizzle/index.js"
-import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js"
-import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js"
-import { createList } from "solid-list"
-import { Modal } from "~/component/modal"
-
-const plansMap = Object.fromEntries(plans.map((p) => [p.id, p])) as Record<string, (typeof plans)[number]>
-
-const getWorkspaces = query(async () => {
-  "use server"
-  const actor = await getActor()
-  if (actor.type === "public") throw redirect("/auth/authorize?continue=/black/subscribe")
-  return withActor(async () => {
-    return Database.use((tx) =>
-      tx
-        .select({
-          id: WorkspaceTable.id,
-          name: WorkspaceTable.name,
-          slug: WorkspaceTable.slug,
-        })
-        .from(UserTable)
-        .innerJoin(WorkspaceTable, eq(UserTable.workspaceID, WorkspaceTable.id))
-        .where(
-          and(
-            eq(UserTable.accountID, Actor.account()),
-            isNull(WorkspaceTable.timeDeleted),
-            isNull(UserTable.timeDeleted),
-          ),
-        ),
-    )
-  })
-}, "black.subscribe.workspaces")
-
-function CheckoutForm(props: { plan: string; amount: number }) {
-  const stripe = useStripe()
-  const elements = useElements()
-  const [error, setError] = createSignal<string | null>(null)
-  const [loading, setLoading] = createSignal(false)
-
-  const handleSubmit = async (e: Event) => {
-    e.preventDefault()
-    if (!stripe() || !elements()) return
-
-    setLoading(true)
-    setError(null)
-
-    const result = await elements()!.submit()
-    if (result.error) {
-      setError(result.error.message ?? "An error occurred")
-      setLoading(false)
-      return
-    }
-
-    const { error: confirmError } = await stripe()!.confirmSetup({
-      elements: elements()!,
-      confirmParams: {
-        return_url: `${window.location.origin}/black/success?plan=${props.plan}`,
-      },
-    })
-
-    if (confirmError) {
-      setError(confirmError.message ?? "An error occurred")
-    }
-    setLoading(false)
-  }
-
-  return (
-    <form onSubmit={handleSubmit} data-slot="checkout-form">
-      <PaymentElement />
-      <Show when={error()}>
-        <p data-slot="error">{error()}</p>
-      </Show>
-      <button type="submit" disabled={loading() || !stripe() || !elements()} data-slot="submit-button">
-        {loading() ? "Processing..." : `Subscribe $${props.amount}`}
-      </button>
-      <p data-slot="charge-notice">You will only be charged when your subscription is activated</p>
-    </form>
-  )
-}
-
-export default function BlackSubscribe() {
-  const workspaces = createAsync(() => getWorkspaces())
-  const [selectedWorkspace, setSelectedWorkspace] = createSignal<string | null>(null)
-
-  const [params] = useSearchParams()
-  const plan = (params.plan as string) || "200"
-  const planData = plansMap[plan] || plansMap["200"]
-
-  const [clientSecret, setClientSecret] = createSignal<string | null>(null)
-  const [stripePromise] = createSignal(loadStripe(config.stripe.publishableKey))
-
-  // Auto-select if only one workspace
-  createEffect(() => {
-    const ws = workspaces()
-    if (ws?.length === 1 && !selectedWorkspace()) {
-      setSelectedWorkspace(ws[0].id)
-    }
-  })
-
-  // Keyboard navigation for workspace picker
-  const { active, setActive, onKeyDown } = createList({
-    items: () => workspaces()?.map((w) => w.id) ?? [],
-    initialActive: null,
-  })
-
-  const handleSelectWorkspace = (id: string) => {
-    setSelectedWorkspace(id)
-  }
-
-  onMount(async () => {
-    const response = await fetch("/api/black/setup-intent", {
-      method: "POST",
-      headers: { "Content-Type": "application/json" },
-      body: JSON.stringify({ plan }),
-    })
-    const data = await response.json()
-    if (data.clientSecret) {
-      setClientSecret(data.clientSecret)
-    }
-  })
-
-  let listRef: HTMLUListElement | undefined
-
-  // Show workspace picker if multiple workspaces and none selected
-  const showWorkspacePicker = () => {
-    const ws = workspaces()
-    return ws && ws.length > 1 && !selectedWorkspace()
-  }
-
-  return (
-    <>
-      <Title>Subscribe to OpenCode Black</Title>
-      <section data-slot="subscribe-form">
-        <div data-slot="form-card">
-          <div data-slot="plan-header">
-            <p data-slot="title">Subscribe to OpenCode Black</p>
-            <div data-slot="icon">
-              <PlanIcon plan={plan} />
-            </div>
-            <p data-slot="price">
-              <span data-slot="amount">${planData.amount}</span> <span data-slot="period">per month</span>
-              <Show when={planData.multiplier}>
-                <span data-slot="multiplier">{planData.multiplier}</span>
-              </Show>
-            </p>
-          </div>
-          <div data-slot="divider" />
-          <p data-slot="section-title">Add payment method</p>
-          <Show
-            when={clientSecret()}
-            fallback={
-              <div data-slot="loading">
-                <p>Loading payment form...</p>
-              </div>
-            }
-          >
-            <Elements
-              stripe={stripePromise()}
-              options={{
-                clientSecret: clientSecret()!,
-                appearance: {
-                  theme: "night",
-                  variables: {
-                    colorPrimary: "#ffffff",
-                    colorBackground: "#1a1a1a",
-                    colorText: "#ffffff",
-                    colorTextSecondary: "#999999",
-                    colorDanger: "#ff6b6b",
-                    fontFamily: "JetBrains Mono, monospace",
-                    borderRadius: "4px",
-                    spacingUnit: "4px",
-                  },
-                  rules: {
-                    ".Input": {
-                      backgroundColor: "#1a1a1a",
-                      border: "1px solid rgba(255, 255, 255, 0.17)",
-                      color: "#ffffff",
-                    },
-                    ".Input:focus": {
-                      borderColor: "rgba(255, 255, 255, 0.35)",
-                      boxShadow: "none",
-                    },
-                    ".Label": {
-                      color: "rgba(255, 255, 255, 0.59)",
-                      fontSize: "14px",
-                      marginBottom: "8px",
-                    },
-                  },
-                },
-              }}
-            >
-              <CheckoutForm plan={plan} amount={planData.amount} />
-            </Elements>
-          </Show>
-        </div>
-
-        {/* Workspace picker modal */}
-        <Modal open={showWorkspacePicker() ?? false} onClose={() => {}} title="Select a workspace for this plan">
-          <div data-slot="workspace-picker">
-            <ul
-              ref={listRef}
-              data-slot="workspace-list"
-              tabIndex={0}
-              onKeyDown={(e) => {
-                if (e.key === "Enter" && active()) {
-                  handleSelectWorkspace(active()!)
-                } else {
-                  onKeyDown(e)
-                }
-              }}
-            >
-              <For each={workspaces()}>
-                {(workspace) => (
-                  <li
-                    data-slot="workspace-item"
-                    data-active={active() === workspace.id}
-                    onMouseEnter={() => setActive(workspace.id)}
-                    onClick={() => handleSelectWorkspace(workspace.id)}
-                  >
-                    <span data-slot="selected-icon">[*]</span>
-                    <span>{workspace.name || workspace.slug}</span>
-                  </li>
-                )}
-              </For>
-            </ul>
-          </div>
-        </Modal>
-        <p data-slot="fine-print">
-          Prices shown don't include applicable tax · <A href="/legal/terms-of-service">Terms of Service</A>
-        </p>
-      </section>
-    </>
-  )
-}

+ 437 - 0
packages/console/app/src/routes/black/subscribe/[plan].tsx

@@ -0,0 +1,437 @@
+import { A, action, createAsync, query, redirect, useParams } from "@solidjs/router"
+import { Title } from "@solidjs/meta"
+import { createEffect, createSignal, For, Show } from "solid-js"
+import { type Stripe, type PaymentMethod, loadStripe } from "@stripe/stripe-js"
+import { Elements, PaymentElement, useStripe, useElements, AddressElement } from "solid-stripe"
+import { PlanIcon, plans } from "../common"
+import { getActor, useAuthSession } from "~/context/auth"
+import { withActor } from "~/context/auth.withActor"
+import { Actor } from "@opencode-ai/console-core/actor.js"
+import { and, Database, eq, isNull } from "@opencode-ai/console-core/drizzle/index.js"
+import { WorkspaceTable } from "@opencode-ai/console-core/schema/workspace.sql.js"
+import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js"
+import { createList } from "solid-list"
+import { Modal } from "~/component/modal"
+import { BillingTable } from "@opencode-ai/console-core/schema/billing.sql.js"
+import { Billing } from "@opencode-ai/console-core/billing.js"
+
+const plansMap = Object.fromEntries(plans.map((p) => [p.id, p])) as Record<string, (typeof plans)[number]>
+const stripePromise = loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY!)
+
+const getWorkspaces = query(async () => {
+  "use server"
+  const actor = await getActor()
+  if (actor.type === "public") throw redirect("/auth/authorize?continue=/black/subscribe")
+  return withActor(async () => {
+    return Database.use((tx) =>
+      tx
+        .select({
+          id: WorkspaceTable.id,
+          name: WorkspaceTable.name,
+          slug: WorkspaceTable.slug,
+          billing: {
+            customerID: BillingTable.customerID,
+            paymentMethodID: BillingTable.paymentMethodID,
+            paymentMethodType: BillingTable.paymentMethodType,
+            paymentMethodLast4: BillingTable.paymentMethodLast4,
+          },
+        })
+        .from(UserTable)
+        .innerJoin(WorkspaceTable, eq(UserTable.workspaceID, WorkspaceTable.id))
+        .innerJoin(BillingTable, eq(WorkspaceTable.id, BillingTable.workspaceID))
+        .where(
+          and(
+            eq(UserTable.accountID, Actor.account()),
+            isNull(WorkspaceTable.timeDeleted),
+            isNull(UserTable.timeDeleted),
+          ),
+        ),
+    )
+  })
+}, "black.subscribe.workspaces")
+
+const createSetupIntent = action(async (input: { plan: string; workspaceID: string }) => {
+  "use server"
+  const { plan, workspaceID } = input
+
+  if (!plan || !["20", "100", "200"].includes(plan)) {
+    return { error: "Invalid plan" }
+  }
+
+  if (!workspaceID) {
+    return { error: "Workspace ID is required" }
+  }
+
+  const actor = await getActor()
+  if (actor.type === "public") {
+    return { error: "Unauthorized" }
+  }
+
+  const session = await useAuthSession()
+  const account = session.data.account?.[session.data.current ?? ""]
+  const email = account?.email
+
+  const stripe = Billing.stripe()
+
+  let customerID = await Database.use((tx) =>
+    tx
+      .select({ customerID: BillingTable.customerID })
+      .from(BillingTable)
+      .where(eq(BillingTable.workspaceID, workspaceID))
+      .then((rows) => rows[0].customerID),
+  )
+  if (!customerID) {
+    const customer = await stripe.customers.create({
+      email,
+      metadata: {
+        workspaceID,
+      },
+    })
+    customerID = customer.id
+  }
+
+  const intent = await stripe.setupIntents.create({
+    customer: customerID,
+    payment_method_types: ["card"],
+    metadata: {
+      workspaceID,
+    },
+  })
+
+  return { clientSecret: intent.client_secret }
+})
+
+const bookSubscription = action(
+  async (input: {
+    workspaceID: string
+    paymentMethodID: string
+    paymentMethodType: string
+    paymentMethodLast4?: string
+  }) => {
+    "use server"
+    const actor = await getActor()
+    if (actor.type === "public") {
+      return { error: "Unauthorized" }
+    }
+
+    await Database.use((tx) =>
+      tx
+        .update(BillingTable)
+        .set({
+          paymentMethodID: input.paymentMethodID,
+          paymentMethodType: input.paymentMethodType,
+          paymentMethodLast4: input.paymentMethodLast4,
+          timeSubscriptionBooked: new Date(),
+        })
+        .where(eq(BillingTable.workspaceID, input.workspaceID)),
+    )
+
+    return { success: true }
+  },
+)
+
+interface SuccessData {
+  plan: string
+  paymentMethodType: string
+  paymentMethodLast4?: string
+}
+
+function PaymentSuccess(props: SuccessData) {
+  return (
+    <div data-slot="success">
+      <p data-slot="title">You're on the OpenCode Black waitlist</p>
+      <dl data-slot="details">
+        <div>
+          <dt>Subscription plan</dt>
+          <dd>OpenCode Black {props.plan}</dd>
+        </div>
+        <div>
+          <dt>Amount</dt>
+          <dd>${props.plan} per month</dd>
+        </div>
+        <div>
+          <dt>Payment method</dt>
+          <dd>
+            <Show when={props.paymentMethodLast4} fallback={<span>{props.paymentMethodType}</span>}>
+              <span>
+                {props.paymentMethodType} - {props.paymentMethodLast4}
+              </span>
+            </Show>
+          </dd>
+        </div>
+        <div>
+          <dt>Date joined</dt>
+          <dd>{new Date().toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}</dd>
+        </div>
+      </dl>
+      <p data-slot="charge-notice">Your card will be charged when your subscription is activated</p>
+    </div>
+  )
+}
+
+function PaymentForm(props: { plan: string; workspaceID: string; onSuccess: (data: SuccessData) => void }) {
+  const stripe = useStripe()
+  const elements = useElements()
+  const [error, setError] = createSignal<string | null>(null)
+  const [loading, setLoading] = createSignal(false)
+
+  const handleSubmit = async (e: Event) => {
+    e.preventDefault()
+    if (!stripe() || !elements()) return
+
+    setLoading(true)
+    setError(null)
+
+    const result = await elements()!.submit()
+    if (result.error) {
+      setError(result.error.message ?? "An error occurred")
+      setLoading(false)
+      return
+    }
+
+    const { error: confirmError, setupIntent } = await stripe()!.confirmSetup({
+      elements: elements()!,
+      confirmParams: {
+        expand: ["setup_intent.payment_method"],
+        payment_method_data: {
+          allow_redisplay: "always",
+        },
+      },
+      redirect: "if_required",
+    })
+
+    if (confirmError) {
+      setError(confirmError.message ?? "An error occurred")
+      setLoading(false)
+      return
+    }
+
+    if (setupIntent?.status === "succeeded") {
+      const pm = setupIntent.payment_method as PaymentMethod
+
+      await bookSubscription({
+        workspaceID: props.workspaceID,
+        paymentMethodID: pm.id,
+        paymentMethodType: pm.type,
+        paymentMethodLast4: pm.card?.last4,
+      })
+
+      props.onSuccess({
+        plan: props.plan,
+        paymentMethodType: pm.type,
+        paymentMethodLast4: pm.card?.last4,
+      })
+    }
+
+    setLoading(false)
+  }
+
+  return (
+    <form onSubmit={handleSubmit} data-slot="checkout-form">
+      <PaymentElement />
+      <AddressElement options={{ mode: "billing" }} />
+      <Show when={error()}>
+        <p data-slot="error">{error()}</p>
+      </Show>
+      <button type="submit" disabled={loading() || !stripe() || !elements()} data-slot="submit-button">
+        {loading() ? "Processing..." : `Subscribe $${props.plan}`}
+      </button>
+      <p data-slot="charge-notice">You will only be charged when your subscription is activated</p>
+    </form>
+  )
+}
+
+export default function BlackSubscribe() {
+  const workspaces = createAsync(() => getWorkspaces())
+  const [selectedWorkspace, setSelectedWorkspace] = createSignal<string | null>(null)
+  const [success, setSuccess] = createSignal<SuccessData | null>(null)
+
+  const params = useParams()
+  const plan = params.plan || "200"
+  const planData = plansMap[plan] || plansMap["200"]
+
+  const [clientSecret, setClientSecret] = createSignal<string | null>(null)
+  const [setupError, setSetupError] = createSignal<string | null>(null)
+  const [stripe, setStripe] = createSignal<Stripe | null>(null)
+
+  // Resolve stripe promise once
+  createEffect(() => {
+    stripePromise.then((s) => {
+      if (s) setStripe(s)
+    })
+  })
+
+  // Auto-select if only one workspace
+  createEffect(() => {
+    const ws = workspaces()
+    if (ws?.length === 1 && !selectedWorkspace()) {
+      setSelectedWorkspace(ws[0].id)
+    }
+  })
+
+  // Fetch setup intent when workspace is selected (unless workspace already has payment method)
+  createEffect(() => {
+    const id = selectedWorkspace()
+    if (!id) return
+
+    const ws = workspaces()?.find((w) => w.id === id)
+    if (ws?.billing.paymentMethodID) {
+      setSuccess({
+        plan,
+        paymentMethodType: ws.billing.paymentMethodType!,
+        paymentMethodLast4: ws.billing.paymentMethodLast4 ?? undefined,
+      })
+      return
+    }
+
+    setClientSecret(null)
+    setSetupError(null)
+
+    createSetupIntent({ plan, workspaceID: id })
+      .then((data) => {
+        if (data.clientSecret) {
+          setClientSecret(data.clientSecret)
+        } else if (data.error) {
+          setSetupError(data.error)
+        }
+      })
+      .catch(() => setSetupError("Failed to initialize payment"))
+  })
+
+  // Keyboard navigation for workspace picker
+  const { active, setActive, onKeyDown } = createList({
+    items: () => workspaces()?.map((w) => w.id) ?? [],
+    initialActive: null,
+  })
+
+  const handleSelectWorkspace = (id: string) => {
+    setSelectedWorkspace(id)
+  }
+
+  let listRef: HTMLUListElement | undefined
+
+  // Show workspace picker if multiple workspaces and none selected
+  const showWorkspacePicker = () => {
+    const ws = workspaces()
+    return ws && ws.length > 1 && !selectedWorkspace()
+  }
+
+  return (
+    <>
+      <Title>Subscribe to OpenCode Black</Title>
+      <section data-slot="subscribe-form">
+        <div data-slot="form-card">
+          <Show
+            when={success()}
+            fallback={
+              <>
+                <div data-slot="plan-header">
+                  <p data-slot="title">Subscribe to OpenCode Black</p>
+                  <div data-slot="icon">
+                    <PlanIcon plan={plan} />
+                  </div>
+                  <p data-slot="price">
+                    <span data-slot="amount">${planData.id}</span> <span data-slot="period">per month</span>
+                    <Show when={planData.multiplier}>
+                      <span data-slot="multiplier">{planData.multiplier}</span>
+                    </Show>
+                  </p>
+                </div>
+                <div data-slot="divider" />
+                <p data-slot="section-title">Payment method</p>
+
+                <Show when={setupError()}>
+                  <p data-slot="error">{setupError()}</p>
+                </Show>
+
+                <Show
+                  when={clientSecret() && selectedWorkspace() && stripe()}
+                  fallback={
+                    <div data-slot="loading">
+                      <p>{selectedWorkspace() ? "Loading payment form..." : "Select a workspace to continue"}</p>
+                    </div>
+                  }
+                >
+                  <Elements
+                    stripe={stripe()!}
+                    options={{
+                      clientSecret: clientSecret()!,
+                      appearance: {
+                        theme: "night",
+                        variables: {
+                          colorPrimary: "#ffffff",
+                          colorBackground: "#1a1a1a",
+                          colorText: "#ffffff",
+                          colorTextSecondary: "#999999",
+                          colorDanger: "#ff6b6b",
+                          fontFamily: "JetBrains Mono, monospace",
+                          borderRadius: "4px",
+                          spacingUnit: "4px",
+                        },
+                        rules: {
+                          ".Input": {
+                            backgroundColor: "#1a1a1a",
+                            border: "1px solid rgba(255, 255, 255, 0.17)",
+                            color: "#ffffff",
+                          },
+                          ".Input:focus": {
+                            borderColor: "rgba(255, 255, 255, 0.35)",
+                            boxShadow: "none",
+                          },
+                          ".Label": {
+                            color: "rgba(255, 255, 255, 0.59)",
+                            fontSize: "14px",
+                            marginBottom: "8px",
+                          },
+                        },
+                      },
+                    }}
+                  >
+                    <PaymentForm plan={plan} workspaceID={selectedWorkspace()!} onSuccess={setSuccess} />
+                  </Elements>
+                </Show>
+              </>
+            }
+          >
+            {(data) => <PaymentSuccess {...data()} />}
+          </Show>
+        </div>
+
+        {/* Workspace picker modal */}
+        <Modal open={showWorkspacePicker() ?? false} onClose={() => {}} title="Select a workspace for this plan">
+          <div data-slot="workspace-picker">
+            <ul
+              ref={listRef}
+              data-slot="workspace-list"
+              tabIndex={0}
+              onKeyDown={(e) => {
+                if (e.key === "Enter" && active()) {
+                  handleSelectWorkspace(active()!)
+                } else {
+                  onKeyDown(e)
+                }
+              }}
+            >
+              <For each={workspaces()}>
+                {(workspace) => (
+                  <li
+                    data-slot="workspace-item"
+                    data-active={active() === workspace.id}
+                    onMouseEnter={() => setActive(workspace.id)}
+                    onClick={() => handleSelectWorkspace(workspace.id)}
+                  >
+                    <span data-slot="selected-icon">[*]</span>
+                    <span>{workspace.name || workspace.slug}</span>
+                  </li>
+                )}
+              </For>
+            </ul>
+          </div>
+        </Modal>
+        <p data-slot="fine-print">
+          Prices shown don't include applicable tax · <A href="/legal/terms-of-service">Terms of Service</A>
+        </p>
+      </section>
+    </>
+  )
+}

+ 1 - 0
packages/console/core/migrations/0051_jazzy_green_goblin.sql

@@ -0,0 +1 @@
+ALTER TABLE `billing` ADD `time_subscription_booked` timestamp(3);

+ 1 - 0
packages/console/core/migrations/0052_aromatic_agent_zero.sql

@@ -0,0 +1 @@
+ALTER TABLE `billing` ADD `subscription_plan` enum('20','100','200');

+ 1302 - 0
packages/console/core/migrations/meta/0051_snapshot.json

@@ -0,0 +1,1302 @@
+{
+  "version": "5",
+  "dialect": "mysql",
+  "id": "14cbf4c8-55f1-4488-956f-56fb5ccb3a5a",
+  "prevId": "a0d18802-c390-47d4-98f1-d1f83869cf0c",
+  "tables": {
+    "account": {
+      "name": "account",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "account_id_pk": {
+          "name": "account_id_pk",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "auth": {
+      "name": "auth",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "provider": {
+          "name": "provider",
+          "type": "enum('email','github','google')",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "subject": {
+          "name": "subject",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "account_id": {
+          "name": "account_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "provider": {
+          "name": "provider",
+          "columns": [
+            "provider",
+            "subject"
+          ],
+          "isUnique": true
+        },
+        "account_id": {
+          "name": "account_id",
+          "columns": [
+            "account_id"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "auth_id_pk": {
+          "name": "auth_id_pk",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "benchmark": {
+      "name": "benchmark",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "model": {
+          "name": "model",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "agent": {
+          "name": "agent",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "result": {
+          "name": "result",
+          "type": "mediumtext",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "time_created": {
+          "name": "time_created",
+          "columns": [
+            "time_created"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "benchmark_id_pk": {
+          "name": "benchmark_id_pk",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "billing": {
+      "name": "billing",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "customer_id": {
+          "name": "customer_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "payment_method_id": {
+          "name": "payment_method_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "payment_method_type": {
+          "name": "payment_method_type",
+          "type": "varchar(32)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "payment_method_last4": {
+          "name": "payment_method_last4",
+          "type": "varchar(4)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "balance": {
+          "name": "balance",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "monthly_limit": {
+          "name": "monthly_limit",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "monthly_usage": {
+          "name": "monthly_usage",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_monthly_usage_updated": {
+          "name": "time_monthly_usage_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "reload": {
+          "name": "reload",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "reload_trigger": {
+          "name": "reload_trigger",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "reload_amount": {
+          "name": "reload_amount",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "reload_error": {
+          "name": "reload_error",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_reload_error": {
+          "name": "time_reload_error",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_reload_locked_till": {
+          "name": "time_reload_locked_till",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "subscription_id": {
+          "name": "subscription_id",
+          "type": "varchar(28)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "subscription_coupon_id": {
+          "name": "subscription_coupon_id",
+          "type": "varchar(28)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_subscription_booked": {
+          "name": "time_subscription_booked",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "global_customer_id": {
+          "name": "global_customer_id",
+          "columns": [
+            "customer_id"
+          ],
+          "isUnique": true
+        },
+        "global_subscription_id": {
+          "name": "global_subscription_id",
+          "columns": [
+            "subscription_id"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "billing_workspace_id_id_pk": {
+          "name": "billing_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "payment": {
+      "name": "payment",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "customer_id": {
+          "name": "customer_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "invoice_id": {
+          "name": "invoice_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "payment_id": {
+          "name": "payment_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "amount": {
+          "name": "amount",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_refunded": {
+          "name": "time_refunded",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "enrichment": {
+          "name": "enrichment",
+          "type": "json",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "payment_workspace_id_id_pk": {
+          "name": "payment_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "subscription": {
+      "name": "subscription",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "user_id": {
+          "name": "user_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "rolling_usage": {
+          "name": "rolling_usage",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "fixed_usage": {
+          "name": "fixed_usage",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_rolling_updated": {
+          "name": "time_rolling_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_fixed_updated": {
+          "name": "time_fixed_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "workspace_user_id": {
+          "name": "workspace_user_id",
+          "columns": [
+            "workspace_id",
+            "user_id"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "subscription_workspace_id_id_pk": {
+          "name": "subscription_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "usage": {
+      "name": "usage",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "model": {
+          "name": "model",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "provider": {
+          "name": "provider",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "input_tokens": {
+          "name": "input_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "output_tokens": {
+          "name": "output_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "reasoning_tokens": {
+          "name": "reasoning_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "cache_read_tokens": {
+          "name": "cache_read_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "cache_write_5m_tokens": {
+          "name": "cache_write_5m_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "cache_write_1h_tokens": {
+          "name": "cache_write_1h_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "cost": {
+          "name": "cost",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "key_id": {
+          "name": "key_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "enrichment": {
+          "name": "enrichment",
+          "type": "json",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "usage_time_created": {
+          "name": "usage_time_created",
+          "columns": [
+            "workspace_id",
+            "time_created"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "usage_workspace_id_id_pk": {
+          "name": "usage_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "ip_rate_limit": {
+      "name": "ip_rate_limit",
+      "columns": {
+        "ip": {
+          "name": "ip",
+          "type": "varchar(45)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "interval": {
+          "name": "interval",
+          "type": "varchar(10)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "count": {
+          "name": "count",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "ip_rate_limit_ip_interval_pk": {
+          "name": "ip_rate_limit_ip_interval_pk",
+          "columns": [
+            "ip",
+            "interval"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "ip": {
+      "name": "ip",
+      "columns": {
+        "ip": {
+          "name": "ip",
+          "type": "varchar(45)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "usage": {
+          "name": "usage",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "ip_ip_pk": {
+          "name": "ip_ip_pk",
+          "columns": [
+            "ip"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "key": {
+      "name": "key",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "key": {
+          "name": "key",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "user_id": {
+          "name": "user_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_used": {
+          "name": "time_used",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "global_key": {
+          "name": "global_key",
+          "columns": [
+            "key"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "key_workspace_id_id_pk": {
+          "name": "key_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "model": {
+      "name": "model",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "model": {
+          "name": "model",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "model_workspace_model": {
+          "name": "model_workspace_model",
+          "columns": [
+            "workspace_id",
+            "model"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "model_workspace_id_id_pk": {
+          "name": "model_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "provider": {
+      "name": "provider",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "provider": {
+          "name": "provider",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "credentials": {
+          "name": "credentials",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "workspace_provider": {
+          "name": "workspace_provider",
+          "columns": [
+            "workspace_id",
+            "provider"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "provider_workspace_id_id_pk": {
+          "name": "provider_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "user": {
+      "name": "user",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "account_id": {
+          "name": "account_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "email": {
+          "name": "email",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_seen": {
+          "name": "time_seen",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "color": {
+          "name": "color",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "role": {
+          "name": "role",
+          "type": "enum('admin','member')",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "monthly_limit": {
+          "name": "monthly_limit",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "monthly_usage": {
+          "name": "monthly_usage",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_monthly_usage_updated": {
+          "name": "time_monthly_usage_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "user_account_id": {
+          "name": "user_account_id",
+          "columns": [
+            "workspace_id",
+            "account_id"
+          ],
+          "isUnique": true
+        },
+        "user_email": {
+          "name": "user_email",
+          "columns": [
+            "workspace_id",
+            "email"
+          ],
+          "isUnique": true
+        },
+        "global_account_id": {
+          "name": "global_account_id",
+          "columns": [
+            "account_id"
+          ],
+          "isUnique": false
+        },
+        "global_email": {
+          "name": "global_email",
+          "columns": [
+            "email"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "user_workspace_id_id_pk": {
+          "name": "user_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "workspace": {
+      "name": "workspace",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "slug": {
+          "name": "slug",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "slug": {
+          "name": "slug",
+          "columns": [
+            "slug"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "workspace_id": {
+          "name": "workspace_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    }
+  },
+  "views": {},
+  "_meta": {
+    "schemas": {},
+    "tables": {},
+    "columns": {}
+  },
+  "internal": {
+    "tables": {},
+    "indexes": {}
+  }
+}

+ 1309 - 0
packages/console/core/migrations/meta/0052_snapshot.json

@@ -0,0 +1,1309 @@
+{
+  "version": "5",
+  "dialect": "mysql",
+  "id": "00774acd-a1e5-49c0-b296-cacc9506a566",
+  "prevId": "14cbf4c8-55f1-4488-956f-56fb5ccb3a5a",
+  "tables": {
+    "account": {
+      "name": "account",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "account_id_pk": {
+          "name": "account_id_pk",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "auth": {
+      "name": "auth",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "provider": {
+          "name": "provider",
+          "type": "enum('email','github','google')",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "subject": {
+          "name": "subject",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "account_id": {
+          "name": "account_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "provider": {
+          "name": "provider",
+          "columns": [
+            "provider",
+            "subject"
+          ],
+          "isUnique": true
+        },
+        "account_id": {
+          "name": "account_id",
+          "columns": [
+            "account_id"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "auth_id_pk": {
+          "name": "auth_id_pk",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "benchmark": {
+      "name": "benchmark",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "model": {
+          "name": "model",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "agent": {
+          "name": "agent",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "result": {
+          "name": "result",
+          "type": "mediumtext",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "time_created": {
+          "name": "time_created",
+          "columns": [
+            "time_created"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "benchmark_id_pk": {
+          "name": "benchmark_id_pk",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "billing": {
+      "name": "billing",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "customer_id": {
+          "name": "customer_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "payment_method_id": {
+          "name": "payment_method_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "payment_method_type": {
+          "name": "payment_method_type",
+          "type": "varchar(32)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "payment_method_last4": {
+          "name": "payment_method_last4",
+          "type": "varchar(4)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "balance": {
+          "name": "balance",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "monthly_limit": {
+          "name": "monthly_limit",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "monthly_usage": {
+          "name": "monthly_usage",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_monthly_usage_updated": {
+          "name": "time_monthly_usage_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "reload": {
+          "name": "reload",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "reload_trigger": {
+          "name": "reload_trigger",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "reload_amount": {
+          "name": "reload_amount",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "reload_error": {
+          "name": "reload_error",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_reload_error": {
+          "name": "time_reload_error",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_reload_locked_till": {
+          "name": "time_reload_locked_till",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "subscription_id": {
+          "name": "subscription_id",
+          "type": "varchar(28)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "subscription_coupon_id": {
+          "name": "subscription_coupon_id",
+          "type": "varchar(28)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "subscription_plan": {
+          "name": "subscription_plan",
+          "type": "enum('20','100','200')",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_subscription_booked": {
+          "name": "time_subscription_booked",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "global_customer_id": {
+          "name": "global_customer_id",
+          "columns": [
+            "customer_id"
+          ],
+          "isUnique": true
+        },
+        "global_subscription_id": {
+          "name": "global_subscription_id",
+          "columns": [
+            "subscription_id"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "billing_workspace_id_id_pk": {
+          "name": "billing_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "payment": {
+      "name": "payment",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "customer_id": {
+          "name": "customer_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "invoice_id": {
+          "name": "invoice_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "payment_id": {
+          "name": "payment_id",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "amount": {
+          "name": "amount",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_refunded": {
+          "name": "time_refunded",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "enrichment": {
+          "name": "enrichment",
+          "type": "json",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "payment_workspace_id_id_pk": {
+          "name": "payment_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "subscription": {
+      "name": "subscription",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "user_id": {
+          "name": "user_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "rolling_usage": {
+          "name": "rolling_usage",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "fixed_usage": {
+          "name": "fixed_usage",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_rolling_updated": {
+          "name": "time_rolling_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_fixed_updated": {
+          "name": "time_fixed_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "workspace_user_id": {
+          "name": "workspace_user_id",
+          "columns": [
+            "workspace_id",
+            "user_id"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "subscription_workspace_id_id_pk": {
+          "name": "subscription_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "usage": {
+      "name": "usage",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "model": {
+          "name": "model",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "provider": {
+          "name": "provider",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "input_tokens": {
+          "name": "input_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "output_tokens": {
+          "name": "output_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "reasoning_tokens": {
+          "name": "reasoning_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "cache_read_tokens": {
+          "name": "cache_read_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "cache_write_5m_tokens": {
+          "name": "cache_write_5m_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "cache_write_1h_tokens": {
+          "name": "cache_write_1h_tokens",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "cost": {
+          "name": "cost",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "key_id": {
+          "name": "key_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "enrichment": {
+          "name": "enrichment",
+          "type": "json",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "usage_time_created": {
+          "name": "usage_time_created",
+          "columns": [
+            "workspace_id",
+            "time_created"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "usage_workspace_id_id_pk": {
+          "name": "usage_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "ip_rate_limit": {
+      "name": "ip_rate_limit",
+      "columns": {
+        "ip": {
+          "name": "ip",
+          "type": "varchar(45)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "interval": {
+          "name": "interval",
+          "type": "varchar(10)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "count": {
+          "name": "count",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "ip_rate_limit_ip_interval_pk": {
+          "name": "ip_rate_limit_ip_interval_pk",
+          "columns": [
+            "ip",
+            "interval"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "ip": {
+      "name": "ip",
+      "columns": {
+        "ip": {
+          "name": "ip",
+          "type": "varchar(45)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "usage": {
+          "name": "usage",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "ip_ip_pk": {
+          "name": "ip_ip_pk",
+          "columns": [
+            "ip"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "key": {
+      "name": "key",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "key": {
+          "name": "key",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "user_id": {
+          "name": "user_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_used": {
+          "name": "time_used",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "global_key": {
+          "name": "global_key",
+          "columns": [
+            "key"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "key_workspace_id_id_pk": {
+          "name": "key_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "model": {
+      "name": "model",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "model": {
+          "name": "model",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "model_workspace_model": {
+          "name": "model_workspace_model",
+          "columns": [
+            "workspace_id",
+            "model"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "model_workspace_id_id_pk": {
+          "name": "model_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "provider": {
+      "name": "provider",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "provider": {
+          "name": "provider",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "credentials": {
+          "name": "credentials",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "workspace_provider": {
+          "name": "workspace_provider",
+          "columns": [
+            "workspace_id",
+            "provider"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "provider_workspace_id_id_pk": {
+          "name": "provider_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "user": {
+      "name": "user",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "workspace_id": {
+          "name": "workspace_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "account_id": {
+          "name": "account_id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "email": {
+          "name": "email",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_seen": {
+          "name": "time_seen",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "color": {
+          "name": "color",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "role": {
+          "name": "role",
+          "type": "enum('admin','member')",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "monthly_limit": {
+          "name": "monthly_limit",
+          "type": "int",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "monthly_usage": {
+          "name": "monthly_usage",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "time_monthly_usage_updated": {
+          "name": "time_monthly_usage_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "user_account_id": {
+          "name": "user_account_id",
+          "columns": [
+            "workspace_id",
+            "account_id"
+          ],
+          "isUnique": true
+        },
+        "user_email": {
+          "name": "user_email",
+          "columns": [
+            "workspace_id",
+            "email"
+          ],
+          "isUnique": true
+        },
+        "global_account_id": {
+          "name": "global_account_id",
+          "columns": [
+            "account_id"
+          ],
+          "isUnique": false
+        },
+        "global_email": {
+          "name": "global_email",
+          "columns": [
+            "email"
+          ],
+          "isUnique": false
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "user_workspace_id_id_pk": {
+          "name": "user_workspace_id_id_pk",
+          "columns": [
+            "workspace_id",
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    },
+    "workspace": {
+      "name": "workspace",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "slug": {
+          "name": "slug",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "time_created": {
+          "name": "time_created",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "(now())"
+        },
+        "time_updated": {
+          "name": "time_updated",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false,
+          "default": "CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)"
+        },
+        "time_deleted": {
+          "name": "time_deleted",
+          "type": "timestamp(3)",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "slug": {
+          "name": "slug",
+          "columns": [
+            "slug"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {
+        "workspace_id": {
+          "name": "workspace_id",
+          "columns": [
+            "id"
+          ]
+        }
+      },
+      "uniqueConstraints": {},
+      "checkConstraint": {}
+    }
+  },
+  "views": {},
+  "_meta": {
+    "schemas": {},
+    "tables": {},
+    "columns": {}
+  },
+  "internal": {
+    "tables": {},
+    "indexes": {}
+  }
+}

+ 15 - 1
packages/console/core/migrations/meta/_journal.json

@@ -358,6 +358,20 @@
       "when": 1767931290031,
       "when": 1767931290031,
       "tag": "0050_bumpy_mephistopheles",
       "tag": "0050_bumpy_mephistopheles",
       "breakpoints": true
       "breakpoints": true
+    },
+    {
+      "idx": 51,
+      "version": "5",
+      "when": 1768341152722,
+      "tag": "0051_jazzy_green_goblin",
+      "breakpoints": true
+    },
+    {
+      "idx": 52,
+      "version": "5",
+      "when": 1768343920467,
+      "tag": "0052_aromatic_agent_zero",
+      "breakpoints": true
     }
     }
   ]
   ]
-}
+}

+ 3 - 1
packages/console/core/src/schema/billing.sql.ts

@@ -1,4 +1,4 @@
-import { bigint, boolean, index, int, json, mysqlTable, uniqueIndex, varchar } from "drizzle-orm/mysql-core"
+import { bigint, boolean, index, int, json, mysqlEnum, mysqlTable, uniqueIndex, varchar } from "drizzle-orm/mysql-core"
 import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types"
 import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types"
 import { workspaceIndexes } from "./workspace.sql"
 import { workspaceIndexes } from "./workspace.sql"
 
 
@@ -23,6 +23,8 @@ export const BillingTable = mysqlTable(
     timeReloadLockedTill: utc("time_reload_locked_till"),
     timeReloadLockedTill: utc("time_reload_locked_till"),
     subscriptionID: varchar("subscription_id", { length: 28 }),
     subscriptionID: varchar("subscription_id", { length: 28 }),
     subscriptionCouponID: varchar("subscription_coupon_id", { length: 28 }),
     subscriptionCouponID: varchar("subscription_coupon_id", { length: 28 }),
+    subscriptionPlan: mysqlEnum("subscription_plan", ["20", "100", "200"] as const),
+    timeSubscriptionBooked: utc("time_subscription_booked"),
   },
   },
   (table) => [
   (table) => [
     ...workspaceIndexes(table),
     ...workspaceIndexes(table),

+ 4 - 0
packages/console/core/sst-env.d.ts

@@ -78,6 +78,10 @@ declare module "sst" {
       "type": "sst.sst.Secret"
       "type": "sst.sst.Secret"
       "value": string
       "value": string
     }
     }
+    "STRIPE_PUBLISHABLE_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "STRIPE_SECRET_KEY": {
     "STRIPE_SECRET_KEY": {
       "type": "sst.sst.Secret"
       "type": "sst.sst.Secret"
       "value": string
       "value": string

+ 4 - 0
packages/console/function/sst-env.d.ts

@@ -78,6 +78,10 @@ declare module "sst" {
       "type": "sst.sst.Secret"
       "type": "sst.sst.Secret"
       "value": string
       "value": string
     }
     }
+    "STRIPE_PUBLISHABLE_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "STRIPE_SECRET_KEY": {
     "STRIPE_SECRET_KEY": {
       "type": "sst.sst.Secret"
       "type": "sst.sst.Secret"
       "value": string
       "value": string

+ 4 - 0
packages/console/resource/sst-env.d.ts

@@ -78,6 +78,10 @@ declare module "sst" {
       "type": "sst.sst.Secret"
       "type": "sst.sst.Secret"
       "value": string
       "value": string
     }
     }
+    "STRIPE_PUBLISHABLE_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "STRIPE_SECRET_KEY": {
     "STRIPE_SECRET_KEY": {
       "type": "sst.sst.Secret"
       "type": "sst.sst.Secret"
       "value": string
       "value": string

+ 4 - 0
packages/enterprise/sst-env.d.ts

@@ -78,6 +78,10 @@ declare module "sst" {
       "type": "sst.sst.Secret"
       "type": "sst.sst.Secret"
       "value": string
       "value": string
     }
     }
+    "STRIPE_PUBLISHABLE_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "STRIPE_SECRET_KEY": {
     "STRIPE_SECRET_KEY": {
       "type": "sst.sst.Secret"
       "type": "sst.sst.Secret"
       "value": string
       "value": string

+ 4 - 0
packages/function/sst-env.d.ts

@@ -78,6 +78,10 @@ declare module "sst" {
       "type": "sst.sst.Secret"
       "type": "sst.sst.Secret"
       "value": string
       "value": string
     }
     }
+    "STRIPE_PUBLISHABLE_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "STRIPE_SECRET_KEY": {
     "STRIPE_SECRET_KEY": {
       "type": "sst.sst.Secret"
       "type": "sst.sst.Secret"
       "value": string
       "value": string

+ 4 - 0
sst-env.d.ts

@@ -104,6 +104,10 @@ declare module "sst" {
       "type": "sst.sst.Secret"
       "type": "sst.sst.Secret"
       "value": string
       "value": string
     }
     }
+    "STRIPE_PUBLISHABLE_KEY": {
+      "type": "sst.sst.Secret"
+      "value": string
+    }
     "STRIPE_SECRET_KEY": {
     "STRIPE_SECRET_KEY": {
       "type": "sst.sst.Secret"
       "type": "sst.sst.Secret"
       "value": string
       "value": string