summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorFrank <[email protected]>2026-01-13 17:51:20 -0500
committerFrank <[email protected]>2026-01-13 17:51:21 -0500
commiteaf18d991576771ccbc3975a6c7a9358b0da8de9 (patch)
tree1a5b3e395714502638fbffd55ac7e6b4fe9f0f1b
parentf3d4dd5099003070800cc9ec161877634fdd7c0a (diff)
downloadopencode-eaf18d991576771ccbc3975a6c7a9358b0da8de9.tar.gz
opencode-eaf18d991576771ccbc3975a6c7a9358b0da8de9.zip
wip: black
-rw-r--r--infra/console.ts2
-rw-r--r--packages/console/app/package.json2
-rw-r--r--packages/console/app/src/config.ts6
-rw-r--r--packages/console/app/src/routes/api/black/setup-intent.ts30
-rw-r--r--packages/console/app/src/routes/auth/[...callback].ts (renamed from packages/console/app/src/routes/auth/callback.ts)3
-rw-r--r--packages/console/app/src/routes/auth/authorize.ts12
-rw-r--r--packages/console/app/src/routes/black.css79
-rw-r--r--packages/console/app/src/routes/black/common.tsx6
-rw-r--r--packages/console/app/src/routes/black/index.tsx2
-rw-r--r--packages/console/app/src/routes/black/subscribe.tsx244
-rw-r--r--packages/console/app/src/routes/black/subscribe/[plan].tsx437
-rw-r--r--packages/console/core/migrations/0051_jazzy_green_goblin.sql1
-rw-r--r--packages/console/core/migrations/0052_aromatic_agent_zero.sql1
-rw-r--r--packages/console/core/migrations/meta/0051_snapshot.json1302
-rw-r--r--packages/console/core/migrations/meta/0052_snapshot.json1309
-rw-r--r--packages/console/core/migrations/meta/_journal.json16
-rw-r--r--packages/console/core/src/schema/billing.sql.ts4
-rw-r--r--packages/console/core/sst-env.d.ts4
-rw-r--r--packages/console/function/sst-env.d.ts4
-rw-r--r--packages/console/resource/sst-env.d.ts4
-rw-r--r--packages/enterprise/sst-env.d.ts4
-rw-r--r--packages/function/sst-env.d.ts4
-rw-r--r--sst-env.d.ts4
23 files changed, 3184 insertions, 296 deletions
diff --git a/infra/console.ts b/infra/console.ts
index 1368ef202..17e4deab6 100644
--- a/infra/console.ts
+++ b/infra/console.ts
@@ -122,6 +122,7 @@ const ZEN_MODELS = [
]
const ZEN_BLACK = new sst.Secret("ZEN_BLACK")
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", {
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_API_URL: gateway.url.apply((url) => url!),
VITE_AUTH_URL: auth.url.apply((url) => url!),
+ VITE_STRIPE_PUBLISHABLE_KEY: STRIPE_PUBLISHABLE_KEY.value,
},
transform: {
server: {
diff --git a/packages/console/app/package.json b/packages/console/app/package.json
index 23171daac..b70fedead 100644
--- a/packages/console/app/package.json
+++ b/packages/console/app/package.json
@@ -6,7 +6,7 @@
"scripts": {
"typecheck": "tsgo --noEmit",
"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",
"start": "vite start"
},
diff --git a/packages/console/app/src/config.ts b/packages/console/app/src/config.ts
index 4396e5117..4ebb2c71a 100644
--- a/packages/console/app/src/config.ts
+++ b/packages/console/app/src/config.ts
@@ -26,10 +26,4 @@ export const config = {
commits: "6,500",
monthlyUsers: "650,000",
},
-
- // Stripe
- stripe: {
- publishableKey:
- "pk_live_51OhXSKEclFNgdHcR9dDfYGwQeKuPfKo0IjA5kWBQIXKMFhE8QFd9bYLdPZC6klRKEgEkxJYSKuZg9U3FKHdLnF4300F9qLqMgP",
- },
} as const
diff --git a/packages/console/app/src/routes/api/black/setup-intent.ts b/packages/console/app/src/routes/api/black/setup-intent.ts
deleted file mode 100644
index eb5571616..000000000
--- a/packages/console/app/src/routes/api/black/setup-intent.ts
+++ /dev/null
@@ -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 })
- }
-}
diff --git a/packages/console/app/src/routes/auth/callback.ts b/packages/console/app/src/routes/auth/[...callback].ts
index 9b7296791..36a9c5194 100644
--- a/packages/console/app/src/routes/auth/callback.ts
+++ b/packages/console/app/src/routes/auth/[...callback].ts
@@ -5,6 +5,7 @@ import { useAuthSession } from "~/context/auth"
export async function GET(input: APIEvent) {
const url = new URL(input.request.url)
+
try {
const code = url.searchParams.get("code")
if (!code) throw new Error("No code found")
@@ -27,7 +28,7 @@ export async function GET(input: APIEvent) {
current: id,
}
})
- return redirect("/auth")
+ return redirect(url.pathname === "/auth/callback" ? "/auth" : url.pathname.replace("/auth/callback", ""))
} catch (e: any) {
return new Response(
JSON.stringify({
diff --git a/packages/console/app/src/routes/auth/authorize.ts b/packages/console/app/src/routes/auth/authorize.ts
index 6be94b146..0f0651ae3 100644
--- a/packages/console/app/src/routes/auth/authorize.ts
+++ b/packages/console/app/src/routes/auth/authorize.ts
@@ -3,12 +3,8 @@ import { AuthClient } from "~/context/auth"
export async function GET(input: APIEvent) {
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)
}
diff --git a/packages/console/app/src/routes/black.css b/packages/console/app/src/routes/black.css
index dfb188ed0..72bf7a657 100644
--- a/packages/console/app/src/routes/black.css
+++ b/packages/console/app/src/routes/black.css
@@ -460,6 +460,39 @@
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"] {
display: flex;
flex-direction: column;
@@ -500,6 +533,52 @@
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"] {
display: flex;
justify-content: center;
diff --git a/packages/console/app/src/routes/black/common.tsx b/packages/console/app/src/routes/black/common.tsx
index c1184bd20..dd643bbc5 100644
--- a/packages/console/app/src/routes/black/common.tsx
+++ b/packages/console/app/src/routes/black/common.tsx
@@ -1,9 +1,9 @@
import { Match, Switch } from "solid-js"
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
export type Plan = (typeof plans)[number]
diff --git a/packages/console/app/src/routes/black/index.tsx b/packages/console/app/src/routes/black/index.tsx
index 2b452c812..57d27a793 100644
--- a/packages/console/app/src/routes/black/index.tsx
+++ b/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">
Cancel
</button>
- <a href={`/black/subscribe?plan=${plan().id}`} data-slot="continue">
+ <a href={`/black/subscribe/${plan().id}`} data-slot="continue">
Continue
</a>
</div>
diff --git a/packages/console/app/src/routes/black/subscribe.tsx b/packages/console/app/src/routes/black/subscribe.tsx
deleted file mode 100644
index 00ce19ef6..000000000
--- a/packages/console/app/src/routes/black/subscribe.tsx
+++ /dev/null
@@ -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>
- </>
- )
-}
diff --git a/packages/console/app/src/routes/black/subscribe/[plan].tsx b/packages/console/app/src/routes/black/subscribe/[plan].tsx
new file mode 100644
index 000000000..e0992a1e2
--- /dev/null
+++ b/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>
+ </>
+ )
+}
diff --git a/packages/console/core/migrations/0051_jazzy_green_goblin.sql b/packages/console/core/migrations/0051_jazzy_green_goblin.sql
new file mode 100644
index 000000000..cadb4a709
--- /dev/null
+++ b/packages/console/core/migrations/0051_jazzy_green_goblin.sql
@@ -0,0 +1 @@
+ALTER TABLE `billing` ADD `time_subscription_booked` timestamp(3); \ No newline at end of file
diff --git a/packages/console/core/migrations/0052_aromatic_agent_zero.sql b/packages/console/core/migrations/0052_aromatic_agent_zero.sql
new file mode 100644
index 000000000..c53ba5e2b
--- /dev/null
+++ b/packages/console/core/migrations/0052_aromatic_agent_zero.sql
@@ -0,0 +1 @@
+ALTER TABLE `billing` ADD `subscription_plan` enum('20','100','200'); \ No newline at end of file
diff --git a/packages/console/core/migrations/meta/0051_snapshot.json b/packages/console/core/migrations/meta/0051_snapshot.json
new file mode 100644
index 000000000..38002a288
--- /dev/null
+++ b/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": {}
+ }
+} \ No newline at end of file
diff --git a/packages/console/core/migrations/meta/0052_snapshot.json b/packages/console/core/migrations/meta/0052_snapshot.json
new file mode 100644
index 000000000..b5e1b4b8c
--- /dev/null
+++ b/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": {}
+ }
+} \ No newline at end of file
diff --git a/packages/console/core/migrations/meta/_journal.json b/packages/console/core/migrations/meta/_journal.json
index 9982daef5..019817f91 100644
--- a/packages/console/core/migrations/meta/_journal.json
+++ b/packages/console/core/migrations/meta/_journal.json
@@ -358,6 +358,20 @@
"when": 1767931290031,
"tag": "0050_bumpy_mephistopheles",
"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
}
]
-}
+} \ No newline at end of file
diff --git a/packages/console/core/src/schema/billing.sql.ts b/packages/console/core/src/schema/billing.sql.ts
index 6c2cfcf96..f1300f849 100644
--- a/packages/console/core/src/schema/billing.sql.ts
+++ b/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 { workspaceIndexes } from "./workspace.sql"
@@ -23,6 +23,8 @@ export const BillingTable = mysqlTable(
timeReloadLockedTill: utc("time_reload_locked_till"),
subscriptionID: varchar("subscription_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) => [
...workspaceIndexes(table),
diff --git a/packages/console/core/sst-env.d.ts b/packages/console/core/sst-env.d.ts
index 96fada3e3..b8e50a261 100644
--- a/packages/console/core/sst-env.d.ts
+++ b/packages/console/core/sst-env.d.ts
@@ -78,6 +78,10 @@ declare module "sst" {
"type": "sst.sst.Secret"
"value": string
}
+ "STRIPE_PUBLISHABLE_KEY": {
+ "type": "sst.sst.Secret"
+ "value": string
+ }
"STRIPE_SECRET_KEY": {
"type": "sst.sst.Secret"
"value": string
diff --git a/packages/console/function/sst-env.d.ts b/packages/console/function/sst-env.d.ts
index 96fada3e3..b8e50a261 100644
--- a/packages/console/function/sst-env.d.ts
+++ b/packages/console/function/sst-env.d.ts
@@ -78,6 +78,10 @@ declare module "sst" {
"type": "sst.sst.Secret"
"value": string
}
+ "STRIPE_PUBLISHABLE_KEY": {
+ "type": "sst.sst.Secret"
+ "value": string
+ }
"STRIPE_SECRET_KEY": {
"type": "sst.sst.Secret"
"value": string
diff --git a/packages/console/resource/sst-env.d.ts b/packages/console/resource/sst-env.d.ts
index 96fada3e3..b8e50a261 100644
--- a/packages/console/resource/sst-env.d.ts
+++ b/packages/console/resource/sst-env.d.ts
@@ -78,6 +78,10 @@ declare module "sst" {
"type": "sst.sst.Secret"
"value": string
}
+ "STRIPE_PUBLISHABLE_KEY": {
+ "type": "sst.sst.Secret"
+ "value": string
+ }
"STRIPE_SECRET_KEY": {
"type": "sst.sst.Secret"
"value": string
diff --git a/packages/enterprise/sst-env.d.ts b/packages/enterprise/sst-env.d.ts
index 96fada3e3..b8e50a261 100644
--- a/packages/enterprise/sst-env.d.ts
+++ b/packages/enterprise/sst-env.d.ts
@@ -78,6 +78,10 @@ declare module "sst" {
"type": "sst.sst.Secret"
"value": string
}
+ "STRIPE_PUBLISHABLE_KEY": {
+ "type": "sst.sst.Secret"
+ "value": string
+ }
"STRIPE_SECRET_KEY": {
"type": "sst.sst.Secret"
"value": string
diff --git a/packages/function/sst-env.d.ts b/packages/function/sst-env.d.ts
index 96fada3e3..b8e50a261 100644
--- a/packages/function/sst-env.d.ts
+++ b/packages/function/sst-env.d.ts
@@ -78,6 +78,10 @@ declare module "sst" {
"type": "sst.sst.Secret"
"value": string
}
+ "STRIPE_PUBLISHABLE_KEY": {
+ "type": "sst.sst.Secret"
+ "value": string
+ }
"STRIPE_SECRET_KEY": {
"type": "sst.sst.Secret"
"value": string
diff --git a/sst-env.d.ts b/sst-env.d.ts
index 035a5fc21..3160fc165 100644
--- a/sst-env.d.ts
+++ b/sst-env.d.ts
@@ -104,6 +104,10 @@ declare module "sst" {
"type": "sst.sst.Secret"
"value": string
}
+ "STRIPE_PUBLISHABLE_KEY": {
+ "type": "sst.sst.Secret"
+ "value": string
+ }
"STRIPE_SECRET_KEY": {
"type": "sst.sst.Secret"
"value": string