summaryrefslogtreecommitdiffhomepage
path: root/packages/console
diff options
context:
space:
mode:
authorFrank <[email protected]>2026-04-18 16:26:58 -0400
committerFrank <[email protected]>2026-04-18 17:33:28 -0400
commit9d012b062186ef9900cc2673b77c446d38ebd789 (patch)
tree0185f564ac585be5e50e1ba090da8a461e6fb4fc /packages/console
parentfbb0a93e12740c7fb3f5f7ff62eee027c157e351 (diff)
downloadopencode-9d012b062186ef9900cc2673b77c446d38ebd789.tar.gz
opencode-9d012b062186ef9900cc2673b77c446d38ebd789.zip
zen: redeem credit
Diffstat (limited to 'packages/console')
-rw-r--r--packages/console/app/src/i18n/ar.ts7
-rw-r--r--packages/console/app/src/i18n/br.ts7
-rw-r--r--packages/console/app/src/i18n/da.ts7
-rw-r--r--packages/console/app/src/i18n/de.ts7
-rw-r--r--packages/console/app/src/i18n/en.ts7
-rw-r--r--packages/console/app/src/i18n/es.ts7
-rw-r--r--packages/console/app/src/i18n/fr.ts7
-rw-r--r--packages/console/app/src/i18n/it.ts7
-rw-r--r--packages/console/app/src/i18n/ja.ts7
-rw-r--r--packages/console/app/src/i18n/ko.ts7
-rw-r--r--packages/console/app/src/i18n/no.ts7
-rw-r--r--packages/console/app/src/i18n/pl.ts7
-rw-r--r--packages/console/app/src/i18n/ru.ts7
-rw-r--r--packages/console/app/src/i18n/th.ts7
-rw-r--r--packages/console/app/src/i18n/tr.ts7
-rw-r--r--packages/console/app/src/i18n/zh.ts7
-rw-r--r--packages/console/app/src/i18n/zht.ts7
-rw-r--r--packages/console/app/src/routes/workspace/[id]/billing/index.tsx2
-rw-r--r--packages/console/app/src/routes/workspace/[id]/billing/redeem-section.module.css61
-rw-r--r--packages/console/app/src/routes/workspace/[id]/billing/redeem-section.tsx71
-rw-r--r--packages/console/core/migrations/20260418195905_shocking_marvel_zombies/migration.sql6
-rw-r--r--packages/console/core/migrations/20260418195905_shocking_marvel_zombies/snapshot.json2670
-rw-r--r--packages/console/core/script/create-coupon.ts24
-rw-r--r--packages/console/core/src/billing.ts33
-rw-r--r--packages/console/core/src/schema/billing.sql.ts24
25 files changed, 3007 insertions, 3 deletions
diff --git a/packages/console/app/src/i18n/ar.ts b/packages/console/app/src/i18n/ar.ts
index 11f76ca59..713703b25 100644
--- a/packages/console/app/src/i18n/ar.ts
+++ b/packages/console/app/src/i18n/ar.ts
@@ -558,6 +558,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "الاستخدام الحالي لـ",
"workspace.monthlyLimit.currentUsage.beforeAmount": "هو $",
+ "workspace.redeem.title": "استرداد قسيمة",
+ "workspace.redeem.subtitle": "استرد رمز القسيمة للحصول على رصيد أو مزايا.",
+ "workspace.redeem.placeholder": "أدخل رمز القسيمة",
+ "workspace.redeem.redeem": "استرداد",
+ "workspace.redeem.redeeming": "جارٍ الاسترداد...",
+ "workspace.redeem.success": "تم استرداد القسيمة بنجاح.",
+
"workspace.reload.title": "إعادة الشحن التلقائي",
"workspace.reload.disabled.before": "إعادة الشحن التلقائي",
"workspace.reload.disabled.state": "معطّل",
diff --git a/packages/console/app/src/i18n/br.ts b/packages/console/app/src/i18n/br.ts
index 79f64485a..bace96569 100644
--- a/packages/console/app/src/i18n/br.ts
+++ b/packages/console/app/src/i18n/br.ts
@@ -567,6 +567,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "Uso atual para",
"workspace.monthlyLimit.currentUsage.beforeAmount": "é $",
+ "workspace.redeem.title": "Resgatar Cupom",
+ "workspace.redeem.subtitle": "Resgate um código de cupom para receber créditos ou vantagens.",
+ "workspace.redeem.placeholder": "Digite o código do cupom",
+ "workspace.redeem.redeem": "Resgatar",
+ "workspace.redeem.redeeming": "Resgatando...",
+ "workspace.redeem.success": "Cupom resgatado com sucesso.",
+
"workspace.reload.title": "Recarga Automática",
"workspace.reload.disabled.before": "A recarga automática está",
"workspace.reload.disabled.state": "desativada",
diff --git a/packages/console/app/src/i18n/da.ts b/packages/console/app/src/i18n/da.ts
index 97b148c06..c2d3bf3ba 100644
--- a/packages/console/app/src/i18n/da.ts
+++ b/packages/console/app/src/i18n/da.ts
@@ -563,6 +563,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "Nuværende brug for",
"workspace.monthlyLimit.currentUsage.beforeAmount": "er $",
+ "workspace.redeem.title": "Indløs kupon",
+ "workspace.redeem.subtitle": "Indløs en kuponkode for at få kreditter eller fordele.",
+ "workspace.redeem.placeholder": "Indtast kuponkode",
+ "workspace.redeem.redeem": "Indløs",
+ "workspace.redeem.redeeming": "Indløser...",
+ "workspace.redeem.success": "Kuponen blev indløst.",
+
"workspace.reload.title": "Automatisk genopfyldning",
"workspace.reload.disabled.before": "Automatisk genopfyldning er",
"workspace.reload.disabled.state": "deaktiveret",
diff --git a/packages/console/app/src/i18n/de.ts b/packages/console/app/src/i18n/de.ts
index 1c5f631ae..e44335bab 100644
--- a/packages/console/app/src/i18n/de.ts
+++ b/packages/console/app/src/i18n/de.ts
@@ -566,6 +566,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "Aktuelle Nutzung für",
"workspace.monthlyLimit.currentUsage.beforeAmount": "ist $",
+ "workspace.redeem.title": "Gutschein einlösen",
+ "workspace.redeem.subtitle": "Löse einen Gutscheincode ein, um Guthaben oder Vorteile zu erhalten.",
+ "workspace.redeem.placeholder": "Gutscheincode eingeben",
+ "workspace.redeem.redeem": "Einlösen",
+ "workspace.redeem.redeeming": "Wird eingelöst...",
+ "workspace.redeem.success": "Gutschein erfolgreich eingelöst.",
+
"workspace.reload.title": "Auto-Reload",
"workspace.reload.disabled.before": "Auto-Reload ist",
"workspace.reload.disabled.state": "deaktiviert",
diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts
index d21d0dc9e..a9c3ca3cc 100644
--- a/packages/console/app/src/i18n/en.ts
+++ b/packages/console/app/src/i18n/en.ts
@@ -559,6 +559,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "Current usage for",
"workspace.monthlyLimit.currentUsage.beforeAmount": "is $",
+ "workspace.redeem.title": "Redeem Coupon",
+ "workspace.redeem.subtitle": "Redeem a coupon code to claim credits or perks.",
+ "workspace.redeem.placeholder": "Enter coupon code",
+ "workspace.redeem.redeem": "Redeem",
+ "workspace.redeem.redeeming": "Redeeming...",
+ "workspace.redeem.success": "Coupon redeemed successfully.",
+
"workspace.reload.title": "Auto Reload",
"workspace.reload.disabled.before": "Auto reload is",
"workspace.reload.disabled.state": "disabled",
diff --git a/packages/console/app/src/i18n/es.ts b/packages/console/app/src/i18n/es.ts
index d6449fd95..e2a0c271a 100644
--- a/packages/console/app/src/i18n/es.ts
+++ b/packages/console/app/src/i18n/es.ts
@@ -567,6 +567,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "Uso actual para",
"workspace.monthlyLimit.currentUsage.beforeAmount": "es $",
+ "workspace.redeem.title": "Canjear cupón",
+ "workspace.redeem.subtitle": "Canjea un código de cupón para obtener crédito o beneficios.",
+ "workspace.redeem.placeholder": "Introduce el código del cupón",
+ "workspace.redeem.redeem": "Canjear",
+ "workspace.redeem.redeeming": "Canjeando...",
+ "workspace.redeem.success": "Cupón canjeado correctamente.",
+
"workspace.reload.title": "Auto Recarga",
"workspace.reload.disabled.before": "La auto recarga está",
"workspace.reload.disabled.state": "deshabilitada",
diff --git a/packages/console/app/src/i18n/fr.ts b/packages/console/app/src/i18n/fr.ts
index c54c43104..5a353e873 100644
--- a/packages/console/app/src/i18n/fr.ts
+++ b/packages/console/app/src/i18n/fr.ts
@@ -569,6 +569,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "L'utilisation actuelle pour",
"workspace.monthlyLimit.currentUsage.beforeAmount": "est de",
+ "workspace.redeem.title": "Utiliser un coupon",
+ "workspace.redeem.subtitle": "Utilisez un code promo pour obtenir du crédit ou des avantages.",
+ "workspace.redeem.placeholder": "Saisissez le code promo",
+ "workspace.redeem.redeem": "Utiliser",
+ "workspace.redeem.redeeming": "Utilisation...",
+ "workspace.redeem.success": "Coupon utilisé avec succès.",
+
"workspace.reload.title": "Rechargement automatique",
"workspace.reload.disabled.before": "Le rechargement automatique est",
"workspace.reload.disabled.state": "désactivé",
diff --git a/packages/console/app/src/i18n/it.ts b/packages/console/app/src/i18n/it.ts
index aadea6fec..b19bff978 100644
--- a/packages/console/app/src/i18n/it.ts
+++ b/packages/console/app/src/i18n/it.ts
@@ -565,6 +565,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "Utilizzo attuale per",
"workspace.monthlyLimit.currentUsage.beforeAmount": "è $",
+ "workspace.redeem.title": "Riscatta Coupon",
+ "workspace.redeem.subtitle": "Riscatta un codice coupon per ottenere credito o vantaggi.",
+ "workspace.redeem.placeholder": "Inserisci il codice coupon",
+ "workspace.redeem.redeem": "Riscatta",
+ "workspace.redeem.redeeming": "Riscatto in corso...",
+ "workspace.redeem.success": "Coupon riscattato con successo.",
+
"workspace.reload.title": "Ricarica Auto",
"workspace.reload.disabled.before": "La ricarica auto è",
"workspace.reload.disabled.state": "disabilitata",
diff --git a/packages/console/app/src/i18n/ja.ts b/packages/console/app/src/i18n/ja.ts
index f3b4c083e..1571345e5 100644
--- a/packages/console/app/src/i18n/ja.ts
+++ b/packages/console/app/src/i18n/ja.ts
@@ -564,6 +564,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "現在の使用状況(",
"workspace.monthlyLimit.currentUsage.beforeAmount": ")は $",
+ "workspace.redeem.title": "クーポンを利用",
+ "workspace.redeem.subtitle": "クーポンコードを利用して、クレジットや特典を受け取ります。",
+ "workspace.redeem.placeholder": "クーポンコードを入力",
+ "workspace.redeem.redeem": "利用する",
+ "workspace.redeem.redeeming": "利用中...",
+ "workspace.redeem.success": "クーポンを利用しました。",
+
"workspace.reload.title": "自動チャージ",
"workspace.reload.disabled.before": "自動チャージは",
"workspace.reload.disabled.state": "無効",
diff --git a/packages/console/app/src/i18n/ko.ts b/packages/console/app/src/i18n/ko.ts
index e2320c359..9ec931031 100644
--- a/packages/console/app/src/i18n/ko.ts
+++ b/packages/console/app/src/i18n/ko.ts
@@ -558,6 +558,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "현재",
"workspace.monthlyLimit.currentUsage.beforeAmount": "사용량: $",
+ "workspace.redeem.title": "쿠폰 사용",
+ "workspace.redeem.subtitle": "쿠폰 코드를 사용해 크레딧이나 혜택을 받으세요.",
+ "workspace.redeem.placeholder": "쿠폰 코드를 입력하세요",
+ "workspace.redeem.redeem": "사용",
+ "workspace.redeem.redeeming": "사용 중...",
+ "workspace.redeem.success": "쿠폰을 성공적으로 사용했습니다.",
+
"workspace.reload.title": "자동 충전",
"workspace.reload.disabled.before": "자동 충전이",
"workspace.reload.disabled.state": "비활성화",
diff --git a/packages/console/app/src/i18n/no.ts b/packages/console/app/src/i18n/no.ts
index 717c2ad1e..132b85a6e 100644
--- a/packages/console/app/src/i18n/no.ts
+++ b/packages/console/app/src/i18n/no.ts
@@ -564,6 +564,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "Gjeldende forbruk for",
"workspace.monthlyLimit.currentUsage.beforeAmount": "er $",
+ "workspace.redeem.title": "Løs inn kupong",
+ "workspace.redeem.subtitle": "Løs inn en kupongkode for å få kreditt eller fordeler.",
+ "workspace.redeem.placeholder": "Skriv inn kupongkode",
+ "workspace.redeem.redeem": "Løs inn",
+ "workspace.redeem.redeeming": "Løser inn...",
+ "workspace.redeem.success": "Kupongen ble løst inn.",
+
"workspace.reload.title": "Auto-påfyll",
"workspace.reload.disabled.before": "Auto-påfyll er",
"workspace.reload.disabled.state": "deaktivert",
diff --git a/packages/console/app/src/i18n/pl.ts b/packages/console/app/src/i18n/pl.ts
index c9daeedee..441dfc7be 100644
--- a/packages/console/app/src/i18n/pl.ts
+++ b/packages/console/app/src/i18n/pl.ts
@@ -565,6 +565,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "Aktualne użycie za",
"workspace.monthlyLimit.currentUsage.beforeAmount": "wynosi $",
+ "workspace.redeem.title": "Zrealizuj kupon",
+ "workspace.redeem.subtitle": "Zrealizuj kod kuponu, aby otrzymać środki lub korzyści.",
+ "workspace.redeem.placeholder": "Wpisz kod kuponu",
+ "workspace.redeem.redeem": "Zrealizuj",
+ "workspace.redeem.redeeming": "Realizowanie...",
+ "workspace.redeem.success": "Kupon został zrealizowany.",
+
"workspace.reload.title": "Automatyczne doładowanie",
"workspace.reload.disabled.before": "Automatyczne doładowanie jest",
"workspace.reload.disabled.state": "wyłączone",
diff --git a/packages/console/app/src/i18n/ru.ts b/packages/console/app/src/i18n/ru.ts
index 01baa8985..ef7bcacd8 100644
--- a/packages/console/app/src/i18n/ru.ts
+++ b/packages/console/app/src/i18n/ru.ts
@@ -571,6 +571,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "Текущее использование за",
"workspace.monthlyLimit.currentUsage.beforeAmount": "составляет $",
+ "workspace.redeem.title": "Активировать купон",
+ "workspace.redeem.subtitle": "Активируйте код купона, чтобы получить кредит или бонусы.",
+ "workspace.redeem.placeholder": "Введите код купона",
+ "workspace.redeem.redeem": "Активировать",
+ "workspace.redeem.redeeming": "Активация...",
+ "workspace.redeem.success": "Купон успешно активирован.",
+
"workspace.reload.title": "Автопополнение",
"workspace.reload.disabled.before": "Автопополнение",
"workspace.reload.disabled.state": "отключено",
diff --git a/packages/console/app/src/i18n/th.ts b/packages/console/app/src/i18n/th.ts
index 59c90ef65..d7d862d94 100644
--- a/packages/console/app/src/i18n/th.ts
+++ b/packages/console/app/src/i18n/th.ts
@@ -560,6 +560,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "การใช้งานปัจจุบันสำหรับ",
"workspace.monthlyLimit.currentUsage.beforeAmount": "คือ $",
+ "workspace.redeem.title": "แลกคูปอง",
+ "workspace.redeem.subtitle": "แลกรหัสคูปองเพื่อรับเครดิตหรือสิทธิพิเศษ",
+ "workspace.redeem.placeholder": "กรอกรหัสคูปอง",
+ "workspace.redeem.redeem": "แลก",
+ "workspace.redeem.redeeming": "กำลังแลก...",
+ "workspace.redeem.success": "แลกคูปองสำเร็จ",
+
"workspace.reload.title": "โหลดซ้ำอัตโนมัติ",
"workspace.reload.disabled.before": "การโหลดซ้ำอัตโนมัติ",
"workspace.reload.disabled.state": "ปิดใช้งานอยู่",
diff --git a/packages/console/app/src/i18n/tr.ts b/packages/console/app/src/i18n/tr.ts
index 196bf9d37..13a074642 100644
--- a/packages/console/app/src/i18n/tr.ts
+++ b/packages/console/app/src/i18n/tr.ts
@@ -567,6 +567,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "Şu anki kullanım",
"workspace.monthlyLimit.currentUsage.beforeAmount": "$",
+ "workspace.redeem.title": "Kupon Kullan",
+ "workspace.redeem.subtitle": "Kredi veya avantajlardan yararlanmak için bir kupon kodu kullanın.",
+ "workspace.redeem.placeholder": "Kupon kodunu girin",
+ "workspace.redeem.redeem": "Kullan",
+ "workspace.redeem.redeeming": "Kullanılıyor...",
+ "workspace.redeem.success": "Kupon başarıyla kullanıldı.",
+
"workspace.reload.title": "Otomatik Yeniden Yükleme",
"workspace.reload.disabled.before": "Otomatik yeniden yükleme:",
"workspace.reload.disabled.state": "devre dışı",
diff --git a/packages/console/app/src/i18n/zh.ts b/packages/console/app/src/i18n/zh.ts
index aaec74fba..c84ea5cc6 100644
--- a/packages/console/app/src/i18n/zh.ts
+++ b/packages/console/app/src/i18n/zh.ts
@@ -542,6 +542,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "当前",
"workspace.monthlyLimit.currentUsage.beforeAmount": "的使用量为 $",
+ "workspace.redeem.title": "兑换优惠券",
+ "workspace.redeem.subtitle": "兑换优惠码以领取充值额度或权益。",
+ "workspace.redeem.placeholder": "输入优惠码",
+ "workspace.redeem.redeem": "兑换",
+ "workspace.redeem.redeeming": "兑换中...",
+ "workspace.redeem.success": "优惠券兑换成功。",
+
"workspace.reload.title": "自动充值",
"workspace.reload.disabled.before": "自动充值已",
"workspace.reload.disabled.state": "禁用",
diff --git a/packages/console/app/src/i18n/zht.ts b/packages/console/app/src/i18n/zht.ts
index b3e0fb077..6a70a81c7 100644
--- a/packages/console/app/src/i18n/zht.ts
+++ b/packages/console/app/src/i18n/zht.ts
@@ -542,6 +542,13 @@ export const dict = {
"workspace.monthlyLimit.currentUsage.beforeMonth": "目前",
"workspace.monthlyLimit.currentUsage.beforeAmount": "的使用量為 $",
+ "workspace.redeem.title": "兌換優惠券",
+ "workspace.redeem.subtitle": "兌換優惠碼以領取儲值額度或權益。",
+ "workspace.redeem.placeholder": "輸入優惠碼",
+ "workspace.redeem.redeem": "兌換",
+ "workspace.redeem.redeeming": "兌換中...",
+ "workspace.redeem.success": "優惠券兌換成功。",
+
"workspace.reload.title": "自動儲值",
"workspace.reload.disabled.before": "自動儲值已",
"workspace.reload.disabled.state": "停用",
diff --git a/packages/console/app/src/routes/workspace/[id]/billing/index.tsx b/packages/console/app/src/routes/workspace/[id]/billing/index.tsx
index 4a7dc2488..fb4848535 100644
--- a/packages/console/app/src/routes/workspace/[id]/billing/index.tsx
+++ b/packages/console/app/src/routes/workspace/[id]/billing/index.tsx
@@ -3,6 +3,7 @@ import { BillingSection } from "./billing-section"
import { ReloadSection } from "./reload-section"
import { PaymentSection } from "./payment-section"
import { BlackSection } from "./black-section"
+import { RedeemSection } from "./redeem-section"
import { createMemo, Show } from "solid-js"
import { createAsync, useParams } from "@solidjs/router"
import { queryBillingInfo, querySessionInfo } from "../../common"
@@ -26,6 +27,7 @@ export default function () {
<MonthlyLimitSection />
<PaymentSection />
</Show>
+ <RedeemSection />
</Show>
</div>
</div>
diff --git a/packages/console/app/src/routes/workspace/[id]/billing/redeem-section.module.css b/packages/console/app/src/routes/workspace/[id]/billing/redeem-section.module.css
new file mode 100644
index 000000000..42140e4e8
--- /dev/null
+++ b/packages/console/app/src/routes/workspace/[id]/billing/redeem-section.module.css
@@ -0,0 +1,61 @@
+.root {
+ [data-slot="redeem-container"] {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-3);
+ min-width: 20rem;
+ width: fit-content;
+
+ @media (max-width: 30rem) {
+ width: 100%;
+ }
+ }
+
+ [data-slot="redeem-form"] {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-2);
+
+ [data-slot="input-row"] {
+ display: flex;
+ gap: var(--space-2);
+ align-items: stretch;
+
+ @media (max-width: 30rem) {
+ flex-direction: column;
+ }
+ }
+
+ input {
+ flex: 1;
+ padding: var(--space-2) var(--space-3);
+ border: 1px solid var(--color-border);
+ border-radius: var(--border-radius-sm);
+ background-color: var(--color-bg);
+ color: var(--color-text);
+ font-size: var(--font-size-sm);
+ font-family: var(--font-mono);
+
+ &:focus {
+ outline: none;
+ border-color: var(--color-accent);
+ }
+
+ &::placeholder {
+ color: var(--color-text-disabled);
+ }
+ }
+
+ [data-slot="form-error"] {
+ color: var(--color-danger);
+ font-size: var(--font-size-sm);
+ line-height: 1.4;
+ }
+
+ [data-slot="form-success"] {
+ color: var(--color-success, var(--color-accent));
+ font-size: var(--font-size-sm);
+ line-height: 1.4;
+ }
+ }
+}
diff --git a/packages/console/app/src/routes/workspace/[id]/billing/redeem-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/redeem-section.tsx
new file mode 100644
index 000000000..872e8954b
--- /dev/null
+++ b/packages/console/app/src/routes/workspace/[id]/billing/redeem-section.tsx
@@ -0,0 +1,71 @@
+import { json, action, useParams, useSubmission } from "@solidjs/router"
+import { Show } from "solid-js"
+import { withActor } from "~/context/auth.withActor"
+import { Billing } from "@opencode-ai/console-core/billing.js"
+import { User } from "@opencode-ai/console-core/user.js"
+import { Actor } from "@opencode-ai/console-core/actor.js"
+import { CouponType } from "@opencode-ai/console-core/schema/billing.sql.js"
+import styles from "./redeem-section.module.css"
+import { queryBillingInfo } from "../../common"
+import { useI18n } from "~/context/i18n"
+import { formError, localizeError } from "~/lib/form-error"
+
+const redeem = action(async (form: FormData) => {
+ "use server"
+ const workspaceID = form.get("workspaceID") as string | null
+ if (!workspaceID) return { error: formError.workspaceRequired }
+ const code = (form.get("code") as string | null)?.trim().toUpperCase()
+ if (!code) return { error: "Coupon code is required." }
+ if (!(CouponType as readonly string[]).includes(code)) return { error: "Invalid coupon code." }
+
+ return json(
+ await withActor(async () => {
+ const actor = Actor.assert("user")
+ const email = await User.getAuthEmail(actor.properties.userID)
+ if (!email) return { error: "No email on account." }
+ return Billing.redeemCoupon(email, code as (typeof CouponType)[number])
+ .then(() => ({ error: undefined, data: true }))
+ .catch((e) => ({ error: e.message as string }))
+ }, workspaceID),
+ { revalidate: queryBillingInfo.key },
+ )
+}, "billing.redeemCoupon")
+
+export function RedeemSection() {
+ const params = useParams()
+ const i18n = useI18n()
+ const submission = useSubmission(redeem)
+
+ return (
+ <section class={styles.root}>
+ <div data-slot="section-title">
+ <h2>{i18n.t("workspace.redeem.title")}</h2>
+ <p>{i18n.t("workspace.redeem.subtitle")}</p>
+ </div>
+ <div data-slot="redeem-container">
+ <form action={redeem} method="post" data-slot="redeem-form">
+ <div data-slot="input-row">
+ <input
+ required
+ data-component="input"
+ name="code"
+ type="text"
+ autocomplete="off"
+ placeholder={i18n.t("workspace.redeem.placeholder")}
+ />
+ <button type="submit" data-color="primary" disabled={submission.pending}>
+ {submission.pending ? i18n.t("workspace.redeem.redeeming") : i18n.t("workspace.redeem.redeem")}
+ </button>
+ </div>
+ <Show when={submission.result && (submission.result as any).error}>
+ {(err: any) => <div data-slot="form-error">{localizeError(i18n.t, err())}</div>}
+ </Show>
+ <Show when={submission.result && !(submission.result as any).error && (submission.result as any).data}>
+ <div data-slot="form-success">{i18n.t("workspace.redeem.success")}</div>
+ </Show>
+ <input type="hidden" name="workspaceID" value={params.id} />
+ </form>
+ </div>
+ </section>
+ )
+}
diff --git a/packages/console/core/migrations/20260418195905_shocking_marvel_zombies/migration.sql b/packages/console/core/migrations/20260418195905_shocking_marvel_zombies/migration.sql
new file mode 100644
index 000000000..7b7f7a2eb
--- /dev/null
+++ b/packages/console/core/migrations/20260418195905_shocking_marvel_zombies/migration.sql
@@ -0,0 +1,6 @@
+CREATE TABLE `coupon` (
+ `email` varchar(255),
+ `type` enum('BUILDATHON','GOFREEMONTH') NOT NULL,
+ `time_redeemed` timestamp(3),
+ CONSTRAINT PRIMARY KEY(`email`,`type`)
+);
diff --git a/packages/console/core/migrations/20260418195905_shocking_marvel_zombies/snapshot.json b/packages/console/core/migrations/20260418195905_shocking_marvel_zombies/snapshot.json
new file mode 100644
index 000000000..40e9d5e15
--- /dev/null
+++ b/packages/console/core/migrations/20260418195905_shocking_marvel_zombies/snapshot.json
@@ -0,0 +1,2670 @@
+{
+ "version": "6",
+ "dialect": "mysql",
+ "id": "18b4281c-1609-47d8-9d51-0b08e3925f2b",
+ "prevIds": [
+ "93c492af-c95b-4213-9fc2-38c3dd10374d"
+ ],
+ "ddl": [
+ {
+ "name": "account",
+ "entityType": "tables"
+ },
+ {
+ "name": "auth",
+ "entityType": "tables"
+ },
+ {
+ "name": "benchmark",
+ "entityType": "tables"
+ },
+ {
+ "name": "billing",
+ "entityType": "tables"
+ },
+ {
+ "name": "coupon",
+ "entityType": "tables"
+ },
+ {
+ "name": "lite",
+ "entityType": "tables"
+ },
+ {
+ "name": "payment",
+ "entityType": "tables"
+ },
+ {
+ "name": "subscription",
+ "entityType": "tables"
+ },
+ {
+ "name": "usage",
+ "entityType": "tables"
+ },
+ {
+ "name": "ip_rate_limit",
+ "entityType": "tables"
+ },
+ {
+ "name": "ip",
+ "entityType": "tables"
+ },
+ {
+ "name": "key_rate_limit",
+ "entityType": "tables"
+ },
+ {
+ "name": "model_rate_limit",
+ "entityType": "tables"
+ },
+ {
+ "name": "key",
+ "entityType": "tables"
+ },
+ {
+ "name": "model",
+ "entityType": "tables"
+ },
+ {
+ "name": "provider",
+ "entityType": "tables"
+ },
+ {
+ "name": "user",
+ "entityType": "tables"
+ },
+ {
+ "name": "workspace",
+ "entityType": "tables"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "account"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "account"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "account"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "account"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "auth"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "auth"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "auth"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "auth"
+ },
+ {
+ "type": "enum('email','github','google')",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "provider",
+ "entityType": "columns",
+ "table": "auth"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "subject",
+ "entityType": "columns",
+ "table": "auth"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "account_id",
+ "entityType": "columns",
+ "table": "auth"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "benchmark"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "benchmark"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "benchmark"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "benchmark"
+ },
+ {
+ "type": "varchar(64)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "model",
+ "entityType": "columns",
+ "table": "benchmark"
+ },
+ {
+ "type": "varchar(64)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "agent",
+ "entityType": "columns",
+ "table": "benchmark"
+ },
+ {
+ "type": "mediumtext",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "result",
+ "entityType": "columns",
+ "table": "benchmark"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "workspace_id",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "customer_id",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "payment_method_id",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "varchar(32)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "payment_method_type",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "varchar(4)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "payment_method_last4",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "bigint",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "balance",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "int",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "monthly_limit",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "bigint",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "monthly_usage",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_monthly_usage_updated",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "boolean",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "reload",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "int",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "reload_trigger",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "int",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "reload_amount",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "reload_error",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_reload_error",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_reload_locked_till",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "json",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "subscription",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "varchar(28)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "subscription_id",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "enum('20','100','200')",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "subscription_plan",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_subscription_booked",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_subscription_selected",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "varchar(28)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "lite_subscription_id",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "json",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "lite",
+ "entityType": "columns",
+ "table": "billing"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "email",
+ "entityType": "columns",
+ "table": "coupon"
+ },
+ {
+ "type": "enum('BUILDATHON','GOFREEMONTH')",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "type",
+ "entityType": "columns",
+ "table": "coupon"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_redeemed",
+ "entityType": "columns",
+ "table": "coupon"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "lite"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "workspace_id",
+ "entityType": "columns",
+ "table": "lite"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "lite"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "lite"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "lite"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "table": "lite"
+ },
+ {
+ "type": "bigint",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "rolling_usage",
+ "entityType": "columns",
+ "table": "lite"
+ },
+ {
+ "type": "bigint",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "weekly_usage",
+ "entityType": "columns",
+ "table": "lite"
+ },
+ {
+ "type": "bigint",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "monthly_usage",
+ "entityType": "columns",
+ "table": "lite"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_rolling_updated",
+ "entityType": "columns",
+ "table": "lite"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_weekly_updated",
+ "entityType": "columns",
+ "table": "lite"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_monthly_updated",
+ "entityType": "columns",
+ "table": "lite"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "payment"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "workspace_id",
+ "entityType": "columns",
+ "table": "payment"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "payment"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "payment"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "payment"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "customer_id",
+ "entityType": "columns",
+ "table": "payment"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "invoice_id",
+ "entityType": "columns",
+ "table": "payment"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "payment_id",
+ "entityType": "columns",
+ "table": "payment"
+ },
+ {
+ "type": "bigint",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "amount",
+ "entityType": "columns",
+ "table": "payment"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_refunded",
+ "entityType": "columns",
+ "table": "payment"
+ },
+ {
+ "type": "json",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "enrichment",
+ "entityType": "columns",
+ "table": "payment"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "subscription"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "workspace_id",
+ "entityType": "columns",
+ "table": "subscription"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "subscription"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "subscription"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "subscription"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "table": "subscription"
+ },
+ {
+ "type": "bigint",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "rolling_usage",
+ "entityType": "columns",
+ "table": "subscription"
+ },
+ {
+ "type": "bigint",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "fixed_usage",
+ "entityType": "columns",
+ "table": "subscription"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_rolling_updated",
+ "entityType": "columns",
+ "table": "subscription"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_fixed_updated",
+ "entityType": "columns",
+ "table": "subscription"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "workspace_id",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "model",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "provider",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "int",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "input_tokens",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "int",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "output_tokens",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "int",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "reasoning_tokens",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "int",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "cache_read_tokens",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "int",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "cache_write_5m_tokens",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "int",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "cache_write_1h_tokens",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "bigint",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "cost",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "key_id",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "session_id",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "json",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "enrichment",
+ "entityType": "columns",
+ "table": "usage"
+ },
+ {
+ "type": "varchar(45)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "ip",
+ "entityType": "columns",
+ "table": "ip_rate_limit"
+ },
+ {
+ "type": "varchar(10)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "interval",
+ "entityType": "columns",
+ "table": "ip_rate_limit"
+ },
+ {
+ "type": "int",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "count",
+ "entityType": "columns",
+ "table": "ip_rate_limit"
+ },
+ {
+ "type": "varchar(45)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "ip",
+ "entityType": "columns",
+ "table": "ip"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "ip"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "ip"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "ip"
+ },
+ {
+ "type": "int",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "usage",
+ "entityType": "columns",
+ "table": "ip"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "key",
+ "entityType": "columns",
+ "table": "key_rate_limit"
+ },
+ {
+ "type": "varchar(40)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "interval",
+ "entityType": "columns",
+ "table": "key_rate_limit"
+ },
+ {
+ "type": "int",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "count",
+ "entityType": "columns",
+ "table": "key_rate_limit"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "key",
+ "entityType": "columns",
+ "table": "model_rate_limit"
+ },
+ {
+ "type": "varchar(40)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "interval",
+ "entityType": "columns",
+ "table": "model_rate_limit"
+ },
+ {
+ "type": "int",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "count",
+ "entityType": "columns",
+ "table": "model_rate_limit"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "key"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "workspace_id",
+ "entityType": "columns",
+ "table": "key"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "key"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "key"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "key"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "name",
+ "entityType": "columns",
+ "table": "key"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "key",
+ "entityType": "columns",
+ "table": "key"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "user_id",
+ "entityType": "columns",
+ "table": "key"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_used",
+ "entityType": "columns",
+ "table": "key"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "model"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "workspace_id",
+ "entityType": "columns",
+ "table": "model"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "model"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "model"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "model"
+ },
+ {
+ "type": "varchar(64)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "model",
+ "entityType": "columns",
+ "table": "model"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "provider"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "workspace_id",
+ "entityType": "columns",
+ "table": "provider"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "provider"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "provider"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "provider"
+ },
+ {
+ "type": "varchar(64)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "provider",
+ "entityType": "columns",
+ "table": "provider"
+ },
+ {
+ "type": "text",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "credentials",
+ "entityType": "columns",
+ "table": "provider"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "workspace_id",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "account_id",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "email",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "name",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_seen",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "int",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "color",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "enum('admin','member')",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "role",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "int",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "monthly_limit",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "bigint",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "monthly_usage",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_monthly_usage_updated",
+ "entityType": "columns",
+ "table": "user"
+ },
+ {
+ "type": "varchar(30)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "id",
+ "entityType": "columns",
+ "table": "workspace"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "slug",
+ "entityType": "columns",
+ "table": "workspace"
+ },
+ {
+ "type": "varchar(255)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "name",
+ "entityType": "columns",
+ "table": "workspace"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(now())",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_created",
+ "entityType": "columns",
+ "table": "workspace"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": true,
+ "autoIncrement": false,
+ "default": "(CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3))",
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_updated",
+ "entityType": "columns",
+ "table": "workspace"
+ },
+ {
+ "type": "timestamp(3)",
+ "notNull": false,
+ "autoIncrement": false,
+ "default": null,
+ "onUpdateNow": false,
+ "onUpdateNowFsp": null,
+ "charSet": null,
+ "collation": null,
+ "generated": null,
+ "name": "time_deleted",
+ "entityType": "columns",
+ "table": "workspace"
+ },
+ {
+ "columns": [
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "account",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "auth",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "benchmark",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "workspace_id",
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "billing",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "email",
+ "type"
+ ],
+ "name": "PRIMARY",
+ "table": "coupon",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "workspace_id",
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "lite",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "workspace_id",
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "payment",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "workspace_id",
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "subscription",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "workspace_id",
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "usage",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "ip",
+ "interval"
+ ],
+ "name": "PRIMARY",
+ "table": "ip_rate_limit",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "ip"
+ ],
+ "name": "PRIMARY",
+ "table": "ip",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "key",
+ "interval"
+ ],
+ "name": "PRIMARY",
+ "table": "key_rate_limit",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "key",
+ "interval"
+ ],
+ "name": "PRIMARY",
+ "table": "model_rate_limit",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "workspace_id",
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "key",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "workspace_id",
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "model",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "workspace_id",
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "provider",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "workspace_id",
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "user",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ "id"
+ ],
+ "name": "PRIMARY",
+ "table": "workspace",
+ "entityType": "pks"
+ },
+ {
+ "columns": [
+ {
+ "value": "provider",
+ "isExpression": false
+ },
+ {
+ "value": "subject",
+ "isExpression": false
+ }
+ ],
+ "isUnique": true,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "provider",
+ "entityType": "indexes",
+ "table": "auth"
+ },
+ {
+ "columns": [
+ {
+ "value": "account_id",
+ "isExpression": false
+ }
+ ],
+ "isUnique": false,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "account_id",
+ "entityType": "indexes",
+ "table": "auth"
+ },
+ {
+ "columns": [
+ {
+ "value": "time_created",
+ "isExpression": false
+ }
+ ],
+ "isUnique": false,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "time_created",
+ "entityType": "indexes",
+ "table": "benchmark"
+ },
+ {
+ "columns": [
+ {
+ "value": "customer_id",
+ "isExpression": false
+ }
+ ],
+ "isUnique": true,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "global_customer_id",
+ "entityType": "indexes",
+ "table": "billing"
+ },
+ {
+ "columns": [
+ {
+ "value": "subscription_id",
+ "isExpression": false
+ }
+ ],
+ "isUnique": true,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "global_subscription_id",
+ "entityType": "indexes",
+ "table": "billing"
+ },
+ {
+ "columns": [
+ {
+ "value": "workspace_id",
+ "isExpression": false
+ },
+ {
+ "value": "user_id",
+ "isExpression": false
+ }
+ ],
+ "isUnique": true,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "workspace_user_id",
+ "entityType": "indexes",
+ "table": "lite"
+ },
+ {
+ "columns": [
+ {
+ "value": "workspace_id",
+ "isExpression": false
+ },
+ {
+ "value": "user_id",
+ "isExpression": false
+ }
+ ],
+ "isUnique": true,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "workspace_user_id",
+ "entityType": "indexes",
+ "table": "subscription"
+ },
+ {
+ "columns": [
+ {
+ "value": "workspace_id",
+ "isExpression": false
+ },
+ {
+ "value": "time_created",
+ "isExpression": false
+ }
+ ],
+ "isUnique": false,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "usage_time_created",
+ "entityType": "indexes",
+ "table": "usage"
+ },
+ {
+ "columns": [
+ {
+ "value": "key",
+ "isExpression": false
+ }
+ ],
+ "isUnique": true,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "global_key",
+ "entityType": "indexes",
+ "table": "key"
+ },
+ {
+ "columns": [
+ {
+ "value": "workspace_id",
+ "isExpression": false
+ },
+ {
+ "value": "model",
+ "isExpression": false
+ }
+ ],
+ "isUnique": true,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "model_workspace_model",
+ "entityType": "indexes",
+ "table": "model"
+ },
+ {
+ "columns": [
+ {
+ "value": "workspace_id",
+ "isExpression": false
+ },
+ {
+ "value": "provider",
+ "isExpression": false
+ }
+ ],
+ "isUnique": true,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "workspace_provider",
+ "entityType": "indexes",
+ "table": "provider"
+ },
+ {
+ "columns": [
+ {
+ "value": "workspace_id",
+ "isExpression": false
+ },
+ {
+ "value": "account_id",
+ "isExpression": false
+ }
+ ],
+ "isUnique": true,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "user_account_id",
+ "entityType": "indexes",
+ "table": "user"
+ },
+ {
+ "columns": [
+ {
+ "value": "workspace_id",
+ "isExpression": false
+ },
+ {
+ "value": "email",
+ "isExpression": false
+ }
+ ],
+ "isUnique": true,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "user_email",
+ "entityType": "indexes",
+ "table": "user"
+ },
+ {
+ "columns": [
+ {
+ "value": "account_id",
+ "isExpression": false
+ }
+ ],
+ "isUnique": false,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "global_account_id",
+ "entityType": "indexes",
+ "table": "user"
+ },
+ {
+ "columns": [
+ {
+ "value": "email",
+ "isExpression": false
+ }
+ ],
+ "isUnique": false,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "global_email",
+ "entityType": "indexes",
+ "table": "user"
+ },
+ {
+ "columns": [
+ {
+ "value": "slug",
+ "isExpression": false
+ }
+ ],
+ "isUnique": true,
+ "using": null,
+ "algorithm": null,
+ "lock": null,
+ "nameExplicit": true,
+ "name": "slug",
+ "entityType": "indexes",
+ "table": "workspace"
+ }
+ ],
+ "renames": []
+} \ No newline at end of file
diff --git a/packages/console/core/script/create-coupon.ts b/packages/console/core/script/create-coupon.ts
new file mode 100644
index 000000000..e13337905
--- /dev/null
+++ b/packages/console/core/script/create-coupon.ts
@@ -0,0 +1,24 @@
+import { Database } from "../src/drizzle/index.js"
+import { CouponTable, CouponType } from "../src/schema/billing.sql.js"
+
+const email = process.argv[2]
+const type = process.argv[3] as (typeof CouponType)[number]
+
+if (!email || !type) {
+ console.error(`Usage: bun create-coupon.ts <email> <${CouponType.join("|")}>`)
+ process.exit(1)
+}
+
+if (!(CouponType as readonly string[]).includes(type)) {
+ console.error(`Error: type must be one of ${CouponType.join(", ")}`)
+ process.exit(1)
+}
+
+await Database.use((tx) =>
+ tx.insert(CouponTable).values({
+ email,
+ type,
+ }),
+)
+
+console.log(`Created ${type} coupon for ${email}`)
diff --git a/packages/console/core/src/billing.ts b/packages/console/core/src/billing.ts
index 9de413e60..d96b19ad7 100644
--- a/packages/console/core/src/billing.ts
+++ b/packages/console/core/src/billing.ts
@@ -1,6 +1,14 @@
import { Stripe } from "stripe"
-import { Database, eq, sql } from "./drizzle"
-import { BillingTable, LiteTable, PaymentTable, SubscriptionTable, UsageTable } from "./schema/billing.sql"
+import { and, Database, eq, sql } from "./drizzle"
+import {
+ BillingTable,
+ CouponTable,
+ CouponType,
+ LiteTable,
+ PaymentTable,
+ SubscriptionTable,
+ UsageTable,
+} from "./schema/billing.sql"
import { Actor } from "./actor"
import { fn } from "./util/fn"
import { z } from "zod"
@@ -147,6 +155,27 @@ export namespace Billing {
return amountInMicroCents
}
+ export const redeemCoupon = async (email: string, type: (typeof CouponType)[number]) => {
+ const coupon = await Database.use((tx) =>
+ tx
+ .select()
+ .from(CouponTable)
+ .where(and(eq(CouponTable.email, email), eq(CouponTable.type, type)))
+ .then((rows) => rows[0]),
+ )
+ if (!coupon) throw new Error("Invalid coupon code")
+ if (coupon.timeRedeemed) throw new Error("Coupon already redeemed")
+
+ if (type === "BUILDATHON") await grantCredit(Actor.workspace(), 500)
+
+ await Database.use((tx) =>
+ tx
+ .update(CouponTable)
+ .set({ timeRedeemed: sql`now()` })
+ .where(and(eq(CouponTable.email, email), eq(CouponTable.type, type))),
+ )
+ }
+
export const setMonthlyLimit = fn(z.number(), async (input) => {
return await Database.use((tx) =>
tx
diff --git a/packages/console/core/src/schema/billing.sql.ts b/packages/console/core/src/schema/billing.sql.ts
index b06ca8966..f8dcbd2b1 100644
--- a/packages/console/core/src/schema/billing.sql.ts
+++ b/packages/console/core/src/schema/billing.sql.ts
@@ -1,4 +1,15 @@
-import { bigint, boolean, index, int, json, mysqlEnum, mysqlTable, uniqueIndex, varchar } from "drizzle-orm/mysql-core"
+import {
+ bigint,
+ boolean,
+ index,
+ int,
+ json,
+ mysqlEnum,
+ mysqlTable,
+ primaryKey,
+ uniqueIndex,
+ varchar,
+} from "drizzle-orm/mysql-core"
import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types"
import { workspaceIndexes } from "./workspace.sql"
@@ -121,3 +132,14 @@ export const UsageTable = mysqlTable(
},
(table) => [...workspaceIndexes(table), index("usage_time_created").on(table.workspaceID, table.timeCreated)],
)
+
+export const CouponType = ["BUILDATHON", "GOFREEMONTH"] as const
+export const CouponTable = mysqlTable(
+ "coupon",
+ {
+ email: varchar("email", { length: 255 }),
+ type: mysqlEnum("type", CouponType).notNull(),
+ timeRedeemed: utc("time_redeemed"),
+ },
+ (table) => [primaryKey({ columns: [table.email, table.type] })],
+)